pi-career 0.2.0 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +52 -2
- package/NOTICE +2 -2
- package/README.md +118 -47
- package/SECURITY.md +8 -8
- package/dist/index.js +7236 -2436
- package/dist/pdf-worker.js +1 -1
- package/docs/application-workspaces.md +744 -99
- package/docs/career-run-roadmap.md +64 -28
- package/docs/cover-letter-contract.md +18 -0
- package/docs/design.md +44 -20
- package/docs/hardening-validation.md +15 -0
- package/docs/native-dependency-inventory.md +1 -1
- package/docs/persistence-acceptance.md +430 -0
- package/docs/product-flow.md +77 -15
- package/docs/release-plan-0.4.0.md +69 -0
- package/docs/releasing.md +74 -32
- package/docs/single-application-state.md +110 -0
- package/docs/variant-save-workflow.md +303 -0
- package/package.json +15 -13
- package/skills/career-core/SKILL.md +52 -133
- package/skills/career-core/references/cli-contract.md +6 -6
|
@@ -0,0 +1,430 @@
|
|
|
1
|
+
# Persistence acceptance preparation — issue #60
|
|
2
|
+
|
|
3
|
+
Status: **#60 acceptance-map/fixture work complete; approved scenario contract with partial executable coverage; no new persistence approval**. The machine-checked disposition in `tests/workflow/persistence-acceptance.test.mjs` identifies behavioral witnesses and explicit deferred rationales. `tests/workflow/persistence-acceptance-behavior.test.mjs` exercises additional catalog boundaries using independent canonical synthetic bytes; these narrower reads do not satisfy the deferred overlay, mutation, or process-shutdown scenarios. Passing that bookkeeping test alone is not behavioral evidence.
|
|
4
|
+
|
|
5
|
+
Approved product specifications: [#51](https://github.com/revazi/pi-career/issues/51), [#52](https://github.com/revazi/pi-career/issues/52), [#53](https://github.com/revazi/pi-career/issues/53).
|
|
6
|
+
Work item: [#60](https://github.com/revazi/pi-career/issues/60).
|
|
7
|
+
|
|
8
|
+
This document records the #60 acceptance history and unresolved implementation evidence. It does not authorize new persistence. Current application-state authority comes from [`single-application-state.md`](single-application-state.md); other workspace behavior remains in [`application-workspaces.md`](application-workspaces.md).
|
|
9
|
+
|
|
10
|
+
## Acceptance harness
|
|
11
|
+
|
|
12
|
+
Use the existing `node:test` + `node:assert/strict` harness, synthetic private temporary directories, and fake Pi contexts. Existing integration examples are in `tests/workflow/application-workspace.test.mjs` and `tests/workflow/helpers.mjs`. No new runtime/test framework dependency is needed.
|
|
13
|
+
|
|
14
|
+
Every acceptance test must:
|
|
15
|
+
|
|
16
|
+
- exercise a public workflow boundary or a future explicitly designed read-only catalog/derivation boundary;
|
|
17
|
+
- assert observed records, bytes, authority, and side effects, not just a success boolean;
|
|
18
|
+
- snapshot original/config/workspace bytes and entry sets before an action;
|
|
19
|
+
- inject Core calls and session writes where supported, and add scoped instrumentation for forbidden boundaries not currently injectable;
|
|
20
|
+
- assert fixed public error codes and absence of synthetic private sentinels in errors/logs;
|
|
21
|
+
- clean only its own synthetic temporary directory;
|
|
22
|
+
- identify its `P3-NN` scenario and owning issue.
|
|
23
|
+
|
|
24
|
+
A missing API or undecided schema is **blocked**, not a passing test. Do not add empty tests or mark all scenarios passing through fixture-only assertions. Fixture validators are not substitutes for behavioral integration tests.
|
|
25
|
+
|
|
26
|
+
## Scenario ledger
|
|
27
|
+
|
|
28
|
+
The Given/When/Then rows below preserve Spec 3 numbering. These are specifications, not test results.
|
|
29
|
+
|
|
30
|
+
| ID | Given | When | Then | Owner |
|
|
31
|
+
|---|---|---|---|---|
|
|
32
|
+
| P3-01 | Valid private root with no applications | List applications | Return empty list; create no index or file | #61 |
|
|
33
|
+
| P3-02 | Valid applications with equal and unequal update times | List applications | Order descending by head time, then ascending UUID for ties | #61 |
|
|
34
|
+
| P3-03 | Two directories claim one application UUID | Discover applications | Report identity conflict; neither is silently selected | #61 |
|
|
35
|
+
| P3-04 | Corrupt manifest, identity, or chain | Discover applications | Never expose the corrupt record as valid | #61/#62 |
|
|
36
|
+
| P3-05 | Unknown direct child beneath root | Discover/configure root | Do not adopt it; preserve existing attachment restrictions | #61 |
|
|
37
|
+
| P3-06 | Valid exact identity labels | Restart and list | Restore exact labels from identity, not slugs | #61 |
|
|
38
|
+
| P3-07 | Unicode-equivalent, byte-different labels on distinct UUIDs | Validate and list | Apply explicit label rules without conflating identities | #61 |
|
|
39
|
+
| P3-08 | Complete canonical state chain | Read application | Return current state without changing bytes | #62/#141 |
|
|
40
|
+
| P3-09 | Valid canonical head | Append approved state change | Preserve contiguous sequence and exact parent hash with one new revision | #62/#141 |
|
|
41
|
+
| P3-10 | Invalid or unsupported chain | Read application | Reject former schemas, gaps, duplicates, forks, or unsupported schema identifiers | #62/#141 |
|
|
42
|
+
| P3-11 | Legacy application | Open/list through future overlay | Create no identity or state file | #63/#55 |
|
|
43
|
+
| P3-12 | Prepared migration | Cancel or change one preview byte | No mutation or reuse of approval | #63 |
|
|
44
|
+
| P3-13 | Valid matching session identity | Confirm migration | Create exact identity once; preserve existing bytes | #63 |
|
|
45
|
+
| P3-14 | Legacy application without matching session | Open or request migration | Read-only legacy display; never promote slugs to exact identity | #63 |
|
|
46
|
+
| P3-15 | Two migration plans for one identity | Commit concurrently | One no-clobber winner; loser cannot merge or overwrite | #63 |
|
|
47
|
+
| P3-16 | Configured root and approved company/role | Create application through registered Applications workflow | Preparing, Incomplete 0/3; no automatic attachment or effects beyond explicitly authorized creation entry | #55 |
|
|
48
|
+
| P3-17 | Valid current job description only | Derive readiness | Incomplete 1/3 | #62 |
|
|
49
|
+
| P3-18 | Valid job description and effective resume only | Derive readiness | Incomplete 2/3 | #62 |
|
|
50
|
+
| P3-19 | All three current valid components, no blockers | Derive readiness | Ready 3/3 | #62 |
|
|
51
|
+
| P3-20 | Ready application with bound cover letter | Change job description | Letter becomes stale; Ready removed | #62/#56 |
|
|
52
|
+
| P3-21 | Ready application with bound cover letter | Change effective resume | Letter becomes stale; Ready removed | #62/#56 |
|
|
53
|
+
| P3-22 | Selected original missing or changed | Validate effective resume | Block binding; never silently select another original | #62 |
|
|
54
|
+
| P3-23 | Tailored artifact bound to another original | Derive effective resume | Reject mismatched artifact; no silent fallback | #62 |
|
|
55
|
+
| P3-24 | Applied or Closed application missing components | Derive readiness | Lifecycle does not bypass completeness checks | #62 |
|
|
56
|
+
| P3-25 | Valid complete package without match result | Derive readiness | Ready; no required persisted score | #62 |
|
|
57
|
+
| P3-26 | No session attachment | Browse applications | Allow bounded read-only browsing | #64/#55 |
|
|
58
|
+
| P3-27 | Unattached session | Highlight/open application | Do not append attachment or change conversation authority | #64/#55 |
|
|
59
|
+
| P3-28 | Clean session and valid application | Explicitly attach with required consent | Attach only selected application | #64 |
|
|
60
|
+
| P3-29 | Session previously used for another application | Request attachment | Reject; offer explicit fresh-session path | #64 |
|
|
61
|
+
| P3-30 | Transient attached session | Shut down | Attachment disappears; approved workspace files remain | #64 |
|
|
62
|
+
| P3-31 | Saved attachment whose root is detached or mismatched | Restore | Unavailable attachment; no invented identity | #64 |
|
|
63
|
+
| P3-32 | Browsing or confirmed local mutation | Execute action | No automatic provider submission | #64/#65 |
|
|
64
|
+
| P3-33 | Synthetic Core/provider/prompt sentinels in memory | Create/migrate/list/derive readiness | No result/prompt/provider bytes persisted | #65 |
|
|
65
|
+
| P3-34 | Private paths and document bodies available | Render list projection | Neither appears in list output | #61/#55 |
|
|
66
|
+
| P3-35 | Eligible private document | Explicitly open authorized detail/preview | Show bounded exact content only on that local surface | #55/#65 |
|
|
67
|
+
| P3-36 | Print or JSON mode | Invoke future `/career` | Fail before private config/session/root/document reads | #54/#55 |
|
|
68
|
+
| P3-37 | Failures containing synthetic private sentinels | Render adapter error | Only stable payload-free error; no sentinel or raw stack | #65 |
|
|
69
|
+
| P3-38 | Two creators use same application UUID | Commit concurrently | One winner; no alternative-name retry | #55/#65 |
|
|
70
|
+
| P3-39 | Two plans for same next revision | Commit concurrently | Single contiguous winner; no silent fork | #62/#65 |
|
|
71
|
+
| P3-40 | Failure after artifact publication but before state | Reconcile | Orphan is not current; no implicit adoption | #63/#65 |
|
|
72
|
+
| P3-41 | Exact approved state committed before ambiguous failure | Settle/reconcile | Recognize exact committed state idempotently | #65 |
|
|
73
|
+
| P3-42 | Crash-left lock | Request mutation | Block; no polling or automatic lock removal | #65 |
|
|
74
|
+
| P3-43 | User edited referenced package bytes | Request mutation | Block; preserve bytes; never bless new hash | #65 |
|
|
75
|
+
| P3-44 | Just-below/at/above capacity, including post-preview race | Plan/commit | Enforce each independent bound before preview and under lock | #65 |
|
|
76
|
+
| P3-45 | Attached persistent application | Use legacy command then overlay | One current authority; cancelled save creates no session-only replacement | #64 |
|
|
77
|
+
| P3-46 | Valid session-only application | Open Applications | Distinguish Not persisted from persistent catalog | #63/#55 |
|
|
78
|
+
| P3-47 | Existing v1 files and approved migration | Commit migration | Every existing v1 file stays byte-identical | #63 |
|
|
79
|
+
| P3-48 | Assisted artifact linked to application | Analyze/match originals | Assisted artifact never becomes eligible original | #64/#56 |
|
|
80
|
+
| P3-49 | Valid catalog with no attachment | Browse/open/filter applications | No custom entry, Career Skill metadata, Career tool schema, Core call, or provider call | #64/#55 |
|
|
81
|
+
| P3-50 | Valid attachment without activation | Run ordinary model turn | No Career Skill metadata/content or Career tool schema | #64 |
|
|
82
|
+
| P3-51 | Valid attached application | Explicitly activate assistance | Append one bounded activation, prepare visible editor handoff, reload resources, and do not submit | #64 |
|
|
83
|
+
| P3-52 | Valid persisted activation | Restart/resume | Revalidate exact pointer, then restore only compact managed Skill/tool surface | #64 |
|
|
84
|
+
| P3-53 | Activated branch | Navigate before activation or detach | Clear handles/tools and reload without provider/Core use | #64 |
|
|
85
|
+
| P3-54 | Session used by one application on any branch | Attach another UUID | Reject and offer explicit replacement-session path | #64 |
|
|
86
|
+
| P3-55 | Valid selected application | Open in new Pi session | Seed attachment only through replacement setup; no copied activation/conversation or automatic message | #64/#55 |
|
|
87
|
+
| P3-56 | Invalid attachment/activation transition or identity drift | Restore or act | Fail closed with payload-free unavailable/conflict state; append and mutate nothing | #64/#65 |
|
|
88
|
+
| P3-57 | No valid activation | Request raw tools | Reject; all four Career tool schemas remain absent from model context | #64 |
|
|
89
|
+
| P3-58 | Transient attachment and activation | Reload, then shut down | Work from in-memory entries during process; lose entries and handles at shutdown | #64 |
|
|
90
|
+
|
|
91
|
+
The ledger preserves all **58** approved Spec 3 IDs (P3-01–P3-58); the first 48 are not the entire current approved map. The #60 disposition test assigns each row exactly once to a behavioral witness or a scenario-specific deferred rationale; the Owner column supplies its owning issue. Currently 56 have scoped witnesses and 2 remain deferred. P3-05 is witnessed by registered configure-root and `/career` Applications discovery/attach on a marked private root with one valid application, one legacy application, one colliding UUID pair, and one unknown direct child. The unknown child remains aggregate drifted and is not listed, attached, adopted, rewritten, removed, or repaired. Configure-root and detach fail closed with the existing payload-free workspace errors and do not preview or mutate; another root path remains unavailable. Only the valid pointer is attachable. Legacy and collision restrictions remain. Repeated actions preserve config, root, application, library, and session names, bytes, SHA-256 values, and private modes, with no Core resolution, send, activation, new session, or prompt/result persistence. P3-06/P3-07 are witnessed by one registered `/career` Applications list and local open/detail flow after restart-like reconstruction. Independently canonical synthetic packages keep exact company/role bytes in identity files while directory slugs differ; two distinct UUIDs retain Unicode-equivalent but byte-different labels without normalization or conflation. Repeated RPC and TUI reads preserve config, root, application, library, and session names, bytes, and private modes. Invalid and colliding children stay under existing catalog classifications and are not adopted. This local witness does not establish provider-wire or process-shutdown evidence. P3-16 is witnessed by the registered `/career` Applications create action on a persisted session: consent is resolved before the existing initialize preview, denial and preview cancellation publish nothing, and a registration-scoped post-preview root drift fails closed with no package, lock, temporary file, application entry, or session name. Approved creation writes one canonical private package and then the creation entry; a fresh empty session renders that catalog row as Preparing, Incomplete 0/3. This is local synthetic acceptance, not provider-wire or process-shutdown evidence. P3-36 is witnessed by installed `pi --print` and `pi --mode json --print` invocations of registered `/career` in a child process whose Node permission policy allows package loading and host-required agent settings, while independently denying existing synthetic private config, session, application-root, library, and document paths. Both modes emit only the stable payload-free `interactive_mode_required` error before those reads, with no Core invocation, provider turn, or private-byte output. Registration-scoped session, UI, append, send, and Core traps remain companion evidence. This is not a resumed-session host load or provider-wire witness. P3-37 is witnessed by registered and installed payload-free error boundaries covering resolver probes, Core invocation, source scan/extraction/validation, catalog/config/workspace reads, session loader/replay, UI select/editor/notification failures, persistence/commit failures, and public managed/raw tool errors. Each public result is an approved stable code or message; cancellation stays distinguishable from generic failure. Stdout, stderr, RPC UI, session entries, result cards, and synthetic config/root/library/package/lock/temp sinks contain no injected sentinel, raw stack, path, environment value, private UUID/hash/body/schema bytes, or errno text. No logger or telemetry was added. P3-29/P3-54 have one synthetic registered Applications-flow witness covering both materially distinct claim locations: A attached on the active branch, and A attached on a replayable sibling branch while the active branch follows a different child from their common ancestor and contains no application claim. A public request to attach independently valid B emits the fixed payload-free conflict notice and explicitly offers `Open application in new Pi session`; declining leaves all old entries and private config/application bytes unchanged. Explicit acceptance alone calls `ctx.newSession`, seeds only B's attachment through replacement setup, and leaves A's original session/history unchanged. Core, model-send, tool-activation, document-injection, and workspace-tree spies remain unchanged at available local boundaries; this does not claim provider-wire or network interception. P3-46 has a synthetic combined Applications view witness: a validated unattached current-session row is marked Not persisted beside persistent records, with read-only TUI/RPC navigation and rescan, unchanged session authority and private-tree bytes, and no Core or automatic send. UUID duplicates and invalid or attached session identities do not create a second row. This local witness does not establish provider-wire behavior. P3-22 has independent synthetic missing and changed selected-original cases at the public attached-source boundary while another eligible original remains. The registered attached Match command and direct public loader remain fail-closed: exact scans distinguish absent A from same-identity/different-digest A, B remains independently eligible, fixed payload-free `workspace_drift` rejects validation, and Core/send spies, full config/library/application snapshots, and session snapshots show no fallback or side effect. P3-23 independently constructs canonical private artifact and sidecar bytes whose exact hashes are referenced by state, while the sidecar binds to eligible original B and state still selects eligible original A. Catalog classification is drifted and public attached-source validation returns fixed payload-free `attachment_unavailable`; registered attached Match reaches neither Core nor send, and complete snapshots prove no fallback, append, or file mutation. These are local public-boundary witnesses, not provider-wire interception. P3-48 has a synthetic canonical application-state chain linking a selected original to an assisted artifact, with a library-visible sidecar-classified copy. Scanner and RPC original selectors exclude that copy; an attached application cannot rebind an original once its artifact is linked. Attached Analyze sends only original bytes to Core, while attached Match intentionally sends the validated effective assisted Resume. Changed artifact bytes and a sidecar bound to a different original block Match without adoption or fallback. The earlier unattached selector test remains a narrower regression; neither test establishes provider-wire behavior. P3-35 has a synthetic RPC/TUI local-preview witness: metadata detail remains body-free until the explicit preview action; eligible Markdown, text, and extracted searchable PDF originals are freshly validated, bounded, and displayed exactly on the transient local surface. Companion attached-workspace UI tests cover current vacancy, selected original, and assisted-labeled effective Resume, with byte/entry/Core checks, stale-source rejection, and exclusion of library assisted variants as originals. This is local UI evidence, not provider-wire acceptance. P3-34 remains deferred and is not promoted by this witness. P3-36's installed print/JSON witness denies each private config, session, application-root, library, and document path and still reaches only the stable command error; retained in-process traps cover session getters, UI, append, send, and Core. It does not establish resumed-session host loading or provider-wire behavior. Earlier P3-37 session, UI, and Core-invoke regressions remain in `early-failure-errors` and are not a substitute for the cohesive resolver, source, catalog, persistence, and sink witness. No logger was added. P3-32 is witnessed by one live installed `pi --mode rpc --offline --no-session` process whose configured model `baseUrl` is a reachable loopback provider trap. A harness probe proves the trap counts a request before the child starts; the child then records zero requests. Registered `/career` lists and opens a synthetic catalog application with no attachment, session append, Core invocation, provider request, or agent/message turn. The same process confirms the no-Core application mutations currently exposed as distinct workspace transactions: legacy identity migration (`finish_application_migration`), persistent package creation (`initialize_application`) plus its creation entry, attached status revision (`record_state`), selected-original binding (`select_original`), and confirmed overlay Detach. Preview cancellation and confirm denial publish nothing. Overlay Detach cancellation appends nothing; confirmation appends only the exact `application_detachment` for the current attachment, retains the used-application claim, leaves workspace files unchanged, and does not reload because assistance is inactive. Approved effects are only the identity file, the new canonical package, the creation and attachment entries, the exact canonical revisions, and that one detachment entry. Vacancy, analyze, and match are excluded because they require Core. Config-root and library-root mutations, including workspace-root detach, and Ask Pi editor handoff are outside this slice; editor preparation remains owned by P3-51 and activated detach reload remains owned by P3-53. Neither is treated as submission. Transient consent is the observed notice, not a persisted-session consent dialog. This is not process-shutdown evidence. P3-33 is witnessed by registered `/career` create, migrate, and list/browse plus public readiness derivation while distinct synthetic Core-result, Core-error, provider-request, provider-response, prompt, and editor sentinels remain in process memory. List renders the in-memory result card only on the local Analyze surface. Cancellation, rejected preview, post-preview drift, and consented success are recursively snapshotted. Approved writes are canonical identity, manifest, and state files plus consent and application session entries and the session name. Config, application root, library, session file, result-card append, lock/temp/residue, synthetic package cache, and the rest of the writable temp tree contain none of those sentinel bytes. A fresh empty-memory read reconstructs readiness from disk. The loopback provider trap receives no workflow request. This is not secure erasure or provider-wire acceptance beyond that trap. P3-26, P3-27, and P3-34 exercise synthetic unattached RPC browse/open and rendered lists with session, invocation, send-path, and private-tree byte assertions; they do not establish model transport behavior or private-read interception. P3-50 and P3-57 are witnessed by isolated installed RPC children and a bounded synthetic loopback provider. P3-50 attaches a valid catalog application without activation and then sends one ordinary non-Career prompt. P3-57 requests raw tools through the registered `/career-tools raw` command, receives the stable inactive rejection with no activation or resource reload, and then sends a separate ordinary prompt. Each captured request contains that explicit prompt once and the unchanged host tool schemas, and contains no Career Skill discovery metadata, Skill content, `career_run` schema, or raw `career_core_discover`, `career_core_resume`, or `career_core_job` schema. Synthetic document, identity, path, session-entry, and editor-handoff bytes are absent. The loopback returns one bounded synthetic acknowledgement, no Career Core executable runs, and no provider request occurs before the explicit prompt. This is local synthetic provider-request evidence, not an external-provider witness. P3-52 uses two separately registered installed-extension instances over independently serialized canonical attachment/activation entries. Each fresh `session_start` revalidates the exact private application pointer, restores only active `career_run` plus the Career Skill path, leaves raw tools inactive, and preserves the complete private config/application/library/session tree; scoped Core-executable, send, append, reload, and new-session observations stay unused. P3-56 exercises malformed attachment and activation data, activation without attachment, duplicate attachment and activation transitions, detachment or activation bound to another attachment, duplicate lifecycle record UUIDs, conflicting application UUID claims, a drifted exact pointer, a missing configured pointer, and a valid pointer whose selected source binding later drifted through the same installed restore, Skill action, and direct managed-action boundaries. Invalid restore records remain inactive; the action-only source drift deactivates its initially pointer-valid surface. Every case returns the fixed inactive/unavailable state before Core resolution while complete trees and entries remain unchanged and the append API remains unused. These are local lifecycle witnesses, not provider-wire or network interception. P3-53 remains deferred because the installed session_tree handler receives ExtensionContext, which has no reload(); reload() exists only on ExtensionCommandContext, and host resources_discover runs on startup or reload rather than after tree navigation. A harness-supplied reload on that event would invent a command-context seam. Explicit detach still does not establish navigate-before-activation Skill reload or absence of provider/Core calls and handles. P3-04 has a catalog test for corrupt manifest, identity, and chain with byte preservation. P3-08 and P3-50 were previously linked to narrower tests that did not establish their full Then clauses. P3-50's provider-request witness above supersedes that narrower surface projection. P3-20/P3-21 now use actual appended current job-description and selected-original transitions from a validated Ready package. P3-30 is witnessed by one live `pi --mode rpc --offline --no-session` process that attaches through the public `/career` select/confirm surface, keeps that attachment only in memory with no session file, and is stopped with SIGTERM. A later process has a new pid, no attachment entry, and no Career Skill or managed tool surface, while approved config, root, application, and library names, bytes, SHA-256 values, and private modes stay exact. The same live pid also shows activation's in-process `ctx.reload()` retaining entries; that is not an independent TUI `/reload`, which RPC `get_commands` does not expose and which must not be prompted. P3-58 is separately witnessed by the native-TUI PTY test above. This witness does not claim provider-wire evidence. Exact-title pointers are bookkeeping, not proof of semantic fitness; a witness represents only its exercised public boundary, not blanket end-to-end assurance. Foundation issue #65 must verify its own applicable subset and report later scenarios as pending rather than pretending #60 or #65 completes all end-to-end coverage.
|
|
92
|
+
|
|
93
|
+
P3-40 is witnessed by the registered attached vacancy mutation and registered `Status and reconcile` action across restart-like reconstruction. A registration-scoped checkpoint throws only after the exact approved replacement vacancy has been no-clobber published, synchronized, privately verified, and had its temporary file removed, but before its state revision is published. The fixed failure retains only that orphan; independently canonical manifest, identity, historical state, and historical vacancy bytes remain exact. Reconciliation recognizes the extra managed artifact against the fully validated committed chain but performs no adoption, write, cleanup, rename, append, Core call, send, session creation, tool activation, or fallback. Catalog and attached-source reads continue to fail closed, so the orphan is never current, attached, selected, or effective. Complete config/root/application/library/session snapshots include names, bytes, SHA-256 values, and private modes. This local synthetic witness is distinct from exact-state settlement and does not claim provider-wire interception. P3-41 is witnessed at the public attached-status boundary by a constructor-scoped fault immediately after no-clobber publication and directory synchronization of the exact approved final state, while still inside commit settlement. Exact independent state bytes and parent hashes prove the contiguous head; settlement returns success, and an equivalent repeated request is read-only. P3-42 is independently witnessed at public initialization: confirmation authors canonical crash-left lock bytes, the real exclusive acquisition is observed exactly once, and stable payload-free `workspace_busy` leaves the lock bytes, mode, device/inode identity, workspace, config, library, session tree, and session entries unchanged. P3-43 uses five independent public attached-status mutations over one valid canonical package. After each public preview and real lock acquisition, the instance-scoped hook edits exactly one materially distinct reference: managed vacancy, external selected original, tailored resume, tailored sidecar, or cover letter. Under-lock revalidation returns the fixed payload-free `workspace_drift`; complete tree and session snapshots prove that only the private-mode user edit remains, every historical authority byte is preserved, no state blesses the new digest, and no revision, temporary, backup, lock, session, Core, send, or unrelated mutation remains. This is local deterministic acceptance, not provider-wire evidence. P3-44 remains deferred as a cohesive cluster: current evidence lacks public-boundary below/at/above witnesses and deterministic post-preview under-lock race witnesses for each independent capacity, plus the required complete-tree/session/history/mode and no-side-effect assertions. The production ceilings inventoried for that matrix are 1,024 root entries, 160 application entries, 64 state revisions, 2,097,152 aggregate managed application bytes, 5,242,880 preview bytes, 16,384 metadata-file bytes, 262,144 vacancy/document bytes, 80 characters per config/application identity label, and 65,536 config-file bytes. The label ceiling is config validation (the write helper may truncate labels), so it requires a public invalid-over-limit input witness rather than assuming the write path accepts it. Existing narrower tests and P3-43's reference-drift race do not establish this matrix; retain the deferral until each dimension and the unused send/session/new-session/tool/Core boundaries are independently covered (except Core where the explicit workflow requires it before mutation).
|
|
94
|
+
|
|
95
|
+
## Exact read-only catalog classification contract
|
|
96
|
+
|
|
97
|
+
This section resolves only the remaining #61 catalog projection. It does not approve state v2, readiness, migration, attachment, overlay UI, or a new persisted schema.
|
|
98
|
+
|
|
99
|
+
`readApplicationCatalog(rootPath, expectedRootId)` will return one process-memory value:
|
|
100
|
+
|
|
101
|
+
```json
|
|
102
|
+
{
|
|
103
|
+
"schema_version": "pi.career.application_catalog.v1",
|
|
104
|
+
"applications": [],
|
|
105
|
+
"reconciliation": {
|
|
106
|
+
"interrupted": 0,
|
|
107
|
+
"drifted": 0,
|
|
108
|
+
"duplicate_id": 0,
|
|
109
|
+
"unsupported": 0,
|
|
110
|
+
"over_limit": 0
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
Exact rules:
|
|
116
|
+
|
|
117
|
+
- `schema_version`, `applications`, and `reconciliation` are always present in that order. Reconciliation keys are always present in the order shown, including zero counts.
|
|
118
|
+
- `applications` contains only completely validated records already approved by #61: `valid` records include immutable exact identity metadata; `legacy` records omit identity; both include only application UUID, lifecycle status, and head update time needed by later local projections.
|
|
119
|
+
- Applications remain ordered by head `updated_at` descending, then application UUID ascending. Classification counts never affect ordering.
|
|
120
|
+
- Every persistent direct child other than the root marker contributes exactly once: to one valid/legacy application record or to one reconciliation count. The root marker contributes neither.
|
|
121
|
+
- Invalid entries never produce an application UUID, path, basename, label, status, timestamp, hash, document body, or raw error in the result. Later UI may render only the five aggregate counts.
|
|
122
|
+
- The return value is an internal local projection, not a persisted index, session entry, log, error payload, provider message, or model context. It is freshly derived on every call.
|
|
123
|
+
|
|
124
|
+
### Root-fatal conditions
|
|
125
|
+
|
|
126
|
+
The function returns no partial result and throws the existing stable payload-free error when the supplied root itself cannot be trusted:
|
|
127
|
+
|
|
128
|
+
- invalid/noncanonical/private-root metadata or root-marker bytes;
|
|
129
|
+
- root-marker UUID mismatch;
|
|
130
|
+
- root direct-child count above the existing bound;
|
|
131
|
+
- a live or crash-left root mutation lock; or
|
|
132
|
+
- root replacement or entry-set drift while the scan is in progress.
|
|
133
|
+
|
|
134
|
+
These remain `workspace_root_invalid`, `workspace_identity_conflict`, `workspace_limit_reached`, `workspace_busy`, or `workspace_drift` as applicable. The catalog never converts an untrusted root into an apparently complete set of application-local notices.
|
|
135
|
+
|
|
136
|
+
### Per-child classifications
|
|
137
|
+
|
|
138
|
+
After the root envelope is trusted, classification precedence for each direct child is exact:
|
|
139
|
+
|
|
140
|
+
1. **`duplicate_id`** — two or more package-shaped directories have valid canonical manifests claiming the same manifest UUID. Every claiming directory is removed from `applications` and counted once under `duplicate_id`; no claimant is preferred, even if another file in one claimant would receive a lower-precedence classification.
|
|
141
|
+
2. **`over_limit`** — a nonduplicate application-shaped directory exceeds the application-entry, managed-byte, or state-revision bound. Bounded reads stop at the existing overflow sentinel; no truncated record is accepted.
|
|
142
|
+
3. **`unsupported`** — a nonduplicate, within-bound application-shaped directory contains canonical package metadata with the expected kind/bindings but an unsupported identity or state schema version. Arbitrary unknown JSON is `drifted`, not evidence of a future schema.
|
|
143
|
+
4. **`interrupted`** — a nonduplicate, within-bound application-shaped directory is a recognizable incomplete no-clobber transaction: empty; valid manifest with optional valid identity but no state 1; or known package artifact/temp content without a committed state. It remains read-only and is never completed, cleaned, or adopted by listing.
|
|
144
|
+
5. **`drifted`** — every other invalid direct child, including an unknown root entry, unsafe/non-directory application-shaped entry, malformed or misbound manifest/identity/chain, bad parent, gap/fork, orphaned referenced content, unsafe metadata/link, alias, or changed referenced bytes.
|
|
145
|
+
|
|
146
|
+
If a category cannot be established without trusting malformed/private bytes, use `drifted`. A valid complete chain with absent identity is `legacy`, not `interrupted`. A valid identity with a complete valid chain is `valid`.
|
|
147
|
+
|
|
148
|
+
### Race and side-effect contract
|
|
149
|
+
|
|
150
|
+
- Classification is based on one bounded snapshot. Before return, root identity and entry names plus every emitted valid/legacy manifest, identity, head, and referenced current file are revalidated for inode/size/hash consistency. Any observed race rejects the whole call with `workspace_drift`; stale records or counts are never returned.
|
|
151
|
+
- The function creates no index, lock, temp, config, identity, state, or session entry; performs no repair/adoption; and invokes no Core resolver, child process, package acquisition, network, provider/model, prompt, or telemetry boundary.
|
|
152
|
+
- Behavioral tests must mix valid and every invalid class in one root, prove duplicate removal and exact counts, preserve all bytes/entries across repeated calls, inject a mid-scan race, and assert no private sentinel reaches invalid projections or errors.
|
|
153
|
+
|
|
154
|
+
This approved contract fixes the #61 API surface. Its implementation remains independently reviewable and does not complete #60 by itself.
|
|
155
|
+
|
|
156
|
+
## Exact application-state and derived-readiness contract
|
|
157
|
+
|
|
158
|
+
This section records the implemented #60/#62/#141 storage/read contract. It is a pi-career contract, not a Career Core schema. The canonical application-state authority is [`single-application-state.md`](single-application-state.md); there is no application-state migration or compatibility path.
|
|
159
|
+
|
|
160
|
+
### Canonical `pi.career.application_state`
|
|
161
|
+
|
|
162
|
+
The canonical value is:
|
|
163
|
+
|
|
164
|
+
```json
|
|
165
|
+
{
|
|
166
|
+
"schema_version": "pi.career.application_state",
|
|
167
|
+
"kind": "application_state_revision",
|
|
168
|
+
"application_id": "00000000-0000-4000-8000-000000000001",
|
|
169
|
+
"sequence": 4,
|
|
170
|
+
"parent_sha256": "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
|
|
171
|
+
"status": "preparing",
|
|
172
|
+
"vacancy": {
|
|
173
|
+
"relative_path": "vacancy.md",
|
|
174
|
+
"content_sha256": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
|
|
175
|
+
"utf8_bytes": 30,
|
|
176
|
+
"source_state_id": "00000000-0000-4000-8000-000000000080"
|
|
177
|
+
},
|
|
178
|
+
"selected_original": {
|
|
179
|
+
"document_id": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb",
|
|
180
|
+
"library_root_id": "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc",
|
|
181
|
+
"text_sha256": "dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd",
|
|
182
|
+
"format": "markdown"
|
|
183
|
+
},
|
|
184
|
+
"resume_artifact": null,
|
|
185
|
+
"cover_letter_artifact": {
|
|
186
|
+
"relative_path": "cover-letter.md",
|
|
187
|
+
"artifact_sha256": "eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee",
|
|
188
|
+
"utf8_bytes": 42,
|
|
189
|
+
"format": "markdown",
|
|
190
|
+
"authority": "user_authored",
|
|
191
|
+
"job_description_sha256": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
|
|
192
|
+
"effective_resume_sha256": "dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd"
|
|
193
|
+
},
|
|
194
|
+
"updated_at": "2026-08-12T00:00:04.000Z"
|
|
195
|
+
}
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
The top-level keys and nested keys occur in exactly the displayed order. `cover_letter_artifact` is either `null` or the exact seven-key object shown. All fields have these unions and meanings:
|
|
199
|
+
|
|
200
|
+
- `application_id` is one canonical lowercase UUID; `sequence` is a safe integer from 1 through 64 inclusive; `parent_sha256` is 64 lowercase hexadecimal characters.
|
|
201
|
+
- `status` is exactly `preparing`, `applied`, `interviewing`, or `closed`.
|
|
202
|
+
- `vacancy` is `null` or the existing ordered `{ relative_path, content_sha256, utf8_bytes, source_state_id }` binding. `relative_path` is exactly `vacancy.md` when first introduced at sequence 1 or `vacancy-<six-digit-introducing-state-sequence>.md` when introduced later; carried references retain their original path. `content_sha256` is 64 lowercase hexadecimal characters, `utf8_bytes` is a safe integer from 1 through 262,144 inclusive, and `source_state_id` is a canonical workflow UUID.
|
|
203
|
+
- `selected_original` is `null` or the existing ordered `{ document_id, library_root_id, text_sha256, format }` binding. Its three IDs/digests are each 64 lowercase hexadecimal characters and `format` is `markdown`, `text`, or `pdf`.
|
|
204
|
+
- `resume_artifact` is `null` or the existing ordered `{ relative_path, artifact_sha256, sidecar_relative_path, sidecar_sha256 }` binding. Its artifact path is exactly `resume.md` or `resume.txt`; its sidecar path is exactly `resume.pi-career.json`; both hashes are 64 lowercase hexadecimal characters. Exact artifact bytes are 1 through 262,144 bytes and the sidecar is 1 through 16,384 bytes.
|
|
205
|
+
- `updated_at` is a real canonical UTC timestamp with milliseconds. Sequence 1 is not earlier than `workspace_created_at`; every later state timestamp is strictly later than its predecessor.
|
|
206
|
+
|
|
207
|
+
A state file is fatal-UTF-8 canonical two-space JSON plus one LF, with no BOM, duplicate decoded key, unknown key, trailing data, or noncanonical value, and is 1 through 16,384 bytes. It remains an owner-only `0600`, one-link, non-symlink regular file. The application entry limit of 160, managed-byte limit of 2,097,152, total state-revision limit of 64, and complete-preview limit of 5,242,880 remain independent unchanged ceilings.
|
|
208
|
+
|
|
209
|
+
`Ready`, component classifications, match scores, Core results, provider data, prompts, session IDs, absolute paths, and document bodies are not additional state keys.
|
|
210
|
+
|
|
211
|
+
### Exact cover-letter reference
|
|
212
|
+
|
|
213
|
+
A non-null `cover_letter_artifact` has these rules:
|
|
214
|
+
|
|
215
|
+
1. `relative_path` is one package-generated direct-child basename. The first distinct letter is `cover-letter.md` for `markdown` or `cover-letter.txt` for `text`. Every later distinct letter is `cover-letter-<six-digit-introducing-state-sequence>.md` or `.txt`. The suffix must equal the state sequence that first introduces those exact bytes. No separator, absolute form, dot component, control character, alternative padding, or user-selected name is accepted.
|
|
216
|
+
2. `artifact_sha256` is SHA-256 over the exact artifact bytes and is 64 lowercase hexadecimal characters. `utf8_bytes` is their exact byte length and is a safe integer from 1 through 262,144 inclusive.
|
|
217
|
+
3. The artifact is fatal UTF-8 text with no BOM, NUL, carriage return, or unpaired surrogate after decoding. Bytes are otherwise preserved exactly; pi-career adds no heading, whitespace, or trailing LF. `format` is exactly `markdown` or `text` and must match the filename extension.
|
|
218
|
+
4. `authority` is exactly `user_authored`. No other authority value is valid. A future assisted authority requires a separately approved contract and cannot be smuggled in as an unknown value.
|
|
219
|
+
5. `job_description_sha256` and `effective_resume_sha256` are each 64 lowercase hexadecimal characters and bind the letter to the same revision's package-derived dependency digests defined below.
|
|
220
|
+
6. There is no cover-letter sidecar. Authority, size, exact-byte hash, format, and dependencies live only in the immutable state reference. A draft cannot be attached before both dependencies can be derived. Draft storage outside this exact approved artifact transaction is not introduced.
|
|
221
|
+
7. Carrying an unchanged reference into a later state is allowed and is how a letter becomes stale after a dependency changes. A rebind may retain the exact path, artifact hash, size, format, and authority while changing only the two dependency hashes, but it is a distinct explicitly reviewed future transaction and both new hashes must match that revision's dependencies. New bytes require a new immutable numbered path. One historical path may never claim different bytes, size, format, or authority.
|
|
222
|
+
8. Every referenced cover-letter file is a direct-child owner-only `0600`, one-link, non-symlink regular file with exact size/hash. It counts toward the existing entry and managed-byte ceilings. The #57 authoring transaction, including exact preview, separate confirmation, under-lock revalidation, and exclusive no-clobber publication, is specified in [`cover-letter-contract.md`](cover-letter-contract.md) and implemented in the attached workspace workflow.
|
|
223
|
+
|
|
224
|
+
### Exact digest domains
|
|
225
|
+
|
|
226
|
+
The **current job-description digest** exists only when the head `vacancy` binding is non-null and its exact package file validates. Its value is `vacancy.content_sha256`, verified as SHA-256 over the exact accepted job-description file bytes. There is no Unicode, whitespace, line-ending, Markdown, URL, or Core normalization at readiness time.
|
|
227
|
+
|
|
228
|
+
The **effective-resume digest** exists only when the Resume component is `Available`:
|
|
229
|
+
|
|
230
|
+
- for an effective original, it is `selected_original.text_sha256`, freshly verified against the eligible original's current scanner `text_sha256`; or
|
|
231
|
+
- for an effective tailored artifact, it is `resume_artifact.artifact_sha256`, freshly verified against the exact package artifact bytes.
|
|
232
|
+
|
|
233
|
+
The scanner-text digest is SHA-256 over the UTF-8 encoding of the existing scanner text: fatal UTF-8 decoded Markdown/text or current PDF extractor text, with CRLF and CR converted to LF and no other Unicode, whitespace, or content normalization. This names the existing pi-career scanner domain; it does not copy or replace a Career Core algorithm. The tailored digest is over exact artifact bytes, not scanner-normalized text. No domain prefix, JSON wrapper, sidecar bytes, path, document ID, or format is added to either dependency digest.
|
|
234
|
+
|
|
235
|
+
### Single-schema complete-chain validation
|
|
236
|
+
|
|
237
|
+
A complete chain contains one through 64 total revisions, and every revision has `schema_version: pi.career.application_state`. Former `.v1` and `.v2` identifiers and every other schema identifier are unsupported. They fail closed without migration, adoption, compatibility parsing, or rewriting.
|
|
238
|
+
|
|
239
|
+
The following rules are fail-closed and never select a last-known-good prefix:
|
|
240
|
+
|
|
241
|
+
1. State basenames start at `.pi-career-state-000001.json`, increase by exactly one, and agree with each embedded `sequence`. Any missing sequence, duplicate/alternate state-shaped basename, embedded mismatch, or revision above 64 is a gap/duplicate and invalidates the chain.
|
|
242
|
+
2. Sequence 1's `parent_sha256` hashes the exact manifest bytes. Every later parent hashes the exact complete canonical bytes of the immediately preceding revision, regardless of schema version. A parent to any earlier revision, unknown bytes, or competing lineage is a fork/bad parent and invalidates the chain.
|
|
243
|
+
3. Every revision binds the manifest application UUID and satisfies the timestamp rules above. The manifest, identity when present, directory, state metadata, and every package-local reference retain their existing private metadata, containment, byte, hash, and aggregate-bound checks.
|
|
244
|
+
4. Any well-formed but noncanonical application-state schema identifier makes the whole entry `unsupported`; no prefix is current. Malformed JSON, arbitrary schema text, unknown kind/binding, or noncanonical future-looking bytes are `drifted`, not `unsupported`.
|
|
245
|
+
5. Every approved mutation appends exactly one canonical revision. Status, vacancy, selected-original, resume-artifact, and cover-letter fields may change only as authorized by that operation; there is no schema-transition revision.
|
|
246
|
+
6. Sequence 1 and every later revision include `cover_letter_artifact`, either `null` or the exact reference shape. At 64 revisions the chain cannot append; there is no compaction or implicit limit increase.
|
|
247
|
+
7. `resume_artifact` requires non-null `selected_original`. Its exact independently versioned assisted sidecar must identify `assisted_non_authoritative`, bind the stored original document/text digest, and bind the exact artifact hash before the artifact can be effective. A selected-original change while an artifact is referenced is invalid unless the same next snapshot clears the artifact; there is no fallback from an invalid referenced artifact to the original.
|
|
248
|
+
8. A newly introduced or explicitly rebound cover-letter reference must match the job/effective-resume digests derivable from that revision's metadata. A byte-identical carried reference may mismatch a later snapshot and is then valid history but `Stale` at that head.
|
|
249
|
+
|
|
250
|
+
Every package-local file referenced by any revision remains immutable managed history and is checked for exact path, type, owner, mode, link count, size, and hash. Reuse of one path with conflicting immutable metadata is structural drift. Missing or changed historical-only vacancy, resume artifact, sidecar, or cover letter invalidates the complete chain when the head no longer references it; no component projection can hide damaged history. A stable failure of a well-formed head reference instead gives that current component the diagnostic classification `Drifted`, excludes the application from valid catalog records, and blocks Ready. Orphan package-shaped files are never adopted as history.
|
|
251
|
+
|
|
252
|
+
Historical `selected_original` bindings are different because their bytes live in an external Resume library: non-head bindings are structurally and chain validated but are not freshly rescanned. An absent or changed historical original therefore does not prevent reading an otherwise intact chain. Only the head selected-original binding is resolved through one fresh complete bounded scan for readiness. No historical source is reconstructed from a sidecar, artifact, chat, or provider content.
|
|
253
|
+
|
|
254
|
+
A former or unsupported schema, gap, fork, malformed revision, conflicting path reuse, or historical-only managed-reference failure yields no trusted head, no `current` label, and no readiness projection. A structurally valid candidate head with a stable current-reference failure may produce only the diagnostic `Drifted` component projection defined below; it is not a valid/current catalog record. Catalog discovery uses its existing aggregate `unsupported`, `drifted`, or `over_limit` classification and exposes no invalid private detail.
|
|
255
|
+
|
|
256
|
+
### Pure component classifications
|
|
257
|
+
|
|
258
|
+
The classification vocabulary is closed and case-sensitive: `Missing`, `Available`, `Stale`, `Unavailable`, and `Drifted`. Classification and readiness derivation are deterministic functions of a validated state snapshot plus bounded read evidence; they do not mutate either input.
|
|
259
|
+
|
|
260
|
+
**Job description**
|
|
261
|
+
|
|
262
|
+
- `Missing`: head `vacancy` is `null`.
|
|
263
|
+
- `Available`: the non-null reference and exact current package bytes validate.
|
|
264
|
+
- `Drifted`: the well-formed non-null local reference has stably absent, changed, unsafe, aliased, or over-bound package bytes/metadata.
|
|
265
|
+
- `Stale` and `Unavailable` are not emitted for this package-local component. There is no URL fetch or alternate source fallback.
|
|
266
|
+
|
|
267
|
+
**Resume**
|
|
268
|
+
|
|
269
|
+
- `Missing`: both `selected_original` and `resume_artifact` are `null`.
|
|
270
|
+
- `Available`: one fresh complete uncapped scan finds exactly one eligible original matching the stored document ID, root ID, format, and scanner-text digest, and either no tailored artifact is referenced or the exact artifact/sidecar and source binding also validate.
|
|
271
|
+
- `Stale`: the same uniquely identified eligible original is found but its current format or scanner-text digest differs from the binding. A referenced tailored artifact cannot hide this and no original/artifact is silently substituted.
|
|
272
|
+
- `Unavailable`: the binding cannot be conclusively checked because the configured root/source is absent or stale, extraction/read fails, the candidate is missing, ambiguous, assisted/quarantined rather than original, or a root/total scan cap is reached.
|
|
273
|
+
- `Drifted`: package-local artifact/sidecar bytes or metadata stably fail, or the hash-valid sidecar authority/source binding contradicts the well-formed state. An artifact without a selected original is structural chain drift and yields no component projection. There is no fallback to the selected original while a referenced artifact is stale, unavailable, or drifted.
|
|
274
|
+
|
|
275
|
+
When Resume is `Available`, effective-resume selection is exact: choose `tailored` when a non-null current `resume_artifact` and its source binding validate; otherwise choose `original` from the valid selected-original binding. Every other Resume classification yields no effective source and no effective-resume digest. Merely finding another original, an assisted variant, or matching text under another identity never changes the selection.
|
|
276
|
+
|
|
277
|
+
**Cover letter**
|
|
278
|
+
|
|
279
|
+
- `Missing`: `cover_letter_artifact` is `null`.
|
|
280
|
+
- `Available`: its exact local artifact validates, both current dependency digests exist, and both equal the stored dependency hashes.
|
|
281
|
+
- `Stale`: its exact local artifact validates, both current dependency digests exist, and either stored dependency hash differs.
|
|
282
|
+
- `Unavailable`: its exact local artifact validates but one or both current dependencies have no digest because the corresponding component is not `Available`.
|
|
283
|
+
- `Drifted`: its well-formed reference has stably missing, changed, unsafe, or over-bound exact local bytes/metadata.
|
|
284
|
+
|
|
285
|
+
After structural chain validation, a null reference is `Missing`; a non-null reference with failed local evidence is `Drifted`; a locally valid cover then resolves dependency `Unavailable`, mismatch `Stale`, or `Available` in that order. Impossible or malformed state combinations are structural chain drift and return no component projection at all. A diagnostic surface may report a well-formed current component as `Drifted`, but catalog discovery must continue to exclude the application from valid/legacy records.
|
|
286
|
+
|
|
287
|
+
### Readiness truth table
|
|
288
|
+
|
|
289
|
+
Let `J`, `R`, and `C` mean that Job description, Resume, and Cover letter respectively classify exactly `Available`. `n` is exactly the number of true values; `Missing`, `Stale`, `Unavailable`, and `Drifted` each contribute zero. Lifecycle status and match-result presence contribute nothing.
|
|
290
|
+
|
|
291
|
+
| J | R | C | Projection | Reachability |
|
|
292
|
+
|---|---|---|---|---|
|
|
293
|
+
| no | no | no | `Incomplete 0/3` | yes |
|
|
294
|
+
| yes | no | no | `Incomplete 1/3` | yes |
|
|
295
|
+
| no | yes | no | `Incomplete 1/3` | yes |
|
|
296
|
+
| no | no | yes | impossible; cover must be `Unavailable` or `Drifted` | no |
|
|
297
|
+
| yes | yes | no | `Incomplete 2/3` | yes |
|
|
298
|
+
| yes | no | yes | impossible; cover must be `Unavailable` or `Drifted` | no |
|
|
299
|
+
| no | yes | yes | impossible; cover must be `Unavailable` or `Drifted` | no |
|
|
300
|
+
| yes | yes | yes | `Ready 3/3` | yes, only with no application blocker |
|
|
301
|
+
|
|
302
|
+
`Ready 3/3` additionally requires a trusted manifest/identity/root, a complete supported chain, all historical managed references valid, and no root/application collision, drift, race, unsupported schema, or exceeded bound. If that envelope is not trusted, the application is not projected as Ready regardless of three isolated component observations. `preparing`, `applied`, `interviewing`, and `closed` all use this same table. A match result is neither read nor persisted for readiness.
|
|
303
|
+
|
|
304
|
+
### Races, privacy, errors, and forbidden effects
|
|
305
|
+
|
|
306
|
+
- Chain/reference/evidence reads are bounded. Before return, the reader revalidates root/application identity and entry set plus every manifest, identity, revision, current/historical managed file, and selected-original scan evidence used by the result. Any observed replacement, inode/size/hash/metadata change, entry-set change, or newly capped scan fails with `workspace_drift`; no stale or partial projection is returned.
|
|
307
|
+
- An unsupported canonical state remains the aggregate `unsupported` classification during catalog discovery. Limit overflow remains `over_limit`. Direct attached reads use only existing stable payload-free workspace failures; this slice adds no error string containing a path, basename, label, UUID, hash, document bytes, schema bytes, environment value, raw filesystem error, or stack.
|
|
308
|
+
- Parsing and derivation create no index, lock, temp, config, identity, revision, artifact, sidecar, cache file, session entry, prompt, result, or log. They perform no repair, adoption, migration, attachment, compaction, deletion, URL fetch, Core resolution/invocation, child process, npm acquisition, provider/model call, network call, telemetry, or automatic prompt submission.
|
|
309
|
+
- Complete document bytes and absolute paths remain confined to an explicitly authorized future local detail/preview surface. Catalog/readiness values, adapter errors, logs, provider context, and session entries receive neither. Digests are internal integrity/dependency evidence and are not displayed by list projections or errors.
|
|
310
|
+
- Cancellation before a read begins returns without private access. Cancellation or a race during the bounded read returns no partial result. Because this slice is read-only, there is no settlement-after-commit path and no retry through another runtime route.
|
|
311
|
+
|
|
312
|
+
### #141 synthetic fixture and ownership map for this contract
|
|
313
|
+
|
|
314
|
+
Fixtures use fixed synthetic UUIDs/timestamps/labels and generated private temporary roots. Document bytes are short strings such as `Synthetic job description.`, `Synthetic original resume.`, and `Synthetic user-authored letter.` Expected canonical bytes and hashes are computed by test-only builders that do not import the production parser as their sole oracle.
|
|
315
|
+
|
|
316
|
+
| Fixture family | Required variants | Spec 3 scenarios | Implementation owner |
|
|
317
|
+
|---|---|---|---|
|
|
318
|
+
| `single-schema-chain` | sequence 1; contiguous chain; direct cover introduction; lower/at/above metadata and revision bounds | S1-01, S1-02, S1-06, S1-07 | #141 |
|
|
319
|
+
| `unsupported-state-schema` | former `.v1`; former `.v2`; gap; embedded-sequence mismatch; bad parent/fork; prefixed and unrelated unsupported schemas; malformed future-looking schema | S1-03, S1-04, S1-05, S1-11 | #141 |
|
|
320
|
+
| `historical-references` | carried vacancy/artifact/letter; cleared current references; absent historical external original; missing/changed historical managed file; conflicting path reuse | P3-04, P3-20, P3-21, P3-43, P3-47 | #60 fixtures; #62 reader; #65 integration |
|
|
321
|
+
| `cover-letter-reference` | Markdown/text first and numbered paths; immutable user-authored revisions; bad authority/format/path/hash/dependency; bytes 0/1/262,144/262,145 | P3-19, P3-20, P3-21, P3-44 | #60 fixtures; #62 validation; #57 writer and workflow tests |
|
|
322
|
+
| `package-completeness` | every reachable availability row; each non-Available class for each component; applied/closed lifecycle; no match result | P3-16 through P3-25 | #60 fixtures; #62 derivation; #55 creation presentation |
|
|
323
|
+
| `source-authority` | current/changed/missing original; stale/capped/ambiguous scan; assisted/quarantined candidate; valid and source-mismatched tailored artifact | P3-18, P3-21, P3-22, P3-23, P3-48 | #60 fixtures; #62 derivation; #64/#56 convergence |
|
|
324
|
+
| `read-races-and-privacy` | revision, historical/current artifact, selected source, and entry-set replacement during read; synthetic private sentinels in failures and spies | P3-33, P3-37, P3-39, P3-43, P3-44 | #60 fixtures; #62 reader; #65 adversarial integration |
|
|
325
|
+
| `transaction-orphans` | cover/artifact published without state and exact state committed after ambiguous failure | P3-40, P3-41 | #60 fixture; registered orphan reconciliation; #65 settlement |
|
|
326
|
+
|
|
327
|
+
The #60 fixture slice encodes approved bytes and corruption cases without itself adding production behavior. Fixture validation alone does not satisfy a behavioral scenario: #62 exercises the public read/derivation boundary, while #57's separate workflow tests exercise mutation, fault handling, and integration. No fixture may contain a real company, role, resume, job description, cover letter, credential, provider response, session file, machine-specific path, or Core checkout.
|
|
328
|
+
|
|
329
|
+
## Synthetic fixture families
|
|
330
|
+
|
|
331
|
+
- `empty-root`: canonical private root and valid marker, no applications.
|
|
332
|
+
- `identity-less`: immutable manifest, contiguous canonical states, optional vacancy, no display identity.
|
|
333
|
+
- `identified`: valid canonical chain plus approved exact identity metadata.
|
|
334
|
+
- `unsupported-state-schema`: former `.v1` and `.v2` schemas plus gap, duplicate, unsupported-schema, and bad-parent variants.
|
|
335
|
+
- `package-completeness`: independent job/resume/letter missing/current/stale/drifted states.
|
|
336
|
+
- `source-authority`: originals, valid assisted variants, quarantined sidecars, changed originals, missing roots, capped scans.
|
|
337
|
+
- `session-attachment`: clean, prior-other-application, persisted, transient, branched, detached-root and mismatched identity.
|
|
338
|
+
- `transaction-faults`: failures at each publication/sync/revalidation boundary; exact committed versus orphaned states.
|
|
339
|
+
- `capacity`: independently generate below/at/above each bound and concurrent changes after preview.
|
|
340
|
+
|
|
341
|
+
Use fixed synthetic UUIDs/timestamps and generated temp-root paths. Hash expected bytes directly; do not import production parsers to manufacture the sole expected test oracle. Full fixtures for new schemas wait for their exact contract approval.
|
|
342
|
+
|
|
343
|
+
## Approved #64 command-authority matrix — implemented for application/vacancy/Resume commands
|
|
344
|
+
|
|
345
|
+
| Interface | No attachment | Valid attachment, no activation | Valid activated attachment |
|
|
346
|
+
|---|---|---|---|
|
|
347
|
+
| `/career-application` | Preserve legacy session-only behavior and explicit workspace creation | Show/update workspace lifecycle only through a previewed file mutation; never append competing session status | Same workspace authority; model activation grants no mutation |
|
|
348
|
+
| `/career-application clear` | Preserve legacy clear boundary | Explicit Detach appends only the exact detachment; retain used-application claim and all files | Detach also clears ephemeral handles and reloads away Career model resources |
|
|
349
|
+
| `/career-vacancy` | Preserve legacy session vacancy behavior | Validate through Core, then preview/confirm workspace revision; cancellation changes neither workspace nor session | Same workspace transaction; no provider call and no session-only vacancy mirror |
|
|
350
|
+
| `/career-workspace` | Configure, initialize, migrate, and reconcile as explicitly available | Administer/reconcile exact attached workspace; no silent synchronization | Same local authority |
|
|
351
|
+
| `/career-match`, `/career-analyze` | Existing explicit deterministic source/consent behavior | Read fresh validated workspace bindings; match uses the effective Resume, analyze uses only the selected original | Same deterministic behavior; activation does not route commands through a model |
|
|
352
|
+
| `/career-workbench` and overlay assistance | Require explicit attachment first; never combine decisions | Explicit action appends activation, prepares `/skill:career-core …`, and reloads; no submission | Reuse activation and stable editor/tool surface; append nothing |
|
|
353
|
+
| `career_run` | Inactive and absent from model context | Inactive and absent from model context | Resolve ephemeral handles from fresh validated workspace sources; no implicit mutation |
|
|
354
|
+
| `/career-tools raw` | Reject | Reject | Explicitly add exact raw compatibility tools for this runtime only; managed/reset removes them |
|
|
355
|
+
| `/career-save` | Existing independent variant-save contract when a legacy ephemeral handle exists | No handle until assistance runs | Independent preview/confirmation; never attaches artifact to application implicitly |
|
|
356
|
+
| Future `/career` | Browse without attachment | Open attached detail; browsing another application never replaces attachment | Same local browsing behavior; no automatic model message |
|
|
357
|
+
|
|
358
|
+
Application, vacancy, match, analyze, workbench, and `career_run context` now follow this matrix when a persistent application is attached. Unattached `/career-workbench` still prepares the legacy editor prompt. Overlay `/career` browsing and `/career-save` application binding remain later. Each remaining overlay implementation must add behavioral tests and preserve the existing privacy, preview, consent, cancellation, and race gates. Opening the overlay is never consent.
|
|
359
|
+
|
|
360
|
+
## Capacity findings and remaining decisions
|
|
361
|
+
|
|
362
|
+
Observed current source limits in `src/workflow/application-workspace.ts`:
|
|
363
|
+
|
|
364
|
+
| Bound | Current value |
|
|
365
|
+
|---|---:|
|
|
366
|
+
| Root persistent entries including marker | 1,024 |
|
|
367
|
+
| Application persistent entries including unknown user files | 160 |
|
|
368
|
+
| State revisions | 64 |
|
|
369
|
+
| Managed application bytes | 2,097,152 |
|
|
370
|
+
| Mutation preview bytes | 5,242,880 |
|
|
371
|
+
| Metadata bytes per file | 16,384 |
|
|
372
|
+
| Vacancy/artifact content ceiling used by current validation | 262,144 |
|
|
373
|
+
|
|
374
|
+
These are independent ceilings, not guaranteed capacity for 64 maximum-sized documents.
|
|
375
|
+
|
|
376
|
+
Including the immutable identity, the maximal canonical shape is 132 files before unknown user entries: manifest + identity + 64 states + 64 job-description files + one resume/sidecar pair. Distinct cover letters can therefore exhaust 160 entries before 64 states. The fixed accounting formula is `2 + S + J + 2R + C + U`, where `S` is state files, `J` is distinct job-description files, `R` is distinct resume artifact/sidecar pairs, `C` is distinct cover-letter files, and `U` is unknown user entries. A cover-letter rebind that reuses exact bytes adds a state but no second artifact; the canonical state has no cover-letter sidecar.
|
|
377
|
+
|
|
378
|
+
Retain limits by default; reject over-capacity plans before preview and under lock. Preview size must be checked using actual canonical encoded preview bytes: JSON escaping means a 2-MiB managed-byte budget does not prove that a complete preview fits 5 MiB. No truncation, compaction, deletion, or larger bounds without separate approval.
|
|
379
|
+
|
|
380
|
+
The canonical application-state schema, cover-letter reference, digest domains, single-schema chain validation, historical-reference behavior, component classes, readiness table, and #64 attachment/activation contract are fixed above and in `application-workspaces.md`. Remaining decisions are:
|
|
381
|
+
|
|
382
|
+
1. #64 behavior slices must implement strict entry replay, pointer revalidation, command convergence, safe explicit session replacement, and context-on-demand activation without combining them into an unreviewable UI change.
|
|
383
|
+
2. #57 defines the user-authored cover-letter preview, distinct confirmation, immutable publication, and state-append transaction in [`cover-letter-contract.md`](cover-letter-contract.md). No draft is persisted; assisted authoring and dependency rebind remain out of scope.
|
|
384
|
+
3. Later overlay issues must decide presentation copy and local detail navigation without changing classification/readiness semantics or exposing invalid-entry detail.
|
|
385
|
+
4. #65's integration checks remain scoped: explicit consented attachment/activation entries are permitted by #64; blanket “no session append anywhere” would contradict reviewed session persistence.
|
|
386
|
+
|
|
387
|
+
## Small PR sequence
|
|
388
|
+
|
|
389
|
+
Each item is a separate reviewable change, not a promise to implement its entire parent issue at once. Do not combine persistence and overlay behavior in a single PR.
|
|
390
|
+
|
|
391
|
+
1. **#60 acceptance baseline (landed):** this ledger, its structural completeness check, and a read-only reconciliation regression.
|
|
392
|
+
2. **#61 identity/catalog foundation (landed):** strict identity parsing/publication and bounded classified discovery without UI.
|
|
393
|
+
3. **#60/#62/#140 exact state/readiness contract (landed):** the schema, dependency, chain, classification, readiness, side-effect, and fixture ownership decisions above; no production behavior.
|
|
394
|
+
4. **#60 fixture support:** independent synthetic byte builders and corruption cases for the reviewed contract. Fixture checks do not count as workflow coverage.
|
|
395
|
+
5. **#62/#141 state reader and readiness:** single-schema validation and pure readiness changes.
|
|
396
|
+
6. **#63/#64:** migrate one explicit transaction or converge one command family per PR; strict #64 record parsing/replay lands before filesystem validation, command wiring, or context activation; no bulk migration or all-command rewrite.
|
|
397
|
+
|
|
398
|
+
Keep each PR independently testable. Add failing behavioral tests and the minimal implementation together when a new boundary is introduced, rather than landing a broken default test suite. Release and remote Git operations remain separately authorized.
|
|
399
|
+
|
|
400
|
+
### Current coverage evidence
|
|
401
|
+
|
|
402
|
+
- `tests/workflow/persistence-acceptance.test.mjs` validates ledger IDs/owners and checks a unique 58-row disposition against actual behavioral test titles (56 witnessed, 2 deferred). This is bookkeeping, not itself behavioral coverage. Deferred rationales remain alongside the evidence map in that test, with owner issue links in the ledger. Some witnesses cover only read or derivation slices: append, UI rendering, race/settlement, and provider-spy requirements remain deferred, even where a fixture or narrower read test exists.
|
|
403
|
+
- `tests/workflow/fixtures/persistence-state.mjs` and `tests/workflow/persistence-fixtures.test.mjs` provide production-independent canonical byte builders, private temporary-root materialization, and the eight reviewed fixture/corruption families. They map each family to its P3 rows but deliberately do not import or validate a production state reader, derive production readiness, or count fixture checks as behavioral coverage.
|
|
404
|
+
- `tests/workflow/application-state-reader.test.mjs` exercises the production catalog/read boundary against canonical chains, former `.v1`/`.v2` and other unsupported schemas, gaps, forks, malformed revisions, historical references, exact cover-letter references, source-bound tailored artifacts, and mutation-free source-failure cases. It snapshots bytes around reads and proves no read-time mutation; it does not claim readiness coverage.
|
|
405
|
+
- `tests/workflow/application-readiness.test.mjs` exercises the pure production derivation boundary against every reachable availability row, each non-Available class, original-source outcomes, tailored selection, cover dependency precedence, determinism, and output privacy.
|
|
406
|
+
- `tests/workflow/application-readiness-integration.test.mjs` exercises the attached read-only state-to-readiness boundary with independently canonicalized synthetic package and library bytes. It establishes a canonical-chain Ready package, then performs separate exact-parent job-description and selected-original transitions, proving a stale bound letter, `Incomplete 2/3`, applied/closed lifecycle non-bypass, preserved history, private modes, and mutation-free derivation. It adds no cover-letter writer or provider/Core/session path; broader filesystem races and overlay presentation remain #65 and later overlay slices. P3-16 is no longer deferred: `tests/workflow/persistent-overlay-creation.test.mjs` drives registered Applications create against a configured private root, resolves persisted consent before exact preview, and proves canonical package bytes, private modes, restart-like Preparing/Incomplete 0/3 catalog visibility, and the absence of attachment, activation, Core, send, result, prompt, library, and residue effects for denial, cancellation, changed preview, post-preview drift, and success.
|
|
407
|
+
- `tests/workflow/session-attachment.test.mjs` exercises the pure #64 strict parsers, factories, active-branch replay, all-entry one-application claim, detach/reattach scope, malformed transitions, determinism, and output privacy. It does not claim filesystem pointer validation, Pi event wiring, command convergence, resource activation, or overlay coverage.
|
|
408
|
+
- `tests/workflow/session-attachment-validation.test.mjs` exercises fresh filesystem pointer validation against one exact configured root, valid identity, missing config, legacy identity, root/manifest timestamp drift, renamed directories, drifted state, and duplicate UUID claims. It snapshots bytes around reads and returns no paths.
|
|
409
|
+
- `tests/workflow/session-model-surface.test.mjs` exercises context-on-demand resolution and Pi wiring: no Career tools/Skill path without activation, managed `career_run` plus `skills/` discovery after valid activation and pointer validation, raw-tool rejection outside activation, and `/skill:career-core` handled without a model turn.
|
|
410
|
+
- `tests/workflow/session-attachment-commands.test.mjs` exercises explicit attach/detach/assistance-activation through `/career-workspace`: confirmation-gated pointer append, cancellation, document-free editor handoff, reload after activation/detach, and unchanged workspace bytes.
|
|
411
|
+
- `tests/workflow/session-catalog-attach.test.mjs` exercises attaching a validated catalog application from a clean Pi session, then drives the registered Applications overlay against active-branch and replayed non-active-branch claims. It proves another UUID is rejected with the fixed conflict notice and explicit replacement-session offer, decline is side-effect free, and acceptance alone attaches the selected application through replacement-session setup while the original session remains unchanged. Broader overlay presentation remains later.
|
|
412
|
+
- `tests/workflow/command-authority.test.mjs` exercises attached `/career-vacancy`, `/career-match`, `/career-analyze`, `/career-workbench`, and `career_run context`: workspace files are the only current vacancy/Resume authority, cancelled vacancy saves change neither workspace nor session, match uses the effective Resume, analyze uses only the selected original, and workbench/assistance never auto-submit.
|
|
413
|
+
- `tests/workflow/application-status-authority.test.mjs` exercises attached `/career-application` status and clear. Its P3-08/P3-09 witness reads the current status from an independently canonicalized two-revision chain through the registered command, then commits an approved attached status mutation through the application workflow. It snapshots the complete observed application-root, library, and config trees (bytes, names, and modes), independently verifies exactly one requested canonical revision with a contiguous sequence and parent SHA-256 value, and proves every prior byte and session entry remains unchanged. The bounded Core invocation spy remains unused; provider/model/network absence is not inferred from unavailable boundaries. Cancellation and clear coverage remain mutation-free.
|
|
414
|
+
- `tests/workflow/application-concurrency-acceptance.test.mjs` exercises P3-38 and P3-39 through public workflow methods with independently prepared approvals and separate instance-local mutation queues. A scoped post-lock checkpoint holds the deterministic winner while the contender performs a real exclusive-lock acquisition. The tests independently construct canonical bytes and parent hashes, snapshot the complete synthetic config/root/application/library/session tree, require one stable payload-free `workspace_busy` loser, and prove exact names, private modes, contiguous authority, no retry/fork/overwrite/gap, no stale lock, no session append, and no mutation outside the approved winner. The same file separately witnesses P3-41 exact-state settlement, P3-42 crash-left lock handling, and P3-43 referenced-byte drift.
|
|
415
|
+
- `tests/workflow/application-artifact-reconciliation-acceptance.test.mjs` exercises P3-40 through the registered vacancy editor and registered `Status and reconcile` action. Its instance-scoped post-artifact/pre-state checkpoint leaves one exact private orphan after publication durability; restart-like reconstruction, catalog projection, and attached-source validation prove mutation-free quarantine with no implicit adoption. Complete synthetic trees, historical bytes, sessions, modes, and available Core/send/new-session/append/tool boundaries remain accounted for.
|
|
416
|
+
- `tests/workflow/unknown-child-attachment-boundary.test.mjs` witnesses P3-05 through registered configure-root and `/career` Applications discovery/attach. A marked private root contains one valid application, one legacy application, one colliding UUID pair, and one unknown direct child. Catalog classification keeps the unknown child aggregate drifted and the collision `duplicate_id`; neither is listed or attachable. Repeated configure, detach, status, and attach actions preserve every config, root, application, library, and session name, byte, SHA-256 value, and private mode. The registered workspace action surfaces the existing payload-free error instead of discarding it. No Core resolution, send, activation, new session, repair, or adoption occurs.
|
|
417
|
+
- `tests/workflow/overlay-exact-label-restart.test.mjs` witnesses P3-06 and P3-07 through the registered `/career` Applications list and local open/detail surfaces. Independently canonical identity bytes, not directory slugs, supply exact company/role labels after restart-like reconstruction. Distinct UUIDs with Unicode-equivalent byte-different labels stay separate in RPC options and TUI render without normalization or disambiguation suffixes. Repeated reads preserve config, root, application, library, and session names, bytes, and private modes. Colliding and malformed children remain existing duplicate/drifted classifications and are not repaired or adopted. Core, send, append, reload, new-session, and tool-activation spies stay unused. This is local synthetic acceptance, not provider-wire or process-shutdown evidence.
|
|
418
|
+
- `tests/workflow/legacy-overlay-migration-acceptance.test.mjs` cohesively witnesses P3-11 through P3-15 and P3-47 through the registered Applications overlay and public workspace migration method. Independently canonical synthetic manifest, canonical state, vacancy, assisted artifact, sidecar, config, root, library, and session bytes are snapshotted with every name and mode. Identity-less list/open, preview cancellation, edited preview, and deterministic post-preview referenced-byte drift create no identity/state file. Confirmed migration without session identity or attachment publishes only the exact canonical private identity; concurrent independently prepared plans have one no-clobber winner with no retry, alternate, fork, or residue. Available Core, send, session append, new-session, and tool boundaries remain unused. This is local synthetic acceptance, not provider-wire evidence. Identity-only migration remains distinct from canonical state mutation.
|
|
419
|
+
- The earlier `P3-08` reconciliation test in `tests/workflow/application-workspace.test.mjs` remains supporting evidence for repeated canonical reconciliation, while the #63 session-bound cases remain regressions for exact identity-only migration and state/session races.
|
|
420
|
+
- `tests/workflow/transient-process-shutdown-acceptance.test.mjs` witnesses P3-30 with a real RPC child and P3-58 with a dependency-free native-TUI PTY child. The PTY uses the public Applications and Workbench UI for attachment/activation, confirms Ask Pi, separates activation’s reload from a later explicit editor `/reload`, and observes two native reload lifecycle/resource cycles. A delayed public observer records the reconstructed Skill/tools/entry surface after resources discovery and records no agent, turn, message, tool-execution, or provider-request events; same-pid retention, shutdown loss, fresh-process absence, and exact private trees are asserted.
|
|
421
|
+
- `tests/workflow/no-automatic-provider-submission.test.mjs` witnesses P3-32 and P3-49 through real installed RPC children and a reachable loopback provider trap. P3-49 browses, opens, filters, clears, observes an empty result, and repeats reads against a valid catalog without attachment; its context/effect assertions cover custom entries, Career Skill metadata/content, Career tool schemas, Core calls, provider calls, and exact private trees. Browsing lists and opens a synthetic catalog application without attachment or session append. Confirmed no-Core mutations cover identity migration, persistent package creation, attached status revision, selected-original binding, and overlay Detach, including preview cancellation, confirm denial, and detach cancellation. Confirmed Detach appends only the exact session detachment, retains the used-application claim, and leaves workspace files unchanged; inactive assistance means this path does not reload. The trap request count stays zero after a positive probe, host agent/turn/message events stay absent, messages stay empty, raw tools stay inactive, and private bytes/modes outside the approved files stay exact. Core-routed vacancy/analyze/match, config-root and library-root mutations (including workspace-root detach), Ask Pi editor handoff, activated detach reload, and process shutdown are not this witness.
|
|
422
|
+
- `tests/workflow/payload-free-error-boundaries.test.mjs` witnesses P3-37 through registered commands/tools and one installed RPC child. Distinct synthetic sentinels are injected into resolver probes, Core invocation, source scan/extraction/validation, catalog/config/workspace reads, session loader/replay, UI select/editor/notification failures, persistence/commit failures, and public managed/raw tool errors. Public results are approved stable codes/messages, cancellation remains distinguishable, and stdout/stderr, RPC UI, session entries, result cards, and synthetic config/root/library/package/lock/temp sinks contain none of the injected private material. No logger or telemetry was added.
|
|
423
|
+
- `tests/workflow/no-private-sentinel-persistence.test.mjs` witnesses P3-33. Distinct synthetic Core-result, Core-error, provider-request, provider-response, prompt, and editor sentinels stay in process memory while registered create, migrate, and list/browse run and public readiness derivation reads an in-memory sentinel-bearing scan. Complete before/after snapshots cover config, application root, library, session file, result-card append, lock/temp/residue, synthetic package cache, and the writable temp tree. Approved writes are canonical only. Restart-like empty-memory reads reconstruct readiness from disk. The loopback trap observes no workflow request. This does not claim secure erasure or provider-wire behavior beyond that trap.
|
|
424
|
+
- `tests/workflow/capacity-boundary-matrix.test.mjs` exercises the reachable P3-44 public plan/commit/read cells: root entries 1,023/1,024/1,025, application entries and 64 revisions through registered status mutation, managed bytes 2,097,151/2,097,152/2,097,153, document reads 262,143/262,144/262,145, metadata size classification, and 80-character config labels plus the separate 120-character application-identity ceiling. Under-lock hooks cover root drift, application-entry `workspace_limit_reached`, revision drift, document-byte `workspace_limit_reached`, and oversized-metadata drift. Preview witnesses use actual canonical encoding and stay below 5,242,880; exactly-at/just-above preview bytes, a schema-valid 16,384-byte metadata file, a 262,144-byte vacancy write, and config/label under-lock injection remain unreachable without new production seams. P3-44 therefore stays deferred. This is local synthetic acceptance, not provider-wire evidence.
|
|
425
|
+
- `tests/workflow/inactive-model-context.test.mjs` witnesses P3-50 and P3-57 through isolated installed `pi --mode rpc --offline --no-session` children and a bounded synthetic loopback provider. P3-50 attaches one valid catalog application without assistance activation, then sends one ordinary non-Career prompt. P3-57 calls registered `/career-tools raw` with no valid activation, observes the stable inactive rejection, and proves a post-startup skill probe stays undiscovered so the command does not reload resources. The following ordinary prompt is the first provider request. Tests parse only that local synthetic body and do not print it: the explicit prompt occurs once, host tool schemas stay `read`, `bash`, `edit`, and `write`, and Career Skill discovery metadata, Skill content, `career_run`, and the raw `career_core_discover`, `career_core_resume`, and `career_core_job` schemas are absent. Tests construct the exact canonical identity-file bytes and the exact attachment session-entry JSON, then assert those serializations are absent along with application and library document bytes, the editor handoff, and private paths including the agent directory, home, sessions directory, Core trap, library, workspace, catalog, and identity file. The installed host system prompt includes the process working directory once; that host line is the only working-directory occurrence and is not a package-owned Career leak. The loopback acknowledgement is the assistant message. No Career Core executable runs. This is local synthetic provider-request evidence, not an external-provider witness.
|
|
426
|
+
- Other ledger rows remain specifications, not newly implemented tests. The 2 deferred rows require issue-owned behavioral integration; the map intentionally refuses to count fixture-only or narrower read evidence as completed mutation/UI coverage. #60 acceptance-map/fixture work is complete with 56 scoped witnesses and 2 explicit deferrals; P3-44 remains pending under #65 and P3-53 remains pending under #64.
|
|
427
|
+
|
|
428
|
+
## Next gate
|
|
429
|
+
|
|
430
|
+
The exact single-schema state/readiness contract, #60/#62/#141 foundations, and #63 identity migration are implemented. #64's attachment bytes, branch/restart/detach lifecycle, command authority, and context-on-demand mechanism are fixed; parsing/replay, pointer validation, on-demand Skill/tool discovery, explicit attach/detach/assistance-activation commands, catalog attach from any session including the explicit cross-UUID replacement offer, and application/vacancy/Resume command-authority convergence are implemented. Broader overlay UI remains later. #57 retains cover-letter writes. The #60 acceptance-map/fixture work is complete; remaining filesystem-race/integration behavior stays deferred only where the map explicitly assigns an owner and substantive rationale, and does not complete #64 or #65.
|