Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 21 additions & 3 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,18 @@ permissions:
jobs:
account-unification-tests:
if: ${{ github.event_name != 'pull_request' || (github.event.action != 'closed' && github.event.pull_request.draft == false) }}
runs-on: ubuntu-latest
# Fail closed until the isolated group has eligible disposable capacity.
# Do not substitute persistent control runners or a hosted fallback.
runs-on:
group: CWL CI isolated
labels: [self-hosted, linux, x64, cwlab-ci-isolated]
defaults:
run:
working-directory: services/account_unification
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
- uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0
with:
python-version: "3.12"
Expand Down Expand Up @@ -52,9 +58,15 @@ jobs:

realm-config-validates:
if: ${{ github.event_name != 'pull_request' || (github.event.action != 'closed' && github.event.pull_request.draft == false) }}
runs-on: ubuntu-latest
# Fail closed until the isolated group has eligible disposable capacity.
# Do not substitute persistent control runners or a hosted fallback.
runs-on:
group: CWL CI isolated
labels: [self-hosted, linux, x64, cwlab-ci-isolated]
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
- uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0
with:
python-version: "3.12"
Expand All @@ -72,9 +84,15 @@ jobs:

compose-config-validates:
if: ${{ github.event_name != 'pull_request' || (github.event.action != 'closed' && github.event.pull_request.draft == false) }}
runs-on: ubuntu-latest
# Fail closed until the isolated group has eligible disposable capacity.
# Do not substitute persistent control runners or a hosted fallback.
runs-on:
group: CWL CI isolated
labels: [self-hosted, linux, x64, cwlab-ci-isolated]
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
- name: Validate docker-compose
run: docker compose -f docker-compose.yml config >/dev/null
env:
Expand Down
11 changes: 9 additions & 2 deletions ARCHITECTURE.md
Original file line number Diff line number Diff line change
Expand Up @@ -221,14 +221,21 @@ explicitly documented deployment-controller responsibility.

## Automation boundaries

- The hourly PR steward advances only trusted same-repository PRs with exact-head
approvals and required Checks.
- Protected PR maintenance belongs to the organization's central
`pr-review-merge-scheduler.yml`; Keyverse's local hourly steward was removed
in #140. Exact-head approvals and required Checks remain mandatory. The local
product-development workflow does not own review or merge authority.
- The hourly product-development workflow runs OpenCode through
`NVIDIA_NIM_API_KEY`, not Copilot Agent Tasks or `COPILOT_GITHUB_TOKEN`.
- The model workspace has no Git metadata, GitHub credential, Actions OIDC,
publication token, or upstream NIM credential.
- Generated text patches are bounded, digest-sealed, independently verified on
a fresh checkout, and published only as a draft PR.
- Repository `ci.yml` proposes the dedicated `CWL CI isolated` group plus
self-hosted/Linux/x64/isolation labels for all three credential-free CI jobs.
Checkout does not persist credentials. This source configuration is not proof
of registered disposable capacity, network isolation, cleanup, or executed
Checks; operator acceptance remains required before public PR execution.
- Existing review agents and their credential system remain independent.
- Neither automation path may self-approve, bypass protection, merge unverified
work, tag, or publish a release.
Expand Down
10 changes: 10 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,16 @@ Keep a Changelog, and releases use semantic versioning.

### Fixed

- Proposed dedicated-group isolated self-hosted routing for the three local CI
jobs after a billing lock prevented hosted job startup. Checkout no longer
persists its token; all test/coverage/build gates remain unchanged. Actual
isolated runner eligibility and execution remain rollout prerequisites.

- Removed the obsolete local PR-steward tests after #140 centralized PR
maintenance. Added an ownership regression and aligned architecture and
operator guidance without restoring local merge automation or changing
production identity behavior.

- Prevented relying-party inventory from silently accepting a KV key/body
identity mismatch, rejected unsafe live or `Location`-derived client UUIDs,
and aligned exact client discovery with Keycloak's documented
Expand Down
67 changes: 67 additions & 0 deletions docs/doctoring/ci-isolated-runner-routing.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
# Local CI isolated-runner routing

**Date:** 2026-10-04
**Status:** Proposed source routing; runtime eligibility and protected integration pending

## Measured cause and bounded repair

PR143 head `0066598098263bd0064e199c9ddb6279913e1ba0` Ready event produced
CI run `37183133580`. GraphQL check annotations for each of the three jobs
state that the job did not start because the account was locked for a billing
issue. That is pre-execution admission failure, not a product test failure.

The existing organization self-hosted migration direction supplies a safe
source contract: `.github#2565` at `ab0c865989012c88d2c10c717f6649a76ea49e27`
uses dedicated group `CWL CI isolated` plus isolation/platform labels. The
current Keyverse proposal uses that exact group and Linux/x64 capability shape,
not a label-only match or privileged central control pool. All three check
names, command blocks, Python 3.12 contract, pins, permissions and event guards
are retained. Checkout explicitly disables credential persistence.

Two source-contract tests failed before changes: hosted selector instead of
exact group/labels, and missing `persist-credentials: false`. Both pass after
changes. These static controls prove intended source selection, not successful
GitHub runner assignment or execution. Existing full gates must run on the
complete final candidate and hosted current head.

## Authority and operation boundary

GitHub documents groups as runner-access organization boundaries; labels narrow
capability selection within the group. Neither selected labels nor YAML proves
machine isolation. Public/fork PR code must not use persistent privileged
runners. `persist-credentials: false` prevents checkout from retaining its
read token for later Git use; it is not a claim that a runner is credential-free
or that trusted GitHub actions never receive their normal job token.

Existing operator issue `linux-cluster-ops#326` retains disposable capacity,
private-service denial, clean-per-job state, registration custody, minimum
repository access, tool-image and real canary requirements. Its observed
credential-free point probes do not establish complete kernel-enforced denial
or a registered eligible pool. The proposal must remain Draft until those
operational boundaries and fresh current-head checks/review are satisfied.
No runner registration, relabeling, ACL expansion, billing purchase, credential
change, protected-gate weakening or release is performed by this source repair.

The separate hourly product-development workflow is unchanged and is not part
of this three-job routing claim; do not claim organization-wide migration.

## References — APA 7th

GitHub. (n.d.). *Managing access to self-hosted runners using groups*. GitHub
Docs. Retrieved October 4, 2026, from
https://docs.github.com/en/actions/how-tos/manage-runners/self-hosted-runners/manage-access

GitHub. (n.d.). *Choosing the runner for a job*. GitHub Docs. Retrieved October
4, 2026, from
https://docs.github.com/en/actions/how-tos/write-workflows/choose-where-workflows-run/choose-the-runner-for-a-job

GitHub. (n.d.). *Checkout* [Source code documentation]. Retrieved October 4,
2026, from https://github.com/actions/checkout/blob/main/README.md

ContextualWisdomLab. (2026). *All self-hosted runner routing* (.github PR #2565,
source snapshot `ab0c865989012c88d2c10c717f6649a76ea49e27`).
https://github.com/ContextualWisdomLab/.github/pull/2565

ContextualWisdomLab. (2026). *Register isolated ContextualWisdomLab Actions runner
on s1 (not b1-b5)* (linux-cluster-ops issue #326).
https://github.com/ContextualWisdomLab/linux-cluster-ops/issues/326
88 changes: 88 additions & 0 deletions docs/doctoring/pr-governance-ownership.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
# PR governance ownership after local steward retirement

**Date:** 2026-10-03
**Scope:** local verification of existing PR #143/#154 remediation; not protected promotion

## Root cause and retained owner

Protected source `7d9151cd2da260e118020c938c7358e2ee75d541` includes
#140's deletion of `.github/workflows/hourly-pr-steward.yml`, but retains five
tests that open that deleted file. The complete local account-unification
suite reproduced five `FileNotFoundError` failures before any repair.

PR #154 at `85deb471a2e5de412e0f378eadd537750bb8476c` removes the obsolete
module. PR #143 at `dc2ca97ae7a33d4660d0179dd6050b57e9faa076` additionally
updates the operating guide. This local candidate reuses #143's two-path
repair and adds ownership regressions, architecture clarification, and this
record; it does not create another PR or adopt either remote branch's authority.
The operator wording is narrowed: observing central workflow source does not
prove its dispatch or effective protection on Keyverse.

## Interpretation and regression boundary

- **Repository policy:** central `pr-review-merge-scheduler.yml` owns PR
maintenance; local product authoring must not become another merge owner.
- **Vendor contract:** reusable workflows are called at job level and use
`workflow_call`. A reusable definition's existence is not execution evidence.
- **Protection boundary:** local tests do not replace required hosted Checks,
independent current-head review, unresolved-thread disposition, or protection.
- **Measured RED:** both new ownership tests failed before the repair: the
retired test remained and architecture did not name the central owner.
- **Measured GREEN:** the replacement tests pass after the repair. They check
that the retired workflow/test stays absent, the local product workflow stays
present, and current operating/architecture prose names central ownership.
- **Harness correction:** a case-sensitive `exact-head` assertion rejected
sentence-initial `Exact-head`; only the assertion was made case-insensitive.
- **Review correction:** independent review rejected the initial candidate
because publication-race guidance still depended on a subsequent hourly
steward. A third test reproduced that contradiction before prose was changed
to the normal protected PR path under central governance. The replacement
makes no claim that central dispatch has executed.
- **Hosted review sensitivity correction (2026-10-04):** CodeRabbit noted
that central-owner wording could coexist with the former statement that the
hourly PR steward advances trusted PRs. Two copied-document controls first
passed unchanged guidance, then restored that contradiction; both initially
failed because the contract did not reject it. The contract now rejects the
exact obsolete active-owner statement in both documents while preserving
historical retirement references. These controls do not claim general
natural-language contradiction detection or central execution evidence.
- **Non-goals:** no production Python, credential, workflow, review gate,
passwordless policy, SCIM contract, or release version is changed. This is
static ownership and local regression evidence, not live login, Keycloak,
PostgreSQL, or central scheduler acceptance.

## Inventory and product-priority decision

Read-only GitHub inventory on 2026-10-03 returned 29 distinct open PRs and
11 distinct issues (the Issues API also returns PRs, which were excluded).
PRD-FR-001 through PRD-FR-010 and gap G0 retain passwordless, verified-email,
side-effect-free preflight, exact reconciliation, and protected queue rules.
The baseline's August inventory is historical, not today's queue.

The existing CI repair takes priority over opening a new product-gap proposal.
Key-vault, authorization, consumer subject/signer trust, and immutable release
requests (#152, #102/#103, #155, #156, #158, #160) remain separate unresolved
owner scopes; this repair does not claim to satisfy them. Likewise issue #131's
orchestrator routing work remains on its existing candidate paths.

GitHub CLI authentication failed. Public API/browser reads and normal git fetch
worked without changing credentials. No remote write, approval, merge, release,
production deployment, or credential migration was performed.

## References — APA 7th

GitHub. (n.d.). *Reuse workflows*. GitHub Docs. Retrieved October 3, 2026, from
https://docs.github.com/en/actions/how-tos/reuse-automations/reuse-workflows

GitHub. (n.d.). *About protected branches*. GitHub Docs. Retrieved October 3,
2026, from
https://docs.github.com/en/repositories/configuring-branches-and-merges-in-your-repository/managing-protected-branches/about-protected-branches

ContextualWisdomLab. (2026). *Remove redundant hourly-pr-steward workflow*
(Keyverse PR #140; commit `d8ff4eded4f82ad5e72deec940cd73e1583b4640`).
https://github.com/ContextualWisdomLab/keyverse/pull/140

ContextualWisdomLab. (2026). *Remove stale hourly-pr-steward test left behind by
#140* (Keyverse PR #143; reviewed source snapshot
`dc2ca97ae7a33d4660d0179dd6050b57e9faa076`).
https://github.com/ContextualWisdomLab/keyverse/pull/143
30 changes: 25 additions & 5 deletions docs/operations/hourly-product-development.md
Original file line number Diff line number Diff line change
@@ -1,19 +1,37 @@
# Hourly product-development loop

Keyverse separates protected pull-request maintenance from autonomous product
development. The schedules are offset so the merge loop has time to settle the
repository before a new product slice is considered.
development. Protected PR maintenance is owned by the organization's central
`pr-review-merge-scheduler.yml`, not a second Keyverse-local merge loop.
Keyverse's former hourly steward was removed in #140. Current-head review,
required Checks, and branch protection remain mandatory; local test success
alone does not prove central dispatch, approval, or merge readiness.

| Minute (UTC) | Workflow | Responsibility |
| --- | --- | --- |
| `17 * * * *` | `hourly-pr-steward.yml` | Update trusted PR branches, require approval and required Checks, then arm exact-head auto-merge. |
| `41 * * * *` | `hourly-product-development.yml` | When the PR queue is empty and exact `main` is healthy, use OpenCode with NVIDIA NIM to produce one bounded buyer-visible draft PR. |

The development scheduler never approves or merges its own work and never
publishes a release. The existing review-agent workflows and their credentials
remain unchanged. Review, repair, revalidation, and merge stay owned by the
normal protected PR path.

## Local CI admission prerequisite

The local `ci.yml` routes its three jobs through the dedicated `CWL CI isolated`
runner group with `self-hosted`, `linux`, `x64`, and `cwlab-ci-isolated` labels.
There is no hosted fallback or persistent control-runner substitution, and each
checkout uses `persist-credentials: false`. The commands, Python 3.12 contract,
coverage thresholds, action pins, and Draft/closed-PR admission remain unchanged.

This is proposed source routing, not activated capacity. Before public PR jobs
execute, the existing isolated-runner operator must prove selected-repository
eligibility, disposable per-job state, host/private-network denial, tool-image
acceptance, and cleanup. Central `.github#2565` and `linux-cluster-ops#326` retain
those existing owner gates. Do not relabel privileged runners, widen access,
change billing, or reuse a token merely to drain the queue. Required Checks and
independent current-head approval remain mandatory for protected merge.

## Architecture

The workflow uses three jobs with different trust levels.
Expand Down Expand Up @@ -199,8 +217,10 @@ a fresh checkout. It creates one run-unique branch named

Workflow concurrency serializes scheduled runs, but GitHub does not provide an
atomic compare-base-and-create-PR operation. If another actor opens a PR in the
final network interval, branch protection and the subsequent hourly steward
remain authoritative. During a duplicate-publication incident, revoke
final network interval, branch protection and the normal protected PR path
under central PR governance remain authoritative. This does not establish that
central dispatch has executed for the new head. During a duplicate-publication
incident, revoke
`OPENCODE_PRODUCT_DEVELOPMENT_TOKEN`, close all but one draft, preserve the
Actions logs and artifacts, add a reproducing contract test, and only then
restore the token.
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
"""Fail-closed routing contracts for the repository's credential-free CI."""
from pathlib import Path

import yaml

ROOT = Path(__file__).resolve().parents[3]


def test_product_ci_uses_only_the_dedicated_isolated_runner_group() -> None:
"""Public PR code must never run on persistent privileged control capacity."""
workflow = yaml.safe_load((ROOT / ".github/workflows/ci.yml").read_text())
assert set(workflow["jobs"]) == {
"account-unification-tests", "realm-config-validates", "compose-config-validates"
}
assert workflow["permissions"] == {"contents": "read"}
for job in workflow["jobs"].values():
assert job["runs-on"] == {
"group": "CWL CI isolated",
"labels": ["self-hosted", "linux", "x64", "cwlab-ci-isolated"],
}


def test_isolated_ci_checkout_does_not_persist_its_read_token() -> None:
"""Checked-out PR test code must not inherit a stored GitHub credential."""
workflow = yaml.safe_load((ROOT / ".github/workflows/ci.yml").read_text())
for job in workflow["jobs"].values():
checkouts = [
step for step in job["steps"]
if str(step.get("uses", "")).startswith("actions/checkout@")
]
assert len(checkouts) == 1
assert checkouts[0].get("with", {}).get("persist-credentials") is False
Loading