docs: preserve reviewed NetKingdom session artifacts
Some checks failed
CI Smoke / host-smoke (push) Successful in 0s
CI Smoke / container-smoke (push) Successful in 2s
Reject generated-only commits / generated-commit-guard (push) Has been cancelled

This commit is contained in:
codex 2026-11-01 23:35:28 +01:00
parent c6410777ac
commit 6f29868361
50 changed files with 4632 additions and 0 deletions

View file

@ -0,0 +1,10 @@
{
"status": "disproven-assumption",
"original_source_commit": "5596185e71db4bff092b75af4d647e7501d47ff9",
"evidence_tip": "a4e90c68604253b9284ba4f67c3f3cad5d80970a",
"tree_identical": true,
"default_rev_list_objects": 237,
"original_commit_only_claim_false": true,
"main_push_not_attempted": true,
"all_ten_prior_receiver_results_retained": true
}

View file

@ -0,0 +1,10 @@
{
"status": "fast-forwarded-locally",
"old_commit": "5596185e71db4bff092b75af4d647e7501d47ff9",
"new_commit": "b17e753efc8022fd482e3b2169ba3a604e4bb526",
"same_tree": true,
"original_commit_retained": true,
"original_complete_index_entries_preserved": true,
"unrelated_worktree_preserved": true,
"force_or_history_rewrite": false
}

View file

@ -0,0 +1,53 @@
"""Real SOPS regressions with generated keys, no host custody or network mounts."""
from pathlib import Path
import fcntl, hashlib, json, os, resource, subprocess
BASE=Path(__file__).resolve().parent
SOURCE=Path('/tmp/custodian-sops3133-fd/source')
BINARY=Path('/tmp/custodian-sops3133-test/bin/sops')
PIN='e5bec3346a873ae91d871550f3e698c1aad962aff462a080e40f25fde17fef6b'
metadata=json.loads((BASE/'sops-source-tool.json').read_text())
for relative,digest in metadata['public_source_files'].items():
assert 'sha256:'+hashlib.sha256((SOURCE/relative).read_bytes()).hexdigest()==digest
binary=BINARY.read_bytes();assert hashlib.sha256(binary).hexdigest()==PIN
fd=os.memfd_create('custodian-generated-sops-test-binary',os.MFD_ALLOW_SEALING)
os.write(fd,binary);os.lseek(fd,0,os.SEEK_SET)
fcntl.fcntl(fd,fcntl.F_ADD_SEALS,fcntl.F_SEAL_WRITE|fcntl.F_SEAL_GROW|fcntl.F_SEAL_SHRINK|fcntl.F_SEAL_SEAL)
script='''import json, os, pathlib, subprocess, sys
assert not pathlib.Path('/home/worsch').exists()
assert not pathlib.Path('/etc/rancher').exists()
assert not pathlib.Path('/home/tester/.config').exists()
assert not pathlib.Path('/proc/net/route').read_text().splitlines()[1:]
assert os.stat('/tmp').st_uid==os.getuid()
r=subprocess.run(['/usr/bin/python3','-m','pytest','-q','-c','/dev/null','-p','no:cacheprovider','--tb=no','--basetemp=/tmp/generated-sops-tests','/work/tests/test_sops_private.py','/work/tests/test_sops_write.py'],capture_output=True,text=True,timeout=150)
# Pytest tracebacks/captured tool output are never emitted. Retain its closed
# count summary only, including any failures rather than treating exit as proof.
lines=[line for line in r.stdout.splitlines() if __import__('re').fullmatch(r'[0-9]+ (?:passed|failed|skipped|error|errors)(?:, [0-9]+ (?:passed|failed|skipped|error|errors))* in [0-9.]+s',line)]
print(json.dumps({'status':'passed' if r.returncode==0 else 'failed','exit_code':r.returncode,'count_summary':lines,'private_diagnostics_suppressed':True,'generated_material_only':True,'host_custody_mounted':False,'network_routes_absent':True}))
sys.exit(r.returncode)
'''
command=['/usr/bin/bwrap','--unshare-all','--die-with-parent','--new-session','--clearenv','--cap-drop','ALL',
'--ro-bind','/usr','/usr','--symlink','usr/bin','/bin','--symlink','usr/lib','/lib',
'--ro-bind-try','/lib64','/lib64','--proc','/proc','--dev','/dev','--dir','/etc',
'--size','67108864','--tmpfs','/tmp','--tmpfs','/home','--dir','/home/tester',
'--ro-bind',str(SOURCE),'/work','--dir','/tools','--perms','0500','--ro-bind-data',str(fd),'/tools/sops',
'--setenv','PATH','/tools:/usr/bin:/bin','--setenv','HOME','/home/tester',
'--setenv','LANG','C.UTF-8','--setenv','PYTHONDONTWRITEBYTECODE','1',
'--setenv','PYTEST_DISABLE_PLUGIN_AUTOLOAD','1','--setenv','GOMAXPROCS','2',
'--chdir','/work','--','/usr/bin/python3','-c',script]
def limits():
resource.setrlimit(resource.RLIMIT_CPU,(120,120))
resource.setrlimit(resource.RLIMIT_AS,(8*1024**3,8*1024**3))
# bwrap copies the sealed 52-MB tool into an anonymous read-only bind file.
# The fixture's writable /tmp remains independently bounded to 64 MiB.
resource.setrlimit(resource.RLIMIT_FSIZE,(64*1024**2,64*1024**2))
try:
result=subprocess.run(command,pass_fds=(fd,),capture_output=True,text=True,timeout=180,preexec_fn=limits)
finally:os.close(fd)
try:receipt=json.loads(result.stdout)
except ValueError:receipt={'status':'unverified','exit_code':result.returncode,'fixed_reason':'namespace_preflight_or_runtime_failed','private_diagnostics_suppressed':True}
receipt.update(binary_sha256='sha256:'+PIN,driver_sha256='sha256:'+hashlib.sha256(Path(__file__).read_bytes()).hexdigest(),
namespace_teardown_complete=True,system_installation=False)
(BASE/'sops-real-regressions.json').write_text(json.dumps(receipt,indent=2)+'\n')
print(json.dumps(receipt))
raise SystemExit(result.returncode)

View file

@ -0,0 +1,12 @@
Traceback (most recent call last):
File "/home/worsch/repo-manager/.venv/bin/rmgr", line 8, in <module>
sys.exit(main())
^^^^^^
File "/home/worsch/repo-manager/src/repo_manager/cli.py", line 853, in main
result = sync_repository_projection(
^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/worsch/repo-manager/src/repo_manager/projection_sync.py", line 256, in sync_repository_projection
_pending_path(repo_root).unlink(missing_ok=True)
File "/usr/lib/python3.12/pathlib.py", line 1344, in unlink
os.unlink(self)
OSError: [Errno 30] Read-only file system: '/home/worsch/state-hub/.git/repo-manager/pending-work-record-projection.json'

View file

@ -0,0 +1,129 @@
# Configured-hook scanner unavailability fixture
Prepared against repo-manager `b02e1cefb0e07fe246dc9fe9c5a989fe06116587` to finish
only RMGR-WP-0021-T05's actual configured-hook unavailability check. Source and
remote receive/CI acceptance remain separate. Canonical files are unchanged by
this packet. The coordinator executed the independently reviewed R3 runner
successfully: ten unit checks, namespace hard-loss lifecycle and six actual
configured-hook cases passed. The owner completion patch is prepared for review
and has not been applied by this agent.
The existing root-owned non-setuid Bubblewrap is pinned by SHA256. The coordinator's
prior disposable capability probe passed; see the adjacent
`namespace-capability-sandbox.json`. No install, system setting, host scanner
permission change or privileged host mutation is proposed.
`run_reviewed_fixture.sh` runs ten profile tests, a generated namespace hard-loss
probe, then six actual configured-hook cases: clean, generated private key and
scanner unavailable for the shared repo-manager and Custodian hooks. The exact
files/hashes, expected results and resource bounds are in `manifest.json`.
The unavailable case overlays the exact admitted scanner pathname with a newly
created empty 0400 regular file using a read-only namespace bind. Only that new
empty fixture receives chmod; the actual scanner file is never modified. The
canonical hook still calls the canonical source and exact configured scanner
pathname. Namespace readback verifies the real scanner in both controls and the
empty non-executable shadow in the unavailable case. Expected refusal is exit 2,
`unverified`, `scanner-file-refused`, zero scanned blobs.
Every hook runs in fresh user, mount and network namespaces. Root is bound read
only, and the original `/dev/shm` is bound writable over itself. The bootstrap
checks root and `/dev/shm` device/inode identity, read-only/writable flags, UID/GID,
changed user/mount/network namespaces, preserved PID namespace, canonical source,
actual hook and `/usr/bin/python3` hashes before exec. It writes fixed metadata
readback only into the private volatile fixture. Network namespace isolation
adds no provider or network calls.
PID namespace isolation is deliberately absent. Destroying a PID namespace would
also destroy the canonical scanner's independent cleanup observer before it can
remove volatile files. Shared PID identity preserves the admitted pidfd and
parent-death behavior. Bubblewrap's `--die-with-parent` bounds the hook command;
canonical Git/scanner children use parent-death SIGKILL. The independent watchdog
survives source-parent death and performs guarded cleanup. The outer fixture also
uses the canonical private-tmpfs watchdog, registered before generating bytes.
`probe_namespace_lifecycle.py` tests this interaction before any actual hook
case. It creates a disposable spawner, namespace inner process and canonical
cleanup observer, writes a public generated sentinel, publishes atomic early PID readiness before source storage, waits for the
coordinator to register exact Bubblewrap/inner pidfds and release an exact generated
gate, then creates source storage and kills only the new spawner. A missing gate
refuses storage after eight seconds. Acceptance requires proven death of the spawner,
Bubblewrap, namespace inner process and cleanup observer, and disappearance of
inner and outer volatile directories. Exceptional cleanup quiesces known source
and readback creators before removing their outer directory. It never kills the
calling shell/tool/harness or an untracked process group. If exact death cannot
be established, the observer retains that duty rather than deleting under a known
live creator.
The hook fixture uses the prior reviewed alternate-index/object-store method.
HEAD tree metadata seeds a temporary index; only one newly generated fixture
blob may differ. Existing blob contents and the real index are not opened. The
real index is checked by stat identity only. Git's fsmonitor, split-index,
sparse-checkout and untracked-cache options are disabled only in the fixture
process environment. No Git refs, worktree source, hooks, source code, scanner
bytes/mode or persistent configuration changes. The only persistent writes are
requested fixed-metadata receipts in this packet. Readbacks and raw hook output
are not retained if they contain unexpected fields or diagnostics.
The original configured-hook clean/key receipt remains unchanged. The owner file still records T05 progress until the coordinator applies and
publishes the prepared completion patch; the bounded runtime receipts now verify
the fixture. No whole TSA15 closure follows.
The independently reviewed but superseded lifecycle revision is retained as
`lifecycle-rev1-superseded.py` (never executed). `lifecycle-gate.patch` records
the pre-effect registration correction. Seven unit checks include refusal of
source storage when coordinator gate release never arrives.
R1 coordinator execution failed after early registration with
`namespace-lifecycle-preflight-failed`; it did not run actual hook cases. Both
reported storage directories were removed. Its raw driver, manifest and receipt
are retained in `failed-r1/`. R1 discarded Bubblewrap/spawner stderr and that lost
diagnostic history cannot be reconstructed.
R2 was prepared with the following diagnostic changes; its later failed
execution is retained below. `lifecycle-r2.patch` atomically publishes the release gate
(previously it could be observed empty before buffered token write/close). This
is a possible cause, not a verified explanation. R2 adds fixed public phase
readback and class/errno/whitelisted source refusal codes. It captures up to
8192 bytes each of actual Bubblewrap/spawner diagnostics, with 1 MiB child file
limits. This lifecycle probe processes only a public generated sentinel; it has
no key, user index or user source blob input. Arbitrary exception messages are
excluded from phase metadata. Eight unit checks pass, including that exclusion.
The retained R2 receipt records the later diagnostic execution.
R2 coordinator execution again refused: the fixed phase reported
`PermissionError`, errno 13; both captured stderr streams were empty and fixture
cleanup was verified. That record is retained in `failed-r2/`. Because the error
phase overwrote its previous stage, the `/dev/null` explanation remained an
unverified hypothesis.
R3 was subsequently reviewed and executed successfully, as recorded in the
current receipts. `namespace-r3.patch` adds the narrow
`--dev-bind /dev/null /dev/null` exception; no other host device is exposed and
root remains read only. Both lifecycle and hook bootstrap verify that it is the
same host character device (device/inode/rdev) and actually open it O_RDWR with
O_NOFOLLOW. Error phases now retain the last successful phase and include an
exception filename only if it is literally `/dev/null`. Ten unit checks pass,
including rejection of a wrong null identity before opening it. The final runtime
record verifies this profile; the earlier cause is not retroactively asserted.
Current delivery: `namespace-lifecycle-results.json` verifies exact disposable
parent loss, Bubblewrap/inner/cleanup-observer death and removed inner/outer
storage. `namespace-hook-results.json` verifies clean (exit 0), generated-key
blocked (exit 1), and exact non-executable scanner-shadow refusal (exit 2,
`scanner-file-refused`, zero scanned blobs) for both actual hooks. Host scanner
stat/hash/mode, hook/source routing, real index stat identities and HEADs stayed
unchanged; all new volatile storage was absent. All six namespace readbacks
verified root/shm and UID/GID identity, canonical source/hook/interpreter hashes
and the null character-device identity/open.
`owner-T05-completion.patch` and `RMGR-WP-0021.completed-proposal.md` are exact
reviewable results against owner commit `b02e1cefb0e07fe246dc9fe9c5a989fe06116587`.
Only T05 changes progress→done; T03 progress, T04 todo and active workplan status
are preserved. R1/R2 failure history and the bounded namespace-only interpretation
are explicit. Source publication and the accepted explicit repo-local CLI route
remain earlier delivery evidence; no global CLI installation or remote receive,
CI, response or whole-TSA15 acceptance is claimed.

View file

@ -0,0 +1,243 @@
---
id: RMGR-WP-0021
type: workplan
title: "Secret-detection adapter and repository enforcement acceptance"
domain: infotech
repo: repo-manager
status: active
owner: codex
topic_slug: repo-manager
created: "2026-10-12"
updated: "2026-10-17"
flavor: implementation
depends_on: []
state_hub_workstream_id: "5aa6f84a-c682-5996-ae26-96daef670833"
---
Native repository-control work for CUST-WP-0080 G07 / DSM-DETECT. Existing
RMGR-WP-0009 provenance remains separate and nonblocking by its contract.
Detection is an additional security check; this plan does not redefine provenance,
credential custody, PDP authority, Forge ownership or incident authorization.
## Provide a bounded content-silent staged-object scanner adapter
```task
id: RMGR-WP-0021-T01
status: done
priority: high
state_hub_task_id: "d3d20c18-5a5f-5f8a-b5c4-a22b4b662ebe"
```
2026-10-12: all 21 reviewed estate checkouts resolve their pre-commit hook to the
same generated-only guard. A disposable valid private key was committed through
that inherited hook, proving no local prevention for that fixture. No real
credential was used. The new `rmgr secret-scan` adapter pins Gitleaks 8.30.1 Linux
x64, reads complete changed index blobs, isolates configuration, suppresses raw
output, verifies index stability and refuses unknown binaries, oversized inputs,
changed gitlinks and other unverified cases. Real scanner tests prove refusal of
a disposable private-key commit, partial/alternate-index correctness, local
configuration/inline suppression refusal and Git replacement-object resistance.
Evidence: Custodian `docs/evidence/2026-10-12-netkingdom-security/secret-detection.json`.
This is source/tool behavior, not workstation or forge activation.
## Admit the tool and activate local prevention for the reviewed repositories
```task
id: RMGR-WP-0021-T02
status: done
priority: high
state_hub_task_id: "e27817e6-b298-581f-b99a-05ec459be749"
```
Review durable executable installation/version custody and exact repository
coverage. Preserve existing shared generated-only and provenance hooks and the
Custodian's separate local hook. Do not replace unknown hooks, alter global
routing or silently affect unreviewed repositories. Test actual configured hooks
with clean/disposable-secret/scanner-failure cases without changing production
source or committing a credential. Record observed coverage and explicit
uncovered checkouts. Installer rollback restores exact prior content/routing.
2026-10-12: activated the reviewed composition in the existing shared hook and
Custodian local hook, with Gitleaks 8.30.1 admitted at
`/home/worsch/.local/lib/repo-manager/gitleaks/8.30.1/gitleaks` under the pinned
SHA256. No Git routing or other hook changed. All 22 exact workstation roots in
the proposal passed actual configured-hook checks: clean exit 0, disposable
private key exit 1, generated-only exit 1, non-executable scanner exit 2. Scanner
mode was restored; a checkout outside the exact scope retained its prior behavior.
Probes used temporary alternate indexes/object stores, without changing user
source, staged content or branches. Eleven activation/rollback/guard tests pass.
Custodian evidence: `secret-hook-activation.json`; reviewed proposal and rollback
executor: `docs/changes/CUST-WP-0080/`. This covers these workstation checkouts,
not other machines/clones, existing history, remote enforcement or real findings.
T03/T04 remain open; local hooks remain bypassable.
## Establish independent forge and CI detection coverage
```task
id: RMGR-WP-0021-T03
status: progress
priority: high
state_hub_task_id: "0ab44bd9-00d8-5470-ad45-7350e7868d0a"
```
Under CUST-WP-0080 coordination with railiance-forge, inspect existing server-side
and required-check controls; define the production repository denominator and
owner-native enforcement record before activating changes. Cover introduced
history/merge cases and bypasses, missing scanner, malformed input and scanner
failure. Record actual rejected/accepted push or required-check receipts. Local
hook success is insufficient and this staged adapter alone does not scan history.
2026-10-12 read-only native baseline: railiance01 runs Forgejo 11.0.3.
All 22 reviewed repositories have only the upstream-generated receive-hook files,
matched by SHA256 to the v11.0.3 templates; no custom scanner hook is installed at
that boundary. Storage contains 165 repository directories, which still need
classification before being an admitted production denominator. Independent
Actions/branch-protection coverage and push acceptance remain unverified. Do not
replace generated dispatchers or enable arbitrary user hook editing to add the
control. Receipt: Custodian `forge-secret-detection-baseline.json`. No live
server mutation, credential access or synthetic push was performed.
2026-10-12 implementation handoff: FORGE-WP-0006 owns the independent receive
boundary. Its introduced-history adapter passes 33 leaf cases with actual
disposable pushes, including added-then-deleted/merge/message/tag secrets and
scanner failures. Source is not installed server enforcement. Native inventory,
exact-artifact custody, SSH/HTTP/frontend/restart/new-repository acceptance and
CI authority remain open in FORGE-WP-0006-T02/T03. Custodian receipt:
`docs/evidence/2026-10-12-netkingdom-security/receive-secret-detection.json`.
2026-10-13 receive lifecycle acceptance now exists in FORGE-WP-0006: 22 server
profiles, template inheritance and repaired scanner custody across two actual
Kubernetes replacements. The original failed rollout is preserved in Custodian's
`forge-custody-recovery-summary.json`; 144 of 166 repositories and the remaining
HTTP/SSO/frontend/CI/response acceptance stay open. The server scanner's 90-second
budget exceeded State Hub's 30-second and Repo Manager's 60-second push deadlines.
Both clients now allow 120 seconds; a timeout reports unverified remote outcome
and requires ref inspection before retry. No force push or scanner exception is
introduced. State Hub owner record: STATE-WP-ADHOC-2026-10-13-T01. Dedicated timeout
regressions and real delayed-hook acceptance are recorded in Custodian's
`push-deadline.json`. This transport correction does not close T03.
2026-10-13 expansion completed: FORGE6-EXPAND-001 revision 1 exited 0 after
all 143 targets passed actual SSH clean/scanner-refusal probes under an exact-ref
veto. The independent final read-only audit reconciles 167 repositories: 166
admitted profiles, one builtin-only (numeric ID 55), zero unknown profiles. All
23 baseline profiles remain exact; no probe refs, temporary vetoes or ownership
markers remain. Each rejected synthetic commit was absent after its probe.
Repository 55 has four external submodules and remains required compatibility
work. Ordinary source acceptance is distinct from vetoed scanner checks.
Production HTTP/API/frontend acceptance remains unverified: the protected API
credential route failed before child handoff and the metadata-only capability
check denied access. Prepare one complete acceptance command for the existing
attended login window. CI, import/mirror, historical/LFS/log/artifact detection
and private response gates remain open; this is no whole-estate closure.
Evidence: Custodian `docs/evidence/2026-10-13-netkingdom-security/forge-expansion-final.json`
and `forge-api-route-readiness.json`.
## Verify private finding-to-response handling
```task
id: RMGR-WP-0021-T04
status: todo
priority: high
state_hub_task_id: "44272818-db49-58a2-83b1-d2f9e9d5976c"
```
Exercise a synthetic finding through metadata-only owner routing and approved
private review. Define exact false-positive exception governance; require actual
approval, scope, expiry/review and regression coverage. For genuine exposed
credentials, retain incident owner and revoke/replace/adopt/validate gates. Do not
execute founder-deferred rotations or treat suppressed output as remediation.
Close only after native coverage and response evidence are adequate for the
applicable DSM-DETECT requirements; retain residuals as live work records.
## Publish measured staged-scanner batching and verify runtime routing
```task
id: RMGR-WP-0021-T05
status: done
priority: medium
state_hub_task_id: "25fbe694-41d8-5232-bce0-4ed362387d5a"
```
2026-10-17 prepared refinement for the local staged-object adapter. Independent
review and a coordinator-executed generated-fixture run cover the exact source
SHA256 `e709c658f779534fcab093207b0a78e49d54fc584c515fdf7ac535ce75f6c400`:
42 tests, 13 exact old/new summary parity cases, immutable scanner snapshot,
volatile-only bounded batches, watchdog and parent-loss refusal/cleanup. Warm
p50 for 1/16/64 distinct 1 KiB blobs is 0.835/0.884/0.904 seconds, compared with
0.702/12.065/49.172 seconds in the retained baseline. The one-blob case regressed;
this is descriptive local fixture evidence, not aggregate workload or tail
acceptance. Larger blobs retain the original stdin route.
Publish the reviewed patch against the exact owner base, verify the configured
shared and Custodian hooks still resolve to the admitted owner source, then run
clean/private-key/scanner-unavailable generated alternate-index probes without
reading or changing user source/indexes. Verify actual CLI import routing; the
repo-local `.venv/bin/rmgr` imports owner source, but the previously advertised
`/home/worsch/.local/bin/rmgr` is absent in the read-only observation and must not
be described as installed operational coverage. Reconcile that exact CLI route
before claiming CLI publication. Preserve existing hook guards and routing;
retain rollback to the exact prior adapter bytes. Source publication and runtime
acceptance must have separate receipts.
Review packet: Custodian
`docs/changes/netkingdom-target-2026-10-16/scanner-batch-r1/`.
No canonical owner mutation or runtime admission has occurred in the packet.
This task does not close T03/T04, independent receive/CI coverage, source-control
bypass limits or whole TSA15.
2026-10-17 integration started: exact reviewed source is applied in the owner
checkout. Canonical tests, configured-hook fixtures and publication are being
verified separately; actual-hook scanner-unavailability remains pending.
2026-10-17 verified source follow-through: source commit `83c521b` passed normal
local scanning and all 42 canonical scanner tests. The exact final tmpfs candidate
also passed 13 old/new parity cases. The actual configured shared and Custodian
hooks each accepted a clean generated fixture and blocked a generated private key,
using alternate indexes/object stores in private tmpfs; the real indexes were not
opened and their stat identities and HEADs stayed unchanged. All new fixture and
scan storage was removed. Scanner/hook/source bytes and routing stayed exact.
No chmod or unavailable-scanner injection touched the real scanner. Source tests
cover unavailable/wrong-digest refusal, but actual configured-hook unavailability
is still pending, so T05 stays progress. The explicit repo-local CLI published
through rmgr sync --push and central primary/railiance01 accepted source projection;
no global installed CLI is claimed. T03/T04 and whole target gates remain open.
Final coordinator evidence: resume-integration-r1/publication-verification.json.
2026-10-17 bounded T05 completion evidence: the independently reviewed R3 namespace
fixture passed ten profile checks, exact-pidfd hard-parent-loss and cleanup
acceptance, and six actual configured-hook cases. Both the shared repo-manager
hook and Custodian hook accepted a clean generated blob (exit 0), blocked a
freshly generated private-key fixture (exit 1), and refused a non-executable
scanner view (exit 2, `unverified`, `scanner-file-refused`, zero scanned blobs).
The unavailable view was a new empty 0400 file read-only-bound over the exact
configured scanner path inside fresh user/mount/network namespaces; the host
scanner's bytes, stat identity and mode were unchanged. The canonical source,
hooks and interpreter hashes were read back before exec, original root and
`/dev/shm` device/inode identities and UID/GID were preserved, root was read only,
and only original `/dev/shm` and exact `/dev/null` had the reviewed writable/device
bind exceptions. The null character device and actual O_RDWR open were verified.
PID namespace identity stayed shared so the canonical independent cleanup
observer survived parent loss. Real indexes were not opened, real index stat
identities and HEADs stayed unchanged, and all new volatile storage was absent.
Retain the failed preparation history: R1 refused after early process
registration without a full readback; R2 recorded PermissionError errno 13,
without enough retained phase information to establish its exact cause. Both
failed revisions and receipts are in `failed-r1/` and `failed-r2/`. R3 atomically
published the release gate, retained fixed public phase diagnostics and verified
the narrow `/dev/null` device bind and open. Its successful result does not
retroactively assign a verified cause or success to R1/R2.
Receipts: Custodian
`docs/changes/netkingdom-target-2026-10-17/scanner-unavailable-r1/namespace-lifecycle-results.json`
and `namespace-hook-results.json`, with exact driver hashes and manifest.
Earlier publication and explicit repo-local CLI acceptance remain recorded above;
no globally installed CLI is claimed. This completes the bounded local staged
scanner optimization and its configured-hook generated-fixture acceptance. It
proves the exact non-executable scanner view within this namespace fixture, not
an observed host outage or coverage of other machines. T03 remains progress,
T04 remains todo, the workplan remains active, and remote receive/CI, broader
source-control coverage, real finding response and whole TSA15 remain open.

View file

@ -0,0 +1 @@
{"status": "unverified", "fixture_removed": true, "inner_storage_removed": true}

View file

@ -0,0 +1,63 @@
{
"state": "prepared; independent root review and coordinator execution pending",
"owner_head": "b02e1cefb0e07fe246dc9fe9c5a989fe06116587",
"source_sha256": "e709c658f779534fcab093207b0a78e49d54fc584c515fdf7ac535ce75f6c400",
"scanner_sha256": "88f91962aa2f93ac6ab281d553b9e125f5197bbbce38f9f2437f7299c32e5509",
"hook_sha256": "d50cf763dc9814383c6886e30b6650bbbdcb49ddd78889082e3fda3626a2cbfd",
"bwrap_sha256": "e318903862396f96de3df57264e0158682b952fd3fb53ac23d876413e7b30f71",
"files": {
"probe_namespace_hooks.py": "0e680c9ae85242bb510cbe871e14c498e01643eccc3656533e6fb2902030c2d8",
"probe_namespace_lifecycle.py": "c46efb37e02349ba73f83b46c8fd8b1abc286282be8dc0a105ae76911e1ca266",
"test_namespace_profile.py": "5571d9f04065fb102236f058bf7ae2e2d62c1ea0b28f13c3585c0e38cdbc6d09",
"run_reviewed_fixture.sh": "07d0b518a4e99c6d88c0cbc2a03c76b20429f0ac7d86d3985ca46528cbffe596"
},
"expected_hook_cases": 6,
"unit_profile_checks_passed": 7,
"namespace_policy": {
"changed": [
"user",
"mount",
"network"
],
"preserved": [
"pid",
"root dev/inode",
"dev/shm dev/inode",
"uid/gid"
],
"writable_bind_only": "/dev/shm to existing /dev/shm",
"scanner_shadow": "new generated empty0400file readonlybound over exact admitted scanner path only for unavailable cases"
},
"expected_unavailable_result": {
"status": "unverified",
"exit_code": 2,
"reason": "scanner-file-refused",
"scanned_blobs": 0
},
"forbidden_actions": [
"host scanner chmod/bytes changes",
"hook/source/config changes",
"real index open/write",
"real source blob scan",
"network/provider calls",
"new install",
"production configuration",
"external messages"
],
"cleanup": "reviewed canonical tmpfs+pidfd watchdog; bwrapdie-with-parent; source childrenPDEATHSIG; actual namespace hard-loss fixture first, exact disposable spawner only, independent cleanupobserver survives",
"bounds": {
"git_seconds": 20,
"hook_case_seconds": 30,
"child_cpu_seconds": 20,
"child_virtual_address_GiB": 8,
"generated_git_file_limit_MiB": 16,
"bwrap_hook_file_limit_MiB": 64,
"outer_watchdog_seconds": 180,
"watchdog_TERM_grace_seconds": 5,
"uncertain_kernel_quiescence": "retain observer duty until exact pidfddeath; never delete under known live creator"
},
"canonical_mutations_performed": false,
"runtime_fixture_executed": false,
"registration_gate": "atomic inner PID+namespace early-ready; main opens exact bwrap+inner pidfds and verifies live before writing exact generated gate; inner refuses storage after8seconds without release",
"superseded_lifecycle_sha256": "7b74d96c867d44a0e994890d58d0d039028684ded3611ffb65f9c7b09d6f5527"
}

View file

@ -0,0 +1,12 @@
{
"status": "unverified",
"scope": "generated namespace hard-parent-loss process tree only",
"real_index_opened": false,
"real_credentials_read": false,
"provider_calls": 0,
"host_scanner_modified": false,
"reason": "namespace-lifecycle-preflight-failed",
"fixture_removed": true,
"inner_storage_removed": true,
"driver_sha256": "c46efb37e02349ba73f83b46c8fd8b1abc286282be8dc0a105ae76911e1ca266"
}

View file

@ -0,0 +1,194 @@
#!/usr/bin/env python3
"""Hard-loss fixture targets only a newly spawned generated-data process tree."""
import argparse
import functools
import importlib.util
import json
import os
from pathlib import Path
import select
import signal
import subprocess
import sys
import time
HERE = Path(__file__).resolve().parent
spec = importlib.util.spec_from_file_location('namespace_profile', HERE/'probe_namespace_hooks.py')
p = importlib.util.module_from_spec(spec)
spec.loader.exec_module(p)
def adapter():
return p.load_bound(p.SOURCE, p.SOURCE_SHA, 'reviewed_lifecycle_storage')
def inner(path):
data = json.loads(path.read_text())
current = p.namespaces()
if (p.identity(Path('/')) != data['root'] or p.identity(Path('/dev/shm')) != data['shm']
or current['pid'] != data['ns']['pid'] or current['mnt'] == data['ns']['mnt']
or current['user'] == data['ns']['user'] or current['net'] == data['ns']['net']
or p.sha(Path('/usr/bin/python3')) != data['interpreter_sha256']):
return 23
# Register the exact inner process before any source-bearing storage can
# exist. Publication is atomic; the only earlier effect is PID metadata.
early = Path(data['early_ready'])
temporary = early.with_suffix('.tmp')
temporary.write_text(json.dumps({'inner_pid':os.getpid(), 'namespace_identity_verified':True}))
temporary.replace(early)
until = time.monotonic() + 8
gate = Path(data['release_gate'])
while not gate.exists() and time.monotonic() < until:
time.sleep(.01)
if not gate.exists() or gate.read_text() != data['gate_token']:
return 25
a = adapter()
with a.private_storage() as (area, watcher):
(area/'public-generated-sentinel').write_bytes(b'public generated parent-loss sentinel')
readback = {'storage':str(area), 'storage_identity':p.identity(area),
'inner_pid':os.getpid(), 'watcher_pid':watcher.pid,
'namespace_identity_verified':True}
temporary = Path(data['readback'] + '.tmp')
temporary.write_text(json.dumps(readback))
temporary.replace(Path(data['readback']))
time.sleep(30)
return 24 # The observer must kill the disposable spawner before normal expiry.
def spawn(path):
a = adapter()
data = json.loads(path.read_text())
env = {'PATH':'/usr/bin:/bin','HOME':'/home/worsch','LANG':'C'}
args = p.command(Path('/home/worsch/repo-manager'), env, path)
args = args[:args.index('--')+1] + ['/usr/bin/python3','-I',str(Path(__file__).resolve()),'--inner',str(path)]
child = subprocess.Popen(args, env=env, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL,
preexec_fn=functools.partial(a.child_limits,64*1024**2,os.getpid()))
try:
temporary = Path(data['bwrap_pid'] + '.tmp')
temporary.write_text(str(child.pid))
temporary.replace(Path(data['bwrap_pid']))
return child.wait(timeout=30)
finally:
if child.poll() is None:
child.kill(); child.wait(timeout=5)
def main():
receipt={'status':'unverified','scope':'generated namespace hard-parent-loss process tree only',
'real_index_opened':False,'real_credentials_read':False,'provider_calls':0,
'host_scanner_modified':False}
descriptors={}; child=None; fixture=None; inner_area=None
try:
if p.sha(p.BWRAP) != p.BWRAP_SHA:
raise p.Refused('bwrap-drift')
a=adapter()
previous=set(Path('/dev/shm').glob('rmgr-secret-scan-*'))
with a.private_storage() as (fixture, outer_watcher):
data={'root':p.identity(Path('/')),'shm':p.identity(Path('/dev/shm')),
'ns':p.namespaces(),'readback':str(fixture/'inner.readback'),
'bwrap_pid':str(fixture/'bwrap.pid'),
'early_ready':str(fixture/'inner.early.ready'),
'release_gate':str(fixture/'release.gate'), 'gate_token':os.urandom(16).hex(),
'interpreter_sha256':p.sha(Path('/usr/bin/python3'))}
path=fixture/'spec.json'; path.write_text(json.dumps(data))
child=subprocess.Popen([sys.executable,'-I',str(Path(__file__).resolve()),'--spawn',str(path)],
env={'PATH':'/usr/bin:/bin','HOME':'/home/worsch','LANG':'C'},
stdout=subprocess.DEVNULL,stderr=subprocess.DEVNULL,
preexec_fn=functools.partial(a.child_limits,64*1024**2,os.getpid()))
try:
descriptors['spawner']=os.pidfd_open(child.pid)
# Wait for atomic pre-effect readiness, register both exact
# process identities, then release only this generated gate.
until=time.monotonic()+8
early=Path(data['early_ready']); bwrap_pid=Path(data['bwrap_pid'])
while (not early.exists() or not bwrap_pid.exists()) and child.poll() is None and time.monotonic()<until:
time.sleep(.01)
if not early.exists() or not bwrap_pid.exists():
raise p.Refused('namespace-early-registration-failed')
ready=json.loads(early.read_text())
if set(ready) != {'inner_pid','namespace_identity_verified'} or not ready['namespace_identity_verified']:
raise p.Refused('namespace-early-readiness-refused')
descriptors['bwrap']=os.pidfd_open(int(bwrap_pid.read_text()))
descriptors['inner']=os.pidfd_open(ready['inner_pid'])
for descriptor in (descriptors['bwrap'],descriptors['inner']):
dead,_,_=select.select([descriptor],[],[],0)
if dead:
raise p.Refused('namespace-creator-died-before-release')
with Path(data['release_gate']).open('x') as gate:
gate.write(data['gate_token'])
until=time.monotonic()+8
readback=Path(data['readback'])
while not readback.exists() and child.poll() is None and time.monotonic()<until:
time.sleep(.02)
if not readback.exists():
raise p.Refused('namespace-lifecycle-preflight-failed')
body=json.loads(readback.read_text()); inner_area=Path(body['storage'])
if (not body['namespace_identity_verified'] or p.identity(inner_area)!=body['storage_identity']
or not str(inner_area).startswith('/dev/shm/rmgr-secret-scan-')):
raise p.Refused('lifecycle-readback-refused')
if body['inner_pid'] != ready['inner_pid']:
raise p.Refused('namespace-inner-identity-changed')
descriptors['cleanup_observer']=os.pidfd_open(body['watcher_pid'])
# Exactly this new disposable spawner is killed. The calling tool,
# shell, test harness, observer and their process groups are untouched.
signal.pidfd_send_signal(descriptors['spawner'],signal.SIGKILL)
child.wait(timeout=5)
until=time.monotonic()+8
pending=set(descriptors.values())
while pending and time.monotonic()<until:
ready,_,_=select.select(list(pending),[],[],max(0,until-time.monotonic()))
pending.difference_update(ready)
if pending or inner_area.exists():
raise p.Refused('namespace-hard-loss-cleanup-unverified')
receipt.update(namespace_identity_verified=True, pre_effect_pidfd_registration_verified=True,
exact_disposable_parent_killed=True,
bwrap_inner_and_cleanup_observer_death_verified=True,inner_storage_removed=True)
finally:
# Quiesce named source/readback creators before the outer storage
# context can remove their directory. Never kill the independent
# cleanup observer; it owns the inner storage recovery duty.
for name in ('spawner', 'bwrap', 'inner'):
descriptor = descriptors.get(name)
if descriptor is None:
continue
dead, _, _ = select.select([descriptor], [], [], 0)
if not dead:
try:
signal.pidfd_send_signal(descriptor, signal.SIGKILL)
except ProcessLookupError:
pass
# Retain the quiescence duty until exact death is proven.
select.select([descriptor], [], [])
if child.poll() is None:
child.kill()
child.wait(timeout=5)
observer = descriptors.get('cleanup_observer')
if observer is not None:
select.select([observer], [], [], 8)
if fixture.exists() or set(Path('/dev/shm').glob('rmgr-secret-scan-*'))-previous:
raise p.Refused('outer-storage-cleanup-unverified')
receipt.update(status='verified',fixture_removed=True,new_scan_storage_absent=True)
except Exception as error:
receipt['reason']=error.args[0] if isinstance(error,p.Refused) else 'lifecycle-probe-unavailable'
finally:
if child is not None and child.poll() is None:
try:
signal.pidfd_send_signal(descriptors['spawner'],signal.SIGKILL)
child.wait(timeout=5)
except (OSError,subprocess.SubprocessError):
pass
for fd in descriptors.values():
os.close(fd)
receipt['fixture_removed']=fixture is None or not fixture.exists()
receipt['inner_storage_removed']=inner_area is None or not inner_area.exists()
receipt['driver_sha256']=p.sha(Path(__file__))
(HERE/'namespace-lifecycle-results.json').write_text(json.dumps(receipt,indent=2)+'\n')
print(json.dumps({'status':receipt['status'],'fixture_removed':receipt['fixture_removed'],
'inner_storage_removed':receipt['inner_storage_removed']}))
return 0 if receipt['status']=='verified' else 2
if __name__=='__main__':
parser=argparse.ArgumentParser();parser.add_argument('--spawn',type=Path);parser.add_argument('--inner',type=Path)
args=parser.parse_args()
raise SystemExit(spawn(args.spawn) if args.spawn else inner(args.inner) if args.inner else main())

View file

@ -0,0 +1,2 @@
....... [100%]
7 passed in 0.04s

View file

@ -0,0 +1 @@
{"status": "unverified", "fixture_removed": true, "inner_storage_removed": true}

View file

@ -0,0 +1,77 @@
{
"state": "R2 prepared for root review; R1 runtime failed and retained, no acceptance",
"owner_head": "b02e1cefb0e07fe246dc9fe9c5a989fe06116587",
"source_sha256": "e709c658f779534fcab093207b0a78e49d54fc584c515fdf7ac535ce75f6c400",
"scanner_sha256": "88f91962aa2f93ac6ab281d553b9e125f5197bbbce38f9f2437f7299c32e5509",
"hook_sha256": "d50cf763dc9814383c6886e30b6650bbbdcb49ddd78889082e3fda3626a2cbfd",
"bwrap_sha256": "e318903862396f96de3df57264e0158682b952fd3fb53ac23d876413e7b30f71",
"files": {
"probe_namespace_hooks.py": "0e680c9ae85242bb510cbe871e14c498e01643eccc3656533e6fb2902030c2d8",
"probe_namespace_lifecycle.py": "9021bd7a6a52ebe4ecd52587094b793a967f2578e24c6a30ed7b81c4a9154f52",
"test_namespace_profile.py": "04e508a072941c5fa1abe9c1ffbfe4452c1fcabfe4e39c6c0b768d76da6ce689",
"run_reviewed_fixture.sh": "07d0b518a4e99c6d88c0cbc2a03c76b20429f0ac7d86d3985ca46528cbffe596"
},
"expected_hook_cases": 6,
"unit_profile_checks_passed": 8,
"namespace_policy": {
"changed": [
"user",
"mount",
"network"
],
"preserved": [
"pid",
"root dev/inode",
"dev/shm dev/inode",
"uid/gid"
],
"writable_bind_only": "/dev/shm to existing /dev/shm",
"scanner_shadow": "new generated empty0400file readonlybound over exact admitted scanner path only for unavailable cases"
},
"expected_unavailable_result": {
"status": "unverified",
"exit_code": 2,
"reason": "scanner-file-refused",
"scanned_blobs": 0
},
"forbidden_actions": [
"host scanner chmod/bytes changes",
"hook/source/config changes",
"real index open/write",
"real source blob scan",
"network/provider calls",
"new install",
"production configuration",
"external messages"
],
"cleanup": "reviewed canonical tmpfs+pidfd watchdog; bwrapdie-with-parent; source childrenPDEATHSIG; actual namespace hard-loss fixture first, exact disposable spawner only, independent cleanupobserver survives",
"bounds": {
"git_seconds": 20,
"hook_case_seconds": 30,
"child_cpu_seconds": 20,
"child_virtual_address_GiB": 8,
"generated_git_file_limit_MiB": 16,
"bwrap_hook_file_limit_MiB": 64,
"outer_watchdog_seconds": 180,
"watchdog_TERM_grace_seconds": 5,
"uncertain_kernel_quiescence": "retain observer duty until exact pidfddeath; never delete under known live creator"
},
"canonical_mutations_performed": false,
"runtime_fixture_executed": false,
"registration_gate": "atomic inner PID+namespace early-ready; main opens exact bwrap+inner pidfds and verifies live before writing exact generated gate; inner refuses storage after8seconds without release",
"superseded_lifecycle_sha256": "7b74d96c867d44a0e994890d58d0d039028684ded3611ffb65f9c7b09d6f5527",
"failed_r1": {
"driver_sha256": "c46efb37e02349ba73f83b46c8fd8b1abc286282be8dc0a105ae76911e1ca266",
"result": "namespace-lifecycle-preflight-failed",
"fixture_removed": true,
"inner_storage_removed": true,
"raw_packet": "failed-r1/",
"stderr_history": "R1 discarded spawner/bwrap stderr; cannot recover retroactively"
},
"r2_delta": [
"atomic release-gate publication",
"fixed public phase readback with exceptionclass/errno/whitelisted source reason",
"lifecycle-only bwrap/spawner stderr capture capped8192bytes each; file growth capped1MiB per child",
"no canonical or actual-hook driver changes"
]
}

View file

@ -0,0 +1,22 @@
{
"status": "unverified",
"scope": "generated namespace hard-parent-loss process tree only",
"real_index_opened": false,
"real_credentials_read": false,
"provider_calls": 0,
"host_scanner_modified": false,
"last_inner_phase": {
"phase": "inner-exception",
"exception_type": "PermissionError",
"errno": 13
},
"disposable_spawner_returncode": 26,
"bwrap_stderr_public": "",
"bwrap_stderr_truncated": false,
"spawner_stderr_public": "",
"spawner_stderr_truncated": false,
"reason": "namespace-lifecycle-preflight-failed",
"fixture_removed": true,
"inner_storage_removed": true,
"driver_sha256": "9021bd7a6a52ebe4ecd52587094b793a967f2578e24c6a30ed7b81c4a9154f52"
}

View file

@ -0,0 +1,252 @@
#!/usr/bin/env python3
"""Generated alternate-index hook probes; no host scanner/hook/source mutation.
Only persistent writes are fixed-metadata receipts in this review packet.
User+mount namespaces shadow the exact scanner path; PID namespace stays shared
so the admitted canonical scanner's independent cleanup watchdog can survive.
"""
from __future__ import annotations
import argparse
import functools
import hashlib
import json
import os
from pathlib import Path
import shutil
import stat
import subprocess
import sys
import types
HERE = Path(__file__).resolve().parent
BASE = HERE.parent.parent / 'netkingdom-target-2026-10-16/scanner-batch-r1/probe_configured_hooks.py'
BASE_SHA = 'c91d2dc83f04ec17147c0e1410e42f4817b69e4cc5a02201682e5fa7b021b6f4'
BWRAP = Path('/usr/bin/bwrap')
BWRAP_SHA = 'e318903862396f96de3df57264e0158682b952fd3fb53ac23d876413e7b30f71'
OWNER_HEAD = b'b02e1cefb0e07fe246dc9fe9c5a989fe06116587'
SOURCE = Path('/home/worsch/repo-manager/src/repo_manager/secret_scan.py')
SOURCE_SHA = 'e709c658f779534fcab093207b0a78e49d54fc584c515fdf7ac535ce75f6c400'
BINARY = Path('/home/worsch/.local/lib/repo-manager/gitleaks/8.30.1/gitleaks')
BINARY_SHA = '88f91962aa2f93ac6ab281d553b9e125f5197bbbce38f9f2437f7299c32e5509'
HOOK_SHA = 'd50cf763dc9814383c6886e30b6650bbbdcb49ddd78889082e3fda3626a2cbfd'
class Refused(Exception):
pass
def sha(path):
return hashlib.sha256(path.read_bytes()).hexdigest()
def identity(path):
item = path.stat()
return [item.st_dev, item.st_ino]
def namespaces():
return {key: os.readlink('/proc/self/ns/' + key) for key in ('user', 'mnt', 'pid', 'net')}
def load_bound(path, digest, name):
content = path.read_bytes()
if hashlib.sha256(content).hexdigest() != digest:
raise Refused('bound-source-drift')
module = types.ModuleType(name)
module.__file__ = str(path)
exec(compile(content, str(path), 'exec'), module.__dict__)
return module
def command(root, env, spec_path, shadow=None):
argv = [str(BWRAP), '--unshare-user', '--unshare-net', '--die-with-parent', '--clearenv',
'--ro-bind', '/', '/', '--bind', '/dev/shm', '/dev/shm',
'--uid', str(os.getuid()), '--gid', str(os.getgid()), '--chdir', str(root)]
if shadow is not None:
argv += ['--ro-bind', str(shadow), str(BINARY)]
for key, value in sorted(env.items()):
argv += ['--setenv', key, value]
argv += ['--', '/usr/bin/python3', '-I', str(Path(__file__).resolve()), '--inside', str(spec_path)]
return argv
def check_spec(spec):
if set(spec) != {'root', 'hook', 'shadow', 'readback', 'host_root', 'host_shm',
'host_ns', 'uid', 'gid', 'interpreter_sha256', 'driver_sha256'}:
raise Refused('spec-schema-refused')
allowed = {
'/home/worsch/repo-manager': '/home/worsch/repo-manager/.githooks/pre-commit',
'/home/worsch/the-custodian': '/home/worsch/the-custodian/.git/hooks/pre-commit',
}
if allowed.get(spec['root']) != spec['hook'] or not isinstance(spec['shadow'], bool):
raise Refused('spec-target-refused')
destination = Path(spec['readback'])
if not str(destination).startswith('/dev/shm/rmgr-secret-scan-'):
raise Refused('readback-storage-refused')
def inside(spec_path):
# All targets originate in the fixed reviewed outer driver. Refuse changes
# before executing a hook; only fixed metadata is written to volatile storage.
try:
spec = json.loads(spec_path.read_text())
check_spec(spec)
observed_ns = namespaces()
if (identity(Path('/')) != spec['host_root']
or identity(Path('/dev/shm')) != spec['host_shm']
or os.getuid() != spec['uid'] or os.getgid() != spec['gid']
or observed_ns['user'] == spec['host_ns']['user']
or observed_ns['mnt'] == spec['host_ns']['mnt']
or observed_ns['net'] == spec['host_ns']['net']
or observed_ns['pid'] != spec['host_ns']['pid']
or not (os.statvfs('/').f_flag & os.ST_RDONLY)
or os.statvfs('/dev/shm').f_flag & os.ST_RDONLY):
raise Refused('namespace-identity-refused')
if (sha(SOURCE) != SOURCE_SHA or sha(Path(spec['hook'])) != HOOK_SHA
or sha(Path(__file__).resolve()) != spec['driver_sha256']
or shutil.which('python3') != '/usr/bin/python3'
or sha(Path('/usr/bin/python3')) != spec['interpreter_sha256']):
raise Refused('namespace-code-readback-refused')
scanner = BINARY.stat()
if spec['shadow']:
if (not stat.S_ISREG(scanner.st_mode) or scanner.st_size != 0
or stat.S_IMODE(scanner.st_mode) != 0o400
or sha(BINARY) != hashlib.sha256(b'').hexdigest()):
raise Refused('scanner-shadow-readback-refused')
elif sha(BINARY) != BINARY_SHA or stat.S_IMODE(scanner.st_mode) != 0o755:
raise Refused('baseline-scanner-readback-refused')
record = {'verified': True, 'root_identity_preserved': True,
'shm_identity_preserved': True, 'root_readonly': True, 'shm_writable': True,
'user_mount_network_namespaces_changed': True, 'pid_namespace_preserved': True,
'uid_gid_preserved': True, 'source_sha256': SOURCE_SHA,
'hook_sha256': HOOK_SHA, 'interpreter_sha256': spec['interpreter_sha256'],
'scanner_view': 'empty-0400-shadow' if spec['shadow'] else 'pinned-real-scanner'}
target = Path(spec['readback'])
with target.open('x') as output:
json.dump(record, output)
os.execve(spec['hook'], [spec['hook']], dict(os.environ))
except Exception:
return 23
def environment(base):
env = base.fixed_env()
env['GIT_CONFIG_GLOBAL'] = '/dev/null'
overrides = [('core.fsmonitor', 'false'), ('core.splitIndex', 'false'),
('core.sparseCheckout', 'false'), ('core.untrackedCache', 'false')]
env['GIT_CONFIG_COUNT'] = str(len(overrides))
for number, (key, value) in enumerate(overrides):
env[f'GIT_CONFIG_KEY_{number}'] = key
env[f'GIT_CONFIG_VALUE_{number}'] = value
return env
def main():
receipt = {'status': 'unverified', 'scope': 'two actual configured hooks; generated alternate-index/object fixtures in mount/user/network namespaces',
'provider_calls': 0, 'real_credentials_read': False, 'real_index_opened': False,
'source_sha256': SOURCE_SHA, 'scanner_sha256': BINARY_SHA, 'hook_sha256': HOOK_SHA,
'bwrap_sha256': BWRAP_SHA, 'host_scanner_modified': False, 'rows': []}
fixture = None
try:
if sha(BWRAP) != BWRAP_SHA or BWRAP.stat().st_mode & 0o6022:
raise Refused('namespace-binary-refused')
base = load_bound(BASE, BASE_SHA, 'reviewed_hook_probe')
records = base.precheck()
if records[0]['head'] != OWNER_HEAD:
raise Refused('owner-head-drift')
before_binary = base.info(BINARY)
adapter = load_bound(SOURCE, SOURCE_SHA, 'canonical_scanner_storage')
prior_storage = set(Path('/dev/shm').glob('rmgr-secret-scan-*'))
host_ns = namespaces()
host_root = identity(Path('/')); host_shm = identity(Path('/dev/shm'))
interpreter_sha = sha(Path('/usr/bin/python3'))
with adapter.private_storage() as (fixture, watcher):
env = environment(base)
key_path = fixture / 'generated-key'
base.run(['/usr/bin/ssh-keygen', '-q', '-t', 'ed25519', '-N', '', '-C',
'public-generated-namespace-probe', '-f', str(key_path)], fixture, env,
adapter=adapter)
key = key_path.read_bytes()
shadow = fixture / 'unavailable-scanner'
with shadow.open('x'):
pass
shadow.chmod(0o400) # Only this newly created empty disposable file.
for number, record in enumerate(records):
root = record['root']; hook = record['hook']
local = fixture / str(number); local.mkdir(mode=0o700)
objects = local / 'objects'; objects.mkdir(mode=0o700)
probe_env = dict(env, GIT_INDEX_FILE=str(local/'index'),
GIT_OBJECT_DIRECTORY=str(objects), GIT_ALTERNATE_OBJECT_DIRECTORIES=record['objects'])
name = '__rmgr_namespace_generated_fixture__.txt'
if base.git(root, probe_env, 'ls-tree', '--name-only', 'HEAD', '--', name, adapter=adapter):
raise Refused('fixture-name-collision')
for case, payload, status, code, unavailable in [
('clean-control', b'public namespace hook fixture\n', 'clean', 0, False),
('generated-key-control', key, 'blocked', 1, False),
('scanner-unavailable', b'public namespace unavailable fixture\n', 'unverified', 2, True),
]:
if watcher.poll() is not None:
raise Refused('outer-watchdog-lost')
base.git(root, probe_env, 'read-tree', 'HEAD', adapter=adapter)
oid = base.git(root, probe_env, 'hash-object', '-w', '--stdin', data=payload,
adapter=adapter).decode().strip()
base.git(root, probe_env, 'update-index', '--add', '--cacheinfo',
'100644,'+oid+','+name, adapter=adapter)
changed = base.git(root, probe_env, 'diff', '--cached', '--name-only', '-z',
'--no-renames', '--no-ext-diff', '--no-textconv', adapter=adapter)
if changed != name.encode()+b'\0':
raise Refused('changed-fixture-scope-refused')
spec_path = local / (case+'.spec.json')
readback_path = local / (case+'.readback.json')
spec = {'root': str(root), 'hook': str(hook), 'shadow': unavailable,
'readback': str(readback_path), 'host_root': host_root, 'host_shm': host_shm,
'host_ns': host_ns, 'uid': os.getuid(), 'gid': os.getgid(),
'interpreter_sha256': interpreter_sha, 'driver_sha256': sha(Path(__file__))}
spec_path.write_text(json.dumps(spec))
result = subprocess.run(command(root, probe_env, spec_path,
shadow if unavailable else None), cwd=root, env=base.fixed_env(),
stdout=subprocess.PIPE, stderr=subprocess.PIPE, timeout=30, check=False,
preexec_fn=functools.partial(adapter.child_limits, 64*1024**2, os.getpid()))
if result.stderr or key.strip() in result.stdout or not readback_path.exists():
raise Refused('namespace-or-hook-output-refused')
readback = json.loads(readback_path.read_text())
body = json.loads(result.stdout)
if result.returncode != code or body.get('status') != status:
raise Refused('hook-result-refused')
if unavailable:
if body != {'status': 'unverified', 'scope': 'changed-staged-blobs',
'reason': 'scanner-file-refused', 'scanned_blobs': 0}:
raise Refused('unavailable-summary-refused')
elif body != {'status': status, 'scope': 'changed-staged-blobs',
'scanner_version': '8.30.1', 'scanner_sha256': BINARY_SHA,
'scanned_blobs': 1, 'blocked_blob_ids': [oid] if status=='blocked' else []}:
raise Refused('control-summary-refused')
receipt['rows'].append({'repo': root.name, 'case': case, 'status': status,
'exit_code': code, 'scanned_blobs': body['scanned_blobs'],
'reason': body.get('reason'), 'namespace_readback': readback})
if fixture.exists() or set(Path('/dev/shm').glob('rmgr-secret-scan-*')) - prior_storage:
raise Refused('volatile-cleanup-unverified')
after_records = base.precheck()
if (before_binary != base.info(BINARY)
or any(a['index_stat'] != b['index_stat'] or a['head'] != b['head']
for a, b in zip(records, after_records))):
raise Refused('host-state-changed')
receipt.update(status='verified', fixture_removed=True, new_scan_storage_absent=True,
real_index_stat_unchanged=True, real_heads_unchanged=True,
host_scanner_stat_hash_mode_unchanged=True, hook_source_routing_unchanged=True)
except Exception as error:
receipt['reason'] = error.args[0] if isinstance(error, Refused) else 'namespace-probe-unavailable'
receipt['fixture_removed'] = fixture is None or not fixture.exists()
receipt['driver_sha256'] = sha(Path(__file__))
(HERE/'namespace-hook-results.json').write_text(json.dumps(receipt, indent=2)+'\n')
print(json.dumps({'status':receipt['status'],'cases':len(receipt['rows']),
'fixture_removed':receipt['fixture_removed']}))
return 0 if receipt['status']=='verified' else 2
if __name__ == '__main__':
parser=argparse.ArgumentParser()
parser.add_argument('--inside', type=Path)
args=parser.parse_args()
raise SystemExit(inside(args.inside) if args.inside else main())

View file

@ -0,0 +1,246 @@
#!/usr/bin/env python3
"""Hard-loss fixture targets only a newly spawned generated-data process tree."""
import argparse
import functools
import importlib.util
import json
import os
from pathlib import Path
import select
import signal
import subprocess
import sys
import time
HERE = Path(__file__).resolve().parent
spec = importlib.util.spec_from_file_location('namespace_profile', HERE/'probe_namespace_hooks.py')
p = importlib.util.module_from_spec(spec)
spec.loader.exec_module(p)
def adapter():
return p.load_bound(p.SOURCE, p.SOURCE_SHA, 'reviewed_lifecycle_storage')
def phase(data, name, error=None):
if 'phase_readback' not in data:
return
record = {'phase':name}
if error is not None:
record['exception_type'] = type(error).__name__
record['errno'] = getattr(error, 'errno', None)
allowed = {'volatile-storage-unavailable','cleanup-watchdog-unavailable',
'volatile-storage-identity-changed','cleanup-watchdog-failed'}
if error.args and isinstance(error.args[0],str) and error.args[0] in allowed:
record['fixed_source_reason'] = error.args[0]
target=Path(data['phase_readback']); temporary=target.with_suffix('.tmp')
temporary.write_text(json.dumps(record)); temporary.replace(target)
def inner(path):
data=json.loads(path.read_text())
try:
phase(data, 'inner-started')
return inner_body(data)
except Exception as error:
phase(data, 'inner-exception', error)
return 26
def inner_body(data):
current = p.namespaces()
if (p.identity(Path('/')) != data['root'] or p.identity(Path('/dev/shm')) != data['shm']
or current['pid'] != data['ns']['pid'] or current['mnt'] == data['ns']['mnt']
or current['user'] == data['ns']['user'] or current['net'] == data['ns']['net']
or p.sha(Path('/usr/bin/python3')) != data['interpreter_sha256']):
return 23
phase(data, 'namespace-verified')
# Register the exact inner process before any source-bearing storage can
# exist. Publication is atomic; the only earlier effect is PID metadata.
early = Path(data['early_ready'])
temporary = early.with_suffix('.tmp')
temporary.write_text(json.dumps({'inner_pid':os.getpid(), 'namespace_identity_verified':True}))
temporary.replace(early)
until = time.monotonic() + 8
gate = Path(data['release_gate'])
while not gate.exists() and time.monotonic() < until:
time.sleep(.01)
if not gate.exists() or gate.read_text() != data['gate_token']:
phase(data, 'gate-token-refused')
return 25
phase(data, 'gate-released')
a = adapter()
phase(data, 'adapter-loaded')
with a.private_storage() as (area, watcher):
phase(data, 'storage-entered')
(area/'public-generated-sentinel').write_bytes(b'public generated parent-loss sentinel')
phase(data, 'sentinel-written')
readback = {'storage':str(area), 'storage_identity':p.identity(area),
'inner_pid':os.getpid(), 'watcher_pid':watcher.pid,
'namespace_identity_verified':True}
temporary = Path(data['readback'] + '.tmp')
temporary.write_text(json.dumps(readback))
temporary.replace(Path(data['readback']))
phase(data, 'full-readback-published')
time.sleep(30)
return 24 # The observer must kill the disposable spawner before normal expiry.
def spawn(path):
a = adapter()
data = json.loads(path.read_text())
env = {'PATH':'/usr/bin:/bin','HOME':'/home/worsch','LANG':'C'}
args = p.command(Path('/home/worsch/repo-manager'), env, path)
args = args[:args.index('--')+1] + ['/usr/bin/python3','-I',str(Path(__file__).resolve()),'--inner',str(path)]
diagnostics = open(data['bwrap_stderr'], 'wb')
child = subprocess.Popen(args, env=env, stdout=subprocess.DEVNULL, stderr=diagnostics,
preexec_fn=functools.partial(a.child_limits,1024**2,os.getpid()))
try:
temporary = Path(data['bwrap_pid'] + '.tmp')
temporary.write_text(str(child.pid))
temporary.replace(Path(data['bwrap_pid']))
return child.wait(timeout=30)
finally:
if child.poll() is None:
child.kill(); child.wait(timeout=5)
diagnostics.close()
def main():
receipt={'status':'unverified','scope':'generated namespace hard-parent-loss process tree only',
'real_index_opened':False,'real_credentials_read':False,'provider_calls':0,
'host_scanner_modified':False}
descriptors={}; child=None; fixture=None; inner_area=None
try:
if p.sha(p.BWRAP) != p.BWRAP_SHA:
raise p.Refused('bwrap-drift')
a=adapter()
previous=set(Path('/dev/shm').glob('rmgr-secret-scan-*'))
with a.private_storage() as (fixture, outer_watcher):
data={'root':p.identity(Path('/')),'shm':p.identity(Path('/dev/shm')),
'ns':p.namespaces(),'readback':str(fixture/'inner.readback'),
'bwrap_pid':str(fixture/'bwrap.pid'),
'early_ready':str(fixture/'inner.early.ready'),
'phase_readback':str(fixture/'inner.phase.json'),
'bwrap_stderr':str(fixture/'bwrap.stderr'),
'release_gate':str(fixture/'release.gate'), 'gate_token':os.urandom(16).hex(),
'interpreter_sha256':p.sha(Path('/usr/bin/python3'))}
path=fixture/'spec.json'; path.write_text(json.dumps(data))
diagnostics = open(fixture/'spawner.stderr', 'wb')
child=subprocess.Popen([sys.executable,'-I',str(Path(__file__).resolve()),'--spawn',str(path)],
env={'PATH':'/usr/bin:/bin','HOME':'/home/worsch','LANG':'C'},
stdout=subprocess.DEVNULL,stderr=diagnostics,
preexec_fn=functools.partial(a.child_limits,1024**2,os.getpid()))
try:
descriptors['spawner']=os.pidfd_open(child.pid)
# Wait for atomic pre-effect readiness, register both exact
# process identities, then release only this generated gate.
until=time.monotonic()+8
early=Path(data['early_ready']); bwrap_pid=Path(data['bwrap_pid'])
while (not early.exists() or not bwrap_pid.exists()) and child.poll() is None and time.monotonic()<until:
time.sleep(.01)
if not early.exists() or not bwrap_pid.exists():
raise p.Refused('namespace-early-registration-failed')
ready=json.loads(early.read_text())
if set(ready) != {'inner_pid','namespace_identity_verified'} or not ready['namespace_identity_verified']:
raise p.Refused('namespace-early-readiness-refused')
descriptors['bwrap']=os.pidfd_open(int(bwrap_pid.read_text()))
descriptors['inner']=os.pidfd_open(ready['inner_pid'])
for descriptor in (descriptors['bwrap'],descriptors['inner']):
dead,_,_=select.select([descriptor],[],[],0)
if dead:
raise p.Refused('namespace-creator-died-before-release')
gate = Path(data['release_gate'])
temporary_gate = gate.with_suffix('.tmp')
temporary_gate.write_text(data['gate_token'])
temporary_gate.replace(gate)
until=time.monotonic()+8
readback=Path(data['readback'])
while not readback.exists() and child.poll() is None and time.monotonic()<until:
time.sleep(.02)
if not readback.exists():
raise p.Refused('namespace-lifecycle-preflight-failed')
body=json.loads(readback.read_text()); inner_area=Path(body['storage'])
if (not body['namespace_identity_verified'] or p.identity(inner_area)!=body['storage_identity']
or not str(inner_area).startswith('/dev/shm/rmgr-secret-scan-')):
raise p.Refused('lifecycle-readback-refused')
if body['inner_pid'] != ready['inner_pid']:
raise p.Refused('namespace-inner-identity-changed')
descriptors['cleanup_observer']=os.pidfd_open(body['watcher_pid'])
# Exactly this new disposable spawner is killed. The calling tool,
# shell, test harness, observer and their process groups are untouched.
signal.pidfd_send_signal(descriptors['spawner'],signal.SIGKILL)
child.wait(timeout=5)
until=time.monotonic()+8
pending=set(descriptors.values())
while pending and time.monotonic()<until:
ready,_,_=select.select(list(pending),[],[],max(0,until-time.monotonic()))
pending.difference_update(ready)
if pending or inner_area.exists():
raise p.Refused('namespace-hard-loss-cleanup-unverified')
receipt.update(namespace_identity_verified=True, pre_effect_pidfd_registration_verified=True,
exact_disposable_parent_killed=True,
bwrap_inner_and_cleanup_observer_death_verified=True,inner_storage_removed=True)
finally:
# Quiesce named source/readback creators before the outer storage
# context can remove their directory. Never kill the independent
# cleanup observer; it owns the inner storage recovery duty.
for name in ('spawner', 'bwrap', 'inner'):
descriptor = descriptors.get(name)
if descriptor is None:
continue
dead, _, _ = select.select([descriptor], [], [], 0)
if not dead:
try:
signal.pidfd_send_signal(descriptor, signal.SIGKILL)
except ProcessLookupError:
pass
# Retain the quiescence duty until exact death is proven.
select.select([descriptor], [], [])
if child.poll() is None:
child.kill()
child.wait(timeout=5)
observer = descriptors.get('cleanup_observer')
if observer is not None:
select.select([observer], [], [], 8)
diagnostics.close()
phase_path=Path(data['phase_readback'])
if phase_path.exists():
receipt['last_inner_phase']=json.loads(phase_path.read_text())
receipt['disposable_spawner_returncode']=child.returncode
# This lifecycle fixture handles public sentinel bytes only, no
# keys/indexes/source blobs. Retain bounded actual diagnostics.
for name in ('bwrap','spawner'):
diagnostic=fixture/(name+'.stderr')
if diagnostic.exists():
with diagnostic.open('rb') as output:
content=output.read(8193)
receipt[name+'_stderr_public']=content[:8192].decode('utf-8','replace')
receipt[name+'_stderr_truncated']=len(content)>8192
if fixture.exists() or set(Path('/dev/shm').glob('rmgr-secret-scan-*'))-previous:
raise p.Refused('outer-storage-cleanup-unverified')
receipt.update(status='verified',fixture_removed=True,new_scan_storage_absent=True)
except Exception as error:
receipt['reason']=error.args[0] if isinstance(error,p.Refused) else 'lifecycle-probe-unavailable'
finally:
if child is not None and child.poll() is None:
try:
signal.pidfd_send_signal(descriptors['spawner'],signal.SIGKILL)
child.wait(timeout=5)
except (OSError,subprocess.SubprocessError):
pass
for fd in descriptors.values():
os.close(fd)
receipt['fixture_removed']=fixture is None or not fixture.exists()
receipt['inner_storage_removed']=inner_area is None or not inner_area.exists()
receipt['driver_sha256']=p.sha(Path(__file__))
(HERE/'namespace-lifecycle-results.json').write_text(json.dumps(receipt,indent=2)+'\n')
print(json.dumps({'status':receipt['status'],'fixture_removed':receipt['fixture_removed'],
'inner_storage_removed':receipt['inner_storage_removed']}))
return 0 if receipt['status']=='verified' else 2
if __name__=='__main__':
parser=argparse.ArgumentParser();parser.add_argument('--spawn',type=Path);parser.add_argument('--inner',type=Path)
args=parser.parse_args()
raise SystemExit(spawn(args.spawn) if args.spawn else inner(args.inner) if args.inner else main())

View file

@ -0,0 +1,2 @@
....... [100%]
7 passed in 0.04s

View file

@ -0,0 +1 @@
{"status": "verified", "cases": 6, "fixture_removed": true}

View file

@ -0,0 +1 @@
{"status": "verified", "fixture_removed": true, "inner_storage_removed": true}

View file

@ -0,0 +1,88 @@
--- a/probe_namespace_lifecycle.py
+++ b/probe_namespace_lifecycle.py
@@ -30,6 +30,18 @@
or current['user'] == data['ns']['user'] or current['net'] == data['ns']['net']
or p.sha(Path('/usr/bin/python3')) != data['interpreter_sha256']):
return 23
+ # Register the exact inner process before any source-bearing storage can
+ # exist. Publication is atomic; the only earlier effect is PID metadata.
+ early = Path(data['early_ready'])
+ temporary = early.with_suffix('.tmp')
+ temporary.write_text(json.dumps({'inner_pid':os.getpid(), 'namespace_identity_verified':True}))
+ temporary.replace(early)
+ until = time.monotonic() + 8
+ gate = Path(data['release_gate'])
+ while not gate.exists() and time.monotonic() < until:
+ time.sleep(.01)
+ if not gate.exists() or gate.read_text() != data['gate_token']:
+ return 25
a = adapter()
with a.private_storage() as (area, watcher):
(area/'public-generated-sentinel').write_bytes(b'public generated parent-loss sentinel')
@@ -52,7 +64,9 @@
child = subprocess.Popen(args, env=env, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL,
preexec_fn=functools.partial(a.child_limits,64*1024**2,os.getpid()))
try:
- Path(data['bwrap_pid']).write_text(str(child.pid))
+ temporary = Path(data['bwrap_pid'] + '.tmp')
+ temporary.write_text(str(child.pid))
+ temporary.replace(Path(data['bwrap_pid']))
return child.wait(timeout=30)
finally:
if child.poll() is None:
@@ -73,6 +87,8 @@
data={'root':p.identity(Path('/')),'shm':p.identity(Path('/dev/shm')),
'ns':p.namespaces(),'readback':str(fixture/'inner.readback'),
'bwrap_pid':str(fixture/'bwrap.pid'),
+ 'early_ready':str(fixture/'inner.early.ready'),
+ 'release_gate':str(fixture/'release.gate'), 'gate_token':os.urandom(16).hex(),
'interpreter_sha256':p.sha(Path('/usr/bin/python3'))}
path=fixture/'spec.json'; path.write_text(json.dumps(data))
child=subprocess.Popen([sys.executable,'-I',str(Path(__file__).resolve()),'--spawn',str(path)],
@@ -81,6 +97,25 @@
preexec_fn=functools.partial(a.child_limits,64*1024**2,os.getpid()))
try:
descriptors['spawner']=os.pidfd_open(child.pid)
+ # Wait for atomic pre-effect readiness, register both exact
+ # process identities, then release only this generated gate.
+ until=time.monotonic()+8
+ early=Path(data['early_ready']); bwrap_pid=Path(data['bwrap_pid'])
+ while (not early.exists() or not bwrap_pid.exists()) and child.poll() is None and time.monotonic()<until:
+ time.sleep(.01)
+ if not early.exists() or not bwrap_pid.exists():
+ raise p.Refused('namespace-early-registration-failed')
+ ready=json.loads(early.read_text())
+ if set(ready) != {'inner_pid','namespace_identity_verified'} or not ready['namespace_identity_verified']:
+ raise p.Refused('namespace-early-readiness-refused')
+ descriptors['bwrap']=os.pidfd_open(int(bwrap_pid.read_text()))
+ descriptors['inner']=os.pidfd_open(ready['inner_pid'])
+ for descriptor in (descriptors['bwrap'],descriptors['inner']):
+ dead,_,_=select.select([descriptor],[],[],0)
+ if dead:
+ raise p.Refused('namespace-creator-died-before-release')
+ with Path(data['release_gate']).open('x') as gate:
+ gate.write(data['gate_token'])
until=time.monotonic()+8
readback=Path(data['readback'])
while not readback.exists() and child.poll() is None and time.monotonic()<until:
@@ -91,8 +126,8 @@
if (not body['namespace_identity_verified'] or p.identity(inner_area)!=body['storage_identity']
or not str(inner_area).startswith('/dev/shm/rmgr-secret-scan-')):
raise p.Refused('lifecycle-readback-refused')
- descriptors['bwrap']=os.pidfd_open(int(Path(data['bwrap_pid']).read_text()))
- descriptors['inner']=os.pidfd_open(body['inner_pid'])
+ if body['inner_pid'] != ready['inner_pid']:
+ raise p.Refused('namespace-inner-identity-changed')
descriptors['cleanup_observer']=os.pidfd_open(body['watcher_pid'])
# Exactly this new disposable spawner is killed. The calling tool,
# shell, test harness, observer and their process groups are untouched.
@@ -105,7 +140,8 @@
pending.difference_update(ready)
if pending or inner_area.exists():
raise p.Refused('namespace-hard-loss-cleanup-unverified')
- receipt.update(namespace_identity_verified=True, exact_disposable_parent_killed=True,
+ receipt.update(namespace_identity_verified=True, pre_effect_pidfd_registration_verified=True,
+ exact_disposable_parent_killed=True,
bwrap_inner_and_cleanup_observer_death_verified=True,inner_storage_removed=True)
finally:
# Quiesce named source/readback creators before the outer storage

View file

@ -0,0 +1,139 @@
--- a/probe_namespace_lifecycle.py
+++ b/probe_namespace_lifecycle.py
@@ -22,14 +22,39 @@
return p.load_bound(p.SOURCE, p.SOURCE_SHA, 'reviewed_lifecycle_storage')
+def phase(data, name, error=None):
+ if 'phase_readback' not in data:
+ return
+ record = {'phase':name}
+ if error is not None:
+ record['exception_type'] = type(error).__name__
+ record['errno'] = getattr(error, 'errno', None)
+ allowed = {'volatile-storage-unavailable','cleanup-watchdog-unavailable',
+ 'volatile-storage-identity-changed','cleanup-watchdog-failed'}
+ if error.args and isinstance(error.args[0],str) and error.args[0] in allowed:
+ record['fixed_source_reason'] = error.args[0]
+ target=Path(data['phase_readback']); temporary=target.with_suffix('.tmp')
+ temporary.write_text(json.dumps(record)); temporary.replace(target)
+
+
def inner(path):
- data = json.loads(path.read_text())
+ data=json.loads(path.read_text())
+ try:
+ phase(data, 'inner-started')
+ return inner_body(data)
+ except Exception as error:
+ phase(data, 'inner-exception', error)
+ return 26
+
+
+def inner_body(data):
current = p.namespaces()
if (p.identity(Path('/')) != data['root'] or p.identity(Path('/dev/shm')) != data['shm']
or current['pid'] != data['ns']['pid'] or current['mnt'] == data['ns']['mnt']
or current['user'] == data['ns']['user'] or current['net'] == data['ns']['net']
or p.sha(Path('/usr/bin/python3')) != data['interpreter_sha256']):
return 23
+ phase(data, 'namespace-verified')
# Register the exact inner process before any source-bearing storage can
# exist. Publication is atomic; the only earlier effect is PID metadata.
early = Path(data['early_ready'])
@@ -41,16 +66,22 @@
while not gate.exists() and time.monotonic() < until:
time.sleep(.01)
if not gate.exists() or gate.read_text() != data['gate_token']:
+ phase(data, 'gate-token-refused')
return 25
+ phase(data, 'gate-released')
a = adapter()
+ phase(data, 'adapter-loaded')
with a.private_storage() as (area, watcher):
+ phase(data, 'storage-entered')
(area/'public-generated-sentinel').write_bytes(b'public generated parent-loss sentinel')
+ phase(data, 'sentinel-written')
readback = {'storage':str(area), 'storage_identity':p.identity(area),
'inner_pid':os.getpid(), 'watcher_pid':watcher.pid,
'namespace_identity_verified':True}
temporary = Path(data['readback'] + '.tmp')
temporary.write_text(json.dumps(readback))
temporary.replace(Path(data['readback']))
+ phase(data, 'full-readback-published')
time.sleep(30)
return 24 # The observer must kill the disposable spawner before normal expiry.
@@ -61,8 +92,9 @@
env = {'PATH':'/usr/bin:/bin','HOME':'/home/worsch','LANG':'C'}
args = p.command(Path('/home/worsch/repo-manager'), env, path)
args = args[:args.index('--')+1] + ['/usr/bin/python3','-I',str(Path(__file__).resolve()),'--inner',str(path)]
- child = subprocess.Popen(args, env=env, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL,
- preexec_fn=functools.partial(a.child_limits,64*1024**2,os.getpid()))
+ diagnostics = open(data['bwrap_stderr'], 'wb')
+ child = subprocess.Popen(args, env=env, stdout=subprocess.DEVNULL, stderr=diagnostics,
+ preexec_fn=functools.partial(a.child_limits,1024**2,os.getpid()))
try:
temporary = Path(data['bwrap_pid'] + '.tmp')
temporary.write_text(str(child.pid))
@@ -71,6 +103,7 @@
finally:
if child.poll() is None:
child.kill(); child.wait(timeout=5)
+ diagnostics.close()
def main():
@@ -88,13 +121,16 @@
'ns':p.namespaces(),'readback':str(fixture/'inner.readback'),
'bwrap_pid':str(fixture/'bwrap.pid'),
'early_ready':str(fixture/'inner.early.ready'),
+ 'phase_readback':str(fixture/'inner.phase.json'),
+ 'bwrap_stderr':str(fixture/'bwrap.stderr'),
'release_gate':str(fixture/'release.gate'), 'gate_token':os.urandom(16).hex(),
'interpreter_sha256':p.sha(Path('/usr/bin/python3'))}
path=fixture/'spec.json'; path.write_text(json.dumps(data))
+ diagnostics = open(fixture/'spawner.stderr', 'wb')
child=subprocess.Popen([sys.executable,'-I',str(Path(__file__).resolve()),'--spawn',str(path)],
env={'PATH':'/usr/bin:/bin','HOME':'/home/worsch','LANG':'C'},
- stdout=subprocess.DEVNULL,stderr=subprocess.DEVNULL,
- preexec_fn=functools.partial(a.child_limits,64*1024**2,os.getpid()))
+ stdout=subprocess.DEVNULL,stderr=diagnostics,
+ preexec_fn=functools.partial(a.child_limits,1024**2,os.getpid()))
try:
descriptors['spawner']=os.pidfd_open(child.pid)
# Wait for atomic pre-effect readiness, register both exact
@@ -114,8 +150,10 @@
dead,_,_=select.select([descriptor],[],[],0)
if dead:
raise p.Refused('namespace-creator-died-before-release')
- with Path(data['release_gate']).open('x') as gate:
- gate.write(data['gate_token'])
+ gate = Path(data['release_gate'])
+ temporary_gate = gate.with_suffix('.tmp')
+ temporary_gate.write_text(data['gate_token'])
+ temporary_gate.replace(gate)
until=time.monotonic()+8
readback=Path(data['readback'])
while not readback.exists() and child.poll() is None and time.monotonic()<until:
@@ -165,6 +203,20 @@
observer = descriptors.get('cleanup_observer')
if observer is not None:
select.select([observer], [], [], 8)
+ diagnostics.close()
+ phase_path=Path(data['phase_readback'])
+ if phase_path.exists():
+ receipt['last_inner_phase']=json.loads(phase_path.read_text())
+ receipt['disposable_spawner_returncode']=child.returncode
+ # This lifecycle fixture handles public sentinel bytes only, no
+ # keys/indexes/source blobs. Retain bounded actual diagnostics.
+ for name in ('bwrap','spawner'):
+ diagnostic=fixture/(name+'.stderr')
+ if diagnostic.exists():
+ with diagnostic.open('rb') as output:
+ content=output.read(8193)
+ receipt[name+'_stderr_public']=content[:8192].decode('utf-8','replace')
+ receipt[name+'_stderr_truncated']=len(content)>8192
if fixture.exists() or set(Path('/dev/shm').glob('rmgr-secret-scan-*'))-previous:
raise p.Refused('outer-storage-cleanup-unverified')
receipt.update(status='verified',fixture_removed=True,new_scan_storage_absent=True)

View file

@ -0,0 +1,158 @@
#!/usr/bin/env python3
"""Hard-loss fixture targets only a newly spawned generated-data process tree."""
import argparse
import functools
import importlib.util
import json
import os
from pathlib import Path
import select
import signal
import subprocess
import sys
import time
HERE = Path(__file__).resolve().parent
spec = importlib.util.spec_from_file_location('namespace_profile', HERE/'probe_namespace_hooks.py')
p = importlib.util.module_from_spec(spec)
spec.loader.exec_module(p)
def adapter():
return p.load_bound(p.SOURCE, p.SOURCE_SHA, 'reviewed_lifecycle_storage')
def inner(path):
data = json.loads(path.read_text())
current = p.namespaces()
if (p.identity(Path('/')) != data['root'] or p.identity(Path('/dev/shm')) != data['shm']
or current['pid'] != data['ns']['pid'] or current['mnt'] == data['ns']['mnt']
or current['user'] == data['ns']['user'] or current['net'] == data['ns']['net']
or p.sha(Path('/usr/bin/python3')) != data['interpreter_sha256']):
return 23
a = adapter()
with a.private_storage() as (area, watcher):
(area/'public-generated-sentinel').write_bytes(b'public generated parent-loss sentinel')
readback = {'storage':str(area), 'storage_identity':p.identity(area),
'inner_pid':os.getpid(), 'watcher_pid':watcher.pid,
'namespace_identity_verified':True}
temporary = Path(data['readback'] + '.tmp')
temporary.write_text(json.dumps(readback))
temporary.replace(Path(data['readback']))
time.sleep(30)
return 24 # The observer must kill the disposable spawner before normal expiry.
def spawn(path):
a = adapter()
data = json.loads(path.read_text())
env = {'PATH':'/usr/bin:/bin','HOME':'/home/worsch','LANG':'C'}
args = p.command(Path('/home/worsch/repo-manager'), env, path)
args = args[:args.index('--')+1] + ['/usr/bin/python3','-I',str(Path(__file__).resolve()),'--inner',str(path)]
child = subprocess.Popen(args, env=env, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL,
preexec_fn=functools.partial(a.child_limits,64*1024**2,os.getpid()))
try:
Path(data['bwrap_pid']).write_text(str(child.pid))
return child.wait(timeout=30)
finally:
if child.poll() is None:
child.kill(); child.wait(timeout=5)
def main():
receipt={'status':'unverified','scope':'generated namespace hard-parent-loss process tree only',
'real_index_opened':False,'real_credentials_read':False,'provider_calls':0,
'host_scanner_modified':False}
descriptors={}; child=None; fixture=None; inner_area=None
try:
if p.sha(p.BWRAP) != p.BWRAP_SHA:
raise p.Refused('bwrap-drift')
a=adapter()
previous=set(Path('/dev/shm').glob('rmgr-secret-scan-*'))
with a.private_storage() as (fixture, outer_watcher):
data={'root':p.identity(Path('/')),'shm':p.identity(Path('/dev/shm')),
'ns':p.namespaces(),'readback':str(fixture/'inner.readback'),
'bwrap_pid':str(fixture/'bwrap.pid'),
'interpreter_sha256':p.sha(Path('/usr/bin/python3'))}
path=fixture/'spec.json'; path.write_text(json.dumps(data))
child=subprocess.Popen([sys.executable,'-I',str(Path(__file__).resolve()),'--spawn',str(path)],
env={'PATH':'/usr/bin:/bin','HOME':'/home/worsch','LANG':'C'},
stdout=subprocess.DEVNULL,stderr=subprocess.DEVNULL,
preexec_fn=functools.partial(a.child_limits,64*1024**2,os.getpid()))
try:
descriptors['spawner']=os.pidfd_open(child.pid)
until=time.monotonic()+8
readback=Path(data['readback'])
while not readback.exists() and child.poll() is None and time.monotonic()<until:
time.sleep(.02)
if not readback.exists():
raise p.Refused('namespace-lifecycle-preflight-failed')
body=json.loads(readback.read_text()); inner_area=Path(body['storage'])
if (not body['namespace_identity_verified'] or p.identity(inner_area)!=body['storage_identity']
or not str(inner_area).startswith('/dev/shm/rmgr-secret-scan-')):
raise p.Refused('lifecycle-readback-refused')
descriptors['bwrap']=os.pidfd_open(int(Path(data['bwrap_pid']).read_text()))
descriptors['inner']=os.pidfd_open(body['inner_pid'])
descriptors['cleanup_observer']=os.pidfd_open(body['watcher_pid'])
# Exactly this new disposable spawner is killed. The calling tool,
# shell, test harness, observer and their process groups are untouched.
signal.pidfd_send_signal(descriptors['spawner'],signal.SIGKILL)
child.wait(timeout=5)
until=time.monotonic()+8
pending=set(descriptors.values())
while pending and time.monotonic()<until:
ready,_,_=select.select(list(pending),[],[],max(0,until-time.monotonic()))
pending.difference_update(ready)
if pending or inner_area.exists():
raise p.Refused('namespace-hard-loss-cleanup-unverified')
receipt.update(namespace_identity_verified=True, exact_disposable_parent_killed=True,
bwrap_inner_and_cleanup_observer_death_verified=True,inner_storage_removed=True)
finally:
# Quiesce named source/readback creators before the outer storage
# context can remove their directory. Never kill the independent
# cleanup observer; it owns the inner storage recovery duty.
for name in ('spawner', 'bwrap', 'inner'):
descriptor = descriptors.get(name)
if descriptor is None:
continue
dead, _, _ = select.select([descriptor], [], [], 0)
if not dead:
try:
signal.pidfd_send_signal(descriptor, signal.SIGKILL)
except ProcessLookupError:
pass
# Retain the quiescence duty until exact death is proven.
select.select([descriptor], [], [])
if child.poll() is None:
child.kill()
child.wait(timeout=5)
observer = descriptors.get('cleanup_observer')
if observer is not None:
select.select([observer], [], [], 8)
if fixture.exists() or set(Path('/dev/shm').glob('rmgr-secret-scan-*'))-previous:
raise p.Refused('outer-storage-cleanup-unverified')
receipt.update(status='verified',fixture_removed=True,new_scan_storage_absent=True)
except Exception as error:
receipt['reason']=error.args[0] if isinstance(error,p.Refused) else 'lifecycle-probe-unavailable'
finally:
if child is not None and child.poll() is None:
try:
signal.pidfd_send_signal(descriptors['spawner'],signal.SIGKILL)
child.wait(timeout=5)
except (OSError,subprocess.SubprocessError):
pass
for fd in descriptors.values():
os.close(fd)
receipt['fixture_removed']=fixture is None or not fixture.exists()
receipt['inner_storage_removed']=inner_area is None or not inner_area.exists()
receipt['driver_sha256']=p.sha(Path(__file__))
(HERE/'namespace-lifecycle-results.json').write_text(json.dumps(receipt,indent=2)+'\n')
print(json.dumps({'status':receipt['status'],'fixture_removed':receipt['fixture_removed'],
'inner_storage_removed':receipt['inner_storage_removed']}))
return 0 if receipt['status']=='verified' else 2
if __name__=='__main__':
parser=argparse.ArgumentParser();parser.add_argument('--spawn',type=Path);parser.add_argument('--inner',type=Path)
args=parser.parse_args()
raise SystemExit(spawn(args.spawn) if args.spawn else inner(args.inner) if args.inner else main())

View file

@ -0,0 +1,126 @@
{
"state": "R3 coordinator-executed fixture verified; owner completion patch prepared for root review, not applied",
"owner_head": "b02e1cefb0e07fe246dc9fe9c5a989fe06116587",
"source_sha256": "e709c658f779534fcab093207b0a78e49d54fc584c515fdf7ac535ce75f6c400",
"scanner_sha256": "88f91962aa2f93ac6ab281d553b9e125f5197bbbce38f9f2437f7299c32e5509",
"hook_sha256": "d50cf763dc9814383c6886e30b6650bbbdcb49ddd78889082e3fda3626a2cbfd",
"bwrap_sha256": "e318903862396f96de3df57264e0158682b952fd3fb53ac23d876413e7b30f71",
"files": {
"probe_namespace_hooks.py": "ff276bae336a560d365ed1255f9af97b4207294574df9bcf74543dc5c0678e35",
"probe_namespace_lifecycle.py": "9c1db89b4379a7e55a72eba58efb3dfdae38d3ce69349d1bc1429465bc8cb5c5",
"test_namespace_profile.py": "dec2b0bdb5bfaad532f8151fa07ce975c9be48ea73cfc1bfc14f7c0151058180",
"run_reviewed_fixture.sh": "07d0b518a4e99c6d88c0cbc2a03c76b20429f0ac7d86d3985ca46528cbffe596"
},
"expected_hook_cases": 6,
"unit_profile_checks_passed": 10,
"namespace_policy": {
"changed": [
"user",
"mount",
"network"
],
"preserved": [
"pid",
"root dev/inode",
"dev/shm dev/inode",
"uid/gid"
],
"writable_bind_only": "/dev/shm to existing /dev/shm",
"scanner_shadow": "new generated empty0400file readonlybound over exact admitted scanner path only for unavailable cases",
"device_bind_exception": "/dev/null only; preserve host dev/inode/rdev, verify character type and actualO_RDWR|O_NOFOLLOW open"
},
"expected_unavailable_result": {
"status": "unverified",
"exit_code": 2,
"reason": "scanner-file-refused",
"scanned_blobs": 0
},
"forbidden_actions": [
"host scanner chmod/bytes changes",
"hook/source/config changes",
"real index open/write",
"real source blob scan",
"network/provider calls",
"new install",
"production configuration",
"external messages"
],
"cleanup": "reviewed canonical tmpfs+pidfd watchdog; bwrapdie-with-parent; source childrenPDEATHSIG; actual namespace hard-loss fixture first, exact disposable spawner only, independent cleanupobserver survives",
"bounds": {
"git_seconds": 20,
"hook_case_seconds": 30,
"child_cpu_seconds": 20,
"child_virtual_address_GiB": 8,
"generated_git_file_limit_MiB": 16,
"bwrap_hook_file_limit_MiB": 64,
"outer_watchdog_seconds": 180,
"watchdog_TERM_grace_seconds": 5,
"uncertain_kernel_quiescence": "retain observer duty until exact pidfddeath; never delete under known live creator"
},
"canonical_mutations_performed": false,
"runtime_fixture_executed": true,
"registration_gate": "atomic inner PID+namespace early-ready; main opens exact bwrap+inner pidfds and verifies live before writing exact generated gate; inner refuses storage after8seconds without release",
"superseded_lifecycle_sha256": "7b74d96c867d44a0e994890d58d0d039028684ded3611ffb65f9c7b09d6f5527",
"failed_r1": {
"driver_sha256": "c46efb37e02349ba73f83b46c8fd8b1abc286282be8dc0a105ae76911e1ca266",
"result": "namespace-lifecycle-preflight-failed",
"fixture_removed": true,
"inner_storage_removed": true,
"raw_packet": "failed-r1/",
"stderr_history": "R1 discarded spawner/bwrap stderr; cannot recover retroactively"
},
"r2_delta": [
"atomic release-gate publication",
"fixed public phase readback with exceptionclass/errno/whitelisted source reason",
"lifecycle-only bwrap/spawner stderr capture capped8192bytes each; file growth capped1MiB per child",
"no canonical or actual-hook driver changes"
],
"failed_r2": {
"driver_sha256": "9021bd7a6a52ebe4ecd52587094b793a967f2578e24c6a30ed7b81c4a9154f52",
"last_inner_phase": {
"phase": "inner-exception",
"exception_type": "PermissionError",
"errno": 13
},
"stderr_empty": true,
"cleanup_true": true,
"raw_packet": "failed-r2/",
"cause": "unverified; narrow /dev/null successor under review"
},
"r3_delta": [
"readonlyroot unchanged; add onlydev-bind/dev/null\u2192/dev/null",
"verify nullcharacter type+hostdevice/inode/rdev+actualO_RDWR open inside namespace",
"preserve last_successful_phase and filenameonlyifliteral/dev/null onexception",
"same gate/lifecycle/scriptpins, no hostscanner/source/hook mutation"
],
"validation": {
"unit_profile_checks": 10,
"namespace_lifecycle_verified": true,
"actual_configured_hook_cases": 6,
"root_and_shm_identity_readback_verified": true,
"source_hook_interpreter_hash_readback_verified": true,
"host_scanner_stat_hash_mode_unchanged": true,
"fixtures_removed": true,
"new_scan_storage_absent": true,
"real_index_opened": false,
"real_index_stat_and_HEAD_unchanged": true
},
"receipts": {
"profile-test-results.txt": "a837324a2f5c0d804ee26513e45c3e17425242b25aba8e53fe57a7379e8a79a5",
"namespace-lifecycle-results.json": "7250def507f30c164499738bb3aa65668c27853319370b34eef6a41685523dc4",
"namespace-hook-results.json": "5aaef79c0be4ae3cf721482784b255dde795559363bfb671e64ba6252fec59bc"
},
"owner_completion": {
"base_commit": "b02e1cefb0e07fe246dc9fe9c5a989fe06116587",
"base_file_sha256": "a75a106b77fe481b45e5d13593261f8a540c7eafeda1b40c0b2116ecdc9ee816",
"result_file_sha256": "966d15ccdabc8edf98bc58f9422ea190566d05fe4208f4749f59a9731f4e108d",
"patch_sha256": "0e7a98972fd6863ba839c000669d167e36b5ae3257a52db285e5ffbe03a7a04c",
"task_status_changes": {
"RMGR-WP-0021-T05": "progress\u2192done"
},
"T03": "progress",
"T04": "todo",
"workplan_status": "active",
"canonical_mutation_performed": false
}
}

View file

@ -0,0 +1,126 @@
--- a/probe_namespace_hooks.py
+++ b/probe_namespace_hooks.py
@@ -45,6 +45,24 @@
return [item.st_dev, item.st_ino]
+def null_identity():
+ item = os.stat('/dev/null')
+ return [item.st_dev, item.st_ino, item.st_rdev, stat.S_ISCHR(item.st_mode)]
+
+
+def check_null(expected):
+ if null_identity() != expected or not expected[3]:
+ raise Refused('null-device-identity-refused')
+ descriptor = os.open(os.devnull, os.O_RDWR | os.O_NOFOLLOW)
+ try:
+ item = os.fstat(descriptor)
+ if [item.st_dev,item.st_ino,item.st_rdev,stat.S_ISCHR(item.st_mode)] != expected:
+ raise Refused('null-device-open-identity-refused')
+ finally:
+ os.close(descriptor)
+ return {'character_device':True,'host_identity_and_rdev_preserved':True,'read_write_open_verified':True}
+
+
def namespaces():
return {key: os.readlink('/proc/self/ns/' + key) for key in ('user', 'mnt', 'pid', 'net')}
@@ -62,6 +80,7 @@
def command(root, env, spec_path, shadow=None):
argv = [str(BWRAP), '--unshare-user', '--unshare-net', '--die-with-parent', '--clearenv',
'--ro-bind', '/', '/', '--bind', '/dev/shm', '/dev/shm',
+ '--dev-bind', '/dev/null', '/dev/null',
'--uid', str(os.getuid()), '--gid', str(os.getgid()), '--chdir', str(root)]
if shadow is not None:
argv += ['--ro-bind', str(shadow), str(BINARY)]
@@ -73,7 +92,7 @@
def check_spec(spec):
if set(spec) != {'root', 'hook', 'shadow', 'readback', 'host_root', 'host_shm',
- 'host_ns', 'uid', 'gid', 'interpreter_sha256', 'driver_sha256'}:
+ 'host_ns', 'host_null', 'uid', 'gid', 'interpreter_sha256', 'driver_sha256'}:
raise Refused('spec-schema-refused')
allowed = {
'/home/worsch/repo-manager': '/home/worsch/repo-manager/.githooks/pre-commit',
@@ -103,6 +122,7 @@
or not (os.statvfs('/').f_flag & os.ST_RDONLY)
or os.statvfs('/dev/shm').f_flag & os.ST_RDONLY):
raise Refused('namespace-identity-refused')
+ null_readback = check_null(spec['host_null'])
if (sha(SOURCE) != SOURCE_SHA or sha(Path(spec['hook'])) != HOOK_SHA
or sha(Path(__file__).resolve()) != spec['driver_sha256']
or shutil.which('python3') != '/usr/bin/python3'
@@ -119,7 +139,7 @@
record = {'verified': True, 'root_identity_preserved': True,
'shm_identity_preserved': True, 'root_readonly': True, 'shm_writable': True,
'user_mount_network_namespaces_changed': True, 'pid_namespace_preserved': True,
- 'uid_gid_preserved': True, 'source_sha256': SOURCE_SHA,
+ 'uid_gid_preserved': True, 'null_device_readback':null_readback, 'source_sha256': SOURCE_SHA,
'hook_sha256': HOOK_SHA, 'interpreter_sha256': spec['interpreter_sha256'],
'scanner_view': 'empty-0400-shadow' if spec['shadow'] else 'pinned-real-scanner'}
target = Path(spec['readback'])
@@ -201,7 +221,7 @@
readback_path = local / (case+'.readback.json')
spec = {'root': str(root), 'hook': str(hook), 'shadow': unavailable,
'readback': str(readback_path), 'host_root': host_root, 'host_shm': host_shm,
- 'host_ns': host_ns, 'uid': os.getuid(), 'gid': os.getgid(),
+ 'host_ns': host_ns, 'host_null': null_identity(), 'uid': os.getuid(), 'gid': os.getgid(),
'interpreter_sha256': interpreter_sha, 'driver_sha256': sha(Path(__file__))}
spec_path.write_text(json.dumps(spec))
result = subprocess.run(command(root, probe_env, spec_path,
--- a/probe_namespace_lifecycle.py
+++ b/probe_namespace_lifecycle.py
@@ -27,12 +27,17 @@
return
record = {'phase':name}
if error is not None:
+ record['last_successful_phase']=data.get('_last_successful_phase')
+ if getattr(error,'filename',None) == '/dev/null':
+ record['fixed_filename']='/dev/null'
record['exception_type'] = type(error).__name__
record['errno'] = getattr(error, 'errno', None)
allowed = {'volatile-storage-unavailable','cleanup-watchdog-unavailable',
'volatile-storage-identity-changed','cleanup-watchdog-failed'}
if error.args and isinstance(error.args[0],str) and error.args[0] in allowed:
record['fixed_source_reason'] = error.args[0]
+ if error is None:
+ data['_last_successful_phase']=name
target=Path(data['phase_readback']); temporary=target.with_suffix('.tmp')
temporary.write_text(json.dumps(record)); temporary.replace(target)
@@ -55,6 +60,8 @@
or p.sha(Path('/usr/bin/python3')) != data['interpreter_sha256']):
return 23
phase(data, 'namespace-verified')
+ null_readback = p.check_null(data['host_null'])
+ phase(data, 'null-device-opened')
# Register the exact inner process before any source-bearing storage can
# exist. Publication is atomic; the only earlier effect is PID metadata.
early = Path(data['early_ready'])
@@ -77,7 +84,7 @@
phase(data, 'sentinel-written')
readback = {'storage':str(area), 'storage_identity':p.identity(area),
'inner_pid':os.getpid(), 'watcher_pid':watcher.pid,
- 'namespace_identity_verified':True}
+ 'namespace_identity_verified':True, 'null_device_readback':null_readback}
temporary = Path(data['readback'] + '.tmp')
temporary.write_text(json.dumps(readback))
temporary.replace(Path(data['readback']))
@@ -118,7 +125,7 @@
previous=set(Path('/dev/shm').glob('rmgr-secret-scan-*'))
with a.private_storage() as (fixture, outer_watcher):
data={'root':p.identity(Path('/')),'shm':p.identity(Path('/dev/shm')),
- 'ns':p.namespaces(),'readback':str(fixture/'inner.readback'),
+ 'ns':p.namespaces(),'host_null':p.null_identity(),'readback':str(fixture/'inner.readback'),
'bwrap_pid':str(fixture/'bwrap.pid'),
'early_ready':str(fixture/'inner.early.ready'),
'phase_readback':str(fixture/'inner.phase.json'),
@@ -179,7 +186,7 @@
if pending or inner_area.exists():
raise p.Refused('namespace-hard-loss-cleanup-unverified')
receipt.update(namespace_identity_verified=True, pre_effect_pidfd_registration_verified=True,
- exact_disposable_parent_killed=True,
+ exact_disposable_parent_killed=True, null_device_readback=body['null_device_readback'],
bwrap_inner_and_cleanup_observer_death_verified=True,inner_storage_removed=True)
finally:
# Quiesce named source/readback creators before the outer storage

View file

@ -0,0 +1,52 @@
--- a/workplans/RMGR-WP-0021-secret-detection-controls.md
+++ b/workplans/RMGR-WP-0021-secret-detection-controls.md
@@ -155,7 +155,7 @@
```task
id: RMGR-WP-0021-T05
-status: progress
+status: done
priority: medium
state_hub_task_id: "25fbe694-41d8-5232-bce0-4ed362387d5a"
```
@@ -204,3 +204,40 @@
through rmgr sync --push and central primary/railiance01 accepted source projection;
no global installed CLI is claimed. T03/T04 and whole target gates remain open.
Final coordinator evidence: resume-integration-r1/publication-verification.json.
+
+
+2026-10-17 bounded T05 completion evidence: the independently reviewed R3 namespace
+fixture passed ten profile checks, exact-pidfd hard-parent-loss and cleanup
+acceptance, and six actual configured-hook cases. Both the shared repo-manager
+hook and Custodian hook accepted a clean generated blob (exit 0), blocked a
+freshly generated private-key fixture (exit 1), and refused a non-executable
+scanner view (exit 2, `unverified`, `scanner-file-refused`, zero scanned blobs).
+The unavailable view was a new empty 0400 file read-only-bound over the exact
+configured scanner path inside fresh user/mount/network namespaces; the host
+scanner's bytes, stat identity and mode were unchanged. The canonical source,
+hooks and interpreter hashes were read back before exec, original root and
+`/dev/shm` device/inode identities and UID/GID were preserved, root was read only,
+and only original `/dev/shm` and exact `/dev/null` had the reviewed writable/device
+bind exceptions. The null character device and actual O_RDWR open were verified.
+PID namespace identity stayed shared so the canonical independent cleanup
+observer survived parent loss. Real indexes were not opened, real index stat
+identities and HEADs stayed unchanged, and all new volatile storage was absent.
+
+Retain the failed preparation history: R1 refused after early process
+registration without a full readback; R2 recorded PermissionError errno 13,
+without enough retained phase information to establish its exact cause. Both
+failed revisions and receipts are in `failed-r1/` and `failed-r2/`. R3 atomically
+published the release gate, retained fixed public phase diagnostics and verified
+the narrow `/dev/null` device bind and open. Its successful result does not
+retroactively assign a verified cause or success to R1/R2.
+
+Receipts: Custodian
+`docs/changes/netkingdom-target-2026-10-17/scanner-unavailable-r1/namespace-lifecycle-results.json`
+and `namespace-hook-results.json`, with exact driver hashes and manifest.
+Earlier publication and explicit repo-local CLI acceptance remain recorded above;
+no globally installed CLI is claimed. This completes the bounded local staged
+scanner optimization and its configured-hook generated-fixture acceptance. It
+proves the exact non-executable scanner view within this namespace fixture, not
+an observed host outage or coverage of other machines. T03 remains progress,
+T04 remains todo, the workplan remains active, and remote receive/CI, broader
+source-control coverage, real finding response and whole TSA15 remain open.

View file

@ -0,0 +1,6 @@
{
"exit_code": 0,
"stdout": "[main 9ebde0a] docs(security): accept bounded staged scanner runtime fixtures\n 1 file changed, 38 insertions(+), 1 deletion(-)\n",
"stderr": "{\"blocked_blob_ids\": [], \"scanned_blobs\": 1, \"scanner_sha256\": \"88f91962aa2f93ac6ab281d553b9e125f5197bbbce38f9f2437f7299c32e5509\", \"scanner_version\": \"8.30.1\", \"scope\": \"changed-staged-blobs\", \"status\": \"clean\"}\n",
"head": "9ebde0a9bd60d5c82910494fbe6bd1b891455cee"
}

View file

@ -0,0 +1,20 @@
{
"ok": true,
"status": "pending_push",
"message": "commit is not yet visible to the authoritative forge",
"git": {
"upstream": "origin/main",
"behind": 0,
"ahead": 1
},
"identifiers": {
"schema": "repo-manager.identifier-assignment.v1",
"ok": true,
"executed": true,
"repo": "repo-manager",
"namespace": "helixforge",
"assignments": [],
"historical_invalid_identifiers": [],
"files_changed": []
}
}

View file

@ -0,0 +1,272 @@
#!/usr/bin/env python3
"""Generated alternate-index hook probes; no host scanner/hook/source mutation.
Only persistent writes are fixed-metadata receipts in this review packet.
User+mount namespaces shadow the exact scanner path; PID namespace stays shared
so the admitted canonical scanner's independent cleanup watchdog can survive.
"""
from __future__ import annotations
import argparse
import functools
import hashlib
import json
import os
from pathlib import Path
import shutil
import stat
import subprocess
import sys
import types
HERE = Path(__file__).resolve().parent
BASE = HERE.parent.parent / 'netkingdom-target-2026-10-16/scanner-batch-r1/probe_configured_hooks.py'
BASE_SHA = 'c91d2dc83f04ec17147c0e1410e42f4817b69e4cc5a02201682e5fa7b021b6f4'
BWRAP = Path('/usr/bin/bwrap')
BWRAP_SHA = 'e318903862396f96de3df57264e0158682b952fd3fb53ac23d876413e7b30f71'
OWNER_HEAD = b'b02e1cefb0e07fe246dc9fe9c5a989fe06116587'
SOURCE = Path('/home/worsch/repo-manager/src/repo_manager/secret_scan.py')
SOURCE_SHA = 'e709c658f779534fcab093207b0a78e49d54fc584c515fdf7ac535ce75f6c400'
BINARY = Path('/home/worsch/.local/lib/repo-manager/gitleaks/8.30.1/gitleaks')
BINARY_SHA = '88f91962aa2f93ac6ab281d553b9e125f5197bbbce38f9f2437f7299c32e5509'
HOOK_SHA = 'd50cf763dc9814383c6886e30b6650bbbdcb49ddd78889082e3fda3626a2cbfd'
class Refused(Exception):
pass
def sha(path):
return hashlib.sha256(path.read_bytes()).hexdigest()
def identity(path):
item = path.stat()
return [item.st_dev, item.st_ino]
def null_identity():
item = os.stat('/dev/null')
return [item.st_dev, item.st_ino, item.st_rdev, stat.S_ISCHR(item.st_mode)]
def check_null(expected):
if null_identity() != expected or not expected[3]:
raise Refused('null-device-identity-refused')
descriptor = os.open(os.devnull, os.O_RDWR | os.O_NOFOLLOW)
try:
item = os.fstat(descriptor)
if [item.st_dev,item.st_ino,item.st_rdev,stat.S_ISCHR(item.st_mode)] != expected:
raise Refused('null-device-open-identity-refused')
finally:
os.close(descriptor)
return {'character_device':True,'host_identity_and_rdev_preserved':True,'read_write_open_verified':True}
def namespaces():
return {key: os.readlink('/proc/self/ns/' + key) for key in ('user', 'mnt', 'pid', 'net')}
def load_bound(path, digest, name):
content = path.read_bytes()
if hashlib.sha256(content).hexdigest() != digest:
raise Refused('bound-source-drift')
module = types.ModuleType(name)
module.__file__ = str(path)
exec(compile(content, str(path), 'exec'), module.__dict__)
return module
def command(root, env, spec_path, shadow=None):
argv = [str(BWRAP), '--unshare-user', '--unshare-net', '--die-with-parent', '--clearenv',
'--ro-bind', '/', '/', '--bind', '/dev/shm', '/dev/shm',
'--dev-bind', '/dev/null', '/dev/null',
'--uid', str(os.getuid()), '--gid', str(os.getgid()), '--chdir', str(root)]
if shadow is not None:
argv += ['--ro-bind', str(shadow), str(BINARY)]
for key, value in sorted(env.items()):
argv += ['--setenv', key, value]
argv += ['--', '/usr/bin/python3', '-I', str(Path(__file__).resolve()), '--inside', str(spec_path)]
return argv
def check_spec(spec):
if set(spec) != {'root', 'hook', 'shadow', 'readback', 'host_root', 'host_shm',
'host_ns', 'host_null', 'uid', 'gid', 'interpreter_sha256', 'driver_sha256'}:
raise Refused('spec-schema-refused')
allowed = {
'/home/worsch/repo-manager': '/home/worsch/repo-manager/.githooks/pre-commit',
'/home/worsch/the-custodian': '/home/worsch/the-custodian/.git/hooks/pre-commit',
}
if allowed.get(spec['root']) != spec['hook'] or not isinstance(spec['shadow'], bool):
raise Refused('spec-target-refused')
destination = Path(spec['readback'])
if not str(destination).startswith('/dev/shm/rmgr-secret-scan-'):
raise Refused('readback-storage-refused')
def inside(spec_path):
# All targets originate in the fixed reviewed outer driver. Refuse changes
# before executing a hook; only fixed metadata is written to volatile storage.
try:
spec = json.loads(spec_path.read_text())
check_spec(spec)
observed_ns = namespaces()
if (identity(Path('/')) != spec['host_root']
or identity(Path('/dev/shm')) != spec['host_shm']
or os.getuid() != spec['uid'] or os.getgid() != spec['gid']
or observed_ns['user'] == spec['host_ns']['user']
or observed_ns['mnt'] == spec['host_ns']['mnt']
or observed_ns['net'] == spec['host_ns']['net']
or observed_ns['pid'] != spec['host_ns']['pid']
or not (os.statvfs('/').f_flag & os.ST_RDONLY)
or os.statvfs('/dev/shm').f_flag & os.ST_RDONLY):
raise Refused('namespace-identity-refused')
null_readback = check_null(spec['host_null'])
if (sha(SOURCE) != SOURCE_SHA or sha(Path(spec['hook'])) != HOOK_SHA
or sha(Path(__file__).resolve()) != spec['driver_sha256']
or shutil.which('python3') != '/usr/bin/python3'
or sha(Path('/usr/bin/python3')) != spec['interpreter_sha256']):
raise Refused('namespace-code-readback-refused')
scanner = BINARY.stat()
if spec['shadow']:
if (not stat.S_ISREG(scanner.st_mode) or scanner.st_size != 0
or stat.S_IMODE(scanner.st_mode) != 0o400
or sha(BINARY) != hashlib.sha256(b'').hexdigest()):
raise Refused('scanner-shadow-readback-refused')
elif sha(BINARY) != BINARY_SHA or stat.S_IMODE(scanner.st_mode) != 0o755:
raise Refused('baseline-scanner-readback-refused')
record = {'verified': True, 'root_identity_preserved': True,
'shm_identity_preserved': True, 'root_readonly': True, 'shm_writable': True,
'user_mount_network_namespaces_changed': True, 'pid_namespace_preserved': True,
'uid_gid_preserved': True, 'null_device_readback':null_readback, 'source_sha256': SOURCE_SHA,
'hook_sha256': HOOK_SHA, 'interpreter_sha256': spec['interpreter_sha256'],
'scanner_view': 'empty-0400-shadow' if spec['shadow'] else 'pinned-real-scanner'}
target = Path(spec['readback'])
with target.open('x') as output:
json.dump(record, output)
os.execve(spec['hook'], [spec['hook']], dict(os.environ))
except Exception:
return 23
def environment(base):
env = base.fixed_env()
env['GIT_CONFIG_GLOBAL'] = '/dev/null'
overrides = [('core.fsmonitor', 'false'), ('core.splitIndex', 'false'),
('core.sparseCheckout', 'false'), ('core.untrackedCache', 'false')]
env['GIT_CONFIG_COUNT'] = str(len(overrides))
for number, (key, value) in enumerate(overrides):
env[f'GIT_CONFIG_KEY_{number}'] = key
env[f'GIT_CONFIG_VALUE_{number}'] = value
return env
def main():
receipt = {'status': 'unverified', 'scope': 'two actual configured hooks; generated alternate-index/object fixtures in mount/user/network namespaces',
'provider_calls': 0, 'real_credentials_read': False, 'real_index_opened': False,
'source_sha256': SOURCE_SHA, 'scanner_sha256': BINARY_SHA, 'hook_sha256': HOOK_SHA,
'bwrap_sha256': BWRAP_SHA, 'host_scanner_modified': False, 'rows': []}
fixture = None
try:
if sha(BWRAP) != BWRAP_SHA or BWRAP.stat().st_mode & 0o6022:
raise Refused('namespace-binary-refused')
base = load_bound(BASE, BASE_SHA, 'reviewed_hook_probe')
records = base.precheck()
if records[0]['head'] != OWNER_HEAD:
raise Refused('owner-head-drift')
before_binary = base.info(BINARY)
adapter = load_bound(SOURCE, SOURCE_SHA, 'canonical_scanner_storage')
prior_storage = set(Path('/dev/shm').glob('rmgr-secret-scan-*'))
host_ns = namespaces()
host_root = identity(Path('/')); host_shm = identity(Path('/dev/shm'))
interpreter_sha = sha(Path('/usr/bin/python3'))
with adapter.private_storage() as (fixture, watcher):
env = environment(base)
key_path = fixture / 'generated-key'
base.run(['/usr/bin/ssh-keygen', '-q', '-t', 'ed25519', '-N', '', '-C',
'public-generated-namespace-probe', '-f', str(key_path)], fixture, env,
adapter=adapter)
key = key_path.read_bytes()
shadow = fixture / 'unavailable-scanner'
with shadow.open('x'):
pass
shadow.chmod(0o400) # Only this newly created empty disposable file.
for number, record in enumerate(records):
root = record['root']; hook = record['hook']
local = fixture / str(number); local.mkdir(mode=0o700)
objects = local / 'objects'; objects.mkdir(mode=0o700)
probe_env = dict(env, GIT_INDEX_FILE=str(local/'index'),
GIT_OBJECT_DIRECTORY=str(objects), GIT_ALTERNATE_OBJECT_DIRECTORIES=record['objects'])
name = '__rmgr_namespace_generated_fixture__.txt'
if base.git(root, probe_env, 'ls-tree', '--name-only', 'HEAD', '--', name, adapter=adapter):
raise Refused('fixture-name-collision')
for case, payload, status, code, unavailable in [
('clean-control', b'public namespace hook fixture\n', 'clean', 0, False),
('generated-key-control', key, 'blocked', 1, False),
('scanner-unavailable', b'public namespace unavailable fixture\n', 'unverified', 2, True),
]:
if watcher.poll() is not None:
raise Refused('outer-watchdog-lost')
base.git(root, probe_env, 'read-tree', 'HEAD', adapter=adapter)
oid = base.git(root, probe_env, 'hash-object', '-w', '--stdin', data=payload,
adapter=adapter).decode().strip()
base.git(root, probe_env, 'update-index', '--add', '--cacheinfo',
'100644,'+oid+','+name, adapter=adapter)
changed = base.git(root, probe_env, 'diff', '--cached', '--name-only', '-z',
'--no-renames', '--no-ext-diff', '--no-textconv', adapter=adapter)
if changed != name.encode()+b'\0':
raise Refused('changed-fixture-scope-refused')
spec_path = local / (case+'.spec.json')
readback_path = local / (case+'.readback.json')
spec = {'root': str(root), 'hook': str(hook), 'shadow': unavailable,
'readback': str(readback_path), 'host_root': host_root, 'host_shm': host_shm,
'host_ns': host_ns, 'host_null': null_identity(), 'uid': os.getuid(), 'gid': os.getgid(),
'interpreter_sha256': interpreter_sha, 'driver_sha256': sha(Path(__file__))}
spec_path.write_text(json.dumps(spec))
result = subprocess.run(command(root, probe_env, spec_path,
shadow if unavailable else None), cwd=root, env=base.fixed_env(),
stdout=subprocess.PIPE, stderr=subprocess.PIPE, timeout=30, check=False,
preexec_fn=functools.partial(adapter.child_limits, 64*1024**2, os.getpid()))
if result.stderr or key.strip() in result.stdout or not readback_path.exists():
raise Refused('namespace-or-hook-output-refused')
readback = json.loads(readback_path.read_text())
body = json.loads(result.stdout)
if result.returncode != code or body.get('status') != status:
raise Refused('hook-result-refused')
if unavailable:
if body != {'status': 'unverified', 'scope': 'changed-staged-blobs',
'reason': 'scanner-file-refused', 'scanned_blobs': 0}:
raise Refused('unavailable-summary-refused')
elif body != {'status': status, 'scope': 'changed-staged-blobs',
'scanner_version': '8.30.1', 'scanner_sha256': BINARY_SHA,
'scanned_blobs': 1, 'blocked_blob_ids': [oid] if status=='blocked' else []}:
raise Refused('control-summary-refused')
receipt['rows'].append({'repo': root.name, 'case': case, 'status': status,
'exit_code': code, 'scanned_blobs': body['scanned_blobs'],
'reason': body.get('reason'), 'namespace_readback': readback})
if fixture.exists() or set(Path('/dev/shm').glob('rmgr-secret-scan-*')) - prior_storage:
raise Refused('volatile-cleanup-unverified')
after_records = base.precheck()
if (before_binary != base.info(BINARY)
or any(a['index_stat'] != b['index_stat'] or a['head'] != b['head']
for a, b in zip(records, after_records))):
raise Refused('host-state-changed')
receipt.update(status='verified', fixture_removed=True, new_scan_storage_absent=True,
real_index_stat_unchanged=True, real_heads_unchanged=True,
host_scanner_stat_hash_mode_unchanged=True, hook_source_routing_unchanged=True)
except Exception as error:
receipt['reason'] = error.args[0] if isinstance(error, Refused) else 'namespace-probe-unavailable'
receipt['fixture_removed'] = fixture is None or not fixture.exists()
receipt['driver_sha256'] = sha(Path(__file__))
(HERE/'namespace-hook-results.json').write_text(json.dumps(receipt, indent=2)+'\n')
print(json.dumps({'status':receipt['status'],'cases':len(receipt['rows']),
'fixture_removed':receipt['fixture_removed']}))
return 0 if receipt['status']=='verified' else 2
if __name__ == '__main__':
parser=argparse.ArgumentParser()
parser.add_argument('--inside', type=Path)
args=parser.parse_args()
raise SystemExit(inside(args.inside) if args.inside else main())

View file

@ -0,0 +1,253 @@
#!/usr/bin/env python3
"""Hard-loss fixture targets only a newly spawned generated-data process tree."""
import argparse
import functools
import importlib.util
import json
import os
from pathlib import Path
import select
import signal
import subprocess
import sys
import time
HERE = Path(__file__).resolve().parent
spec = importlib.util.spec_from_file_location('namespace_profile', HERE/'probe_namespace_hooks.py')
p = importlib.util.module_from_spec(spec)
spec.loader.exec_module(p)
def adapter():
return p.load_bound(p.SOURCE, p.SOURCE_SHA, 'reviewed_lifecycle_storage')
def phase(data, name, error=None):
if 'phase_readback' not in data:
return
record = {'phase':name}
if error is not None:
record['last_successful_phase']=data.get('_last_successful_phase')
if getattr(error,'filename',None) == '/dev/null':
record['fixed_filename']='/dev/null'
record['exception_type'] = type(error).__name__
record['errno'] = getattr(error, 'errno', None)
allowed = {'volatile-storage-unavailable','cleanup-watchdog-unavailable',
'volatile-storage-identity-changed','cleanup-watchdog-failed'}
if error.args and isinstance(error.args[0],str) and error.args[0] in allowed:
record['fixed_source_reason'] = error.args[0]
if error is None:
data['_last_successful_phase']=name
target=Path(data['phase_readback']); temporary=target.with_suffix('.tmp')
temporary.write_text(json.dumps(record)); temporary.replace(target)
def inner(path):
data=json.loads(path.read_text())
try:
phase(data, 'inner-started')
return inner_body(data)
except Exception as error:
phase(data, 'inner-exception', error)
return 26
def inner_body(data):
current = p.namespaces()
if (p.identity(Path('/')) != data['root'] or p.identity(Path('/dev/shm')) != data['shm']
or current['pid'] != data['ns']['pid'] or current['mnt'] == data['ns']['mnt']
or current['user'] == data['ns']['user'] or current['net'] == data['ns']['net']
or p.sha(Path('/usr/bin/python3')) != data['interpreter_sha256']):
return 23
phase(data, 'namespace-verified')
null_readback = p.check_null(data['host_null'])
phase(data, 'null-device-opened')
# Register the exact inner process before any source-bearing storage can
# exist. Publication is atomic; the only earlier effect is PID metadata.
early = Path(data['early_ready'])
temporary = early.with_suffix('.tmp')
temporary.write_text(json.dumps({'inner_pid':os.getpid(), 'namespace_identity_verified':True}))
temporary.replace(early)
until = time.monotonic() + 8
gate = Path(data['release_gate'])
while not gate.exists() and time.monotonic() < until:
time.sleep(.01)
if not gate.exists() or gate.read_text() != data['gate_token']:
phase(data, 'gate-token-refused')
return 25
phase(data, 'gate-released')
a = adapter()
phase(data, 'adapter-loaded')
with a.private_storage() as (area, watcher):
phase(data, 'storage-entered')
(area/'public-generated-sentinel').write_bytes(b'public generated parent-loss sentinel')
phase(data, 'sentinel-written')
readback = {'storage':str(area), 'storage_identity':p.identity(area),
'inner_pid':os.getpid(), 'watcher_pid':watcher.pid,
'namespace_identity_verified':True, 'null_device_readback':null_readback}
temporary = Path(data['readback'] + '.tmp')
temporary.write_text(json.dumps(readback))
temporary.replace(Path(data['readback']))
phase(data, 'full-readback-published')
time.sleep(30)
return 24 # The observer must kill the disposable spawner before normal expiry.
def spawn(path):
a = adapter()
data = json.loads(path.read_text())
env = {'PATH':'/usr/bin:/bin','HOME':'/home/worsch','LANG':'C'}
args = p.command(Path('/home/worsch/repo-manager'), env, path)
args = args[:args.index('--')+1] + ['/usr/bin/python3','-I',str(Path(__file__).resolve()),'--inner',str(path)]
diagnostics = open(data['bwrap_stderr'], 'wb')
child = subprocess.Popen(args, env=env, stdout=subprocess.DEVNULL, stderr=diagnostics,
preexec_fn=functools.partial(a.child_limits,1024**2,os.getpid()))
try:
temporary = Path(data['bwrap_pid'] + '.tmp')
temporary.write_text(str(child.pid))
temporary.replace(Path(data['bwrap_pid']))
return child.wait(timeout=30)
finally:
if child.poll() is None:
child.kill(); child.wait(timeout=5)
diagnostics.close()
def main():
receipt={'status':'unverified','scope':'generated namespace hard-parent-loss process tree only',
'real_index_opened':False,'real_credentials_read':False,'provider_calls':0,
'host_scanner_modified':False}
descriptors={}; child=None; fixture=None; inner_area=None
try:
if p.sha(p.BWRAP) != p.BWRAP_SHA:
raise p.Refused('bwrap-drift')
a=adapter()
previous=set(Path('/dev/shm').glob('rmgr-secret-scan-*'))
with a.private_storage() as (fixture, outer_watcher):
data={'root':p.identity(Path('/')),'shm':p.identity(Path('/dev/shm')),
'ns':p.namespaces(),'host_null':p.null_identity(),'readback':str(fixture/'inner.readback'),
'bwrap_pid':str(fixture/'bwrap.pid'),
'early_ready':str(fixture/'inner.early.ready'),
'phase_readback':str(fixture/'inner.phase.json'),
'bwrap_stderr':str(fixture/'bwrap.stderr'),
'release_gate':str(fixture/'release.gate'), 'gate_token':os.urandom(16).hex(),
'interpreter_sha256':p.sha(Path('/usr/bin/python3'))}
path=fixture/'spec.json'; path.write_text(json.dumps(data))
diagnostics = open(fixture/'spawner.stderr', 'wb')
child=subprocess.Popen([sys.executable,'-I',str(Path(__file__).resolve()),'--spawn',str(path)],
env={'PATH':'/usr/bin:/bin','HOME':'/home/worsch','LANG':'C'},
stdout=subprocess.DEVNULL,stderr=diagnostics,
preexec_fn=functools.partial(a.child_limits,1024**2,os.getpid()))
try:
descriptors['spawner']=os.pidfd_open(child.pid)
# Wait for atomic pre-effect readiness, register both exact
# process identities, then release only this generated gate.
until=time.monotonic()+8
early=Path(data['early_ready']); bwrap_pid=Path(data['bwrap_pid'])
while (not early.exists() or not bwrap_pid.exists()) and child.poll() is None and time.monotonic()<until:
time.sleep(.01)
if not early.exists() or not bwrap_pid.exists():
raise p.Refused('namespace-early-registration-failed')
ready=json.loads(early.read_text())
if set(ready) != {'inner_pid','namespace_identity_verified'} or not ready['namespace_identity_verified']:
raise p.Refused('namespace-early-readiness-refused')
descriptors['bwrap']=os.pidfd_open(int(bwrap_pid.read_text()))
descriptors['inner']=os.pidfd_open(ready['inner_pid'])
for descriptor in (descriptors['bwrap'],descriptors['inner']):
dead,_,_=select.select([descriptor],[],[],0)
if dead:
raise p.Refused('namespace-creator-died-before-release')
gate = Path(data['release_gate'])
temporary_gate = gate.with_suffix('.tmp')
temporary_gate.write_text(data['gate_token'])
temporary_gate.replace(gate)
until=time.monotonic()+8
readback=Path(data['readback'])
while not readback.exists() and child.poll() is None and time.monotonic()<until:
time.sleep(.02)
if not readback.exists():
raise p.Refused('namespace-lifecycle-preflight-failed')
body=json.loads(readback.read_text()); inner_area=Path(body['storage'])
if (not body['namespace_identity_verified'] or p.identity(inner_area)!=body['storage_identity']
or not str(inner_area).startswith('/dev/shm/rmgr-secret-scan-')):
raise p.Refused('lifecycle-readback-refused')
if body['inner_pid'] != ready['inner_pid']:
raise p.Refused('namespace-inner-identity-changed')
descriptors['cleanup_observer']=os.pidfd_open(body['watcher_pid'])
# Exactly this new disposable spawner is killed. The calling tool,
# shell, test harness, observer and their process groups are untouched.
signal.pidfd_send_signal(descriptors['spawner'],signal.SIGKILL)
child.wait(timeout=5)
until=time.monotonic()+8
pending=set(descriptors.values())
while pending and time.monotonic()<until:
ready,_,_=select.select(list(pending),[],[],max(0,until-time.monotonic()))
pending.difference_update(ready)
if pending or inner_area.exists():
raise p.Refused('namespace-hard-loss-cleanup-unverified')
receipt.update(namespace_identity_verified=True, pre_effect_pidfd_registration_verified=True,
exact_disposable_parent_killed=True, null_device_readback=body['null_device_readback'],
bwrap_inner_and_cleanup_observer_death_verified=True,inner_storage_removed=True)
finally:
# Quiesce named source/readback creators before the outer storage
# context can remove their directory. Never kill the independent
# cleanup observer; it owns the inner storage recovery duty.
for name in ('spawner', 'bwrap', 'inner'):
descriptor = descriptors.get(name)
if descriptor is None:
continue
dead, _, _ = select.select([descriptor], [], [], 0)
if not dead:
try:
signal.pidfd_send_signal(descriptor, signal.SIGKILL)
except ProcessLookupError:
pass
# Retain the quiescence duty until exact death is proven.
select.select([descriptor], [], [])
if child.poll() is None:
child.kill()
child.wait(timeout=5)
observer = descriptors.get('cleanup_observer')
if observer is not None:
select.select([observer], [], [], 8)
diagnostics.close()
phase_path=Path(data['phase_readback'])
if phase_path.exists():
receipt['last_inner_phase']=json.loads(phase_path.read_text())
receipt['disposable_spawner_returncode']=child.returncode
# This lifecycle fixture handles public sentinel bytes only, no
# keys/indexes/source blobs. Retain bounded actual diagnostics.
for name in ('bwrap','spawner'):
diagnostic=fixture/(name+'.stderr')
if diagnostic.exists():
with diagnostic.open('rb') as output:
content=output.read(8193)
receipt[name+'_stderr_public']=content[:8192].decode('utf-8','replace')
receipt[name+'_stderr_truncated']=len(content)>8192
if fixture.exists() or set(Path('/dev/shm').glob('rmgr-secret-scan-*'))-previous:
raise p.Refused('outer-storage-cleanup-unverified')
receipt.update(status='verified',fixture_removed=True,new_scan_storage_absent=True)
except Exception as error:
receipt['reason']=error.args[0] if isinstance(error,p.Refused) else 'lifecycle-probe-unavailable'
finally:
if child is not None and child.poll() is None:
try:
signal.pidfd_send_signal(descriptors['spawner'],signal.SIGKILL)
child.wait(timeout=5)
except (OSError,subprocess.SubprocessError):
pass
for fd in descriptors.values():
os.close(fd)
receipt['fixture_removed']=fixture is None or not fixture.exists()
receipt['inner_storage_removed']=inner_area is None or not inner_area.exists()
receipt['driver_sha256']=p.sha(Path(__file__))
(HERE/'namespace-lifecycle-results.json').write_text(json.dumps(receipt,indent=2)+'\n')
print(json.dumps({'status':receipt['status'],'fixture_removed':receipt['fixture_removed'],
'inner_storage_removed':receipt['inner_storage_removed']}))
return 0 if receipt['status']=='verified' else 2
if __name__=='__main__':
parser=argparse.ArgumentParser();parser.add_argument('--spawn',type=Path);parser.add_argument('--inner',type=Path)
args=parser.parse_args()
raise SystemExit(spawn(args.spawn) if args.spawn else inner(args.inner) if args.inner else main())

View file

@ -0,0 +1,2 @@
.......... [100%]
10 passed in 0.06s

View file

@ -0,0 +1,7 @@
#!/bin/bash
set -euo pipefail
packet=/home/worsch/the-custodian/docs/changes/netkingdom-target-2026-10-17/scanner-unavailable-r1
export PYTHONDONTWRITEBYTECODE=1
/home/worsch/repo-manager/.venv/bin/pytest -q "$packet/test_namespace_profile.py" > "$packet/profile-test-results.txt" 2>&1
/home/worsch/repo-manager/.venv/bin/python "$packet/probe_namespace_lifecycle.py" > "$packet/lifecycle-driver-result.txt"
/home/worsch/repo-manager/.venv/bin/python "$packet/probe_namespace_hooks.py" > "$packet/hook-driver-result.txt"

View file

@ -0,0 +1,107 @@
import importlib.util
import json
from pathlib import Path
import pytest
spec = importlib.util.spec_from_file_location('namespace_probe', Path(__file__).with_name('probe_namespace_hooks.py'))
probe = importlib.util.module_from_spec(spec)
spec.loader.exec_module(probe)
def profile(shadow=None):
return probe.command(Path('/home/worsch/repo-manager'),
{'PATH': '/usr/bin:/bin', 'GIT_INDEX_FILE': '/dev/shm/generated/index'},
Path('/dev/shm/generated/spec.json'), shadow)
def test_mount_profile_preserves_real_shm_and_readonly_root():
args = profile()
assert args[args.index('--ro-bind') + 1:args.index('--ro-bind') + 3] == ['/', '/']
assert args[args.index('--bind') + 1:args.index('--bind') + 3] == ['/dev/shm', '/dev/shm']
assert '--tmpfs' not in args
def test_pid_namespace_preserved_for_independent_cleanup_observer():
args = profile()
assert '--unshare-user' in args and '--unshare-net' in args
assert '--unshare-pid' not in args
assert '--die-with-parent' in args
def test_shadow_mount_targets_only_exact_admitted_scanner():
args = profile(Path('/dev/shm/generated/empty-0400'))
mounts = [args[i + 1:i + 3] for i, arg in enumerate(args) if arg == '--ro-bind']
assert mounts == [['/', '/'], ['/dev/shm/generated/empty-0400', str(probe.BINARY)]]
assert '--chmod' not in args
def test_child_interpreter_and_driver_are_explicit():
args = profile()
assert args[args.index('--') + 1:args.index('--') + 3] == ['/usr/bin/python3', '-I']
assert '--clearenv' in args
def test_unknown_target_spec_refuses():
spec = dict(root='/unreviewed', hook='/unreviewed/hook', shadow=True,
readback='/dev/shm/rmgr-secret-scan-test/readback', host_root=[1, 2], host_shm=[3, 4],
host_ns={}, host_null=[1,2,3,True], uid=1, gid=1, interpreter_sha256='x', driver_sha256='x')
with pytest.raises(probe.Refused, match='spec-target-refused'):
probe.check_spec(spec)
def test_inside_refuses_without_actual_namespace_identity(tmp_path, monkeypatch):
spec = dict(root='/home/worsch/repo-manager', hook='/home/worsch/repo-manager/.githooks/pre-commit',
shadow=True, readback='/dev/shm/rmgr-secret-scan-test/readback', host_root=[0, 0],
host_shm=[0, 0], host_ns=probe.namespaces(), host_null=[1,2,3,True], uid=0, gid=0,
interpreter_sha256='x', driver_sha256='x')
path = tmp_path/'spec.json'; path.write_text(json.dumps(spec))
monkeypatch.setattr(probe.os, 'execve', lambda *args: pytest.fail('hook must not execute'))
assert probe.inside(path) == 23
def test_lifecycle_gate_refuses_storage_without_coordinator_release(tmp_path, monkeypatch):
spec = importlib.util.spec_from_file_location('namespace_lifecycle', Path(__file__).with_name('probe_namespace_lifecycle.py'))
life = importlib.util.module_from_spec(spec); spec.loader.exec_module(life)
data = {'root':[1,2], 'shm':[1,2], 'ns':{'user':'old-user','mnt':'old-mnt','net':'old-net','pid':'same-pid'},
'interpreter_sha256':'interpreter', 'host_null':[1,2,3,True], 'early_ready':str(tmp_path/'early'),
'release_gate':str(tmp_path/'absent-gate'), 'gate_token':'exact-generated-gate'}
path = tmp_path/'spec.json'; path.write_text(json.dumps(data))
monkeypatch.setattr(life.p, 'identity', lambda _: [1,2])
monkeypatch.setattr(life.p, 'namespaces', lambda: {'user':'new-user','mnt':'new-mnt','net':'new-net','pid':'same-pid'})
monkeypatch.setattr(life.p, 'sha', lambda _: 'interpreter')
monkeypatch.setattr(life.p, 'check_null', lambda _: {'read_write_open_verified':True})
clock = [0]
monkeypatch.setattr(life.time, 'monotonic', lambda: clock[0])
monkeypatch.setattr(life.time, 'sleep', lambda _: clock.__setitem__(0, 9))
monkeypatch.setattr(life, 'adapter', lambda: pytest.fail('source storage must wait for registered creator release'))
assert life.inner(path) == 25
assert json.loads((tmp_path/'early').read_text())['namespace_identity_verified'] is True
def test_public_phase_never_copies_arbitrary_exception_message(tmp_path, monkeypatch):
spec = importlib.util.spec_from_file_location('namespace_lifecycle_diagnostics', Path(__file__).with_name('probe_namespace_lifecycle.py'))
life = importlib.util.module_from_spec(spec); spec.loader.exec_module(life)
path=tmp_path/'spec.json'; phase=tmp_path/'phase.json'
path.write_text(json.dumps({'phase_readback':str(phase)}))
def fail(_):
raise ValueError('unreviewed synthetic exception payload')
monkeypatch.setattr(life, 'inner_body', fail)
assert life.inner(path)==26
recorded=phase.read_text()
assert 'unreviewed synthetic exception payload' not in recorded
assert json.loads(recorded)=={'phase':'inner-exception','last_successful_phase':'inner-started','exception_type':'ValueError','errno':None}
def test_only_null_device_is_exposed_as_device_bind():
args=profile()
mounts=[args[i+1:i+3] for i,arg in enumerate(args) if arg=='--dev-bind']
assert mounts==[['/dev/null','/dev/null']]
def test_wrong_null_identity_refuses_before_open(monkeypatch):
monkeypatch.setattr(probe,'null_identity',lambda:[1,2,3,True])
monkeypatch.setattr(probe.os,'open',lambda *args: pytest.fail('mismatched device must not open'))
with pytest.raises(probe.Refused,match='null-device-identity-refused'):
probe.check_null([1,2,4,True])

View file

@ -0,0 +1,57 @@
{
"owner": "secrets-engine",
"exit_code": 0,
"stdout": "[main c59bbf5] feat(recovery): prepare owner-bound offline continuity preflight\n 5 files changed, 248 insertions(+)\n create mode 100644 docs/keycape-isolated-recovery-selector.md\n create mode 100644 docs/keycape-recovery-selector.json\n create mode 100644 tests/test_keycape_recovery_selector.py\n create mode 100644 tools/check-keycape-recovery-selector.py\n create mode 100644 workplans/SECRETS-WP-0015-original-keycape-recovery-selector.md\n",
"stderr": "{\"blocked_blob_ids\": [], \"scanned_blobs\": 5, \"scanner_sha256\": \"88f91962aa2f93ac6ab281d553b9e125f5197bbbce38f9f2437f7299c32e5509\", \"scanner_version\": \"8.30.1\", \"scope\": \"changed-staged-blobs\", \"status\": \"clean\"}\n",
"head": "c59bbf568c0be8a72ac593508f48c9b1f61ec4c1",
"files": {
"tools/check-keycape-recovery-selector.py": "sha256:e3e5e3ee743a212247701d6cb40fcf5b7f19349126fa9b32cbef9a3cc9459150",
"tests/test_keycape_recovery_selector.py": "sha256:221112ba303c58bc4205b577359ca90d8a6f60d09eb0b538990b1e53a156e262",
"docs/keycape-isolated-recovery-selector.md": "sha256:ed23b0df3d4b49e4b76df795455153c805971ccd37886836c960f550709e0739",
"docs/keycape-recovery-selector.json": "sha256:02077af3c18b24f5e4a85992a3d4d0df51a8e458de1e48b48f7eb5f482257012",
"workplans/SECRETS-WP-0015-original-keycape-recovery-selector.md": "sha256:b3cab4e8d14b3b03179fc72a6e9ce1c0ee840cfa3247c022c1324d60378bde5b"
},
"managed_identifier_assignments": {
"schema": "repo-manager.identifier-assignment.v1",
"ok": true,
"executed": true,
"repo": "secrets-engine",
"namespace": "helixforge",
"assignments": [
{
"kind": "workplan",
"record_id": "SECRETS-WP-0015",
"uuid": "68a0642e-4908-5260-89c9-3adce60e6a4d",
"path": "workplans/SECRETS-WP-0015-original-keycape-recovery-selector.md"
},
{
"kind": "task",
"record_id": "SECRETS-WP-0015-T01",
"uuid": "a3e0e243-edac-5ade-a3d5-f58dac41633a",
"path": "workplans/SECRETS-WP-0015-original-keycape-recovery-selector.md"
},
{
"kind": "task",
"record_id": "SECRETS-WP-0015-T02",
"uuid": "eab3b758-10ce-5464-b5f7-3a152ee1327a",
"path": "workplans/SECRETS-WP-0015-original-keycape-recovery-selector.md"
},
{
"kind": "task",
"record_id": "SECRETS-WP-0015-T03",
"uuid": "6262a915-7655-50be-b9f7-481f816d7335",
"path": "workplans/SECRETS-WP-0015-original-keycape-recovery-selector.md"
},
{
"kind": "task",
"record_id": "SECRETS-WP-0015-T04",
"uuid": "aeec6eb0-39e2-5f7c-8f5d-778133edfc73",
"path": "workplans/SECRETS-WP-0015-original-keycape-recovery-selector.md"
}
],
"historical_invalid_identifiers": [],
"files_changed": [
"workplans/SECRETS-WP-0015-original-keycape-recovery-selector.md"
]
}
}

View file

@ -0,0 +1,87 @@
{
"repo_slug": "secrets-engine",
"repo_path": "/home/worsch/secrets-engine",
"source_revision": "c59bbf568c0be8a72ac593508f48c9b1f61ec4c1",
"source_revision_reason": null,
"issues": [
{
"severity": "WARN",
"check_id": "C-33",
"message": "WORK-RECORDS.md is missing or stale \u2014 regenerate via fix-consistency (CUST-WP-0061-T04 generated work-record index)",
"file_path": "WORK-RECORDS.md",
"db_id": "",
"file_value": "",
"db_value": "",
"fixable": true
},
{
"severity": "WARN",
"check_id": "C-23",
"message": "Lifecycle drift in 'secrets-wp-0013': workplan status 'proposed' has an active task \u2014 report only (ADR-007: do not auto-promote proposed)",
"file_path": "workplans/SECRETS-WP-0013-task-scoped-openbao-execution.md",
"db_id": "5e38aecc-85ca-5f55-94c6-9fbb08604819",
"file_value": "proposed",
"db_value": "active",
"fixable": false
},
{
"severity": "WARN",
"check_id": "C-06",
"message": "Authoritative workplan 68a0642e\u2026 is absent from this projection",
"file_path": "workplans/SECRETS-WP-0015-original-keycape-recovery-selector.md",
"db_id": "68a0642e-4908-5260-89c9-3adce60e6a4d",
"file_value": "",
"db_value": "",
"fixable": true
},
{
"severity": "INFO",
"check_id": "C-08",
"message": "Closed DB workstream 'secrets-wp-0002' (id=7929a2d1\u2026, status=finished) has no backing workplan file",
"file_path": "",
"db_id": "7929a2d1-3006-5d4b-85e4-c62da055ee9b",
"file_value": "",
"db_value": "",
"fixable": false
},
{
"severity": "WARN",
"check_id": "C-28",
"message": "3 unread inbox message(s) older than 3 day(s): railiance-platform:0490edcb, the-custodian:23172cb2, the-custodian:51e9eace",
"file_path": "",
"db_id": "",
"file_value": "",
"db_value": "",
"fixable": false
},
{
"severity": "WARN",
"check_id": "C-28",
"message": "2 unread message(s) lack thread_id for supersession tracking: the-custodian:23172cb2, the-custodian:51e9eace",
"file_path": "",
"db_id": "",
"file_value": "",
"db_value": "",
"fixable": false
}
],
"fixes_applied": [
"bindings: synced 16/17",
"C-17 cleared: pushed 1 backlogged commit(s)",
"C-33 fixed: regenerated WORK-RECORDS.md",
"C-06 fixed: created workstream 68a0642e\u2026 for SECRETS-WP-0015, wrote ID to SECRETS-WP-0015-original-keycape-recovery-selector.md",
" + task SECRETS-WP-0015-T01 \u2192 a3e0e243\u2026",
" + task SECRETS-WP-0015-T02 \u2192 eab3b758\u2026",
" + task SECRETS-WP-0015-T03 \u2192 6262a915\u2026",
" + task SECRETS-WP-0015-T04 \u2192 aeec6eb0\u2026",
"brief: .custodian-brief.md updated",
"push: pushed"
],
"summary": {
"fail": 0,
"automation_error": 0,
"warn": 5,
"info": 1
},
"result": "warn"
}

View file

@ -0,0 +1 @@
WARN: git commit failed for writeback: Generated-only commits rejected: staged

View file

@ -0,0 +1,67 @@
<!-- custodian-brief: generated by fix-consistency — do not edit manually -->
# Custodian Brief — secrets-engine
**Domain:** infotech
**Last synced:** 2026-10-16 19:07 UTC
**State Hub:** http://127.0.0.1:8000 *(adjust if running on a remote machine)*
## Active Workstreams
### Design and prove task-scoped protected OpenBao execution
Progress: 1/3 done | workplan_id: `5e38aecc-85ca-5f55-94c6-9fbb08604819`
**Open tasks:**
- ! Define the exact mediated execution contract `b2f0d462`
*(wait: Independent Platform mediated-contract review and identity/approval/PDP owner returns remain required; D3 wrapped primitive source is implemented, no native entitlement is inferred.)*
- ! Implement and prove one native metadata action `5f8f7c41`
### Constrain PDP transport and authenticate decision responses
Progress: 1/3 done | workplan_id: `7252469d-d7a5-5c18-8911-b511b8c6a736`
**Open tasks:**
- ! Verify the admitted native consumer and rotation path `85aa4c78`
*(wait: Requires reviewed verification-key admission, source enforcement and exact native rollout receipt; no production trust change is proposed yet.)*
- ► Implement independently anchored responder authentication `877782e5`
### Activate native Claude credential delivery for Glas
Progress: 2/3 done | workplan_id: `40ccc3b4-d046-5a58-8649-e7935f45c974`
**Open tasks:**
- ! Activate the approved native lane and verify real owner delivery `f8069c8a`
*(wait: Next owner action: reconcile held parent reservation 6efa9436-6a91-47c0-94e5-b31b5a0e7e3a (EUR 10, observed USD still null) from existing provider records. No corrected runtime digest is admitted; do not retry or replay consumed approvals.)*
### Adopt concrete OpenBao credential lanes from ops-warden
Progress: 4/6 done | workplan_id: `31f7f8ea-7f73-516c-8877-f03a13f1db82`
**Open tasks:**
- ! Stage live apply and verification `fb103f1e`
*(wait: Owner work first: publish a reviewed scoped-apply command per lane. Per-lane approvals are no longer needed (D1 standing rule); each lane with a command enters the attended window.)*
- ! Reconcile routing ownership and retire interim proxies `1431edae`
*(wait: Needs owner-agreed routing/proxy retirement for each verified lane and custody disposition of the legacy npm pointer; a single approved OpenRouter key-check does not authorize broader routing cutover.)*
### Evolve the Lifecycle engine to the accepted security layer model
Progress: 5/6 done | workplan_id: `9c9e5164-b2f5-5ea2-a557-5368d65e9fe0`
**Open tasks:**
- ! No standing engine credential `d7bc8bdc`
*(wait: Published JWT contract and positive login/revocation are delivered. Native KEY-WP-0039-T02 claim negatives, CCR-2026-0038 effective-policy/capability/expiry/use checks and MASON-WP-0009-T05 remain. Login-self-only grants no protected-operation authority: agree and implement separately reviewed task-scoped backend execution entitlement, then prove functional steady-state service-identity adoption without bootstrap/env fallback.)*
### Production-safe provisioning, authorization, and lifecycle hardening
Progress: 6/7 done | workplan_id: `68a39be1-bd9c-5133-ad64-e7bca892aaf3`
**Open tasks:**
- ! Resume native production lane adoption `a0a1dd92`
*(wait: Engine approval hardening is complete. Remaining per-lane cutover includes native routing/proxy retirement with ops-warden under SECRETS-WP-0006-T05/T06; the exact OpenRouter key-check receipt does not establish broader recipient readiness.)*
## Inbox Hygiene
**Stale unread:** 3 message(s) older than 3 day(s) — triage at session start.
**Missing thread_id:** 2 unread message(s) lack supersession chains.
---
## MCP Orientation (when available)
If the state-hub MCP server is reachable, call:
`get_domain_summary("infotech")`
This provides richer cross-domain context.
If the MCP call fails, use this file as your orientation source.

View file

@ -0,0 +1,95 @@
# Work Records — secrets-engine
> Generated by `statehub fix-consistency` (CUST-WP-0061-T04, work-record
> stage 3). Do not edit by hand — edit the source file/block listed for
> each record and re-run fix-consistency to refresh this index. Archived
> workplans are omitted; closed decisions/intakes/engagements stay listed
> so recently-resolved work is still visible. [auto]
| Kind | ID | Status | Lane | Source |
| --- | --- | --- | --- | --- |
| workplan | SECRETS-WP-ADHOC-2026-08-21 | finished | — | workplans/ADHOC-2026-08-21.md |
| workplan | SECRETS-WP-ADHOC-2026-08-23 | finished | — | workplans/ADHOC-2026-08-23.md |
| workplan | SECRETS-WP-0001 | finished | — | workplans/SECRETS-WP-0001-statehub-bootstrap.md |
| workplan | SECRETS-WP-0002 | finished | — | workplans/SECRETS-WP-0002-bootstrap.md |
| workplan | SECRETS-WP-0004 | finished | — | workplans/SECRETS-WP-0004-warden-sign-token-lane.md |
| workplan | SECRETS-WP-0005 | finished | — | workplans/SECRETS-WP-0005-scope-intent-value-gaps.md |
| workplan | SECRETS-WP-0006 | blocked | — | workplans/SECRETS-WP-0006-catalog-lane-adoption.md |
| workplan | SECRETS-WP-0007 | blocked | — | workplans/SECRETS-WP-0007-production-lifecycle-hardening.md |
| workplan | SECRETS-WP-0008 | blocked | — | workplans/SECRETS-WP-0008-layer-model-lifecycle-conformance.md |
| workplan | SECRETS-WP-0009 | blocked | — | workplans/SECRETS-WP-0009-glas-claude-native-delivery.md |
| workplan | SECRETS-WP-0010 | finished | — | workplans/SECRETS-WP-0010-openrouter-native-access.md |
| workplan | SECRETS-WP-0011 | finished | — | workplans/SECRETS-WP-0011-multi-lane-exec-owner-delivery.md |
| workplan | SECRETS-WP-0012 | finished | — | workplans/SECRETS-WP-0012-keycape-openbao-consumer-custody.md |
| workplan | SECRETS-WP-0013 | proposed | — | workplans/SECRETS-WP-0013-task-scoped-openbao-execution.md |
| workplan | SECRETS-WP-0014 | active | — | workplans/SECRETS-WP-0014-pdp-transport-and-responder-authentication.md |
| task | SECRETS-WP-ADHOC-2026-08-21-T01 | done | — | workplans/ADHOC-2026-08-21.md |
| task | SECRETS-WP-ADHOC-2026-08-23-T01 | done | — | workplans/ADHOC-2026-08-23.md |
| task | SECRETS-WP-0001-T01 | done | — | workplans/SECRETS-WP-0001-statehub-bootstrap.md |
| task | SECRETS-WP-0001-T02 | done | — | workplans/SECRETS-WP-0001-statehub-bootstrap.md |
| task | SECRETS-WP-0001-T03 | done | — | workplans/SECRETS-WP-0001-statehub-bootstrap.md |
| task | SECRETS-WP-0002-T01 | done | — | workplans/SECRETS-WP-0002-bootstrap.md |
| task | SECRETS-WP-0002-T02 | done | — | workplans/SECRETS-WP-0002-bootstrap.md |
| task | SECRETS-WP-0002-T03 | done | — | workplans/SECRETS-WP-0002-bootstrap.md |
| task | SECRETS-WP-0002-T04 | done | — | workplans/SECRETS-WP-0002-bootstrap.md |
| task | SECRETS-WP-0002-T05 | done | — | workplans/SECRETS-WP-0002-bootstrap.md |
| task | SECRETS-WP-0002-T06 | done | — | workplans/SECRETS-WP-0002-bootstrap.md |
| task | SECRETS-WP-0002-T07 | done | — | workplans/SECRETS-WP-0002-bootstrap.md |
| task | SECRETS-WP-0002-T08 | done | — | workplans/SECRETS-WP-0002-bootstrap.md |
| task | SECRETS-WP-0002-T09 | done | — | workplans/SECRETS-WP-0002-bootstrap.md |
| task | SECRETS-WP-0002-T10 | done | — | workplans/SECRETS-WP-0002-bootstrap.md |
| task | SECRETS-WP-0004-T01 | done | — | workplans/SECRETS-WP-0004-warden-sign-token-lane.md |
| task | SECRETS-WP-0004-T02 | done | — | workplans/SECRETS-WP-0004-warden-sign-token-lane.md |
| task | SECRETS-WP-0004-T03 | done | — | workplans/SECRETS-WP-0004-warden-sign-token-lane.md |
| task | SECRETS-WP-0004-T04 | done | — | workplans/SECRETS-WP-0004-warden-sign-token-lane.md |
| task | SECRETS-WP-0004-T05 | done | — | workplans/SECRETS-WP-0004-warden-sign-token-lane.md |
| task | SECRETS-WP-0005-T01 | done | — | workplans/SECRETS-WP-0005-scope-intent-value-gaps.md |
| task | SECRETS-WP-0005-T02 | done | — | workplans/SECRETS-WP-0005-scope-intent-value-gaps.md |
| task | SECRETS-WP-0005-T03 | done | — | workplans/SECRETS-WP-0005-scope-intent-value-gaps.md |
| task | SECRETS-WP-0005-T04 | done | — | workplans/SECRETS-WP-0005-scope-intent-value-gaps.md |
| task | SECRETS-WP-0005-T05 | done | — | workplans/SECRETS-WP-0005-scope-intent-value-gaps.md |
| task | SECRETS-WP-0005-T06 | done | — | workplans/SECRETS-WP-0005-scope-intent-value-gaps.md |
| task | SECRETS-WP-0005-T07 | done | — | workplans/SECRETS-WP-0005-scope-intent-value-gaps.md |
| task | SECRETS-WP-0006-T01 | done | — | workplans/SECRETS-WP-0006-catalog-lane-adoption.md |
| task | SECRETS-WP-0006-T02 | done | — | workplans/SECRETS-WP-0006-catalog-lane-adoption.md |
| task | SECRETS-WP-0006-T03 | done | — | workplans/SECRETS-WP-0006-catalog-lane-adoption.md |
| task | SECRETS-WP-0006-T04 | done | — | workplans/SECRETS-WP-0006-catalog-lane-adoption.md |
| task | SECRETS-WP-0006-T05 | wait | — | workplans/SECRETS-WP-0006-catalog-lane-adoption.md |
| task | SECRETS-WP-0006-T06 | wait | — | workplans/SECRETS-WP-0006-catalog-lane-adoption.md |
| task | SECRETS-WP-0007-T01 | done | — | workplans/SECRETS-WP-0007-production-lifecycle-hardening.md |
| task | SECRETS-WP-0007-T02 | done | — | workplans/SECRETS-WP-0007-production-lifecycle-hardening.md |
| task | SECRETS-WP-0007-T03 | done | — | workplans/SECRETS-WP-0007-production-lifecycle-hardening.md |
| task | SECRETS-WP-0007-T04 | done | — | workplans/SECRETS-WP-0007-production-lifecycle-hardening.md |
| task | SECRETS-WP-0007-T05 | done | — | workplans/SECRETS-WP-0007-production-lifecycle-hardening.md |
| task | SECRETS-WP-0007-T06 | done | — | workplans/SECRETS-WP-0007-production-lifecycle-hardening.md |
| task | SECRETS-WP-0007-T07 | wait | — | workplans/SECRETS-WP-0007-production-lifecycle-hardening.md |
| task | SECRETS-WP-0008-T01 | done | — | workplans/SECRETS-WP-0008-layer-model-lifecycle-conformance.md |
| task | SECRETS-WP-0008-T02 | done | — | workplans/SECRETS-WP-0008-layer-model-lifecycle-conformance.md |
| task | SECRETS-WP-0008-T03 | done | — | workplans/SECRETS-WP-0008-layer-model-lifecycle-conformance.md |
| task | SECRETS-WP-0008-T04 | done | — | workplans/SECRETS-WP-0008-layer-model-lifecycle-conformance.md |
| task | SECRETS-WP-0008-T05 | done | — | workplans/SECRETS-WP-0008-layer-model-lifecycle-conformance.md |
| task | SECRETS-WP-0008-T06 | wait | — | workplans/SECRETS-WP-0008-layer-model-lifecycle-conformance.md |
| task | SECRETS-WP-0009-T01 | done | — | workplans/SECRETS-WP-0009-glas-claude-native-delivery.md |
| task | SECRETS-WP-0009-T02 | done | — | workplans/SECRETS-WP-0009-glas-claude-native-delivery.md |
| task | SECRETS-WP-0009-T03 | wait | — | workplans/SECRETS-WP-0009-glas-claude-native-delivery.md |
| task | SECRETS-WP-0010-T01 | done | — | workplans/SECRETS-WP-0010-openrouter-native-access.md |
| task | SECRETS-WP-0010-T02 | done | — | workplans/SECRETS-WP-0010-openrouter-native-access.md |
| task | SECRETS-WP-0010-T03 | done | — | workplans/SECRETS-WP-0010-openrouter-native-access.md |
| task | SECRETS-WP-0011-T01 | done | — | workplans/SECRETS-WP-0011-multi-lane-exec-owner-delivery.md |
| task | SECRETS-WP-0011-T02 | done | — | workplans/SECRETS-WP-0011-multi-lane-exec-owner-delivery.md |
| task | SECRETS-WP-0011-T03 | done | — | workplans/SECRETS-WP-0011-multi-lane-exec-owner-delivery.md |
| task | SECRETS-WP-0011-T04 | done | — | workplans/SECRETS-WP-0011-multi-lane-exec-owner-delivery.md |
| task | SECRETS-WP-0011-T05 | done | — | workplans/SECRETS-WP-0011-multi-lane-exec-owner-delivery.md |
| task | SECRETS-WP-0012-T01 | done | — | workplans/SECRETS-WP-0012-keycape-openbao-consumer-custody.md |
| task | SECRETS-WP-0012-T02 | cancel | — | workplans/SECRETS-WP-0012-keycape-openbao-consumer-custody.md |
| task | SECRETS-WP-0012-T03 | done | — | workplans/SECRETS-WP-0012-keycape-openbao-consumer-custody.md |
| task | SECRETS-WP-0012-T04 | done | — | workplans/SECRETS-WP-0012-keycape-openbao-consumer-custody.md |
| task | SECRETS-WP-0013-T01 | wait | — | workplans/SECRETS-WP-0013-task-scoped-openbao-execution.md |
| task | SECRETS-WP-0013-T02 | done | — | workplans/SECRETS-WP-0013-task-scoped-openbao-execution.md |
| task | SECRETS-WP-0013-T03 | wait | — | workplans/SECRETS-WP-0013-task-scoped-openbao-execution.md |
| task | SECRETS-WP-0014-T01 | done | — | workplans/SECRETS-WP-0014-pdp-transport-and-responder-authentication.md |
| task | SECRETS-WP-0014-T02 | progress | — | workplans/SECRETS-WP-0014-pdp-transport-and-responder-authentication.md |
| task | SECRETS-WP-0014-T03 | wait | — | workplans/SECRETS-WP-0014-pdp-transport-and-responder-authentication.md |
| intake | SECRETS-IN-0001 | closed | — | intakes/intakes.md |
| intake | SECRETS-IN-0002 | closed | — | intakes/intakes.md |
| intake | SECRETS-IN-0003 | closed | — | intakes/intakes.md |

View file

@ -0,0 +1 @@
{".custodian-brief.md": "100644 f5952182bbfde84b60c85c4155da8c65f12ba0ab 0\t.custodian-brief.md\n", "WORK-RECORDS.md": "100644 70e5831d75b067c0d05efa3fab37a76a029cf9e9 0\tWORK-RECORDS.md\n"}

View file

@ -0,0 +1,14 @@
{
"owner": "secrets-engine",
"base_revision": "535681052cd55ca613706ecc60c39d299929b3c5",
"applied": true,
"files": {
"tools/check-keycape-recovery-selector.py": "sha256:e3e5e3ee743a212247701d6cb40fcf5b7f19349126fa9b32cbef9a3cc9459150",
"tests/test_keycape_recovery_selector.py": "sha256:221112ba303c58bc4205b577359ca90d8a6f60d09eb0b538990b1e53a156e262",
"docs/keycape-isolated-recovery-selector.md": "sha256:ed23b0df3d4b49e4b76df795455153c805971ccd37886836c960f550709e0739",
"docs/keycape-recovery-selector.json": "sha256:02077af3c18b24f5e4a85992a3d4d0df51a8e458de1e48b48f7eb5f482257012",
"workplans/SECRETS-WP-0015-original-keycape-recovery-selector.md": "sha256:22b148f0f403b8a9d471f34b2fae6938066123203d5c6f21ad463c5c262705c5"
},
"preexisting_brief_preserved": true,
"native_acceptance": false
}

View file

@ -0,0 +1,20 @@
{
"owner_base": "6cb43c0cc55212363a5406b02db046e2384a7c40",
"files": [
{
"path": "tests/test_sops_private.py",
"before_sha256": "sha256:b29c3759aacf7ab31b8a7909fe947b05b0ae5fe2acea88a5dac7e996101cb354",
"after_sha256": "sha256:a5ff8d7847cdce151be44cdf4a89385d5e2585cdd59143dee4be3cc6106eb7f5"
},
{
"path": "tests/test_sops_write.py",
"before_sha256": "sha256:3d4b26080c9a6328caaf82072363d40d27b2c96b07c441c7922c164f29fcfbd9",
"after_sha256": "sha256:f832925283e79589b3ce0bded7e50f49bfd4e78620c224549bb7d31a7868fca6"
}
],
"patch_sha256": "sha256:1ee771f243408c1d4f7472bd59af89e8cd73e4aec47bc25471269b804ce22888",
"real_sops_generated_crypto_tests": 65,
"new_end_to_end_fd_cases": 4,
"all_previously_skipped_real_sops_cases_now_run": 61,
"production_runtime_admitted": false
}

View file

@ -0,0 +1,82 @@
--- a/tests/test_sops_private.py
+++ b/tests/test_sops_private.py
@@ -10,6 +10,40 @@
ROOT = Path(__file__).resolve().parents[1]
SOPS = shutil.which('sops')
pytestmark = pytest.mark.skipif(SOPS is None, reason='SOPS required for real crypto regression')
+
+
+@pytest.mark.parametrize('wrong_recipient', [False, True])
+def test_real_sops_decrypt_with_only_sealed_descriptor(case, wrong_recipient):
+ import fcntl
+ original = case[1].read_bytes()
+ material = (subprocess.run(['age-keygen'], capture_output=True, check=True).stdout
+ if wrong_recipient else original)
+ fd = os.memfd_create('generated-sops-custody', os.MFD_ALLOW_SEALING)
+ try:
+ os.fchmod(fd, 0o600); os.write(fd, material); os.lseek(fd, 0, os.SEEK_SET)
+ fcntl.fcntl(fd, fcntl.F_ADD_SEALS,
+ fcntl.F_SEAL_WRITE | fcntl.F_SEAL_GROW | fcntl.F_SEAL_SHRINK | fcntl.F_SEAL_SEAL)
+ case[1].unlink()
+ env = {**case[2], 'NETKINGDOM_CUSTODY_AGE_KEY_FD': str(fd)}
+ env.pop('NETKINGDOM_CUSTODY_AGE_KEY_FILE')
+ if wrong_recipient:
+ # A correct ambient key must never rescue the wrong explicit FD.
+ env['SOPS_AGE_KEY'] = original.decode()
+ result = subprocess.run(['make', '-s', 'sops-decrypt', 'FILE=' + str(case[3]),
+ 'OUTPUT=' + str(case[4])], cwd=case[0], env=env,
+ pass_fds=(fd,), capture_output=True, text=True, timeout=15)
+ assert not case[1].exists()
+ assert 'synthetic-secret-payload' not in result.stdout + result.stderr
+ if wrong_recipient:
+ assert result.returncode != 0
+ assert not case[4].exists()
+ else:
+ assert result.returncode == 0
+ assert json.loads(case[4].read_text()) == {'credential': 'synthetic-secret-payload'}
+ assert case[4].stat().st_mode & 0o077 == 0
+ assert not list(case[4].parent.glob('.netkingdom-sops-*'))
+ finally:
+ os.close(fd)
@pytest.fixture
--- a/tests/test_sops_write.py
+++ b/tests/test_sops_write.py
@@ -11,6 +11,36 @@
SOPS=shutil.which('sops')
pytestmark=pytest.mark.skipif(SOPS is None,reason='real SOPS required')
PLAIN='synthetic-sops-write-value'
+
+
+@pytest.mark.parametrize('action', ['rotate', 'edit'])
+def test_real_sops_write_with_only_sealed_descriptor(case, action):
+ import fcntl
+ fd = os.memfd_create('generated-sops-write-custody', os.MFD_ALLOW_SEALING)
+ try:
+ os.fchmod(fd, 0o600); os.write(fd, case['key'].read_bytes()); os.lseek(fd, 0, os.SEEK_SET)
+ fcntl.fcntl(fd, fcntl.F_ADD_SEALS,
+ fcntl.F_SEAL_WRITE | fcntl.F_SEAL_GROW | fcntl.F_SEAL_SHRINK | fcntl.F_SEAL_SEAL)
+ case['key'].unlink()
+ env = {**case['env'], 'NETKINGDOM_CUSTODY_AGE_KEY_FD': str(fd)}
+ env.pop('NETKINGDOM_CUSTODY_AGE_KEY_FILE'); env.pop('SOPS_AGE_KEY_FILE')
+ before = case['cipher'].read_bytes()
+ result = subprocess.run(['make', '-s', 'sops-' + action,
+ 'FILE=' + str(case['cipher']), 'INPUT=' + str(case['input'])],
+ cwd=case['repo'], env=env, pass_fds=(fd,),
+ capture_output=True, text=True, timeout=15)
+ assert result.returncode == 0
+ assert PLAIN not in result.stdout + result.stderr
+ assert not case['key'].exists()
+ assert before != case['cipher'].read_bytes()
+ clear = subprocess.run([SOPS, '--decrypt', str(case['cipher'])],
+ env={**env, 'SOPS_AGE_KEY_FILE': '/proc/self/fd/' + str(fd)},
+ pass_fds=(fd,), capture_output=True, check=True)
+ assert json.loads(clear.stdout) == {'credential': PLAIN + ('-edited' if action == 'edit' else '')}
+ assert case['cipher'].stat().st_mode & 0o077 == 0
+ assert not list(case['cipher'].parent.glob('.netkingdom-sops-write-*'))
+ finally:
+ os.close(fd)
@pytest.fixture

View file

@ -0,0 +1,11 @@
{
"owner": "net-kingdom",
"base_revision": "6cb43c0cc55212363a5406b02db046e2384a7c40",
"applied": true,
"files": {
"tests/test_sops_private.py": "sha256:a5ff8d7847cdce151be44cdf4a89385d5e2585cdd59143dee4be3cc6106eb7f5",
"tests/test_sops_write.py": "sha256:f832925283e79589b3ce0bded7e50f49bfd4e78620c224549bb7d31a7868fca6"
},
"preexisting_brief_preserved": true,
"native_acceptance": false
}

View file

@ -0,0 +1,12 @@
{
"owner": "net-kingdom",
"base_revision": "6cb43c0cc55212363a5406b02db046e2384a7c40",
"patch_sha256": "5364b1966334869c71a58ff2d90194db45c7ea6f3e60d57327a231f558437641",
"files": {
"workplans/NK-WP-0049-bootstrap-secret-free-recovery-handoff.md": "95dfb5a264ba179aba4aeddb602039a098af5c33c893a509d31f3631d39b7046"
},
"index_unchanged": true,
"production_mutation": false,
"registrar_enabled": false,
"status": "applied_source_only"
}

View file

@ -0,0 +1,858 @@
[
{
"path": "docs/changes/netkingdom-target-2026-10-17/key39-infra-finalization-r1/finalization-recheck-progress.json",
"bytes": 973
},
{
"path": "docs/changes/netkingdom-target-2026-10-17/key39-infra-finalization-r1/finalization-recheck.json",
"bytes": 6768
},
{
"path": "docs/changes/netkingdom-target-2026-10-17/nk48-catalog-fixture-publication-r1/apply_prepare.py",
"bytes": 5464
},
{
"path": "docs/changes/netkingdom-target-2026-10-17/nk48-catalog-fixture-publication-r1/candidate.patch",
"bytes": 10999
},
{
"path": "docs/changes/netkingdom-target-2026-10-17/nk48-catalog-fixture-publication-r1/preparation.json",
"bytes": 3554
},
{
"path": "docs/changes/netkingdom-target-2026-10-17/nk48-catalog-fixture-publication-r1/publication-inputs.json",
"bytes": 16672
},
{
"path": "docs/changes/netkingdom-target-2026-10-17/nk48-catalog-fixture-publication-r1/run_validation.py",
"bytes": 4070
},
{
"path": "docs/changes/netkingdom-target-2026-10-17/nk48-catalog-fixture-publication-r1/task-T35.md",
"bytes": 2187
},
{
"path": "docs/changes/netkingdom-target-2026-10-17/nk48-catalog-fixture-publication-r1/validation-child.py",
"bytes": 2119
},
{
"path": "docs/changes/netkingdom-target-2026-10-17/nk48-catalog-fixture-publication-r1/validation-guard.py",
"bytes": 1737
},
{
"path": "docs/changes/netkingdom-target-2026-10-17/nk48-catalog-fixture-publication-r1/workplan.candidate.md",
"bytes": 95774
},
{
"path": "docs/changes/netkingdom-target-2026-10-17/nk48-catalog-fixture-publication-r1/workplan.preimage.md",
"bytes": 93587
},
{
"path": "docs/changes/netkingdom-target-2026-10-17/nk48-catalog-fixture-publication-r2/apply_prepare.py",
"bytes": 5464
},
{
"path": "docs/changes/netkingdom-target-2026-10-17/nk48-catalog-fixture-publication-r2/candidate.patch",
"bytes": 10999
},
{
"path": "docs/changes/netkingdom-target-2026-10-17/nk48-catalog-fixture-publication-r2/canonical-validation.json",
"bytes": 637
},
{
"path": "docs/changes/netkingdom-target-2026-10-17/nk48-catalog-fixture-publication-r2/identifier-assignment.json",
"bytes": 509
},
{
"path": "docs/changes/netkingdom-target-2026-10-17/nk48-catalog-fixture-publication-r2/identifier-preview.json",
"bytes": 510
},
{
"path": "docs/changes/netkingdom-target-2026-10-17/nk48-catalog-fixture-publication-r2/preparation.json",
"bytes": 3554
},
{
"path": "docs/changes/netkingdom-target-2026-10-17/nk48-catalog-fixture-publication-r2/publication-inputs.allocated.json",
"bytes": 841
},
{
"path": "docs/changes/netkingdom-target-2026-10-17/nk48-catalog-fixture-publication-r2/publication-inputs.json",
"bytes": 16672
},
{
"path": "docs/changes/netkingdom-target-2026-10-17/nk48-catalog-fixture-publication-r2/revision-refresh.json",
"bytes": 535
},
{
"path": "docs/changes/netkingdom-target-2026-10-17/nk48-catalog-fixture-publication-r2/run_validation.py",
"bytes": 4070
},
{
"path": "docs/changes/netkingdom-target-2026-10-17/nk48-catalog-fixture-publication-r2/task-T35.md",
"bytes": 2187
},
{
"path": "docs/changes/netkingdom-target-2026-10-17/nk48-catalog-fixture-publication-r2/validation-child.py",
"bytes": 2119
},
{
"path": "docs/changes/netkingdom-target-2026-10-17/nk48-catalog-fixture-publication-r2/validation-guard.py",
"bytes": 1737
},
{
"path": "docs/changes/netkingdom-target-2026-10-17/nk48-catalog-fixture-publication-r2/workplan.allocated.md",
"bytes": 95832
},
{
"path": "docs/changes/netkingdom-target-2026-10-17/nk48-catalog-fixture-publication-r2/workplan.candidate.md",
"bytes": 95774
},
{
"path": "docs/changes/netkingdom-target-2026-10-17/nk48-catalog-fixture-publication-r2/workplan.preimage.md",
"bytes": 93587
},
{
"path": "docs/changes/netkingdom-target-2026-10-17/nk48-catalog-fixture-update-r1/candidate.patch",
"bytes": 10999
},
{
"path": "docs/changes/netkingdom-target-2026-10-17/nk48-catalog-fixture-update-r1/edit.py",
"bytes": 5370
},
{
"path": "docs/changes/netkingdom-target-2026-10-17/nk48-catalog-fixture-update-r1/implementation-r1.json",
"bytes": 6352
},
{
"path": "docs/changes/netkingdom-target-2026-10-17/nk48-catalog-fixture-update-r1/run.py",
"bytes": 676
},
{
"path": "docs/changes/netkingdom-target-2026-10-17/nk48-catalog-fixture-update-r1/test_runner.py",
"bytes": 1279
},
{
"path": "docs/changes/netkingdom-target-2026-10-17/nk48-current-source-publication-r3/canonical-validation.json",
"bytes": 637
},
{
"path": "docs/changes/netkingdom-target-2026-10-17/nk48-current-source-publication-r3/consistency.json",
"bytes": 13229
},
{
"path": "docs/changes/netkingdom-target-2026-10-17/nk48-current-source-publication-r3/consistency.stderr.txt",
"bytes": 79
},
{
"path": "docs/changes/netkingdom-target-2026-10-17/nk48-current-source-publication-r3/projection.json",
"bytes": 36692
},
{
"path": "docs/changes/netkingdom-target-2026-10-17/nk48-current-source-publication-r3/projection.stderr.txt",
"bytes": 0
},
{
"path": "docs/changes/netkingdom-target-2026-10-17/nk48-current-source-publication-r3/publication-commit.json",
"bytes": 1450
},
{
"path": "docs/changes/netkingdom-target-2026-10-17/nk48-current-source-publication-r3/publication-inputs.final.json",
"bytes": 1023
},
{
"path": "docs/changes/netkingdom-target-2026-10-17/nk48-current-source-publication-r3/publication-inputs.json",
"bytes": 16672
},
{
"path": "docs/changes/netkingdom-target-2026-10-17/nk48-current-source-publication-r3/run_validation.py",
"bytes": 4070
},
{
"path": "docs/changes/netkingdom-target-2026-10-17/nk48-current-source-publication-r3/validation-child.py",
"bytes": 2119
},
{
"path": "docs/changes/netkingdom-target-2026-10-17/nk48-current-source-publication-r3/validation-guard.py",
"bytes": 1737
},
{
"path": "docs/changes/netkingdom-target-2026-10-17/nk48-current-source-publication-r3/validation-inputs-refresh.json",
"bytes": 572
},
{
"path": "docs/changes/netkingdom-target-2026-10-17/nk48-current-source-publication-r3/verified-task-bindings.json",
"bytes": 760
},
{
"path": "docs/changes/netkingdom-target-2026-10-17/nk48-issuer-reference-integration-r1/apply.py",
"bytes": 5250
},
{
"path": "docs/changes/netkingdom-target-2026-10-17/nk48-issuer-reference-integration-r1/composition-regenerated.json",
"bytes": 9331
},
{
"path": "docs/changes/netkingdom-target-2026-10-17/nk48-issuer-reference-integration-r1/initial-syntax-failure.py.txt",
"bytes": 6484
},
{
"path": "docs/changes/netkingdom-target-2026-10-17/nk48-issuer-reference-integration-r1/type.preimage.yaml",
"bytes": 24322
},
{
"path": "docs/changes/netkingdom-target-2026-10-17/nk48-issuer-reference-integration-r1/verification.json",
"bytes": 538
},
{
"path": "docs/changes/netkingdom-target-2026-10-17/nk48-issuer-reference-integration-r1/workplan.preimage.md",
"bytes": 95832
},
{
"path": "docs/changes/netkingdom-target-2026-10-17/nk48-r5-f1-implementation-r1/README.md",
"bytes": 2023
},
{
"path": "docs/changes/netkingdom-target-2026-10-17/nk48-r5-f1-implementation-r1/canonical-application.json",
"bytes": 364
},
{
"path": "docs/changes/netkingdom-target-2026-10-17/nk48-r5-f1-implementation-r1/canonical-net-kingdom-status-after.txt",
"bytes": 333
},
{
"path": "docs/changes/netkingdom-target-2026-10-17/nk48-r5-f1-implementation-r1/canonical-validation.json",
"bytes": 506
},
{
"path": "docs/changes/netkingdom-target-2026-10-17/nk48-r5-f1-implementation-r1/implementation.json",
"bytes": 4277
},
{
"path": "docs/changes/netkingdom-target-2026-10-17/nk48-r5-f1-implementation-r1/manifest.json",
"bytes": 1453
},
{
"path": "docs/changes/netkingdom-target-2026-10-17/nk48-r5-f1-implementation-r1/preimage-frozen.txt",
"bytes": 87
},
{
"path": "docs/changes/netkingdom-target-2026-10-17/nk48-r5-f1-implementation-r1/preimage-mutant.txt",
"bytes": 87
},
{
"path": "docs/changes/netkingdom-target-2026-10-17/nk48-r5-f1-implementation-r1/reproduce-scratch-checks.py",
"bytes": 2371
},
{
"path": "docs/changes/netkingdom-target-2026-10-17/nk48-r5-f1-implementation-r1/scratch-kernel-mutation.patch",
"bytes": 489
},
{
"path": "docs/changes/netkingdom-target-2026-10-17/nk48-r5-f1-implementation-r1/scratch.json",
"bytes": 238
},
{
"path": "docs/changes/netkingdom-target-2026-10-17/nk48-r5-f1-implementation-r1/successor-frozen.txt",
"bytes": 87
},
{
"path": "docs/changes/netkingdom-target-2026-10-17/nk48-r5-f1-implementation-r1/successor-mutant.txt",
"bytes": 1779
},
{
"path": "docs/changes/netkingdom-target-2026-10-17/nk48-r5-f1-implementation-r1/test-admit-1-3-agent-mint-coverage.patch",
"bytes": 4158
},
{
"path": "docs/changes/netkingdom-target-2026-10-17/nk48-r5-f1-implementation-r1/test-results.json",
"bytes": 2403
},
{
"path": "docs/changes/netkingdom-target-2026-10-17/nk48-r5-f1-implementation-r1/test_admit_1_3_type.after.py",
"bytes": 8901
},
{
"path": "docs/changes/netkingdom-target-2026-10-17/nk48-r5-f1-implementation-r1/test_admit_1_3_type.before.py",
"bytes": 7816
},
{
"path": "docs/changes/netkingdom-target-2026-10-17/nk48-r5-f2-implementation-r1/OWNER-REVIEW.md",
"bytes": 4737
},
{
"path": "docs/changes/netkingdom-target-2026-10-17/nk48-r5-f2-implementation-r1/canonical-source-readonly-state.json",
"bytes": 789
},
{
"path": "docs/changes/netkingdom-target-2026-10-17/nk48-r5-f2-implementation-r1/focused-tests.json",
"bytes": 336
},
{
"path": "docs/changes/netkingdom-target-2026-10-17/nk48-r5-f2-implementation-r1/focused-tests.txt",
"bytes": 1022
},
{
"path": "docs/changes/netkingdom-target-2026-10-17/nk48-r5-f2-implementation-r1/manifest.json",
"bytes": 1671
},
{
"path": "docs/changes/netkingdom-target-2026-10-17/nk48-r5-f2-implementation-r1/netkingdom-entry-point.conditional.patch",
"bytes": 1269
},
{
"path": "docs/changes/netkingdom-target-2026-10-17/nk48-r5-f2-implementation-r1/platform-candidate/docs/keycape-issuer-eso-contract.md",
"bytes": 4616
},
{
"path": "docs/changes/netkingdom-target-2026-10-17/nk48-r5-f2-implementation-r1/platform-candidate/manifests/templates/keycape-issuer-eso.yaml",
"bytes": 1315
},
{
"path": "docs/changes/netkingdom-target-2026-10-17/nk48-r5-f2-implementation-r1/platform-candidate/scripts/keycape_issuer_eso.py",
"bytes": 3138
},
{
"path": "docs/changes/netkingdom-target-2026-10-17/nk48-r5-f2-implementation-r1/platform-candidate/tests/test_keycape_issuer_eso.py",
"bytes": 6757
},
{
"path": "docs/changes/netkingdom-target-2026-10-17/nk48-r5-f2-implementation-r1/platform.candidate.patch",
"bytes": 16431
},
{
"path": "docs/changes/netkingdom-target-2026-10-17/nk48-r5-f2-implementation-r1/review.json",
"bytes": 3125
},
{
"path": "docs/changes/netkingdom-target-2026-10-17/nk48-r5-f2-implementation-r1/source-pins.json",
"bytes": 3123
},
{
"path": "docs/changes/netkingdom-target-2026-10-17/nk48-r5-f2-implementation-r1/structural-and-patch-checks.json",
"bytes": 281
},
{
"path": "docs/changes/netkingdom-target-2026-10-17/nk48-r5-f2-implementation-r1/type.before.yaml",
"bytes": 24322
},
{
"path": "docs/changes/netkingdom-target-2026-10-17/nk48-r5-f2-implementation-r1/type.candidate.yaml",
"bytes": 24585
},
{
"path": "docs/changes/netkingdom-target-2026-10-17/nk48-r5-f2-publication-r1/README.md",
"bytes": 2644
},
{
"path": "docs/changes/netkingdom-target-2026-10-17/nk48-r5-f2-publication-r1/canonical-validation.json",
"bytes": 331
},
{
"path": "docs/changes/netkingdom-target-2026-10-17/nk48-r5-f2-publication-r1/consistency.json",
"bytes": 24932
},
{
"path": "docs/changes/netkingdom-target-2026-10-17/nk48-r5-f2-publication-r1/consistency.stderr.txt",
"bytes": 0
},
{
"path": "docs/changes/netkingdom-target-2026-10-17/nk48-r5-f2-publication-r1/integrate_platform.py",
"bytes": 4127
},
{
"path": "docs/changes/netkingdom-target-2026-10-17/nk48-r5-f2-publication-r1/integration-checks.json",
"bytes": 2523
},
{
"path": "docs/changes/netkingdom-target-2026-10-17/nk48-r5-f2-publication-r1/manifest.json",
"bytes": 1512
},
{
"path": "docs/changes/netkingdom-target-2026-10-17/nk48-r5-f2-publication-r1/netkingdom-entry-point.conditional.patch",
"bytes": 1269
},
{
"path": "docs/changes/netkingdom-target-2026-10-17/nk48-r5-f2-publication-r1/packet-hashes.json",
"bytes": 1073
},
{
"path": "docs/changes/netkingdom-target-2026-10-17/nk48-r5-f2-publication-r1/platform-source/docs/keycape-issuer-eso-contract.md",
"bytes": 4616
},
{
"path": "docs/changes/netkingdom-target-2026-10-17/nk48-r5-f2-publication-r1/platform-source/manifests/templates/keycape-issuer-eso.yaml",
"bytes": 1315
},
{
"path": "docs/changes/netkingdom-target-2026-10-17/nk48-r5-f2-publication-r1/platform-source/scripts/keycape_issuer_eso.py",
"bytes": 3138
},
{
"path": "docs/changes/netkingdom-target-2026-10-17/nk48-r5-f2-publication-r1/platform-source/tests/test_keycape_issuer_eso.py",
"bytes": 6757
},
{
"path": "docs/changes/netkingdom-target-2026-10-17/nk48-r5-f2-publication-r1/progress-paragraph.md",
"bytes": 1360
},
{
"path": "docs/changes/netkingdom-target-2026-10-17/nk48-r5-f2-publication-r1/projection.json",
"bytes": 14864
},
{
"path": "docs/changes/netkingdom-target-2026-10-17/nk48-r5-f2-publication-r1/projection.stderr.txt",
"bytes": 0
},
{
"path": "docs/changes/netkingdom-target-2026-10-17/nk48-r5-f2-publication-r1/publication-commit.json",
"bytes": 1352
},
{
"path": "docs/changes/netkingdom-target-2026-10-17/nk48-r5-f2-publication-r1/publication-inputs.json",
"bytes": 791
},
{
"path": "docs/changes/netkingdom-target-2026-10-17/nk48-r5-f2-review-r1/REVIEW.md",
"bytes": 4743
},
{
"path": "docs/changes/netkingdom-target-2026-10-17/nk48-r5-f2-review-r1/evidence.json",
"bytes": 2495
},
{
"path": "docs/changes/netkingdom-target-2026-10-17/nk48-r5-f2-review-r1/focused-tests.txt",
"bytes": 1150
},
{
"path": "docs/changes/netkingdom-target-2026-10-17/nk48-r5-f2-review-r1/reproduce.py",
"bytes": 4588
},
{
"path": "docs/changes/netkingdom-target-2026-10-17/nk48-r5-f2-review-r1/review.json",
"bytes": 1478
},
{
"path": "docs/changes/netkingdom-target-2026-10-17/nk48-r5-f3-implementation-r1/README.md",
"bytes": 3793
},
{
"path": "docs/changes/netkingdom-target-2026-10-17/nk48-r5-f3-implementation-r1/candidate-validation.json",
"bytes": 723
},
{
"path": "docs/changes/netkingdom-target-2026-10-17/nk48-r5-f3-implementation-r1/failure_inverse_omitted.txt",
"bytes": 2257
},
{
"path": "docs/changes/netkingdom-target-2026-10-17/nk48-r5-f3-implementation-r1/focused-tests-before-admission-binding.json",
"bytes": 894
},
{
"path": "docs/changes/netkingdom-target-2026-10-17/nk48-r5-f3-implementation-r1/focused-tests-before-admission-binding.txt",
"bytes": 106
},
{
"path": "docs/changes/netkingdom-target-2026-10-17/nk48-r5-f3-implementation-r1/focused-tests.json",
"bytes": 681
},
{
"path": "docs/changes/netkingdom-target-2026-10-17/nk48-r5-f3-implementation-r1/focused-tests.txt",
"bytes": 101
},
{
"path": "docs/changes/netkingdom-target-2026-10-17/nk48-r5-f3-implementation-r1/implementation.json",
"bytes": 6080
},
{
"path": "docs/changes/netkingdom-target-2026-10-17/nk48-r5-f3-implementation-r1/manifest.json",
"bytes": 1933
},
{
"path": "docs/changes/netkingdom-target-2026-10-17/nk48-r5-f3-implementation-r1/negative-controls.json",
"bytes": 1099
},
{
"path": "docs/changes/netkingdom-target-2026-10-17/nk48-r5-f3-implementation-r1/net-kingdom-unchanged-owner-status.txt",
"bytes": 333
},
{
"path": "docs/changes/netkingdom-target-2026-10-17/nk48-r5-f3-implementation-r1/owner-contract-candidate.md",
"bytes": 8157
},
{
"path": "docs/changes/netkingdom-target-2026-10-17/nk48-r5-f3-implementation-r1/owner_configuration_contract.py",
"bytes": 3675
},
{
"path": "docs/changes/netkingdom-target-2026-10-17/nk48-r5-f3-implementation-r1/post_revision_guard_removed.txt",
"bytes": 1085
},
{
"path": "docs/changes/netkingdom-target-2026-10-17/nk48-r5-f3-implementation-r1/railiance-apps-unchanged-owner-status.txt",
"bytes": 23
},
{
"path": "docs/changes/netkingdom-target-2026-10-17/nk48-r5-f3-implementation-r1/test_owner_configuration_contract.py",
"bytes": 16794
},
{
"path": "docs/changes/netkingdom-target-2026-10-17/nk48-r5-f3-implementation-r1/type-owner-configuration-inverse.candidate.patch",
"bytes": 4508
},
{
"path": "docs/changes/netkingdom-target-2026-10-17/nk48-r5-f3-implementation-r1/type.before.yaml",
"bytes": 24322
},
{
"path": "docs/changes/netkingdom-target-2026-10-17/nk48-r5-f3-implementation-r1/type.candidate.yaml",
"bytes": 25909
},
{
"path": "docs/changes/netkingdom-target-2026-10-17/nk48-r5-f3-implementation-r2/README.md",
"bytes": 3100
},
{
"path": "docs/changes/netkingdom-target-2026-10-17/nk48-r5-f3-implementation-r2/candidate-validation.json",
"bytes": 761
},
{
"path": "docs/changes/netkingdom-target-2026-10-17/nk48-r5-f3-implementation-r2/focused-tests.json",
"bytes": 715
},
{
"path": "docs/changes/netkingdom-target-2026-10-17/nk48-r5-f3-implementation-r2/focused-tests.txt",
"bytes": 86
},
{
"path": "docs/changes/netkingdom-target-2026-10-17/nk48-r5-f3-implementation-r2/fresh-inverse-session.candidate.patch",
"bytes": 918
},
{
"path": "docs/changes/netkingdom-target-2026-10-17/nk48-r5-f3-implementation-r2/fresh-session-guard-omitted.txt",
"bytes": 27254
},
{
"path": "docs/changes/netkingdom-target-2026-10-17/nk48-r5-f3-implementation-r2/implementation.json",
"bytes": 6392
},
{
"path": "docs/changes/netkingdom-target-2026-10-17/nk48-r5-f3-implementation-r2/manifest.json",
"bytes": 2298
},
{
"path": "docs/changes/netkingdom-target-2026-10-17/nk48-r5-f3-implementation-r2/negative-controls.json",
"bytes": 547
},
{
"path": "docs/changes/netkingdom-target-2026-10-17/nk48-r5-f3-implementation-r2/owner-backend-next.md",
"bytes": 6278
},
{
"path": "docs/changes/netkingdom-target-2026-10-17/nk48-r5-f3-implementation-r2/owner-contract-candidate.md",
"bytes": 9431
},
{
"path": "docs/changes/netkingdom-target-2026-10-17/nk48-r5-f3-implementation-r2/owner-source-inventory.json",
"bytes": 2016
},
{
"path": "docs/changes/netkingdom-target-2026-10-17/nk48-r5-f3-implementation-r2/owner_configuration_contract.py",
"bytes": 4122
},
{
"path": "docs/changes/netkingdom-target-2026-10-17/nk48-r5-f3-implementation-r2/test_owner_configuration_contract.py",
"bytes": 22919
},
{
"path": "docs/changes/netkingdom-target-2026-10-17/nk48-r5-f3-implementation-r2/type-owner-configuration-inverse.candidate.patch",
"bytes": 5004
},
{
"path": "docs/changes/netkingdom-target-2026-10-17/nk48-r5-f3-implementation-r2/type.before.yaml",
"bytes": 24322
},
{
"path": "docs/changes/netkingdom-target-2026-10-17/nk48-r5-f3-implementation-r2/type.candidate.yaml",
"bytes": 26284
},
{
"path": "docs/changes/netkingdom-target-2026-10-17/nk48-r5-f3-review-r1/README.md",
"bytes": 6879
},
{
"path": "docs/changes/netkingdom-target-2026-10-17/nk48-r5-f3-review-r1/fresh-inverse-session.candidate.patch",
"bytes": 918
},
{
"path": "docs/changes/netkingdom-target-2026-10-17/nk48-r5-f3-review-r1/original-authority-tests.txt",
"bytes": 2708
},
{
"path": "docs/changes/netkingdom-target-2026-10-17/nk48-r5-f3-review-r1/patched-authority-tests.txt",
"bytes": 570
},
{
"path": "docs/changes/netkingdom-target-2026-10-17/nk48-r5-f3-review-r1/review.json",
"bytes": 6572
},
{
"path": "docs/changes/netkingdom-target-2026-10-17/nk48-r5-f3-review-r1/test_inverse_authority.py",
"bytes": 2737
},
{
"path": "docs/changes/netkingdom-target-2026-10-17/nk48-r5-source-followthrough-r1/apply_prepare.py",
"bytes": 1985
},
{
"path": "docs/changes/netkingdom-target-2026-10-17/nk48-r5-source-followthrough-r1/consistency.json",
"bytes": 13861
},
{
"path": "docs/changes/netkingdom-target-2026-10-17/nk48-r5-source-followthrough-r1/consistency.stderr.txt",
"bytes": 79
},
{
"path": "docs/changes/netkingdom-target-2026-10-17/nk48-r5-source-followthrough-r1/identifier-assignment.json",
"bytes": 881
},
{
"path": "docs/changes/netkingdom-target-2026-10-17/nk48-r5-source-followthrough-r1/identifier-preview.json",
"bytes": 882
},
{
"path": "docs/changes/netkingdom-target-2026-10-17/nk48-r5-source-followthrough-r1/preimage.json",
"bytes": 783
},
{
"path": "docs/changes/netkingdom-target-2026-10-17/nk48-r5-source-followthrough-r1/projection.json",
"bytes": 36744
},
{
"path": "docs/changes/netkingdom-target-2026-10-17/nk48-r5-source-followthrough-r1/projection.stderr.txt",
"bytes": 0
},
{
"path": "docs/changes/netkingdom-target-2026-10-17/nk48-r5-source-followthrough-r1/publication-commit.json",
"bytes": 872
},
{
"path": "docs/changes/netkingdom-target-2026-10-17/nk48-r5-source-followthrough-r1/publication-inputs.json",
"bytes": 515
},
{
"path": "docs/changes/netkingdom-target-2026-10-17/nk48-r5-source-followthrough-r1/workplan.allocated.md",
"bytes": 93587
},
{
"path": "docs/changes/netkingdom-target-2026-10-17/nk48-r5-source-followthrough-r1/workplan.candidate.md",
"bytes": 93413
},
{
"path": "docs/changes/netkingdom-target-2026-10-17/nk48-r5-source-followthrough-r1/workplan.preimage.md",
"bytes": 88901
},
{
"path": "docs/changes/netkingdom-target-2026-10-17/warden-1.3-kernel-fixes-r1/candidate.patch",
"bytes": 15036
},
{
"path": "docs/changes/netkingdom-target-2026-10-17/warden-1.3-kernel-fixes-r1/candidate/src/warden/case_run.py",
"bytes": 41144
},
{
"path": "docs/changes/netkingdom-target-2026-10-17/warden-1.3-kernel-fixes-r1/candidate/src/warden/case_type.py",
"bytes": 6894
},
{
"path": "docs/changes/netkingdom-target-2026-10-17/warden-1.3-kernel-fixes-r1/candidate/src/warden/routing/models.py",
"bytes": 15339
},
{
"path": "docs/changes/netkingdom-target-2026-10-17/warden-1.3-kernel-fixes-r1/candidate/tests/test_case_1_3_integration.py",
"bytes": 6834
},
{
"path": "docs/changes/netkingdom-target-2026-10-17/warden-1.3-kernel-fixes-r1/candidate/tests/test_case_admission_modes.py",
"bytes": 5252
},
{
"path": "docs/changes/netkingdom-target-2026-10-17/warden-1.3-kernel-fixes-r1/candidate/tests/test_case_attended_boundary.py",
"bytes": 4831
},
{
"path": "docs/changes/netkingdom-target-2026-10-17/warden-1.3-kernel-fixes-r1/evidence/run.py",
"bytes": 641
},
{
"path": "docs/changes/netkingdom-target-2026-10-17/warden-1.3-kernel-fixes-r1/evidence/sitecustomize.py",
"bytes": 688
},
{
"path": "docs/changes/netkingdom-target-2026-10-17/warden-1.3-kernel-fixes-r1/implementation-r1.json",
"bytes": 7441
},
{
"path": "docs/changes/netkingdom-target-2026-10-17/warden-1.3-kernel-fixes-r1/test-isolation-proposal.patch",
"bytes": 1803
},
{
"path": "docs/changes/netkingdom-target-2026-10-17/warden-1.3-kernel-review-r2/integration_runner.py",
"bytes": 1212
},
{
"path": "docs/changes/netkingdom-target-2026-10-17/warden-1.3-kernel-review-r2/kernel-review-r2.json",
"bytes": 11541
},
{
"path": "docs/changes/netkingdom-target-2026-10-17/warden-1.3-kernel-review-r2/reviewer-probes.py",
"bytes": 4213
},
{
"path": "docs/changes/netkingdom-target-2026-10-17/warden-1.3-kernel-review-r2/run-baseline.py",
"bytes": 542
},
{
"path": "docs/changes/netkingdom-target-2026-10-17/warden-1.3-kernel-review-r2/run.py",
"bytes": 544
},
{
"path": "docs/changes/netkingdom-target-2026-10-17/warden-1.3-kernel-review-r2/setup.py",
"bytes": 1766
},
{
"path": "docs/changes/netkingdom-target-2026-10-17/warden-1.3-kernel-review-r2/sitecustomize.py",
"bytes": 879
},
{
"path": "docs/changes/netkingdom-target-2026-10-17/warden-kernel-source-integration-r1/commit.json",
"bytes": 268
},
{
"path": "docs/changes/netkingdom-target-2026-10-17/warden-kernel-source-integration-r1/consistency-preimage.json",
"bytes": 15107
},
{
"path": "docs/changes/netkingdom-target-2026-10-17/warden-kernel-source-integration-r1/consistency.json",
"bytes": 5425
},
{
"path": "docs/changes/netkingdom-target-2026-10-17/warden-kernel-source-integration-r1/consistency.stderr.txt",
"bytes": 0
},
{
"path": "docs/changes/netkingdom-target-2026-10-17/warden-kernel-source-integration-r1/focused-tests.txt",
"bytes": 179
},
{
"path": "docs/changes/netkingdom-target-2026-10-17/warden-kernel-source-integration-r1/integrate.py",
"bytes": 7327
},
{
"path": "docs/changes/netkingdom-target-2026-10-17/warden-kernel-source-integration-r1/integration.json",
"bytes": 930
},
{
"path": "docs/changes/netkingdom-target-2026-10-17/warden-kernel-source-integration-r1/normal-sync.json",
"bytes": 9997
},
{
"path": "docs/changes/netkingdom-target-2026-10-17/warden-kernel-source-integration-r1/normal-sync.stderr.txt",
"bytes": 0
},
{
"path": "docs/changes/netkingdom-target-2026-10-17/warden-kernel-source-integration-r1/publish.py",
"bytes": 4575
},
{
"path": "docs/changes/netkingdom-target-2026-10-17/warden-kernel-source-integration-r1/verification.json",
"bytes": 1648
},
{
"path": "docs/changes/netkingdom-target-2026-10-17/warden-kernel-source-integration-r1/workplan.preimage.md",
"bytes": 16634
},
{
"path": "docs/changes/netkingdom-target-2026-10-17/warden-safe-unit-runner-r1/README.md",
"bytes": 3977
},
{
"path": "docs/changes/netkingdom-target-2026-10-17/warden-safe-unit-runner-r1/candidate.patch",
"bytes": 32117
},
{
"path": "docs/changes/netkingdom-target-2026-10-17/warden-safe-unit-runner-r1/candidate/Makefile",
"bytes": 1957
},
{
"path": "docs/changes/netkingdom-target-2026-10-17/warden-safe-unit-runner-r1/candidate/docs/development/safe-unit-tests.md",
"bytes": 4289
},
{
"path": "docs/changes/netkingdom-target-2026-10-17/warden-safe-unit-runner-r1/candidate/scripts/run_unit_tests.py",
"bytes": 14899
},
{
"path": "docs/changes/netkingdom-target-2026-10-17/warden-safe-unit-runner-r1/candidate/tests/fixtures/workload-coverage/provenance.json",
"bytes": 932
},
{
"path": "docs/changes/netkingdom-target-2026-10-17/warden-safe-unit-runner-r1/candidate/tests/fixtures/workload-coverage/rapp-core-hub/declarations/rapp.yaml",
"bytes": 413
},
{
"path": "docs/changes/netkingdom-target-2026-10-17/warden-safe-unit-runner-r1/candidate/tests/fixtures/workload-coverage/rapp-issue-core/declarations/rapp.yaml",
"bytes": 292
},
{
"path": "docs/changes/netkingdom-target-2026-10-17/warden-safe-unit-runner-r1/candidate/tests/fixtures/workload-coverage/rapp-qonto/declarations/rapp.yaml",
"bytes": 284
},
{
"path": "docs/changes/netkingdom-target-2026-10-17/warden-safe-unit-runner-r1/candidate/tests/test_case_plan.py",
"bytes": 8547
},
{
"path": "docs/changes/netkingdom-target-2026-10-17/warden-safe-unit-runner-r1/candidate/tests/test_case_type.py",
"bytes": 5039
},
{
"path": "docs/changes/netkingdom-target-2026-10-17/warden-safe-unit-runner-r1/candidate/tests/test_layer_conformance.py",
"bytes": 15990
},
{
"path": "docs/changes/netkingdom-target-2026-10-17/warden-safe-unit-runner-r1/candidate/tests/test_safe_unit_runner.py",
"bytes": 3368
},
{
"path": "docs/changes/netkingdom-target-2026-10-17/warden-safe-unit-runner-r1/candidate/tests/test_workload_join.py",
"bytes": 3081
},
{
"path": "docs/changes/netkingdom-target-2026-10-17/warden-safe-unit-runner-r1/candidate/tests/unit_isolation_probe.py",
"bytes": 1079
},
{
"path": "docs/changes/netkingdom-target-2026-10-17/warden-safe-unit-runner-r1/candidate/workplans/WARDEN-WP-0044-security-case-follow-through.md",
"bytes": 21045
},
{
"path": "docs/changes/netkingdom-target-2026-10-17/warden-safe-unit-runner-r1/implementation.json",
"bytes": 6038
},
{
"path": "docs/changes/netkingdom-target-2026-10-17/warden-safe-unit-runner-r1/packet-hashes.json",
"bytes": 2647
},
{
"path": "docs/netkingdom-target-implementation.md",
"bytes": 80197
},
{
"path": "docs/netkingdom-target-security-architecture.md",
"bytes": 18310
},
{
"path": "workplans/CUST-WP-0080-netkingdom-security-blueprint-and-gap-closure.md",
"bytes": 83344
}
]

View file

@ -0,0 +1,42 @@
[
{
"path": ".custodian-brief.md",
"sha256": "74e3f825b14c6fe5a0f8cf511e2b85d9010f56109ea5bee700b360766b3dd453",
"index": "100644 6aad3a5788fad3abd60c0f1270f160062dc0168b 0\t.custodian-brief.md"
},
{
"path": "WORK-RECORDS.md",
"sha256": "b8dc1ac2245e7aa59b13af1f62b0ca21b6c5704cafdb5a4de7a81b2d5595265b",
"index": "100644 d535e0f2dcc3d454e041a8f1b547b5dea4493380 0\tWORK-RECORDS.md"
},
{
"path": "docs/assessments/netkingdom-2026-10-14/hosted-before-federated.json",
"sha256": "baecc157233131d17c73e84cd997db922d36ad235cbaa91f4938852220a824a2",
"index": "100644 bbe2969551797f8c0c7c33e1009f1b293a631113 0\tdocs/assessments/netkingdom-2026-10-14/hosted-before-federated.json"
},
{
"path": "docs/assessments/netkingdom-2026-10-14/hub-private-source-pending.json",
"sha256": "92916fa2fcabbe3f4b7c4b89ddbd6dc6cb079ffd6f06cf66b2c6e6d6ff5fabde",
"index": "100644 af6b3430909c8cbf8190c53cd541da651291151a 0\tdocs/assessments/netkingdom-2026-10-14/hub-private-source-pending.json"
},
{
"path": "docs/assessments/netkingdom-2026-10-14/owner-access-gate.json",
"sha256": "059d36b607383c1458dd2909e9adc5ec8be42af7c41412b4ce2d244d20d093df",
"index": "100644 514edc14eb0a48736594bdd1bde2348e3d55e365 0\tdocs/assessments/netkingdom-2026-10-14/owner-access-gate.json"
},
{
"path": "docs/assessments/netkingdom-2026-10-14/publication-preflight.json",
"sha256": "4b041890abae585ca78536fa12bb9668392f21b7c2c21f5f581e2eed516a1164",
"index": "100644 ee5730a4c683ee71240a4086e34a448cad92d88d 0\tdocs/assessments/netkingdom-2026-10-14/publication-preflight.json"
},
{
"path": "docs/assessments/netkingdom-2026-10-14/published-source-verification.json",
"sha256": "f0095fc7a8089443f27ad50e358247705a6a5ce83c85f4d57b402b116741e7c0",
"index": "100644 83cdeb35d0ccd0b3a2472f8aa95767437566cbd9 0\tdocs/assessments/netkingdom-2026-10-14/published-source-verification.json"
},
{
"path": "docs/assessments/netkingdom-2026-10-14/scoped-access-handoff.json",
"sha256": "29c43c9909bb8a94ebdc74312a545b66bcc73de1a355158bf247cf8fc405f16b",
"index": "100644 44097c5ea5ab08a0834ab1bd1d42fe4528bbb2c2 0\tdocs/assessments/netkingdom-2026-10-14/scoped-access-handoff.json"
}
]

View file

@ -0,0 +1,62 @@
<!-- custodian-brief: generated by fix-consistency — do not edit manually -->
# Custodian Brief — the-custodian
**Domain:** infotech
**Last synced:** 2026-10-15 23:45 UTC
**State Hub:** http://127.0.0.1:8000 *(adjust if running on a remote machine)*
## Active Workstreams
### NetKingdom target security architecture and SEC-DSM implementation
Progress: 2/6 done | workplan_id: `dfadb19b-445e-59c6-bcd6-48e87b912c52`
**Open tasks:**
- ► Close source defects and reconcile uncovered lifecycle gaps `87637402`
- ► Coordinate self-service Playwright identity delivery `ed8b909a`
- ► Establish the target architecture and drive the restructuring `6aca534c`
- · Verify native closure against every requirement `82378b0f`
### Separate agent credentials and establish supervised privileged execution
Progress: 2/5 done | workplan_id: `a98a9f34-83b4-5c8c-8107-e05f7806d50d`
**Open tasks:**
- ! Build and hand out the agent identity `4b88b0b7`
*(wait: Await GLAS-WP-0012 (glas-harness) production acceptance of the local supervised profile; then railiance-platform RBAC, railiance-enablement k3s config, railiance-infra principal mapping and ops-warden certificate issuance.)*
- ! Fleet guidance and harness guards `90725511`
*(wait: Await CUST-WP-0073-T02: the verified agent identity and execution path must exist before it can be documented; Codex/Grok read-denial guard needs glas-harness or harness-owner delivery.)*
- ! Rotate what was exposed `1b41b532`
*(wait: Deferred by founder decision 2026-09-24; reopened only by the founder on one of the three triggers below, in one attended rotation window.)*
### Size Railiance workloads from actual demand and establish a weekly allocation review
Progress: 1/5 done | workplan_id: `2249bddb-7524-5add-bd5c-c4163a6ca0f3`
**Open tasks:**
- ! Measure the Vergabe prototype under representative pilot use `82192370`
*(wait: Await RAPPS-WP-0014-T03 (blocked, needs_human): populated two-user/document workflow run by Bernd and the company contact, giving representative load for p95 <= 2s / zero failures.)*
- ! Review ecosystem allocations and reserve operating room `6dc67558`
*(wait: Await CUST-WP-0071-T02 representative sample; Forgejo/runner demand and zero-request workload review need owner input (railiance-cluster, railiance-forge, resource-control).)*
- ! Apply accepted sizing changes and verify their effects `944f98e2`
*(wait: Await reviewed allocation proposals and applicable workload-owner authority.)*
- ! Establish the regular weekly workload-demand and allocation assessment `20ddd4d7`
*(wait: Await the repeatable observation and accepted sizing/review procedure.)*
### Deterministic security flow: standing authorizations, flow report, and agent re-engagement
Progress: 3/7 done | workplan_id: `ab288f92-d364-5c24-9362-aee451f266c3`
**Open tasks:**
- ! Schedule the flow report and decision sync `1be0569c`
*(wait: Activity Core accepted the schedule in ACTIVITY-WP-0047. Await claiming rein workstation/hub acceptance, owner activation and the first unassisted fire with report/checkpoint evidence.)*
- ! Encode the standing change rule as a policy-nexus guardrail `5dd52156`
*(wait: policy-nexus owns guardrail publication; handoff written as PNEX-WP-0006.)*
- ! Stop agent-authored index and sync commits `8a3dc219`
*(wait: Local guard and repeatable shared-hook installation are implemented. Fleet generator adoption and the required full week of clean history remain unverified; repo-manager owner acceptance is needed.)*
- ! Attended window #1 `e3da807f`
*(wait: Partly done 2026-10-11: list cut from 14 to 3; U05-U07 accepted, U08 waits on KEY-WP-0040-T01. Remaining founder acts: USER-WP-0026-T03 readback, RPF-WP-0044-T08 coulombcore check, the U08 re-run, and Sol's added RPF-WP-0044-T04 issuer login.)*
---
## MCP Orientation (when available)
If the state-hub MCP server is reachable, call:
`get_domain_summary("infotech")`
This provides richer cross-domain context.
If the MCP call fails, use this file as your orientation source.

View file

@ -0,0 +1,536 @@
# Work Records — the-custodian
> Generated by `statehub fix-consistency` (CUST-WP-0061-T04, work-record
> stage 3). Do not edit by hand — edit the source file/block listed for
> each record and re-run fix-consistency to refresh this index. Archived
> workplans are omitted; closed decisions/intakes/engagements stay listed
> so recently-resolved work is still visible. [auto]
| Kind | ID | Status | Lane | Source |
| --- | --- | --- | --- | --- |
| workplan | CUST-WP-ADHOC-2026-05-02 | done | — | workplans/ADHOC-2026-05-02.md |
| workplan | CUST-WP-ADHOC-2026-07-02 | finished | — | workplans/ADHOC-2026-07-02.md |
| workplan | CUST-WP-ADHOC-2026-08-25-RETIRED | finished | — | workplans/ADHOC-2026-08-25-retired.md |
| workplan | CUST-WP-ADHOC-2026-08-25 | finished | — | workplans/ADHOC-2026-08-25.md |
| workplan | CUST-WP-ADHOC-2026-09-06 | finished | — | workplans/ADHOC-2026-09-06.md |
| workplan | CUST-WP-0000 | finished | — | workplans/CUST-WP-0000-state-hub-v0.1-build-deploy.md |
| workplan | CUST-WP-0000b | finished | — | workplans/CUST-WP-0000b-state-hub-v0.2-decisions-dependencies.md |
| workplan | CUST-WP-0001 | done | — | workplans/CUST-WP-0001-custodian-agent-runtime.md |
| workplan | CUST-WP-0002 | finished | — | workplans/CUST-WP-0002-contribution-tracking-sbom.md |
| workplan | CUST-WP-0004 | finished | — | workplans/CUST-WP-0004-ep-td-tracking.md |
| workplan | CUST-WP-0005 | finished | — | workplans/CUST-WP-0005-dynamic-domains.md |
| workplan | CUST-WP-0006 | done | — | workplans/CUST-WP-0006-gems-state-hub.md |
| workplan | CUST-WP-0007 | finished | — | workplans/CUST-WP-0007-gems-migration.md |
| workplan | CUST-WP-0008 | done | — | workplans/CUST-WP-0008-consistency-engine.md |
| workplan | CUST-WP-0009 | finished | — | workplans/CUST-WP-0009-human-interventions.md |
| workplan | CUST-WP-0010 | finished | — | workplans/CUST-WP-0010-workstream-lifecycle-docs.md |
| workplan | CUST-WP-0010b | finished | — | workplans/CUST-WP-0010b-domain-and-repo-goals.md |
| workplan | CUST-WP-0013 | finished | — | workplans/CUST-WP-0013-sbom-infra-expansion.md |
| workplan | CUST-WP-0015 | done | — | workplans/CUST-WP-0015-agent-inbox.md |
| workplan | CUST-WP-0016 | done | — | workplans/CUST-WP-0016-kaizen-agentic-integration.md |
| workplan | CUST-WP-0017 | done | — | workplans/CUST-WP-0017-scope-md-agent-and-coverage.md |
| workplan | CUST-WP-0018 | done | — | workplans/CUST-WP-0018-api-hardening-code-quality.md |
| workplan | CUST-WP-0019 | done | — | workplans/CUST-WP-0019-dashboard-ux-polish.md |
| workplan | CUST-WP-0020 | done | — | workplans/CUST-WP-0020-test-suite.md |
| workplan | CUST-WP-0021 | done | — | workplans/CUST-WP-0021-multi-host-repo-paths.md |
| workplan | CUST-WP-0022 | done | — | workplans/CUST-WP-0022-capability-requests.md |
| workplan | CUST-WP-0023 | done | — | workplans/CUST-WP-0023-tpsc.md |
| workplan | CUST-WP-0024 | done | — | workplans/CUST-WP-0024-repo-doi-gate.md |
| workplan | CUST-WP-0026 | done | — | workplans/CUST-WP-0026-distributed-consistency.md |
| workplan | CUST-WP-0027 | done | — | workplans/CUST-WP-0027-capability-request-dispute.md |
| workplan | CUST-WP-0029 | done | — | workplans/CUST-WP-0029-token-consumption-tracking.md |
| workplan | CUST-WP-0030 | done | — | workplans/CUST-WP-0030-dashboard-entity-list-ux.md |
| workplan | CUST-WP-0031 | done | — | workplans/CUST-WP-0031-capability-registry.md |
| workplan | CUST-WP-0032 | done | — | workplans/CUST-WP-0032-haskell-build-machine.md |
| workplan | CUST-WP-0033 | done | — | workplans/CUST-WP-0033-interface-change-registry.md |
| workplan | CUST-WP-0039 | done | — | workplans/CUST-WP-0039-dashboard-poll-optimization.md |
| workplan | CUST-WP-0040 | finished | — | workplans/CUST-WP-0040-state-hub-nats-activity-core-integration.md |
| workplan | CUST-WP-0041 | done | — | workplans/CUST-WP-0041-api-performance.md |
| workplan | CUST-WP-0043 | finished | — | workplans/CUST-WP-0043-state-hub-repo-extraction.md |
| workplan | CUST-WP-0044 | finished | — | workplans/CUST-WP-0044-daily-statehub-wsjf-triage.md |
| workplan | CUST-WP-0045 | finished | — | workplans/CUST-WP-0045-activity-core-daily-triage-runner.md |
| workplan | CUST-WP-0069 | finished | — | workplans/CUST-WP-0045-cutover-runbook.md |
| workplan | CUST-WP-0046 | finished | — | workplans/CUST-WP-0046-hourly-recently-on-scope-activity-core.md |
| workplan | CUST-WP-0047 | finished | — | workplans/CUST-WP-0047-ops-hub-service-inventory-now-view.md |
| workplan | CUST-WP-0048 | finished | — | workplans/CUST-WP-0048-hub-core-state-hub-import-refactor.md |
| workplan | CUST-WP-0049 | finished | — | workplans/CUST-WP-0049-interhub-bootstrap-access-lane.md |
| workplan | CUST-WP-0050 | finished | — | workplans/CUST-WP-0050-repo-classification-registration-redesign.md |
| workplan | CUST-WP-0051 | finished | — | workplans/CUST-WP-0051-infrastructure-stabilization-metaplan.md |
| workplan | CUST-WP-0052 | finished | — | workplans/CUST-WP-0052-core-hub-fos-reset.md |
| workplan | CUST-WP-0053 | finished | — | workplans/CUST-WP-0053-coordination-hygiene-improvements.md |
| workplan | CUST-WP-0055 | finished | — | workplans/CUST-WP-0055-workplan-terminology-fleet-refactor.md |
| workplan | CUST-WP-0056 | finished | — | workplans/CUST-WP-0056-daily-todo-md-stale-review.md |
| workplan | CUST-WP-0059 | finished | — | workplans/CUST-WP-0059-forgejo-ci-publish-cutover-tail.md |
| workplan | CUST-WP-0060 | finished | — | workplans/CUST-WP-0060-work-record-canonization.md |
| workplan | CUST-WP-0061 | finished | — | workplans/CUST-WP-0061-work-record-stage3-intake-promotion-index.md |
| workplan | CUST-WP-0062 | finished | — | workplans/CUST-WP-0062-sbom-nexus-daily-catchup.md |
| workplan | CUST-WP-0063 | finished | — | workplans/CUST-WP-0063-inbox-governance-packets.md |
| workplan | CUST-WP-0064 | finished | — | workplans/CUST-WP-0064-sbom-controlled-scan-inputs.md |
| workplan | CUST-WP-0065 | finished | — | workplans/CUST-WP-0065-reclassify-repos-and-guidance-docs-to-the-new-sector-domain.md |
| workplan | CUST-WP-0066 | finished | — | workplans/CUST-WP-0066-repository-qualified-ad-hoc-identifiers.md |
| workplan | CUST-WP-0067 | finished | — | workplans/CUST-WP-0067-hub-authority-target-resolution.md |
| workplan | CUST-WP-0068 | finished | — | workplans/CUST-WP-0068-cache-only-work-record-recovery.md |
| workplan | CUST-WP-0070 | finished | — | workplans/CUST-WP-0070-publication-repo-category.md |
| workplan | CUST-WP-0071 | blocked | — | workplans/CUST-WP-0071-measured-workload-sizing-and-weekly-review.md |
| workplan | CUST-WP-0072 | finished | — | workplans/CUST-WP-0072-fleet-flavor-and-depends-on-backfill.md |
| workplan | CUST-WP-0073 | blocked | — | workplans/CUST-WP-0073-agent-credential-separation.md |
| workplan | CUST-WP-0074 | finished | — | workplans/CUST-WP-0074-qualified-wait-states.md |
| workplan | CUST-WP-0075 | finished | — | workplans/CUST-WP-0075-dependency-graph-driven-unblocking.md |
| workplan | CUST-WP-0076 | finished | — | workplans/CUST-WP-0076-provisioning-window-cadence.md |
| workplan | CUST-WP-0077 | finished | — | workplans/CUST-WP-0077-dependency-root-execution-wave.md |
| workplan | CUST-WP-0078 | finished | — | workplans/CUST-WP-0078-security-collaboration-consolidation.md |
| workplan | CUST-WP-0079 | blocked | — | workplans/CUST-WP-0079-deterministic-security-flow.md |
| workplan | CUST-WP-0080 | active | — | workplans/CUST-WP-0080-netkingdom-security-blueprint-and-gap-closure.md |
| workplan | CUST-WP-0081 | finished | — | workplans/CUST-WP-0081-netkingdom-architecture-review-and-reuse.md |
| workplan | THE-WP-0001 | finished | — | workplans/THE-WP-0001-federation-interface.md |
| task | CUST-WP-ADHOC-2026-05-02-T01 | done | — | workplans/ADHOC-2026-05-02.md |
| task | CUST-WP-ADHOC-2026-07-02-T01 | done | — | workplans/ADHOC-2026-07-02.md |
| task | ADHOC-2026-08-25-T01 | done | — | workplans/ADHOC-2026-08-25-retired.md |
| task | CUST-WP-ADHOC-2026-08-25-T01 | done | — | workplans/ADHOC-2026-08-25.md |
| task | CUST-WP-ADHOC-2026-09-06-T01 | done | — | workplans/ADHOC-2026-09-06.md |
| task | CUST-WP-0001-T01 | done | — | workplans/CUST-WP-0001-custodian-agent-runtime.md |
| task | CUST-WP-0001-T02 | done | — | workplans/CUST-WP-0001-custodian-agent-runtime.md |
| task | CUST-WP-0002-T01 | done | — | workplans/CUST-WP-0002-contribution-tracking-sbom.md |
| task | CUST-WP-0002-T02 | done | — | workplans/CUST-WP-0002-contribution-tracking-sbom.md |
| task | CUST-WP-0002-T03 | done | — | workplans/CUST-WP-0002-contribution-tracking-sbom.md |
| task | CUST-WP-0002-T04 | done | — | workplans/CUST-WP-0002-contribution-tracking-sbom.md |
| task | CUST-WP-0002-T05 | done | — | workplans/CUST-WP-0002-contribution-tracking-sbom.md |
| task | CUST-WP-0002-T06 | done | — | workplans/CUST-WP-0002-contribution-tracking-sbom.md |
| task | CUST-WP-0002-T07 | done | — | workplans/CUST-WP-0002-contribution-tracking-sbom.md |
| task | CUST-WP-0002-T08 | done | — | workplans/CUST-WP-0002-contribution-tracking-sbom.md |
| task | CUST-WP-0002-T09 | done | — | workplans/CUST-WP-0002-contribution-tracking-sbom.md |
| task | CUST-WP-0002-T10 | done | — | workplans/CUST-WP-0002-contribution-tracking-sbom.md |
| task | CUST-WP-0002-T11 | done | — | workplans/CUST-WP-0002-contribution-tracking-sbom.md |
| task | CUST-WP-0002-T12 | done | — | workplans/CUST-WP-0002-contribution-tracking-sbom.md |
| task | CUST-WP-0002-T13 | done | — | workplans/CUST-WP-0002-contribution-tracking-sbom.md |
| task | CUST-WP-0002-T14 | done | — | workplans/CUST-WP-0002-contribution-tracking-sbom.md |
| task | CUST-WP-0002-T15 | done | — | workplans/CUST-WP-0002-contribution-tracking-sbom.md |
| task | CUST-WP-0004-T01 | done | — | workplans/CUST-WP-0004-ep-td-tracking.md |
| task | CUST-WP-0004-T02 | done | — | workplans/CUST-WP-0004-ep-td-tracking.md |
| task | CUST-WP-0004-T03 | done | — | workplans/CUST-WP-0004-ep-td-tracking.md |
| task | CUST-WP-0004-T04 | done | — | workplans/CUST-WP-0004-ep-td-tracking.md |
| task | CUST-WP-0004-T05 | done | — | workplans/CUST-WP-0004-ep-td-tracking.md |
| task | CUST-WP-0004-T06 | done | — | workplans/CUST-WP-0004-ep-td-tracking.md |
| task | CUST-WP-0004-T07 | done | — | workplans/CUST-WP-0004-ep-td-tracking.md |
| task | CUST-WP-0004-T08 | done | — | workplans/CUST-WP-0004-ep-td-tracking.md |
| task | CUST-WP-0004-T09 | done | — | workplans/CUST-WP-0004-ep-td-tracking.md |
| task | CUST-WP-0004-T10 | done | — | workplans/CUST-WP-0004-ep-td-tracking.md |
| task | CUST-WP-0005-T01 | done | — | workplans/CUST-WP-0005-dynamic-domains.md |
| task | CUST-WP-0005-T02 | done | — | workplans/CUST-WP-0005-dynamic-domains.md |
| task | CUST-WP-0005-T03 | done | — | workplans/CUST-WP-0005-dynamic-domains.md |
| task | CUST-WP-0005-T04 | done | — | workplans/CUST-WP-0005-dynamic-domains.md |
| task | CUST-WP-0005-T05 | done | — | workplans/CUST-WP-0005-dynamic-domains.md |
| task | CUST-WP-0005-T06 | done | — | workplans/CUST-WP-0005-dynamic-domains.md |
| task | CUST-WP-0005-T07 | done | — | workplans/CUST-WP-0005-dynamic-domains.md |
| task | CUST-WP-0005-T08 | done | — | workplans/CUST-WP-0005-dynamic-domains.md |
| task | CUST-WP-0005-T09 | done | — | workplans/CUST-WP-0005-dynamic-domains.md |
| task | CUST-WP-0005-T10 | done | — | workplans/CUST-WP-0005-dynamic-domains.md |
| task | CUST-WP-0005-T11 | done | — | workplans/CUST-WP-0005-dynamic-domains.md |
| task | T01 | done | — | workplans/CUST-WP-0006-gems-state-hub.md |
| task | T02 | done | — | workplans/CUST-WP-0006-gems-state-hub.md |
| task | T03 | done | — | workplans/CUST-WP-0006-gems-state-hub.md |
| task | T04 | done | — | workplans/CUST-WP-0006-gems-state-hub.md |
| task | T05 | done | — | workplans/CUST-WP-0006-gems-state-hub.md |
| task | T01 | done | — | workplans/CUST-WP-0007-gems-migration.md |
| task | T02 | done | — | workplans/CUST-WP-0007-gems-migration.md |
| task | T03 | done | — | workplans/CUST-WP-0007-gems-migration.md |
| task | T04 | done | — | workplans/CUST-WP-0007-gems-migration.md |
| task | T05 | done | — | workplans/CUST-WP-0007-gems-migration.md |
| task | T06 | done | — | workplans/CUST-WP-0007-gems-migration.md |
| task | T07 | done | — | workplans/CUST-WP-0007-gems-migration.md |
| task | T08 | done | — | workplans/CUST-WP-0007-gems-migration.md |
| task | T09 | done | — | workplans/CUST-WP-0007-gems-migration.md |
| task | T10 | done | — | workplans/CUST-WP-0007-gems-migration.md |
| task | T11 | done | — | workplans/CUST-WP-0007-gems-migration.md |
| task | T12 | done | — | workplans/CUST-WP-0007-gems-migration.md |
| task | T13 | done | — | workplans/CUST-WP-0007-gems-migration.md |
| task | T14 | done | — | workplans/CUST-WP-0007-gems-migration.md |
| task | T15 | done | — | workplans/CUST-WP-0007-gems-migration.md |
| task | T16 | done | — | workplans/CUST-WP-0007-gems-migration.md |
| task | T17 | done | — | workplans/CUST-WP-0007-gems-migration.md |
| task | CUST-WP-0008-T01 | done | — | workplans/CUST-WP-0008-consistency-engine.md |
| task | CUST-WP-0008-T02 | done | — | workplans/CUST-WP-0008-consistency-engine.md |
| task | CUST-WP-0008-T03 | done | — | workplans/CUST-WP-0008-consistency-engine.md |
| task | CUST-WP-0008-T04 | done | — | workplans/CUST-WP-0008-consistency-engine.md |
| task | CUST-WP-0009-T1 | done | — | workplans/CUST-WP-0009-human-interventions.md |
| task | CUST-WP-0009-T2 | done | — | workplans/CUST-WP-0009-human-interventions.md |
| task | CUST-WP-0009-T3 | done | — | workplans/CUST-WP-0009-human-interventions.md |
| task | CUST-WP-0010-T1 | done | — | workplans/CUST-WP-0010-workstream-lifecycle-docs.md |
| task | CUST-WP-0010-T2 | done | — | workplans/CUST-WP-0010-workstream-lifecycle-docs.md |
| task | CUST-WP-0010-T3 | done | — | workplans/CUST-WP-0010-workstream-lifecycle-docs.md |
| task | CUST-WP-0010b-T01 | done | — | workplans/CUST-WP-0010b-domain-and-repo-goals.md |
| task | CUST-WP-0010b-T02 | done | — | workplans/CUST-WP-0010b-domain-and-repo-goals.md |
| task | CUST-WP-0013-T01 | done | — | workplans/CUST-WP-0013-sbom-infra-expansion.md |
| task | CUST-WP-0013-T02 | done | — | workplans/CUST-WP-0013-sbom-infra-expansion.md |
| task | CUST-WP-0013-T03 | done | — | workplans/CUST-WP-0013-sbom-infra-expansion.md |
| task | CUST-WP-0013-T04 | done | — | workplans/CUST-WP-0013-sbom-infra-expansion.md |
| task | CUST-WP-0013-T05 | done | — | workplans/CUST-WP-0013-sbom-infra-expansion.md |
| task | CUST-WP-0013-T06 | done | — | workplans/CUST-WP-0013-sbom-infra-expansion.md |
| task | CUST-WP-0013-T07 | done | — | workplans/CUST-WP-0013-sbom-infra-expansion.md |
| task | CUST-WP-0013-T08 | done | — | workplans/CUST-WP-0013-sbom-infra-expansion.md |
| task | CUST-WP-0013-T09 | done | — | workplans/CUST-WP-0013-sbom-infra-expansion.md |
| task | CUST-WP-0013-T10 | done | — | workplans/CUST-WP-0013-sbom-infra-expansion.md |
| task | CUST-WP-0013-T11 | done | — | workplans/CUST-WP-0013-sbom-infra-expansion.md |
| task | CUST-WP-0013-T12 | done | — | workplans/CUST-WP-0013-sbom-infra-expansion.md |
| task | CUST-WP-0013-T13 | done | — | workplans/CUST-WP-0013-sbom-infra-expansion.md |
| task | CUST-WP-0013-T14 | done | — | workplans/CUST-WP-0013-sbom-infra-expansion.md |
| task | CUST-WP-0015-T01 | done | — | workplans/CUST-WP-0015-agent-inbox.md |
| task | CUST-WP-0015-T02 | done | — | workplans/CUST-WP-0015-agent-inbox.md |
| task | CUST-WP-0015-T03 | done | — | workplans/CUST-WP-0015-agent-inbox.md |
| task | CUST-WP-0015-T04 | done | — | workplans/CUST-WP-0015-agent-inbox.md |
| task | CUST-WP-0015-T05 | done | — | workplans/CUST-WP-0015-agent-inbox.md |
| task | CUST-WP-0016-T01 | done | — | workplans/CUST-WP-0016-kaizen-agentic-integration.md |
| task | CUST-WP-0016-T02 | done | — | workplans/CUST-WP-0016-kaizen-agentic-integration.md |
| task | CUST-WP-0016-T03 | done | — | workplans/CUST-WP-0016-kaizen-agentic-integration.md |
| task | CUST-WP-0016-T04 | done | — | workplans/CUST-WP-0016-kaizen-agentic-integration.md |
| task | CUST-WP-0016-T05 | done | — | workplans/CUST-WP-0016-kaizen-agentic-integration.md |
| task | CUST-WP-0017-T01 | done | — | workplans/CUST-WP-0017-scope-md-agent-and-coverage.md |
| task | CUST-WP-0017-T02 | done | — | workplans/CUST-WP-0017-scope-md-agent-and-coverage.md |
| task | CUST-WP-0017-T03 | done | — | workplans/CUST-WP-0017-scope-md-agent-and-coverage.md |
| task | CUST-WP-0017-T04 | done | — | workplans/CUST-WP-0017-scope-md-agent-and-coverage.md |
| task | CUST-WP-0017-T05 | done | — | workplans/CUST-WP-0017-scope-md-agent-and-coverage.md |
| task | CUST-WP-0017-T06 | done | — | workplans/CUST-WP-0017-scope-md-agent-and-coverage.md |
| task | CUST-WP-0018-T01 | done | — | workplans/CUST-WP-0018-api-hardening-code-quality.md |
| task | CUST-WP-0018-T02 | done | — | workplans/CUST-WP-0018-api-hardening-code-quality.md |
| task | CUST-WP-0018-T03 | done | — | workplans/CUST-WP-0018-api-hardening-code-quality.md |
| task | CUST-WP-0018-T04 | done | — | workplans/CUST-WP-0018-api-hardening-code-quality.md |
| task | CUST-WP-0018-T05 | done | — | workplans/CUST-WP-0018-api-hardening-code-quality.md |
| task | CUST-WP-0018-T06 | done | — | workplans/CUST-WP-0018-api-hardening-code-quality.md |
| task | CUST-WP-0018-T07 | done | — | workplans/CUST-WP-0018-api-hardening-code-quality.md |
| task | CUST-WP-0019-T01 | done | — | workplans/CUST-WP-0019-dashboard-ux-polish.md |
| task | CUST-WP-0019-T02 | done | — | workplans/CUST-WP-0019-dashboard-ux-polish.md |
| task | CUST-WP-0019-T03 | done | — | workplans/CUST-WP-0019-dashboard-ux-polish.md |
| task | CUST-WP-0020-T01 | done | — | workplans/CUST-WP-0020-test-suite.md |
| task | CUST-WP-0020-T02 | done | — | workplans/CUST-WP-0020-test-suite.md |
| task | CUST-WP-0020-T03 | done | — | workplans/CUST-WP-0020-test-suite.md |
| task | CUST-WP-0020-T04 | done | — | workplans/CUST-WP-0020-test-suite.md |
| task | CUST-WP-0020-T05 | done | — | workplans/CUST-WP-0020-test-suite.md |
| task | CUST-WP-0021-T01 | done | — | workplans/CUST-WP-0021-multi-host-repo-paths.md |
| task | CUST-WP-0021-T02 | done | — | workplans/CUST-WP-0021-multi-host-repo-paths.md |
| task | CUST-WP-0021-T03 | done | — | workplans/CUST-WP-0021-multi-host-repo-paths.md |
| task | CUST-WP-0021-T04 | done | — | workplans/CUST-WP-0021-multi-host-repo-paths.md |
| task | CUST-WP-0021-T05 | done | — | workplans/CUST-WP-0021-multi-host-repo-paths.md |
| task | CUST-WP-0022-T01 | done | — | workplans/CUST-WP-0022-capability-requests.md |
| task | CUST-WP-0022-T02 | done | — | workplans/CUST-WP-0022-capability-requests.md |
| task | CUST-WP-0022-T03 | done | — | workplans/CUST-WP-0022-capability-requests.md |
| task | CUST-WP-0022-T04 | done | — | workplans/CUST-WP-0022-capability-requests.md |
| task | CUST-WP-0022-T05 | done | — | workplans/CUST-WP-0022-capability-requests.md |
| task | CUST-WP-0022-T06 | done | — | workplans/CUST-WP-0022-capability-requests.md |
| task | CUST-WP-0022-T07 | done | — | workplans/CUST-WP-0022-capability-requests.md |
| task | CUST-WP-0022-T08 | done | — | workplans/CUST-WP-0022-capability-requests.md |
| task | CUST-WP-0022-T09 | done | — | workplans/CUST-WP-0022-capability-requests.md |
| task | CUST-WP-0022-T10 | done | — | workplans/CUST-WP-0022-capability-requests.md |
| task | CUST-WP-0023-T01 | done | — | workplans/CUST-WP-0023-tpsc.md |
| task | CUST-WP-0023-T02 | done | — | workplans/CUST-WP-0023-tpsc.md |
| task | CUST-WP-0023-T03 | done | — | workplans/CUST-WP-0023-tpsc.md |
| task | CUST-WP-0023-T04 | done | — | workplans/CUST-WP-0023-tpsc.md |
| task | CUST-WP-0023-T05 | done | — | workplans/CUST-WP-0023-tpsc.md |
| task | CUST-WP-0023-T06 | done | — | workplans/CUST-WP-0023-tpsc.md |
| task | CUST-WP-0023-T07 | done | — | workplans/CUST-WP-0023-tpsc.md |
| task | CUST-WP-0023-T08 | done | — | workplans/CUST-WP-0023-tpsc.md |
| task | CUST-WP-0023-T09 | done | — | workplans/CUST-WP-0023-tpsc.md |
| task | CUST-WP-0023-T10 | done | — | workplans/CUST-WP-0023-tpsc.md |
| task | CUST-WP-0024-T01 | done | — | workplans/CUST-WP-0024-repo-doi-gate.md |
| task | CUST-WP-0024-T02 | done | — | workplans/CUST-WP-0024-repo-doi-gate.md |
| task | CUST-WP-0024-T03 | done | — | workplans/CUST-WP-0024-repo-doi-gate.md |
| task | CUST-WP-0024-T04 | done | — | workplans/CUST-WP-0024-repo-doi-gate.md |
| task | CUST-WP-0024-T05 | done | — | workplans/CUST-WP-0024-repo-doi-gate.md |
| task | CUST-WP-0026-T01 | done | — | workplans/CUST-WP-0026-distributed-consistency.md |
| task | CUST-WP-0026-T02 | done | — | workplans/CUST-WP-0026-distributed-consistency.md |
| task | CUST-WP-0026-T03 | done | — | workplans/CUST-WP-0026-distributed-consistency.md |
| task | CUST-WP-0026-T04 | done | — | workplans/CUST-WP-0026-distributed-consistency.md |
| task | CUST-WP-0026-T05 | done | — | workplans/CUST-WP-0026-distributed-consistency.md |
| task | CUST-WP-0027-T01 | done | — | workplans/CUST-WP-0027-capability-request-dispute.md |
| task | CUST-WP-0027-T02 | done | — | workplans/CUST-WP-0027-capability-request-dispute.md |
| task | CUST-WP-0027-T03 | done | — | workplans/CUST-WP-0027-capability-request-dispute.md |
| task | CUST-WP-0027-T04 | done | — | workplans/CUST-WP-0027-capability-request-dispute.md |
| task | CUST-WP-0027-T05 | done | — | workplans/CUST-WP-0027-capability-request-dispute.md |
| task | CUST-WP-0029-T01 | done | — | workplans/CUST-WP-0029-token-consumption-tracking.md |
| task | CUST-WP-0029-T02 | done | — | workplans/CUST-WP-0029-token-consumption-tracking.md |
| task | CUST-WP-0029-T03 | done | — | workplans/CUST-WP-0029-token-consumption-tracking.md |
| task | CUST-WP-0029-T04 | done | — | workplans/CUST-WP-0029-token-consumption-tracking.md |
| task | CUST-WP-0029-T05 | done | — | workplans/CUST-WP-0029-token-consumption-tracking.md |
| task | CUST-WP-0029-T06 | done | — | workplans/CUST-WP-0029-token-consumption-tracking.md |
| task | CUST-WP-0029-T07 | done | — | workplans/CUST-WP-0029-token-consumption-tracking.md |
| task | CUST-WP-0029-T08 | done | — | workplans/CUST-WP-0029-token-consumption-tracking.md |
| task | T01 | done | — | workplans/CUST-WP-0030-dashboard-entity-list-ux.md |
| task | T02 | done | — | workplans/CUST-WP-0030-dashboard-entity-list-ux.md |
| task | T03 | done | — | workplans/CUST-WP-0030-dashboard-entity-list-ux.md |
| task | T04 | done | — | workplans/CUST-WP-0030-dashboard-entity-list-ux.md |
| task | T05 | done | — | workplans/CUST-WP-0030-dashboard-entity-list-ux.md |
| task | T06 | done | — | workplans/CUST-WP-0030-dashboard-entity-list-ux.md |
| task | T07 | done | — | workplans/CUST-WP-0030-dashboard-entity-list-ux.md |
| task | T08 | done | — | workplans/CUST-WP-0030-dashboard-entity-list-ux.md |
| task | T09 | done | — | workplans/CUST-WP-0030-dashboard-entity-list-ux.md |
| task | T01 | done | — | workplans/CUST-WP-0031-capability-registry.md |
| task | T02 | done | — | workplans/CUST-WP-0031-capability-registry.md |
| task | T03 | done | — | workplans/CUST-WP-0031-capability-registry.md |
| task | T04 | done | — | workplans/CUST-WP-0031-capability-registry.md |
| task | T05 | done | — | workplans/CUST-WP-0031-capability-registry.md |
| task | T06 | done | — | workplans/CUST-WP-0031-capability-registry.md |
| task | T07 | done | — | workplans/CUST-WP-0031-capability-registry.md |
| task | CUST-WP-0032-T01 | done | — | workplans/CUST-WP-0032-haskell-build-machine.md |
| task | CUST-WP-0032-T02 | done | — | workplans/CUST-WP-0032-haskell-build-machine.md |
| task | CUST-WP-0032-T03 | done | — | workplans/CUST-WP-0032-haskell-build-machine.md |
| task | CUST-WP-0032-T04 | done | — | workplans/CUST-WP-0032-haskell-build-machine.md |
| task | CUST-WP-0032-T05 | done | — | workplans/CUST-WP-0032-haskell-build-machine.md |
| task | CUST-WP-0032-T06 | done | — | workplans/CUST-WP-0032-haskell-build-machine.md |
| task | CUST-WP-0032-T07 | done | — | workplans/CUST-WP-0032-haskell-build-machine.md |
| task | CUST-WP-0032-T08 | done | — | workplans/CUST-WP-0032-haskell-build-machine.md |
| task | CUST-WP-0032-T09 | done | — | workplans/CUST-WP-0032-haskell-build-machine.md |
| task | CUST-WP-0032-T10 | done | — | workplans/CUST-WP-0032-haskell-build-machine.md |
| task | CUST-WP-0032-T11 | done | — | workplans/CUST-WP-0032-haskell-build-machine.md |
| task | CUST-WP-0032-T12 | done | — | workplans/CUST-WP-0032-haskell-build-machine.md |
| task | CUST-WP-0032-T13 | done | — | workplans/CUST-WP-0032-haskell-build-machine.md |
| task | CUST-WP-0032-T14 | done | — | workplans/CUST-WP-0032-haskell-build-machine.md |
| task | CUST-WP-0032-T15 | done | — | workplans/CUST-WP-0032-haskell-build-machine.md |
| task | CUST-WP-0033-T01 | done | — | workplans/CUST-WP-0033-interface-change-registry.md |
| task | CUST-WP-0033-T02 | done | — | workplans/CUST-WP-0033-interface-change-registry.md |
| task | CUST-WP-0033-T03 | done | — | workplans/CUST-WP-0033-interface-change-registry.md |
| task | CUST-WP-0033-T04 | done | — | workplans/CUST-WP-0033-interface-change-registry.md |
| task | CUST-WP-0033-T05 | done | — | workplans/CUST-WP-0033-interface-change-registry.md |
| task | CUST-WP-0033-T06 | done | — | workplans/CUST-WP-0033-interface-change-registry.md |
| task | CUST-WP-0039-T1 | done | — | workplans/CUST-WP-0039-dashboard-poll-optimization.md |
| task | CUST-WP-0039-T2 | done | — | workplans/CUST-WP-0039-dashboard-poll-optimization.md |
| task | CUST-WP-0039-T3 | done | — | workplans/CUST-WP-0039-dashboard-poll-optimization.md |
| task | CUST-WP-0039-T4 | done | — | workplans/CUST-WP-0039-dashboard-poll-optimization.md |
| task | CUST-WP-0039-T5 | done | — | workplans/CUST-WP-0039-dashboard-poll-optimization.md |
| task | CUST-WP-0039-T6 | done | — | workplans/CUST-WP-0039-dashboard-poll-optimization.md |
| task | T01 | done | — | workplans/CUST-WP-0040-state-hub-nats-activity-core-integration.md |
| task | T02 | done | — | workplans/CUST-WP-0040-state-hub-nats-activity-core-integration.md |
| task | T03 | done | — | workplans/CUST-WP-0040-state-hub-nats-activity-core-integration.md |
| task | T04 | done | — | workplans/CUST-WP-0040-state-hub-nats-activity-core-integration.md |
| task | T05 | done | — | workplans/CUST-WP-0040-state-hub-nats-activity-core-integration.md |
| task | T06 | done | — | workplans/CUST-WP-0040-state-hub-nats-activity-core-integration.md |
| task | CUST-WP-0041-T1 | done | — | workplans/CUST-WP-0041-api-performance.md |
| task | CUST-WP-0041-T2 | done | — | workplans/CUST-WP-0041-api-performance.md |
| task | CUST-WP-0041-T3 | done | — | workplans/CUST-WP-0041-api-performance.md |
| task | CUST-WP-0041-T4 | done | — | workplans/CUST-WP-0041-api-performance.md |
| task | CUST-WP-0043-T01 | done | — | workplans/CUST-WP-0043-state-hub-repo-extraction.md |
| task | CUST-WP-0043-T02 | done | — | workplans/CUST-WP-0043-state-hub-repo-extraction.md |
| task | CUST-WP-0043-T03 | done | — | workplans/CUST-WP-0043-state-hub-repo-extraction.md |
| task | CUST-WP-0043-T04 | done | — | workplans/CUST-WP-0043-state-hub-repo-extraction.md |
| task | CUST-WP-0043-T05 | done | — | workplans/CUST-WP-0043-state-hub-repo-extraction.md |
| task | CUST-WP-0043-T06 | done | — | workplans/CUST-WP-0043-state-hub-repo-extraction.md |
| task | CUST-WP-0043-T07 | done | — | workplans/CUST-WP-0043-state-hub-repo-extraction.md |
| task | CUST-WP-0043-T08 | done | — | workplans/CUST-WP-0043-state-hub-repo-extraction.md |
| task | CUST-WP-0043-T09 | done | — | workplans/CUST-WP-0043-state-hub-repo-extraction.md |
| task | CUST-WP-0044-T01 | done | — | workplans/CUST-WP-0044-daily-statehub-wsjf-triage.md |
| task | CUST-WP-0044-T02 | done | — | workplans/CUST-WP-0044-daily-statehub-wsjf-triage.md |
| task | CUST-WP-0044-T03 | done | — | workplans/CUST-WP-0044-daily-statehub-wsjf-triage.md |
| task | CUST-WP-0044-T04 | done | — | workplans/CUST-WP-0044-daily-statehub-wsjf-triage.md |
| task | CUST-WP-0044-T05 | done | — | workplans/CUST-WP-0044-daily-statehub-wsjf-triage.md |
| task | CUST-WP-0044-T06 | done | — | workplans/CUST-WP-0044-daily-statehub-wsjf-triage.md |
| task | CUST-WP-0045-T01 | done | — | workplans/CUST-WP-0045-activity-core-daily-triage-runner.md |
| task | CUST-WP-0045-T02 | done | — | workplans/CUST-WP-0045-activity-core-daily-triage-runner.md |
| task | CUST-WP-0045-T03 | done | — | workplans/CUST-WP-0045-activity-core-daily-triage-runner.md |
| task | CUST-WP-0045-T04 | done | — | workplans/CUST-WP-0045-activity-core-daily-triage-runner.md |
| task | CUST-WP-0045-T05 | done | — | workplans/CUST-WP-0045-activity-core-daily-triage-runner.md |
| task | CUST-WP-0045-T06 | done | — | workplans/CUST-WP-0045-activity-core-daily-triage-runner.md |
| task | CUST-WP-0045-T07 | done | — | workplans/CUST-WP-0045-activity-core-daily-triage-runner.md |
| task | CUST-WP-0045-T08 | done | — | workplans/CUST-WP-0045-activity-core-daily-triage-runner.md |
| task | CUST-WP-0046-T01 | done | — | workplans/CUST-WP-0046-hourly-recently-on-scope-activity-core.md |
| task | CUST-WP-0046-T02 | done | — | workplans/CUST-WP-0046-hourly-recently-on-scope-activity-core.md |
| task | CUST-WP-0046-T03 | done | — | workplans/CUST-WP-0046-hourly-recently-on-scope-activity-core.md |
| task | CUST-WP-0046-T04 | done | — | workplans/CUST-WP-0046-hourly-recently-on-scope-activity-core.md |
| task | CUST-WP-0046-T05 | done | — | workplans/CUST-WP-0046-hourly-recently-on-scope-activity-core.md |
| task | CUST-WP-0046-T06 | done | — | workplans/CUST-WP-0046-hourly-recently-on-scope-activity-core.md |
| task | CUST-WP-0046-T07 | done | — | workplans/CUST-WP-0046-hourly-recently-on-scope-activity-core.md |
| task | CUST-WP-0047-T01 | done | — | workplans/CUST-WP-0047-ops-hub-service-inventory-now-view.md |
| task | CUST-WP-0047-T02 | done | — | workplans/CUST-WP-0047-ops-hub-service-inventory-now-view.md |
| task | CUST-WP-0047-T03 | done | — | workplans/CUST-WP-0047-ops-hub-service-inventory-now-view.md |
| task | CUST-WP-0047-T04 | done | — | workplans/CUST-WP-0047-ops-hub-service-inventory-now-view.md |
| task | CUST-WP-0047-T05 | cancel | — | workplans/CUST-WP-0047-ops-hub-service-inventory-now-view.md |
| task | CUST-WP-0047-T06 | done | — | workplans/CUST-WP-0047-ops-hub-service-inventory-now-view.md |
| task | CUST-WP-0047-T07 | done | — | workplans/CUST-WP-0047-ops-hub-service-inventory-now-view.md |
| task | CUST-WP-0048-T01 | done | — | workplans/CUST-WP-0048-hub-core-state-hub-import-refactor.md |
| task | CUST-WP-0048-T02 | done | — | workplans/CUST-WP-0048-hub-core-state-hub-import-refactor.md |
| task | CUST-WP-0048-T03 | done | — | workplans/CUST-WP-0048-hub-core-state-hub-import-refactor.md |
| task | CUST-WP-0048-T04 | done | — | workplans/CUST-WP-0048-hub-core-state-hub-import-refactor.md |
| task | CUST-WP-0048-T05 | done | — | workplans/CUST-WP-0048-hub-core-state-hub-import-refactor.md |
| task | CUST-WP-0048-T06 | done | — | workplans/CUST-WP-0048-hub-core-state-hub-import-refactor.md |
| task | CUST-WP-0048-T07 | done | — | workplans/CUST-WP-0048-hub-core-state-hub-import-refactor.md |
| task | CUST-WP-0048-T08 | done | — | workplans/CUST-WP-0048-hub-core-state-hub-import-refactor.md |
| task | CUST-WP-0049-T01 | done | — | workplans/CUST-WP-0049-interhub-bootstrap-access-lane.md |
| task | CUST-WP-0049-T02 | done | — | workplans/CUST-WP-0049-interhub-bootstrap-access-lane.md |
| task | CUST-WP-0049-T03 | done | — | workplans/CUST-WP-0049-interhub-bootstrap-access-lane.md |
| task | CUST-WP-0049-T04 | done | — | workplans/CUST-WP-0049-interhub-bootstrap-access-lane.md |
| task | CUST-WP-0049-T05 | done | — | workplans/CUST-WP-0049-interhub-bootstrap-access-lane.md |
| task | CUST-WP-0049-T06 | cancel | — | workplans/CUST-WP-0049-interhub-bootstrap-access-lane.md |
| task | CUST-WP-0050-T01 | done | — | workplans/CUST-WP-0050-repo-classification-registration-redesign.md |
| task | CUST-WP-0050-T02 | done | — | workplans/CUST-WP-0050-repo-classification-registration-redesign.md |
| task | CUST-WP-0050-T03 | cancel | — | workplans/CUST-WP-0050-repo-classification-registration-redesign.md |
| task | CUST-WP-0050-T04 | cancel | — | workplans/CUST-WP-0050-repo-classification-registration-redesign.md |
| task | CUST-WP-0050-T05 | cancel | — | workplans/CUST-WP-0050-repo-classification-registration-redesign.md |
| task | CUST-WP-0050-T06 | cancel | — | workplans/CUST-WP-0050-repo-classification-registration-redesign.md |
| task | CUST-WP-0050-T07 | cancel | — | workplans/CUST-WP-0050-repo-classification-registration-redesign.md |
| task | CUST-WP-0050-T08 | cancel | — | workplans/CUST-WP-0050-repo-classification-registration-redesign.md |
| task | CUST-WP-0050-T09 | cancel | — | workplans/CUST-WP-0050-repo-classification-registration-redesign.md |
| task | CUST-WP-0050-T10 | cancel | — | workplans/CUST-WP-0050-repo-classification-registration-redesign.md |
| task | CUST-WP-0050-T11 | done | — | workplans/CUST-WP-0050-repo-classification-registration-redesign.md |
| task | CUST-WP-0051-T01 | done | — | workplans/CUST-WP-0051-infrastructure-stabilization-metaplan.md |
| task | CUST-WP-0051-T02 | done | — | workplans/CUST-WP-0051-infrastructure-stabilization-metaplan.md |
| task | CUST-WP-0051-T03 | done | — | workplans/CUST-WP-0051-infrastructure-stabilization-metaplan.md |
| task | CUST-WP-0051-T04 | done | — | workplans/CUST-WP-0051-infrastructure-stabilization-metaplan.md |
| task | CUST-WP-0051-T05 | done | — | workplans/CUST-WP-0051-infrastructure-stabilization-metaplan.md |
| task | CUST-WP-0051-T06 | done | — | workplans/CUST-WP-0051-infrastructure-stabilization-metaplan.md |
| task | CUST-WP-0051-T07 | done | — | workplans/CUST-WP-0051-infrastructure-stabilization-metaplan.md |
| task | CUST-WP-0051-T08 | done | — | workplans/CUST-WP-0051-infrastructure-stabilization-metaplan.md |
| task | CUST-WP-0052-T01 | done | — | workplans/CUST-WP-0052-core-hub-fos-reset.md |
| task | CUST-WP-0052-T02 | done | — | workplans/CUST-WP-0052-core-hub-fos-reset.md |
| task | CUST-WP-0052-T03 | done | — | workplans/CUST-WP-0052-core-hub-fos-reset.md |
| task | CUST-WP-0052-T04 | done | — | workplans/CUST-WP-0052-core-hub-fos-reset.md |
| task | CUST-WP-0052-T05 | done | — | workplans/CUST-WP-0052-core-hub-fos-reset.md |
| task | CUST-WP-0052-T06 | done | — | workplans/CUST-WP-0052-core-hub-fos-reset.md |
| task | CUST-WP-0052-T07 | done | — | workplans/CUST-WP-0052-core-hub-fos-reset.md |
| task | CUST-WP-0053-T01 | done | — | workplans/CUST-WP-0053-coordination-hygiene-improvements.md |
| task | CUST-WP-0053-T02 | done | — | workplans/CUST-WP-0053-coordination-hygiene-improvements.md |
| task | CUST-WP-0053-T03 | done | — | workplans/CUST-WP-0053-coordination-hygiene-improvements.md |
| task | CUST-WP-0053-T04 | done | — | workplans/CUST-WP-0053-coordination-hygiene-improvements.md |
| task | CUST-WP-0053-T05 | done | — | workplans/CUST-WP-0053-coordination-hygiene-improvements.md |
| task | CUST-WP-0055-T01 | done | — | workplans/CUST-WP-0055-workplan-terminology-fleet-refactor.md |
| task | CUST-WP-0055-T02 | done | — | workplans/CUST-WP-0055-workplan-terminology-fleet-refactor.md |
| task | CUST-WP-0055-T03 | done | — | workplans/CUST-WP-0055-workplan-terminology-fleet-refactor.md |
| task | CUST-WP-0055-T04 | done | — | workplans/CUST-WP-0055-workplan-terminology-fleet-refactor.md |
| task | CUST-WP-0055-T05 | done | — | workplans/CUST-WP-0055-workplan-terminology-fleet-refactor.md |
| task | CUST-WP-0055-T06 | done | — | workplans/CUST-WP-0055-workplan-terminology-fleet-refactor.md |
| task | CUST-WP-0055-T07 | done | — | workplans/CUST-WP-0055-workplan-terminology-fleet-refactor.md |
| task | CUST-WP-0055-T08 | done | — | workplans/CUST-WP-0055-workplan-terminology-fleet-refactor.md |
| task | CUST-WP-0056-T01 | done | — | workplans/CUST-WP-0056-daily-todo-md-stale-review.md |
| task | CUST-WP-0056-T02 | done | — | workplans/CUST-WP-0056-daily-todo-md-stale-review.md |
| task | CUST-WP-0056-T03 | done | — | workplans/CUST-WP-0056-daily-todo-md-stale-review.md |
| task | CUST-WP-0059-T01 | done | — | workplans/CUST-WP-0059-forgejo-ci-publish-cutover-tail.md |
| task | CUST-WP-0059-T02 | done | — | workplans/CUST-WP-0059-forgejo-ci-publish-cutover-tail.md |
| task | CUST-WP-0059-T03 | done | — | workplans/CUST-WP-0059-forgejo-ci-publish-cutover-tail.md |
| task | CUST-WP-0059-T04 | done | — | workplans/CUST-WP-0059-forgejo-ci-publish-cutover-tail.md |
| task | CUST-WP-0059-T05 | done | — | workplans/CUST-WP-0059-forgejo-ci-publish-cutover-tail.md |
| task | CUST-WP-0059-T06 | done | — | workplans/CUST-WP-0059-forgejo-ci-publish-cutover-tail.md |
| task | CUST-WP-0060-T01 | done | — | workplans/CUST-WP-0060-work-record-canonization.md |
| task | CUST-WP-0060-T02 | done | — | workplans/CUST-WP-0060-work-record-canonization.md |
| task | CUST-WP-0060-T03 | done | — | workplans/CUST-WP-0060-work-record-canonization.md |
| task | CUST-WP-0060-T04 | done | — | workplans/CUST-WP-0060-work-record-canonization.md |
| task | CUST-WP-0060-T05 | done | — | workplans/CUST-WP-0060-work-record-canonization.md |
| task | CUST-WP-0060-T06 | done | — | workplans/CUST-WP-0060-work-record-canonization.md |
| task | CUST-WP-0060-T07 | done | — | workplans/CUST-WP-0060-work-record-canonization.md |
| task | CUST-WP-0061-T01 | done | — | workplans/CUST-WP-0061-work-record-stage3-intake-promotion-index.md |
| task | CUST-WP-0061-T02 | done | — | workplans/CUST-WP-0061-work-record-stage3-intake-promotion-index.md |
| task | CUST-WP-0061-T03 | done | — | workplans/CUST-WP-0061-work-record-stage3-intake-promotion-index.md |
| task | CUST-WP-0061-T04 | done | — | workplans/CUST-WP-0061-work-record-stage3-intake-promotion-index.md |
| task | CUST-WP-0061-T05 | done | — | workplans/CUST-WP-0061-work-record-stage3-intake-promotion-index.md |
| task | CUST-WP-0061-T06 | done | — | workplans/CUST-WP-0061-work-record-stage3-intake-promotion-index.md |
| task | CUST-WP-0062-T01 | done | — | workplans/CUST-WP-0062-sbom-nexus-daily-catchup.md |
| task | CUST-WP-0062-T02 | done | — | workplans/CUST-WP-0062-sbom-nexus-daily-catchup.md |
| task | CUST-WP-0062-T03 | done | — | workplans/CUST-WP-0062-sbom-nexus-daily-catchup.md |
| task | CUST-WP-0062-T04 | done | — | workplans/CUST-WP-0062-sbom-nexus-daily-catchup.md |
| task | CUST-WP-0062-T05 | done | — | workplans/CUST-WP-0062-sbom-nexus-daily-catchup.md |
| task | CUST-WP-0062-T06 | done | — | workplans/CUST-WP-0062-sbom-nexus-daily-catchup.md |
| task | CUST-WP-0063-T01 | done | — | workplans/CUST-WP-0063-inbox-governance-packets.md |
| task | CUST-WP-0063-T02 | done | — | workplans/CUST-WP-0063-inbox-governance-packets.md |
| task | CUST-WP-0063-T03 | done | — | workplans/CUST-WP-0063-inbox-governance-packets.md |
| task | CUST-WP-0063-T04 | done | — | workplans/CUST-WP-0063-inbox-governance-packets.md |
| task | CUST-WP-0063-T05 | done | — | workplans/CUST-WP-0063-inbox-governance-packets.md |
| task | CUST-WP-0064-T01 | done | — | workplans/CUST-WP-0064-sbom-controlled-scan-inputs.md |
| task | CUST-WP-0064-T02 | done | — | workplans/CUST-WP-0064-sbom-controlled-scan-inputs.md |
| task | CUST-WP-0064-T03 | done | — | workplans/CUST-WP-0064-sbom-controlled-scan-inputs.md |
| task | CUST-WP-0064-T04 | done | — | workplans/CUST-WP-0064-sbom-controlled-scan-inputs.md |
| task | CUST-WP-0065-T01 | done | — | workplans/CUST-WP-0065-reclassify-repos-and-guidance-docs-to-the-new-sector-domain.md |
| task | CUST-WP-0065-T02 | done | — | workplans/CUST-WP-0065-reclassify-repos-and-guidance-docs-to-the-new-sector-domain.md |
| task | CUST-WP-0065-T03 | done | — | workplans/CUST-WP-0065-reclassify-repos-and-guidance-docs-to-the-new-sector-domain.md |
| task | CUST-WP-0065-T04 | done | — | workplans/CUST-WP-0065-reclassify-repos-and-guidance-docs-to-the-new-sector-domain.md |
| task | CUST-WP-0066-T01 | done | — | workplans/CUST-WP-0066-repository-qualified-ad-hoc-identifiers.md |
| task | CUST-WP-0066-T02 | done | — | workplans/CUST-WP-0066-repository-qualified-ad-hoc-identifiers.md |
| task | CUST-WP-0066-T03 | done | — | workplans/CUST-WP-0066-repository-qualified-ad-hoc-identifiers.md |
| task | CUST-WP-0067-T01 | done | — | workplans/CUST-WP-0067-hub-authority-target-resolution.md |
| task | CUST-WP-0067-T02 | done | — | workplans/CUST-WP-0067-hub-authority-target-resolution.md |
| task | CUST-WP-0067-T03 | done | — | workplans/CUST-WP-0067-hub-authority-target-resolution.md |
| task | CUST-WP-0067-T04 | done | — | workplans/CUST-WP-0067-hub-authority-target-resolution.md |
| task | CUST-WP-0067-T05 | done | — | workplans/CUST-WP-0067-hub-authority-target-resolution.md |
| task | CUST-WP-0067-T06 | done | — | workplans/CUST-WP-0067-hub-authority-target-resolution.md |
| task | CUST-WP-0067-T07 | done | — | workplans/CUST-WP-0067-hub-authority-target-resolution.md |
| task | CUST-WP-0067-T08 | done | — | workplans/CUST-WP-0067-hub-authority-target-resolution.md |
| task | CUST-WP-0067-T09 | done | — | workplans/CUST-WP-0067-hub-authority-target-resolution.md |
| task | CUST-WP-0067-T10 | done | — | workplans/CUST-WP-0067-hub-authority-target-resolution.md |
| task | CUST-WP-0068-T01 | done | — | workplans/CUST-WP-0068-cache-only-work-record-recovery.md |
| task | CUST-WP-0068-T02 | done | — | workplans/CUST-WP-0068-cache-only-work-record-recovery.md |
| task | CUST-WP-0068-T03 | done | — | workplans/CUST-WP-0068-cache-only-work-record-recovery.md |
| task | CUST-WP-0068-T04 | done | — | workplans/CUST-WP-0068-cache-only-work-record-recovery.md |
| task | CUST-WP-0068-T05 | done | — | workplans/CUST-WP-0068-cache-only-work-record-recovery.md |
| task | CUST-WP-0068-T06 | done | — | workplans/CUST-WP-0068-cache-only-work-record-recovery.md |
| task | CUST-WP-0068-T07 | done | — | workplans/CUST-WP-0068-cache-only-work-record-recovery.md |
| task | CUST-WP-0068-T08 | done | — | workplans/CUST-WP-0068-cache-only-work-record-recovery.md |
| task | CUST-WP-0068-T09 | done | — | workplans/CUST-WP-0068-cache-only-work-record-recovery.md |
| task | CUST-WP-0070-T01 | done | — | workplans/CUST-WP-0070-publication-repo-category.md |
| task | CUST-WP-0070-T02 | done | — | workplans/CUST-WP-0070-publication-repo-category.md |
| task | CUST-WP-0070-T03 | done | — | workplans/CUST-WP-0070-publication-repo-category.md |
| task | CUST-WP-0071-T01 | done | — | workplans/CUST-WP-0071-measured-workload-sizing-and-weekly-review.md |
| task | CUST-WP-0071-T02 | wait | — | workplans/CUST-WP-0071-measured-workload-sizing-and-weekly-review.md |
| task | CUST-WP-0071-T03 | wait | — | workplans/CUST-WP-0071-measured-workload-sizing-and-weekly-review.md |
| task | CUST-WP-0071-T04 | wait | — | workplans/CUST-WP-0071-measured-workload-sizing-and-weekly-review.md |
| task | CUST-WP-0071-T05 | wait | — | workplans/CUST-WP-0071-measured-workload-sizing-and-weekly-review.md |
| task | CUST-WP-0072-T01 | done | — | workplans/CUST-WP-0072-fleet-flavor-and-depends-on-backfill.md |
| task | CUST-WP-0072-T02 | done | — | workplans/CUST-WP-0072-fleet-flavor-and-depends-on-backfill.md |
| task | CUST-WP-0072-T03 | done | — | workplans/CUST-WP-0072-fleet-flavor-and-depends-on-backfill.md |
| task | CUST-WP-0072-T04 | done | — | workplans/CUST-WP-0072-fleet-flavor-and-depends-on-backfill.md |
| task | CUST-WP-0073-T01 | done | — | workplans/CUST-WP-0073-agent-credential-separation.md |
| task | CUST-WP-0073-T02 | wait | — | workplans/CUST-WP-0073-agent-credential-separation.md |
| task | CUST-WP-0073-T03 | done | — | workplans/CUST-WP-0073-agent-credential-separation.md |
| task | CUST-WP-0073-T04 | wait | — | workplans/CUST-WP-0073-agent-credential-separation.md |
| task | CUST-WP-0073-T05 | wait | — | workplans/CUST-WP-0073-agent-credential-separation.md |
| task | CUST-WP-0074-T01 | done | — | workplans/CUST-WP-0074-qualified-wait-states.md |
| task | CUST-WP-0074-T02 | done | — | workplans/CUST-WP-0074-qualified-wait-states.md |
| task | CUST-WP-0074-T03 | done | — | workplans/CUST-WP-0074-qualified-wait-states.md |
| task | CUST-WP-0074-T04 | done | — | workplans/CUST-WP-0074-qualified-wait-states.md |
| task | CUST-WP-0074-T05 | done | — | workplans/CUST-WP-0074-qualified-wait-states.md |
| task | CUST-WP-0074-T06 | done | — | workplans/CUST-WP-0074-qualified-wait-states.md |
| task | CUST-WP-0075-T01 | done | — | workplans/CUST-WP-0075-dependency-graph-driven-unblocking.md |
| task | CUST-WP-0075-T02 | done | — | workplans/CUST-WP-0075-dependency-graph-driven-unblocking.md |
| task | CUST-WP-0075-T03 | done | — | workplans/CUST-WP-0075-dependency-graph-driven-unblocking.md |
| task | CUST-WP-0075-T04 | done | — | workplans/CUST-WP-0075-dependency-graph-driven-unblocking.md |
| task | CUST-WP-0075-T05 | done | — | workplans/CUST-WP-0075-dependency-graph-driven-unblocking.md |
| task | CUST-WP-0075-T06 | done | — | workplans/CUST-WP-0075-dependency-graph-driven-unblocking.md |
| task | CUST-WP-0076-T01 | done | — | workplans/CUST-WP-0076-provisioning-window-cadence.md |
| task | CUST-WP-0077-T01 | done | — | workplans/CUST-WP-0077-dependency-root-execution-wave.md |
| task | CUST-WP-0077-T02 | done | — | workplans/CUST-WP-0077-dependency-root-execution-wave.md |
| task | CUST-WP-0077-T03 | done | — | workplans/CUST-WP-0077-dependency-root-execution-wave.md |
| task | CUST-WP-0077-T04 | done | — | workplans/CUST-WP-0077-dependency-root-execution-wave.md |
| task | CUST-WP-0077-T05 | done | — | workplans/CUST-WP-0077-dependency-root-execution-wave.md |
| task | CUST-WP-0078-T01 | done | — | workplans/CUST-WP-0078-security-collaboration-consolidation.md |
| task | CUST-WP-0078-T02 | done | — | workplans/CUST-WP-0078-security-collaboration-consolidation.md |
| task | CUST-WP-0078-T03 | done | — | workplans/CUST-WP-0078-security-collaboration-consolidation.md |
| task | CUST-WP-0078-T04 | done | — | workplans/CUST-WP-0078-security-collaboration-consolidation.md |
| task | CUST-WP-0079-T01 | done | — | workplans/CUST-WP-0079-deterministic-security-flow.md |
| task | CUST-WP-0079-T02 | done | — | workplans/CUST-WP-0079-deterministic-security-flow.md |
| task | CUST-WP-0079-T03 | wait | — | workplans/CUST-WP-0079-deterministic-security-flow.md |
| task | CUST-WP-0079-T04 | wait | — | workplans/CUST-WP-0079-deterministic-security-flow.md |
| task | CUST-WP-0079-T05 | wait | — | workplans/CUST-WP-0079-deterministic-security-flow.md |
| task | CUST-WP-0079-T06 | wait | — | workplans/CUST-WP-0079-deterministic-security-flow.md |
| task | CUST-WP-0079-T07 | done | — | workplans/CUST-WP-0079-deterministic-security-flow.md |
| task | CUST-WP-0080-T01 | done | — | workplans/CUST-WP-0080-netkingdom-security-blueprint-and-gap-closure.md |
| task | CUST-WP-0080-T02 | done | — | workplans/CUST-WP-0080-netkingdom-security-blueprint-and-gap-closure.md |
| task | CUST-WP-0080-T03 | progress | — | workplans/CUST-WP-0080-netkingdom-security-blueprint-and-gap-closure.md |
| task | CUST-WP-0080-T04 | todo | — | workplans/CUST-WP-0080-netkingdom-security-blueprint-and-gap-closure.md |
| task | CUST-WP-0080-T05 | progress | — | workplans/CUST-WP-0080-netkingdom-security-blueprint-and-gap-closure.md |
| task | CUST-WP-0080-T06 | progress | — | workplans/CUST-WP-0080-netkingdom-security-blueprint-and-gap-closure.md |
| task | CUST-WP-0081-T01 | done | — | workplans/CUST-WP-0081-netkingdom-architecture-review-and-reuse.md |
| task | CUST-WP-0081-T02 | done | — | workplans/CUST-WP-0081-netkingdom-architecture-review-and-reuse.md |
| task | CUST-WP-0081-T03 | done | — | workplans/CUST-WP-0081-netkingdom-architecture-review-and-reuse.md |
| task | THE-WP-0001-T01 | done | — | workplans/THE-WP-0001-federation-interface.md |
| task | THE-WP-0001-T02 | done | — | workplans/THE-WP-0001-federation-interface.md |
| intake | CUST-IN-0001 | closed | green | intake-legacy-suggestions-migration.md |
| intake | CUST-IN-0002 | closed | green | intake-legacy-suggestions-migration.md |
| intake | CUST-IN-0003 | closed | green | intake-legacy-suggestions-migration.md |
| intake | CUST-IN-0004 | routed | green | intake-legacy-suggestions-migration.md |
| intake | CUST-IN-0005 | closed | green | intake-legacy-suggestions-migration.md |
| intake | CUST-IN-0006 | closed | green | intake-legacy-suggestions-migration.md |
| intake | CUST-IN-0007 | closed | green | intake-legacy-suggestions-migration.md |
| intake | CUST-IN-0008 | closed | blue | intake-legacy-suggestions-migration.md |
| intake | CUST-IN-0009 | closed | blue | intake-legacy-suggestions-migration.md |
| intake | CUST-IN-0010 | closed | green | intake-legacy-suggestions-migration.md |
| intake | CUST-IN-0011 | routed | red | intakes.md |
| intake | CUST-IN-0012 | closed | green | intakes.md |
| intake | CUST-IN-0013 | closed | blue | intakes.md |
| intake | CUST-IN-0014 | closed | blue | intakes.md |
| intake | CUST-IN-0015 | open | blue | intakes.md |
| intake | CUST-IN-0016 | open | green | intakes.md |
| intake | CUST-IN-0017 | open | green | intakes.md |
| intake | CUST-IN-0018 | open | green | intakes.md |