Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Assistant: claude-code Assistant-Model: opus Assistant-Process: 673304@bnt-lap001 Assistant-Session: 959b12c7-cf2e-440b-a60d-91229cc9e96e
28 KiB
| id | type | title | domain | repo | status | owner | topic_slug | created | updated | flavor | depends_on | related | state_hub_workstream_id | ||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| NK-WP-0055 | workplan | Reach and prove security platform production readiness | infotech | net-kingdom | active | claude-code | netkingdom | 2026-10-27 | 2026-10-27 | implementation |
|
55438344-f67c-53f5-ac70-31cac1405e83 |
The estate is in builder mode. This workplan holds the work that has to pass before NetKingdom's security platform is declared production-ready. Builder-mode workplans can close with named residuals, and those residuals land here instead of keeping their source plans open. Nothing in this plan needs to run before the founder decides to move toward production.
Definition of production readiness
The security platform is production-ready when every area of the Production Readiness Checks table has its check recorded as met, with evidence, or as an accepted exception with an owner and a review date. A check counts only if it was observed on the estate that serves production traffic. Fixtures, rehearsals and builder-mode acceptances do not count. The areas are:
- Platform root custody
- MFA and identity
- Bootstrap and recovery
- OpenBao runtime secrets
- Secret rotation
- flex-auth policy state
- Topaz runtime
- Tenant onboarding
- Audit sink
- Break-glass
For Bootstrap and recovery, this plan adds three requirements, drawn from NK-WP-0049:
- Joint restore: the restored identity services and OpenBao work together for a real login.
- Recurring drill: restores are re-proved on a schedule, not just once.
- Credential cleanup: the remaining bootstrap-era credentials are rotated or revoked.
At production entry, these one-time actions must also have run:
- Revoke the initial root token. The held initial OpenBao root token is revoked with
railiance-platform/scripts/openbao_revoke_initial_root_token.py, and its receipt showsrevoked(T16).
Readiness does not mean HA. HA is a separate decision, and the current estate runs on one node.
Assess every readiness area against current evidence
id: NK-WP-0055-T01
status: done
priority: medium
assignee: claude-code
state_hub_task_id: "8c91597e-4d3e-5811-ae0d-96ff6b7d9017"
Done when: a readiness ledger
(docs/evidence/<date>-production-readiness-ledger.md) lists all ten areas, each with:
- a status: met, partial, open, or accepted exception;
- the evidence or the exact missing proof;
- the owner repository;
- the task that carries the gap.
Gaps that the tasks below don't cover get new tasks in this plan, or a pointer to an existing owner workplan. The assessment is read-only.
2026-10-27: done. Readiness ledger: 0 areas met, 7 partial, 3 open (Topaz, audit sink, break-glass). Uncovered gaps became T10–T15 below.
Build and rehearse the joint-restore drill (from NK-WP-0049-T43/T44)
id: NK-WP-0055-T02
status: wait
priority: medium
assignee: claude-code
blocking_reason: "Starts when the founder schedules the move toward production."
state_hub_task_id: "057ed64a-6f63-516a-b13c-65e7f1fd01f9"
Start from the design retained in NK-WP-0049-T43:
- the secrets-engine inherited-pipe runner (
65a3dbe), with the founder's optimizations 1, 3, 4 and 5; - the railiance-platform phase B network (
5658150:rpf64-nk49-pb,10.249.64.0/28; the rehearsal variant uses-rh-); - the client secret
keycape-secrets-engine-openbao-client(keyclient-secret), read from archive memberresources/sso/secret/keycape-secrets-engine-openbao-client.json.
The work:
- a new reviewed phase B module, with its verifier and tests;
- a single-member, non-echoing decrypt wrapper;
- the owners' adapter and runner changes;
- a synthetic-client rehearsal on the throwaway network;
- the value-free OpenBao
/jwkstrust probe.
Do not edit the pinned NK-WP-0049 T38/T40 sources.
Done when: the module, wrapper, adapter and runner are reviewed to T38 depth and the synthetic rehearsal passes.
Run the joint restore with a live consumer and a PKCE client
id: NK-WP-0055-T03
status: wait
priority: medium
assignee: claude-code
depends_on: [NK-WP-0055-T02]
blocking_reason: "Needs T02 and a founder-signed window. The letsencrypt-prod reissue for kc.coulomb.social needs a fresh duplicate-certificate check, or at least 7 days since the last issuance."
state_hub_task_id: "4037afe7-9dfa-5454-9373-f9d47f81e040"
Done when:
- restored KeyCape and restored OpenBao are joined on the isolated network;
secrets-engine-openbaopasses the native positive and negative login checks;- one browser authorization-code/PKCE client passes as well;
- the verifier has independently checked the receipt.
This closes NK-WP-0049 residuals key-cape K1 and railiance-platform R1/R2. The founder explicitly accepts the unseal window length when signing.
Re-prove the reserved-group denial and the resolver cutover (from NK-WP-0049-T21)
id: NK-WP-0055-T04
status: wait
priority: medium
assignee: claude-code
depends_on: [NK-WP-0055-T02]
blocking_reason: "Runs in the joint-restore drill environment or as its own owner-admitted live check."
state_hub_task_id: "4338365e-cdaa-5c62-880d-db3536f39fa8"
Done when:
- the deployed reserved LDAP group is natively denied, both in a positive and a negative case;
- the privacyIDEA LLDAP resolver/cutover inputs have provenance and a functional proof on the target estate.
Admit a credential lane for the attended factor diagnostic
id: NK-WP-0055-T05
status: done
priority: low
assignee: claude-code
decision_id: "55dcb6aa-e081-4aec-b644-1f49a4ec96a8"
state_hub_task_id: "9adbc2b8-3680-5d91-8a80-670f712bf9d9"
The diagnostic (mfa_state.py, check-user-mfa-state.sh) has no admitted credential. It
must not borrow KeyCape's keycape-factor-read. Live, only sso/keycape mounts that
secret, verified 2026-10-27.
Done when: the owner has an admitted delivery and execution arrangement, found through
warden route, and one attended diagnostic run passes. The alternative is an accepted
decision that the diagnostic is not needed for production.
Done 2026-10-28 by founder decision 55dcb6aa: not needed for production. Factor state is
proven by the isolated restore drill (NK-WP-0053, by-user MFA stage) and by real login;
pi-admin in the privacyIDEA UI is the attended live-repair fallback. mfa_state.py stays in the
repository but is not a production capability, and no credential lane is created for it.
Rotate or revoke the bootstrap-era and exposed credentials
id: NK-WP-0055-T06
status: wait
priority: high
assignee: claude-code
blocking_reason: "Founder rotation deferral CUST-WP-0073-T05 / decision 1591daa1 is in force until the founder lifts it."
state_hub_task_id: "a7731db5-8569-52df-99ea-c4524777d25b"
This includes the privacyIDEA credentials behind the deleted sso/keycape-pi-token and
mfa/privacyidea-trigger-admin. The architecture requires rotating bootstrap-era
credentials before live workloads rely on the platform.
Done when: each affected credential has verified revocation or rotation, with signing and client-secret preservation proven, or an accepted exception. Execution belongs to the credential owners. This task tracks it and does not duplicate CUST-WP-0073.
Make restore assurance recurring
id: NK-WP-0055-T07
status: todo
priority: medium
assignee: claude-code
state_hub_task_id: "15ae6653-898c-593c-8ba9-35b7bd5a50a0"
Carries NK-WP-0049-T24 G3 and railiance-platform R6 (RPF-WP-0036-T03).
Done when: a scheduled drill re-proves the isolated identity and OpenBao restores on the current backup generation. It must include:
- image-lineage proof (R5);
- the audit-device mount (R8);
- a reconciliation procedure for changes made after the archive was taken (K2).
Drill results land in the readiness ledger.
2026-10-27: the identity drill already lives in NK-WP-0053 (quarterly isolated identity restore drill; T02 first run, T04 admin-operated). This task tracks NK-WP-0053 and RPF-WP-0036-T03 (scheduled OpenBao snapshot) rather than building a second drill; it adds only image lineage, the audit-device mount and the post-archive reconciliation procedure.
Finding 2026-10-29: no identity backup from 2026-10-20 to 2026-10-29. The NK-WP-0053 drill could only
pick generation 20261019T034919Z, older than admin's OTP enrolment, so stage 5 found no token
(user_token_count: 0); stages 2 to 4 passed on that generation. Cause: net-kingdom-identity-backup.service
refused daily since 2026-10-20 03:47 UTC at its first Storage Share check, which needs 2 GiB headroom plus one
512 MiB bundle free. The Backup account has 10 GiB in total; the validated 5.35 GB full Forgejo archive in
railiance-backups/forgejo/ (RPF-WP-0038) plus nightly CNPG dumps that are pruned only locally
(cnpg-option-a-backup, about 2.5 GiB in r01-net-kingdom-pg) used it up. Ruled out read-only: run marker,
local disk, accepted recovery receipt, publisher and retention ExternalSecrets, all profile bindings, database
primary, NetworkPolicies. Detection gap: the hourly health check failed and posted plain hub progress notes
(103 of the last 500 events) that raised no alert. Relief 2026-10-29: the founder removed the contents of
railiance-backups/forgejo/, consistent with the founder's 2026-10-11 decision that Nextcloud carries only
Forgejo essentials while full archives live on Scaleway; this lifts the 2026-09-15 no-expiry decision for that
folder. Follow-ups routed to owners: railiance-platform (CNPG remote retention, Forgejo essentials-only
secondary, confirm a verified full Forgejo archive on Scaleway, quota), disaster-control (alert on backup
refusal). Next: a fresh generation, then drill stages 1 and 5 on it.
2026-10-29/30: fresh generation 20261029T230600Z captured after space was freed; the NK-WP-0053 drill
passed on it (next due 2027-01-29). G1 decision e8935fa6: second-provider intake to railiance-platform for
a Scaleway secondary of the full identity bundle; this task tracks it, with the Backup quota, CNPG remote
retention and the refusal/staleness alert.
Decide durable custody for receipts kept outside Git
id: NK-WP-0055-T08
status: done
priority: low
assignee: claude-code
needs_human: true
decision_id: "3291751f-4dad-4b19-bee9-379368962046"
state_hub_task_id: "4533872f-ccfa-5538-96ed-a3bad0ea550e"
The T18 KeyCape receipt (16d72f7c…1651) and the OpenBao restore receipt
(4e048dee…579d) exist only on the founder workstation, because the secret scanners flag
their public digests.
Done when: an accepted custody location with a second copy holds them, still bound by their recorded hashes, or the founder accepts single-copy custody as an exception.
2026-10-28 founder decision 3291751f: Storage Share, sealed to the railiance-backup age key
with kingpath-offsite.py, beside the break-glass copy. --verify gained --expect NAME=SHA256
(3 new tests, 24 total), so the read-back binds each item to its recorded digest without printing
content. Founder run, in your own terminal from ~/net-kingdom:
sha256sum <keycape-t18-receipt> <openbao-restore-receipt> # must show 16d72f7c…1651 and 4e048dee…579d
python3 tools/bootstrap-recovery/kingpath-offsite.py \
--item nk49-t18-keycape-receipt=<keycape-t18-receipt> \
--item rpf64-t07-openbao-receipt=<openbao-restore-receipt> \
--receipt ~/nk-wp-0055-t08-upload.json
sso-mfa/bootstrap/sops-custody-unlock.sh --sealed-fd \
--expected-recipient "$(python3 -c 'import json;print(json.load(open("tools/bootstrap-recovery/identity-backup-profile.json"))["public_recipient"])')" -- \
python3 tools/bootstrap-recovery/kingpath-offsite.py --verify ~/nk-wp-0055-t08-upload.json \
--expect nk49-t18-keycape-receipt=<full sha256 16d72f7c…1651> \
--expect rpf64-t07-openbao-receipt=<full sha256 4e048dee…579d> \
--receipt ~/nk-wp-0055-t08-verify.json
The full digests are kept out of this file because the secret scanner flags them; they are in
docs/evidence/2026-10-23-nk49-t18-keycape-attempt/verifier-output.json and railiance-platform
workplans/RPF-WP-0064-isolated-original-openbao-restore.md. Both files must be mode 0400 or 0600. The sealed key is the railiance-backup key (crisis item 1),
not the custodian key. Done when the verify receipt shows status: verified with both names
under sha256_matched; the upload and verify receipts are value-free and can be committed under
docs/evidence/.
Done 2026-10-30 (founder-run): both receipts sealed to Storage Share as
net-kingdom-kingpath-20261030T212015Z-96b930bcfb9d.tar.age, read back, then fetched and decrypted in memory
with the railiance-backup key: status: verified, both names under sha256_matched, unrelated key refused,
no plaintext on disk. Upload receipt and verify summary.
Founder production-scope decisions
id: NK-WP-0055-T10
status: done
priority: high
assignee: claude-code
needs_human: true
decision_id: "37464824-a939-415f-8a7a-5f81cbf498c8"
Decide what production requires: (a) whether manual Shamir unseal is the approved production mechanism, or auto-unseal is required; (b) whether a delegated Topaz PDP is required, or the access-engine Go core satisfies the PDP area; (c) who the two-of-three escrow holders and the OpenBao unseal share holders are (names and places, never values); (d) that HA stays out of scope.
Done when: each answer is recorded as a hub decision and reflected in the ledger.
2026-10-27 founder answers: (a) manual Shamir unseal is the approved mechanism for now; (c) the founder, as platform-root, holds the OpenBao unseal shares (single holder; two-of-three escrow holders not named); (d) HA stays out of scope for now. (b) Topaz is pending an explanation of the accepted-exception consequences.
2026-10-27: done. (b) accepted as an exception: the access-engine core is the production PDP, Topaz is deferred (ADR-0018); (c) single-holder custody accepted as an exception. All answers are in hub decision 37464824 and the ledger. Exceptions are reviewed at T09.
Get every audit source into the durable sink with one correlation id
id: NK-WP-0055-T11
status: progress
priority: high
assignee: claude-code
state_hub_task_id: "93caa9e0-3d28-58ac-808a-47e15fe6d6ab"
Owners are audit-core (receiving), railiance-platform (OpenBao audit forwarding), railiance-cluster (Kubernetes API audit), access-engine (AUDIT-WP-0013-T02 registration) and NetKingdom (identity-provider events and the correlation-id contract). Topaz is not a source (ADR-0018).
Done when: each owner has a task in its own workplan; identity, authorization, OpenBao, Kubernetes and workload records land durably; one correlation id is defined and tested across the onboarding chain; audit-core has a recurring restore drill and AUDIT-WP-0015-T01's offsite chain head.
2026-10-27 owner scoping (proposed workplans, unpushed in the owner repos): audit-core AUDIT-WP-0017 (ead0f09: intake package per sender, correlation field, quarterly restore drill, offsite chain head); railiance-platform RPF-WP-0066 (87a488c: file audit device plus async sidecar shipper, snapshots, live conformance); railiance-cluster RCLUSTER-WP-0021 (3ed1ac1: k3s audit policy, node buffer, shipper, founder-run restart); access-engine FLEX-WP-0031-T10/T11 and FLEX-WP-0039 (7cbd4e5). NetKingdom's part: the Audit Correlation Contract v0.1 (proposed) and the four identity-provider intake packages (still to draft). Noted: audit-core lists six access-engine pins, the registry has nine.
2026-10-27 identity-provider intake: KeyCape package and propagation task in key-cape KEY-WP-0044 (9adfb0b; KeyCape emits stdout JSON only, /token failures, client-auth failures, revoke and introspect are unaudited today, issuance lacks subject/tenant). Authelia, LLDAP and privacyIDEA packages in docs/audit-core-intake-identity-providers.md (ccd0b15, draft): Authelia via a read-only SQLite sidecar plus JSON logs; LLDAP text logs, image must be pinned first; privacyIDEA signed pidea_audit export with signatures intact. Open decision for audit-core and the founder: signed privacyIDEA rows carry raw usernames and IPs, and pseudonymising them breaks the signature.
Record live conformance receipts
id: NK-WP-0055-T12
status: todo
priority: medium
assignee: claude-code
state_hub_task_id: "c93fa290-663a-582c-a5b2-beb876fcff1e"
Done when: dated receipts exist for the live IAM issuer conformance run (NK-WP-0054-T04), caller-auth enforcement on every
access-engine release unit (only ops-warden is proven today), the access-engine core's health, data freshness, policy load
status and per-consumer fail-closed stance (ADR-0018), the live OpenBao auth methods and mounts against the committed
policies, and the tenant onboarding completion test for tenant:coulomb.
Record and drill break-glass with SSO down
id: NK-WP-0055-T13
status: done
priority: high
assignee: claude-code
state_hub_task_id: "6dfdf2be-e87a-5368-b2b6-45dcb92fe6e4"
Done when: the crisis custody list items 4, 7 and 9 are confirmed (kept current by NK-WP-0054-T07; item 8 retired 2026-10-27); the
break-glass material is on Storage Share via kingpath-offsite.py; the OpenBao generate-root ceremony is written with
railiance-platform; and the founder drills the path with KeyCape/Authelia down, including a validity check of the held initial
root token against an isolated restored OpenBao (never production); use produces a post-event review record.
2026-10-27 documentation pass: the crisis custody list (items 3, 7, 9) and the disaster recovery guide (new section "Reaching the platform when SSO and OpenBao are down") now record what is known. Findings: ops-warden SSH certificates do not work with OpenBao down (warden backend is OpenBao); the working path today is the static-key tunnel k3s-api-railiance01 as tegwick plus the admin kubeconfig client certificate, workstation-only with no second copy; the OpenBao generate-root break-glass ceremony is undocumented; provider console access, the ops bundle location (item 8) and offline/mirror status of the password safe are TO CONFIRM.
2026-10-27 founder answers: unseal shares and pi-admin are in the founder's replicated browser password safe (unseal shares under the kingpath.credentials pseudo-URL entry); console and rescue access to railiance01 through the Host Europe provider interface; the ops bundle and the cluster break-glass material (static tunnel key, admin kubeconfig) are to be kept age-encrypted on the Storage Share Backup account so they survive workstation loss. Next: a guarded upload helper with readback (founder-run), the generate-root ceremony with railiance-platform, and the king-path drill. Still open: whether the initial OpenBao root token was kept or revoked.
2026-10-27: the founder holds the initial OpenBao root token offline; whether it is still valid is unconfirmed (no rotation was recorded). Built tools/bootstrap-recovery/kingpath-offsite.py with 11 contained tests: it seals named private files in memory to the railiance-backup recipient, uploads to Backup/railiance-backups/net-kingdom-kingpath/ without overwriting, and reads back with a hash check. Founder-run. No ops bundle exists on the workstation (make creds-bundle packs only greenfield creds-generate output); the daily identity backup already carries current service secrets, so item 8 is proposed for retirement as superseded.
2026-10-27 founder decisions: the ops bundle (crisis list item 8) is retired as superseded by the identity backup; the initial root token validity check is folded into the king-path drill, run against an isolated restored OpenBao.
2026-10-27: founder ran kingpath-offsite.py: net-kingdom-kingpath-20261027T223050Z-8c9d48421f1b.tar.age (items admin-kubeconfig, tunnel-ssh-key) sealed to railiance-backup, uploaded to Backup/railiance-backups/net-kingdom-kingpath/ and read back (sha256 8c9d48421f1b…dd4aa, ETag "5a14c69d…8252"). Restoring it from Storage Share is part of the king-path drill.
2026-10-27: railiance-platform wrote "Break-glass: OpenBao with SSO down" in docs/openbao.md (8016f56, pushed): access via the static-key tunnel and admin kubeconfig, unseal at hidden prompts, value-free held-token check, the generate-root ceremony through the API (server OTP, shares at hidden prompts, in-memory decode, nothing in argv/env/history), revoke-and-confirm, and a post-event review record. Drill: RPF-WP-0064-T10 on an isolated restore, including the held root-token check. Finding: OpenBao 2.5.4 disables unauthenticated generate-root by default and the production listener (rapp-openbao/helm/openbao-values.yaml) does not enable it, so the ceremony cannot run on production without an existing token. rapp-openbao must choose (a) an incident-time listener edit plus restart and re-unseal, or (b) a standing loopback-only listener reachable only through kubectl port-forward/exec.
2026-10-27 founder decision (hub decision 732b5c96): option (b), a standing loopback-only OpenBao listener with generate-root enabled, reachable only through kubectl port-forward/exec with the admin kubeconfig. Owner rapp-openbao prepares the change for founder review and rollout.
2026-10-27: kingpath-offsite.py --verify UPLOAD_RECEIPT added for the drill (7 more contained tests, 18 total): run under sops-custody-unlock.sh --sealed-fd, it checks the custody key against the recorded recipient, fetches the artifact with ETag/size/digest checks, refuses an unrelated key, decrypts in memory and checks each item's size and shape (kubeconfig with clusters/users, SSH private key header), writing a value-free receipt. The OpenBao part of the drill is RPF-WP-0064-T10 (drill mode being built).
2026-10-27 king-path drill, part 1 (founder-run): kingpath-offsite.py --verify restored net-kingdom-kingpath-20261027T223050Z-8c9d48421f1b.tar.age from Storage Share, refused an unrelated key, decrypted in memory and found admin-kubeconfig (kubeconfig shape) and tunnel-ssh-key (SSH private key header) intact. The custody helper refused the custodian age key three times before the founder entered the railiance-backup key; crisis list item 1 is split into 1 (backup key) and 1b (custodian key) so the two are not confused again. Part 2 (OpenBao, RPF-WP-0064-T10) is being built.
2026-10-28: founder rolled out the loopback generate-root listener (RAPP-OPENBAO-WP-0003-T02): 200 on 8210 without a token, 405 on the main listener 8200. The break-glass ceremony can now run on production with SSO down. railiance-platform built and rehearsed the drill mode for part 2 (RPF-WP-0064-T10, a2da408: 34 offline tests, native rehearsal 16/16); its production read-only walk must be updated to expect 200 on 8210.
2026-10-28: crisis list item 5 now records the admission signing key's fingerprint and both public anchor lines, so a recovery workstation can re-create them; founder decision: the private key goes to the password safe kingpath entry, not the Storage Share bundle. Its file on the workstation is still being located.
2026-10-28 king-path drill part 2 (founder-run): RPF-WP-0064-T10 attempt -20261027-01 drilled in 101 s, receipt e4591346…8397 independently verified (PASS). Held initial root token valid as of the 2026-10-14 snapshot; fresh generate-root with re-entered shares, read-only action, revoke 204, lookup 403, cancel drilled, full teardown. Post-event record: 2026-10-28 king-path drill. Open: founder decision on the production root token, the read-only production SSO-down walk, the signing key copy in the safe.
2026-10-28: done. The production read-only SSO-down walk passed (OpenBao unsealed 2/3; break-glass listener 200, main listener 405); RPF-WP-0064-T10 is done. Crisis list items 4, 5, 7 and 9 are confirmed; item 8 is retired; the break-glass material is on Storage Share; the ceremony is written and drilled; the post-event record exists. Residuals go to the recurring drill (NK-WP-0053): using the restored item-9 material against the cluster, and the Host Europe console. The production-entry root-token revoke is T16. Readiness area 10 (break-glass) is now partial.
Policy import pipeline and platform/tenant package split
id: NK-WP-0055-T14
status: todo
priority: medium
assignee: claude-code
state_hub_task_id: "bd28a970-9616-5323-9f97-d5b260a144f1"
Owner: access-engine. Done when: policy changes are imported without rebuilding the image, tenant:coulomb has platform and
tenant packages split, one production explain receipt exists, and FLEX-WP-0031 (decision records) and FLEX-WP-0024 (signed
envelope) are delivered or accepted as exceptions.
2026-10-27 founder decision: import path B, a policy bundle mounted into access-engine and pinned by digest, so policy changes no longer need an image rebuild; move to C (signed bundle) once FLEX-WP-0024 signing custody exists. Delivery sits in access-engine FLEX-WP-0039-T03.
Register rotation lanes with blast radius and verification
id: NK-WP-0055-T15
status: done
priority: medium
assignee: claude-code
state_hub_task_id: "d9c0584e-10a1-5edf-a1f9-cec5738f94a8"
Done when: every service, database, OpenBao-issued, client-secret and break-glass credential lane is listed with its blast radius and verification step, linked to its owner lane (RPF-WP-0035, RPF-WP-0055-T01, T06).
Done 2026-10-28. tools/rotation-lanes/lanes.yaml lists 24 lanes (service, database,
client-secret, OpenBao-issued, break-glass), each with path, blast radius, verification step
and owner lane. make rotation-lanes-check derives every known credential from the
service-identity declarations, Credential Management v0.2 section 6 and the crisis custody list,
and fails on a credential without a complete lane; 7 synthetic tests plus a test on the
checked-in register. State today: 5 admitted, 7 designed, 10 deferred (rotation deferral
1591daa1, T06), 2 none (PI_PEPPER, the legacy trigger-admin to be revoked). Readiness
notes for T09: KEYCAPE_RSA_KEY has no overlap rotation (single kid, rotation is an outage
window); LLDAP_LDAP_USER_PASS stays three-way coupled until the NK-WP-0054-T05 bind split.
Revoke the held initial OpenBao root token at production entry
id: NK-WP-0055-T16
status: wait
priority: high
assignee: claude-code
blocking_reason: "Founder decision 7ce684ec: the token stays escrowed during builder mode and is revoked at production entry."
state_hub_task_id: "39e4d90e-b69f-5e24-be82-17d76c4a540d"
The king-path drill (2026-10-28) found the held initial root token valid as of the 2026-10-14 snapshot: root,
orphan, no TTL. The guarded script railiance-platform/scripts/openbao_revoke_initial_root_token.py (95b5a19,
7 tests) reads the token at a hidden prompt. It refuses to revoke unless the loopback generate-root listener
answers, so a replacement break-glass path exists first, and it writes a value-free receipt. The runbook is in
railiance-platform/docs/openbao.md.
Done when: at production entry, the founder runs revoke under the production-entry decision id; the
receipt shows revoked (revoke-self 204, then lookup-self 403); the token is removed from the password safe;
and crisis list item 3 is updated.
Close readiness and declare production
id: NK-WP-0055-T09
status: wait
priority: high
assignee: claude-code
depends_on: [NK-WP-0055-T01, NK-WP-0055-T03, NK-WP-0055-T04, NK-WP-0055-T05, NK-WP-0055-T06, NK-WP-0055-T07, NK-WP-0055-T08, NK-WP-0055-T10, NK-WP-0055-T11, NK-WP-0055-T12, NK-WP-0055-T13, NK-WP-0055-T14, NK-WP-0055-T15, NK-WP-0055-T16]
blocking_reason: "Every readiness area must be met or an accepted exception."
state_hub_task_id: "0630b0ea-dec1-5355-8b08-0d317d4a3c9b"
Done when:
- the readiness ledger shows every area as met or as an accepted exception;
- the founder records the production declaration as a decision;
- SCOPE.md's capability table is updated to match.