Skip to content

fix(adapters): reconcile quoted tasks-axi fields and record CP-08 acceptance - #15

Merged
0xnotdev merged 10 commits into
mainfrom
fm/factory-cp08
Oct 7, 2026
Merged

0xnotdev merged 10 commits into
mainfrom
fm/factory-cp08

Conversation

@0xnotdev

@0xnotdev 0xnotdev commented Oct 7, 2026

Copy link
Copy Markdown
Owner

Intent

Complete Factory CP-08 end to end after CP-07 merged at 9ba7ded, according to the original PROJECT.md, ARCHITECTURE.md, COMPLETION.md, BUILD_PLAN.md CP-08, docs/CONTRACTS.md, docs/INTEGRATIONS.md and docs/WORKFLOW.md without weakening frozen contracts. Prove one nontrivial localhost-only read-later application begun in a previously unused empty separate Git repository from the exact archived brief, with Pi-authored product truth, architecture, decisions, completion oracle and two-slice DAG frozen in first oracle commit 5fadae52 before implementation. Preserve the original brief and oracle digests. The app must provide separate DUMMY accounts, ownership derived from authenticated principals rather than client owner input, persistence across restart, list/search by URL/title/notes, own-item edit/delete, usable UI and reproducible setup; negative channels must conceal foreign items and preserve state. It must be delivered as at least two genuine Firstmate-owned vertical slices with guarded local-only landings, no public remote/deployment/real credentials, and exact release 5281646d81ebabaee2f93d14cec3da46b703838b.

Satisfy and honestly evidence every original V0 gate F-01 through F-09 and V1 P-01 through P-08, not merely unit/CI or closed tasks. Preserve independent completion behavior: failed, changed-contract and changed-release evidence cannot pass; when all tasks are closed a failed project check remains NOT COMPLETE and repair/retest is observed. Prove reviewed tasks-axi 0.2.5 dry-run/apply/idempotence, dependency holding and interrupted-publication recovery only in disposable fixtures or the authorized reviewed operation, with named-home hashes unchanged for read-only operations. Preserve CTX provenance and the initial strict 30k PARTIAL results versus later 45k STRICT_AGENT/HYBRID_SEMANTIC COMPLETE results; do not relabel CP-06 STANDARD ten-pack evidence as strict. Preserve CP-06 DUMMY/no-range/read-only security controls and CP-07 current-Pi command, reload and CLI parity without real credential attacks. Keep Linux Node verification, Windows Chrome loopback browser verification, and native Windows Node/macOS limitations explicit.

The real app passed RL-001 through RL-005 plus exact-PID kill/restart, clean-clone, account-isolation and browser proofs. The captain's genuine scoped human UI disposition was exactly “yes it looks okay , very simple ask claude to test it out”; record only that the UI looked okay and simple, not that the captain personally ran every workflow. The separately requested Claude Opus 5.5 exact-release test passed seven stable commands and functional/isolation/restart journeys with no accepted defect. Preserve its limits: native AXI confirm-dialog dismissal hung twice, so cancel/delete logic used an explicit window.confirm stub rather than native OK/Cancel clicks; terse errors are optional low-severity UX polish; possible search response ordering was code-reading only and not reproduced; no native Windows server, macOS, screen-reader, load or concurrency claim.

Implement only the smallest Factory fixes exposed by this greenfield exercise: tasks-axi quoted scalar reconciliation, replayable immutable-oracle validation, replayable closed-task/failed-project/stale-evidence status negatives, and a precise CP-08 evidence ledger/sanitized release receipt. Generated runtime evidence stays ignored; application source stays in its separate registered repository. Do not add a scheduler, model router, autonomous/background controller, worktree manager, shipping gate, deployment, global authentication change or tool update. Factory validates and packages; Pi reasons; Firstmate dispatches and alone merges. Preserve prior checkpoint commits/copies and all failed evidence as failures. Produce one normal no-mistakes PR with final-head review/tests/docs/lint and green exact-head CI; never merge it from this worker.

What Changed

  • src/adapters/tasks-axi.ts now decodes every JSON-quoted scalar returned by tasks-axi show (title, state, kind, repo, blocked_by, held, as well as body). Before this, only the body was decoded, so a title with punctuation could stop a re-run of --apply from reconciling the task. If a quoted value fails to parse or is not a string, the adapter now raises TASKS_AXI_OUTPUT_INVALID. A new installed-tasks-axi test in test/sync.test.ts checks that a title with commas is created once and stays unchanged on retry, with the backlog hash unchanged.
  • Adds two replayable CP-08 proof scripts, run with npm run proof:cp08:oracle and npm run proof:cp08:status, plus tests for each:
    • Oracle proof: ties a release commit in a separate repo to the unchanged first oracle commit and archived brief. It rejects the release if any frozen truth or contract file changed later.
    • Status proof: replays closed-task scenarios: a failed project check, a repaired retest, a stale release head and a stale contract. It requires NOT COMPLETE and stale results where expected, and checks that the backlog is unchanged. It refuses to write output outside ignored .factory/state, including when the state root does not exist yet.
  • Adds the CP-08 evidence ledger (docs/probes/CP-08.md) and a sanitized release receipt (docs/probes/CP-08-release.json) for the greenfield read-later app (oracle 5fadae52, release 5281646d). It marks the CP-08 checklist complete in BUILD_PLAN.md and updates the README status to point to the ledger and its platform limits; the README document-authority table is also re-aligned.

Risk Assessment

✅ Low: The fix round fixes both findings the user chose to fix, and the changes are narrow. The new canonicalPath falls back to the canonicalized nearest existing ancestor only on ENOENT, so a missing .factory/state now yields OUTPUT_OUTSIDE_STATE rather than INTERNAL_ERROR. A dangling symlink still cannot make a write escape state, because the later non-recursive mkdir fails. The stale pre-completion sentence was removed from the CP-08 ledger.

Testing

I ran the CP-08 proof tests on their own on a clean tree, compared the old and new state guard on the same fixture, and showed the new tasks-axi quoted-title test fails before the fix and passes after it. I replayed the real oracle and status-negative proofs against the registered app at release 5281646 using only read-only checks, and confirmed the named home and the subject repo were unchanged. A clean clone of the app passed all seven of its checks. Transcripts and status JSON are saved in the evidence directory. Everything passed and no defects were found. There is no UI change in this Factory diff, so no screenshots were taken; the app's browser evidence comes from the recorded receipts.

Evidence: Status guard before/after fix with .factory/state absent

pre-fix: {"status":"fail","error":{"code":"INTERNAL_ERROR","message":"ENOENT ... realpath '.../.factory/state'"}} exit=1 fixed: {"status":"fail","error":{"code":"OUTPUT_OUTSIDE_STATE","message":"output must be a new path under .factory/state"}} exit=1

$ node scripts/.prefix-cp08-status.mjs --subject <fixture> --evidence-source <clone> --home <home> --release 362beea1aa77ab58d8a97d8f64d0be452b8e0cd7 --output <tmp>/outside-state --reviewer 'CP08 test'   # .factory/state absent: absent
{
  "schema_version": 1,
  "status": "fail",
  "error": {
    "code": "INTERNAL_ERROR",
    "message": "ENOENT: no such file or directory, realpath '/home/ansh/.treehouse/Factory-86709f/9/Factory/.factory/state/cp08/no-mistakes/n/worktrees/8c36ce929a68/01M4B78HQ1WBJ0DMXY6M7W97QB/.factory/state'"
  }
}
exit=1

$ node scripts/cp08-status-proof.mjs --subject <fixture> --evidence-source <clone> --home <home> --release 362beea1aa77ab58d8a97d8f64d0be452b8e0cd7 --output <tmp>/outside-state --reviewer 'CP08 test'   # .factory/state absent: absent
{
  "schema_version": 1,
  "status": "fail",
  "error": {
    "code": "OUTPUT_OUTSIDE_STATE",
    "message": "output must be a new path under .factory/state"
  }
}
exit=1
Evidence: CP08 proof tests run alone on a clean tree
✔ CP08 oracle proof binds a separate release to its unchanged first-commit truth (454.944166ms)
✔ CP08 oracle proof rejects a later change to .factory/completion.yaml (194.05611ms)
✔ CP08 oracle proof rejects a later change to PROJECT.md (166.517906ms)
✔ CP08 status proof reports structured usage errors (46.532867ms)
✔ CP08 status proof refuses output outside ignored Factory state (135.431298ms)
ℹ tests 5
ℹ suites 0
ℹ pass 5
ℹ fail 0
ℹ cancelled 0
ℹ skipped 0
ℹ todo 0
ℹ duration_ms 876.977365
Evidence: tasks-axi 0.2.5 sync tests including quoted-title reconciliation
✔ dry-run previews create/unchanged/conflict without changing one backlog byte (1951.891784ms)
✔ a dependency conflict deterministically blocks an unpublished dependent (560.511484ms)
✔ apply uses installed tasks-axi in dependency order and a second apply is idempotent (1789.029815ms)
✔ installed tasks-axi quoted scalar output reconciles punctuation in task titles (1136.895885ms)
✔ an existing held dependency stays held and keeps its dependent non-ready (1904.451745ms)
✔ partial apply reports durable IDs and retry converges without duplicates (2232.845478ms)
✔ wrong home fails without changing backlog bytes (225.166714ms)
✔ unregistered project fails without changing backlog bytes (226.865701ms)
✔ manual backend fails without changing backlog bytes (220.511518ms)
✔ unsupported storage backend fails without changing backlog bytes (203.589946ms)
✔ incompatible tasks-axi fails without changing backlog bytes (368.730352ms)
✔ edited existing body fails without changing backlog bytes (1126.31223ms)
✔ symlink home fails without changing backlog bytes (219.446489ms)
✔ stale contract fails without changing backlog bytes (541.075484ms)
✔ publication ID collision after tasks-axi encoding is rejected (232.47472ms)
✔ duplicate local task ID is rejected before publication (241.317153ms)
ℹ tests 16
ℹ suites 0
ℹ pass 16
ℹ fail 0
ℹ cancelled 0
ℹ skipped 0
ℹ todo 0
ℹ duration_ms 13268.809074
Evidence: Real oracle replay at release 5281646 (frozen digests, subject unchanged)
$ npm run --silent proof:cp08:oracle -- --subject <registered FactoryReadLaterAcceptance> --oracle 5fadae52bc582fe3820d45e587059d3af8c7671e --release 5281646d81ebabaee2f93d14cec3da46b703838b --reviewer "no-mistakes test phase"
{
  "schema_version": 1,
  "check_id": "cp08-frozen-oracle",
  "status": "pass",
  "subject": "FactoryReadLaterAcceptance",
  "oracle_commit": "5fadae52bc582fe3820d45e587059d3af8c7671e",
  "release_commit": "5281646d81ebabaee2f93d14cec3da46b703838b",
  "original_brief_sha256": "6b0779f95c44fb2c74c331afa5d4e78292d56a3813a5f49609495553ea065c54",
  "frozen_source_digests": {
    "ORIGINAL_BRIEF.md": "6b0779f95c44fb2c74c331afa5d4e78292d56a3813a5f49609495553ea065c54",
    "PROJECT.md": "33cf31114b94950dde720b997837b6c44513debc5a81efaa5cb662adda968c63",
    "ARCHITECTURE.md": "d9562c27a52724148a53af0fbdf9797ce724a9b93b7097f016c8229683f4a7ae",
    "COMPLETION.md": "7dc39232e6fb210bf6a2ede8ca5adb3fa01208a02c02372d5b7271a7508ed71a",
    "docs/DECISIONS.md": "4d43a3837ae578fe4096fe427d54bfd62997a9ebf3bae5a2b7412ebe2697ab8b",
    "docs/VERIFICATION.md": "a02d81256646f65f880bf68198a0d8848ea50952b5bd783e1e019b8daacbca0d",
    ".factory/completion.yaml": "c7661b443f601f4ed62110c3300372f01d150ee52a968b69dc46d924465a0bea",
    ".factory/project.yaml": "87c0e76b9930a14590d25b0f3fcaa7a8c3e302f35802a9f432ac1c94f45e2913",
    ".factory/tasks/SLICE-001.yaml": "5ba451e9e4916a0a478226f74e7a9ab2c93dc4e72242cc0677506abfaf2dfacc",
    ".factory/tasks/SLICE-002.yaml": "4b37cd9ac2e3cd4a10e5755531cf4a2604ef9219bc6f79b27248e0e3cae2c33f"
  },
  "oracle_tracked_files": 12,
  "oracle_application_files": 0,
  "factory_validation": {
    "exit_code": 0,
    "project_id": "factory-read-later-acceptance",
    "task_count": 2,
    "condition_count": 6,
    "task_order": [
      "SLICE-001",
      "SLICE-002"
    ]
  },
  "reviewer": "no-mistakes test phase",
  "recorded_at": "2026-10-07T13:05:51.142Z"
}
exit=0
subject head/status/refs digest before=29dc8f237a39f2f2733ffea88a9e408c78fd2ddb33ff7b08199362142371d2e2 after=29dc8f237a39f2f2733ffea88a9e408c78fd2ddb33ff7b08199362142371d2e2
Evidence: Changed-release oracle negative (RELEASE_HEAD_MISMATCH)
$ node scripts/cp08-oracle-proof.mjs --subject <registered-subject> --oracle 5fadae52… --release 0fee6e2c749ae6ace1be44fdd3ae15449a5a0acc (registered seed, not the clean release head) --reviewer neg
{
  "schema_version": 1,
  "status": "fail",
  "error": {
    "code": "RELEASE_HEAD_MISMATCH",
    "message": "checked-out HEAD is not the declared release",
    "details": {
      "expected": "0fee6e2c749ae6ace1be44fdd3ae15449a5a0acc",
      "actual": "5281646d81ebabaee2f93d14cec3da46b703838b"
    }
  }
}
exit=1
Evidence: Real status negatives proof with named-home hashes
$ npm run --silent proof:cp08:status -- --subject <registered-app> --evidence-source <retained slice-2 worker copy> --home <named Firstmate home> --release 5281646d81ebabaee2f93d14cec3da46b703838b --output .factory/state/nm-test-status --reviewer "no-mistakes test phase"
{
  "schema_version": 1,
  "check_id": "cp08-independent-status-negatives",
  "status": "pass",
  "release_commit": "5281646d81ebabaee2f93d14cec3da46b703838b",
  "reviewer": "no-mistakes test phase",
  "recorded_at": "2026-10-07T13:06:20.187Z",
  "operating_backlog_sha256_before": "7bd9460b978a7046d143dfec9253b59d2c4182de5935fd59889268998b0311d1",
  "operating_backlog_sha256_after": "7bd9460b978a7046d143dfec9253b59d2c4182de5935fd59889268998b0311d1",
  "assertions": [
    "both-actual-tasks-done",
    "failed-project-check-remains-not-complete",
    "repair-restores-five-executable-passes",
    "changed-release-head-is-stale",
    "changed-task-contract-is-stale",
    "actual-human-RL-006-remains-bound-to-release",
    "operating-backlog-byte-identical"
  ],
  "artifacts": {
    "baseline.json": "3079c28ef4acce7bb9d8911e336cedc798d42a732e4dc9aa8a94d5833df989c3",
    "failed-project-check.json": "90e81657405b2839d8fd012a8f12f4e86654be71f79ceb5655a1c1881eb13724",
    "repaired-retest.json": "3079c28ef4acce7bb9d8911e336cedc798d42a732e4dc9aa8a94d5833df989c3",
    "stale-release-head.json": "e8adcd73dbad4de15710ee69e6e5d5d79f1b0588aad47693609786e677426e8b",
    "stale-contract.json": "8e9dd125611cf732eec80d9a72659beec5defa2bc79ac46a60a96a8cb20208c9"
  }
}
exit=0
independent named-home backlog.md sha256 before=7bd9460b978a7046d143dfec9253b59d2c4182de5935fd59889268998b0311d1 after=7bd9460b978a7046d143dfec9253b59d2c4182de5935fd59889268998b0311d1
independent named-home data/ tree digest before=edbdf56352f8af6a977434a4e643e4a27877b965d721492c27fcbe822f27479f after=edbdf56352f8af6a977434a4e643e4a27877b965d721492c27fcbe822f27479f
Evidence: Status negatives verdict summary

baseline product=COMPLETE | RL-001..RL-006 passed failed-project-check product=NOT COMPLETE | RL-002:failed, others passed repaired-retest product=COMPLETE | RL-001..RL-006 passed stale-release-head product=NOT COMPLETE | RL-001..RL-006 stale stale-contract product=NOT COMPLETE | RL-001..RL-006 stale

baseline               product=COMPLETE | RL-001:passed RL-002:passed RL-003:passed RL-004:passed RL-005:passed RL-006:passed | SLICE-001:unverified SLICE-002:passed
failed-project-check   product=NOT COMPLETE | RL-001:passed RL-002:failed RL-003:passed RL-004:passed RL-005:passed RL-006:passed | SLICE-001:unverified SLICE-002:failed
repaired-retest        product=COMPLETE | RL-001:passed RL-002:passed RL-003:passed RL-004:passed RL-005:passed RL-006:passed | SLICE-001:unverified SLICE-002:passed
stale-release-head     product=NOT COMPLETE | RL-001:stale RL-002:stale RL-003:stale RL-004:stale RL-005:stale RL-006:stale | SLICE-001:unverified SLICE-002:stale
stale-contract         product=NOT COMPLETE | RL-001:stale RL-002:stale RL-003:stale RL-004:stale RL-005:stale RL-006:stale | SLICE-001:unverified SLICE-002:stale
  • Evidence: Generated Factory status reports (baseline/failed/repaired/stale) (local file: /home/ansh/.treehouse/Factory-86709f/9/Factory/.factory/state/cp08/no-mistakes/n/evidence/01M4B78HQ1WBJ0DMXY6M7W97QB/status-negatives)
Evidence: App clean-clone stable checks at release 5281646
clean clone HEAD=5281646d81ebabaee2f93d14cec3da46b703838b node=v24.20.0
npm ci exit=0
npm run test-unit exit=0 | test-unit: pass
npm run test-integration exit=0 | test-integration: pass
npm run e2e-save-list-persist exit=0 | {"check_id":"e2e-save-list-persist","assertions":["signup-login","save-list","restart-relogin","exactly-one"]}
npm run e2e-account-isolation exit=0 | {"check_id":"e2e-account-isolation","assertions":["principal-derived-owner","foreign-list-empty","foreign-search-empty","owner-supply-ignored","foreign-absent-r
npm run e2e-search-edit-delete exit=0 | {"check_id":"e2e-search-edit-delete","assertions":["search-url","search-title","search-notes","no-result","edit","delete","restart-persistence"]}
npm run e2e-interruption-recovery exit=0 | {"check_id":"e2e-interruption-recovery","assertions":["acknowledged-write","identified-fixture-pid","sigkill-only-fixture","same-data-file","exactly-one-retaine
npm run release-setup exit=0 | 
tracked status after: 0 changed

Pipeline

Updates from git push no-mistakes

✅ **intent** - passed

✅ No issues found.

✅ **Rebase** - passed

✅ No issues found.

🔧 **Review** - 2 issues found → auto-fixed ✅
  • ⚠️ scripts/cp08-status-proof.mjs:275 - The round-1 fix the user chose is still not in the target commit. main() still calls realpath(stateRoot) (&lt;factoryRoot&gt;/.factory/state) before the output-location guard. That directory is gitignored and is absent in this worktree, as in any fresh clone. When it is missing, realpath throws ENOENT and the script exits with INTERNAL_ERROR, not OUTPUT_OUTSIDE_STATE. So test/cp08-status-proof.test.mjs "refuses output outside ignored Factory state" passes only when an earlier test file in the same run has already created .factory/state. It is order-dependent and fails when run alone on a clean clone. Fix: when realpath(stateRoot) throws ENOENT, fall back to the resolved non-realpath state root for the prefix comparison, so the guard no longer depends on the directory existing.
  • ℹ️ docs/probes/CP-08.md:250 - The round-1 fix the user chose is still not in the target commit. The Limits section still ends with "The final section must record exact release SHA, commands, exits, artifact hashes, dates, reviewers, intervention counts, task/merge refs, and residual risk before the remaining checkpoint checkboxes change." The same change ticks every CP-08 checkbox in BUILD_PLAN.md and adds the prevalidation and acceptance sections, so this pre-completion instruction now contradicts the ledger. Remove it or reword it as a historical note.

🔧 Fix: Fix CP08 state guard for missing state root
✅ Re-checked - no issues remain.

✅ **Test** - passed

✅ No issues found.

  • npm ci &amp;&amp; npm run build (test toolchain only; node_modules, dist and .factory/state removed afterwards)
  • node --experimental-import-meta-resolve --test test/cp08-status-proof.test.mjs test/cp08-oracle-proof.test.mjs run alone with .factory/state absent (clean-clone condition for review-1)
  • Before/after comparison: pre-fix scripts/cp08-status-proof.mjs from 3dca129 vs fixed script on the same fixture with .factory/state absent (INTERNAL_ERROR ENOENT → OUTPUT_OUTSIDE_STATE)
  • node --experimental-import-meta-resolve --test dist/test/sync.test.js against installed tasks-axi 0.2.5 (16 tests, none skipped)
  • Regression reproduction: --test-name-pattern=&#34;quoted scalar&#34; with base 9ba7ded src/adapters/tasks-axi.ts (fails PARTIAL_SYNC), then restored the fixed adapter
  • node scripts/cp08-oracle-proof.mjs --subject &lt;registered FactoryReadLaterAcceptance&gt; --oracle 5fadae52… --release 5281646d… --reviewer … (pass; subject HEAD/status/refs digest unchanged)
  • Changed-release negative: cp08-oracle-proof.mjs --release 0fee6e2… against the real subject (RELEASE_HEAD_MISMATCH, exit 1)
  • node scripts/cp08-status-proof.mjs --subject &lt;registered app&gt; --evidence-source &lt;retained slice-2 worker copy&gt; --home &lt;named Firstmate home&gt; --release 5281646d… --output .factory/state/nm-test-status --reviewer … (pass; independent backlog.md and data/ tree hashes unchanged)
  • Parsed the generated status reports: baseline, failed-project-check, repaired-retest, stale-release-head and stale-contract product/condition/task states
  • Clean temp clone of the registered app at 5281646: npm ci plus npm run test-unit|test-integration|e2e-save-list-persist|e2e-account-isolation|e2e-search-edit-delete|e2e-interruption-recovery|release-setup
  • Checked the ledger Limits section for review-2: the stale pre-completion sentence was removed in 786a7b6
✅ **Document** - passed

✅ No issues found.

✅ **Lint** - passed

✅ No issues found.

✅ **Push** - passed

✅ No issues found.

@0xnotdev
0xnotdev merged commit 34e2a89 into main Oct 7, 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