v0.1.0 release readiness: first-run availability + Z.ai endpoint path + TLS healthcheck fixes, PyPI-last publication ordering, candidate preflight, program closeout #109

Merged
adrian.tkacz merged 8 commits from release/v0.1.0-readiness into develop 2026-09-22 16:20:06 +00:00
Member

Summary

v0.1.0 release-readiness program on top of develop @ 9d6192e (PROGRAM_BASE_SHA). Three parts: (1) release blockers found by the readiness audit, (2) closeout reconciliation of docs and tracker, (3) release-gate hardening — publication ordering, a non-publishing candidate preflight, and programmatic verification of the external publication configuration.

Release blockers fixed

1. Server-direct execution resources could never become available (81cd2a2, decision D-050)

  • Found by: Phase 4 first-run acceptance through a real wheel install and a real composed server (not test fixtures). Configure provider → configure resource → issue client key → execute: every execution failed 503 target_unavailable (resource_never_observed).
  • Root cause: the M01 refresh contract ("no background refresh; the server's request loop calls refresh_due") was never wired: no production code called it, nothing ever constructed a ResourceStateSnapshot for a server-direct resource, and the M10 e2e masked the gap by injecting healthy observations through the test seam (apply_resource_observation). The diagnostics remediation ("wait for its collection cadence or trigger a health check") referenced actions that could not change the state.
  • Fix: the execution ingress now probes due server-direct resources through the M04 adapter's quota-free readiness probe and records the outcome as the resource's observation; server-direct registrations default to a 300 s polling cadence (explicit values win); presets without a native health endpoint are probed with a GET on their DOCUMENTED endpoint path (any well-formed answer = reachable → ok; 401/403 → auth_required; 404/410 → schema_changed; transport failure → unavailable); the connection test records its probe result so the remediation is a real action.
  • Discrimination: new no-injection e2e tests (FirstRunAvailabilityTests scenarios 17–18) fail on the pre-fix HEAD with exactly the reported 503.

2. Z.ai Coding Plan preset composed the wrong URL (81cd2a2)

  • The documented chat endpoint is https://api.z.ai/api/coding/paas/v4/chat/completions; administrators configure a bare origin, so the preset endpoint path must carry the base path — the OpenRouter preset already did this, the Z.ai preset did not, so composed Z.ai resources could never reach the documented endpoint. Path corrected and pinned by tests.

3. Documented TLS container deployment reported permanently unhealthy (3e041e0)

  • The baked HEALTHCHECK probed plaintext against the container's fixed port, but the documented LAN/VPN variant serves verified TLS on that port — a correctly serving deployment reported unhealthy forever (verified live). The probe now optionally speaks verified TLS via SR_HEALTHCHECK_URL/SR_HEALTHCHECK_CA (never weakens verification); compose example documents it. Re-verified live: healthy.

Release-gate hardening (23fb618 + 079b7fa)

  • Publication ordering: publish-pypi previously depended only on the Python build, so the irreversible PyPI publication of 0.1.0 could complete while the Windows worker build (never yet executed on a real Windows runner) failed later — a partial public release that cannot be replaced. The graph is now verify → build → build-windows-worker → finalize-release-bundle → publish-github-release → publish-pypi: the Windows ZIP, the verified final SHA256SUMS and the GitHub Release must all exist before anything reaches PyPI. Both publishing jobs are gated to the SemVer tag push event.
  • Manual release-candidate preflight (workflow_dispatch): the same workflow builds and verifies every public artifact from the exact selected ref — including the Windows worker ZIP on a real Windows runner — records the candidate identity (ref, SHA, package version), refuses a tag ref, and can never publish. The first real execution of the Windows build no longer has to be the v0.1.0 release run.
  • Structural release-workflow tests (tests/test_release_workflow.py, 17 tests; pyyaml added as dev-only dependency): dispatch exists and reaches the Windows build but cannot reach any publishing job; no PR event triggers; SemVer/version/main-ancestry invariants enforced; PyPI strictly downstream of the final bundle AND the GitHub Release; no long-lived publishing token; OIDC Trusted Publishing only.
  • Programmatically verified owner gates (docs/release-engineering.md checklist updated): GitHub Actions enablement on the mirror is MISSING (workflow index empty, dispatch API 404 — one-time interactive enablement required); the GitHub pypi environment does NOT exist (zero environments — must be pre-created with reviewers); the PyPI project is unpublished (Trusted Publisher not yet registrable/verifiable); Forgejo develop branch protection requires owner-level credentials to verify (kilo token is not an admin).

Closeout reconciliation (docs, 8c375b1 + fe2cb89)

  • docs/roadmap.md records per-module completion with preserved external gates; README no longer claims "M10 still in progress"; docs/m10-acceptance.md aligned with issue #106's resolution.
  • Forgejo issues #82, #87–#91, #93–#95, #97 closed with per-issue acceptance evidence; external gates preserved explicitly rather than treated as unfinished implementation.

Validation

  • Full gate at final HEAD: uv sync --only-dev, make check (1895 tests), uv run basedpyright (0 findings), git diff --check, make package-check, make guardrails (40 tests) — all green. Forgejo CI green on the branch.
  • Clean-checkout gate from exact 9d6192e: green (pre-fix baseline).
  • Container acceptance from clean git archive: 13/13 (build, non-root uid 10001, version banner, verified-TLS 200 / wrong CA refused / plaintext refused, healthcheck healthy, bootstrap replay 409, restart persistence, 0600 store, no socket).
  • Clean-install recommendation-only acceptance (fresh HOME, wheel): CLI, install-config, select with honest degraded-unknown capacity, doctor, loopback REST.
  • Server first-run acceptance end to end (real processes): onboarding → replay refusal → provider/resource/client key → execution 200 → secret-free diagnostics/export → restart persistence.
  • Codex live gate PREPARED (not executed — owner-interactive): controlled home created and adapter-validated at /home/adrian/.local/share/scarcity-router/worker/codex/codex-home (0700, generated config, "Not logged in"); official login flows confirmed against the installed codex-cli 0.154.0-alpha.6.2 (login browser flow, login --device-auth).

External gates (verified 2026-09-21; recorded in docs/release-engineering.md)

  1. GitHub Actions enablement on the mirror — MISSING (blocks candidate preflight AND any tag run; one-time owner click).
  2. Forgejo runner — operating (CI green).
  3. develop branch protection requiring check — unverifiable with current credentials; owner action.
  4. PyPI Trusted Publisher — not yet registrable (project unpublished); owner action before tag.
  5. GitHub pypi environment — MISSING (pre-create with reviewers before tag).

Tag blockers for v0.1.0

LIVE_WINDOWS_ACCEPTANCE (no Windows host; candidate artifact name scarcity-worker-0.1.0-windows-x64.zip from the candidate HEAD once Actions is enabled), LIVE_CODEX_SUBSCRIPTION (owner login gate prepared above), GitHub Actions enablement (1), PyPI Trusted Publisher (4), pypi environment (5). WINDOWS_CODE_SIGNING does NOT block the portable-ZIP release (D-046). None blocks MERGING this PR to develop.

Do not merge without human review; release happens only after the owner reviews the release-readiness result.

## Summary v0.1.0 release-readiness program on top of `develop` @ `9d6192e` (PROGRAM_BASE_SHA). Three parts: (1) release blockers found by the readiness audit, (2) closeout reconciliation of docs and tracker, (3) release-gate hardening — publication ordering, a non-publishing candidate preflight, and programmatic verification of the external publication configuration. ## Release blockers fixed ### 1. Server-direct execution resources could never become available (`81cd2a2`, decision D-050) - **Found by:** Phase 4 first-run acceptance through a real wheel install and a real composed server (not test fixtures). Configure provider → configure resource → issue client key → execute: every execution failed `503 target_unavailable` (`resource_never_observed`). - **Root cause:** the M01 refresh contract ("no background refresh; the server's request loop calls `refresh_due`") was never wired: no production code called it, nothing ever constructed a `ResourceStateSnapshot` for a server-direct resource, and the M10 e2e masked the gap by injecting healthy observations through the test seam (`apply_resource_observation`). The diagnostics remediation ("wait for its collection cadence or trigger a health check") referenced actions that could not change the state. - **Fix:** the execution ingress now probes due server-direct resources through the M04 adapter's quota-free readiness probe and records the outcome as the resource's observation; server-direct registrations default to a 300 s polling cadence (explicit values win); presets without a native health endpoint are probed with a GET on their DOCUMENTED endpoint path (any well-formed answer = reachable → `ok`; 401/403 → `auth_required`; 404/410 → `schema_changed`; transport failure → `unavailable`); the connection test records its probe result so the remediation is a real action. - **Discrimination:** new no-injection e2e tests (`FirstRunAvailabilityTests` scenarios 17–18) fail on the pre-fix HEAD with exactly the reported 503. ### 2. Z.ai Coding Plan preset composed the wrong URL (`81cd2a2`) - The documented chat endpoint is `https://api.z.ai/api/coding/paas/v4/chat/completions`; administrators configure a bare origin, so the preset endpoint path must carry the base path — the OpenRouter preset already did this, the Z.ai preset did not, so composed Z.ai resources could never reach the documented endpoint. Path corrected and pinned by tests. ### 3. Documented TLS container deployment reported permanently unhealthy (`3e041e0`) - The baked HEALTHCHECK probed plaintext against the container's fixed port, but the documented LAN/VPN variant serves verified TLS on that port — a correctly serving deployment reported `unhealthy` forever (verified live). The probe now optionally speaks verified TLS via `SR_HEALTHCHECK_URL`/`SR_HEALTHCHECK_CA` (never weakens verification); compose example documents it. Re-verified live: `healthy`. ## Release-gate hardening (`23fb618` + `079b7fa`) - **Publication ordering:** `publish-pypi` previously depended only on the Python build, so the irreversible PyPI publication of 0.1.0 could complete while the Windows worker build (never yet executed on a real Windows runner) failed later — a partial public release that cannot be replaced. The graph is now `verify → build → build-windows-worker → finalize-release-bundle → publish-github-release → publish-pypi`: the Windows ZIP, the verified final `SHA256SUMS` and the GitHub Release must all exist before anything reaches PyPI. Both publishing jobs are gated to the SemVer tag push event. - **Manual release-candidate preflight (`workflow_dispatch`):** the same workflow builds and verifies every public artifact from the exact selected ref — including the Windows worker ZIP on a real Windows runner — records the candidate identity (ref, SHA, package version), refuses a tag ref, and can never publish. The first real execution of the Windows build no longer has to be the v0.1.0 release run. - **Structural release-workflow tests** (`tests/test_release_workflow.py`, 17 tests; `pyyaml` added as dev-only dependency): dispatch exists and reaches the Windows build but cannot reach any publishing job; no PR event triggers; SemVer/version/main-ancestry invariants enforced; PyPI strictly downstream of the final bundle AND the GitHub Release; no long-lived publishing token; OIDC Trusted Publishing only. - **Programmatically verified owner gates** (`docs/release-engineering.md` checklist updated): GitHub Actions enablement on the mirror is MISSING (workflow index empty, dispatch API 404 — one-time interactive enablement required); the GitHub `pypi` environment does NOT exist (zero environments — must be pre-created with reviewers); the PyPI project is unpublished (Trusted Publisher not yet registrable/verifiable); Forgejo `develop` branch protection requires owner-level credentials to verify (kilo token is not an admin). ## Closeout reconciliation (docs, `8c375b1` + `fe2cb89`) - `docs/roadmap.md` records per-module completion with preserved external gates; README no longer claims "M10 still in progress"; `docs/m10-acceptance.md` aligned with issue #106's resolution. - Forgejo issues #82, #87–#91, #93–#95, #97 closed with per-issue acceptance evidence; external gates preserved explicitly rather than treated as unfinished implementation. ## Validation - Full gate at final HEAD: `uv sync --only-dev`, `make check` (1895 tests), `uv run basedpyright` (0 findings), `git diff --check`, `make package-check`, `make guardrails` (40 tests) — all green. Forgejo CI green on the branch. - Clean-checkout gate from exact `9d6192e`: green (pre-fix baseline). - Container acceptance from clean `git archive`: 13/13 (build, non-root uid 10001, version banner, verified-TLS 200 / wrong CA refused / plaintext refused, healthcheck healthy, bootstrap replay 409, restart persistence, 0600 store, no socket). - Clean-install recommendation-only acceptance (fresh HOME, wheel): CLI, install-config, select with honest degraded-unknown capacity, doctor, loopback REST. - Server first-run acceptance end to end (real processes): onboarding → replay refusal → provider/resource/client key → execution 200 → secret-free diagnostics/export → restart persistence. - Codex live gate PREPARED (not executed — owner-interactive): controlled home created and adapter-validated at `/home/adrian/.local/share/scarcity-router/worker/codex/codex-home` (0700, generated config, "Not logged in"); official login flows confirmed against the installed `codex-cli 0.154.0-alpha.6.2` (`login` browser flow, `login --device-auth`). ## External gates (verified 2026-09-21; recorded in `docs/release-engineering.md`) 1. GitHub Actions enablement on the mirror — **MISSING** (blocks candidate preflight AND any tag run; one-time owner click). 2. Forgejo runner — **operating** (CI green). 3. `develop` branch protection requiring `check` — **unverifiable with current credentials**; owner action. 4. PyPI Trusted Publisher — **not yet registrable** (project unpublished); owner action before tag. 5. GitHub `pypi` environment — **MISSING** (pre-create with reviewers before tag). ## Tag blockers for v0.1.0 `LIVE_WINDOWS_ACCEPTANCE` (no Windows host; candidate artifact name `scarcity-worker-0.1.0-windows-x64.zip` from the candidate HEAD once Actions is enabled), `LIVE_CODEX_SUBSCRIPTION` (owner login gate prepared above), GitHub Actions enablement (1), PyPI Trusted Publisher (4), `pypi` environment (5). `WINDOWS_CODE_SIGNING` does NOT block the portable-ZIP release (D-046). None blocks MERGING this PR to `develop`. Do not merge without human review; release happens only after the owner reviews the release-readiness result.
The implementation program (A0 #85, M01-M10 #86-#95, CI #97) is complete;
record the per-module completion state with the preserved external gates,
update the README boundary text that still called M10 work in progress,
and align the m10 acceptance record with issue #106's resolution.
Release-readiness audit finding (Phase 4 first-run acceptance): the
composed server never observed server_direct_http resources, so every
freshly configured resource was permanently resource_never_observed and
each pinned execution failed 503 target_unavailable with a remediation
no action could satisfy; the M10 e2e masked the gap by injecting healthy
observations through the test seam.

Complete the designed-but-unwired M01 refresh contract (decision D-050):

- the execution ingress asks the registry which resources are due
  (refresh_due) and probes each due server_direct_http resource through
  the M04 adapter's quota-free readiness probe, recording the outcome as
  its observation via apply_resource_observation;
- server-direct registrations default to a 300 s polling cadence
  (server-side policy is authoritative); an explicit value wins;
- presets without an evidenced native health endpoint are probed with a
  GET on their DOCUMENTED endpoint path: any well-formed answer records
  health ok with the exact status in the note, 401/403 records
  auth_required, 404/410 records schema_changed, transport failures
  record unavailable — no undocumented provider endpoint, no quota;
- the control connection test records its probe result, making the
  diagnostics remediation ('run the connection test to probe now') a
  real action, and the ladder remediation text describes reality;
- correct the Z.ai Coding Plan preset endpoint path to the documented
  base URL path (/api/coding/paas/v4/chat/completions): administrators
  configure a bare origin, so the preset carries the base path exactly
  like the OpenRouter preset already did;

Pinned by no-injection first-run e2e tests (scenario 17/18), adapter
probe-mapping tests, the documented-path pins, and the configuration
default tests. No routing-core, coordinator or serialized-contract
change; frozen recommendation-only surfaces untouched.
fix(container): make the baked HEALTHCHECK usable by the documented TLS deployment
All checks were successful
ci / check (pull_request) Successful in 11m51s
3e041e014a
The LAN/VPN compose variant (non-loopback bind requires verified TLS,
D-044) serves TLS on the container's fixed internal port, so the baked
plaintext health probe could never answer: a correctly configured and
correctly serving TLS deployment reported permanently unhealthy to
orchestrators. The probe now optionally speaks VERIFIED TLS when the
deployment sets SR_HEALTHCHECK_URL and SR_HEALTHCHECK_CA (the same CA
its clients use) — it never weakens certificate verification — while
plaintext loopback deployments keep the previous behavior. The compose
example documents the two extra mounts and environment values.
Final GLM-5.3/MAX release review (verdict RELEASE_READY, zero blockers)
returned four DEFER hygiene items; the three trivially risk-reducing
ones are applied:

- remove a duplicated, unreachable 401/403 + 404/410 check pair in
  _probe_reachability (leftover from development, dead on arrival);
- hoist the server-direct adapter resolve/isinstance check above the
  refresh loop in prepare_execution_admission (a constant-condition
  return inside the loop misled readers);
- document that SR_HEALTHCHECK_URL must name a host or IP in the
  certificate's SAN list (Dockerfile + compose example) and that
  request-path probes run under the adapter's deadline once per
  polling cadence (docs/control-surface.md).

The fourth DEFER (worst-case first-request latency note) is covered by
the same control-surface paragraph.
The release graph let publish-pypi run from the Python build alone, so an
irreversible PyPI publication of 0.1.0 could complete while the Windows
worker build (never yet executed on a real Windows runner) failed later —
leaving a partial public release that cannot be replaced.

Reorder the pipeline so every public artifact exists and is finalized
before anything is published:

  verify-release-contract -> build -> build-windows-worker
    -> finalize-release-bundle -> publish-github-release -> publish-pypi

Both publishing jobs are gated to the SemVer tag push event; PyPI is
additionally needs-downstream of the GitHub Release, so the Windows ZIP,
the verified final SHA256SUMS and the public release all exist before any
irreversible publication. The verify job keeps every fail-closed tag
invariant (strict SemVer, package-version equality from the single
__version__ literal, stable-main ancestry, exact-commit builds) unchanged.

Add the manual release-candidate preflight (workflow_dispatch): the same
workflow builds and verifies all artifacts from the exact selected ref —
including the Windows worker ZIP — records the candidate identity (ref,
SHA, package version) in the step summary, refuses a tag ref, and can
never publish: the first real execution of the Windows build no longer
has to be the v0.1.0 release run. Attestations still cover final bytes;
no tag/main/version check is weakened for the real release path.

Pin the whole contract with tests/test_release_workflow.py (17 structural
tests: dispatch exists and reaches the Windows build but cannot reach any
publishing job; no PR event triggers; SemVer/version/main-ancestry
enforced; PyPI downstream of the final bundle AND the GitHub Release; no
long-lived publishing token; OIDC Trusted Publishing only). pyyaml is
added as a dev-only dependency for the structural parser.
docs(release): record the verified-missing GitHub Actions enablement and PyPI/environment owner gates
All checks were successful
ci / check (pull_request) Successful in 11m56s
079b7fa55d
Programmatic verification (2026-09-21) found the GitHub mirror's workflow
index empty (zero registered workflows, dispatch API 404) even though
release.yml is on develop and Actions reads enabled — the one-time
interactive workflow enablement has never happened and is now documented
as owner gate 1. Also verified the repository defines zero environments,
so the pypi environment with required reviewers must be pre-created
before the first release; and the PyPI-failure recovery story is updated
to the new ordering (GitHub Release already public; re-run publish-pypi
after fixing the Trusted Publisher).
kilo changed title from v0.1.0 release readiness: first-run availability fix, Z.ai endpoint path fix, TLS healthcheck fix, program closeout to v0.1.0 release readiness: first-run availability + Z.ai endpoint path + TLS healthcheck fixes, PyPI-last publication ordering, candidate preflight, program closeout 2026-09-21 20:53:07 +00:00
Reviewer-wording nuance from the release-gate review (RELEASE_GATE_APPROVE):
finalize and publish jobs perform no checkout at all and handle only this
run's uploaded artifacts, which is strictly tighter than a re-checkout.
adrian.tkacz deleted branch release/v0.1.0-readiness 2026-09-22 16:20:06 +00:00
Sign in to join this conversation.
No description provided.