Skip to content

feat: add CP-06 hardened worker proofs and scoped context retrieval - #13

Merged
0xnotdev merged 45 commits into
mainfrom
fm/factory-cp06-complete
Oct 6, 2026
Merged

0xnotdev merged 45 commits into
mainfrom
fm/factory-cp06-complete

Conversation

@0xnotdev

@0xnotdev 0xnotdev commented Oct 6, 2026 •

Copy link
Copy Markdown
Owner

Intent

Finish Factory CP-06 only as the authorized ship correction, preserving PR8-PR12 and every recovered no-mistakes fix through recovered head 75620d0 (descendant of 7b96ee6, 19e785d and 93f424c, preserving 9afae5c and all earlier ancestry). Do not implement CP-07/08, change Firstmate routing/shipping configuration, merge, deploy, or add broader product architecture. CP-06 must satisfy P-06 and P-07 with precise risk review and executable evidence, without rerunning no-mistakes from Factory itself.

Repair and validate the actual credential/isolation/evidence boundaries. All adversarial or destructive probes must use supervisor-owned literal DUMMY fixtures, fake providers/callbacks, disposable namespaces, and ignored task-local output only. Never inspect, print, hash, copy/export, mutate, refresh, or attack real credentials. Preserve the public Pi 0.85.1 SDK path with injected fail-closed read-only CredentialStore.modify/delete rejection before callbacks, refreshOnCreate:false, no default mutable CLI AuthStorage, private read-only mounts, evaluated-child empty capability sets, locked securebits, no_new_privs, and seccomp denial of mount/namespace/credential escapes. Expired and near-expiry DUMMY OAuth must have zero callback/provider/persistence entry; valid unexpired fake auth must succeed without refresh. Source/target/parent replacement, unlink/rename/symlink/hardlink, remount/unmount, namespace/UID/ptrace and subprocess escape negatives must execute at actual boundaries with no unsupported fallback. Preserve unsafe-vs-safe mutation control only inside the bounded DUMMY fixture; hardened/live paths require unchanged integrity.

Pin the task-local Pi 0.85.1 executable, package and pi-ai dependency by canonical selected paths and independently trusted npm artifact integrity, not inherited PATH, same-version metadata, self-hashes, or global fallback. Resolve pi-ai through the selected package's supported ESM import condition and reject absent/global/unrelated/substituted installs before SDK/model use. Verify selected package/dependency provenance against the tracked trusted SRI/file manifests and actual selected roots/entries. Same-version selected-file substitution must fail. Do not patch third-party/global packages or modify global auth/model configuration.

Complete descriptor-bound identity handoff at actual consumers: source/target parents and mount inputs must retain and consume descriptor identities through mount; compiled helpers/probes must be created without following leaf symlinks and retain the same identity through execution and hashing. Pin runner artifact child directories through creation/removal/write, and validate/pin the ignored task-local output boundary before compilation, rm, mkdir, or any artifact write. Replacement between preparation/check and mount/exec/write/hash must reject before external sentinel read/write/mutation/execution. Maintain evaluated-child zero capabilities and seccomp protections; native helper-level descriptor-scoped changes are authorized, but no generalized filesystem policy subsystem.

Preserve A1's exact structured outcome oracle: MISSING_SOURCE with canonical relative docs/AUTH.md; broad_scan false; one successful correlated exact-original read and byte equality; complete original may use omitted range or offset:1 plus positive limit only when returned bytes are the complete original; reject partial, forged, extra, wrong, failed, orphaned, out-of-order, credential/arbitrary paths, symlink/path races, duplicate/empty/wrong/contradictory/passed/legacy/mixed evidence, extra response prose/channels, and any nonexact nested payload. Require exactly one creation-time-ownership gap with status unverified and exactly principal-derived-owner and request-owner-ignored. Preserve canonical corrected constraints and reject extra fields/evidence channels. Guard the actual read before filesystem/provider access using pinned safe source identity.

Preserve C1 compound failure semantics through supervisor, wrapper, replay runner and blocked.json. The actual executable boundary must retain initiating setup/launch/timeout/child-exit/parse/audit/source-integrity causes plus independently awaited mount/fixture cleanup causes. Distinguish cleanup-only, audit-only, child-exit, missing-source, outer namespace ETIMEDOUT, and successful paths with correct nonzero exits. Flatten bounded nested allowlisted causes without dropping identities. Caller-visible errors, logs, manifests and blocked records must expose only sanitized typed stage/code/descriptions, never raw child stdout/stderr, arbitrary exception payloads, transcript data or DUMMY sentinel secrets. A thrown AggregateError alone is not proof: assert serialized stderr, exit status and blocked-record causes at the CLI boundary. Retain the independent PR12 regression: successful child exit plus non-JSON stdout and an independently throwing mount.cleanup must retain the initiating parse/audit cause, comparing child-exit, audit-only, cleanup-only and successful controls. Separate initiating trigger, independent cleanup condition and visible lost-cause symptom; inspect relevant history, use the smallest counterfactual, preserve disconfirming evidence, and do not reinvent already completed fixes.

Validate the complete compact DUMMY SDK proof contract before a pass: exact schema/keys, actual expired/near-expiry/valid-auth cases, callback/provider/persistence/network counts, positive control, outcome cases, fixture_origin true, semantic_acceptance false, and exact trusted selected SDK/dependency provenance. Reject omitted, empty, duplicate, contradictory, extra, forged, non-0.85.1 or arbitrary nested payloads. Fix all currently accepted findings CP06-DUMMY-SDK-PROVENANCE-FORGED, CP06-WORKER-CLEANUP-OUTPUT-ESCAPE, and CP06-DOCS-STALE-HANDOFF-GAPS: validate provenance against independently trusted pins and actual selected package paths; enforce the cleanup-proof output boundary before every write; and update stale handoff documentation to exact code-matched behavior and honest residual limits. Preserve all earlier accepted review fixes. Also FIX the already explicitly authorized CP06-HELPER-LEAF-SYMLINK-RACE and CP06-DUMMY-SDK-NESTED-PAYLOAD-STILL-FORGEABLE findings: close the compiler-write boundary against replaced leaf symlinks before external mutation, reject unknown nested sdk_worker.read_audit keys instead of retaining arbitrary child payloads, and require exact scenario-specific modify/delete denial counts rather than arbitrary nonnegative or zero values. Add executable literal-DUMMY regressions for nested forged fields, zero/arbitrary counts and leaf substitution, alongside valid controls. These fixes have Firstmate's explicit FIX decision; do not re-request approval for them. Any genuinely new ask-user finding remains Firstmate-owned and must be relayed in full. No --yes, skipped findings, duplicate run or manual code edits while pipeline custody is active.

Final-head acceptance requires npm clean install, format check, lint, typecheck, full tests, git diff checks, actual DUMMY auth/outcome/cleanup/transition controls, worker-cleanup proof, and actual executable boundary regressions. Reproduce the original offline STANDARD/HYBRID_SEMANTIC ten-pack as 10/10 relevant with zero irrelevant and its missing-source/global-only/disconfirming controls; do not relabel the separately observed STRICT_AGENT PARTIAL/CONFLICTING evidence as COMPLETE. Preserve P-07's malformed-JSON fail-before, repair/retest, and critical tenant/auth retest: absent/forged 401, own-account success, concealed nonmutating cross-account 404, principal-derived ownership, and no foreign identifier oracle.

Only after final-head DUMMY protections pass, perform the required genuine fresh semantic-worker acceptance through the already approved hardened read-only SDK/store path using existing sign-in read-only. Fixture/faux streams are not genuine semantic evidence. Never put secret material in arguments, logs, reports or tests, and never invoke a mutable default auth path, refresh, login or sign-in write. If sign-in is expired/near-expiry or unusable, block before callback/provider side effects rather than repairing auth. Successful genuine evidence must be sanitized and attributable to model source, tested SHA, dates, commands/exits, transcript hashes, tool events and complete canonical original read. Required failed/unrun acceptance remains unverified rather than passed. Keep final documentation honest, including Linux/WSL and exact-SDK limits, and obtain green CI plus independent exact-final-head security/acceptance review before landing.

Firstmate handled/004 explicitly authorizes FIX ALL eleven review findings from run 01M40XXPQJ3BCVXNQSFNZ2TX5A, including both auto-fixes and the previously authorized nested SDK payload fix. Close writable helper descriptors before actual exec to avoid ETXTBSY while retaining identity-verified read-only execution descriptors. Retain source and destination inode descriptors through actual mount, not just parent-FD/leaf names. Protect all artifact leaf writes and intermediate directories, including blocked.json, input.json, evidence.json and worker-cleanup descendants, before any redirected mutation. Pin no-follow original ancestors through initial snapshot construction; leaf O_NOFOLLOW alone is insufficient. Validate the entire assistant-message/content envelope, rejecting contradictory earlier assistant evidence and unsupported non-text final channels rather than discarding them. Validate semantic child evidence inside the supervisor cleanup action so valid JSON with an invalid contract plus cleanup failure preserves both typed causes. Execute real CLI regressions and inspect serialized stderr, exit status and persisted blocked.json for malformed-output+cleanup and semantic-audit+cleanup, child-exit+cleanup, audit-only, cleanup-only, and success controls; injected in-process serialization alone is insufficient. Sanitize event-controlled names and IDs at the SDK-worker stderr boundary with allowlisted audit reasons. Execute DUMMY ptrace/process-memory and inherited subprocess attack negatives and observe evaluated-child locked securebits. Importing serializers must be read-only and must not delete/reset existing evidence before main. Validate exact nested read_audit schemas and scenario-specific modify/delete/runtime_create/to_auth counts; reject arbitrary/zero invalid variants. Preserve all prior fixes and accepted scope without adding a generalized architecture. All these corrections already have Firstmate FIX authority; genuinely new ask-user findings still require Firstmate disposition.

Current accepted correction requirements: all nine source defects below remain blocking, already authorized FIX by Firstmate handled/004, handled/007 and handled/008. Their complete original descriptions are verbatim, not superseded or waived by earlier review/test/lint.completed flags. Preserve recovered 75620d0 and all batch1/document/format fixes. Source review must report ALL material unresolved defects, including previously known ones, rather than only new regressions; no empty findings while these remain. Use bounded 3-4-defect work units inside source review and explicit checkpoints; maintain active blocking findings for every incomplete unit. Do not route source repairs into lint. Full final-head validation only after all source defects are corrected; no skipped findings, --yes or manual edits during custody.

CP06-MOUNT-INODE-HANDOFF-INCOMPLETE | scripts/cp06-credential-isolation.mjs:129 | severity error | authorized FIX
Intent requires 'Retain source and destination inode descriptors through actual mount, not just parent-FD/leaf names'. These mount commands still consume parent-anchor/leaf destination paths, and no destination inode descriptor is retained. Replacing a leaf after preparation redirects the mount before the subsequent lstat rejection; util-linux mount also canonicalizes source descriptor paths by default. Complete the already-authorized native descriptor-bound mount handoff at this shared boundary, with actual between-preparation-and-mount substitution negatives.

CP06-ARTIFACT-LEAF-REDIRECTION | scripts/replay-cp06-worker.mjs:72 | severity error | authorized FIX
Intent requires protecting 'blocked.json, input.json, evidence.json and worker-cleanup descendants, before any redirected mutation'. Anchoring workerRoot protects its directory but ordinary writeFile follows a replaced leaf. A symlink at input.json, evidence.json or blocked.json therefore truncates an external sentinel; later fileHash can also follow a substituted leaf. Equivalent unpinned intermediate writes remain in the cleanup proof and other runners. Apply no-follow, identity-bound artifact operations at these actual consumers, rather than relying only on the parent directory anchor.

CP06-INITIAL-ORIGINAL-ANCESTOR-RACE | scripts/cp06-guarded-read.mjs:101 | severity error | authorized FIX
Intent requires 'Pin no-follow original ancestors through initial snapshot construction; leaf O_NOFOLLOW alone is insufficient'. After canonicalExactPath succeeds, replacing docs with a symlink lets openSync follow that intermediate component into an external directory. Both fstat and lstat then agree on the substituted regular file, so its bytes are read and accepted as the original snapshot. Pin and verify the original ancestor chain through the initial open, before reading any bytes.

CP06-ASSISTANT-ENVELOPE-DISCARDS-EVIDENCE | scripts/cp06-sdk-worker.mjs:227 | severity error | authorized FIX
Intent requires validating 'the entire assistant-message/content envelope' and rejecting competing earlier evidence and unsupported non-text final channels. Selecting only messages.at(-1) and filtering its content to text silently discards both. An earlier assistant claim that creation passed, followed by the valid canonical response, is accepted; a final message containing valid JSON text plus an unsupported non-text block is also accepted. Validate every assistant message and the final content envelope while preserving legitimate tool-call messages.

CP06-SEMANTIC-AUDIT-CLEANUP-CAUSE-LOSS | scripts/cp06-namespace-supervisor.mjs:142 | severity error | authorized FIX
Intent requires 'Validate the full child semantic contract inside the cleanup action'. This boundary only JSON-parses stdout. For exit 0 with {"result":"fail"} and independently failing mount.cleanup, parsing succeeds and only cleanup is reported; the replay's semantic rejection at lines 100–112 is never reached. The PR12 malformed-JSON repair is real but does not cover valid JSON with an invalid contract. Validate the complete mode-specific child contract here before either cleanup runs, preserving audit plus cleanup causes.

CP06-CLI-COMPOUND-REGRESSIONS-ABSENT | test/cp06-worker-lifecycle.test.mjs:474 | severity error | authorized FIX
Intent explicitly requires actual CLI regressions asserting 'serialized stderr, exit status and persisted blocked.json' and says injected in-process serialization is insufficient. This regression calls superviseCredentialChild, supervisorFailureRecord, namespaceWorkerError and createWorkerBlockedStatus directly without launching the affected CLI or persisting a blocked record. The cleanup proof launches only expired, near-expiry and missing-source cases. Add executable malformed-output+cleanup, semantic-audit+cleanup, child-exit+cleanup, audit-only, cleanup-only and success controls; correct the documentation's claim that these CLI regressions already exist.

CP06-AUDIT-ERROR-EVENT-DATA-LEAK | scripts/cp06-sdk-worker.mjs:117 | severity error | authorized FIX
Intent requires sanitizing event-controlled names and IDs before SDK stderr. auditReadEvents still interpolates unexpected tool names and unmatched tool-call IDs into reason; this line wraps that reason in Cp06AuthBlockedError, whose message is printed verbatim. An unexpected tool named DUMMY-SECRET therefore reaches stderr. Translate rejection reasons to allowlisted descriptions at this boundary and verify sentinel secrecy through the SDK executable.

CP06-KERNEL-PROOF-INCOMPLETE | scripts/cp06-isolation-syscalls.c:26 | severity error | authorized FIX
Intent requires executing DUMMY ptrace/process-memory and inherited-subprocess attack negatives and observing evaluated-child locked securebits. This probe only attempts namespace and mount syscalls; the adversary neither attempts ptrace/process-memory access nor reads securebits. Installing seccomp rules and passing setpriv arguments does not prove these outcomes, although docs/probes/CP-06.md claims they are proven. Execute the required DUMMY attacks and observations and require their results in assertHardenedProof.

CP06-DUMMY-SDK-NESTED-PAYLOAD-STILL-FORGEABLE | scripts/cp06-auth-security.mjs:549 | severity error | authorized FIX
The explicitly authorized exact nested-contract fix remains absent. sdk_worker.read_audit and outcome read_audit are only checked for exact_original/read_count and returned unchanged, so extra:'DUMMY-SECRET' is accepted and persisted. validateCredentialAudit accepts zero/arbitrary denial counts, and non-auth-negative outcome cases do not validate runtime_create/to_auth. This contradicts 'Validate exact nested read_audit schemas and scenario-specific modify/delete/runtime_create/to_auth counts'. Validate complete nested contracts and exact scenario expectations; replace the two-field positive fixture with the actual contract and add executable forged-field/count negatives.

Publication order: do not push, open a PR, or report completion while any of the nine source defects remains unresolved or before the full final-head deterministic suite, DUMMY namespace/SDK/kernel/executable/compound proofs, STANDARD ten-pack/P-07 reproduction and genuine hardened read-only semantic acceptance have been run and honestly recorded. Preserve 19e785d, 93f424c and 75620d0 ancestry. Validation tooling/model selection is operational only and changes no product scope.

Status at 948e785 (preserve c12d24d, 5953aea, 05c4960, 948e785): fixed CP06-INITIAL-ORIGINAL-ANCESTOR-RACE, CP06-ASSISTANT-ENVELOPE-DISCARDS-EVIDENCE, CP06-SEMANTIC-AUDIT-CLEANUP-CAUSE-LOSS, CP06-AUDIT-ERROR-EVENT-DATA-LEAK, CP06-DUMMY-SDK-NESTED-PAYLOAD-STILL-FORGEABLE, CP06-ARTIFACT-LEAF-REDIRECTION and the review follow-ups (exact read-audit paths, honest cleanup manifest, descriptor-bound anchored scratch/evaluation-home removal, pinned HOME, identity-change removal regression). Still blocking and FIX-authorized (handled/009, 011): CP06-MOUNT-INODE-HANDOFF-INCOMPLETE (fd-based open_tree/move_mount/mount_setattr handoff in the existing native helper; util-linux path canonicalization of /proc//fd anchors is also why the hardened DUMMY probe fails closed with CP06_ISOLATION_SETUP_FAILED on this host; never weaken the post-mount identity check), CP06-CLI-COMPOUND-REGRESSIONS-ABSENT, and CP06-KERNEL-PROOF-INCOMPLETE. Firstmate routes the kernel-proof unit to a separate Codex-backed fix round; it remains an open blocker until fixed and must not be waived or documented away.

fdc8321 preserves the uncommitted partial mount/CLI work of the timed-out fix turn of run 01M45P9Q8DNTVQ4A79YVW11S6K (snapshot, not validated). With it the hardened DUMMY probe passes mount setup but fails "direct syscall probe failed to execute"; review and complete it rather than discarding it, keeping the fd-based mount handoff and never weakening identity checks.

Status at fdc8321 (verified 2026-10-05 in copy16 with task-local Pi 0.85.1 SDK): all test/cp06-*.test.mjs pass 78/0/0, including fd-based mount leaf/parent substitution regressions and real-CLI compound regressions; CP06-MOUNT-INODE-HANDOFF-INCOMPLETE and CP06-CLI-COMPOUND-REGRESSIONS-ABSENT still need source review confirmation. npm run proof:cp06:auth-security exits 1 "direct syscall probe failed to execute": the hardened adversary (CapEff 0, NoNewPrivs 1, Seccomp 2) receives the probe as /proc//fd/4, which a zero-capability process cannot open, and the seccomp helper closes inherited fds >= 3, so the probe never executes. CP06-KERNEL-PROOF-INCOMPLETE remains open and FIX-authorized.

Firstmate handled/012 (current accepted form, supersedes the earlier Codex-native routing): perform the CP-06 proof-launch correction and defensive fixture verification. Repair descriptor-bound execution of the probe for the zero-capability test child without restoring capabilities, weakening seccomp/securebits, or allowing unbounded inherited descriptors. Establish actual executable-boundary DUMMY reproduction with counterfactual/disconfirming controls. All test targets must be freshly created disposable local fixture processes containing ONLY literal DUMMY bytes, with bounded cleanup; no other-user, system, real-credential or production process targets. No exploit toolkit, secret access or generalized memory-extraction capability is authorized; denial attempts are negative controls only. If a requested control cannot be implemented safely, report the exact limitation rather than bypassing safeguards. Keep required kernel controls (namespace/mount syscalls, ptrace/process-memory denial against the DUMMY fixture process, inherited subprocess repetition, evaluated-child zero capability sets, NoNewPrivs and locked securebits read back) and honest acceptance evidence; never treat an unexecuted probe as passing, and assertHardenedProof must require the executed outcomes. Preserve all earlier fixes and ancestry through fdc8321.

Status at cc86a0e (pipeline review fix commit of run 01M45XH5JBK0FSCBGGGDAZJASY, recovered after a Codex usage-limit failure): the six handled/014 findings (probe execution handoff, kernel proof, semantic contract, remaining-runner leaf redirection, DUMMY read-audit forged bytes, stale docs) were fixed and fix-review no longer lists them. Interim, non-final-head evidence at cc86a0e: proof:cp06:auth-security exit 0 pass (zero capability sets, NoNewPrivs, seccomp, securebits 15, DUMMY process-memory and inherited-subprocess denials, unsafe counterfactual holds) and test/cp06-*.test.mjs 83/0/0. Preserve the kernel/probe handoff implemented at cc86a0e; do not recreate it, and do not weaken it.

Five remaining source findings, FIX-authorized by Firstmate handled/015 and handled/016 (verbatim from the fix-review at cc86a0e):

CP06-CREDENTIAL-ANCESTOR-PREPARATION-ESCAPE | scripts/cp06-credential-isolation.mjs | severity error | authorized FIX
Intent requires protecting intermediate directories before any redirected mutation. For target /fixture/home/pi-agent/auth.json, replacing home with a symlink to an external DUMMY directory before this recursive mkdir creates pi-agent and the placeholder externally. openParent applies O_NOFOLLOW only to pi-agent, and the native helper's visible-path check likewise follows intermediate symlinks, so their identities agree on the redirected destination. Retain and consume the evaluation-home/ancestor descriptors during target preparation, including mkdir and placeholder creation; apply no-follow ancestor traversal when initially opening an unanchored source parent.

CP06-ARTIFACT-REPLACEMENT-IDENTITY-UNBOUND | scripts/cp06-probe-fixture.mjs | severity error | authorized FIX
Intent requires replacement between preparation and write/hash to reject. With replace:true, replacing the prepared AUTH-001.yaml with another single-link regular inode passes both checks: they compare the newly opened inode only with its current name, then truncate it. readAnchoredFile similarly accepts a substituted regular evidence.json; ten-pack's subsequent manifest hash can therefore describe substituted evidence without error. Carry the prepared inode or trusted digest into replacement/read operations, and use the returned write digest for freshly emitted manifests rather than reopening them without an expected identity.

CP06-WORKER-PROVENANCE-UNBOUND | scripts/cp06-worker-evidence.mjs | severity error | authorized FIX
The new supervisor validator checks provenance syntax, not the independently trusted installation. An otherwise valid child can report unrelated absolute package paths, arbitrary hexadecimal hashes, and tarball_integrity:'sha512-DUMMY-SECRET'; validation succeeds and replay persists them as passing evidence. The new DUMMY positive fixture demonstrates acceptance of invented provenance. This contradicts the requirements to verify provenance against trusted pins and actual selected paths and reject arbitrary nested payloads. Capture expected installation provenance independently in workerEvidenceContext and compare every reported provenance value inside the cleanup action; inject explicit trusted DUMMY expectations for fixture tests.

CP06-FIXTURE-SETUP-CLEANUP-CAUSE-LOSS | scripts/cp06-probe-fixture.mjs | severity error | authorized FIX
C1 requires retaining initiating setup failures plus independent fixture-cleanup failures. After tmpfs mounting succeeds, a source/setup failure enters this catch; if checkedMount(umount) also fails, its exception replaces the initiating error. The supervisor's createProbeFixture catch then serializes only a setup failure, without a cleanup cause. Preserve both failures at fixture construction and teach the supervisor's pre-action preparation catch to serialize that compound result, as its credential-mount setup path already does.

CP06-DUMMY-SDK-OUTER-REMOVAL-PATH-BASED | scripts/cp06-auth-security.mjs | severity error | authorized FIX
Intent requires pinning runner artifact directories through removal. Although this round descriptor-binds the SDK child's cleanup, the outer runner still recursively removes proofRoot by pathname. A timeout can terminate the child before its cleanup, leaving descendants; swapping one for a symlink between Node rimraf's lstat and traversal can redirect deletion into an external DUMMY directory. Retain the temporary-root/proof-root descriptors in runDummySdkProof and use removeAnchoredEntry for this outer failure cleanup too.

Firstmate handled/015 decision (current accepted form):
Decision cp06-pi-fixreview-1: review action FIX ALL FIVE in existing run01M45XH5JBK0FSCBGGGDAZJASY at cc86a0e. CP06-CREDENTIAL-ANCESTOR-PREPARATION-ESCAPE,CP06-ARTIFACT-REPLACEMENT-IDENTITY-UNBOUND,CP06-WORKER-PROVENANCE-UNBOUND,CP06-FIXTURE-SETUP-CLEANUP-CAUSE-LOSS,CP06-DUMMY-SDK-OUTER-REMOVAL-PATH-BASED. All restore accepted requirements: no redirected mutation, retained artifact identity, independently trusted provenance, initiating+cleanup causes, descriptor-bound removal. They do not add new product/security guarantees. Captain repeats DO NOT STOP UNLESS CP6 IS COMPLETE END TO END. No further routine captain approval wait is needed.

Use your exact supported active source-review command from scoped copy16 v/n/h: no-mistakes axi respond --action fix --findings CP06-CREDENTIAL-ANCESTOR-PREPARATION-ESCAPE,CP06-ARTIFACT-REPLACEMENT-IDENTITY-UNBOUND,CP06-WORKER-PROVENANCE-UNBOUND,CP06-FIXTURE-SETUP-CLEANUP-CAUSE-LOSS,CP06-DUMMY-SDK-OUTER-REMOVAL-PATH-BASED --instructions . You own respond and synchronous returns; no --yes, approve, skip, manual edit during custody, abort/restart, duplicate or lost prior fixes.

Retain evaluation-home/ancestor descriptors through actual target mkdir/placeholder creation and no-follow initial source ancestry. Bind artifact reads/replacements to prepared inode or trusted digest, and consume returned write digest for fresh manifests. Compare worker provenance to independently captured installation pins/actual selected paths INSIDE cleanup action, with trusted explicit DUMMY fixture positives and realistically forged negatives. Preserve initial setup error plus independently failed cleanup and serialize both sanitized causes. Use existing anchored descriptor-relative removal for OUTER SDK failure/timeout cleanup too, not pathname rimraf. Minimal existing-design corrections and actual-boundary DUMMY regressions; no broad platform/framework, credential access, global/shared changes or generalized exploit tools. Preserve cc86a0e and every ancestor plus controls that now pass. Interim 83 tests/security PASS cannot certify a later head; run all mandatory final-head proofs/semantic acceptance/ten-pack/P07 and full pipeline before greenPR readiness. Firstmate performs requested independent review and explicitly approved CP06 merge after verified completion. Further findings must be assessed promptly by Firstmate, not treated as captain decisions by default; send full evidence/exact command and continue immediately after answer. Matching resolved acknowledgement required, resume NOW.

Firstmate handled/016: run 01M45XH5JBK0FSCBGGGDAZJASY failed on a Codex usage limit before fixing the five. Custody was recovered at cc86a0e. This fresh full source-review run from cc86a0e (native Claude validator) supersedes the respond command above: fix all five findings in SOURCE REVIEW, in bounded units, using DUMMY fixtures only. Preserve cc86a0e and every ancestor.

Sixth in-scope finding (auto-fix, same accepted mechanism, FIX-authorized under handled/016):
CP06-PROBE-FIXTURE-CLEANUP-PATH-RM | scripts/cp06-probe-fixture.mjs | severity warning
Fixture cleanup used pathname-based recursive removal: after umount, rm(directory, {recursive, force}) (in normal cleanup and in the setup catch) removed the DUMMY-probe-* directory by path instead of through the retained output.anchor, although removeAnchoredEntry already exists in this file. Cleanup was also not exception-safe: if the alias or directory umount threw, sourceFd, sourceDirFd, agentDirFd, rootFd and the output descriptor were never closed and no other cleanup step ran or was reported. Required: existing anchored descriptor-relative removal through output.anchor, plus exception-safe fixture cleanup that closes every retained descriptor and reports every failed step as a sanitized cause.

Recovery state (current accepted form, Firstmate 2026-10-06 relaunch): run 01M465TS9M0J1KCERVPWF6GHBY (fresh run from cc86a0e under handled/016) produced fix commit 76e4783 "Bind CP06 ancestry, artifact identity, provenance, and cleanup causes" for all six findings above before the host rebooted; its dedicated daemon restart reconciled the run to failed ("daemon crashed during execution") and supported no-mistakes axi sync --recover returned custody, equal/clean at 76e4783 with cc86a0e and every ancestor preserved. This fresh full source-review run from 76e4783 must independently verify, against the code, that each of the six findings (CP06-CREDENTIAL-ANCESTOR-PREPARATION-ESCAPE, CP06-ARTIFACT-REPLACEMENT-IDENTITY-UNBOUND, CP06-WORKER-PROVENANCE-UNBOUND, CP06-FIXTURE-SETUP-CLEANUP-CAUSE-LOSS, CP06-DUMMY-SDK-OUTER-REMOVAL-PATH-BASED, CP06-PROBE-FIXTURE-CLEANUP-PATH-RM) is actually resolved with an actual-boundary DUMMY regression and passing control; re-raise any that is not, and fix in SOURCE REVIEW (not lint) in bounded units, DUMMY fixtures only. A fix commit existing is not proof of resolution. Interim worker evidence at 76e4783 (not final-head certification): 90/90 test/cp06-*.test.mjs pass, npm run proof:cp06:auth-security exit 0 with task-local pinned SDK. Preserve 76e4783, cc86a0e and every ancestor; no reset/discard/abort-restart, --yes, skip/approve of unresolved findings, or duplicate runs. Full exact-final-head tests/format/lint/typecheck, hardened DUMMY auth/SDK/kernel/executable/compound controls, original STANDARD ten-pack 10/10 and P-07 repair/retest, and genuine hardened read-only pinned-SDK semantic acceptance remain mandatory before green PR; STRICT_AGENT partial/conflicting evidence must be disclosed honestly. Firstmate performs the captain-requested independent exact-head review and CP06 merge; the worker never merges. No CP-07/08 implementation.

Later accepted state and decisions (current form, 2026-10-06):

  • Run 01M47V1C2VY8W9C6Y10RAYZBW2 from 76e4783 verified five of the six fixes above and raised four more, all fixed per Firstmate handled/017: CP06-SUPERVISOR-PROVENANCE-RESOLUTION-UNFLAGGED, CP06-SUPERVISOR-EXECUTES-PI-UNHARDENED, CP06-PROVENANCE-SETUP-MISLABELED-AUDIT, and CP06-NOFOLLOW-WALK-REJECTS-LEGIT-SOURCE-ANCESTORS (option A: keep strict no-follow ancestor traversal and document that symlinked or search-only credential-source ancestors are unsupported and rejected before any secret access or mutation; no realpath/canonicalization relaxation). Commits 00321e0, b21a39b and the CI fix b9bfceb, checks-passed on PR 13. Preserve all of them.
  • Independent exact-head audit of b9bfceb (Firstmate handled/018) found one blocking mismatch, R2: the guard (createGuardedReadTool/assertAllowedRead) and auditReadEvents accepted an explicit {offset:1, limit:N} range that returned the complete bytes, contrary to the accepted R1-R3 requirement "exact original, one complete read, no offset/limit". Required minimal correction, now in follow-up commit a8c4c3d on top of b9bfceb: unconditionally reject the presence of offset OR limit before the read executes and independently at the event-audit boundary; keep the worker instruction exact ("use the read tool exactly once, without offset or limit"); make the documentation exact; restore negative guard and audit tests (including the SDK first-line range with complete bytes) plus the full unbounded positive; add ranged-call rejections through the guard around the pinned SDK's actual read tool in the DUMMY SDK proof. Unknown/partial/failed/event controls stay unchanged. This is not full-byte equivalence and must not be waived as such; no architecture, auth or compatibility expansion.
  • This run validates the follow-up as post-pipeline work on top of b9bfceb, published to the existing PR 13 (no duplicate PR). The earlier green CI monitor does not certify this new head. Final-head deterministic tests (170+)/format/lint/typecheck/diff, hardened DUMMY security and cleanup proofs, STANDARD ten-pack and P-07, and genuine hardened read-only semantic acceptance under the original no-offset/no-limit restriction are rerun at the new final head, followed by the independent bounded retest and the Firstmate merge. The worker never merges.

What Changed

  • src/core/context.ts now passes the task's required documents to ctx pack, or the project's required documents when the task lists none, as --document arguments. Context generation blocks with RETRIEVAL_SCOPE_INVALID when a selected document doesn't match a validated mandatory source. It blocks with RETRIEVAL_SCOPE_WIDENED when an excerpt comes from outside that selection. test/context.test.ts covers both cases.
  • Adds the CP-06 proof harness under scripts/cp06-* and scripts/replay-*/prove-*, with new proof:cp06:* npm scripts:
    • Pinned SDK: uses the task-local Pi 0.85.1 SDK, with package and dependency provenance checked against .factory/cp06-sdk-integrity.json.
    • Credential isolation: a read-only credential store and descriptor-bound private mounts. A native helper (cp06-seccomp-exec.c, cp06-isolation-syscalls.c) runs the evaluated child with empty capability sets, locked securebits, no_new_privs and seccomp.
    • Guarded read: an exact-original read that rejects any offset or limit.
    • Worker supervision: a namespace supervisor that keeps the initiating failure and the cleanup failure as sanitized typed causes, plus no-follow, identity-bound artifact writes and removal.
    • Replays and proofs: the offline STANDARD ten-pack, the P-07 repair/retest, the worker cleanup proof and the DUMMY auth/security proof.
  • Adds DUMMY-only tests and fixtures:
    • test/cp06-*.test.mjs, the test/fixtures/cp06-context ten-pack project and the P-07 workflow fixtures with test/workflow.test.ts.
    • npm test now also runs the .mjs tests.
    • CI lifts the AppArmor restriction on unprivileged user namespaces.

... (body truncated to keep the PR body within GitHub's 65536-char limit.)

Risk Assessment

✅ Low: The follow-up commit a8c4c3d is a small tightening that fails closed. The guard and the event audit now reject any offset/limit key before the read and independently at the audit. Negative tests restore the SDK first-line range, the unbounded positive remains, and the faux SDK positive still runs through the real session and audit. The four earlier fixes I spot-checked also match the accepted decisions: unflagged supervisor resolution, Pi no longer executed while privileged, setup-versus-audit classification, and the strict no-follow walk.

Testing

I installed the dependencies and the pinned task-local Pi 0.85.1 SDK, then ran the targeted guard and audit tests at a8c4c3d (all pass) and against the pre-fix b9bfceb code (the new range tests fail). A DUMMY-only harness wrapped the pinned SDK's real read tool to show the before/after: b9bfceb executed an {offset:1, limit:2000} read and returned the complete bytes, while a8c4c3d rejects that range and also offset-only and limit-only; the unranged complete read still succeeds. The hardened DUMMY auth-security proof, the worker-cleanup proof and the worker-lifecycle tests all pass. I touched no real credentials and removed all transient installs and outputs from the worktree afterwards. Everything passed; final-head CI/format/lint, the ten-pack and P-07 runs, and genuine semantic acceptance are owned by other phases.

Evidence: Guarded read around pinned Pi 0.85.1 SDK read tool: fix vs pre-fix (DUMMY data)

== guard from a8c4c3d (fix) wrapping pinned SDK read tool == {} -> EXECUTED, returned "# DUMMY original\nDUMMY line two\n" {"offset":1,"limit":2000} -> REJECTED: read denied: the original must be read without offset or limit {"offset":1} -> REJECTED: read denied: the original must be read without offset or limit {"limit":2000} -> REJECTED: read denied: the original must be read without offset or limit == guard from b9bfceb (pre-fix counterfactual) == {} -> EXECUTED {"offset":1,"limit":2000} -> EXECUTED, returned complete original {"offset":1} -> REJECTED: incomplete explicit range {"limit":2000} -> REJECTED: incomplete explicit range

== guard from a8c4c3d (fix) wrapping pinned SDK read tool ==
{} -> EXECUTED, returned "# DUMMY original\nDUMMY line two\n"
{"offset":1,"limit":2000} -> REJECTED: read denied: the original must be read without offset or limit
{"offset":1} -> REJECTED: read denied: the original must be read without offset or limit
{"limit":2000} -> REJECTED: read denied: the original must be read without offset or limit

== guard from b9bfceb (pre-fix counterfactual) wrapping pinned SDK read tool ==
{} -> EXECUTED, returned "# DUMMY original\nDUMMY line two\n"
{"offset":1,"limit":2000} -> EXECUTED, returned "# DUMMY original\nDUMMY line two\n"
{"offset":1} -> REJECTED: read denied: incomplete explicit range
{"limit":2000} -> REJECTED: read denied: incomplete explicit range
Evidence: New guard/audit tests run against pre-fix b9bfceb code (2 expected failures)
✖ guarded read denies noncanonical and unauthorized paths before tool access (13.609583ms)
✔ worker paths reject symlink escapes and credential overlap (8.204226ms)
✔ initial original snapshot does not follow a substituted ancestor directory (7.619973ms)
✔ worker read audit rejects omitted completion (2.398842ms)
✔ worker read audit rejects stub failed read completion (1.943237ms)
✔ worker read audit rejects partial read (0.485336ms)
✔ worker read audit rejects explicit first-line offset with complete bytes (0.455418ms)
✔ worker read audit rejects explicit limit with complete bytes (0.303767ms)
✔ worker read audit rejects wrong starting range (0.180149ms)
✔ worker read audit rejects mismatched completion id (0.176463ms)
✔ worker read audit rejects completion before start (0.166401ms)
✔ worker read audit rejects response before completion (0.350579ms)
✔ worker read audit rejects orphan non-read completion (0.449635ms)
✔ worker read audit rejects another project read (0.313365ms)
✔ worker missing-source identity accepts only the canonical original path (0.310051ms)
✔ worker read audit accepts one completed exact-original read without offset or limit (0.284551ms)
✖ worker read audit rejects the SDK first-line range even when it returns the complete original (1.589446ms)
✔ worker read audit rejects an explicit offset even when it returns the complete original (0.237971ms)
✔ worker read audit rejects an explicit limit even when it returns the complete original (0.222793ms)
✔ worker read audit reasons never carry event-controlled names or IDs (0.44349ms)
✔ assistant envelope rejects competing evidence and unsupported final channels (1.360814ms)
ℹ tests 21
ℹ suites 0
ℹ pass 19
ℹ fail 2
ℹ cancelled 0
ℹ skipped 0
ℹ todo 0
ℹ duration_ms 105.198767

✖ failing tests:

test at test/cp06-guarded-read.test.mjs:12:1
✖ guarded read denies noncanonical and unauthorized paths before tool access (13.609583ms)
  AssertionError [ERR_ASSERTION]: Missing expected rejection.
      at async TestContext.<anonymous> (file:///tmp/tmp.BwdBu3hnjx/test/cp06-guarded-read.test.mjs:57:7)
      at async Test.run (node:internal/test_runner/test:1404:7)
      at async startSubtestAfterBootstrap (node:internal/test_runner/harness:387:3) {
    generatedMessage: false,
    code: 'ERR_ASSERTION',
    actual: undefined,
    expected: undefined,
    operator: 'rejects',
    diff: 'simple'
  }

test at test/cp06-worker-audit.test.mjs:199:3
✖ worker read audit rejects the SDK first-line range even when it returns the complete original (1.589446ms)
  AssertionError [ERR_ASSERTION]: Expected values to be strictly equal:
  
  true !== false
  
      at TestContext.<anonymous> (file:///tmp/tmp.BwdBu3hnjx/test/cp06-worker-audit.test.mjs:204:12)
      at Test.runInAsyncScope (node:async_hooks:227:14)
      at Test.run (node:internal/test_runner/test:1397:25)
      at Test.processPendingSubtests (node:internal/test_runner/test:969:18)
      at Test.postRun (node:internal/test_runner/test:1537:19)
      at Test.run (node:internal/test_runner/test:1462:12)
      at async Test.processPendingSubtests (node:internal/test_runner/test:969:7) {
    generatedMessage: true,
    code: 'ERR_ASSERTION',
    actual: true,
    expected: false,
    operator: 'strictEqual',
    diff: 'simple'
  }
Evidence: Guard/audit tests at a8c4c3d
✔ guarded read denies noncanonical and unauthorized paths before tool access (14.546061ms)
✔ worker paths reject symlink escapes and credential overlap (7.71905ms)
✔ initial original snapshot does not follow a substituted ancestor directory (6.375076ms)
✔ worker read audit rejects omitted completion (1.533293ms)
✔ worker read audit rejects stub failed read completion (0.258919ms)
✔ worker read audit rejects partial read (0.213635ms)
✔ worker read audit rejects explicit first-line offset with complete bytes (0.366541ms)
✔ worker read audit rejects explicit limit with complete bytes (0.218536ms)
✔ worker read audit rejects wrong starting range (0.185531ms)
✔ worker read audit rejects mismatched completion id (0.263534ms)
✔ worker read audit rejects completion before start (0.186771ms)
✔ worker read audit rejects response before completion (0.374004ms)
✔ worker read audit rejects orphan non-read completion (3.58375ms)
✔ worker read audit rejects another project read (0.508545ms)
✔ worker missing-source identity accepts only the canonical original path (0.504523ms)
✔ worker read audit accepts one completed exact-original read without offset or limit (0.309374ms)
✔ worker read audit rejects the SDK first-line range even when it returns the complete original (0.266475ms)
✔ worker read audit rejects an explicit offset even when it returns the complete original (0.261592ms)
✔ worker read audit rejects an explicit limit even when it returns the complete original (0.188639ms)
✔ worker read audit reasons never carry event-controlled names or IDs (0.401644ms)
✔ assistant envelope rejects competing evidence and unsupported final channels (1.135301ms)
ℹ tests 21
ℹ suites 0
ℹ pass 21
ℹ fail 0
ℹ cancelled 0
ℹ skipped 0
ℹ todo 0
ℹ duration_ms 88.532114
Evidence: Hardened DUMMY auth-security proof output (exit 0, pass)
npm notice run @factory/core@0.0.0-cp00 proof:cp06:auth-security
npm notice run node --experimental-import-meta-resolve scripts/prove-cp06-auth-security.mjs
{"ok":true,"gate":"CP-06-read-only-auth-security","evidence_path":".factory/state/cp06-correction/auth-security/evidence.json","result":"pass"}
Evidence: Auth-security evidence.json at a8c4c3d
{
  "schema_version": 1,
  "gate": "CP-06-read-only-auth-security",
  "result": "pass",
  "tested_sha": "a8c4c3d5588a2e5bc19dd93a3bc1068f5fc850f8",
  "recorded_at": "2026-10-06T07:04:19.748Z",
  "reviewer": "Pi CP-06 read-only auth correction worker",
  "command": "npm run proof:cp06:auth-security",
  "exit_code": 0,
  "pi_version": "0.85.1",
  "pi_install": {
    "install_root": "/home/ansh/.treehouse/Factory-86709f/16/Factory/.factory/state/w/01M4803EZXB3KN751C0H6QNYNV/.factory/state/cp06-sdk",
    "package_root": "/home/ansh/.treehouse/Factory-86709f/16/Factory/.factory/state/w/01M4803EZXB3KN751C0H6QNYNV/.factory/state/cp06-sdk/node_modules/@earendil-works/pi-coding-agent",
    "package_artifact": {
      "manifest_sha256": "ff28a78bb025ee9fc182929f8eec27908f5e20870a5b7d8b1b37a1ded8507ecf",
      "tarball_integrity": "sha512-FGRN+OHbWaefBPGaTggAdLjrIHW+s2PzLyglz/5dfLzb9of7uuXMXYC0fJIeZTw+shS32o2cuQ9jF7YSDuL/oQ=="
    },
    "dependency": {
      "manifest_sha256": "3e1894e3f18b90f39c068cd0815f8559083c382e7d343efd1f961a8f07b0cefc",
      "tarball_integrity": "sha512-+VgVIJDkDO2efYJKEEqvPTH4zmnIaXdAppGbO+vKFA9qy5PdhFiAenuFAkU+oiCSfOC4dMHDyrjdQeL4ZoC5CQ==",
      "name": "@earendil-works/pi-ai",
      "version": "0.85.1",
      "root": "/home/ansh/.treehouse/Factory-86709f/16/Factory/.factory/state/w/01M4803EZXB3KN751C0H6QNYNV/.factory/state/cp06-sdk/node_modules/@earendil-works/pi-ai",
      "entry": "/home/ansh/.treehouse/Factory-86709f/16/Factory/.factory/state/w/01M4803EZXB3KN751C0H6QNYNV/.factory/state/cp06-sdk/node_modules/@earendil-works/pi-ai/dist/index.js",
      "resolution": "esm-import-condition",
      "package_sha256": "b54df5a36d523febdeebfc5682dc4faed101fee10aba913d5f3679582f018da3",
      "entry_sha256": "010778daab84fd68b88507d6cd2c4ff1fc1f2efe230e096100eebff98d5183a5"
    },
    "executable": "/home/ansh/.treehouse/Factory-86709f/16/Factory/.factory/state/w/01M4803EZXB3KN751C0H6QNYNV/.factory/state/cp06-sdk/node_modules/.bin/pi",
    "executable_entry": "/home/ansh/.treehouse/Factory-86709f/16/Factory/.factory/state/w/01M4803EZXB3KN751C0H6QNYNV/.factory/state/cp06-sdk/node_modules/@earendil-works/pi-coding-agent/dist/bundle/cli.js",
    "sdk_entry": "/home/ansh/.treehouse/Factory-86709f/16/Factory/.factory/state/w/01M4803EZXB3KN751C0H6QNYNV/.factory/state/cp06-sdk/node_modules/@earendil-works/pi-coding-agent/dist/index.js",
    "package_sha256": "f1738e4b42203e5f22bcb513f13fb2fb224f1e98d1f129ff042f87048665a94c",
    "executable_sha256": "e6d7fcf36a239cf3746e67ddf4222081ac01a601b85a3ee688bdfe9c161d754c",
    "sdk_entry_sha256": "82cb4ea864f3d8816c06bc8f2f2d9a8d82d883297af179dc69d287d042834844"
  },
  "platform": {
    "os": "linux",
    "architecture": "x64",
    "kernel": "6.18.33.2-microsoft-standard-WSL2",
    "user_mount_namespace": true,
    "libseccomp": true
  },
  "binaries": {
    "seccomp_helper_sha256": "acdd0a8106ab3cf5fe748ebf02468a5fb0961c5a92a736a03d3cfaf0210686dc",
    "syscall_probe_sha256": "473cd25786748983d92b4df478996090bcc12adf565f348486f833eddccc1af6"
  },
  "unsafe_control": {
    "retained_capabilities": "000001ffffffffff",
    "remount_succeeded": true,
    "unmount_succeeded": true,
    "parent_bind_succeeded": true,
    "dummy_source_changed": true
  },
  "hardened_child": {
    "capability_sets_zero": true,
    "no_new_privs": true,
    "seccomp_filter": true,
    "locked_root_securebits": 15,
    "dummy_process_memory_denials": true,
    "inherited_subprocess_denials": true,
    "dummy_process_target_unchanged": true,
    "ordinary_child_allowed": true,
    "direct_writes_denied": true,
    "replacement_denied": true,
    "remount_unmount_denied": true,
    "namespace_entry_creation_denied": true,
    "uid_change_denied": true,
    "alternate_parent_bind_denied": true,
    "credential_parent_roots_read_only": true,
    "dedicated_scratch_writable": true,
    "dummy_source_unchanged": true
  },
  "dummy_sdk": {
    "schema_version": 1,
    "result": "pass",
    "auth_cases": [
      {
        "scenario": "expired",
        "result": "blocked",
        "refresh_callbacks": 0,
        "to_auth_calls": 0,
        "credential_store": {
          "reads": 1,
          "lists": 0,
          "modify_denials": 1,
          "delete_denials": 0
        },
        "persistence_operations": 0,
        "source_unchanged": true
      },
      {
        "scenario": "near_expiry",
        "result": "blocked",
        "refresh_callbacks": 0,
        "to_auth_calls": 0,
        "credential_store": {
          "reads": 1,
          "lists": 0,
          "modify_denials": 1,
          "delete_denials": 0
        },
        "persistence_operations": 0,
        "source_unchanged": true
      },
      {
        "scenario": "unexpired",
        "result": "resolved",
        "refresh_callbacks": 0,
        "to_auth_calls": 1,
        "credential_store": {
          "reads": 1,
          "lists": 0,
          "modify_denials": 0,
          "delete_denials": 0
        },
        "persistence_operations": 0,
        "source_unchanged": true
      }
    ],
    "sdk_worker": {
      "active_tools": [
        "read"
      ],
      "in_memory_session": true,
      "event_count": 28,
      "event_sha256": "9aa7bdcc803f70dbf5d87597c6ea5576e7083072257d4733c43c058e7afe671b",
      "read_audit": {
        "read_count": 1,
        "project_read_count": 1,
        "project_read_paths": [
          "/tmp/factory-cp06-DUMMY-sdk-Gxym8J/DUMMY-worker/DUMMY-original.md"
        ],
        "rejected_read_paths": [],
        "other_tool_calls": [],
        "other_tool_completions": [],
        "completed_successfully": true,
        "exact_original": true,
        "expected_sha256": "de2a93a26588002754bceb3bab5578cf51ff5882e1c40e31a55ae6b00abf63d0",
        "returned_sha256": "de2a93a26588002754bceb3bab5578cf51ff5882e1c40e31a55ae6b00abf63d0",
        "returned_bytes": 117,
        "tool_call_id": "DUMMY-read",
        "start_event_index": 13,
        "end_event_index": 14,
        "response_event_index": 24
      },
      "refresh_callbacks": 0,
      "credential_store": {
        "reads": 203,
        "lists": 1,
        "modify_denials": 0,
        "delete_denials": 0
      }
    },
    "sdk_dependency": {
      "manifest_sha256": "3e1894e3f18b90f39c068cd0815f8559083c382e7d343efd1f961a8f07b0cefc",
      "tarball_integrity": "sha512-+VgVIJDkDO2efYJKEEqvPTH4zmnIaXdAppGbO+vKFA9qy5PdhFiAenuFAkU+oiCSfOC4dMHDyrjdQeL4ZoC5CQ==",
      "name": "@earendil-works/pi-ai",
      "version": "0.85.1",
      "root": "/home/ansh/.treehouse/Factory-86709f/16/Factory/.factory/state/w/01M4803EZXB3KN751C0H6QNYNV/.factory/state/cp06-sdk/node_modules/@earendil-works/pi-ai",
      "entry": "/home/ansh/.treehouse/Factory-86709f/16/Factory/.factory/state/w/01M4803EZXB3KN751C0H6QNYNV/.factory/state/cp06-sdk/node_modules/@earendil-works/pi-ai/dist/index.js",
      "resolution": "esm-import-condition",
      "package_sha256": "b54df5a36d523febdeebfc5682dc4faed101fee10aba913d5f3679582f018da3",
      "entry_sha256": "010778daab84fd68b88507d6cd2c4ff1fc1f2efe230e096100eebff98d5183a5"
    },
    "actual_sdk_outcomes": {
      "fixture_origin": true,
      "semantic_acceptance": false,
      "cases": [
        {
          "scenario": "valid",
          "exit_code": 0,
          "expected_exit_code": 0,
          "fixture_origin": true,
          "sdk_dependency": {
            "manifest_sha256": "3e1894e3f18b90f39c068cd0815f8559083c382e7d343efd1f961a8f07b0cefc",
            "tarball_integrity": "sha512-+VgVIJDkDO2efYJKEEqvPTH4zmnIaXdAppGbO+vKFA9qy5PdhFiAenuFAkU+oiCSfOC4dMHDyrjdQeL4ZoC5CQ==",
            "name": "@earendil-works/pi-ai",
            "version": "0.85.1",
            "root": "/home/ansh/.treehouse/Factory-86709f/16/Factory/.factory/state/w/01M4803EZXB3KN751C0H6QNYNV/.factory/state/cp06-sdk/node_modules/@earendil-works/pi-ai",
            "entry": "/home/ansh/.treehouse/Factory-86709f/16/Factory/.factory/state/w/01M4803EZXB3KN751C0H6QNYNV/.factory/state/cp06-sdk/node_modules/@earendil-works/pi-ai/dist/index.js",
            "resolution": "esm-import-condition",
            "package_sha256": "b54df5a36d523febdeebfc5682dc4faed101fee10aba913d5f3679582f018da3",


... [14869 bytes truncated] ...

00eebff98d5183a5"
          },
          "default_storage": 0,
          "network": 0,
          "refresh": 0,
          "to_auth": 3,
          "runtime_create": 1,
          "exit": 75,
          "source_unchanged": true
        },
        {
          "scenario": "earlier-assistant-claim",
          "exit_code": 75,
          "expected_exit_code": 75,
          "fixture_origin": true,
          "sdk_dependency": {
            "manifest_sha256": "3e1894e3f18b90f39c068cd0815f8559083c382e7d343efd1f961a8f07b0cefc",
            "tarball_integrity": "sha512-+VgVIJDkDO2efYJKEEqvPTH4zmnIaXdAppGbO+vKFA9qy5PdhFiAenuFAkU+oiCSfOC4dMHDyrjdQeL4ZoC5CQ==",
            "name": "@earendil-works/pi-ai",
            "version": "0.85.1",
            "root": "/home/ansh/.treehouse/Factory-86709f/16/Factory/.factory/state/w/01M4803EZXB3KN751C0H6QNYNV/.factory/state/cp06-sdk/node_modules/@earendil-works/pi-ai",
            "entry": "/home/ansh/.treehouse/Factory-86709f/16/Factory/.factory/state/w/01M4803EZXB3KN751C0H6QNYNV/.factory/state/cp06-sdk/node_modules/@earendil-works/pi-ai/dist/index.js",
            "resolution": "esm-import-condition",
            "package_sha256": "b54df5a36d523febdeebfc5682dc4faed101fee10aba913d5f3679582f018da3",
            "entry_sha256": "010778daab84fd68b88507d6cd2c4ff1fc1f2efe230e096100eebff98d5183a5"
          },
          "default_storage": 0,
          "network": 0,
          "refresh": 0,
          "to_auth": 3,
          "runtime_create": 1,
          "exit": 75,
          "source_unchanged": true
        },
        {
          "scenario": "final-extra-channel",
          "exit_code": 75,
          "expected_exit_code": 75,
          "fixture_origin": true,
          "sdk_dependency": {
            "manifest_sha256": "3e1894e3f18b90f39c068cd0815f8559083c382e7d343efd1f961a8f07b0cefc",
            "tarball_integrity": "sha512-+VgVIJDkDO2efYJKEEqvPTH4zmnIaXdAppGbO+vKFA9qy5PdhFiAenuFAkU+oiCSfOC4dMHDyrjdQeL4ZoC5CQ==",
            "name": "@earendil-works/pi-ai",
            "version": "0.85.1",
            "root": "/home/ansh/.treehouse/Factory-86709f/16/Factory/.factory/state/w/01M4803EZXB3KN751C0H6QNYNV/.factory/state/cp06-sdk/node_modules/@earendil-works/pi-ai",
            "entry": "/home/ansh/.treehouse/Factory-86709f/16/Factory/.factory/state/w/01M4803EZXB3KN751C0H6QNYNV/.factory/state/cp06-sdk/node_modules/@earendil-works/pi-ai/dist/index.js",
            "resolution": "esm-import-condition",
            "package_sha256": "b54df5a36d523febdeebfc5682dc4faed101fee10aba913d5f3679582f018da3",
            "entry_sha256": "010778daab84fd68b88507d6cd2c4ff1fc1f2efe230e096100eebff98d5183a5"
          },
          "default_storage": 0,
          "network": 0,
          "refresh": 0,
          "to_auth": 4,
          "runtime_create": 1,
          "exit": 75,
          "source_unchanged": true
        },
        {
          "scenario": "unexpected-tool-secret",
          "exit_code": 75,
          "expected_exit_code": 75,
          "fixture_origin": true,
          "sdk_dependency": {
            "manifest_sha256": "3e1894e3f18b90f39c068cd0815f8559083c382e7d343efd1f961a8f07b0cefc",
            "tarball_integrity": "sha512-+VgVIJDkDO2efYJKEEqvPTH4zmnIaXdAppGbO+vKFA9qy5PdhFiAenuFAkU+oiCSfOC4dMHDyrjdQeL4ZoC5CQ==",
            "name": "@earendil-works/pi-ai",
            "version": "0.85.1",
            "root": "/home/ansh/.treehouse/Factory-86709f/16/Factory/.factory/state/w/01M4803EZXB3KN751C0H6QNYNV/.factory/state/cp06-sdk/node_modules/@earendil-works/pi-ai",
            "entry": "/home/ansh/.treehouse/Factory-86709f/16/Factory/.factory/state/w/01M4803EZXB3KN751C0H6QNYNV/.factory/state/cp06-sdk/node_modules/@earendil-works/pi-ai/dist/index.js",
            "resolution": "esm-import-condition",
            "package_sha256": "b54df5a36d523febdeebfc5682dc4faed101fee10aba913d5f3679582f018da3",
            "entry_sha256": "010778daab84fd68b88507d6cd2c4ff1fc1f2efe230e096100eebff98d5183a5"
          },
          "default_storage": 0,
          "network": 0,
          "refresh": 0,
          "to_auth": 3,
          "runtime_create": 1,
          "exit": 75,
          "source_unchanged": true
        },
        {
          "scenario": "expired",
          "exit_code": 75,
          "expected_exit_code": 75,
          "fixture_origin": true,
          "sdk_dependency": {
            "manifest_sha256": "3e1894e3f18b90f39c068cd0815f8559083c382e7d343efd1f961a8f07b0cefc",
            "tarball_integrity": "sha512-+VgVIJDkDO2efYJKEEqvPTH4zmnIaXdAppGbO+vKFA9qy5PdhFiAenuFAkU+oiCSfOC4dMHDyrjdQeL4ZoC5CQ==",
            "name": "@earendil-works/pi-ai",
            "version": "0.85.1",
            "root": "/home/ansh/.treehouse/Factory-86709f/16/Factory/.factory/state/w/01M4803EZXB3KN751C0H6QNYNV/.factory/state/cp06-sdk/node_modules/@earendil-works/pi-ai",
            "entry": "/home/ansh/.treehouse/Factory-86709f/16/Factory/.factory/state/w/01M4803EZXB3KN751C0H6QNYNV/.factory/state/cp06-sdk/node_modules/@earendil-works/pi-ai/dist/index.js",
            "resolution": "esm-import-condition",
            "package_sha256": "b54df5a36d523febdeebfc5682dc4faed101fee10aba913d5f3679582f018da3",
            "entry_sha256": "010778daab84fd68b88507d6cd2c4ff1fc1f2efe230e096100eebff98d5183a5"
          },
          "default_storage": 0,
          "network": 0,
          "refresh": 0,
          "to_auth": 0,
          "runtime_create": 0,
          "exit": 75,
          "source_unchanged": true
        },
        {
          "scenario": "near-expiry",
          "exit_code": 75,
          "expected_exit_code": 75,
          "fixture_origin": true,
          "sdk_dependency": {
            "manifest_sha256": "3e1894e3f18b90f39c068cd0815f8559083c382e7d343efd1f961a8f07b0cefc",
            "tarball_integrity": "sha512-+VgVIJDkDO2efYJKEEqvPTH4zmnIaXdAppGbO+vKFA9qy5PdhFiAenuFAkU+oiCSfOC4dMHDyrjdQeL4ZoC5CQ==",
            "name": "@earendil-works/pi-ai",
            "version": "0.85.1",
            "root": "/home/ansh/.treehouse/Factory-86709f/16/Factory/.factory/state/w/01M4803EZXB3KN751C0H6QNYNV/.factory/state/cp06-sdk/node_modules/@earendil-works/pi-ai",
            "entry": "/home/ansh/.treehouse/Factory-86709f/16/Factory/.factory/state/w/01M4803EZXB3KN751C0H6QNYNV/.factory/state/cp06-sdk/node_modules/@earendil-works/pi-ai/dist/index.js",
            "resolution": "esm-import-condition",
            "package_sha256": "b54df5a36d523febdeebfc5682dc4faed101fee10aba913d5f3679582f018da3",
            "entry_sha256": "010778daab84fd68b88507d6cd2c4ff1fc1f2efe230e096100eebff98d5183a5"
          },
          "default_storage": 0,
          "network": 0,
          "refresh": 0,
          "to_auth": 0,
          "runtime_create": 0,
          "exit": 75,
          "source_unchanged": true
        },
        {
          "scenario": "timeout",
          "exit_code": 70,
          "expected_exit_code": 70,
          "fixture_origin": true,
          "sdk_dependency": {
            "manifest_sha256": "3e1894e3f18b90f39c068cd0815f8559083c382e7d343efd1f961a8f07b0cefc",
            "tarball_integrity": "sha512-+VgVIJDkDO2efYJKEEqvPTH4zmnIaXdAppGbO+vKFA9qy5PdhFiAenuFAkU+oiCSfOC4dMHDyrjdQeL4ZoC5CQ==",
            "name": "@earendil-works/pi-ai",
            "version": "0.85.1",
            "root": "/home/ansh/.treehouse/Factory-86709f/16/Factory/.factory/state/w/01M4803EZXB3KN751C0H6QNYNV/.factory/state/cp06-sdk/node_modules/@earendil-works/pi-ai",
            "entry": "/home/ansh/.treehouse/Factory-86709f/16/Factory/.factory/state/w/01M4803EZXB3KN751C0H6QNYNV/.factory/state/cp06-sdk/node_modules/@earendil-works/pi-ai/dist/index.js",
            "resolution": "esm-import-condition",
            "package_sha256": "b54df5a36d523febdeebfc5682dc4faed101fee10aba913d5f3679582f018da3",
            "entry_sha256": "010778daab84fd68b88507d6cd2c4ff1fc1f2efe230e096100eebff98d5183a5"
          },
          "default_storage": 0,
          "network": 0,
          "refresh": 0,
          "to_auth": 2,
          "runtime_create": 1,
          "exit": 70,
          "source_unchanged": true
        }
      ]
    },
    "fixture_origin": true,
    "semantic_acceptance": false,
    "network_calls": 0
  }
}
Evidence: DUMMY worker-cleanup proof (9 cases, exit 0)
npm notice run @factory/core@0.0.0-cp00 proof:cp06:worker-cleanup
npm notice run node scripts/prove-cp06-worker-cleanup.mjs
{"result":"pass","gate":"CP06-DUMMY-worker-cleanup","tested_sha":"a8c4c3d5588a2e5bc19dd93a3bc1068f5fc850f8","cases":[{"scenario":"expired","exit_code":75,"evaluation_home_removed":true},{"scenario":"near-expiry","exit_code":75,"evaluation_home_removed":true},{"scenario":"missing-source-setup","exit_code":70,"evaluation_home_removed":true},{"scenario":"malformed-output-and-cleanup","exit_code":74,"evaluation_home_removed":true},{"scenario":"semantic-audit-and-cleanup","exit_code":74,"evaluation_home_removed":true},{"scenario":"child-exit-and-cleanup","exit_code":74,"evaluation_home_removed":true},{"scenario":"audit-only","exit_code":70,"evaluation_home_removed":true},{"scenario":"forged-provenance","exit_code":70,"evaluation_home_removed":true},{"scenario":"cleanup-only","exit_code":74,"evaluation_home_removed":true}]}

Pipeline

Updates from git push no-mistakes

... (5 earlier update rounds omitted to keep the PR body within GitHub's 65536-char limit; full history is in the run log.)

✅ **Lint** - passed

✅ No issues found.

✅ **Push** - passed

✅ No issues found.

Factory Maintainer and others added 30 commits September 28, 2026 19:13
Factory Maintainer and others added 15 commits October 3, 2026 18:08
Preserves uncommitted work from no-mistakes run 01M45P9Q8DNTVQ4A79YVW11S6K,
whose review fix turn timed out at 25m before committing. Snapshot taken
read-only from the run worktree shortly before the timeout (base 948e785).
Partial: fd-based mount handoff in the native helper and CLI shims/tests.
With it the hardened DUMMY probe passes mount setup (baseline 948e785 fails
CP06_ISOLATION_SETUP_FAILED) but now fails "direct syscall probe failed to
execute"; cp06 tests 77 pass / 0 fail / 1 skip (SDK-dependent). Needs
pipeline review and completion; not a validated fix.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The accepted R2 protocol requires one complete read of the supplied
original without offset or limit. The guard and event audit accepted an
explicit offset:1/limit range when it returned the complete bytes. Reject
the presence of either argument before the SDK read executes and again at
the event-audit boundary, restore the negative tests (including the SDK
first-line range with complete bytes), keep the unbounded positive, add
ranged-call rejections through the guard around the pinned SDK's actual
read tool in the DUMMY SDK proof, and correct the probe documentation.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@0xnotdev 0xnotdev changed the title feat: complete CP-06 risk-aware workflow with scoped context retrieval and hardened DUMMY proofs feat: add CP-06 hardened worker proofs and scoped context retrieval Oct 6, 2026
@0xnotdev
0xnotdev merged commit c241673 into main Oct 6, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant