@huseynsnmz/pi-board 0.15.3 → 0.16.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +13 -4
- package/CONTRIBUTING.md +7 -0
- package/README.md +53 -419
- package/SECURITY.md +19 -0
- package/docs/how-it-works.md +31 -0
- package/docs/reference.md +276 -0
- package/package.json +5 -11
- package/src/index.ts +1 -1
- package/src/runtime/service.mjs +12 -0
- package/src/ui/dashboard.ts +14 -8
- package/IMPLEMENTATION_PLAN.md +0 -920
- package/PRD.md +0 -484
- package/PROGRESS.md +0 -142
- package/VERIFY.md +0 -115
- package/docs/BATCH_SELECTION_READ_FLOW.md +0 -277
- package/docs/EXPLORATION.md +0 -187
- package/docs/PTY_ATTACH_IMPLEMENTATION_PLAN.md +0 -581
- package/docs/RELEASE.md +0 -148
- package/docs/superpowers/plans/2026-08-15-screenlog-gc.md +0 -704
- package/docs/superpowers/plans/2026-08-16-attach-double-cursor-jiggle-retry.md +0 -499
- package/docs/superpowers/plans/2026-08-21-attach-coldstart-jiggle-rearm.md +0 -797
- package/docs/superpowers/plans/2026-08-21-dashboard-keypress-lag.md +0 -366
- package/docs/superpowers/plans/2026-08-21-issue-14-needs-input-no-auto-done.md +0 -576
- package/docs/superpowers/plans/2026-08-22-jiggle-shrink-and-hold.md +0 -337
- package/docs/superpowers/plans/2026-08-22-launch-cwd-favorites.md +0 -916
- package/docs/superpowers/plans/2026-08-22-question-tool-grouping.md +0 -211
- package/docs/superpowers/plans/2026-08-22-rename-state-labels.md +0 -182
- package/docs/superpowers/plans/2026-08-22-stable-list-order.md +0 -51
- package/docs/superpowers/plans/2026-08-27-locks-acquirelock-spin.md +0 -614
- package/docs/superpowers/plans/2026-08-27-pty-runner-test-flaky.md +0 -32
- package/docs/superpowers/plans/2026-08-29-code-refs-badges.md +0 -223
- package/docs/superpowers/plans/2026-08-30-circular-navigation.md +0 -308
- package/docs/superpowers/plans/2026-08-30-post-exit-timing-fix.md +0 -37
- package/docs/superpowers/plans/2026-08-30-pty-attach-quality-debt.md +0 -311
- package/docs/superpowers/plans/2026-08-30-readme-v2.md +0 -294
- package/docs/superpowers/plans/2026-09-01-attach-detach-gate-cursor-anchor.md +0 -284
- package/docs/superpowers/plans/2026-09-02-attach-detach-editor-state.md +0 -722
- package/docs/superpowers/plans/2026-09-03-code-refs-pr-backlink-narrow.md +0 -551
- package/docs/superpowers/plans/2026-09-03-detach-gate-glyph-fallback.md +0 -146
- package/docs/superpowers/plans/2026-09-04-evidence-outputpreview.md +0 -209
- package/docs/superpowers/plans/2026-09-04-warm-host-reclaim.md +0 -796
- package/docs/superpowers/plans/2026-09-05-issue-13-drainnextfollowup-pty-probe.md +0 -114
- package/docs/superpowers/plans/2026-09-05-issue-38-windows-wezterm-ime-cursor.md +0 -73
- package/docs/superpowers/plans/2026-09-05-issue-39-truncate-codepoint-boundary.md +0 -143
- package/docs/superpowers/plans/2026-09-05-issue-61-mention-fallback-guards.md +0 -226
- package/docs/superpowers/plans/2026-09-05-issue-63-flaky-manual-completion.md +0 -87
- package/docs/superpowers/plans/2026-09-05-issue-64-changelog-release-helper.md +0 -53
- package/docs/superpowers/plans/2026-09-05-pty-host-stacking-sock-race.md +0 -731
- package/docs/superpowers/plans/2026-09-08-attach-ctrl-left-detach.md +0 -30
- package/docs/superpowers/plans/2026-09-08-dashboard-shrink-repaint.md +0 -68
- package/docs/superpowers/plans/2026-09-08-issue-11-attach-runtime-desync-heal.md +0 -917
- package/docs/superpowers/plans/2026-09-08-legacy-stale-host-recovery.md +0 -125
- package/docs/superpowers/plans/2026-09-08-spawn-async-error-swallow.md +0 -56
- package/docs/superpowers/plans/2026-09-08-stale-model-attach-guard.md +0 -96
- package/docs/superpowers/plans/2026-09-09-claimpid-blocks-replace.md +0 -267
- package/docs/superpowers/plans/2026-09-09-harden-runner-architecture.md +0 -603
- package/docs/superpowers/plans/2026-09-09-single-writer-completion.md +0 -252
- package/docs/superpowers/plans/2026-09-10-reader-consistency.md +0 -115
- package/docs/superpowers/plans/2026-09-14-attach-cursor-dectcem-gate.md +0 -469
- package/docs/superpowers/plans/2026-09-14-attach-snapshot.md +0 -92
- package/docs/superpowers/plans/2026-09-14-host-meta-orphan-lock.md +0 -771
- package/docs/superpowers/plans/2026-09-14-issue-106-terminal-frame-cognition.md +0 -299
- package/docs/superpowers/plans/2026-09-14-issue-113-foreground-preview-race.md +0 -609
- package/docs/superpowers/plans/2026-09-14-terminal-model.md +0 -145
- package/docs/superpowers/plans/2026-09-15-coordinator-pipe-root-normalize.md +0 -224
- package/docs/superpowers/plans/2026-09-15-lease-publish-eprem-reclaim.md +0 -341
- package/docs/superpowers/plans/2026-09-18-detach-anchor-reporter-endpoint.md +0 -875
- package/docs/superpowers/plans/2026-09-20-control-lifecycle.md +0 -116
- package/docs/superpowers/plans/2026-09-20-issue-121-perf-gate-out-of-coverage.md +0 -517
- package/docs/superpowers/plans/2026-09-23-a5-mid-stream-assertion.md +0 -25
- package/docs/superpowers/plans/2026-09-23-cwd-browse-tab-drill.md +0 -393
- package/docs/superpowers/plans/2026-09-23-terminal-query-forwarding.md +0 -51
- package/docs/superpowers/plans/2026-09-23-unconditional-detach-key.md +0 -58
- package/docs/superpowers/plans/2026-09-24-control-reconcile-flake.md +0 -698
- package/docs/superpowers/plans/2026-09-24-probe-attached-clients.md +0 -605
- package/docs/superpowers/plans/2026-09-29-issue-145-holding-semantic-state.md +0 -1183
- package/docs/superpowers/plans/2026-09-29-issue-145-user-verification.md +0 -66
- package/docs/superpowers/plans/2026-09-30-board-delete-key-x-y-confirm.md +0 -649
- package/docs/superpowers/plans/2026-09-30-issue-153-runner-stop-boot-window.md +0 -618
- package/docs/superpowers/plans/2026-09-30-issue-95-test-discipline.md +0 -555
- package/docs/superpowers/plans/2026-09-30-publish-dispatch-tag-check.md +0 -259
- package/docs/superpowers/plans/2026-10-06-attach-settle-scheme-delivery.md +0 -751
- package/docs/superpowers/plans/2026-10-09-issue-167-attach-middle-paste.md +0 -509
- package/docs/superpowers/plans/2026-10-09-issue-169-fullscreen-mouse-ownership.md +0 -346
- package/docs/superpowers/plans/2026-10-10-attach-delete-in-place.md +0 -832
- package/docs/superpowers/plans/2026-10-10-issue-174-selection-mirror-paste-source.md +0 -510
- package/docs/superpowers/plans/2026-10-14-issue-170-attach-reply-guard.md +0 -771
- package/docs/superpowers/plans/2026-10-14-issue-178-accept-registration-race.md +0 -1257
- package/docs/superpowers/plans/2026-10-14-issue-184-snapshot-window-contract.md +0 -657
- package/docs/superpowers/plans/2026-10-14-issue-185-attach-wheel-alt-screen.md +0 -47
- package/docs/superpowers/plans/2026-10-14-issue-187-motionless-drag.md +0 -931
- package/docs/superpowers/plans/2026-10-14-issue-189-mixed-input-segments.md +0 -823
- package/docs/superpowers/plans/2026-10-15-issue-188-x10-mouse-release.md +0 -526
- package/docs/superpowers/plans/2026-10-16-issue-198-attach-wheel-forward-fallback.md +0 -32
- package/docs/superpowers/plans/2026-10-18-attach-wheel-replay-pseudo-scrollback.md +0 -437
- package/docs/superpowers/plans/2026-10-19-issue-213-reply-guard-csi-key.md +0 -257
- package/docs/superpowers/plans/2026-10-19-issue-214-attach-forward-alt-modifier.md +0 -202
- package/docs/superpowers/plans/2026-10-21-issue-221-ask-user-question.md +0 -198
- package/docs/superpowers/plans/2026-10-23-issue-222-attach-ready.md +0 -290
- package/docs/superpowers/plans/2026-10-23-issue-225-monotonic-foreground-state.md +0 -450
- package/docs/superpowers/plans/2026-10-23-issue-229-vim-jkl.md +0 -449
- package/docs/superpowers/plans/2026-10-23-issue-232-attach-bg-only-cells.md +0 -153
- package/docs/superpowers/plans/2026-10-23-lease-heartbeat-staleness.md +0 -537
- package/docs/superpowers/plans/2026-10-23-selected-row-highlight.md +0 -405
- package/docs/superpowers/plans/2026-10-24-issue-217-windows-pid-reuse-stopping.md +0 -367
- package/docs/superpowers/plans/2026-10-24-issue-230-warm-host-background-runs.md +0 -806
- package/docs/superpowers/plans/2026-10-24-issue-238-windows-process-identity-token.md +0 -490
- package/docs/superpowers/plans/2026-10-24-issue-241-coordinator-root-exit.md +0 -461
- package/docs/superpowers/plans/2026-10-25-issue-239-coordinator-replacement-identity.md +0 -504
- package/docs/superpowers/plans/2026-10-26-issue-245-key-hints-doc-sync.md +0 -244
- package/docs/superpowers/plans/2026-10-27-issue-172-fullscreen-selection-clear.md +0 -344
- package/docs/superpowers/plans/2026-10-27-issue-252-select-key-hints.md +0 -209
- package/docs/superpowers/plans/2026-10-28-issue-255-coordinator-endpoint-zombie.md +0 -442
- package/docs/superpowers/plans/2026-10-28-issue-257-legacy-pty-runner-endpoint-cleanup.md +0 -256
- package/docs/superpowers/plans/2026-11-03-cwd-favorites-full-pool.md +0 -266
- package/docs/superpowers/specs/2026-08-15-screenlog-gc-design.md +0 -105
- package/docs/superpowers/specs/2026-08-16-attach-double-cursor-jiggle-retry-design.md +0 -142
- package/docs/superpowers/specs/2026-08-21-attach-coldstart-jiggle-rearm-design.md +0 -110
- package/docs/superpowers/specs/2026-08-21-dashboard-keypress-lag-design.md +0 -59
- package/docs/superpowers/specs/2026-08-21-issue-14-needs-input-no-auto-done-design.md +0 -109
- package/docs/superpowers/specs/2026-08-22-cwd-favorites-design.md +0 -131
- package/docs/superpowers/specs/2026-08-22-jiggle-shrink-and-hold-design.md +0 -111
- package/docs/superpowers/specs/2026-08-22-question-tool-grouping-design.md +0 -114
- package/docs/superpowers/specs/2026-08-22-rename-state-labels-design.md +0 -80
- package/docs/superpowers/specs/2026-08-27-locks-acquirelock-spin-design.md +0 -97
- package/docs/superpowers/specs/2026-08-27-pty-runner-test-flaky-design.md +0 -35
- package/docs/superpowers/specs/2026-08-29-code-refs-badges-design.md +0 -128
- package/docs/superpowers/specs/2026-08-30-circular-navigation-design.md +0 -47
- package/docs/superpowers/specs/2026-08-30-eprm-atomicwrite-race-design.md +0 -77
- package/docs/superpowers/specs/2026-08-30-post-exit-timing-fix-design.md +0 -80
- package/docs/superpowers/specs/2026-08-30-pty-attach-quality-debt-design.md +0 -105
- package/docs/superpowers/specs/2026-08-30-readme-v2-design.md +0 -115
- package/docs/superpowers/specs/2026-09-01-attach-detach-gate-cursor-anchor-design.md +0 -78
- package/docs/superpowers/specs/2026-09-02-attach-detach-editor-state-design.md +0 -120
- package/docs/superpowers/specs/2026-09-03-code-refs-pr-backlink-narrow-design.md +0 -92
- package/docs/superpowers/specs/2026-09-03-detach-gate-glyph-fallback-design.md +0 -99
- package/docs/superpowers/specs/2026-09-04-evidence-outputpreview-design.md +0 -50
- package/docs/superpowers/specs/2026-09-04-warm-host-reclaim-design.md +0 -106
- package/docs/superpowers/specs/2026-09-05-issue-13-drainnextfollowup-pty-probe-design.md +0 -64
- package/docs/superpowers/specs/2026-09-05-issue-38-windows-wezterm-ime-design.md +0 -48
- package/docs/superpowers/specs/2026-09-05-issue-39-truncate-codepoint-boundary-design.md +0 -64
- package/docs/superpowers/specs/2026-09-05-issue-61-mention-fallback-design.md +0 -71
- package/docs/superpowers/specs/2026-09-05-issue-63-flaky-manual-completion-design.md +0 -49
- package/docs/superpowers/specs/2026-09-05-issue-64-changelog-helper-design.md +0 -76
- package/docs/superpowers/specs/2026-09-05-pty-host-stacking-sock-race-design.md +0 -510
- package/docs/superpowers/specs/2026-09-07-issue-11-attach-runtime-desync-heal-design.md +0 -130
- package/docs/superpowers/specs/2026-09-08-attach-ctrl-left-detach-design.md +0 -58
- package/docs/superpowers/specs/2026-09-08-dashboard-shrink-repaint-design.md +0 -52
- package/docs/superpowers/specs/2026-09-08-legacy-stale-host-recovery-design.md +0 -87
- package/docs/superpowers/specs/2026-09-08-spawn-async-error-swallow-design.md +0 -56
- package/docs/superpowers/specs/2026-09-08-stale-model-attach-guard-design.md +0 -79
- package/docs/superpowers/specs/2026-09-09-claimpid-blocks-replace-design.md +0 -147
- package/docs/superpowers/specs/2026-09-09-harden-runner-architecture-design.md +0 -304
- package/docs/superpowers/specs/2026-09-14-attach-cursor-dectcem-gate-design.md +0 -114
- package/docs/superpowers/specs/2026-09-14-host-meta-orphan-lock-design.md +0 -120
- package/docs/superpowers/specs/2026-09-14-issue-106-terminal-frame-cognition-design.md +0 -146
- package/docs/superpowers/specs/2026-09-14-issue-113-foreground-preview-race-design.md +0 -116
- package/docs/superpowers/specs/2026-09-15-coordinator-pipe-root-normalize-design.md +0 -84
- package/docs/superpowers/specs/2026-09-15-lease-publish-eprem-reclaim-design.md +0 -92
- package/docs/superpowers/specs/2026-09-18-detach-anchor-reporter-endpoint-design.md +0 -123
- package/docs/superpowers/specs/2026-09-20-issue-121-perf-gate-out-of-coverage-design.md +0 -204
- package/docs/superpowers/specs/2026-09-23-a5-mid-stream-assertion-design.md +0 -43
- package/docs/superpowers/specs/2026-09-23-cwd-browse-tab-drill-design.md +0 -95
- package/docs/superpowers/specs/2026-09-23-terminal-query-forwarding-design.md +0 -63
- package/docs/superpowers/specs/2026-09-23-unconditional-detach-key-design.md +0 -57
- package/docs/superpowers/specs/2026-09-24-control-reconcile-flake-design.md +0 -98
- package/docs/superpowers/specs/2026-09-24-probe-attached-clients-design.md +0 -190
- package/docs/superpowers/specs/2026-09-29-issue-145-holding-semantic-state-design.md +0 -394
- package/docs/superpowers/specs/2026-09-30-board-delete-key-x-y-confirm-design.md +0 -86
- package/docs/superpowers/specs/2026-09-30-issue-153-runner-stop-boot-window-design.md +0 -75
- package/docs/superpowers/specs/2026-09-30-issue-95-test-discipline-design.md +0 -226
- package/docs/superpowers/specs/2026-09-30-publish-dispatch-tag-check-design.md +0 -129
- package/docs/superpowers/specs/2026-10-06-attach-settle-scheme-delivery-design.md +0 -196
- package/docs/superpowers/specs/2026-10-09-issue-167-attach-middle-paste-design.md +0 -125
- package/docs/superpowers/specs/2026-10-09-issue-169-fullscreen-mouse-ownership-design.md +0 -130
- package/docs/superpowers/specs/2026-10-10-attach-delete-in-place-design.md +0 -224
- package/docs/superpowers/specs/2026-10-10-issue-174-selection-mirror-paste-source-design.md +0 -154
- package/docs/superpowers/specs/2026-10-14-issue-170-attach-reply-guard-design.md +0 -195
- package/docs/superpowers/specs/2026-10-14-issue-178-accept-registration-race-design.md +0 -287
- package/docs/superpowers/specs/2026-10-14-issue-184-snapshot-window-contract-design.md +0 -288
- package/docs/superpowers/specs/2026-10-14-issue-185-attach-wheel-alt-screen-design.md +0 -126
- package/docs/superpowers/specs/2026-10-14-issue-187-motionless-drag-design.md +0 -269
- package/docs/superpowers/specs/2026-10-14-issue-189-mixed-input-segments-design.md +0 -369
- package/docs/superpowers/specs/2026-10-15-issue-188-x10-mouse-release-design.md +0 -252
- package/docs/superpowers/specs/2026-10-16-issue-198-attach-wheel-forward-fallback-design.md +0 -67
- package/docs/superpowers/specs/2026-10-18-attach-wheel-replay-pseudo-scrollback-design.md +0 -250
- package/docs/superpowers/specs/2026-10-19-issue-213-reply-guard-csi-key-design.md +0 -165
- package/docs/superpowers/specs/2026-10-19-issue-214-attach-forward-alt-modifier-design.md +0 -131
- package/docs/superpowers/specs/2026-10-20-issue-221-ask-user-question-design.md +0 -270
- package/docs/superpowers/specs/2026-10-22-issue-225-monotonic-foreground-state-design.md +0 -225
- package/docs/superpowers/specs/2026-10-23-issue-222-attach-ready-design.md +0 -204
- package/docs/superpowers/specs/2026-10-23-issue-229-vim-jkl-design.md +0 -90
- package/docs/superpowers/specs/2026-10-23-issue-232-attach-bg-only-cells-design.md +0 -146
- package/docs/superpowers/specs/2026-10-23-lease-heartbeat-staleness-design.md +0 -271
- package/docs/superpowers/specs/2026-10-23-selected-row-highlight-design.md +0 -191
- package/docs/superpowers/specs/2026-10-24-issue-217-windows-pid-reuse-stopping-design.md +0 -334
- package/docs/superpowers/specs/2026-10-24-issue-230-warm-host-background-runs-design.md +0 -283
- package/docs/superpowers/specs/2026-10-24-issue-238-windows-process-identity-token-design.md +0 -286
- package/docs/superpowers/specs/2026-10-24-issue-241-coordinator-root-exit-design.md +0 -381
- package/docs/superpowers/specs/2026-10-25-issue-239-coordinator-replacement-identity-design.md +0 -331
- package/docs/superpowers/specs/2026-10-26-issue-245-key-hints-doc-sync-design.md +0 -72
- package/docs/superpowers/specs/2026-10-27-issue-172-fullscreen-selection-clear-design.md +0 -248
- package/docs/superpowers/specs/2026-10-27-issue-252-select-key-hints-design.md +0 -95
- package/docs/superpowers/specs/2026-10-28-issue-255-coordinator-endpoint-zombie-design.md +0 -380
- package/docs/superpowers/specs/2026-10-28-issue-257-legacy-pty-runner-endpoint-cleanup-design.md +0 -197
- package/docs/superpowers/specs/2026-11-03-cwd-favorites-full-pool-design.md +0 -106
- package/scripts/budget-audit.mjs +0 -135
- package/scripts/release.mjs +0 -446
- package/scripts/release_helper.mjs +0 -309
- package/scripts/run-perf-gate.mjs +0 -40
- package/scripts/run-tests.mjs +0 -375
|
@@ -1,490 +0,0 @@
|
|
|
1
|
-
# Windows Process Identity Token Implementation Plan
|
|
2
|
-
|
|
3
|
-
> **For agentic workers:** REQUIRED SUB-SKILL: Use subagent-driven-development (recommended) or executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
|
|
4
|
-
|
|
5
|
-
**Goal:** Unify the four duplicate Linux-only `captureStartToken` implementations into one, give win32 a real comparable token (`ct:<unix-ms>` from the existing identity probe), and make host-role observation compare tokens — without touching the lease layer.
|
|
6
|
-
|
|
7
|
-
**Architecture:** `src/core/pid.mjs` keeps the only synchronous token reader; `src/core/process-identity-probe.mjs` gains the async, platform-dispatching reader (`readProcessStartToken`) plus a pure `creationTimeToken`. `runner/pty-runner.mjs` writes the probed token into `host.json`'s `runnerIdentity`/`childIdentity`. `src/runtime/service.mjs` assembles an observation snapshot (alive + observed token, memoized per pid) and lets the pure `processIdentityState` decide; `revalidateProbeOwned` re-reads before any signal. Lease identities (`host-start`/`host-meta`/coordinator) keep using the synchronous reader, so `locks.mjs` is untouched.
|
|
8
|
-
|
|
9
|
-
**Tech Stack:** Node ESM (`.mjs` + one `.ts` module), `node:test` + `assert/strict`, c8 coverage, no new dependencies.
|
|
10
|
-
|
|
11
|
-
**Spec:** `docs/superpowers/specs/2026-10-24-issue-238-windows-process-identity-token-design.md`
|
|
12
|
-
|
|
13
|
-
## Global Constraints
|
|
14
|
-
|
|
15
|
-
- Tabs for indentation; English comments and commit messages.
|
|
16
|
-
- Pure functions first, thin I/O shell; the spec's §5 split is a hard constraint — do not re-couple assembly and judgment.
|
|
17
|
-
- Tests: `node:test` + `assert/strict`; anything touching fs/git uses a temp-dir fixture, never the host repository.
|
|
18
|
-
- No new runtime dependencies.
|
|
19
|
-
- Token format is exactly `ct:<positive-safe-integer-ms>` (`creationTimeToken()`), and only win32 produces it.
|
|
20
|
-
- `readProcessStartToken` must never throw: every failure path returns `null` (callers read `null` as "unverifiable", never "foreign").
|
|
21
|
-
- Commit subjects: conventional (`feat`/`fix`/`refactor`/`test`/`docs`/`chore`).
|
|
22
|
-
|
|
23
|
-
## Review Focus
|
|
24
|
-
|
|
25
|
-
- **An old `host.json` (Windows, `startToken: null`) must behave exactly as today** — observation returns `unknown` immediately and the #217 probe fallback runs unchanged, with zero added probes.
|
|
26
|
-
- **A hung probe (PowerShell disabled / 3 s timeout) must not consume the recovery budget** — `HOST_RECOVERY_POLL_MS`/`HOST_RECOVERY_GRACE_MS` still bound the loop, and a probe failure degrades to `unknown`, never `foreign`.
|
|
27
|
-
- **A malformed record (identity present, `pid` or `spawnedAt` missing) must never become a releasable state** — `not_started` requires `identity == null && spawnedAt == null`; identity-bearing records are judged by observation.
|
|
28
|
-
- **A reused pid must never receive a signal** — `revalidateProbeOwned` re-reads the token and refuses on mismatch or read failure; the `tokenMemo` may not shortcut this.
|
|
29
|
-
- **Concurrent/bypassed memo must not leak** — each `recoverHost`/resolver invocation owns its own `tokenMemo`; a stale successful token must not be cached beyond one invocation.
|
|
30
|
-
|
|
31
|
-
---
|
|
32
|
-
|
|
33
|
-
### Task 1: `creationTimeToken` pure function
|
|
34
|
-
|
|
35
|
-
**Files:**
|
|
36
|
-
- Modify: `src/core/process-identity-probe.mjs`
|
|
37
|
-
- Test: `test/process-identity-probe.test.mjs`
|
|
38
|
-
|
|
39
|
-
**Interfaces:**
|
|
40
|
-
- Produces: `creationTimeToken(creationTimeMs: number): string | null` — `"ct:<ms>"` for a positive safe integer, `null` otherwise.
|
|
41
|
-
|
|
42
|
-
- [ ] **Step 1: Write the failing test**
|
|
43
|
-
|
|
44
|
-
Add to `test/process-identity-probe.test.mjs`:
|
|
45
|
-
|
|
46
|
-
```js
|
|
47
|
-
test("creationTimeToken formats only positive safe integers", () => {
|
|
48
|
-
assert.equal(creationTimeToken(1792811668715), "ct:1792811668715");
|
|
49
|
-
assert.equal(creationTimeToken(1), "ct:1");
|
|
50
|
-
assert.equal(creationTimeToken(0), null);
|
|
51
|
-
assert.equal(creationTimeToken(-1), null);
|
|
52
|
-
assert.equal(creationTimeToken(1.5), null);
|
|
53
|
-
assert.equal(creationTimeToken(NaN), null);
|
|
54
|
-
assert.equal(creationTimeToken(Infinity), null);
|
|
55
|
-
assert.equal(creationTimeToken(Number.MAX_SAFE_INTEGER + 1), null);
|
|
56
|
-
assert.equal(creationTimeToken("1792811668715"), null);
|
|
57
|
-
assert.equal(creationTimeToken(null), null);
|
|
58
|
-
assert.equal(creationTimeToken(undefined), null);
|
|
59
|
-
});
|
|
60
|
-
```
|
|
61
|
-
|
|
62
|
-
- [ ] **Step 2: Run test to verify it fails**
|
|
63
|
-
|
|
64
|
-
Run: `node --test test/process-identity-probe.test.mjs`
|
|
65
|
-
Expected: FAIL — `creationTimeToken is not a function` (or import error).
|
|
66
|
-
|
|
67
|
-
- [ ] **Step 3: Implement `creationTimeToken` in `src/core/process-identity-probe.mjs`**
|
|
68
|
-
|
|
69
|
-
Signature and contract:
|
|
70
|
-
|
|
71
|
-
```js
|
|
72
|
-
export function creationTimeToken(creationTimeMs) { /* positive safe integer → `ct:${n}`; else null */ }
|
|
73
|
-
```
|
|
74
|
-
|
|
75
|
-
Use `Number.isSafeInteger(creationTimeMs) && creationTimeMs > 0`; no string coercion.
|
|
76
|
-
|
|
77
|
-
- [ ] **Step 4: Run test to verify it passes**
|
|
78
|
-
|
|
79
|
-
Run: `node --test test/process-identity-probe.test.mjs`
|
|
80
|
-
Expected: PASS (all existing probe tests plus the new one).
|
|
81
|
-
|
|
82
|
-
- [ ] **Step 5: Commit**
|
|
83
|
-
|
|
84
|
-
```bash
|
|
85
|
-
git add src/core/process-identity-probe.mjs test/process-identity-probe.test.mjs
|
|
86
|
-
git commit -m "feat: add creationTimeToken for comparable win32 process tokens"
|
|
87
|
-
```
|
|
88
|
-
|
|
89
|
-
---
|
|
90
|
-
|
|
91
|
-
### Task 2: `readProcessStartToken` cross-platform reader
|
|
92
|
-
|
|
93
|
-
**Files:**
|
|
94
|
-
- Modify: `src/core/process-identity-probe.mjs`
|
|
95
|
-
- Test: `test/process-identity-probe.test.mjs`
|
|
96
|
-
|
|
97
|
-
**Interfaces:**
|
|
98
|
-
- Consumes: `captureStartToken(pid)` from `src/core/pid.mjs`; `readProcessIdentityProbe(pid, opts)` (same module); `creationTimeToken(ms)` from Task 1.
|
|
99
|
-
- Produces: `readProcessStartToken(pid, { platform?, probe? }): Promise<string|null>` — linux → `captureStartToken`, win32 → `probe()` → `creationTimeToken(probe.creationTimeMs)`, every other platform → `null` **without calling `probe`**.
|
|
100
|
-
|
|
101
|
-
- [ ] **Step 1: Write the failing tests**
|
|
102
|
-
|
|
103
|
-
Add to `test/process-identity-probe.test.mjs`:
|
|
104
|
-
|
|
105
|
-
```js
|
|
106
|
-
test("readProcessStartToken: linux delegates to captureStartToken", async () => {
|
|
107
|
-
let probed = false;
|
|
108
|
-
const token = await readProcessStartToken(process.pid, { platform: "linux", probe: async () => { probed = true; return null; } });
|
|
109
|
-
assert.equal(probed, false);
|
|
110
|
-
assert.equal(token, captureStartToken(process.pid));
|
|
111
|
-
});
|
|
112
|
-
|
|
113
|
-
test("readProcessStartToken: win32 converts the probe creation time", async () => {
|
|
114
|
-
let seenPid = null;
|
|
115
|
-
const token = await readProcessStartToken(4242, {
|
|
116
|
-
platform: "win32",
|
|
117
|
-
probe: async (pid) => { seenPid = pid; return { creationTimeMs: 1792811668715, commandLine: "node x" }; },
|
|
118
|
-
});
|
|
119
|
-
assert.equal(seenPid, 4242);
|
|
120
|
-
assert.equal(token, "ct:1792811668715");
|
|
121
|
-
});
|
|
122
|
-
|
|
123
|
-
test("readProcessStartToken: darwin never probes and returns null", async () => {
|
|
124
|
-
let probed = false;
|
|
125
|
-
const token = await readProcessStartToken(4242, { platform: "darwin", probe: async () => { probed = true; return { creationTimeMs: 1, commandLine: null }; } });
|
|
126
|
-
assert.equal(probed, false);
|
|
127
|
-
assert.equal(token, null);
|
|
128
|
-
});
|
|
129
|
-
|
|
130
|
-
test("readProcessStartToken: probe failure and bad pids degrade to null", async () => {
|
|
131
|
-
assert.equal(await readProcessStartToken(4242, { platform: "win32", probe: async () => null }), null);
|
|
132
|
-
assert.equal(await readProcessStartToken(4242, { platform: "win32", probe: async () => ({ creationTimeMs: null, commandLine: null }) }), null);
|
|
133
|
-
assert.equal(await readProcessStartToken(0, { platform: "win32", probe: async () => { throw new Error("must not probe"); } }), null);
|
|
134
|
-
assert.equal(await readProcessStartToken(null, { platform: "win32", probe: async () => { throw new Error("must not probe"); } }), null);
|
|
135
|
-
});
|
|
136
|
-
```
|
|
137
|
-
|
|
138
|
-
- [ ] **Step 2: Run tests to verify they fail**
|
|
139
|
-
|
|
140
|
-
Run: `node --test test/process-identity-probe.test.mjs`
|
|
141
|
-
Expected: FAIL — `readProcessStartToken is not a function`.
|
|
142
|
-
|
|
143
|
-
- [ ] **Step 3: Implement `readProcessStartToken` in `src/core/process-identity-probe.mjs`**
|
|
144
|
-
|
|
145
|
-
Signature and dispatch exactly as the Interfaces block. Validate `pid` first (`Number.isSafeInteger(pid) && pid > 0` → else `null`, no probe). Linux path is synchronous inside the async function. Win32 path: `const probe = await probeFn(pid); return probe ? creationTimeToken(probe.creationTimeMs) : null;`. Any thrown probe error must be caught and become `null`. Update the module header comment: linux is supported via `/proc`, win32 via creation time, **darwin is deliberately unsupported** (ps elapsed time is second-resolution).
|
|
146
|
-
|
|
147
|
-
- [ ] **Step 4: Run tests to verify they pass**
|
|
148
|
-
|
|
149
|
-
Run: `node --test test/process-identity-probe.test.mjs`
|
|
150
|
-
Expected: PASS.
|
|
151
|
-
|
|
152
|
-
- [ ] **Step 5: Commit**
|
|
153
|
-
|
|
154
|
-
```bash
|
|
155
|
-
git add src/core/process-identity-probe.mjs test/process-identity-probe.test.mjs
|
|
156
|
-
git commit -m "feat: read process start tokens across platforms (win32 creation time)"
|
|
157
|
-
```
|
|
158
|
-
|
|
159
|
-
---
|
|
160
|
-
|
|
161
|
-
### Task 3: Collapse the four token copies into one
|
|
162
|
-
|
|
163
|
-
**Files:**
|
|
164
|
-
- Modify: `runner/pty-runner.mjs` (delete private `captureStartToken` at ~1613; import from `../src/core/pid.mjs`)
|
|
165
|
-
- Modify: `runner/state-coordinator.mjs` (delete private `captureStartToken` at ~494; import from `../src/core/pid.mjs`)
|
|
166
|
-
- Modify: `src/runtime/service.mjs` (delete private `readProcStartToken` at ~2546; import `captureStartToken`)
|
|
167
|
-
|
|
168
|
-
**Interfaces:**
|
|
169
|
-
- Consumes: `captureStartToken(pid)` from `src/core/pid.mjs`.
|
|
170
|
-
- Produces: no new API — this task only removes duplicates. All three call sites keep their current argument and behaviour (lease identities stay `null` on non-Linux).
|
|
171
|
-
|
|
172
|
-
- [ ] **Step 1: Replace the runner copies**
|
|
173
|
-
|
|
174
|
-
In `runner/pty-runner.mjs` add `import { captureStartToken } from "../src/core/pid.mjs";` and delete the function at ~1613. In `runner/state-coordinator.mjs` add the same import (path `../src/core/pid.mjs`) and delete the function at ~494.
|
|
175
|
-
|
|
176
|
-
- [ ] **Step 2: Replace the service copy**
|
|
177
|
-
|
|
178
|
-
In `src/runtime/service.mjs`, delete `readProcStartToken` (~2546) and change `serviceIdentity()` and `defaultObserveProcess` to call `captureStartToken` (import it from `../core/pid.mjs`).
|
|
179
|
-
|
|
180
|
-
- [ ] **Step 3: Verify the static convergence and types**
|
|
181
|
-
|
|
182
|
-
Run: `Get-ChildItem src,runner -Recurse -Filter *.mjs | Select-String -Pattern 'function captureStartToken|function readProcStartToken'`
|
|
183
|
-
Expected: exactly one hit — `src/core/pid.mjs`. (On POSIX: `grep -rn "function captureStartToken\|function readProcStartToken" src runner`.)
|
|
184
|
-
|
|
185
|
-
Run: `npm run typecheck`
|
|
186
|
-
Expected: clean.
|
|
187
|
-
|
|
188
|
-
- [ ] **Step 4: Run the affected suites**
|
|
189
|
-
|
|
190
|
-
Run: `node --test test/pid.test.mjs test/pty-runner.integration.test.mjs test/state-coordinator.integration.test.mjs test/service.test.mjs`
|
|
191
|
-
Expected: no new failures versus the recorded baseline (`research/baseline-test.log`); the `/proc` token assertions in `pty-runner.integration.test.mjs` still pass on Linux.
|
|
192
|
-
|
|
193
|
-
- [ ] **Step 5: Commit**
|
|
194
|
-
|
|
195
|
-
```bash
|
|
196
|
-
git add runner/pty-runner.mjs runner/state-coordinator.mjs src/runtime/service.mjs
|
|
197
|
-
git commit -m "refactor: collapse the four start-token copies into src/core/pid.mjs"
|
|
198
|
-
```
|
|
199
|
-
|
|
200
|
-
---
|
|
201
|
-
|
|
202
|
-
### Task 4: pty-runner writes real tokens into `host.json`
|
|
203
|
-
|
|
204
|
-
**Files:**
|
|
205
|
-
- Modify: `runner/pty-runner.mjs`
|
|
206
|
-
|
|
207
|
-
**Interfaces:**
|
|
208
|
-
- Consumes: `readProcessStartToken(pid, opts)` from `../src/core/process-identity-probe.mjs`.
|
|
209
|
-
- Produces: `host.json` records whose `runnerIdentity.startToken` / `childIdentity.startToken` are `/proc` tokens on Linux and `ct:<ms>` on win32; `null` when the probe is unavailable.
|
|
210
|
-
|
|
211
|
-
- [ ] **Step 1: Start the self probe before the start lease**
|
|
212
|
-
|
|
213
|
-
At the very top of `async function ownedMain(config)` (before the `acquireOwnedViewLock(..., "host-start", ...)` call at ~768):
|
|
214
|
-
|
|
215
|
-
```js
|
|
216
|
-
const selfTokenPromise = readProcessStartToken(process.pid);
|
|
217
|
-
```
|
|
218
|
-
|
|
219
|
-
Do **not** await it here — it runs in parallel with lease acquisition, the yield check and socket binding.
|
|
220
|
-
|
|
221
|
-
- [ ] **Step 2: Use it for `runnerIdentity`**
|
|
222
|
-
|
|
223
|
-
At the "Publish runner identity" `ownedUpdate` (~933), await before the update and use the result:
|
|
224
|
-
|
|
225
|
-
```js
|
|
226
|
-
const selfToken = await selfTokenPromise;
|
|
227
|
-
const claimedSelf = ownedUpdate((cur) => ({ ...cur, runnerPid: process.pid, runnerIdentity: { pid: process.pid, startToken: selfToken }, ... }));
|
|
228
|
-
```
|
|
229
|
-
|
|
230
|
-
Leave the `host-start` lease identity at ~771 on the synchronous `captureStartToken` (lease layer unchanged).
|
|
231
|
-
|
|
232
|
-
- [ ] **Step 3: Use it for `childIdentity`**
|
|
233
|
-
|
|
234
|
-
At the post-spawn `ownedUpdate` (~1023), read the child token first:
|
|
235
|
-
|
|
236
|
-
```js
|
|
237
|
-
const childToken = await readProcessStartToken(childPid);
|
|
238
|
-
const ready = ownedUpdate((cur) => ({ ...cur, childPid, childIdentity: { pid: childPid, startToken: childToken }, ... }));
|
|
239
|
-
```
|
|
240
|
-
|
|
241
|
-
- [ ] **Step 4: Run the integration suite**
|
|
242
|
-
|
|
243
|
-
Run: `node --test test/pty-runner.integration.test.mjs`
|
|
244
|
-
Expected: PASS on Linux — `runnerIdentity.startToken` and `childIdentity.startToken` still match `/^\d+$/` (the `/proc` value); on a Windows host the same assertions read `ct:` and the run/ready timing stays within the suite's existing tolerances.
|
|
245
|
-
|
|
246
|
-
- [ ] **Step 5: Commit**
|
|
247
|
-
|
|
248
|
-
```bash
|
|
249
|
-
git add runner/pty-runner.mjs
|
|
250
|
-
git commit -m "feat(host): publish a real start token on win32 host records"
|
|
251
|
-
```
|
|
252
|
-
|
|
253
|
-
---
|
|
254
|
-
|
|
255
|
-
### Task 5: `processIdentityState` — narrow `not_started`
|
|
256
|
-
|
|
257
|
-
**Files:**
|
|
258
|
-
- Modify: `src/core/host-coordination.mjs:49-54`
|
|
259
|
-
- Test: `test/host-coordination.test.mjs`
|
|
260
|
-
|
|
261
|
-
**Interfaces:**
|
|
262
|
-
- Produces: `processIdentityState(identity, observed, spawnedAt)` now returns `not_started` only when `spawnedAt == null && identity == null`; an identity-bearing record with a missing `spawnedAt` is judged by `observed`.
|
|
263
|
-
|
|
264
|
-
- [ ] **Step 1: Write the failing tests**
|
|
265
|
-
|
|
266
|
-
Add to `test/host-coordination.test.mjs`:
|
|
267
|
-
|
|
268
|
-
```js
|
|
269
|
-
test("processIdentityState: an identity-bearing record is never not_started", () => {
|
|
270
|
-
assert.equal(processIdentityState({ pid: 1, startToken: "t" }, { alive: true, startToken: "t" }, null), "owned");
|
|
271
|
-
assert.equal(processIdentityState({ pid: 1, startToken: "t" }, { alive: true, startToken: "u" }, null), "foreign");
|
|
272
|
-
assert.equal(processIdentityState({ pid: 1, startToken: "t" }, { alive: false }, null), "dead");
|
|
273
|
-
assert.equal(processIdentityState({ pid: 1, startToken: "t" }, { alive: true, startToken: null }, null), "unknown");
|
|
274
|
-
});
|
|
275
|
-
|
|
276
|
-
test("processIdentityState: not_started needs both identity and spawnedAt to be absent", () => {
|
|
277
|
-
assert.equal(processIdentityState(null, null, null), "not_started");
|
|
278
|
-
assert.equal(processIdentityState(undefined, null, null), "not_started");
|
|
279
|
-
});
|
|
280
|
-
```
|
|
281
|
-
|
|
282
|
-
- [ ] **Step 2: Run tests to verify they fail**
|
|
283
|
-
|
|
284
|
-
Run: `node --test test/host-coordination.test.mjs`
|
|
285
|
-
Expected: FAIL — the identity-bearing `null`-`spawnedAt` cases return `not_started`.
|
|
286
|
-
|
|
287
|
-
- [ ] **Step 3: Change the guard**
|
|
288
|
-
|
|
289
|
-
In `src/core/host-coordination.mjs`:
|
|
290
|
-
|
|
291
|
-
```js
|
|
292
|
-
if (spawnedAt == null && identity == null) return "not_started";
|
|
293
|
-
```
|
|
294
|
-
|
|
295
|
-
Update the JSDoc sentence that explains the degradation rule (identity present ⇒ spawn happened ⇒ judge by observation; suggesting `not_started` there would mark a possibly-live host releasable).
|
|
296
|
-
|
|
297
|
-
- [ ] **Step 4: Run tests to verify they pass**
|
|
298
|
-
|
|
299
|
-
Run: `node --test test/host-coordination.test.mjs`
|
|
300
|
-
Expected: PASS, including the pre-existing `(null, null, null) → not_started` case.
|
|
301
|
-
|
|
302
|
-
- [ ] **Step 5: Commit**
|
|
303
|
-
|
|
304
|
-
```bash
|
|
305
|
-
git add src/core/host-coordination.mjs test/host-coordination.test.mjs
|
|
306
|
-
git commit -m "fix: never classify an identity-bearing record as not_started"
|
|
307
|
-
```
|
|
308
|
-
|
|
309
|
-
---
|
|
310
|
-
|
|
311
|
-
### Task 6: Service observation assembly + `tokenMemo`
|
|
312
|
-
|
|
313
|
-
**Files:**
|
|
314
|
-
- Modify: `src/runtime/service.mjs` (`observeHostRole` ~983, `defaultObserveProcess` ~2624, `createService` ~136-161, six call sites)
|
|
315
|
-
- Test: `test/service.test.mjs`
|
|
316
|
-
|
|
317
|
-
**Interfaces:**
|
|
318
|
-
- Consumes: `captureStartToken` (Task 3), `readProcessStartToken` (Task 2), `processIdentityState` (Task 5).
|
|
319
|
-
- Produces:
|
|
320
|
-
- `createService(opts)` accepts `opts.isAlive?: (pid) => boolean` and `opts.readStartToken?: (pid) => Promise<string|null>` (defaults `isAlive`, `readProcessStartToken`).
|
|
321
|
-
- `observeHostRole(host, role, { sessionFile, memo, tokenMemo })` — `tokenMemo: Map<number, Promise<string|null>>`.
|
|
322
|
-
- Default observation: `identity == null && spawnedAt == null → "not_started"`; `pid == null → "unknown"`; dead → `"dead"`; record token `null` → `"unknown"` **without probing**; otherwise compare the memoized observed token and return `processIdentityState(...)`.
|
|
323
|
-
|
|
324
|
-
- [ ] **Step 1: Write the failing tests**
|
|
325
|
-
|
|
326
|
-
Add to `test/service.test.mjs` (follow the file's existing `createService` fixture pattern):
|
|
327
|
-
|
|
328
|
-
```js
|
|
329
|
-
test("observe: a matching win32 token is owned and a mismatching one is foreign", async () => {
|
|
330
|
-
// inject isAlive → true and readStartToken → "ct:111" for a stored identity whose token is "ct:111" / "ct:222"
|
|
331
|
-
});
|
|
332
|
-
|
|
333
|
-
test("observe: a null record token never probes and stays unknown", async () => {
|
|
334
|
-
// readStartToken must not be called; observation must be "unknown"
|
|
335
|
-
});
|
|
336
|
-
|
|
337
|
-
test("observe: tokenMemo probes each pid once per recovery", async () => {
|
|
338
|
-
// counting stub: two observations of the same pid → exactly 1 read
|
|
339
|
-
});
|
|
340
|
-
```
|
|
341
|
-
|
|
342
|
-
Write real assertions in the body; the three comments name the cases the tests must pin.
|
|
343
|
-
|
|
344
|
-
- [ ] **Step 2: Run tests to verify they fail**
|
|
345
|
-
|
|
346
|
-
Run: `node --test test/service.test.mjs`
|
|
347
|
-
Expected: FAIL — observations fall back to the old behaviour / the injected seams do not exist.
|
|
348
|
-
|
|
349
|
-
- [ ] **Step 3: Implement the assembly and wire the memo**
|
|
350
|
-
|
|
351
|
-
Move the observation assembly into the `createService` closure as `observeProcessIdentity(identity, { spawnedAt, pid, tokenMemo })` (spec D4 pseudo-code). Keep `opts.observeProcess` as the outer override; default to the new closure. Add `opts.isAlive` / `opts.readStartToken`. Thread `tokenMemo` through `observeHostRole` and create one per invocation at all six call sites (`~1109`, `~1110`, `~1152`, `~1155`, `~1416`, `~1417`), next to the existing `probeMemo`.
|
|
352
|
-
|
|
353
|
-
- [ ] **Step 4: Run tests to verify they pass**
|
|
354
|
-
|
|
355
|
-
Run: `node --test test/service.test.mjs test/host-recovery.test.mjs test/host-resolver.test.mjs`
|
|
356
|
-
Expected: PASS; existing injected `observeProcess` stubs keep working (they may stay synchronous).
|
|
357
|
-
|
|
358
|
-
- [ ] **Step 5: Commit**
|
|
359
|
-
|
|
360
|
-
```bash
|
|
361
|
-
git add src/runtime/service.mjs test/service.test.mjs
|
|
362
|
-
git commit -m "feat(service): compare start tokens when observing host roles"
|
|
363
|
-
```
|
|
364
|
-
|
|
365
|
-
---
|
|
366
|
-
|
|
367
|
-
### Task 7: `revalidateProbeOwned` covers the token path
|
|
368
|
-
|
|
369
|
-
**Files:**
|
|
370
|
-
- Modify: `src/runtime/service.mjs:1005-1018`
|
|
371
|
-
- Test: `test/service.test.mjs`
|
|
372
|
-
|
|
373
|
-
**Interfaces:**
|
|
374
|
-
- Produces: `revalidateProbeOwned(host, role, sessionFile, memo, tokenMemo)` — with a recorded token it re-reads via `readStartTokenImpl(pid)` **bypassing `tokenMemo`**, compares, and returns `false` on mismatch or `null`.
|
|
375
|
-
|
|
376
|
-
- [ ] **Step 1: Write the failing tests**
|
|
377
|
-
|
|
378
|
-
Add to `test/service.test.mjs`:
|
|
379
|
-
|
|
380
|
-
```js
|
|
381
|
-
test("revalidate: a reused pid with a different token never receives a signal", async () => {
|
|
382
|
-
// first read "ct:111" (observation, memoized), then re-read "ct:222" → no SIGTERM recorded
|
|
383
|
-
});
|
|
384
|
-
|
|
385
|
-
test("revalidate: a failing re-read refuses the signal", async () => {
|
|
386
|
-
// observation "ct:111", re-read null → no signal
|
|
387
|
-
});
|
|
388
|
-
```
|
|
389
|
-
|
|
390
|
-
- [ ] **Step 2: Run tests to verify they fail**
|
|
391
|
-
|
|
392
|
-
Run: `node --test test/service.test.mjs`
|
|
393
|
-
Expected: FAIL — the token path currently returns `true` unconditionally.
|
|
394
|
-
|
|
395
|
-
- [ ] **Step 3: Implement the revalidation**
|
|
396
|
-
|
|
397
|
-
Replace the `identity?.startToken != null → return true` shortcut: re-read with `readStartTokenImpl(pid)` (not the memo), compare against `identity.startToken`, return `false` on mismatch/`null`. Keep the probe branch unchanged (it still writes back to `probeMemo`). Do not write token results into `probeMemo` (its values are probe objects).
|
|
398
|
-
|
|
399
|
-
- [ ] **Step 4: Run the recovery suites**
|
|
400
|
-
|
|
401
|
-
Run: `node --test test/service.test.mjs test/host-recovery.test.mjs`
|
|
402
|
-
Expected: PASS.
|
|
403
|
-
|
|
404
|
-
- [ ] **Step 5: Commit**
|
|
405
|
-
|
|
406
|
-
```bash
|
|
407
|
-
git add src/runtime/service.mjs test/service.test.mjs
|
|
408
|
-
git commit -m "fix(service): re-read the token before signalling an owned process"
|
|
409
|
-
```
|
|
410
|
-
|
|
411
|
-
---
|
|
412
|
-
|
|
413
|
-
### Task 8: Degradation-path acceptance test
|
|
414
|
-
|
|
415
|
-
**Files:**
|
|
416
|
-
- Test: `test/service.test.mjs`
|
|
417
|
-
|
|
418
|
-
**Interfaces:**
|
|
419
|
-
- Consumes: everything from Tasks 6–7; no production change expected.
|
|
420
|
-
|
|
421
|
-
- [ ] **Step 1: Write the test**
|
|
422
|
-
|
|
423
|
-
```js
|
|
424
|
-
test("degradation: unreadable token and unavailable probe stay unknown and pend recovery", async () => {
|
|
425
|
-
// record token "ct:111"; readStartToken → null; probeProcessIdentity → null
|
|
426
|
-
// expect observation "unknown" and the recovery result "recovery_pending"
|
|
427
|
-
// assert no signal was sent to any pid
|
|
428
|
-
});
|
|
429
|
-
```
|
|
430
|
-
|
|
431
|
-
- [ ] **Step 2: Run it**
|
|
432
|
-
|
|
433
|
-
Run: `node --test test/service.test.mjs`
|
|
434
|
-
Expected: PASS. If it fails because production behaviour differs, fix production (the spec's D7 row is the contract), then re-run.
|
|
435
|
-
|
|
436
|
-
- [ ] **Step 3: Commit**
|
|
437
|
-
|
|
438
|
-
```bash
|
|
439
|
-
git add test/service.test.mjs
|
|
440
|
-
git commit -m "test: pin the unverifiable-identity degradation path"
|
|
441
|
-
```
|
|
442
|
-
|
|
443
|
-
---
|
|
444
|
-
|
|
445
|
-
### Task 9: Full verification and PR preparation
|
|
446
|
-
|
|
447
|
-
**Files:**
|
|
448
|
-
- Modify: none (verification only; PR body goes to `~/.github-issue-driven/zhuxixi/pi-agent-board/issue-238/pr-body.md`, outside the repo).
|
|
449
|
-
|
|
450
|
-
- [ ] **Step 1: Typecheck and full test run (Windows host)**
|
|
451
|
-
|
|
452
|
-
Run: `npm run typecheck` then `npm test *> "$HOME/baseline-after.log"`
|
|
453
|
-
Expected: typecheck clean; failure set equals the recorded baseline (`research/baseline-test.log` / `baseline-failures.txt`, 1298 tests / 66 fail / 5 skip) — diff the `✖` lines and require an empty difference.
|
|
454
|
-
|
|
455
|
-
- [ ] **Step 2: Coverage and package sanity**
|
|
456
|
-
|
|
457
|
-
Run: `npm run test:coverage` then `npm run pack:dry`
|
|
458
|
-
Expected: coverage thresholds hold (lines 85 / funcs 80 / branches 70) for the changed files; `pack:dry` lists the same file set plus no strays.
|
|
459
|
-
|
|
460
|
-
- [ ] **Step 3: Record the acceptance matrix**
|
|
461
|
-
|
|
462
|
-
Write the A1–A11 results (command → outcome) and U1 as `pending (user acceptance, needs Windows host + reload)` into the issue-238 ledger; do not claim U1 as passed.
|
|
463
|
-
|
|
464
|
-
- [ ] **Step 4: Write the PR body**
|
|
465
|
-
|
|
466
|
-
`pr-body.md` must contain: summary, the spec link, per-gap mapping (A-IDs), the two Windows-only behaviours that CI cannot cover, and the local-baseline evidence.
|
|
467
|
-
|
|
468
|
-
- [ ] **Step 5: Push and open the PR**
|
|
469
|
-
|
|
470
|
-
```bash
|
|
471
|
-
git push -u origin issue-238-process-identity-token
|
|
472
|
-
gh pr create --repo zhuxixi/pi-agent-board --base main --head issue-238-process-identity-token --title "fix(host): unify process identity tokens and produce them on win32 (#238)" --body-file "$HOME/.github-issue-driven/zhuxixi/pi-agent-board/issue-238/pr-body.md"
|
|
473
|
-
gh pr edit <PR> --repo zhuxixi/pi-agent-board --add-label zima:needs-review
|
|
474
|
-
```
|
|
475
|
-
|
|
476
|
-
Then block on Zima CR (skill `zima-pr-monitor`) in the same turn.
|
|
477
|
-
|
|
478
|
-
---
|
|
479
|
-
|
|
480
|
-
## Self-Review
|
|
481
|
-
|
|
482
|
-
**Spec coverage:** A1→T1, A2→T2, A3/A6→T6, A4→T5 (+T6), A5→T7, A7→T3, A8→T4, A9→T8, A10/A11→T9, U1→T9 Step 3 (recorded pending). D1→T3, D2→T2, D3→T4, D4→T6, D5→T5, D6→T7, D7→T8. No spec section without a task.
|
|
483
|
-
|
|
484
|
-
**Step scan:** every step names one action and its checkable result; bodies are limited to signatures, dispatch rules and the exact guards the spec pins.
|
|
485
|
-
|
|
486
|
-
**Type consistency:** `creationTimeToken(number) → string|null` (T1) is consumed by `readProcessStartToken` (T2) and both live in `process-identity-probe.mjs`; `tokenMemo: Map<pid, Promise<string|null>>` is introduced in T6 and consumed by T7; `processIdentityState(identity, observed, spawnedAt)` keeps its three-argument shape in T5 and T6.
|
|
487
|
-
|
|
488
|
-
**Review Focus:** old-record zero-probe path → T6 Step 1 case 2; hung probe degradation → T8; malformed record not releasable → T5 Step 1; reused-pid signal refusal → T7 Step 1; memo isolation → T6 Step 1 case 3.
|
|
489
|
-
|
|
490
|
-
**Proportion:** ~9 tasks against a 286-line spec; code blocks are signatures and test assertions, not implementations.
|