pi-career 0.4.0 → 0.4.1

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,16 @@
2
2
 
3
3
  ## Unreleased
4
4
 
5
+ ## 0.4.1 - 2026-10-04
6
+
7
+ ### Fixed
8
+
9
+ - 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.
10
+
11
+ ### Changed
12
+
13
+ - 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.
14
+
5
15
  ## 0.4.0 - 2026-10-04
6
16
 
7
17
  ### Added
package/README.md CHANGED
@@ -21,7 +21,7 @@ It gives you:
21
21
 
22
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.
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.1`. The application-centric `pi-career@0.4.0` release is 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.1
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
 
@@ -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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pi-career",
3
- "version": "0.4.0",
3
+ "version": "0.4.1",
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",
@@ -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.1"
9
9
  ---
10
10
 
11
11
  # Career Core through pi-career