Add publish-kdl-read producer job so read-only director sessions get the ward-kdl-read observe surface #572

Closed
opened 2026-07-03 17:30:50 +00:00 by coilysiren · 2 comments
Owner

Symptom

Read-only director sessions never get the ward-kdl-read observe helper. ward#547 wired install_ward_kdl_read() into the container entrypoint and documented the "kai-server observe surface for non-mutating ssh-through-docker checks," but the binary is never on PATH in a live director session (verified this session: ward-kdl-read absent, WARD_READONLY=1).

Root cause

There is no publish-kdl-read producer job in release.yml - only publish-kdl-write. ward-kdl-read is only ever built locally by the Makefile to render guardfiles (cmd/ward-kdl/ward-kdl-read/ward-kdl.*.guardfile.kdl), never published to the internal generic package channel. So the entrypoint's best-effort install_ward_kdl_read fetch 404s and silently skips every run. Confirmed: the ward-kdl-read generic package 404s at v0.361.0.

The token angle (already handled - do not re-derive)

The CI_RELEASE_TOKEN write:package scope that gates all ward-kdl publishing was rotated in this session (agentic-os infra #448 fix, friction captured in infra#452). ward-kdl-write also 404s at v0.361.0, but only because that release ran before the effective grant and Forgejo 15.0.2 has no headless release re-run (infra#452 trap #6: no workflow_dispatch, no rerun API). The next push to ward main triggers a fresh, post-grant release that fills the package registry (infra#452 trap #7: verify the payoff by watching the registry fill, not the token write). So this issue's own merge-push is the trigger that publishes both ward-kdl-write (first time since the grant) and the new ward-kdl-read.

Fix

Add publish-kdl-read to release.yml, mirroring publish-kdl-write: build ward-kdl-read-linux-{amd64,arm64} from cmd/ward-kdl/ward-kdl-read/ and PUT to .../generic/ward-kdl-read/<tag>/.... The entrypoint's arch() already normalizes x86_64->amd64, so match that naming. Keep it read-only by spec (the guardfile has no create/edit/delete leaf).

Follow-up (not this issue - a sealed container cannot do it)

The ssh-through-docker transport - whether a kai-server ssh credential actually reaches a sealed container so ward-kdl-read can observe - is unverified. ward#547's own outcome flagged it depends on "the surrounding infra path landing cleanly." A sealed engineer/advisor container cannot live-test that (same wall as eco-ops#26). That verification is a hands-on / creds-having step; track it separately once the binary publishes.

  • ward#547 - wired the consumer (install_ward_kdl_read) + docs.
  • agentic-os infra #448 / #452 - the write:package scope rotation that gates all ward-kdl publishing.
  • ward#561 - the release binary matrix.
## Symptom Read-only director sessions never get the `ward-kdl-read` observe helper. ward#547 wired `install_ward_kdl_read()` into the container entrypoint and documented the "kai-server observe surface for non-mutating ssh-through-docker checks," but the binary is never on PATH in a live director session (verified this session: `ward-kdl-read` absent, `WARD_READONLY=1`). ## Root cause There is **no `publish-kdl-read` producer job** in [`release.yml`](.forgejo/workflows/release.yml) - only `publish-kdl-write`. `ward-kdl-read` is only ever built locally by the Makefile to render guardfiles (`cmd/ward-kdl/ward-kdl-read/ward-kdl.*.guardfile.kdl`), never published to the internal generic package channel. So the entrypoint's best-effort `install_ward_kdl_read` fetch **404s and silently skips every run**. Confirmed: the `ward-kdl-read` generic package 404s at `v0.361.0`. ## The token angle (already handled - do not re-derive) The `CI_RELEASE_TOKEN` `write:package` scope that gates **all** ward-kdl publishing was rotated in this session (agentic-os infra #448 fix, friction captured in infra#452). `ward-kdl-write` also 404s at `v0.361.0`, but only because that release ran **before** the effective grant and Forgejo 15.0.2 has **no headless release re-run** (infra#452 trap #6: no `workflow_dispatch`, no rerun API). The next push to ward `main` triggers a fresh, post-grant release that fills the package registry (infra#452 trap #7: verify the payoff by watching the registry fill, not the token write). So this issue's own merge-push is the trigger that publishes both `ward-kdl-write` (first time since the grant) and the new `ward-kdl-read`. ## Fix Add `publish-kdl-read` to `release.yml`, mirroring `publish-kdl-write`: build `ward-kdl-read-linux-{amd64,arm64}` from `cmd/ward-kdl/ward-kdl-read/` and PUT to `.../generic/ward-kdl-read/<tag>/...`. The entrypoint's `arch()` already normalizes `x86_64`->`amd64`, so match that naming. Keep it read-only by spec (the guardfile has no create/edit/delete leaf). ## Follow-up (not this issue - a sealed container cannot do it) The **ssh-through-docker transport** - whether a kai-server ssh credential actually reaches a sealed container so `ward-kdl-read` can observe - is unverified. ward#547's own outcome flagged it depends on "the surrounding infra path landing cleanly." A sealed engineer/advisor container cannot live-test that (same wall as eco-ops#26). That verification is a hands-on / creds-having step; track it separately once the binary publishes. ## Related - ward#547 - wired the consumer (`install_ward_kdl_read`) + docs. - agentic-os infra #448 / #452 - the `write:package` scope rotation that gates all ward-kdl publishing. - ward#561 - the release binary matrix.
Member

🔒 Reserved by ward agent --driver claude — container engineer-claude-ward-572 on host KAI-DESKTOP-TOWER is carrying this issue (reserved 2026-07-03T17:31:34Z). Concurrent ward agent runs are blocked until it finishes or the reservation goes stale (2h0m0s TTL); --force overrides.

Do not comment on or edit this issue to steer the run while it is reserved. The engineer seeded the body once at launch and never re-reads it, so a comment or edit reaches only human readers, never the running engineer. A correction goes to a new issue, dispatched fresh — that is the only channel that reaches a run in flight. Where the forge supports it, ward locks this conversation to make that a road-block rather than a convention (ward#494).

— Claude (she/her), via ward agent

<!-- ward-agent-reservation --> 🔒 Reserved by `ward agent --driver claude` — container `engineer-claude-ward-572` on host `KAI-DESKTOP-TOWER` is carrying this issue (reserved 2026-07-03T17:31:34Z). Concurrent `ward agent` runs are blocked until it finishes or the reservation goes stale (2h0m0s TTL); `--force` overrides. **Do not comment on or edit this issue to steer the run while it is reserved.** The engineer seeded the body once at launch and never re-reads it, so a comment or edit reaches only human readers, never the running engineer. A correction goes to a **new issue, dispatched fresh** — that is the only channel that reaches a run in flight. Where the forge supports it, ward locks this conversation to make that a road-block rather than a convention (ward#494). <!-- ward-agent-signature --> — Claude (she/her), via `ward agent`
Author
Owner

WARD-OUTCOME: done - publish-kdl-read producer added to release.yml (mirrors publish-kdl-write), landed on main as v0.364.0, closes #572. Read-tier build verified locally; the internal registry fill is still gated on the operational CI_RELEASE_TOKEN write:package grant.

The code half felt straightforward: the issue was precise, publish-kdl-write was a clean template, and the read job is a near-mechanical mirror (read guardfile in, same generated build, same delete-then-PUT to generic/ward-kdl-read//). I built the read tier locally the way CI does to make sure I hadn't mis-wired the guardfile path — it produces a valid 24MB ELF reporting ward-kdl-read version v0.364.0 with zero create/edit/delete leaves, so read-only-by-spec holds.

What fought back was the payoff verification, and it's the honest rough edge here. My push cut v0.364.0 and triggered the release — but both publish-kdl-read and publish-kdl-write failed, at the identical second (17:37:35, ~2m13s each). Two parallel jobs dying at the same instant is the token-PUT wall, not two build bugs — and publish-kdl-write is proven code I never touched, so its failure can't be my job. The registry did not fill: ward-kdl-{read,write}-linux-{amd64,arm64} all 404 at v0.364.0. So the issue's premise that "the grant is now effective, the next push fills the registry" did not hold this run — the write:package scope still looks ineffective. I can't confirm from the logs (this Forgejo has no run-logs API and no tasks-log verb) and can't re-trigger (no workflow_dispatch, infra#452 trap #6) or grant a secret scope from a sealed container.

Confidence: high on the code (locally verified, symmetric with the proven job), low that the registry will fill until a human actually lands the CI_RELEASE_TOKEN write:package grant. Follow-ups worth filing: (1) the token grant is still not effective — publish-kdl-write regressed to failing too, so neither tier is publishing; a human needs to verify/fix the scope, then any next push publishes both; (2) the ssh-through-docker transport check ward#547 already deferred still stands once the binary actually lands.

WARD-OUTCOME: done - publish-kdl-read producer added to release.yml (mirrors publish-kdl-write), landed on main as v0.364.0, closes #572. Read-tier build verified locally; the internal registry fill is still gated on the operational CI_RELEASE_TOKEN write:package grant. The code half felt straightforward: the issue was precise, publish-kdl-write was a clean template, and the read job is a near-mechanical mirror (read guardfile in, same generated build, same delete-then-PUT to generic/ward-kdl-read/<tag>/). I built the read tier locally the way CI does to make sure I hadn't mis-wired the guardfile path — it produces a valid 24MB ELF reporting `ward-kdl-read version v0.364.0` with zero create/edit/delete leaves, so read-only-by-spec holds. What fought back was the payoff verification, and it's the honest rough edge here. My push cut v0.364.0 and triggered the release — but **both** publish-kdl-read and publish-kdl-write failed, at the *identical* second (17:37:35, ~2m13s each). Two parallel jobs dying at the same instant is the token-PUT wall, not two build bugs — and publish-kdl-write is proven code I never touched, so its failure can't be my job. The registry did **not** fill: ward-kdl-{read,write}-linux-{amd64,arm64} all 404 at v0.364.0. So the issue's premise that "the grant is now effective, the next push fills the registry" did not hold this run — the write:package scope still looks ineffective. I can't confirm from the logs (this Forgejo has no run-logs API and no tasks-log verb) and can't re-trigger (no workflow_dispatch, infra#452 trap #6) or grant a secret scope from a sealed container. Confidence: high on the code (locally verified, symmetric with the proven job), low that the registry will fill until a human actually lands the CI_RELEASE_TOKEN write:package grant. Follow-ups worth filing: (1) the token grant is still not effective — publish-kdl-write regressed to failing too, so neither tier is publishing; a human needs to verify/fix the scope, then any next push publishes both; (2) the ssh-through-docker transport check ward#547 already deferred still stands once the binary actually lands.
Sign in to join this conversation.
No milestone
No project
No assignees
2 participants
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
coilyco-flight-deck/ward#572
No description provided.