ops-warden/workplans/WARDEN-WP-0037-whynot-design-forgejo-npm-lane.md
tegwick baf53602ca Revert the npm field, re-measure coverage, and hold the layer divergence
Five inbox items worked, none of which changed a credential value or moved a
secret.

whynot-design-npm-publish: field reverted npm_token -> NPM_AUTH_TOKEN and the
path confirmed, on railiance-platform's attended, read-only, no-value field
enumeration (their docs/evidence/2026-09-10-npm-lane-field-resolution.json).
Exactly one field is present at the governed path. The 2026-09-09 change was
adopted from a coordination message and would have failed at the WP-0037-T03
rotation. The ungoverned second location is recorded as an explicit non-lane,
not deleted and not tidied away.

pep-stance coverage: published figures were stale by eight lanes (unknown
18->20, not_applicable 12->15) while resolved stayed at 3 — the denominator
moved, the classification did not. Caught by the test that asserts the published
block equals what report_coverage.py measures. tests/test_workload_join.py held
the same stale counts; both now measure the same populations.

rapp-qonto-keycape-client: blocker character updated — authority exists and is
unexercised by owner decision ("not yet", offer open), which is not the same as
no authority existing. Reopen triggers are events, never elapsed time.

flex-auth -> access-engine rename (WARDEN-IN-0003): access-engine added to the
policy-check lane's keywords so routing resolves under both names from today.
owner_repo deliberately not flipped — policy.py sends it as resource.system on
every /v1/check, and FLEX-DEC-2026-013 keeps runtime names as flex-auth.

layer declaration: INTENT.md says Staff, layer.yaml says staff, section 11 does
not say which governs. Neither changed; gate-house holds the ruling. Position in
docs/layer-declaration-precedence.md, wait in WARDEN-WP-0034-T06, and a comment
in layer.yaml telling the next session not to "fix" it — the divergence is the
evidence the ruling is made against.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

Assistant: claude-code
Assistant-Model: opus
Assistant-Process: 63291@bnt-lap001
Assistant-Session: 8bd77868-ca68-4f49-bb1e-d539ecc0d703
2026-09-21 02:16:33 +02:00

7.8 KiB

id type title domain repo status flavor owner topic_slug created updated state_hub_workstream_id
WARDEN-WP-0037 workplan Repoint the whynot-design npm lane to Forgejo infotech ops-warden active planning codex whynot-design-forgejo-npm-lane 2026-09-04 2026-09-21 42a097db-1c24-558e-a724-030bb2b4443e

Verify the existing credential against Forgejo

id: WARDEN-WP-0037-T01
status: done
priority: high
state_hub_task_id: "afc4d325-1c6d-5c25-aaf7-2118aa8f86c6"

Use only the governed execution transport to test the existing publish identity against the canonical Forgejo npm endpoint. Do not print or persist the token.

2026-09-04: warden plan classified the exact verification as autonomous and selected this lane. A contained login using the documented whynot-design-workload-kv-read role proved read on the exact OpenBao data path, and the governed child proved the secret is present. A real 0.4.2 publish through that credential then failed. No value was printed or persisted and each contained session self-revoked. The lane therefore needs token rotation, not an OpenBao policy repair.

Repoint the catalog and playbook

id: WARDEN-WP-0037-T02
status: done
priority: high
state_hub_task_id: "7ceb2f74-496c-54e8-bf5a-3c49f994ff23"

Replace the retired Gitea endpoint and discovery language with Forgejo while preserving the established OpenBao path, field, and least-privilege boundary. This delivers the npm facet of routed intake 01a06e07-f2f9-7586-9745-b359eb0025b6; its inter-hub SSH facet remains separate.

Completed 2026-09-04. The catalog title, discovery keywords, rotation guidance, and worker playbook now name the canonical Forgejo registry at https://forgejo.coulomb.social/api/packages/coulomb/npm/. The OpenBao path, field, owner, native-exec pointer, and high-risk boundary are unchanged. A regression assertion prevents the retired Gitea discovery term and guidance from returning.

Prove routing and publication

id: WARDEN-WP-0037-T03
status: wait
priority: high
needs_human: true
intervention_note: "Rotate the dedicated Forgejo package token, then prove a fresh publish and exact npm view through this lane."
state_hub_task_id: "a8b1b855-ab34-5835-b9fd-5f48bc0b6817"

Pass catalog and routing tests, verify the checkout route, and record the exact Forgejo package release proven through the lane.

2026-09-04: repo-local verification is complete: the checkout route ranks whynot-design-npm-publish first for a Forgejo npm publish need, reports the canonical Forgejo title and verification command, all focused routing/access/proxy tests pass (145 passed).

The sibling repo's @whynot/design@0.4.2 release (105 files; IR designVersion 0.4.2; five visual tests pass) was published through the plan-authorized forgejo-admin-api-token one-time recovery lane. An authenticated exact-version lookup proved that Forgejo's remote integrity matches the local dry-run. T03 waits only on rotating the dedicated package token and proving the next fresh version through whynot-design-npm-publish; the package migration itself is complete.

2026-09-09 — field claim corrected, path routed. secrets-engine (msg 15f0c0ca) corrected two things and declined a third, all correctly.

The KV field is npm_token. NPM_AUTH_TOKEN is the environment variable their publication-scope policy injects, and ops-warden had copied the env var in as the field name — so the catalog's fetch_command named a field that does not exist and could only ever have failed. Corrected in registry/routing/catalog.yaml and wiki/playbooks/whynot-design-npm-publish.md from the owner's statement rather than re-derived here. This was ADR-0001's failure mode rather than a typo: a pointer layer restating an owner's procedure and getting a detail wrong.

The endpoint claim already agreed; delivery_config.npm.registry has been the Forgejo URL throughout.

The path is routed to railiance-platform and the catalog is unchanged pending their answer. Which location backs the lane for reads is custody state they own; secrets-engine has no lane read authority to confirm it and refused to rewrite a production lane pointer from a coordination message (SECRETS-WP-0006-T06). Their reasoning is right, and asserting our own pointer is authoritative because it is ours would route around it. The ask names a location only and flags that a bao kv get answer would be the 2026-07-16 disclosure vector on a risk: high lane.

ready: false is not being read as path evidence: a source checkout with no production authority reports not-ready regardless of which path the catalog names.

T03 still waits on the human rotation of the dedicated Forgejo package token; the path question does not block that, it determines whether the pointer is correct once it rotates.

2026-09-21 — field reverted to NPM_AUTH_TOKEN; path confirmed; a second location found. railiance-platform, who holds custody of the path, answered both halves (msgs c6841bdb, 79f3e047) and the answer reverses the 2026-09-09 change above.

An attended founder session enumerated the field names present at platform/workloads/coulomb/whynot-design/npm-publish: read-only, no mutation, no value emitted, attended_identity true. Exactly one field is present, and it is NPM_AUTH_TOKEN. Receipt: railiance-platform docs/evidence/2026-09-10-npm-lane-field-resolution.json, commit 9d24086. The both-fields reconciliation offered the day before is ruled out by the same enumeration. CCR-2026-0001 has carried two dated receipts naming that field since 2026-06-28, one of them an attended founder fetch that exited zero — which is itself proof the field exists.

So npm_token is wrong for this path, and the catalog and playbook are reverted to NPM_AUTH_TOKEN. Reverting is a correction back to the evidenced value, not a new lane change.

The lesson is the one this plan already recorded, one level in. On 2026-09-09 this file wrote that adopting a correction from secrets-engine rather than re-deriving it was the right shape. It was the right source and the wrong standard of evidence: a correction adopted from a coordination message is still an unverified mutation, even when it is only a field name in a catalog, and this one would have failed at the rotation T03 is waiting for — the moment it is most expensive to discover. railiance-platform's phrasing, kept because it is better than ours: it will break "at the moment you least want it to".

The second location, which is not ours to dispose of. secret/coulomb/whynot-design/npm/publish exists — version 1, created 2026-07-03T15:00:44Z, never updated, five days after the governed lane was verified. It sits outside this lane's exact-path policy and outside any CCR. railiance-platform read metadata only: field names were not enumerated, the value was not read, nothing was deleted, because a location holding real credential material is disposed of deliberately by its owner rather than tidied away by whoever finds it.

Their unconfirmed hypothesis, recorded because it changes what this lane's acceptance evidence means if true: secrets-engine's lowercase field may belong to that path, their catalog may declare that location, and the proven pilot publish may have been reading the duplicate all along. If so, a working production lane has been running ungoverned and this lane's acceptance evidence describes a path its consumer does not use. Tracked as RPF-WP-0035-T07; railiance-platform has asked secrets-engine which location their publish reads, and ops-warden has asked the same about the native secrets-engine exec front door this catalog points at (exec_owner).

Recorded in the catalog and in wiki/playbooks/whynot-design-npm-publish.md as an explicit non-lane rather than deleted from the record. Not routed around: the governed path stays the pointer.