Program integration: M06 Codex execution adapter (#91) + M10 distribution and acceptance (#95) #108

Merged
adrian.tkacz merged 25 commits from program/m06-m10-final-wave into develop 2026-09-21 16:35:25 +00:00
Member

Program wave: M06 Codex Stage 2 (#91) + M10 distribution & acceptance (#95)

One integration PR for the final execution-program wave. Base: 4df6099 (current develop head at branch time). Left open for human review; not merged by any agent.

Workstream A — M06 Codex execution adapter (issue #91, Stage 2)

  • scarcity_router/worker_codex_adapter.py: CodexLocalAdapter (id codex) implementing the M05 LocalAdapter protocol; server side unchanged (worker_bridged + local_adapter_id, D-049).
  • Official App Server stable surface only (stdio JSONL; initialize/account/read/model/list/thread/start/thread/inject_items/turn/start/turn/interrupt — enforced by a load-bearing wire-method allowlist test); experimental API never enabled; forbidden surfaces never sent.
  • Bounded discovery: pinned --codex-bin → PATH → U-001 extension layout; Desktop bundles never discovered (Stage-1 UNKNOWN).
  • Version gate codex-cli >= 0.154.0 (evidenced generation), fail-closed; strict bounded JSONL parsing (line/byte/event/depth/unknown-notification budgets).
  • Auth strictly provider-managed and read-only: account/read typed verdict requiring chatgpt; the adapter performs no provider-state mutation (D-018 stays collector-only, unamended — this was the one review blocker, resolved by removal, not by decision amendment); API-key never silently converts to PAYG; stale auth → auth_unverified with official codex login remediation.
  • Isolation: adapter-owned 0o700 controlled CODEX_HOME with minimal generated config; per-turn workspaceWrite sandbox (writableRoots=[scratch], network off, approvals declined, approvalPolicy: never); ephemeral threads; minimal constructed env; scratch dirs under the worker state dir.
  • Exact model/effort binding verified against model/list before execution; client tool_calls and unevidenced parameters rejected before execution (fail closed); bounded turn/interrupt cancellation; crash-before-start → permanent, loss-after-start → ambiguous (never retried); honest usage mapping.

Workstream B — M10 distribution, installation, update and acceptance (issue #95, M10-A + M10-B)

  • Linux: uv tool install scarcity-router path; new scarcity-router-worker console script (frozen three untouched); systemd user service example; package-check verifies all 4 entry points.
  • Server container: non-root (uid 10001), persistent 0o700 data volume, healthcheck, secure defaults, single process — built and live-verified (health, 401s, TLS right/wrong-CA, restart persistence, non-loopback-without-TLS refused); examples/docker-compose.yml.
  • Windows worker: PyInstaller spec (tracked; the stock *.spec gitignore swallow was a review blocker, fixed with a negation rule and proven via clean-archive test runs) + minimal tray (optional extra, lazy imports, no routing duplication, no secrets); release workflow builds scarcity-worker-X.Y.Z-windows-x64.zip; MSIX is a fail-closed seam (EXTERNAL_RELEASE_GATE: WINDOWS_CODE_SIGNING).
  • Release integrity: new finalize-release-bundle job attests the zip + the final SHA256SUMS (checksum file never modified after attestation); tag/SemVer/version-literal/main-ancestry guards untouched; Forgejo keeps sole development CI; no GHCR publish job until the frozen contract's first-release insertion (image itself is in-tree, built, unpublished).
  • Update path: uv tool upgrade / container tag pull / reinstall; no auto-update.
  • E2E/acceptance: 16 non-Codex scenarios + 11 real-TLS tests (trustme, real sockets, no verify=false anywhere) + 23 security-acceptance tests (D-044 matrix) + 14 M10-B Codex tests through the full composed stack (client → coordinator → worker protocol → adapter → deterministic fake App Server), incl. ownership, cancellation, ambiguity, usage, isolation, leakage lines. Scenario→test mapping in docs/m10-acceptance.md; security matrix in docs/m10-security-acceptance.md.
  • Real-binary probe (local, opt-in, skip-safe): extension codex-cli 0.154.0-alpha.6.2 — real initialize handshake with controlled home adopted; unsigned-in account/read fails closed honestly. No turn.

Review and audit trail (all reviews fresh, GLM-5.3 non-Flash, MAX)

Gate Result
M06 initial review CHANGES_REQUESTED (1 blocker: D-018 refresh extended silently) → remediation r1 (removal + 6 defers) → APPROVE @ d78a905
M10 initial review CHANGES_REQUESTED (1 blocker: untracked worker.spec breaking fresh checkouts/tagged builds) → remediation r1 (track + attestation reconciliation + docs) → APPROVE @ 20d0a0c
Integration one semantic conflict (worker_client.py tray seam × codex registry; state-dir threading so the Codex controlled home follows the identity store)
Final integration audit AUDIT_PASS — 32/32 checklist points PASS, provenance byte-identity verified, zero blockers

Validation at integration HEAD d5cdc17

uv sync --only-dev ✓ · make check 1846 tests OK (~520 s) · uv run basedpyright 0/0/0 · git diff --check ✓ · make package-check 9/9 PASS · make guardrails 40 tests OK · actionlint both workflows clean · branch-diff secrets scan clean (12,305 added lines) · wheel/sdist/container built and inspected from a clean archive of this exact HEAD.

Recorded external gates (not blockers; owner actions later)

  • EXTERNAL_RELEASE_GATE: WINDOWS_CODE_SIGNING — MSIX seam fails closed even with a secret configured; unsigned zip builds.
  • EXTERNAL_ACCEPTANCE_GATE: LIVE_WINDOWS_ACCEPTANCE — Windows-native runtime never executed here.
  • EXTERNAL_ACCEPTANCE_GATE: LIVE_CODEX_SUBSCRIPTION — a live turn needs an owner-performed official codex login inside a dedicated controlled home (isolation forbids ~/.codex; token copying forbidden).
  • PYPI_TRUSTED_PUBLISHER + Forgejo runner/branch-protection owner actions unchanged from #97 (never claimed configured).
  • Follow-ups recorded: #106 (administrative compatibility-evidence cells), #107 (curated Codex catalog binding with D-025 provenance).

Explicit confirmations

Nothing merged to develop by this PR's authors; main untouched; no release published; no ZCode execution adapter (D-047 stands); no credentials committed; no prompt/response content in default logs/audit; no automatic inference retry/failover; no generic worker shell/command execution; no private Creatidy infrastructure required for normal OSS use.

## Program wave: M06 Codex Stage 2 (#91) + M10 distribution & acceptance (#95) One integration PR for the final execution-program wave. Base: `4df6099` (current `develop` head at branch time). **Left open for human review; not merged by any agent.** ### Workstream A — M06 Codex execution adapter (issue #91, Stage 2) - `scarcity_router/worker_codex_adapter.py`: `CodexLocalAdapter` (id `codex`) implementing the M05 `LocalAdapter` protocol; server side unchanged (`worker_bridged` + `local_adapter_id`, D-049). - Official App Server stable surface only (stdio JSONL; `initialize`/`account/read`/`model/list`/`thread/start`/`thread/inject_items`/`turn/start`/`turn/interrupt` — enforced by a load-bearing wire-method allowlist test); experimental API never enabled; forbidden surfaces never sent. - Bounded discovery: pinned `--codex-bin` → PATH → U-001 extension layout; Desktop bundles never discovered (Stage-1 UNKNOWN). - Version gate `codex-cli >= 0.154.0` (evidenced generation), fail-closed; strict bounded JSONL parsing (line/byte/event/depth/unknown-notification budgets). - Auth strictly provider-managed and read-only: `account/read` typed verdict requiring `chatgpt`; **the adapter performs no provider-state mutation** (D-018 stays collector-only, unamended — this was the one review blocker, resolved by removal, not by decision amendment); API-key never silently converts to PAYG; stale auth → `auth_unverified` with official `codex login` remediation. - Isolation: adapter-owned `0o700` controlled `CODEX_HOME` with minimal generated config; per-turn `workspaceWrite` sandbox (`writableRoots=[scratch]`, network off, approvals declined, `approvalPolicy: never`); ephemeral threads; minimal constructed env; scratch dirs under the worker state dir. - Exact model/effort binding verified against `model/list` before execution; client `tool_calls` and unevidenced parameters rejected before execution (fail closed); bounded `turn/interrupt` cancellation; crash-before-start → permanent, loss-after-start → ambiguous (never retried); honest usage mapping. ### Workstream B — M10 distribution, installation, update and acceptance (issue #95, M10-A + M10-B) - Linux: `uv tool install scarcity-router` path; new `scarcity-router-worker` console script (frozen three untouched); systemd **user** service example; `package-check` verifies all 4 entry points. - Server container: non-root (uid 10001), persistent `0o700` data volume, healthcheck, secure defaults, single process — **built and live-verified** (health, 401s, TLS right/wrong-CA, restart persistence, non-loopback-without-TLS refused); `examples/docker-compose.yml`. - Windows worker: PyInstaller spec (tracked; the stock `*.spec` gitignore swallow was a review blocker, fixed with a negation rule and proven via clean-archive test runs) + minimal tray (optional extra, lazy imports, no routing duplication, no secrets); release workflow builds `scarcity-worker-X.Y.Z-windows-x64.zip`; MSIX is a **fail-closed seam** (`EXTERNAL_RELEASE_GATE: WINDOWS_CODE_SIGNING`). - Release integrity: new `finalize-release-bundle` job attests the zip + the **final** `SHA256SUMS` (checksum file never modified after attestation); tag/SemVer/version-literal/main-ancestry guards untouched; Forgejo keeps sole development CI; no GHCR publish job until the frozen contract's first-release insertion (image itself is in-tree, built, unpublished). - Update path: `uv tool upgrade` / container tag pull / reinstall; no auto-update. - E2E/acceptance: 16 non-Codex scenarios + 11 real-TLS tests (trustme, real sockets, no `verify=false` anywhere) + 23 security-acceptance tests (D-044 matrix) + 14 M10-B Codex tests through the **full composed stack** (client → coordinator → worker protocol → adapter → deterministic fake App Server), incl. ownership, cancellation, ambiguity, usage, isolation, leakage lines. Scenario→test mapping in `docs/m10-acceptance.md`; security matrix in `docs/m10-security-acceptance.md`. - Real-binary probe (local, opt-in, skip-safe): extension `codex-cli 0.154.0-alpha.6.2` — real `initialize` handshake with controlled home adopted; unsigned-in `account/read` fails closed honestly. No turn. ### Review and audit trail (all reviews fresh, GLM-5.3 non-Flash, MAX) | Gate | Result | | --- | --- | | M06 initial review | CHANGES_REQUESTED (1 blocker: D-018 refresh extended silently) → remediation r1 (removal + 6 defers) → **APPROVE** @ `d78a905` | | M10 initial review | CHANGES_REQUESTED (1 blocker: untracked `worker.spec` breaking fresh checkouts/tagged builds) → remediation r1 (track + attestation reconciliation + docs) → **APPROVE** @ `20d0a0c` | | Integration | one semantic conflict (`worker_client.py` tray seam × codex registry; state-dir threading so the Codex controlled home follows the identity store) | | Final integration audit | **AUDIT_PASS** — 32/32 checklist points PASS, provenance byte-identity verified, zero blockers | ### Validation at integration HEAD `d5cdc17` `uv sync --only-dev` ✓ · `make check` 1846 tests OK (~520 s) · `uv run basedpyright` 0/0/0 · `git diff --check` ✓ · `make package-check` 9/9 PASS · `make guardrails` 40 tests OK · actionlint both workflows clean · branch-diff secrets scan clean (12,305 added lines) · wheel/sdist/container built and inspected from a clean archive of this exact HEAD. ### Recorded external gates (not blockers; owner actions later) - `EXTERNAL_RELEASE_GATE: WINDOWS_CODE_SIGNING` — MSIX seam fails closed even with a secret configured; unsigned zip builds. - `EXTERNAL_ACCEPTANCE_GATE: LIVE_WINDOWS_ACCEPTANCE` — Windows-native runtime never executed here. - `EXTERNAL_ACCEPTANCE_GATE: LIVE_CODEX_SUBSCRIPTION` — a live turn needs an owner-performed official `codex login` inside a dedicated controlled home (isolation forbids `~/.codex`; token copying forbidden). - `PYPI_TRUSTED_PUBLISHER` + Forgejo runner/branch-protection owner actions unchanged from #97 (never claimed configured). - Follow-ups recorded: #106 (administrative compatibility-evidence cells), #107 (curated Codex catalog binding with D-025 provenance). ### Explicit confirmations Nothing merged to `develop` by this PR's authors; `main` untouched; no release published; no ZCode execution adapter (D-047 stands); no credentials committed; no prompt/response content in default logs/audit; no automatic inference retry/failover; no generic worker shell/command execution; no private Creatidy infrastructure required for normal OSS use.
kilo added 19 commits 2026-09-21 05:35:43 +00:00
Issue #95 distribution foundation:

- add the scarcity-router-worker console script (the M05 worker parser
  already anticipated this invoked name); the frozen three scripts keep
  their names and semantics, package_check now inspects and smoke-helps
  all four entry points;
- serve GET /healthz on the composed server's control plane with the
  frozen D-028 liveness semantics ({"status":"ok"}, no collector,
  no store, no auth data) so container/service managers get an honest
  liveness probe (D-045: the path sets are disjoint and may share one
  listener); documented in docs/control-surface.md;
- scarcity-router --version renders the single authoritative version;
  the server startup banner reports it (version visible in logs);
- examples/scarcity-router-worker.service: systemd USER unit for Linux
  worker background operation with start/stop/status/logs recipes.
One container, one process (D-041): python:3.12-slim, multi-stage wheel
build, non-root runtime user (uid/gid 10001), /data volume as the only
write path, EXPOSE 8787, HEALTHCHECK against the unauthenticated
GET /healthz liveness endpoint, no baked secrets, no Docker socket,
version visible in the startup banner/logs.

examples/docker-compose.yml documents the real flag surface only
(loopback host-networking default; LAN/VPN exposure strictly via the
verified-TLS flags D-044 requires) plus update, volume and backup notes.

Verified live on this host (Docker 29.7.2, WSL2 backend): image builds;
/healthz serves {"status":"ok"}; healthcheck reaches healthy; single
process confirmed; store survives restart (second bootstrap 409);
non-root user confirmed; verified-TLS bind serves 200 with the correct
CA, wrong CA fails verification (curl exit 60), plaintext refused
(exit 52). Not published anywhere; the GHCR publication contract stays
the recorded future contract in docs/release-engineering.md.
Issue #95, per the D-046 Windows artifact contract:

- scarcity_router/windows_tray.py: the tray's platform-independent core
  (state model running/disconnected/error, pure status text, bounded
  redacted worker log, run_tray_worker assembly with cooperative
  restart/quit and never-concurrent runtimes, tray_main entry reusing
  the worker CLI's parser and allowlist builder via the new public
  open_worker_store/build_local_adapter_registry seams);
- packaging/windows/: the PyInstaller spec (one-dir, windowless,
  pystray._win32 pinned), the thin launcher, and the packaging-owned
  pystray adapter (lazy imports, programmatic state-colored icon, no
  module-level GUI imports — kept out of the library so the core
  package stays dependency-clean);
- pyproject: optional 'tray' extra (pystray, Pillow); package_check
  asserts the core wheel's runtime dependency set is still exactly mcp
  with only the two extra-conditional entries;
- .github/workflows/release.yml: build-windows-worker job on
  windows-latest from the exact tagged commit producing
  scarcity-worker-X.Y.Z-windows-x64.zip, checksummed into SHA256SUMS
  and attached to the GitHub Release; the MSIX direction is a
  fail-closed seam behind the signing secret
  (EXTERNAL_RELEASE_GATE: WINDOWS_CODE_SIGNING; no signature is ever
  fabricated);
- tests: tray state/runloop/log suites with injected fakes, static
  spec-shape verification with stubbed PyInstaller callables, adapter
  lazy-import and off-Windows guard tests;
- docs/release-engineering.md records the realized ZIP contract and the
  signing gate. Live Windows runner/end-user acceptance stays recorded
  as EXTERNAL_ACCEPTANCE_GATE: LIVE_WINDOWS_ACCEPTANCE.
Issue #91 Stage 2: one worker-local adapter (allowlist id "codex") drives
the official codex app-server over stdio JSONL through the existing M05
worker bridge (channel worker_bridged, resource local_adapter_id per
D-049). No second worker protocol, no server-to-local-Codex path.

- discovery: --codex-bin pin (regular, executable, non-symlink), then
  PATH, then the U-001 extension layout (collector discovery reused by
  import); Desktop bundles are not discovered (Stage 1: UNKNOWN)
- version contract: codex-cli >= 0.154.0 required; failed/unparseable
  probes leave the resource ineligible
- auth: D-018 boundary absolute; official account/read verdict requiring
  account.type == "chatgpt"; API-key auth is not an execution resource;
  bounded D-018 refresh (-32603 trigger, one refresh + one retry) with a
  failed recovery staying auth_unverified
- isolation: adapter-owned controlled CODEX_HOME (0o700, minimal
  config.toml, handshake-verified adoption), ephemeral threads,
  per-attempt scratch cwd, workspaceWrite sandbox pinned to the scratch
  root with networkAccess false, approvalPolicy never plus a defensive
  cancel answer for approval server-requests, minimal child env,
  process-group shutdown with proven reaping; bubblewrap required on
  Linux/WSL2; WSL1 and non-evidenced platforms ineligible
- mapping: system/developer -> base/developerInstructions; prior
  user/assistant -> inject_items Responses items; final user message ->
  turn input; json_schema -> outputSchema (bounds-checked); model slug +
  effort verified against model/list before execution and pinned per
  turn; tool-bearing requests rejected before anything executes
- lifecycle: strict JSONL budgets, one invocation per call (no retry),
  process loss after turn start reported as unknown (ambiguous), safe
  notes only from the documented codexErrorInfo vocabulary
- snapshots: honest closed-vocabulary eligibility observations; binary
  installed is not eligible
- worker CLI: --allow-codex / --codex-resource / --codex-bin; the
  package-write guardrail now names the adapter's bounded controlled-home
  provisioning as the second allowed provisioning path
A scripted fake codex binary (spawned through the adapter's injected
process seam; no real binary, no live quota, synthetic strings only)
plus 71 behavior tests covering the Stage 2 acceptance areas: discovery
paths (pinned/PATH/extension layout, non-symlink pin rule), the version
contract, controlled-home creation and isolation posture (spawn spec,
env, thread/sandbox/approval parameters, no dangerFullAccess), auth
diagnostics (missing, API-key, chatgpt ok, bounded D-018 refresh and
its failed-recovery bound), model/effort exact binding, role/history
mapping, structured output, pre-execution tool rejections, streaming
order, protocol drift (malformed/duplicate-keys/deep/oversized lines),
bounded unknown notifications, honest usage mapping, cancellation
(before start, mid-turn with interrupt, deadline), approval
cancel-not-accept, startup timeout, definitive vs ambiguous process
loss, single-invocation (no retry), allowlist and resource-ownership
enforcement, stderr capture bounds, reaping/orphan checks, snapshots,
and the worker CLI wiring.
- codex-adapter-stage1-evidence.md: dated Stage 2 implementation section
  (re-verified live probes of 2026-09-20 -- version, initialize
  structure, interleaved notifications, model/list error shape on a
  fresh controlled home), the pinned rust-v0.155.1 protocol shapes, the
  implemented isolation profile, the Stage 2 compatibility-matrix cells
  with evidence classes, and the honest not-tested/gap list
- providers.md: M06 status section -- discovery, version contract, D-018
  auth boundary, isolation profile, forbidden surfaces, mapping,
  snapshots, per-installation-type remediation (Desktop-only, CLI,
  VS Code, controlled-home sign-in, Windows, WSL) and worker
  registration
- execution-surface.md: the M06 Codex adapter is delivered through the
  worker_bridged channel as a worker-local adapter (D-049);
  local_app_adapter itself remains unregistered
Review verdict CHANGES_REQUESTED on 83b23b2: one MERGE_BLOCKER, six
DEFER items (program controller chose remediation (b) for the blocker).

MERGE_BLOCKER (option b): the execution adapter is now STRICTLY READ-ONLY
against the provider. The single owner-approved mutation exception — the
bounded managed-auth refresh on the evidenced rate-limits -32603 shape —
stays collector-only (D-018, docs/decisions.md, unamended); it is no
longer performed by verify_account_auth on either the dispatch or the
snapshot path. Any account/read protocol error fails closed to the typed
auth_unverified verdict with the official interactive sign-in
remediation (browser/device code; never token copying). Module docstring
corrected; docs/providers.md 'the D-018 recovery, unchanged' wording
corrected; Stage-2 evidence section records the correction. Tests pin
that exactly ONE read-only account/read is sent and NO refreshToken
request ever appears, on both paths.

DEFER fixes:
1. trailing whitespace removed; git diff --check 4df6099..HEAD clean
2. max_output_tokens / non-empty generation_params are rejected BEFORE
   execution (request_parameters_unsupported, refuse-not-drop like M04);
   discriminating tests added; refusal recorded in docs and matrix notes
3. Stage-2 matrix cells now use single conservative D-043 values
   (PARTIAL where live turn-level verification is pending); the
   adapter-mapping evidence moved into the cell notes, substance unchanged
4. the trace-methods helper is load-bearing: a new test asserts the
   observed wire surface equals an explicit stable-method allowlist
   (initialize, initialized, account/read, model/list, thread/start,
   thread/inject_items, turn/start, turn/interrupt) across completed and
   cancelled calls, and that no forbidden method name ever appears; the
   fake now traces every incoming protocol message exactly once
5. cumulative message accounting uses a running counter instead of the
   O(n^2) per-delta sum
6. an incomplete model/list catalog after the bounded page budget fails
   closed with the explicit model_listing_budget_exceeded reason (never a
   generic model_not_listed); pinned by a pagination-loop test
Reviewed head d78a905: initial review CHANGES_REQUESTED (one MERGE_BLOCKER:
D-018 refresh exception silently extended to the adapter surface), remediation
round 1 dropped the mutation (adapter strictly read-only, D-018 collector-only
unamended) and fixed six DEFER items; fresh GLM-5.3 re-review: APPROVE.
tests/m10_fixtures.py: real-clock composed-server harness, SSE helpers,
trustme-backed ephemeral certificate materials and polling utilities.

tests/test_e2e_acceptance.py (scenarios 1-5, 13-16): recommendation-only
surface (CLI version/help, frozen REST v1 with synthetic collectors),
composed-server liveness (GET /healthz), onboarding/login/session,
client-key creation (shown once, hash stored, identity separation),
execution ingress with an evidenced matrix (streaming SSE framing),
store restart/persistence with future-schema refusal, idempotent v2
migration, permissions enforcement, remote M08 bridge against the real
server, doctor/diagnostics and secret-free export/audit after a real
dispatch (prompt/response/credential markers absent everywhere).

tests/test_e2e_execution.py (scenarios 6-12): configured provider
end to end (non-streaming + honest fail-closed streaming without matrix
evidence), ollama preset without credentials, worker pairing over real
verified TLS, worker-bridged Ollama execution end to end (server →
coordinator → real worker session → local adapter → synthetic origin),
exact resource ownership (hijacked reports rejected, dispatch reaches
only the owner), client-disconnect cancellation propagation over a real
socket, and ambiguous worker disconnect resolved interrupted with no
duplicate dispatch on reconnect.

tests/test_tls_acceptance.py: verified-TLS liveness, wrong CA / wrong
hostname / expired certificate refusals, plaintext refusal, worker-side
verification on real sockets, and an AST-scanned proof that no TLS
verification bypass exists in product code.

tests/test_security_acceptance.py: authentication boundaries across the
three identity classes, CSRF, immediate revocation for client keys and
workers, router-loop marker and own-origin provider refusal, unknown
client fields refused, plain-HTTP/credential-URL provider configs
refused, cross-origin redirects refused and never followed, protocol
vocabulary closed (no shell/ssh), oversized/deep/malformed input bounds,
store and worker-store permission and schema discipline.

trustme joins the dev dependency group (test-only).
- docs/m10-security-acceptance.md: the D-044 security acceptance matrix
  mapping every scenario to its M10 test (and prior module coverage),
  plus the recorded external gates;
- docs/m10-acceptance.md: platform support table (built/tested vs
  contracted vs seam), measured first-run sequences and friction notes,
  external gates (WINDOWS_CODE_SIGNING, LIVE_WINDOWS_ACCEPTANCE,
  PYPI_TRUSTED_PUBLISHER) and the fail-closed behaviors verified along
  the way;
- README: four console commands, the optional-gateway deployment guide
  (server container, worker pairing, systemd unit, updates/uninstall)
  and pointers to the acceptance records;
- package_check: case-insensitive conditional-extra match (pillow).
The stock Python .gitignore pattern '*.spec' silently excluded the
committed Windows worker build spec: the file existed only untracked in
the authoring worktree, so a fresh checkout could not run
tests.test_windows_packaging (the PR's own required check fails) and
build-windows-worker could never produce the zip from a tagged commit
(D-046 exact-tagged-commit provenance). The spec is source, not build
residue: add a negation rule so it stays visible in git status.
The windows worker zip used to be appended to SHA256SUMS inside
publish-github-release, after the bundle's attestation: the published
checksum file no longer matched its attested subject digest and the zip
itself carried no Sigstore attestation (build-windows-worker runs with
contents:read only).

Restructure into a finalization stage: build attests exactly the
artifacts whose bytes are final there (wheel + sdist); the new
finalize-release-bundle job (needs build + build-windows-worker,
contents:read + id-token:write + attestations:write) completes
SHA256SUMS with the zip entry, re-verifies every entry against the
actual bytes, enforces the exact final asset set, attests the zip and
the FINAL SHA256SUMS, and uploads release-bundle-final — the exact set
publish-github-release attaches. An attestation now always covers the
exact bytes a consumer downloads. All actions remain SHA-pinned,
permissions stay minimal, and the tag/commit guards are untouched.
docs/release-engineering.md describes exactly this job graph.
- docs/m10-acceptance.md: every scenario in issue #95's acceptance list
  is now explicitly mapped to covered (test reference) / documented /
  external gate / deferred — including worker restart, worker offline,
  exhausted quota, different-host and LAN/VPN deployments, SSH access
  and version upgrade, with the prior-coverage tests named;
- the streaming compatibility-matrix gap now references Forgejo issue
  #106 instead of a vague follow-up note;
- the WSL2 caveat is broadened: any Docker Desktop-backed engine
  (including a WSL2 distro integrated with Docker Desktop) does not
  share the host/distro loopback — host networking will not surface the
  server on 127.0.0.1 there (verified: curl 000); the compose example
  documents the same;
- README: 'a recorded external gate'.
The second scenario-11 variant still used an unguarded recv: under
load the read could sit out the socket timeout before the server closed
its side, erroring the whole suite. Apply the same bounded-timeout
drain the sibling test uses.
Reviewed head 20d0a0c: initial review CHANGES_REQUESTED (one MERGE_BLOCKER:
worker.spec silently ignored by the stock *.spec gitignore pattern, breaking
fresh checkouts and the tagged Windows build), remediation round 1 tracked the
spec, reconciled release-integrity attestation ordering and fixed the doc
DEFERs; fresh GLM-5.3 re-review: APPROVE.

# Conflicts:
#	scarcity_router/worker_client.py
Deterministic, synthetic, CI-safe Codex acceptance through the full
composed stacks with the shared fake App Server as the only Codex
backend:

- packaged-style worker path (console-script pair/run --allow-codex,
  fake codex discovered on a tmpdir PATH, real verified TLS, resource
  in the server registry/state, execution end to end);
- Codex resource composition and exact configured ownership (D-049);
- honest auth verdicts driving eligibility through the snapshot path;
- non-streaming execution with provider-reported usage honesty through
  the composed server; streaming with synthetic compatibility cells
  supplied programmatically (the evidenced-streaming seam, issue #106);
- client disconnect propagating to turn/interrupt, never
  completed-after-cancel;
- verbatim model/effort binding and pre-turn rejection of an
  unrepresentable effort; structured output via outputSchema;
- tools-bearing requests refused at admission (no dispatch);
- mid-execution worker loss resolving to the audited ambiguous state
  with no duplicate execution after reconnect;
- leakage and isolation asserts (closed wire surface, minimal child
  env, controlled CODEX_HOME, scratch cwd, sandbox policy);
- a local-only, skip-safe structure-only probe against the real
  installed binary (discovery + --version + handshake/adoption +
  account/read verdict; no turn, no quota read).

The fake App Server gains one opt-in test-support knob
(pauseBeforeDelta) so a client disconnect mid-turn is deterministic;
absent keys keep the exact M06 behavior. No production module changes.
- docs/m10-acceptance.md: the M10-B section (scenario-to-test mapping
  for the thirteen Codex areas, the observed streaming surface shape,
  the local real-binary probe record dated 2026-09-20 with the observed
  codex-cli version and honest unsigned-in verdict, the recorded
  EXTERNAL_ACCEPTANCE_GATE: LIVE_CODEX_SUBSCRIPTION with the exact
  owner action, and Windows-native-Codex platform honesty);
- docs/codex-adapter-stage1-evidence.md: a dated M10-B note on the
  Stage-2 compatibility matrix recording which cells gained
  composed-stack test evidence while every cell value stays
  conservative (live confirmation remains the gate);
- docs/m10-security-acceptance.md: rows 18/19 cite the new Codex
  leakage/diagnostic evidence.
docs(m10): cite issue #107 for the Codex catalog fail-closed behavior (audit note)
All checks were successful
ci / check (pull_request) Successful in 8m46s
d5cdc173d7
The worker built ResourceIdentity(model="codex") — the execution
SURFACE (local_adapter_id), not a physical model — so the routing
core's exact (provider, model) binding could never match a calibrated
catalog entry and the composed Codex resource was unadmittable.

- worker CLI: --codex-model SLUG is now REQUIRED with --allow-codex,
  validated as a safe id; never guessed from the installed runtime,
  the account state or model/list's default (model/list stays runtime
  verification only). The resource identity is variant-less: the M02
  binding rule binds every calibrated variant of the physical model.
- CodexLocalAdapter: typed preflight invariant (model_not_served) — a
  call whose selected ModelIdentity provider/model does not match the
  configured resource's physical model is rejected BEFORE any
  thread/turn and before any process spawn; no substitution, no silent
  mapping. The per-turn model/list effort verification and exact
  ModelIdentity pinning are unchanged.
- read-only .resource accessor so composition/tests can read the
  identity the adapter serves.

Discriminating tests: the CLI rejects --allow-codex without
--codex-model, the slug becomes the resource identity, and a
configured/selected mismatch fails closed (unit: no spawn at all).
The composed server built its GatewayApplication with an empty
compatibility cell set, so feature-bearing requests failed closed
compatibility_unknown even for evidence-backed adapters, and the Codex
streaming E2E only worked by injecting synthetic cells programmatically.

- server_composition.build_compatibility_cells: every server_direct_http
  resource with a resolvable binding receives its M04 preset's evidenced
  default cells (default_cells_for, no duplicated tables; the generic
  preset stays all-UNKNOWN); every worker_bridged Codex resource
  (worker_id + local_adapter_id "codex" + provider openai) receives the
  reviewed M06 evidence cells keyed to its physical model.
- codex_worker_evidence: the Stage-2 matrix (docs/
  codex-adapter-stage1-evidence.md, 2026-09-20, codex-cli
  0.154.0-alpha.6.2 / schemas rust-v0.155.1) as a static module-level
  table — turn-level cells PARTIAL, tool_calls/tool_results
  UNSUPPORTED, nothing upgraded, nothing derived at runtime, dated
  provenance (codex_adapter_stage2), adapter codex-worker-local 1.0.0.
- control_api._rebuild_application passes the composed cells, so the
  matrix rebuilds with every configuration change; built-in evidence
  stays the ceiling (administrator narrowing/elevation remains issue
  #106); no compatibility assertions are sourced from request content.
The M10-B suites hid both integration blockers: the fake App Server
advertised the artificial slug "codex" against a synthetic (openai,
"codex") catalog entry, and every streaming test injected synthetic
compatibility cells into a bare gateway.

- fixtures: the Codex resource binds the SHIPPED model-catalog.json
  through its physical model (openai/gpt-5.6-sol, calibrated efforts
  medium/high); the synthetic catalog entry, the synthetic cells and
  the programmatic cell seam are gone.
- the fake advertises gpt-5.6-sol (never "codex") with the shipped
  calibrated efforts; the packaged-style worker runs with
  --codex-model.
- all streaming semantics (roles/history SSE, client-disconnect
  interrupt, effort verbatim/rejected-before-turn, structured output,
  pre-dispatch tool rejection, isolation profile) now run through the
  ACTUAL composed server with the production matrix — no cell
  injection anywhere.
- new PhysicalModelIdentityTests: pinned requests bind the shipped
  calibrated identity (audited executed target: provider/model/
  variant exact) and a configured/selected model mismatch fails before
  any dispatch spawn; new ProductionCompatibilityMatrixTests: M06
  cells equal the reviewed values with dated provenance, M04 preset
  cells appear for evidence-backed resources, no leakage across
  providers/models, and the matrix rebuilds/removes with
  configuration.
- scenario 06 (generic preset) now pins fail-closed WITH its
  all-UNKNOWN cells present — evidence, not missing cells.
docs(program): record the Codex physical-model binding and composed-matrix wiring
All checks were successful
ci / check (pull_request) Successful in 11m13s
28d30e862f
- providers.md: the worker registration now documents --codex-model
  (required, safe-id, never guessed), the pre-spawn model_not_served
  invariant, variant-less resource identity binding every calibrated
  variant, and the composed M06 evidence cells.
- codex-adapter-stage1-evidence.md: Stage-2 matrix note — the recorded
  cell values are now keyed into the production composition verbatim
  (static table, dated provenance, no runtime derivation, built-in
  evidence as the ceiling).
- m10-acceptance.md: the #107 gap is resolved by physical-model binding
  (no administrator catalog invention; D-025 calibration for NEW models
  unchanged); #106 narrows honestly to the ADMINISTRATOR evidence-
  recording surface — built-in evidence (M04 presets + reviewed M06
  cells) is wired and streaming works on the composed path; the M10-B
  area table reflects the composed streaming runs. External gates
  (WINDOWS_CODE_SIGNING, LIVE_WINDOWS_ACCEPTANCE,
  LIVE_CODEX_SUBSCRIPTION, PYPI_TRUSTED_PUBLISHER) unchanged; no live
  or Windows evidence claimed.
Author
Member

Integration blockers corrected on this branch (d5cdc17 → 28d30e8, 4 commits). Scope stayed surgical — no M06/M10 redesign, no release-platform work, external gates unchanged.

Blocker 1 — physical Codex model identity. --codex-model SLUG is now required with --allow-codex; the resource is ResourceIdentity(worker_bridged, openai, <slug>, subscription_included) with no variant, binding the shipped calibrated catalog via the exact (provider, model) M02 rule (e.g. gpt-5.6-sol with its calibrated medium/high variants). The adapter rejects any selected model outside its resource (model_not_served) before discovery/spawn/thread/turn, and still verifies the effort against runtime model/list, pinning the exact selected identity per turn. The fake App Server and all E2E advertise real slugs against the real shipped catalog; the synthetic openai/codex catalog fixture is deleted. No catalog model named codex exists. (#107 closed with the corrected record.)

Blocker 2 — production compatibility matrix. The composed server now builds real cells from administrator configuration: M04 default_cells_for per configured preset resource + new codex_worker_evidence (the reviewed Stage-2 values verbatim: 8×PARTIAL, tool_calls/tool_results UNSUPPORTED, dated provenance 2026-09-20, codex-cli 0.154.0-alpha.6.2 / rust-v0.155.1), passed into GatewayApplication by _rebuild_application with the same rebuild-on-configuration-change lifecycle as adapters. Streaming on evidenced composed deployments works without any test-only cell injection; tools requests are rejected from the real UNSUPPORTED cell before dispatch; generic presets stay all-UNKNOWN fail-closed; built-in evidence remains the ceiling (no admin override surface). (#106 closed with the delivered/remaining boundary recorded.)

Adversarial review (fresh GLM-5.3/MAX): APPROVE, zero blockers, zero DEFERs. The reviewer independently re-proved both gaps on d5cdc17 — notably the old adapter executed a wrong-model turn (502 != 200) and old composed streaming answered 200 with an empty matrix — and re-ran the full gate at 28d30e8: make check 1858 tests OK, basedpyright 0/0/0, git diff --check clean, make package-check PASS, make guardrails 40 OK; scope audit (12 files, each serving one blocker) and secrets scan clean.

Integration blockers corrected on this branch (`d5cdc17` → `28d30e8`, 4 commits). Scope stayed surgical — no M06/M10 redesign, no release-platform work, external gates unchanged. **Blocker 1 — physical Codex model identity.** `--codex-model SLUG` is now required with `--allow-codex`; the resource is `ResourceIdentity(worker_bridged, openai, <slug>, subscription_included)` with no variant, binding the shipped calibrated catalog via the exact `(provider, model)` M02 rule (e.g. `gpt-5.6-sol` with its calibrated `medium`/`high` variants). The adapter rejects any selected model outside its resource (`model_not_served`) before discovery/spawn/thread/turn, and still verifies the effort against runtime `model/list`, pinning the exact selected identity per turn. The fake App Server and all E2E advertise real slugs against the real shipped catalog; the synthetic `openai/codex` catalog fixture is deleted. No catalog model named `codex` exists. (#107 closed with the corrected record.) **Blocker 2 — production compatibility matrix.** The composed server now builds real cells from administrator configuration: M04 `default_cells_for` per configured preset resource + new `codex_worker_evidence` (the reviewed Stage-2 values verbatim: 8×PARTIAL, tool_calls/tool_results UNSUPPORTED, dated provenance `2026-09-20`, `codex-cli 0.154.0-alpha.6.2` / `rust-v0.155.1`), passed into `GatewayApplication` by `_rebuild_application` with the same rebuild-on-configuration-change lifecycle as adapters. Streaming on evidenced composed deployments works without any test-only cell injection; tools requests are rejected from the real `UNSUPPORTED` cell before dispatch; generic presets stay all-`UNKNOWN` fail-closed; built-in evidence remains the ceiling (no admin override surface). (#106 closed with the delivered/remaining boundary recorded.) **Adversarial review (fresh GLM-5.3/MAX): APPROVE, zero blockers, zero DEFERs.** The reviewer independently re-proved both gaps on `d5cdc17` — notably the old adapter *executed a wrong-model turn* (`502 != 200`) and old composed streaming answered `200` with an empty matrix — and re-ran the full gate at `28d30e8`: `make check` 1858 tests OK, basedpyright 0/0/0, `git diff --check` clean, `make package-check` PASS, `make guardrails` 40 OK; scope audit (12 files, each serving one blocker) and secrets scan clean.
build_compatibility_cells emitted cells per configured resource, but the
D-043 matrix is keyed by (channel, provider, model, variant, feature) and
RouteRequest rejects duplicate current cells for a key — so two legitimate
resources executing the same physical model (two Codex workers on
different workers serving openai/gpt-5.6-sol, or two server-direct
resources on one evidenced preset) composed a matrix the routing core
refused. Compatibility is backend/surface evidence, not resource
ownership (D-042).

Canonicalize the per-resource emission in server_composition._canonical_cells:
first occurrence wins the slot; a later cell with the same frozen key is
silently merged when semantically identical (same value, adapter,
adapter_version, evidence — frozen-dataclass equality over the exact
EvidenceRef fields) and otherwise fails closed with the typed
CompositionError naming the key — no first/last winner, no silent
optimism or restriction. Cells are returned deterministically ordered by
the key tuple (absent variant first, the routing core's own ordering).

Surface the typed error the way other composition failures surface:
service_add_resource and service_set_resource_enabled map it onto
ControlHTTPError.invalid_request (the service_add_provider idiom), and
_save_config composes the candidate configuration's cells before any
state mutation so a rejected save cannot poison later saves or the
durable store.
test(program): discriminate two-resource matrix canonicalization
All checks were successful
ci / check (pull_request) Successful in 11m54s
30d39ee343
Discriminating coverage for the D-042/D-043 canonicalization (all of
these fail on 28d30e8, proven in a throwaway extraction):

- unit (test_program_integration.CompatibilityMatrixCanonicalizationTests):
  two Codex resources and two server-direct resources on one preset each
  emit exactly one cell set; conflicting evidence for one frozen key
  (evidenced vs generic preset) raises the typed CompositionError naming
  the key; distinct physical models and distinct channels stay separate;
  canonical key ordering.
- control surface (CompositionFromConfigurationTests): a conflicting
  second resource is rejected at save with 400 and the key named, with
  no half-applied state and no poisoned later saves.
- E2E (test_e2e_codex_acceptance.TwoCodexResourcesSamePhysicalModelTests):
  two workers each owning a resource for the SAME physical model compose
  exactly one reviewed M06 cell set, a real RouteRequest accepts the
  matrix end to end (on 28d30e8 the duplicate-cell rejection surfaces as
  an invalid_state 500), and routing stays resource-distinct — each pin
  reaches only its owning worker. start_codex_worker gains an additive
  resource_id seam; the composed-streaming and physical-identity suites
  stay untouched and green.
Author
Member

Final integration blocker corrected on this branch (28d30e8 → 30d39ee, two commits). Scope surgical: 4 files (+618/−11) — server_composition.py (the canonicalization), control_api.py (surfacing only), two test files. No CompatibilityCell/EvidenceRef schema change, no M02 routing change, no evidence-value/preset/isolation/packaging change, no fallback.

Fix: build_compatibility_cells now canonicalizes onto the existing frozen D-043 key (channel, provider, model, variant, feature) — literally the same tuple the routing core rejects duplicates on (routing_core.py:2239). Semantically identical cells (same value, adapter, adapter_version, and exact EvidenceRef) merge to one; conflicting assertions for the same key fail closed with the typed CompositionError naming the full key and both evidence identifiers — no first/last/optimistic/restrictive winner. Output deterministically ordered exactly as the routing core orders. Compatibility is backend/surface evidence; multiple resources may execute one physical model (D-042) — worker/resource ownership is untouched (worker_adapter_map stays resource-keyed).

Surfacing: conflicting evidence at save time answers 400 invalid_request; _save_config composes the candidate config before any state mutation, so a rejected save can neither poison in-memory config nor reach the durable store. (Upgrade note, judged honest fail-closed: a pre-fix persisted config with conflicting same-key evidence now refuses server start with a remediation-bearing error instead of booting with a dispatch-500 matrix.)

Adversarial review (fresh GLM-5.3/MAX): APPROVE, zero blockers. The reviewer independently re-proved discrimination on 28d30e8 — the two-worker E2E failed there with the literal duplicate-cell rejections (20 != 10 cell-count; 200 != 500 invalid_state from a real RouteRequest), both dedupe unit tests failed with 10 extra duplicate cells, the conflict test failed CompositionError not raised — and the same tests pass on 30d39ee. Verified: dedupe key/equality covers all 9 cell fields with total equality; the two resources remain two independent admittable routing targets with per-resource ownership; evidence modules (openai_http_evidence, codex_worker_evidence, presets) untouched since 9462c30; #106 composed-streaming and #107 physical-identity suites green. Full gate at 30d39ee: make check 1868 tests OK (~712 s), basedpyright 0/0/0, git diff --check clean, make package-check PASS, make guardrails 40 OK.

Final integration blocker corrected on this branch (`28d30e8` → `30d39ee`, two commits). Scope surgical: 4 files (+618/−11) — `server_composition.py` (the canonicalization), `control_api.py` (surfacing only), two test files. No `CompatibilityCell`/`EvidenceRef` schema change, no M02 routing change, no evidence-value/preset/isolation/packaging change, no fallback. **Fix:** `build_compatibility_cells` now canonicalizes onto the existing frozen D-043 key `(channel, provider, model, variant, feature)` — literally the same tuple the routing core rejects duplicates on (`routing_core.py:2239`). Semantically identical cells (same value, adapter, adapter_version, and exact `EvidenceRef`) merge to one; conflicting assertions for the same key fail closed with the typed `CompositionError` naming the full key and both evidence identifiers — no first/last/optimistic/restrictive winner. Output deterministically ordered exactly as the routing core orders. Compatibility is backend/surface evidence; multiple resources may execute one physical model (D-042) — worker/resource ownership is untouched (`worker_adapter_map` stays resource-keyed). **Surfacing:** conflicting evidence at save time answers `400 invalid_request`; `_save_config` composes the *candidate* config **before** any state mutation, so a rejected save can neither poison in-memory config nor reach the durable store. (Upgrade note, judged honest fail-closed: a pre-fix persisted config with conflicting same-key evidence now refuses server start with a remediation-bearing error instead of booting with a dispatch-500 matrix.) **Adversarial review (fresh GLM-5.3/MAX): APPROVE, zero blockers.** The reviewer independently re-proved discrimination on `28d30e8` — the two-worker E2E failed there with the literal duplicate-cell rejections (`20 != 10` cell-count; `200 != 500 invalid_state` from a real `RouteRequest`), both dedupe unit tests failed with 10 extra duplicate cells, the conflict test failed `CompositionError not raised` — and the same tests pass on `30d39ee`. Verified: dedupe key/equality covers all 9 cell fields with total equality; the two resources remain two independent admittable routing targets with per-resource ownership; evidence modules (`openai_http_evidence`, `codex_worker_evidence`, presets) untouched since `9462c30`; #106 composed-streaming and #107 physical-identity suites green. Full gate at `30d39ee`: `make check` 1868 tests OK (~712 s), basedpyright 0/0/0, `git diff --check` clean, `make package-check` PASS, `make guardrails` 40 OK.
adrian.tkacz deleted branch program/m06-m10-final-wave 2026-09-21 16:35:25 +00:00
Sign in to join this conversation.
No description provided.