pi-career 0.4.0 → 0.4.2

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 CHANGED
@@ -2,6 +2,27 @@
2
2
 
3
3
  ## Unreleased
4
4
 
5
+ ## 0.4.2 - 2026-10-26
6
+
7
+ ### Added
8
+
9
+ - Added a documentation-only specification, threat model, synthetic black-box acceptance map, and bounded later implementation plan for issue #66 assisted cover-letter drafting. No provider/model integration, response capture, persistence, or production behavior is implemented by this release.
10
+
11
+ ### Changed
12
+
13
+ - Updated the exact lockfile-pinned Pi development suite from 1.0.2 to 1.0.4; the four Pi-provided runtime packages remain wildcard external peer dependencies.
14
+ - Pinned the development-only transitive `undici` resolution to 8.12.3 to remediate the reviewed low-severity advisories and preserve the zero-vulnerability full-audit publication gate. Runtime package dependencies remain unchanged.
15
+
16
+ ## 0.4.1 - 2026-10-04
17
+
18
+ ### Fixed
19
+
20
+ - Fixed native Pi input, editor, selection, confirmation, and exact workspace-mutation dialogs opened from the Career TUI so they own the foreground instead of rendering underneath the custom Career modal. After the native dialog completes or is cancelled, the same in-memory Career route and selection are restored with refreshed data; local document preview and cancellable Resume rescan remain inside the modal.
21
+
22
+ ### Changed
23
+
24
+ - Hardened post-publication registry verification for npm propagation and trusted-publisher metadata by retaining a finite 235-second scheduled retry bound and accepting only the reviewed canonical GitHub OIDC UUID in its bare or `oidc:`-prefixed representation. This does not add publication retry behavior.
25
+
5
26
  ## 0.4.0 - 2026-10-04
6
27
 
7
28
  ### Added
package/README.md CHANGED
@@ -19,9 +19,9 @@ It gives you:
19
19
  - a bounded resolver for a compatible external Career Core runtime;
20
20
  - no bundled native binary, telemetry, vacancy URL fetching, automatic document overwrite, or hidden provider call.
21
21
 
22
- Career Core remains authoritative for scores, evidence, warnings, uncertainty, matching, and proposal review. `pi-career` owns the Pi workflow and presentation layer; it does not reimplement Career Core algorithms or schemas.
22
+ Career Core remains authoritative for scores, evidence, warnings, uncertainty, matching, and proposal review. `pi-career` owns the Pi workflow and presentation layer; it does not reimplement Career Core algorithms or schemas. A separate [issue #66 assisted cover-letter proposal](docs/issue-66-assisted-cover-letter-proposal.md) is documentation-only and does not describe current behavior or authorize provider/model implementation.
23
23
 
24
- > **Version note:** this documentation describes `pi-career@0.4.0`. The prior native-free release is `pi-career@0.3.0`; `pi-career@0.2.0` is the earlier native-free release, and `pi-career@0.1.0` is the historical bundled-runtime release.
24
+ > **Version note:** this documentation describes `pi-career@0.4.2`. The prior `pi-career@0.4.1` and application-centric `pi-career@0.4.0` releases are immutable; `pi-career@0.3.0` and `pi-career@0.2.0` are earlier native-free releases, and `pi-career@0.1.0` is the historical bundled-runtime release.
25
25
 
26
26
  ### `/career` application mode
27
27
 
@@ -45,7 +45,7 @@ Windows is unsupported. npm enforces the package `os` allowlist; for a local or
45
45
  Install the exact reviewed version:
46
46
 
47
47
  ```bash
48
- pi install npm:pi-career@0.4.0
48
+ pi install npm:pi-career@0.4.2
49
49
  pi list
50
50
  ```
51
51
 
package/dist/index.js CHANGED
@@ -8162,13 +8162,14 @@ function listBodyLines(pane, view, cursor, operationLabel, width, theme) {
8162
8162
  return { lines, focusLine };
8163
8163
  }
8164
8164
  var CareerOverlay = class {
8165
- constructor(session, theme, keybindings, requestRender, close, maximumHeight = () => Number.MAX_SAFE_INTEGER) {
8165
+ constructor(session, theme, keybindings, requestRender, close, maximumHeight = () => Number.MAX_SAFE_INTEGER, presentNativeDialog) {
8166
8166
  this.session = session;
8167
8167
  this.theme = theme;
8168
8168
  this.keybindings = keybindings;
8169
8169
  this.requestRender = requestRender;
8170
8170
  this.close = close;
8171
8171
  this.maximumHeight = maximumHeight;
8172
+ this.presentNativeDialog = presentNativeDialog;
8172
8173
  }
8173
8174
  session;
8174
8175
  theme;
@@ -8176,6 +8177,7 @@ var CareerOverlay = class {
8176
8177
  requestRender;
8177
8178
  close;
8178
8179
  maximumHeight;
8180
+ presentNativeDialog;
8179
8181
  previewPage = 0;
8180
8182
  contentOffset = 0;
8181
8183
  helpVisible = !1;
@@ -8204,28 +8206,29 @@ var CareerOverlay = class {
8204
8206
  ];
8205
8207
  }
8206
8208
  keyedAction(key) {
8207
- return [
8208
- ["/", this.session.canFilterApplications, () => this.session.filterApplications()],
8209
- ["l", this.session.canFilterApplicationLifecycle, () => this.session.filterApplicationLifecycle()],
8210
- ["k", this.session.canClearApplicationFilter, async () => (this.session.clearApplicationFilter(), !0)],
8211
- ["v", this.session.canPreview, () => this.session.openPreview()],
8212
- ["a", this.session.canAttach, () => this.session.attach()],
8213
- ["i", this.session.canMigrate, () => this.session.migrate()],
8214
- ["n", this.session.canAddRoot, () => this.session.addRoot()],
8215
- ["x", this.session.canRemoveRoot, () => this.session.removeRoot()],
8216
- ["r", this.session.canRescan, () => this.session.rescan()],
8217
- ["c", this.session.canCreate, () => this.session.createApplication()],
8218
- ["g", this.session.canAnalyze, () => this.session.analyze()],
8219
- ["g", this.session.canMatch && !this.session.canAnalyze, () => this.session.match()],
8220
- ["t", this.session.canMatch, () => this.session.match()],
8221
- ["e", this.session.canEditVacancy, () => this.session.editVacancy()],
8222
- ["s", this.session.canUpdateStatus, () => this.session.updateStatus()],
8223
- ["m", this.session.canWorkspace, () => this.session.workspace()],
8224
- ["p", this.session.canAskPi, () => this.session.askPi()],
8225
- ["d", this.session.canDetach, () => this.session.detach()],
8226
- ["k", this.session.canClearVacancy, () => this.session.clearVacancy()],
8227
- ["o", this.session.canSelectOriginal, () => this.session.selectOriginal()]
8228
- ].find(([name, enabled]) => name === key && enabled)?.[2]();
8209
+ let entry = [
8210
+ ["/", this.session.canFilterApplications, !0, () => this.session.filterApplications()],
8211
+ ["l", this.session.canFilterApplicationLifecycle, !0, () => this.session.filterApplicationLifecycle()],
8212
+ ["k", this.session.canClearApplicationFilter, !1, async () => (this.session.clearApplicationFilter(), !0)],
8213
+ ["v", this.session.canPreview, !1, () => this.session.openPreview()],
8214
+ ["a", this.session.canAttach, !0, () => this.session.attach()],
8215
+ ["i", this.session.canMigrate, !0, () => this.session.migrate()],
8216
+ ["n", this.session.canAddRoot, !0, () => this.session.addRoot()],
8217
+ ["x", this.session.canRemoveRoot, !0, () => this.session.removeRoot()],
8218
+ ["r", this.session.canRescan, !1, () => this.session.rescan()],
8219
+ ["c", this.session.canCreate, !0, () => this.session.createApplication()],
8220
+ ["g", this.session.canAnalyze, !0, () => this.session.analyze()],
8221
+ ["g", this.session.canMatch && !this.session.canAnalyze, !0, () => this.session.match()],
8222
+ ["t", this.session.canMatch, !0, () => this.session.match()],
8223
+ ["e", this.session.canEditVacancy, !0, () => this.session.editVacancy()],
8224
+ ["s", this.session.canUpdateStatus, !0, () => this.session.updateStatus()],
8225
+ ["m", this.session.canWorkspace, !0, () => this.session.workspace()],
8226
+ ["p", this.session.canAskPi, !0, () => this.session.askPi()],
8227
+ ["d", this.session.canDetach, !0, () => this.session.detach()],
8228
+ ["k", this.session.canClearVacancy, !0, () => this.session.clearVacancy()],
8229
+ ["o", this.session.canSelectOriginal, !0, () => this.session.selectOriginal()]
8230
+ ].find(([name, enabled]) => name === key && enabled);
8231
+ return entry === void 0 ? void 0 : { run: entry[3], nativeDialog: entry[2] };
8229
8232
  }
8230
8233
  handleCancel() {
8231
8234
  if (this.helpVisible) {
@@ -8287,7 +8290,7 @@ var CareerOverlay = class {
8287
8290
  }
8288
8291
  let keyed = this.keyedAction(key);
8289
8292
  if (keyed !== void 0) {
8290
- this.requestRender(), keyed.finally(() => this.requestRender());
8293
+ keyed.nativeDialog && this.presentNativeDialog !== void 0 ? this.presentNativeDialog(keyed.run) : (this.requestRender(), keyed.run().finally(() => this.requestRender()));
8291
8294
  return;
8292
8295
  }
8293
8296
  this.handleListInput(data);
@@ -8442,25 +8445,35 @@ async function openCareerUi(ctx, view, agentDir, actions = {}) {
8442
8445
  careerPreviewLoader(agentDir, ctx),
8443
8446
  (error) => notifyCareerUiFailure(ctx, error)
8444
8447
  );
8445
- if (ctx.mode === "tui") {
8446
- await ctx.ui.custom((tui, theme, keybindings, done) => new CareerOverlay(
8447
- session,
8448
- theme,
8449
- keybindings,
8450
- () => tui.requestRender(),
8451
- () => done(void 0),
8452
- () => Math.max(1, Math.floor(tui.terminal.rows * 0.9))
8453
- ), {
8454
- overlay: !0,
8455
- overlayOptions: {
8456
- width: "90%",
8457
- maxHeight: "90%",
8458
- anchor: "center",
8459
- margin: { top: 1, right: 2, bottom: 1, left: 2 }
8448
+ if (ctx.mode === "tui")
8449
+ for (; ; ) {
8450
+ let action = await ctx.ui.custom(
8451
+ (tui, theme, keybindings, done) => new CareerOverlay(
8452
+ session,
8453
+ theme,
8454
+ keybindings,
8455
+ () => tui.requestRender(),
8456
+ () => done(void 0),
8457
+ () => Math.max(1, Math.floor(tui.terminal.rows * 0.9)),
8458
+ (pending) => done(pending)
8459
+ ),
8460
+ {
8461
+ overlay: !0,
8462
+ overlayOptions: {
8463
+ width: "90%",
8464
+ maxHeight: "90%",
8465
+ anchor: "center",
8466
+ margin: { top: 1, right: 2, bottom: 1, left: 2 }
8467
+ }
8468
+ }
8469
+ );
8470
+ if (action === void 0) return;
8471
+ try {
8472
+ await action();
8473
+ } catch (error) {
8474
+ notifyCareerUiFailure(ctx, error);
8460
8475
  }
8461
- });
8462
- return;
8463
- }
8476
+ }
8464
8477
  await runCareerUiRpc(ctx, session);
8465
8478
  }
8466
8479
 
@@ -4,7 +4,7 @@
4
4
 
5
5
  **Implementation status:** Gate 1, the approved #61 catalog foundation, both #62 read slices, #63 explicit identity migration, #64 attachment/command-authority slices through application/vacancy/Resume convergence, #141's single application-state schema, and the user-authored cover-letter transaction authorized by #57 are implemented in the current unreleased source for independent security/architecture review. Every application-state revision now uses [`pi.career.application_state`](single-application-state.md); former state `.v1`/`.v2` identifiers fail closed without migration or compatibility parsing. Config migration, display-identity migration, session attachment/activation, and other independently versioned package contracts are unchanged. The attached source detail and persistent Applications catalog derive readiness from each validated package plus the same bounded library-scan evidence; readiness is never persisted. The overlay renders all three component classifications, effective-Resume authority, lifecycle, and exact validated update time without exposing document bodies or paths. The integrated #58 overlay now derives a visible contextual next action from those classifications and the session's Analyze/Match result cards only when their resume and vacancy digests match the currently bound sources; historical cards with drifted bindings do not advance the recommendation. It is presentation only, does not execute an action, and remains subordinate to the persisted workspace plus explicit attachment/activation authority. The #58 SBDD evidence in `tests/workflow/overlay.test.mjs` includes one black-box journey that opens and attaches a persistent application, writes the vacancy, selects the Original, runs Analyze and Match, adds a user-authored cover letter, reviews derived Ready state, and records Applied. It cancels before each explicit step, reconstructs through a newly registered command surface after every successful boundary, and verifies cover-letter drift fails closed before restoring the exact bytes. The same suite covers the derived next-action classification table and digest-scoped result evidence. The Career modal now presents Applications and Resumes as its only top-level destinations; package setup, job description, Analyze, Match, Workspace, and Ask Pi remain contextual actions/direct routes with breadcrumb-aware back navigation. Application detail and prerequisite states make the current state, recommendation, and safe alternatives visible without crossing any consent boundary. `tests/workflow/application-workspace.test.mjs` adds transaction-level cover-letter cancellation, source drift, immutable revisions, and fault settlement; `tests/workflow/application-readiness-integration.test.mjs` verifies complete/incomplete readiness derivation; `tests/workflow/no-automatic-provider-submission.test.mjs` verifies no implicit provider/submission. Applied remains a separate explicit status update with its incomplete-package warning; package readiness remains derived. This status does not authorize release, publication, tagging, assisted cover-letter content, or any later gate.
6
6
 
7
- Career Core remains authoritative for every career-domain operation, schema, algorithm, warning, error, evidence rule, and assisted/non-authoritative result. This design defines only pi-career-owned configuration and local-file protocols. It does not copy a Core schema or algorithm.
7
+ Career Core remains authoritative for every career-domain operation, schema, algorithm, warning, error, evidence rule, and assisted/non-authoritative result. This design defines only pi-career-owned configuration and local-file protocols. It does not copy a Core schema or algorithm. Issue #66's assisted cover-letter contract/threat model is a later, specification-only proposal; it does not authorize provider behavior or alter this workspace implementation.
8
8
 
9
9
  The deliberately bounded **implemented Gate 1 and #57 slice** is:
10
10
 
@@ -1,6 +1,6 @@
1
1
  # Application-owned cover letters — issue #57
2
2
 
3
- This contract authorizes only user-authored Markdown or UTF-8 plain-text cover-letter artifacts in the application workspace. It does not authorize provider/model drafting, adoption of files, submission, or deletion.
3
+ This contract authorizes only user-authored Markdown or UTF-8 plain-text cover-letter artifacts in the application workspace. It does not authorize provider/model drafting, adoption of files, submission, or deletion. Issue #66 is documented separately as a **proposal only** in [issue-66-assisted-cover-letter-proposal.md](issue-66-assisted-cover-letter-proposal.md); it does not change this contract or its `user_authored` authority.
4
4
 
5
5
  ## Authority and state
6
6
 
package/docs/design.md CHANGED
@@ -14,7 +14,7 @@ In the current command-oriented implementation, the primary managed Pi surface i
14
14
 
15
15
  The TypeScript source is authoritative. Checked-in deterministic `dist/index.js` and `dist/pdf-worker.js` bundles support clean local, pinned-Git, and npm Pi loading without packaged runtime dependencies. The isolated PDF worker bundles the reviewed text extractor; Pi-provided imports remain external peers. Package metadata permits only separately reviewed public publication of the unscoped `pi-career` package to the canonical npm registry and declares only macOS/Linux installation through `os: ["darwin", "linux"]`.
16
16
 
17
- The workflow layer registers `/career`, `/career-setup`, `/career-library`, `/career-application`, `/career-vacancy`, `/career-match`, `/career-analyze`, `/career-workbench`, `/career-workspace`, the TUI-only `/career-review`, and the user-only TUI/RPC `/career-save`. Those `/career*` view commands open one view model; TUI overlay and RPC dialogs only render it. Application-workspace Gate 1 owns only explicit config-v2 migration, one private disjoint application root, immutable manifest/state/vacancy/original bindings, and read-only reconciliation; assisted workspace artifacts and deletion remain unimplemented later gates. Application state has one approved schema, [`pi.career.application_state`](single-application-state.md); append-only revision numbers remain integrity/history controls rather than schema versions, and former state `.v1`/`.v2` identifiers fail closed without migration. Setup/library scanning remains local. Core-backed `career_run` uses the same resolver and process helper as before. `/career-review` also invokes neither Core nor a provider; it reads one current in-memory non-PDF variant review, collects explicit canonical IDs after warning/discard and exact-change inspection, and prepares a later editor message containing only the handle and IDs. See [`product-flow.md`](product-flow.md) and [`application-workspaces.md`](application-workspaces.md).
17
+ The workflow layer registers `/career`, `/career-setup`, `/career-library`, `/career-application`, `/career-vacancy`, `/career-match`, `/career-analyze`, `/career-workbench`, `/career-workspace`, the TUI-only `/career-review`, and the user-only TUI/RPC `/career-save`. The [issue #66 assisted cover-letter proposal](issue-66-assisted-cover-letter-proposal.md) is a later specification/threat model only; it does not add a provider boundary, persistence, or current command behavior. Those `/career*` view commands open one view model; TUI overlay and RPC dialogs only render it. Application-workspace Gate 1 owns only explicit config-v2 migration, one private disjoint application root, immutable manifest/state/vacancy/original bindings, and read-only reconciliation; assisted workspace artifacts and deletion remain unimplemented later gates. Application state has one approved schema, [`pi.career.application_state`](single-application-state.md); append-only revision numbers remain integrity/history controls rather than schema versions, and former state `.v1`/`.v2` identifiers fail closed without migration. Setup/library scanning remains local. Core-backed `career_run` uses the same resolver and process helper as before. `/career-review` also invokes neither Core nor a provider; it reads one current in-memory non-PDF variant review, collects explicit canonical IDs after warning/discard and exact-change inspection, and prepares a later editor message containing only the handle and IDs. See [`product-flow.md`](product-flow.md) and [`application-workspaces.md`](application-workspaces.md).
18
18
 
19
19
  The user-only `/career-save <variant-handle>` workflow is specified in [`variant-save-workflow.md`](variant-save-workflow.md). It accepts only a current successful non-PDF materialization, uses supported Pi TUI/RPC editor and confirmation dialogs, and writes nothing until the exact preview is returned unchanged and separately confirmed. Saving performs no Core/provider/network call, appends no session entry, and preserves all runtime-resolution, private-stdin, registry, and payload-free error boundaries in this document.
20
20
 
@@ -0,0 +1,336 @@
1
+ # Issue #66 — operator-mediated assisted cover-letter drafting
2
+
3
+ **Status: proposed specification and threat model only.** This document is not implemented behavior, an executed test result, or authorization to change `src/`, `dist/`, Skills, tests, package metadata, scripts, workflows, or Career Core. Production implementation requires a separate owner approval after independent technical/security review. Existing cover-letter behavior remains governed by [cover-letter-contract.md](cover-letter-contract.md) and accepts only genuinely `user_authored` content.
4
+
5
+ ## 1. Decision and scope
6
+
7
+ The proposed MVP is a **transient, operator-mediated drafting and local-review flow** for one currently attached application. It may proceed only when all of these conditions remain true at every applicable boundary:
8
+
9
+ - the Pi session is ephemeral (`ctx.sessionManager.getSessionFile() === undefined`, normally `pi --no-session`);
10
+ - one application attachment is valid and current;
11
+ - the application has a current job description and a current effective Resume;
12
+ - the effective Resume authority is explicitly identified as `original` or `tailored`;
13
+ - the user explicitly starts drafting after any assistance-activation reload has completed;
14
+ - the user reviews the visible handoff and uses ordinary Pi submission as the sole provider-consent action; and
15
+ - any later candidate enters local review only through an explicit user paste, while the same process-local source-bound attempt remains valid.
16
+
17
+ This proposal does not add a provider client, credential access, hidden submission, automatic response capture, transcript scraping, web research, employer submission, automatic save, or model-callable drafting tool. It does not authorize assisted Resume creation or mutation. Career Core does not draft, review, or certify cover-letter prose or factual truth.
18
+
19
+ The proposed content authority is exactly `model_assisted_non_authoritative`, distinct from `user_authored`. Editing, reviewing, approving, or manually pasting assisted-derived text does not upgrade its authority. The current user-authored writer cannot be used as an assisted-content persistence bridge.
20
+
21
+ ## 2. Current behavior and evidence
22
+
23
+ ### 2.1 Implemented behavior that remains unchanged
24
+
25
+ Current application attachment and assistance activation use path-free custom session entries. Activation appends an existing non-private activation pointer, places the document-free Career handoff in the editor, and calls `ctx.reload()` without submitting it. Current tests establish that an ephemeral session retains its in-memory session entries across that same-process reload and loses them on process restart. Persistent activation can be reconstructed from session entries after restart. Neither result means extension-local variables survive reload.
26
+
27
+ The existing managed surfaces, compatibility names, and persistence contracts remain unchanged:
28
+
29
+ - `career_run` remains the primary managed tool;
30
+ - `career_core_discover`, `career_core_resume`, and `career_core_job` remain the exact raw compatibility names;
31
+ - `pi.career.application_state` remains the sole canonical application-state identifier;
32
+ - former or unknown state identifiers fail closed without migration or prefix compatibility;
33
+ - the current cover-letter parser/writer accepts only `authority: "user_authored"`; and
34
+ - existing exact-preview, confirmation, lock, no-clobber, capacity, concurrency, crash-settlement, payload-free-error, and privacy rules remain in force.
35
+
36
+ ### 2.2 Pi 1.0.4 API facts relevant to feasibility
37
+
38
+ The reviewed Pi documentation and installed declarations establish the following:
39
+
40
+ - Reload replaces the extension runtime. Code after `await ctx.reload()` belongs to the old runtime and must not reuse session-bound state.
41
+ - Reload emits `session_shutdown` with reason `reload`, loads a replacement extension runtime, emits `session_start` with reason `reload`, and then performs `resources_discover` with reason `reload`.
42
+ - `session_start` reasons are `startup|reload|new|resume|fork`; `session_shutdown` reasons are `quit|reload|new|resume|fork`; `session_tree` follows branch navigation.
43
+ - `input` exposes submitted text, input source, optional images, and streaming behavior before later prompt processing. It may continue, transform, or handle the input. A thrown `input` handler error is reported and processing continues, and later handlers may transform or consume text already validated by an earlier handler.
44
+ - `before_agent_start` sees the raw user prompt after Pi expansion, but its declared result is not a general prompt-cancellation gate. A package cannot invent a final cancellable provider-payload hook from these APIs.
45
+ - Provider/message hooks exist, including `after_provider_response`, `provider_stream_event`, and `message_end`. Their existence does not authorize this package to capture provider output.
46
+ - Ordinary user, system, assistant, tool, and metadata appends advance the session leaf. Leaf change is therefore not equivalent to branch navigation and cannot unconditionally invalidate an attempt that is expected to survive its own run.
47
+ - Accepted input may fail model/authentication preflight without `agent_start` or final settlement. `agent_settled` has no outcome field; `agent_before_settle` exposes `completed|aborted|error` but may be skipped on some abort paths.
48
+ - Active model-declared tools and registered callable tools are different sets. `codemode`/`deferred` tools may remain callable without being active declarations, and the current Career `input` handler refreshes the Career tool surface.
49
+ - `ctx.ui.setEditorText()` is direct in TUI but fire-and-forget in RPC; an RPC client may ignore it. RPC `editor()` is a request/response dialog, but Pi exposes no authenticated evidence that a later RPC `prompt` was a distinct human action rather than automatic client behavior.
50
+ - Pi adds a submitted ordinary message to the active branch. Sessions persist by default, and user/assistant messages are written to session JSONL unless Pi was started with `--no-session`.
51
+ - The provider request includes ordinary Pi system/context material and active-branch history in addition to the handoff. Retry, recovery, compaction, cache warming, queued work, and later turns may reuse context under Pi's own lifecycle.
52
+ - Compaction and context edits do not erase raw session history. Session export/share may expose prompts, responses, tool arguments, and other private content.
53
+
54
+ These facts rule out the earlier idea that a private process-local source snapshot could safely span the activation reload. They also rule out claiming “no prompt/response persistence” in an ordinary persistent Pi session, treating handoff bounds as complete provider-request bounds, or treating one `input` check/empty active-tool list as a proved security boundary.
55
+
56
+ ### 2.3 Proposal-only behavior
57
+
58
+ A future implementation would add a separate cover-letter drafting action that is available only **after** assistance activation and its reload are complete. That action would create a visible, bounded handoff in the replacement runtime. It would not call `ctx.reload()` again as part of creating the handoff.
59
+
60
+ The ordinary submitted prompt would first be checked at `input`, but that check would create only a `validated_input_not_started` state, not eligibility. A future approved final-boundary and metadata-only lifecycle correlation would have to bind protected prompt bytes, current sources, branch lineage, observed start, positive completion, and final settlement before paste eligibility could exist. Pi would own the provider request, display, errors, and ordinary transcript. The package would not inspect or copy the assistant response. A later local review action could accept one explicit user paste only if every currently blocking correlation and isolation requirement had been proved.
61
+
62
+ ## 3. Proposed contract
63
+
64
+ ### 3.1 Privacy prerequisite and consent
65
+
66
+ The drafting action must refuse when `ctx.sessionManager.getSessionFile()` is defined. The notice must explain that normal Pi submission persists the complete prompt and provider response and direct the user to start a separately reviewed `pi --no-session` run, attach the application there, activate assistance, and retry.
67
+
68
+ `--no-session` prevents Pi session-file persistence; it does not promise secure erasure. The TUI, RPC client, terminal scrollback, editor, OS, provider, and provider-side systems may retain submitted or displayed content. Those limitations must be visible before handoff. npm cache behavior remains unrelated and unchanged.
69
+
70
+ The only provider-consent action is the user's ordinary Pi submission of the visible handoff. The package must not call `ctx.modelRegistry.streamSimple()`, `pi.sendUserMessage()`, `pi.sendMessage(..., { triggerTurn: true })`, a provider API, or any network client for this flow.
71
+
72
+ ### 3.2 Eligibility and source authority
73
+
74
+ The action accepts no application ID, path, provider, model, temperature, or executable/tool argument. It operates only on the currently attached application reconstructed from the active branch and exact validated workspace pointer.
75
+
76
+ The source snapshot contains in process memory:
77
+
78
+ 1. session ID, a pre-submission branch anchor, and a future reviewed navigation/run generation identity;
79
+ 2. attachment, application, and activation IDs;
80
+ 3. exact resolved job-description UTF-8 text bytes and digest;
81
+ 4. exact resolved effective Resume UTF-8 text bytes, text digest, document binding, and authority (`original` or `tailored`);
82
+ 5. bounded company and role labels; and
83
+ 6. the exact explicit facts/instruction accepted from the visible handoff.
84
+
85
+ No arbitrary Resume fallback is permitted. If tailored is the current effective authority, the original cannot silently replace it. For an original PDF, “text” and its digest mean the existing validated scanner/extractor output after its current newline normalization, not raw PDF bytes; tailored text comes from the validated managed artifact. Raw-file identity, resolved text identity, and workspace binding must not be treated as interchangeable. Missing, ambiguous, stale, drifted, over-capacity, or unavailable sources fail closed.
86
+
87
+ The implementation must re-read and compare current source identities and digests:
88
+
89
+ - before constructing the handoff;
90
+ - in `input`, before ordinary submission is allowed;
91
+ - before accepting a pasted candidate;
92
+ - before each claims/review preview; and
93
+ - immediately before any future authorized persistence preview and again under its application lock.
94
+
95
+ A changed source never rebinds an old prompt or pasted candidate. It invalidates the attempt and requires a new explicit drafting action.
96
+
97
+ ### 3.3 Reload-safe lifecycle
98
+
99
+ The lifecycle is deliberately two-stage:
100
+
101
+ 1. **Activation stage:** existing attachment/activation behavior may reload Pi to expose the existing Career surface. No cover-letter attempt or source snapshot exists yet.
102
+ 2. **Drafting stage:** after the replacement runtime has completed `session_start` and resource discovery, the user explicitly invokes the cover-letter drafting action. The new runtime reads current sources and prepares the full handoff without another reload.
103
+
104
+ This removes any need to carry private source state across activation reload. A reload at any later point invalidates the attempt. So do shutdown, restart, new/resume/fork, actual tree navigation, attachment loss, session-ID change, source drift, cancellation, or a second competing attempt. Ordinary append-driven leaf advancement is expected during a run and must not itself invalidate. A future design must define a pre-submit anchor plus narrowly permitted run-owned descendant progression using metadata/lineage only; navigation, unrelated turns, unexpected ancestry, and intervening work must invalidate. No such generation/lineage contract is approved yet.
105
+
106
+ At `input`, a reserved, non-command handoff grammar would have to reject images, extension-originated submission, stale session/source state, duplicate submission, missing sections, reordered or changed protected source sections, and over-bound editable sections. The user may edit only explicitly marked facts and instruction fields. Company/role labels and exact source sections would compare byte-for-byte with the pending handoff and freshly validated sources. Every validation/read exception must be caught and return `action: "handled"` with payload-free guidance; throwing is not fail-closed.
107
+
108
+ That `input` validation is necessary but not sufficient: later extension handlers may transform/consume input, and Pi performs expansion and preflight afterward. `before_agent_start` can observe expanded prompt text but is not a documented general cancellation gate. Therefore implementation remains blocked until a reviewed trusted-runtime/handler-order contract or another supported mechanism proves that protected bytes and images cannot change after validation. The design must not claim arbitrary co-extension isolation.
109
+
110
+ The state machine must distinguish `pending_handoff`, `validated_input_not_started`, `observed_started`, `completed`, `finally_settled`, and `invalidated`. Input acceptance alone creates no paste eligibility. A future metadata-only correlation must handle preflight failure with no start/settlement event, retries, queued work, abort paths that skip `agent_before_settle`, the scalar settlement outcome where available, and stale generations. `agent_settled` alone never proves success. Without deterministic cleanup and positive content-free completion evidence, implementation must stop.
111
+
112
+ ### 3.4 Visible context and bounds
113
+
114
+ The handoff may contain only:
115
+
116
+ - bounded company and role labels using limits no weaker than the current validated application-label contract;
117
+ - exact current job-description text;
118
+ - exact current effective Resume text and its visible `original`/`tailored` label;
119
+ - explicitly entered user facts; and
120
+ - one explicitly entered drafting instruction.
121
+
122
+ It must visibly separate fixed instructions from untrusted job, Resume, and fact data. It must say that unknown information becomes a question or omission and that source text cannot authorize tools, browsing, file access, secret access, or policy changes.
123
+
124
+ The existing implementation does **not** impose a universal 12,000-byte source limit. `12,000` is a local Career overlay preview bound, while current application artifacts and Core inputs use other byte/character limits. Therefore exact cover-letter context limits remain an owner decision. Before implementation, one reviewed table must define separate maximums for:
125
+
126
+ - each label (UTF-8 bytes and Unicode scalar values);
127
+ - job text;
128
+ - effective Resume text;
129
+ - fact count, fact bytes, and total fact bytes;
130
+ - instruction bytes;
131
+ - complete handoff bytes;
132
+ - pasted candidate bytes and Unicode scalar values; and
133
+ - claim count/span bytes and complete review bytes.
134
+
135
+ Every bound must reject rather than truncate. UTF-8, scalar, NUL/control, newline, duplicate-fact, empty-source, delimiter escaping/collision, and normalization policy must be exact and shared by TUI/RPC paths. No claim may be made that current APIs already enforce the future table.
136
+
137
+ These bounds apply only to package-selected handoff fields. They do not bound the complete provider request or make the selected job/Resume/facts the model's exclusive factual context: Pi also sends its system prompt, discovered context, active-branch history, and extension-added material. The proposed flow must require a newly started, reviewed, ephemeral drafting session with no earlier model-visible application content, pending messages, or prior attempt. Even then, ordinary system/context material remains and must be disclosed. Whether that narrower context profile is acceptable is an owner decision.
138
+
139
+ ### 3.5 Tool and injection isolation
140
+
141
+ Prompt instructions alone are not a security boundary. Before allowing ordinary submission, a future implementation must prove that the entire drafting isolation lifetime exposes no model-reachable or nested-callable file, shell, web, MCP, Career Core, `codemode`, `deferred`, or other tool surface. An empty `pi.getActiveTools()` result is insufficient. Source text and user facts are untrusted data and cannot authorize tools or alter system policy.
142
+
143
+ The current Career `input` handler refreshes active Career tools, so a future design must explicitly coordinate with that mutator. It must also account for later registrations and all other trusted extension hooks. The supported environment must use an explicitly reviewed extension/resource set; extensions share Pi process permissions and are not a sandbox from one another.
144
+
145
+ A temporary restore-after-settlement design is unsafe because the untrusted source prompt and response remain in ordinary in-memory context and can influence later tool-enabled turns. The safer proposed boundary is a dedicated, queue-empty, no-tool ephemeral drafting session whose no-tool lease remains until copy-out and shutdown, with no tool restoration or unrelated continuation in that session. This is still only a design direction: exclusive loadout ownership, callable-versus-declared reachability, compare-before-change behavior, retries, cache warming, queued/deferred work, competing commands, abort, reload, and shutdown must be proved. If any other actor can make a tool reachable or submit unrelated work, drafting remains blocked.
146
+
147
+ The model's non-invention instruction is guidance, not a proof. The package cannot guarantee that generated prose contains no unsupported claim. Local claims review must therefore remain advisory and human-controlled.
148
+
149
+ ### 3.6 Provider result and explicit paste
150
+
151
+ Pi—not pi-career—displays the provider response and any provider refusal, timeout, rate limit, transport error, or malformed model output. This package must not inspect `provider_stream_event`, `message_end`, session entries, RPC event history, or any provider body to recover the draft.
152
+
153
+ Consequences:
154
+
155
+ - The package cannot claim to reject or discard an over-bound provider response before Pi displays it.
156
+ - Provider errors are governed by Pi's normal UI/RPC behavior, not converted into pi-career adapter errors.
157
+ - A scenario can prove that pi-career adds no raw error/body logging or persistence, but cannot claim Pi/provider wire secrecy from package tests.
158
+
159
+ Only after an observed start, a positively correlated `completed` outcome, final settlement, and unchanged generation/source state may the user invoke one local review action and explicitly paste one candidate. This sequence is a blocking feasibility requirement, not an established Pi contract; if it cannot be proved without inspecting assistant content, no candidate is eligible. The action accepts the paste only while that attempt remains valid and after current-source revalidation. The paste is bounded and validated locally. The user may paste the response unchanged or an edited version, but either remains `model_assisted_non_authoritative` and bound to the original source snapshot. The package neither proves that the paste came from the provider nor treats that provenance limitation as truth certification.
160
+
161
+ A paste after reload, restart, branch change, source drift, attachment change, failed/aborted run, or attempt invalidation is rejected. Text similarity, labels, session history, and a user assertion cannot recreate eligibility.
162
+
163
+ ### 3.7 Claims review and authority
164
+
165
+ Claims review shows bounded spans or numbered candidate claims and asks the operator to retain, revise, remove, or convert each to a question. It must not label a claim “verified,” “true,” “Career Core approved,” or equivalent. It cannot infer facts from plausibility, company knowledge, the model name, or omitted source material.
166
+
167
+ Any operator edit creates a new transient candidate under the same `model_assisted_non_authoritative` authority and the same still-valid source snapshot. Approval does not promote authority. Career Core is not called to review prose.
168
+
169
+ The existing `user_authored` cover-letter action is not an authorized persistence route for model-assisted or assisted-derived bytes. Its UI and parser assert `user_authored`; sending assisted content through it would erase provenance and violate this contract. This is an operator/authorization rule and a prohibition on package-owned bridges, prefill, or automatic invocation—not a claim that the unchanged writer can detect arbitrary assisted text pasted after copy-out, editing, reload, or restart.
170
+
171
+ ### 3.8 Persistence remains separately blocked
172
+
173
+ The MVP may end after transient review and explicit copy-out. It adds no artifact, state revision, sidecar, custom entry, prompt cache, backup, or recovery file.
174
+
175
+ Persisting assisted content requires an additional owner decision and implementation authorization because current project instructions prohibit unapproved payload persistence and the current parser accepts only `user_authored`. Any later authorized persistence design must:
176
+
177
+ - add exact `model_assisted_non_authoritative` parsing without accepting aliases or authority upgrades;
178
+ - retain `pi.career.application_state` as the sole state identifier, with no migration, history rewrite, or compatibility-prefix reader;
179
+ - document that older readers reject the new authority and fail closed rather than reinterpret or rewrite it;
180
+ - bind the artifact to the exact job/effective-Resume digests and effective authority;
181
+ - show an exact unchanged content/file preview;
182
+ - obtain a distinct artifact-persistence approval and the existing separate workspace-mutation approval;
183
+ - publish an immutable Markdown/plain-text artifact before committing state last;
184
+ - revalidate source/state before preview and under lock;
185
+ - preserve capacity, concurrency, crash settlement, collision handling, and no-clobber behavior; and
186
+ - never promote assisted content to `user_authored` because of edits or approvals.
187
+
188
+ Until that contract is separately authorized and implemented, the correct persistence result is “unsupported; copy-out only,” not fallback to the current writer.
189
+
190
+ ### 3.9 TUI and RPC behavior
191
+
192
+ The validation/state machine must be shared. TUI may place the reviewed handoff in the main editor. RPC cannot assume `set_editor_text` was honored because it is fire-and-forget and clients may ignore it. An RPC flow must use the supported `editor()` request/response to expose the handoff, then require the operator/client to issue a separate ordinary `prompt`; `input` must compare the actual prompt with the pending handoff before allowing it.
193
+
194
+ No supported RPC client may automatically submit the editor response as part of the extension UI response. Pi cannot distinguish an auto-submitting client from a human-controlled client when both emit the same editor response and later `prompt` record, so operator mediation is an external trusted-client conformance requirement, not an extension-observable guarantee. Supported clients require separate review and negative tests; all others keep RPC drafting unavailable. Native custom TUI components are not a substitute because `custom()` returns `undefined` in RPC.
195
+
196
+ ## 4. Threat model
197
+
198
+ | Threat | Required mitigation or fail-closed result |
199
+ |---|---|
200
+ | Persistent Pi session stores job, Resume, facts, prompt, and response | Refuse drafting unless `getSessionFile()` is undefined; explain remaining client/provider/OS retention. |
201
+ | Activation reload loses a private source snapshot | Create no attempt before reload; require a second explicit action in the replacement runtime. |
202
+ | Old handoff is submitted after source change | Reserved-envelope validation compares protected exact sections and freshly read identities/digests; every failure is handled rather than thrown. Final post-expansion integrity remains a blocking feasibility gate. |
203
+ | User edits protected job/Resume/labels | Exact structured parser rejects changed, missing, reordered, duplicate, or delimiter-colliding protected sections. |
204
+ | Later handler or Pi expansion changes validated input | Require reviewed ordering/trust and final-boundary evidence; if protected bytes/images cannot be proved unchanged, block drafting. |
205
+ | Job/Resume prompt injection requests secrets, browsing, or tools | Treat all sources as data; require a dedicated no-tool session through copy-out/shutdown; otherwise block before submission. |
206
+ | Model invents experience, employers, dates, metrics, motivation, or company facts | Fixed instruction requests omission/questions; bounded human claims review remains advisory and cannot certify truth. |
207
+ | Package captures provider response or transcript | No provider/message/session-history response hook for this flow; candidate enters only by explicit paste. |
208
+ | Overlarge provider response | Pi may display it; package makes no interception claim. Explicit pasted candidate is rejected if over bound. |
209
+ | Provider failure leaks through adapter errors | Package does not ingest provider errors/bodies; no package log or persistence. Pi/provider behavior is outside this adapter guarantee. |
210
+ | Assisted text is laundered through `user_authored` | No bridge to current writer; persistence remains unsupported until exact new authority is authorized. |
211
+ | Approval/editing upgrades authority | Every assisted-derived transient candidate remains `model_assisted_non_authoritative`. |
212
+ | Restart/reload/tree/fork/resume/new silently recovers eligibility | Invalidate; no recovery from entries, transcript, text similarity, or workspace bytes. Ordinary run-owned leaf advancement alone is not tree navigation; exact permitted lineage remains to be proved. |
213
+ | Source drifts during provider work or review | Revalidate before paste and every review/preview; discard local eligibility on mismatch. |
214
+ | Prior branch history/context contaminates source authority | Require a fresh reviewed ephemeral context profile; disclose that system/context material still accompanies the handoff and block pending/unrelated work. |
215
+ | Tools are restored while untrusted drafting context remains | Keep the dedicated session no-tool through copy-out and shutdown; do not continue ordinary tool-enabled work in it. |
216
+ | Second or concurrent attempt races the first | One generation token per session/application; new attempt explicitly cancels old or is rejected; late work cannot display as eligible or persist. |
217
+ | RPC client ignores or auto-submits handoff | Pi cannot authenticate the distinction; allow only separately reviewed conforming clients or keep RPC unavailable. |
218
+ | Cancellation, preflight failure, retry, cache warming, or queued work crosses attempt boundaries | Clear or conservatively invalidate; prove event ordering, outcome correlation, isolation lifetime, and no unrelated reuse. |
219
+ | Crash suggests recoverable draft | No package persistence or adoption; restart requires a new ephemeral session attempt. |
220
+ | Future save races source/state or collides | Separate authorization; exact preview, distinct approvals, lock-time revalidation, state-last, no-clobber, fail-closed settlement. |
221
+
222
+ ## 5. Synthetic black-box SBDD acceptance map
223
+
224
+ These Given/When/Then rows are a future acceptance specification, not executable evidence or witnessed behavior.
225
+
226
+ | ID | Given | When | Then |
227
+ |---|---|---|---|
228
+ | 66-01 | Persistent Pi session with a valid attached application | User starts assisted drafting | Refuse before reading private source bodies into a handoff; explain `--no-session` and retention. |
229
+ | 66-02 | Ephemeral session, valid attachment, current job, effective original Resume | User starts drafting after activation reload | Build one bounded visible handoff labelled `original`; make no provider call. |
230
+ | 66-03 | Same with current tailored Resume | User starts drafting | Bind only tailored identity/text/digest and label it `tailored`; never fall back to original. |
231
+ | 66-04 | Missing job, effective Resume, activation, or valid attachment | User starts drafting | Refuse payload-free before editor/provider input. |
232
+ | 66-05 | Assistance is inactive | User activates it | Perform existing activation/reload only; create no cover-letter attempt or private snapshot. |
233
+ | 66-06 | Activation reload completed in a replacement runtime | User explicitly starts drafting | Read and validate sources in that runtime; do not depend on pre-reload variables. |
234
+ | 66-07 | A pending exact handoff exists in TUI under the reviewed handler/resource profile | User submits it normally | Reserved-envelope validation handles every failure; later-boundary evidence proves protected bytes/images unchanged before the run or drafting remains blocked. |
235
+ | 66-08 | A pending RPC editor handoff exists | RPC client returns editor content but sends no prompt | No provider work begins and no attempt becomes submitted. |
236
+ | 66-09 | Same, using a separately reviewed conforming client | Operator directs a separate ordinary prompt | Apply the same envelope/source checks as TUI; client conformance—not `InputEvent`—supplies the human-consent assumption. |
237
+ | 66-10 | An unreviewed RPC client ignores UI or auto-submits | Drafting is requested | Keep RPC drafting unavailable; do not claim Pi can detect indistinguishable automatic records. |
238
+ | 66-11 | User edits only bounded fact/instruction fields | Prompt is submitted | Accept exact allowed edits, freshly bind them, and preserve protected source sections. |
239
+ | 66-12 | User edits, removes, reorders, or duplicates protected source/label sections | Prompt is submitted | Handle/reject before provider processing; invalidate pending handoff. |
240
+ | 66-13 | Input includes images, extension-originated submission, malformed envelope, or validation throws | Input arrives | Catch and return handled with payload-free guidance; no assisted run or eligibility. |
241
+ | 66-14 | Job/Resume contains instructions to browse, call tools, reveal secrets, or override policy | Draft prompt is submitted | Source remains quoted untrusted data; the dedicated session exposes no declared or callable tool through copy-out/shutdown. |
242
+ | 66-15 | Any declared, nested-callable, `codemode`, `deferred`, Career, or open-world tool would remain reachable | Submission is attempted | Block the assisted action before provider input. |
243
+ | 66-16 | Unknown or contradictory employer/date/metric/skill/motivation fact | Model drafts | Prompt requests omission or a marked question; later review never treats inferred text as verified. |
244
+ | 66-17 | Facts, instruction, source, or total handoff exceeds an approved bound | Handoff is prepared/submitted | Reject without truncation, provider call, or persistence. |
245
+ | 66-18 | Source/attachment changes before `input` | User submits old handoff | Reject and invalidate; never rebind old text. |
246
+ | 66-19 | Source changes after submission but before paste | User opens local review | Reject paste eligibility and require a new attempt. |
247
+ | 66-20 | Source changes after paste but before claims preview | Preview opens | Discard candidate and fail closed. |
248
+ | 66-21 | Source changes after a future persistence preview | Save is attempted under lock | Future writer rejects; no artifact/state commit or overwrite. |
249
+ | 66-22 | Pi displays a valid provider response | User does nothing | Package captures and stores nothing; no local draft becomes eligible merely from displayed content. |
250
+ | 66-23 | Pi displays an overlarge or malformed response | User does nothing | Package makes no interception claim and stores nothing. |
251
+ | 66-24 | Provider refuses, times out, rate-limits, errors, retries, recovers, compacts, or cache-warms | Pi processes the lifecycle | Package adds no raw body/error log or reconstructed draft; the attempt is ineligible unless the exact approved metadata-only completion sequence is proved. |
252
+ | 66-25 | Observed-started attempt has positively correlated completion/final settlement, unchanged sources/generation, and no unrelated lineage | User explicitly pastes one bounded candidate | Accept one transient `model_assisted_non_authoritative` candidate; do not prove provider provenance. |
253
+ | 66-26 | Pasted candidate exceeds byte/scalar bounds or has invalid encoding/control content | Review starts | Reject without truncation or persistence. |
254
+ | 66-27 | No submitted attempt, or attempt was invalidated | User pastes an old draft | Reject; text similarity, labels, and user assertion cannot recreate eligibility. |
255
+ | 66-28 | Candidate contains an unsupported metric/employer/date/claim | Claims review opens | Present it for retain/revise/remove/question judgment without truth certification. |
256
+ | 66-29 | User revises or approves candidate | Review completes | Keep `model_assisted_non_authoritative`; never promote to `user_authored`. |
257
+ | 66-30 | User requests Career Core prose/truth certification | Review continues | Refuse the claim and make no Core prose-review call. |
258
+ | 66-31 | Package-owned assisted candidate/attempt is still known in process | User requests the current `user_authored` action through a package-owned route | Do not bridge, prefill, or automatically invoke that writer; explain the authority mismatch. Do not claim detection of arbitrary external paste after copy-out/restart. |
259
+ | 66-32 | User declines review or copy-out | Flow ends | Clear candidate/attempt; create no artifact, state, custom entry, backup, or sidecar. |
260
+ | 66-33 | User cancels at handoff, submission preparation, paste, claims review, or preview | Cancellation occurs | Clear relevant transient state; no automatic retry or save. |
261
+ | 66-34 | Accepted input fails preflight without `agent_start`, or an observed run aborts/errors | Available lifecycle/timeout boundary occurs | Conservatively invalidate; do not assume a never-started run emits settlement or that `agent_settled` proves success. |
262
+ | 66-35 | Actual tree navigation, reload, new, resume, fork, shutdown, or process restart occurs | Lifecycle event fires | Clear pending/submitted attempt and candidate; ordinary owned descendant appends follow the separately proved lineage rule, and no recovery occurs from transcript/workspace. |
263
+ | 66-36 | Two attempts target the same application/session | Second begins | Apply exact one-generation policy; no stale candidate can become eligible. |
264
+ | 66-37 | Labels collide across applications | Handoff/paste is validated | Attachment/application/source identity controls authority; labels never select the application. |
265
+ | 66-38 | User asks to research a company or submit to an employer | Drafting action is used | Refuse; no web fetch, provider client, employer submission, or external tool action. |
266
+ | 66-39 | Private synthetic sentinels exist in source/facts/candidate | Package-controlled logs/errors/config/workspace are inspected | Sentinels are absent; only the operator-approved ephemeral Pi/provider handoff contains selected context. |
267
+ | 66-40 | Crash occurs after response or paste | Process restarts | No package draft recovery/adoption; approved workspace bytes remain unchanged. |
268
+ | 66-41 | Future assisted persistence is separately authorized | Exact file preview is returned changed | Reject and require a fresh preview; no authority change or write. |
269
+ | 66-42 | Same | Exact preview is unchanged but artifact approval is declined | Write nothing. |
270
+ | 66-43 | Same | Artifact approval succeeds but distinct workspace mutation approval is declined | Write nothing; approvals are not interchangeable. |
271
+ | 66-44 | Same | Collision, capacity, lock, state drift, or crash occurs | Preserve immutable history, no-clobber, state-last, and existing settlement classifications. |
272
+ | 66-45 | Older pi-career reader encounters future assisted authority under canonical state ID | It reads the state | Fail closed; do not reinterpret as user-authored, migrate, rewrite, or prefix-match. |
273
+ | 66-46 | TUI and separately reviewed conforming RPC client execute equivalent synthetic scenarios | Results are compared | Enforceable eligibility, bounds, invalidation, and authority outcomes match; RPC human mediation remains a client trust assumption and unsupported clients remain unavailable. |
274
+ | 66-47 | Draft completes in a dedicated no-tool ephemeral session | Candidate review/copy-out finishes | Keep tools unavailable and require session shutdown; later tool-enabled continuation in that contaminated context is unsupported. |
275
+ | 66-48 | Prior application prompts, pending messages, or earlier attempt exist in the session | Drafting starts | Refuse and require a fresh reviewed ephemeral session; handoff bounds are never described as complete request bounds. |
276
+
277
+ ## 6. Bounded later implementation and verification plan
278
+
279
+ ### Phase A — owner decisions and executable Pi probes (no product implementation)
280
+
281
+ 1. Approve the exact bounds table described in §3.4.
282
+ 2. Decide whether requiring `--no-session` is acceptable product behavior. If persistent sessions must be supported, first authorize a different retention contract; “no prompt/response persistence” cannot be claimed.
283
+ 3. Approve the exact structured handoff grammar and which fact/instruction edits are allowed.
284
+ 4. Approve a dedicated-session no-tool isolation design. Probe Pi 1.0.4 for declared versus callable reachability, the existing Career input-refresh conflict, all loadout writers, queue/cancellation/retry/cache-warming behavior, and a no-restoration-through-shutdown lifetime.
285
+ 5. Prove a fail-closed final prompt boundary after handler composition/expansion. If supported APIs cannot prove protected bytes/images unchanged, stop.
286
+ 6. Define a pre-submit branch anchor and exact permitted run-owned descendant lineage; distinguish ordinary appends from navigation and unrelated work.
287
+ 7. Probe TUI and RPC separately for handoff presentation and ordinary submission. Define reviewed RPC-client conformance as an external trust prerequisite or keep RPC blocked.
288
+ 8. Define exact metadata-only events for accepted-but-not-started, observed start, completion outcome, abort/failure, final settlement, and deterministic cleanup. If positive eligibility cannot be correlated without response content, stop.
289
+ 9. Decide whether issue #66's first implementation ends at transient review/copy-out or separately authorizes future assisted persistence.
290
+
291
+ ### Phase B — transient implementation, only after separate approval
292
+
293
+ 1. Add a small in-memory state machine: `idle -> pending_handoff -> validated_input_not_started -> observed_started -> completed -> finally_settled -> pasted_candidate -> reviewed`, with conservative invalidation from every state.
294
+ 2. Add the post-reload explicit drafting action and exact source/handoff validator. Do not change activation entries or persist private drafting state.
295
+ 3. Enforce a fresh ephemeral-session context profile and the approved dedicated no-tool isolation lifetime through copy-out/shutdown.
296
+ 4. Validate the reserved ordinary prompt fail-closed at `input` and at the approved final boundary; do not automatically submit it.
297
+ 5. Add exact branch-lineage/generation and metadata-only run-outcome correlation established in Phase A.
298
+ 6. Add explicit bounded paste and advisory claims review. Do not inspect provider/message/session output.
299
+ 7. Preserve existing reader/writer, runtime resolver, Core, privacy, and packaging contracts. Any separately authorized authoritative TypeScript implementation must add synthetic tests and reproducible tracked `dist` updates required by `npm run check:dist`; this specification phase changes neither.
300
+
301
+ ### Phase C — optional persistence, separately authorized again
302
+
303
+ 1. Specify exact new authority parsing and old-reader fail-closed behavior under `pi.career.application_state`.
304
+ 2. Implement immutable artifact/state transaction with exact unchanged preview, distinct artifact/workspace approvals, lock-time source revalidation, no-clobber publication, and state commit last.
305
+ 3. Prove no user action or approval upgrades assisted authority.
306
+
307
+ ### Verification
308
+
309
+ Before any implementation review:
310
+
311
+ - turn every applicable §5 row into synthetic black-box SBDD evidence;
312
+ - add focused lifecycle probes for activation reload, later reload, restart, ordinary leaf advancement versus branch navigation, input-handler errors/transforms, expansion, preflight-no-start, abort, retry/recovery/compaction/cache warming, queued input, completion outcome, and settlement;
313
+ - test declared and callable tool reachability, existing Career refresh conflicts, dedicated-session no-restoration behavior, TUI, and reviewed conforming RPC clients independently; keep unsupported RPC unavailable rather than claiming automatic-client detection;
314
+ - use synthetic resumes, job descriptions, facts, provider events, and sentinel errors only;
315
+ - distinguish scenario specifications, unit/integration evidence, host-Pi evidence, and provider-wire evidence;
316
+ - obtain independent technical/security review of privacy, tool isolation, lifecycle binding, authority, old-reader behavior, and transaction safety; and
317
+ - run the complete governing verification ladder from `AGENTS.md`, reporting exact results and objective skips.
318
+
319
+ ## 7. Unresolved authorization decisions
320
+
321
+ The following decisions block production implementation:
322
+
323
+ 1. Is an ephemeral Pi session mandatory, as required by the current no-persistence boundary, or may ordinary Pi prompt/response persistence be authorized with revised consent and retention language?
324
+ 2. What are the exact context, fact, instruction, handoff, candidate, and claims bounds?
325
+ 3. What exact editable handoff grammar is approved?
326
+ 4. Can Pi 1.0.4 provide a reviewed, race-safe dedicated no-tool session through copy-out/shutdown, including callable tools, Career refresh, retries, cache warming, and queued/deferred work?
327
+ 5. Can supported APIs prove a fail-closed final prompt boundary after all input handlers and expansion, or must drafting remain blocked?
328
+ 6. What branch anchor/lineage permits only the owned run's normal appends while rejecting navigation and unrelated work?
329
+ 7. Which metadata-only lifecycle events establish accepted-but-not-started, observed start, positive completion, failure/abort, final settlement, and deterministic cleanup without observing assistant content?
330
+ 8. What reviewed RPC-client behavior is trusted, and is unavailable RPC drafting acceptable for all other clients?
331
+ 9. Is a fresh ephemeral context plus no tool restoration and required shutdown after copy-out acceptable product behavior?
332
+ 10. Does the first separately approved implementation stop at transient review/copy-out?
333
+ 11. If persistence is later desired, does the owner explicitly authorize the new `model_assisted_non_authoritative` parser/writer and expected older-reader failure under the unchanged canonical state identifier?
334
+ 12. What retention statements are required for provider retry/cache behavior, Pi in-memory context/cache warming, TUI/terminal, RPC client, editor/clipboard, exports, and OS surfaces?
335
+
336
+ Until these decisions and independent review are complete, issue #66 remains a documentation/threat-model proposal only. No production provider/model behavior, automatic submission, assisted persistence, implementation, release, or publication is authorized.
@@ -1,6 +1,6 @@
1
1
  # Product flow roadmap
2
2
 
3
- The cross-repository migration plan and measured findings are recorded in [`career-run-roadmap.md`](career-run-roadmap.md). Career Core Phase 8, the first managed `career_run` implementation, the threat-reviewed package-owned Markdown/text save workflow in [`variant-save-workflow.md`](variant-save-workflow.md), and application-workspace Gate 1 in [`application-workspaces.md`](application-workspaces.md) are implemented. Synthetic PDF compatibility covers reviewed Chromium-generated tagged/untagged and ReportLab-generated two-page documents, embedded-font and multi-column layouts, and fail-closed text-unavailable cases. The Git-history/tree/hash-bound token-optimization study is complete: its frozen before/after evidence includes Pi Skill discovery and matching-task full-Skill context and records a 15.98% aggregate workflow reduction with no workflow regression. Application-workspace assisted resume artifacts, deletion, repair/adoption/archive/sync, broader workspace files, and further PDF extraction expansion remain later separately approved phases.
3
+ The cross-repository migration plan and measured findings are recorded in [`career-run-roadmap.md`](career-run-roadmap.md). Career Core Phase 8, the first managed `career_run` implementation, the threat-reviewed package-owned Markdown/text save workflow in [`variant-save-workflow.md`](variant-save-workflow.md), and application-workspace Gate 1 in [`application-workspaces.md`](application-workspaces.md) are implemented. The [issue #66 assisted cover-letter proposal](issue-66-assisted-cover-letter-proposal.md) is documentation-only and is not current behavior or an implementation authorization. Synthetic PDF compatibility covers reviewed Chromium-generated tagged/untagged and ReportLab-generated two-page documents, embedded-font and multi-column layouts, and fail-closed text-unavailable cases. The Git-history/tree/hash-bound token-optimization study is complete: its frozen before/after evidence includes Pi Skill discovery and matching-task full-Skill context and records a 15.98% aggregate workflow reduction with no workflow regression. Application-workspace assisted resume artifacts, deletion, repair/adoption/archive/sync, broader workspace files, and further PDF extraction expansion remain later separately approved phases.
4
4
 
5
5
  ## Approved target: `/career` as a local Pi application
6
6
 
@@ -55,7 +55,7 @@ Every overlay slice must prove with synthetic scenarios that:
55
55
 
56
56
  TUI overlay and RPC select/confirm dialogs render one Career view model. **Applications** and **Resumes** are its only peer top-level destinations. Setup belongs under Resumes; job description, Analyze, Match, Workspace, and Ask Pi are application or Resume context. The existing `/career-setup`, `/career-library`, `/career-application`, `/career-vacancy`, `/career-match`, `/career-analyze`, `/career-workbench`, and `/career-workspace` commands remain direct compatibility routes into that same hierarchy rather than tabs. A contextual route shows its full breadcrumb and Escape/Back returns to its owning destination; TUI Left/Right or Tab switches only the two destinations. RPC **Switch view** remains available but likewise lists only Applications and Resumes.
57
57
 
58
- Opening, browsing, filtering, switching destinations, viewing help, and highlighting do not attach, activate assistance, bind a Resume, call Core or a provider, or submit a message. Attach, add/remove/rescan library roots, create application, selected-original binding, analyze/match, vacancy edit/clear, status update, detach, Ask Pi, and Gate 1 workspace management are explicit contextual actions on that same model. Attached selected-original binding uses the existing exact workspace preview and separate confirmation, while Analyze and Match require that authoritative binding instead of falling back to another library Resume. Application detail and prerequisite/empty states show current state, a derived recommended next action, and safe alternatives without executing that recommendation. Footer hints show only current navigation and eligible actions; TUI help describes the hierarchy without performing work.
58
+ Opening, browsing, filtering, switching destinations, viewing help, and highlighting do not attach, activate assistance, bind a Resume, call Core or a provider, or submit a message. Attach, add/remove/rescan library roots, create application, selected-original binding, analyze/match, vacancy edit/clear, status update, detach, Ask Pi, and Gate 1 workspace management are explicit contextual actions on that same model. In TUI mode, a contextual action that needs a native Pi input, editor, selection, or confirmation temporarily dismisses the Career modal so the native dialog owns the foreground, then restores the same Career session with refreshed data; local preview and cancellable rescan remain inside the modal. Attached selected-original binding uses the existing exact workspace preview and separate confirmation, while Analyze and Match require that authoritative binding instead of falling back to another library Resume. Application detail and prerequisite/empty states show current state, a derived recommended next action, and safe alternatives without executing that recommendation. Footer hints show only current navigation and eligible actions; TUI help describes the hierarchy without performing work.
59
59
 
60
60
  The centered TUI modal has explicit host margin, one complete rounded theme-colored Unicode frame, connected separators, and equal interior horizontal padding. All header, breadcrumb, destination, body, preview, and footer rows are wrapped or bounded against the inner content width so the complete ANSI-styled outer line stays within Pi's supplied width. Its terminal-derived row budget always retains header, destinations, footer, and bottom border while scrolling only the content region; long catalogs keep selection visible, and detail/help expose Up/Down scrolling. Widths or heights too small for the minimum complete padded frame show only bounded resize guidance and no private preview bytes. TUI list labels wrap instead of being clipped so warning/state wording remains available at narrow supported widths; selection also has a visible text marker independent of theme color. Rendering is recomputed at the supplied viewport, so resizing does not retain stale layout or theme-colored output.
61
61
 
@@ -1,12 +1,12 @@
1
- # pi-career 0.4.0 release candidate
1
+ # pi-career 0.4.0 release record
2
2
 
3
- **Status: release-candidate metadata finalized; not a release-execution authorization.** Package and lockfile metadata, Skill metadata, the dated changelog, package assertions, release helpers, and README installation coordinate identify `0.4.0`. The complete local candidate ladder passed on 2026-10-04, including fixture parity against the exact reviewed Career Core `v0.2.0` checkout. The immutable candidate SHA is established only by the reviewed commit and is recorded externally rather than embedded self-referentially in tracked files. Tag creation, publication, and GitHub Release creation require clean same-SHA hosted evidence and separate explicit authorization.
3
+ **Status: released and immutable.** `pi-career@0.4.0` is published as `latest` from commit `31d1a8068ddff727cd7bb27e7546965def51e574`; the annotated unsigned `v0.4.0` tag and asset-free GitHub Release target that same commit. The complete local candidate ladder passed on 2026-10-04, including fixture parity against the exact reviewed Career Core `v0.2.0` checkout, and same-SHA hosted evidence passed before publication. The publication incident and recovery are recorded below and in [`releasing.md`](releasing.md). This historical record is not authorization to move or recreate the tag, rerun publication, republish the immutable npm version, or alter its GitHub Release.
4
4
 
5
5
  ## Version rationale and scope
6
6
 
7
7
  The selected **0.4.0** version reflects the substantial additive, user-visible application-centric workflow: one shared Career overlay across TUI/RPC, persistent application catalog and attachment, workspace-backed current vacancy and selected-original authority, explicit lifecycle/revision handling, readiness presentation, and the separately approved user-authored cover-letter transaction. This is not a breaking change to the canonical application-state contract. It does not justify 1.0: boundaries and later workspace gates remain deliberately narrow.
8
8
 
9
- The candidate scope is only the implemented application-centric experience recorded in the dated `CHANGELOG.md` 0.4.0 entry: one shared overlay and views; application create/catalog/attach; library-root add/rescan/remove; confirmation-gated analyze/match, vacancy edit, status update, and workspace management; workspace-backed vacancy/selected-original authority and lifecycle; derived readiness/next action; and user-authored cover-letter handling. Legacy identity-only migration remains exact-label, canonical-byte-previewed, separately confirmed, and no-clobber. Preserve the exact `career_run` primary managed tool, raw compatibility names, Core contract, local-first runtime boundary, consent/privacy/cancellation guarantees, and native-free package. Release claims must be checked against the final source rather than copied from this proposal.
9
+ The release scope is only the implemented application-centric experience recorded in the dated `CHANGELOG.md` 0.4.0 entry: one shared overlay and views; application create/catalog/attach; library-root add/rescan/remove; confirmation-gated analyze/match, vacancy edit, status update, and workspace management; workspace-backed vacancy/selected-original authority and lifecycle; derived readiness/next action; and user-authored cover-letter handling. Legacy identity-only migration remains exact-label, canonical-byte-previewed, separately confirmed, and no-clobber. Preserve the exact `career_run` primary managed tool, raw compatibility names, Core contract, local-first runtime boundary, consent/privacy/cancellation guarantees, and native-free package. Release claims must be checked against the final source rather than copied from this record.
10
10
 
11
11
  ### State and migration distinctions
12
12
 
@@ -29,41 +29,41 @@ All examples, UI captures, and render checks use synthetic labels/documents, syn
29
29
 
30
30
  Local documents and Pi sessions, RPC clients, editor history, backups/snapshots/sync, provider systems, and npm cache are distinct retention surfaces. Exact runtime acquisition receives no private document stdin, but ordinary npm cache or `_npx` residue may remain; this is not secure erasure. Do not promise cache cleansing or secure deletion. Existing privacy and persistence descriptions remain authoritative.
31
31
 
32
- ## Evidence matrix — prepared local candidate
32
+ ## Evidence matrix — completed release
33
33
 
34
- The 2026-10-04 results below cover the prepared candidate content before its SHA is frozen. They are local release-candidate evidence, not production-wire acceptance and not a substitute for externally recorded same-SHA hosted evidence on the final reviewed commit.
34
+ The 2026-10-04 local results cover the bytes later frozen at `31d1a8068ddff727cd7bb27e7546965def51e574`. Hosted and registry evidence below is tied to that same immutable commit.
35
35
 
36
- | Gate / evidence | Current classification | Remaining release requirement |
37
- | --- | --- | --- |
38
- | Candidate identity | Package, root lockfile entries, Skill metadata, package assertions, release helpers, README coordinate, and dated changelog all identify 0.4.0. | Freeze the reviewed bytes once and record the resulting full SHA externally without adding a self-referential placeholder to tracked files. |
39
- | Build / dist reproducibility | Passed immediately after `npm run build` against a temporary-index snapshot of the prepared candidate's tracked bundles. | On the clean committed SHA, run the standard immediate `git diff --exit-code -- dist/index.js dist/pdf-worker.js` proof. |
40
- | Token and complete adapter checks | `bench:tokens`, `bench:tokens:compare`, and `check` passed locally. | Require the protected same-SHA `Adapter checks` result after commit/push. |
41
- | Exact Career package runtime integration | Passed locally with exact `@revazi/career@0.2.0`, including synthetic managed discovery and representative resume/job operations. | Require the same-SHA six-target hosted matrix; this local result is not production-wire evidence. |
42
- | Production and full audits | Both passed with zero vulnerabilities at the explicit low threshold under exact Pi 1.0.2 development pins. | No baseline, exception, dependency downgrade, or lockfile workaround is permitted. |
43
- | Package/publication readiness | `check:publish` passed; the candidate remains native-free with four wildcard Pi peers and no production/optional/bundled dependency tree or lifecycle/publication script. | Rerun on the clean committed candidate and in the authorized release workflow. |
44
- | Fixture-backed compatibility | Passed, not skipped, against reviewed Career Core commit `536690632884c17336cc3c108f1bba0f254b862b` / `v0.2.0`. | Keep the fixture checkout read-only and local; do not add its machine path to runtime code or hosted CI. |
45
- | Offline Pi load and isolated install/remove | Both passed locally with `PI_OFFLINE=1`. | Preserve the offline no-acquisition boundary. |
46
- | Registry state | Canonical registry query confirmed `pi-career@0.4.0` absent. | Reconfirm authoritative absence immediately before any first, separately authorized publication attempt. |
47
- | Hosted candidate evidence | Intentionally external to the tracked candidate so evidence cannot change its SHA. | Require same-SHA `Adapter checks`, then dispatch `external-career.yml` on that exact ref and require all six jobs before release authorization. |
36
+ | Gate / evidence | Historical outcome |
37
+ | --- | --- |
38
+ | Release identity | Package, root lockfile entries, Skill metadata, package assertions, release helpers, README coordinate, and dated changelog identify 0.4.0; annotated unsigned tag `v0.4.0` and the asset-free GitHub Release target the frozen commit. |
39
+ | Build / dist reproducibility | Passed immediately after `npm run build` against the tracked bundles and again in the release gates. |
40
+ | Token and complete adapter checks | `bench:tokens`, `bench:tokens:compare`, and `check` passed locally; same-SHA Adapter run [`37191508057`](https://github.com/revazi/pi-career/actions/runs/37191508057) passed. |
41
+ | Exact Career package runtime integration | Passed locally with exact `@revazi/career@0.2.0`, including synthetic managed discovery and representative resume/job operations; same-SHA six-target run [`37191625998`](https://github.com/revazi/pi-career/actions/runs/37191625998) passed. |
42
+ | Production and full audits | Both passed with zero vulnerabilities at the explicit low threshold under exact Pi 1.0.2 development pins. No acceptance baseline was used. |
43
+ | Package/publication | `check:publish` passed and the native-free package was published through OIDC in run [`37191969844`](https://github.com/revazi/pi-career/actions/runs/37191969844). Registry integrity is `sha512-ks5xCnt2sDKCTzjvUuRQCJJSGaiHvt1lmwJNT6hhJLIV2MCmCrOUOG2dLW9uhdyGjHXR7Eu4SRlBXSNAVDtWpA==`; shasum is `460b9d69b42bc572bf966498a34c8818c3f26a6a`. |
44
+ | Fixture-backed compatibility | Passed, not skipped, against reviewed Career Core commit `536690632884c17336cc3c108f1bba0f254b862b` / `v0.2.0`; the fixture checkout remained read-only and local. |
45
+ | Offline and isolated package acceptance | Pre-release offline Pi load and isolated install/remove passed. After publication, an isolated agent-directory test passed exact install/list/load, acquisition, synthetic resume and job operations, offline failure, and removal. |
46
+ | Authoritative registry state | `pi-career@0.4.0` is immutable and `latest`; exact metadata, tarball bytes, `gitHead`, trusted publisher, provenance, and dist-tag were independently verified after propagation settled. |
47
+ | Publication incident and recovery | Run `37191969844` published successfully but failed during bounded post-publish registry verification. No rerun or republish occurred; the checked-in GitHub Release creator completed asset-free bookkeeping only after authoritative verification. |
48
48
 
49
- The complete local ladder passed: `npm ci`; `npm run build` plus immediate candidate-relative dist comparison; `npm run bench:tokens`; `npm run bench:tokens:compare`; `npm run check`; `npm run test:runtime-resolution`; `npm run test:career-package`; `npm run audit:production`; `npm run audit:full`; `npm run check:publish`; `PI_OFFLINE=1 npm run test:pi-smoke`; `PI_OFFLINE=1 npm run test:install`; fixture-backed `npm run test:compat`; `npm ls --omit=dev --depth=0`; `git diff --check`. The exact Pi development pins remain 1.0.2, and the resolved vulnerable `brace-expansion@5.0.9` selection is absent. Any content change after this evidence requires the affected gates again; after the candidate is committed, the standard clean-SHA local and hosted gates remain mandatory.
49
+ The complete pre-release local ladder passed: `npm ci`; `npm run build` plus immediate candidate-relative dist comparison; `npm run bench:tokens`; `npm run bench:tokens:compare`; `npm run check`; `npm run test:runtime-resolution`; `npm run test:career-package`; `npm run audit:production`; `npm run audit:full`; `npm run check:publish`; `PI_OFFLINE=1 npm run test:pi-smoke`; `PI_OFFLINE=1 npm run test:install`; fixture-backed `npm run test:compat`; `npm ls --omit=dev --depth=0`; `git diff --check`. The exact Pi development pins remain 1.0.2, and the resolved vulnerable `brace-expansion@5.0.9` selection was absent. These are historical candidate and release results, not authorization for a new publication action.
50
50
 
51
- ## Exact publication-path checklist (future authorized execution only)
51
+ ## Historical publication path and immutable-release safeguards
52
52
 
53
- The sole publication path remains existing [.github/workflows/release.yml](../.github/workflows/release.yml), triggered only by reviewed annotated unsigned `v*.*.*` tags. Before any separately authorized tag action, verify against the exact workflow and maintainer-controlled configuration:
53
+ The release used the sole publication path, [.github/workflows/release.yml](../.github/workflows/release.yml), triggered by the reviewed annotated unsigned `v0.4.0` tag:
54
54
 
55
- - GitHub Actions trusted publisher is exactly `revazi/pi-career`, workflow `release.yml`, environment `npm`; protected `npm` environment is enabled.
56
- - Workflow grants `id-token: write` only to the publication job and uses that `npm` environment; no long-lived npm token, `NPM_TOKEN`, `NODE_AUTH_TOKEN`, OTP, manual token publishing, or alternate workflow/path exists.
57
- - Pinned checkout/setup-node actions, Node 22.19.0 release host, exact npm 11.6.2 tooling, lifecycle-disabled dependency installation/publication, and provenance settings match the reviewed workflow.
58
- - Tag/version/changelog/lockfile/full SHA/annotated unsigned tag checks, same-SHA hosted gates, complete audits/package gates, and clean-tree checks all pass before publish. The workflow alone may publish and create the GitHub Release, only after registry verification.
59
- - Trusted publisher/environment configuration is verified before release authorization; do not alter repository/npm settings as part of candidate preparation.
55
+ - GitHub Actions trusted publisher was exactly `revazi/pi-career`, workflow `release.yml`, environment `npm`, with the protected `npm` environment enabled.
56
+ - The workflow granted `id-token: write` only to the publication job and used no long-lived npm token, `NPM_TOKEN`, `NODE_AUTH_TOKEN`, OTP, manual token publishing, or alternate workflow/path.
57
+ - Pinned checkout/setup-node actions, Node 22.19.0, exact npm 11.6.2, lifecycle-disabled dependency installation/publication, and provenance settings matched the reviewed workflow.
58
+ - Tag/version/changelog/lockfile/full SHA/annotated unsigned tag checks, same-SHA hosted gates, complete audits/package gates, and clean-tree checks passed before publication.
59
+ - The authoritative registry represented the trusted publisher's OIDC configuration as bare UUID `59e29379-4ad7-4ac5-8484-68bba66677fe`; the publisher name, email, and `github` provider ID remained exact.
60
60
 
61
61
  ### Registry-first and ambiguous-outcome rule
62
62
 
63
- Immediately before any first publish, query the authoritative registry explicitly: `npm view pi-career@0.4.0 version --json` against `https://registry.npmjs.org/`. It must report absence before a first publish. For any failed, timed-out, or ambiguous publish response, do **not** blindly rerun the workflow, republish, move/replace the tag, or attempt overwrite. First query authoritative registry state and inspect exact version metadata, dist-tag, tarball integrity/shasum, provenance/publisher identity, and `gitHead`; preserve evidence and stop if indeterminate. If the exact package is already present, recovery is verification/bookkeeping only through the approved workflow after explicit maintainer incident authorization; never republish immutable version. If absent, investigate and obtain explicit authorization before a controlled retry, following the existing release procedure. No alternate publish channel.
63
+ The authoritative registry reported `pi-career@0.4.0` absent before the one authorized publication. When the post-publication workflow result became ambiguous, maintainers did **not** rerun the workflow, republish, move/replace the tag, or attempt overwrite. They first inspected exact version metadata, dist-tag, tarball integrity/shasum, provenance/publisher identity, and `gitHead`. Because the exact package was present, recovery was limited to verification and GitHub Release bookkeeping with the existing checked-in helper. This rule remains mandatory: preserve evidence and stop if registry state is indeterminate; never treat a failed post-publication check as permission for an automatic retry or alternate publication channel.
64
64
 
65
- ## Rollback, recovery, and post-release verification
65
+ ## Recovery and post-release verification
66
66
 
67
- Before publication, rollback is simply stop: leave the tag and registry untouched, fix the candidate in a reviewed commit, and rerun all gates on the new SHA. A bad published package cannot be overwritten or “rolled back” by republishing; stop installation promotion, document the incident, and use npm's immutable-version policy plus maintainer-directed deprecation/communication only after verifying authoritative state. Do not move a tag or fabricate a replacement artifact. A post-publication failure is an incident, not permission to retry.
67
+ `pi-career@0.4.0` cannot be overwritten or “rolled back” by republishing, and its tag must not move. Run `37191969844` exceeded the former registry propagation bound after successful publication; the now-authoritative registry metadata also used a bare UUID where the verifier expected the historical `oidc:` prefix. The package's exact identity and bytes were independently verified, so no rerun or republish occurred. The checked-in `scripts/create-github-release.mjs` then created the asset-free GitHub Release against the existing tag.
68
68
 
69
- After successful workflow completion, independently verify the exact npm version's registry metadata and tarball integrity/shasum, provenance and trusted publisher, `gitHead` against full candidate SHA, `latest` dist-tag, annotated tag target, asset-free GitHub Release target/notes, and main CI. In an isolated Pi agent directory install exact `npm:pi-career@0.4.0`, list/load, exercise synthetic runtime operation/acquisition and `PI_OFFLINE=1` failure, then remove the exact installed package. Confirm no native assets/custom Release assets and no unexpected package contents. Triage failures as release blockers/incidents in #73; record the observed Pi 1.0.2 remediation for #149, keep fixture-parity blockers visible, and open focused issues for any newly discovered defect without broadening support claims.
69
+ Independent verification proved npm integrity `sha512-ks5xCnt2sDKCTzjvUuRQCJJSGaiHvt1lmwJNT6hhJLIV2MCmCrOUOG2dLW9uhdyGjHXR7Eu4SRlBXSNAVDtWpA==`, shasum `460b9d69b42bc572bf966498a34c8818c3f26a6a`, exact `gitHead`, provenance and trusted publisher, `latest` dist-tag, tag/Release target, and absence of native or custom Release assets. In an isolated Pi agent directory, exact `npm:pi-career@0.4.0` install/list/load, runtime acquisition with synthetic resume and job operations, offline failure, and removal all passed. No production-wire claim is inferred from synthetic operation fixtures beyond acceptance of this exact published package.
package/docs/releasing.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # Release process
2
2
 
3
- This document defines the bounded trusted-publishing process for `pi-career@0.4.0` and records the historical `v0.1.0`, `v0.2.0`, and `v0.3.0` outcomes. Candidate metadata and the dated changelog must be finalized before the release SHA is frozen; tracked files do not embed that self-referential SHA. Publication and tag creation always require the separate explicit authorization described below. In the instructions below, `<version>` is the exact package version without `v`, `<tag>` is `v<version>`, and `<sha>` is the full frozen candidate commit.
3
+ This document defines the bounded trusted-publishing process and records the historical `v0.1.0`, `v0.2.0`, `v0.3.0`, and `v0.4.0` outcomes. Candidate metadata and the dated changelog must be finalized before the release SHA is frozen; tracked files do not embed that self-referential SHA. Publication and tag creation always require the separate explicit authorization described below. In the instructions below, `<version>` is the exact package version without `v`, `<tag>` is `v<version>`, and `<sha>` is the full frozen candidate commit.
4
4
 
5
5
  ## Release boundary
6
6
 
@@ -73,6 +73,28 @@ Release execution completed on 2026-08-14:
73
73
 
74
74
  The published package is native-free, supports the six reviewed macOS/Linux targets through exact external `@revazi/career@0.2.0`, and validates its exact ordered six-package v2 launcher manifest. Production and complete development/host-Pi audits were both clean at the explicit low threshold before publication.
75
75
 
76
+ ## Historical `v0.4.0` outcome
77
+
78
+ Release execution completed from the frozen 2026-10-04 candidate:
79
+
80
+ - npm: [`pi-career@0.4.0`](https://www.npmjs.com/package/pi-career/v/0.4.0), promoted as `latest`
81
+ - published commit: `31d1a8068ddff727cd7bb27e7546965def51e574`
82
+ - annotated unsigned tag and asset-free GitHub Release: [`v0.4.0`](https://github.com/revazi/pi-career/releases/tag/v0.4.0), both targeting that commit
83
+ - npm integrity: `sha512-ks5xCnt2sDKCTzjvUuRQCJJSGaiHvt1lmwJNT6hhJLIV2MCmCrOUOG2dLW9uhdyGjHXR7Eu4SRlBXSNAVDtWpA==`
84
+ - npm shasum: `460b9d69b42bc572bf966498a34c8818c3f26a6a`
85
+ - same-SHA main Adapter checks: [`37191508057`](https://github.com/revazi/pi-career/actions/runs/37191508057)
86
+ - same-SHA six-target compatibility run: [`37191625998`](https://github.com/revazi/pi-career/actions/runs/37191625998)
87
+ - OIDC publication and post-publication verification run: [`37191969844`](https://github.com/revazi/pi-career/actions/runs/37191969844)
88
+ - npm publisher identity: exact GitHub Actions trusted publisher; registry `oidcConfigId` `59e29379-4ad7-4ac5-8484-68bba66677fe`
89
+ - exact published-package Pi install/list/load, runtime acquisition with synthetic resume and job operations, offline failure, and removal in an isolated agent directory: passed
90
+ - custom GitHub Release assets: none
91
+
92
+ Run `37191969844` passed every pre-publication gate and published the immutable package successfully through OIDC. Its post-publication job then failed closed before GitHub Release creation: canonical registry propagation exceeded the verifier's former 36-attempt, five-second interval, and the settled registry metadata represented `trustedPublisher.oidcConfigId` as a bare UUID rather than the historical `oidc:<UUID>` spelling. The UUID value and exact GitHub publisher name, email, and provider ID matched the reviewed identity. This was a release-tooling compatibility incident, not evidence that publication failed.
93
+
94
+ No workflow rerun, tag movement, or npm republish occurred. After authoritative registry state proved the exact metadata, `gitHead`, tarball integrity/shasum, trusted publisher, provenance, and `latest` dist-tag, the existing checked-in `scripts/create-github-release.mjs` completed the asset-free GitHub Release bookkeeping. Independent isolated acceptance then exercised the exact published package as recorded above. `v0.4.0` and `pi-career@0.4.0` are immutable; this hardening must not alter or recreate them.
95
+
96
+ Future registry-resource polling uses exactly 48 attempts at five-second intervals: at most 47 scheduled sleeps, or 235 seconds of propagation delay, with each request retaining its separate 30-second timeout. Only `404`, `5xx`, and request failures are retried within that finite bound. Other HTTP statuses fail immediately; authoritative metadata, provenance, integrity, publisher, and `gitHead` mismatches fail closed, and an indeterminate final state never authorizes an automatic publication retry.
97
+
76
98
  ## Release gates
77
99
 
78
100
  A skipped, unknown, stale, or merely planned result is not a pass.
@@ -8,7 +8,7 @@ This contract replaces application-state schema versioning with one exact pi-car
8
8
  pi.career.application_state
9
9
  ```
10
10
 
11
- Issue #140 approved this contract. Issue #141 implements production, fixture, generated-bundle, and documentation convergence.
11
+ Issue #140 approved this contract. Issue #141 implements production, fixture, generated-bundle, and documentation convergence. Issue #66's assisted cover-letter proposal is explicitly transient and non-authoritative; it adds no state field, migration, reader compatibility, or persistence authorization.
12
12
 
13
13
  There is no application-state schema migration or compatibility path. Files whose `schema_version` is `pi.career.application_state.v1`, `pi.career.application_state.v2`, or any other value are unsupported and fail closed. They are never rewritten, adopted, interpreted as a compatible prefix, or exposed as current state.
14
14
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pi-career",
3
- "version": "0.4.0",
3
+ "version": "0.4.2",
4
4
  "private": false,
5
5
  "description": "Pi tools, slash commands, and Agent Skill for deterministic Career Core workflows",
6
6
  "license": "MIT OR Apache-2.0",
@@ -71,9 +71,9 @@
71
71
  "typebox": "*"
72
72
  },
73
73
  "devDependencies": {
74
- "@earendil-works/pi-ai": "1.0.2",
75
- "@earendil-works/pi-coding-agent": "1.0.2",
76
- "@earendil-works/pi-tui": "1.0.2",
74
+ "@earendil-works/pi-ai": "1.0.4",
75
+ "@earendil-works/pi-coding-agent": "1.0.4",
76
+ "@earendil-works/pi-tui": "1.0.4",
77
77
  "@types/node": "24.19.0",
78
78
  "esbuild": "0.28.2",
79
79
  "js-tiktoken": "1.0.21",
@@ -82,6 +82,9 @@
82
82
  "typescript": "5.9.3",
83
83
  "unpdf": "1.8.1"
84
84
  },
85
+ "overrides": {
86
+ "undici": "8.12.3"
87
+ },
85
88
  "publishConfig": {
86
89
  "access": "public",
87
90
  "registry": "https://registry.npmjs.org/"
@@ -5,7 +5,7 @@ license: MIT OR Apache-2.0
5
5
  compatibility: Requires Pi with pi-career on ARM64/x64 macOS or GNU/musl Linux and a compatible Career Core route. Windows is unsupported.
6
6
  metadata:
7
7
  author: revazi
8
- version: "0.4.0"
8
+ version: "0.4.2"
9
9
  ---
10
10
 
11
11
  # Career Core through pi-career