pi-session-mcp 0.8.1 → 0.8.3

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.
@@ -16,6 +16,16 @@ Provider-free tests exercise the real Pi SDK and real stdio child processes with
16
16
  a scripted model. They do not establish live client or model acceptance. State
17
17
  only what was run.
18
18
 
19
+ Targeted live checks are not a level. The [Pi extension live
20
+ check](#pi-extension-live-check) and the [multi-session skill
21
+ acceptance](#multi-session-skill-acceptance) use a real provider and model on one
22
+ path with one or two sessions: the first drives the server with a scripted
23
+ client, the second with one real controller. They are not a Level 3 cycle,
24
+ do not count towards its [gate](#gate) and do not replace it. A record of one
25
+ of them never says that Level 3 passed. What a package version, the MCP tool
26
+ contract and a setup report `schemaVersion` identify is defined in [tool
27
+ contracts](tool-contracts.md#versions).
28
+
19
29
  ## Level 1: repository checks
20
30
 
21
31
  Run on a clean checkout of the exact source under test:
@@ -24,7 +34,7 @@ Run on a clean checkout of the exact source under test:
24
34
  npm ci
25
35
  npm run typecheck
26
36
  npm run build:cli
27
- npm test
37
+ NODE_OPTIONS=--unhandled-rejections=strict npm test
28
38
  npm run build
29
39
  npm audit
30
40
  git diff --check
@@ -122,6 +132,17 @@ prefix (`npm install -g --prefix <dir> pi-session-mcp@<version>`) and runs the
122
132
  lifecycle through the installed `pi-session-mcp-setup`, which also proves the
123
133
  executables and the entry-point detection through npm's symlinks.
124
134
 
135
+ A packed-tarball run installs the tarball of the release candidate, before it is
136
+ published, into a fresh temporary prefix (`npm pack`, then
137
+ `npm install -g --prefix <dir> ./pi-session-mcp-<version>.tgz`, with `<dir>`
138
+ created by `mktemp -d` and removed afterwards) and runs the lifecycle through
139
+ the installed `pi-session-mcp-setup`. It is the only acceptance-level
140
+ pre-release check that resolves dependencies like a consumer install does,
141
+ without our lockfile, before publication. The working-tree run and the CI build
142
+ cannot prove that, because they install from the lockfile; the CI install smoke
143
+ also resolves fresh, but it is an early warning, not acceptance. The packed
144
+ tarball run is the pre-release counterpart of the published-package run.
145
+
125
146
  A published-release run uses a fresh clone of the published tag instead of an
126
147
  existing branch or local tag. It additionally records the tag object and the
127
148
  peeled commit, confirms `git describe --tags --exact-match`, passes Level 1 on
@@ -169,6 +190,35 @@ node scripts/setup-acceptance.mjs \
169
190
  --label npm-<version> --out level2-result.json
170
191
  ```
171
192
 
193
+ Packed tarball: pack the built candidate and install the tarball into a fresh
194
+ temporary prefix outside `/tmp`, then pass the installed executable and package
195
+ directory as for the published package. Create the prefix with `mktemp -d`,
196
+ never reuse a fixed one, and remove it and the tarball afterwards.
197
+
198
+ ```bash
199
+ npm pack
200
+ PREFIX="$(mktemp -d "$HOME/.cache/pi-session-mcp-pack.XXXXXX")"
201
+ npm install -g --prefix "$PREFIX" ./pi-session-mcp-<x.y.z>.tgz
202
+ node scripts/setup-acceptance.mjs \
203
+ --setup "$PREFIX/bin/pi-session-mcp-setup" \
204
+ --build-dir "$PREFIX/lib/node_modules/pi-session-mcp" \
205
+ --label packed-<x.y.z> --out level2-result.json
206
+ rm -rf "$PREFIX" ./pi-session-mcp-<x.y.z>.tgz
207
+ ```
208
+
209
+ The CI job and a nightly workflow (`.github/workflows/install-smoke.yml`) run
210
+ `scripts/install-smoke.mjs` against a lockfile-free install: CI against the
211
+ packed tarball of the commit, the nightly job against the published
212
+ `pi-session-mcp@latest`. The smoke starts the installed server, checks the
213
+ handshake, its name and version and the eight tools, and requires it to exit by
214
+ itself with status 0 after stdin EOF. It starts no session and uses no provider.
215
+ It reports one JSON line whose code is `smoke_passed` or one of
216
+ `package_invalid`, `server_exited`, `initialize_invalid`, `tools_invalid`,
217
+ `stdout_invalid`, `shutdown_timeout`, `shutdown_failed` or `timeout`. On any
218
+ failure it kills the server's whole process group. Both are early warnings for
219
+ a broken fresh install, not acceptance and not a replacement for the
220
+ packed-tarball run.
221
+
172
222
  Tag clone: build a fresh clone of the tag (`npm ci`, `npm run build`,
173
223
  `npm run build:cli`) and use it like the working tree, with `--setup` and
174
224
  `--build-dir` pointing at the clone.
@@ -316,6 +366,11 @@ external MCP grants, and client restart or resume.
316
366
  A narrower live check can cover a single path. It must state its scope and does
317
367
  not count as a ten-task cycle.
318
368
 
369
+ This applies to the two-session records below: the extension live check
370
+ started two sessions and the multi-session acceptance drives two concurrent
371
+ sessions from one controller. Both are targeted evidence, not a Level 3 cycle,
372
+ and no number of such runs adds up to the gate.
373
+
319
374
  ## Pi extension live check
320
375
 
321
376
  Manual, on a machine with Pi, `pi-cursor-sdk@0.5.3` and a stored Cursor key. Run it from a working tree (`npm run build`, then `node dist/main.js`) with a temporary configuration, passed through `PI_SESSION_MCP_CONFIG`, whose profile names `"extensions": ["npm:pi-cursor-sdk@0.5.3"]` and a Cursor model from Pi's catalog.
@@ -328,6 +383,9 @@ Manual, on a machine with Pi, `pi-cursor-sdk@0.5.3` and a stored Cursor key. Run
328
383
 
329
384
  Record date, source commit, versions and outcome under Status. No secret, path or prompt content goes into the record.
330
385
 
386
+ This check is targeted. Its two parallel sessions show that the extension path
387
+ works for the recorded build, provider and model. They are not a Level 3 cycle.
388
+
331
389
  ## Multi-session skill acceptance
332
390
 
333
391
  A targeted live check for profile skill selection ([skills](skills.md)) and for
@@ -347,8 +405,12 @@ Pi Session MCP tools; the script never does.
347
405
  `dist/`; `run` refuses a changed build.
348
406
  - Configuration: `prepare --base-config <operator config> --from-profile
349
407
  <alias>` copies only provider, model and thinking level of the one explicitly
350
- selected profile into a run configuration with two profiles: `accept-read` (default, `read-only`, skill `review`) and
351
- `accept-code` (`coding`, skills `implementation` and `handshake`). From the
408
+ selected profile into a run configuration with the profiles `accept-read` (default, `read-only`, skill `review`) and
409
+ `accept-code` (`coding`). From the Sprint 2 harness (#68) on, `accept-code`
410
+ selects exactly `implementation` and is used for every task except `slug`,
411
+ and a second coding profile `accept-code-handshake` selects `implementation`
412
+ and `handshake` and is used only for the `slug` session; before, `accept-code`
413
+ carried both skills for every task. From the
352
414
  harness of `3f98104` on, all three are `builtin:` references: the two worker
353
415
  skills ship with the candidate, and the `handshake` skill sits in the
354
416
  override directory `skills/` next to the run configuration, so the run also
@@ -357,16 +419,18 @@ Pi Session MCP tools; the script never does.
357
419
  `mcpServers` is always rejected. A profile with `extensions` is rejected
358
420
  unless `--with-extensions` is given; with it, `prepare` also copies exactly
359
421
  that profile's extension allowlist (1 to 8 distinct exact
360
- `npm:<name>@<version>` pins) into both run profiles and installs nothing.
422
+ `npm:<name>@<version>` pins) into every run profile and installs nothing.
361
423
  `--with-extensions` on a profile without extensions is rejected. Nothing else
362
424
  is copied: the run has its own workspaces and skills.
363
425
  - Working directory: `--work-dir` (default `~/.cache/pi-session-mcp-acceptance`)
364
426
  must not be inside a temporary directory (the system temporary directory,
365
427
  `/tmp`, `/var/tmp` or `/dev/shm`), because Codex refuses helper binaries
366
428
  there.
367
- - Fixtures: four small synthetic git repositories per client (`slug`, `stats`,
368
- `wait`, `range`), each a separate workspace alias (`cc-*` for Claude Code,
369
- `cx-*` for Codex). Both clients use the same configuration and build.
429
+ - Fixtures: five small synthetic git repositories per client (`slug`, `stats`,
430
+ `wait`, `range` and, from the Sprint 3 harness (#71) on, `review`), each a
431
+ separate workspace alias (`cc-*` for Claude Code, `cx-*` for Codex). `review`
432
+ holds a finished, frozen implementation that only the read-only reviewer of
433
+ `trio` uses. Both clients use the same configuration and build.
370
434
  - Fixture baselines: when it creates a fixture, `prepare` stores its initial
371
435
  commit and a manifest of its files (path, type, mode, SHA-256; without
372
436
  `.git/`) under the run's private directory, never inside the worker's
@@ -381,7 +445,31 @@ Pi Session MCP tools; the script never does.
381
445
  home (`~/.claude/skills` and `~/.agents/skills`, recorded as missing when
382
446
  absent). `run` rechecks all of them before the launch and again after the
383
447
  run. A change before the launch refuses the run; a change after it fails the
384
- result with `resourcesChanged`.
448
+ result with `resourcesChanged`. From the Sprint 2 harness (#66, #67) on it
449
+ also binds, under path-free names: per allowlisted extension the tree of its
450
+ real package root (`extension:<name>`) and the whole npm installation of
451
+ Pi's agent directory, with dependencies, `package.json` and lockfile
452
+ (`extensionNpmInstallation`, `none` without extensions); and every Codex
453
+ skill source besides the run's own link: `$CODEX_HOME/skills` with the
454
+ bundled `.system` skills (`codexHomeSkills`), all of `~/.agents/skills`
455
+ (`homeAgentsSkills`), `/etc/codex/skills` (`etcCodexSkills`) and the
456
+ `.agents/skills` of every ancestor of the Codex controller's directory
457
+ (`codexAncestorSkills`, up to `/`). These extension, Codex source and
458
+ candidate skill digests (the controller skill and both worker skills) walk a
459
+ tree without following links, record every link's text, and for a link
460
+ whose real path lies outside the bound root also bind what it leads to (the
461
+ file's bytes, or the same digest of the target directory, recursively); a
462
+ link that stays inside the root needs only its text. Each real directory is
463
+ digested once, so link cycles end, and at most 200,000 entries are read. A
464
+ value of `unreadable` or `tooLarge` means that a resource cannot be bound
465
+ completely. For every key, composed ones included, `prepare` then refuses and
466
+ names the key, and `run` refuses before the launch with `resourcesUnbound`.
467
+ `missing`, `none`, `notDirectory`, `unset` and a dangling top-level link are
468
+ determinate values and stay allowed. The other resources keep the plain tree
469
+ digest. `prepare` resolves Pi's
470
+ agent directory (`PI_CODING_AGENT_DIR`, else `~/.pi/agent`) and `CODEX_HOME`
471
+ (else `~/.codex`) once and records both only in the run's private data; they
472
+ never appear in a result or the evidence.
385
473
  - Home controller skills: Claude Code prefers a personal skill over a project
386
474
  skill of the same name. With `--setting-sources project,local`, as the
387
475
  harness starts it, Claude Code `2.1.296` listed only the project copy when a
@@ -389,8 +477,25 @@ Pi Session MCP tools; the script never does.
389
477
  without that flag the personal copy shadowed the project copy. Re-check this
390
478
  when the client version changes. Codex's precedence between its home skills
391
479
  and the run's repository skill is not established, so a Codex run is refused
392
- while `~/.agents/skills/pi-session-orchestration` differs from the
393
- candidate's skill.
480
+ while any bound Codex skill source (`$CODEX_HOME/skills`,
481
+ `~/.agents/skills`, `/etc/codex/skills` or an ancestor's `.agents/skills`)
482
+ holds a controller skill whose resolved content differs from the
483
+ candidate's. A controller skill is a directory named
484
+ `pi-session-orchestration` or one whose `SKILL.md` frontmatter declares that
485
+ `name:`. The frontmatter is read as a YAML block mapping whose top-level keys
486
+ are those at the indentation of its first content line; `name` may be a plain
487
+ or quoted scalar, and a ` #` comment outside quotes is ignored. Any other
488
+ form (a flow mapping or sequence, a bare scalar, a dedent or tab
489
+ indentation, a block or multi-line scalar, malformed quoting, a duplicate
490
+ `name`, unclosed frontmatter), and a `SKILL.md` that is not a regular file,
491
+ make the skill indeterminate, so its source counts as differing. Only the
492
+ first 16 KiB of a `SKILL.md` are read, after its type was checked. The
493
+ bounded search includes hidden directories such as `.system` and
494
+ follows links. An equal copy, also behind a link, or none is allowed; a
495
+ source that cannot be searched completely refuses the run. Skills that Codex
496
+ might load by other means, such as other file names or plugin caches, are
497
+ not covered. Before the Sprint 2 harness only
498
+ `~/.agents/skills/pi-session-orchestration` was checked.
394
499
  - Launch record and failed analysis: `run` records the launch once before the
395
500
  controller starts, so an attempt that ends without a result is never repeated
396
501
  silently. If the analysis after the controller fails, the result is recorded
@@ -410,7 +515,10 @@ Pi Session MCP tools; the script never does.
410
515
  the shipped skill. Codex installs skills only in the user's home, which the
411
516
  run must not change, so the Codex controller gets one run-scoped symbolic link
412
517
  in `.agents/skills` of its directory. Earlier runs linked both. No global
413
- skill directory changes.
518
+ skill directory changes. From the Sprint 2 harness (#67) on, the evidence
519
+ records per client the kind of controller skill, `installed` for Claude Code
520
+ and `linked` for Codex, with its tree digest and without paths
521
+ (`controllerSkills`).
414
522
  - Clients: Claude Code runs as `claude -p` with `--mcp-config`,
415
523
  `--strict-mcp-config`, `--setting-sources project,local`,
416
524
  `--permission-mode dontAsk` and an `--allowedTools` list of the eight tools
@@ -418,8 +526,19 @@ Pi Session MCP tools; the script never does.
418
526
  `codex exec --ignore-user-config --sandbox read-only` with the server
419
527
  defined through `-c mcp_servers.pi-candidate.*` and the three per-tool
420
528
  approvals from [client setup](client-setup.md#run-codex-without-prompts).
421
- Neither run changes a persistent registration, `HOME` or `CODEX_HOME`, and
422
- both use the existing authentication.
529
+ The harness changes neither a persistent registration, `HOME` nor the
530
+ contents of `CODEX_HOME`, and both runs use the existing authentication.
531
+ Codex itself can install its bundled `.system` skills into
532
+ `$CODEX_HOME/skills` on its first start after an upgrade, or create that
533
+ directory in a fresh `CODEX_HOME`. Because those skills are bound, such a
534
+ change invalidates the prepared run for both clients; it fails safe and never
535
+ passes. After a Codex upgrade, start Codex once with the same `CODEX_HOME`
536
+ before `prepare`. From the Sprint 2
537
+ harness (#66, #67) on, the Codex controller runs with exactly the
538
+ `CODEX_HOME` that `prepare` recorded, whatever the launching environment
539
+ holds, and the server of both clients receives the recorded Pi agent
540
+ directory as `PI_CODING_AGENT_DIR`, so the bound extension directory is the
541
+ one the server loads from.
423
542
  - Time limit: `run --timeout-min` takes a number above 0 and at most 180
424
543
  (default 25). After the limit the harness sends `SIGTERM` to the client's
425
544
  process group and waits up to 10 seconds. It then sends `SIGKILL` to that
@@ -435,12 +554,14 @@ Pi Session MCP tools; the script never does.
435
554
 
436
555
  ### Scenarios
437
556
 
438
- Each client runs two invocations, one per scenario:
557
+ Each client runs one invocation per scenario: `parallel` and `abort`, and from
558
+ the Sprint 3 harness (#71) on also `trio`:
439
559
 
440
560
  | Scenario | What the controller does | What is checked |
441
561
  | --- | --- | --- |
442
- | `parallel` | Capabilities first; two sessions of `accept-code` on `slug` and `stats`; both first turns started before waiting; one follow-up in the `slug` session that adds a test and completes the handshake from the worker's skills; own verification; close both | Candidate version and configuration fingerprint seen through capabilities; `skills` of `accept-code`; first turns overlap by the server's `startedAt` and `completedAt`; follow-up completed; tests pass and only allowed files changed; handshake file holds the token although no prompt contained it |
443
- | `abort` | Two sessions on `wait` (a bounded `sleep 120` command) and `range` (a bounded `sleep 45`, then the change); abort `wait` about 15 seconds after both turns started, while `range` runs; verify and close both | Every abort result is `ok` (an `abort_timeout` stays on record even after a retry); the first successful abort comes before `pi_turn_get` shows the `wait` turn `aborted`, and both before its session is closed; its abort time lies inside the running interval of `range`; `range` completed and verified; at the end of the run no late file exists and no worker `sleep` remains |
562
+ | `parallel` | Capabilities first; a session of `accept-code-handshake` on `slug` and one of `accept-code` on `stats` (before the Sprint 2 harness: `accept-code` for both); both first turns started before waiting; one follow-up in the `slug` session that adds a test and completes the handshake from the worker's skills; own verification; close both | Candidate version and configuration fingerprint seen through capabilities; `skills` of both coding profiles and the profile of each session; first turns overlap by the server's `startedAt` and `completedAt`; follow-up completed; tests pass and only allowed files changed; handshake file holds the token although no prompt contained it |
563
+ | `abort` | Two sessions of `accept-code` on `wait` (a bounded `sleep 120` command) and `range` (a bounded `sleep 45`, then the change); abort `wait` about 15 seconds after both turns started, while `range` runs; verify and close both | Every `pi_session_abort` call of the transcript is `ok` and targets the `wait` session (an `abort_timeout`, an unknown session id or an abort on `range` stays on record and fails, also after a retry); the first successful abort comes before `pi_turn_get` shows the `wait` turn `aborted`, and both before its session is closed; its abort time lies inside the running interval of `range`; `range` completed and verified; at the end of the run no late file exists and no worker `sleep` remains |
564
+ | `trio` | Capabilities first; three sessions whose first turns start in the order `review`, `slug`, `wait`, all before waiting for any: `accept-read` on `review` (an enumerated read-only review of the frozen `review` fixture, one finding per exported function with a line reference), `accept-code` on `slug` (a bounded `sleep 45`, then the change, only in `src/slug.js`) and on `wait` (a bounded `sleep 120`); abort `wait` about 5 seconds after its turn was accepted, while `slug` and `review` run; own verification of `slug`; confirm `review` changed nothing; close all three; no handshake | Candidate version and configuration fingerprint seen through capabilities; three sessions, each on its expected alias and profile; `accept-read` offers exactly `review` and only the `review` session used it; all three first turns overlap; every `pi_session_abort` call is `ok` and on `wait`, the first successful abort comes before `wait` is seen `aborted`, both before close; the abort lies inside the running intervals of both `slug` and `review`; `slug` and `review` completed; `slug` tests pass; the `review` fixture is byte-identical in working tree, index and `HEAD`, with no empty directory; `wait` leaves no late file; no worker `sleep` remains |
444
565
 
445
566
  ### Independent checks
446
567
 
@@ -482,6 +603,8 @@ Each client runs two invocations, one per scenario:
482
603
  - the controller exit code is 0 (`controllerExit`), neither `timedOut`,
483
604
  `spawnFailed` nor `harnessAborted` is set, and the analysis finished
484
605
  (`analysisFailed`);
606
+ - every bound resource was completely readable when recorded and after the
607
+ run (`resourcesUnbound`);
485
608
  - no bound resource changed after the run (`resourcesChanged`), and for a
486
609
  reanalysis no resource or fixture differs from the state recorded at the
487
610
  end of the run (`stateChangedSinceRun`);
@@ -489,8 +612,15 @@ Each client runs two invocations, one per scenario:
489
612
  process of the run remains (`residualProcesses`);
490
613
  - the controller called `pi_capabilities_get` first (`capabilitiesNotFirst`),
491
614
  saw the candidate version and configuration fingerprint
492
- (`candidateNotConfirmed`) and saw exactly the skills `implementation` and
493
- `handshake` on `accept-code` (`workerSkills`);
615
+ (`candidateNotConfirmed`), saw exactly the skill `implementation` on
616
+ `accept-code` and exactly `implementation` and `handshake` on
617
+ `accept-code-handshake`, and only the `slug` session used
618
+ `accept-code-handshake` while every other session used `accept-code`
619
+ (`workerSkills`; before the Sprint 2 harness: exactly `implementation` and
620
+ `handshake` on `accept-code`). In `trio` there is no handshake: `slug` and
621
+ `wait` use `accept-code`, `accept-read` offers exactly `review`, and only the
622
+ `review` session may use `accept-read`; in `parallel` and `abort` no session
623
+ uses `accept-read`;
494
624
  - the structural leak scan found nothing (`structuralLeaks`), the token
495
625
  appears nowhere it must not (`tokenExposed`), and no worker prompt or
496
626
  controller action touched a private marker (`privateAccess`);
@@ -499,13 +629,31 @@ Each client runs two invocations, one per scenario:
499
629
  overlapped (`noOverlap`) and the follow-up completed
500
630
  (`followUpNotCompleted`);
501
631
  - `abort`: the `wait` turn ended `aborted` after only successful aborts
502
- (`abortFailed`), in the required order and before its session closed
632
+ (`abortFailed`), every abort call on the `wait` session
633
+ (`offTargetAbort`), in the required order and before its session closed
503
634
  (`abortOrder`), and `range` completed with the abort inside its running
504
635
  interval (`neighborNotRunningDuringAbort`);
636
+ - `trio`: exactly three sessions started (`sessionsNotStarted`), each on its
637
+ expected workspace alias and profile (`sessionAssociation`); the `slug` and
638
+ `review` first turns completed (`firstTurnsNotCompleted`) and all three
639
+ first turns overlapped (`noOverlap`); the `wait` turn ended `aborted` after
640
+ only successful aborts (`abortFailed`) and only on `wait`
641
+ (`offTargetAbort`), in the required order and before
642
+ close (`abortOrder`), with the abort inside the running intervals of both
643
+ `slug` and `review` (`neighborsNotRunningDuringAbort`); the `review` fixture
644
+ is unchanged in working tree, index and `HEAD`, `HEAD` is still its base
645
+ commit, and no empty directory appeared (`review:readOnly`); the `slug`
646
+ task of `trio` may change only `src/slug.js`, while `test/slug.test.js`
647
+ and `HANDSHAKE.txt` stay allowed in `parallel` only. The read-only check
648
+ compares the end state with the baseline, so a write reverted before the
649
+ end, a `git stash`, new refs or branches and directory-mode changes are not
650
+ seen; the read-only profile is the actual guard;
505
651
  - per fixture: only allowed changes (`<task>:changes`), every change written
506
652
  during a worker turn (`<task>:attribution`), fixture tests and business
507
- checks passing (`<task>:tests`), for `slug` the added test and the
508
- handshake (`slug:followUp`), for `wait` no late file (`wait:lateFile`),
653
+ checks passing (`<task>:tests`), for `slug` in `parallel` the added test
654
+ and the handshake (`slug:followUp`), for `review` the read-only invariance
655
+ (`review:readOnly`) instead of tests, for `wait` no late file
656
+ (`wait:lateFile`),
509
657
  and an oracle for every task of the scenario (`oracleMissing`).
510
658
  - Liveness observation: for each turn of a session, `turnLiveness` records the
511
659
  number of `pi_turn_get` polls that saw the turn `running` and whether
@@ -530,7 +678,8 @@ Each client runs two invocations, one per scenario:
530
678
  - `evidence` writes one sanitized JSON record and refuses to write a local path
531
679
  or the token. It lists the original results and the reanalyses separately,
532
680
  lists every launch with whether it left a result, and includes the extension
533
- names and versions and the resource digests.
681
+ names and versions, the resource digests, the profiles and, from the Sprint 2
682
+ harness on, the controller skill kinds and digests.
534
683
  Transcripts and the configuration stay in the run's private directory and
535
684
  are never published.
536
685
 
@@ -555,6 +704,19 @@ limits, which that change removed:
555
704
  client to close without a bound. A hang would have shown as a hang, not as a
556
705
  pass.
557
706
 
707
+ Records made with the harness before Sprint 2 (#66, #67, #68) have these
708
+ further method limits:
709
+
710
+ - Pi extensions were bound by name and version only, not by the package
711
+ contents the server loaded, and the run's server did not receive the agent
712
+ directory explicitly.
713
+ - For Codex, only `~/.agents/skills/pi-session-orchestration` was checked;
714
+ `$CODEX_HOME/skills`, `/etc/codex/skills`, other home skills and ancestor
715
+ `.agents/skills` were neither bound nor excluded, and the controller
716
+ inherited `CODEX_HOME` from the launching environment.
717
+ - The `handshake` skill was offered to every task's worker; this is how the
718
+ v0.8.1 Codex `abort` run's worker could apply it to an unrequested file.
719
+
558
720
  These limits do not show that any recorded result was wrong. The records stay
559
721
  as recorded; a new run gets a new record.
560
722
 
@@ -573,6 +735,13 @@ as recorded; a new run gets a new record.
573
735
 
574
736
  ## Status
575
737
 
738
+ Targeted records below, the Pi extension live check and the multi-session
739
+ skill acceptance with one or two concurrent sessions, are not Level 3 cycles
740
+ even where they used a real controller or a real model. The wording "passed all
741
+ three levels" refers to earlier private cycles only; the full ten-task Level 3
742
+ cycle has not been repeated on Pi SDK `1.x`. This note adds no result and
743
+ changes none.
744
+
576
745
  Release notes state which levels were run for a release and what was not
577
746
  covered. Pi Session MCP has passed all three levels in earlier private cycles. The
578
747
  live two-client acceptance has not yet been repeated on a build with Pi SDK
@@ -1204,3 +1373,361 @@ release candidate `baa6406` on Linux (`x64`), with Node.js `26.11.1`, Codex CLI
1204
1373
  `0c7bad3`. Its built modules have the same dist tree SHA-256
1205
1374
  (`7b16757f9a1a0318247914f56debe79119a3845e1a1debcf1ad371db3a958fce`) as the
1206
1375
  final candidate `1e904be` of the multi-session acceptance recorded above.
1376
+
1377
+ ### v0.8.1 post-release evidence carried over from the release notes
1378
+
1379
+ The post-release results of `v0.8.1` were recorded in the [v0.8.1 release
1380
+ notes](https://github.com/plagor44-ux/pi-session-mcp/releases/tag/v0.8.1),
1381
+ published on 2026-10-12 (22:06 UTC), and were carried over into this document
1382
+ on 2026-10-13 as roadmap item R19. This is a historical record taken from
1383
+ those notes: the checks were not rerun for it, and every item below keeps the
1384
+ scope, result and limitation that the notes state. The pre-release results of
1385
+ the same release candidate are recorded above.
1386
+
1387
+ Source and CI, as stated in the notes:
1388
+ - Release source and annotated tag target: `e462054a37505ef00e1e0c549ebab27e4db7ef55`,
1389
+ the merge of #55 (head `440f2e4ccb4f7cebd88825abd8515218f4bbbdee`). The
1390
+ annotated tag object is `02f0b30588115058fbb30148cb0934f18cf05aa3`.
1391
+ - #55 passed CI on Linux, macOS 15 and macOS 26. The merged-main CI run
1392
+ `38309519719` and the tag CI run `38309738675` are named in the notes. CI is
1393
+ neither Level 2 nor Level 3 acceptance.
1394
+
1395
+ Provider-free (Level 1), on a fresh clone of the tag, with Node.js `26.11.1`
1396
+ and npm `12.2.0`. Every command exited with `0`:
1397
+ - Typecheck, server build and CLI build.
1398
+ - 50 test files: 1035 passed and 6 skipped.
1399
+ - `npm audit` and `npm audit --omit=dev`: 0 vulnerabilities.
1400
+ - Offline Doctor: package version `0.8.1`. With the example configuration, the
1401
+ only finding was its placeholder workspace.
1402
+
1403
+ Package publication, a release fact and not an acceptance level: the npm
1404
+ package `pi-session-mcp@0.8.1` was published from a fresh clone of the tag
1405
+ through staged publishing, approved by the maintainer. It has 129 files and
1406
+ 215.6 kB, with shasum `b39fe48aff6ade4bf52c427960593951e150191b`. The tarball
1407
+ downloaded from the registry has the same SHA-1 and SHA-512 integrity. The
1408
+ package has no provenance attestation, because it was published from the
1409
+ maintainer's machine.
1410
+
1411
+ Real clients without a model (Level 2), with `scripts/setup-acceptance.mjs`:
1412
+ 160 of 160 checks passed in each of three variants:
1413
+ - the release candidate's working tree (`baa6406`);
1414
+ - a fresh clone of the tag;
1415
+ - the npm package installed into a temporary prefix.
1416
+
1417
+ The clients were Codex CLI `0.162.1` (`user`) and Claude Code `2.1.296`
1418
+ (`user`, `project`, `local`), in disposable homes. The real client
1419
+ registrations were unchanged, no process remained, and the build stayed
1420
+ byte-identical. The notes do not state the platform of these variants; the
1421
+ pre-release run of the candidate above states Linux (`x64`).
1422
+
1423
+ Real model, targeted multi-session skill acceptance (not a Level 3 cycle), on
1424
+ the final code candidate `1e904be`, whose built modules equal this release's
1425
+ (dist tree SHA-256 `7b16757f…`, abbreviated in the notes; the full value is
1426
+ recorded above). The detailed record is in the multi-session section above.
1427
+ - Controllers: Claude Code `2.1.296` and Codex CLI `0.162.1`. Workers: Cursor
1428
+ (`pi-cursor-sdk@0.5.3`, `composer-2.5`) on Pi SDK `1.1.0`.
1429
+ - Both required Claude Code scenarios passed every check: two overlapping
1430
+ sessions with a same-session follow-up, and a targeted abort while the
1431
+ neighbor kept running.
1432
+ - `updatedAt` had moved past `startedAt` in every Cursor turn polled while
1433
+ running: 31 of 31 across four runs.
1434
+
1435
+ Limitations and failures stated in the notes:
1436
+ - No full ten-task Level 3 cycle. The multi-session check is targeted.
1437
+ - Live acceptance ran on Linux only, with Cursor (`pi-cursor-sdk@0.5.3`,
1438
+ `composer-2.5`) workers. macOS is covered by CI.
1439
+ - Not live-proven: a Codex controller reading the skill from a copy installed
1440
+ in `~/.agents/skills`; a third concurrent or `read-only` worker; a real crash
1441
+ in the middle of a setup skill update (provider-free tests cover it).
1442
+ - In the final run, the supplementary Codex `abort` invocation failed its scope
1443
+ check: the Cursor worker applied the `handshake` test skill on its own. The
1444
+ required Claude Code invocations and Codex `parallel` passed, and Codex
1445
+ `abort` had passed on earlier runs of the same build.
1446
+
1447
+ ### v0.8.2 pre-release acceptance
1448
+
1449
+ Before its release, `v0.8.2` passed Level 1 and the working-tree Level 2 on its
1450
+ release candidate `bdbdf00` on Linux (`x64`), with Node.js `26.11.1`, Codex CLI
1451
+ `0.162.1` and Claude Code `2.1.296`, on 2026-10-13:
1452
+ - Level 1 on the release branch: every command exited with `0`.
1453
+ - The test run, with `NODE_OPTIONS=--unhandled-rejections=strict`, reported
1454
+ 54 files, 1409 passed and 6 skipped, and no unhandled error.
1455
+ - `npm audit` and `npm audit --omit=dev` reported 0 vulnerabilities.
1456
+ - `npm pack --dry-run` listed 135 files, including the three skills, and
1457
+ no acceptance harness, sources, tests, lockfile or implementation plan.
1458
+ - Doctor reported `packageVersion` `0.8.2`. With the example configuration
1459
+ its only finding was the placeholder workspace.
1460
+ - Level 2 through `scripts/setup-acceptance.mjs` on the candidate's working
1461
+ tree: 160 of 160 checks passed. All nine steps passed on all four targets.
1462
+ The real client registrations were unchanged, no process remained, and the
1463
+ built files were unchanged.
1464
+ - Apart from the version and documentation, the candidate's sources equal
1465
+ `166ffef`, current main; its runtime sources (`src/`, `skills/`) equal
1466
+ those of `0aae639`, on which Sprint 3 ran. Its built modules have the same
1467
+ `dist/main.js` SHA-256 (`47875d38886528ace6b242df2c6ad79d624c51e330e63c2f401576eadc449ed7`)
1468
+ and `dist` tree as the build on which the
1469
+ [Sprint 3 live acceptance](#sprint-3-live-acceptance-2026-10-13) ran, including
1470
+ the accepted ten-task Level 3 cycle.
1471
+
1472
+ ### v0.8.2 post-release evidence
1473
+
1474
+ The published-release acceptance of `v0.8.2` ran on 2026-10-15 from 15:36 UTC
1475
+ on Linux (`x64`) with Node.js `26.11.1`, npm `12.2.0`, Codex CLI `0.162.1` and
1476
+ Claude Code `2.1.299`. It **failed** for the installed npm package; the tag
1477
+ passed. The failure is recorded as it happened and is tracked as
1478
+ [#78](https://github.com/plagor44-ux/pi-session-mcp/issues/78).
1479
+
1480
+ Tag binding: a fresh clone of the annotated tag `v0.8.2` (tag object
1481
+ `d068067539a5cf86917e0be08014c9535dce0cc2`) peels to
1482
+ `bdfb95de9a46defa64d2eb382d58d454f97fc8fb`, the merge of #76, and
1483
+ `git describe --tags --exact-match` reports `v0.8.2`.
1484
+
1485
+ Provider-free (Level 1), on that clone. Every command exited with `0`:
1486
+ - 54 test files: 1409 passed and 6 skipped, with strict unhandled rejections
1487
+ and no unhandled error.
1488
+ - `npm audit` and `npm audit --omit=dev`: 0 vulnerabilities.
1489
+ - `git diff --check` and `git status --short` printed nothing.
1490
+ - Offline Doctor with the example configuration: `packageVersion` `0.8.2`;
1491
+ its only finding was the placeholder workspace (`workspace_missing`).
1492
+
1493
+ `package.json`, `package-lock.json`, `dist/main.js` and the whole `dist` tree
1494
+ (84 files) were byte-identical before and after the client cycles.
1495
+ `dist/main.js` has the SHA-256 of the release build
1496
+ (`47875d38886528ace6b242df2c6ad79d624c51e330e63c2f401576eadc449ed7`).
1497
+
1498
+ Real clients without a model (Level 2), with `scripts/setup-acceptance.mjs`:
1499
+ - Tag clone: 160 of 160 checks passed; all nine steps passed on all four
1500
+ targets. The real client registrations were unchanged, no process
1501
+ remained, and the build stayed byte-identical.
1502
+ - npm package, installed with `npm install -g --prefix` into a temporary
1503
+ prefix: the installed version is `0.8.2`, the registry shasum is
1504
+ `1ab640909d8c513f3dbaad3c3691f7ce1f267945` and `dist/main.js` has the same
1505
+ SHA-256 as above. **151 of 160 checks passed.** `--verify` (steps 5 and 8)
1506
+ reported `mcp_unsupported` instead of `mcp_verified` on all four targets;
1507
+ every other step passed, no process remained and the package stayed
1508
+ byte-identical. `realRegistrationsUnchanged` was `false` (see below).
1509
+
1510
+ Cause of the verify failure (#78): the prefix resolved
1511
+ `@earendil-works/pi-codemode` `1.2.0`, while the lockfile pins `1.1.0`. The
1512
+ pinned Pi SDK `1.1.0` declares it as `^1.1.0`, and `1.2.0` no longer exports
1513
+ `MCP_TYPESCRIPT_PREAMBLE`, which the SDK imports. Started directly, the
1514
+ installed `dist/main.js` exits with `1` and a `SyntaxError` before its first
1515
+ MCP frame; the tag clone's server answers `initialize`. Verify reports a
1516
+ server that exits before `initialize` as `mcp_unsupported`. The published
1517
+ bytes are correct; a fresh install of them is not. Installations made before
1518
+ `pi-codemode` `1.2.0` was published (2026-10-12, 23:00 UTC) keep `1.1.0` and
1519
+ start.
1520
+
1521
+ `realRegistrationsUnchanged` `false`: the cause was not determined. Another
1522
+ process wrote the real Codex configuration file during the npm run (15:39:09
1523
+ UTC). Afterwards no real registration referenced the run's directories, the
1524
+ real setup ownership records were unchanged since 2026-10-13, and the real
1525
+ Claude Code registration still targeted the installed `0.8.1`. A live client
1526
+ that changes its registrations during a run is a known source of a false
1527
+ failure (see [Tooling](#tooling)); the check is not counted as passed.
1528
+
1529
+ A run against the published release on 2026-10-14 was reported with exit `0`,
1530
+ but neither its variant nor its check counts were saved; it is not evidence.
1531
+
1532
+ Result: `v0.8.2` is accepted as a release source (tag clone), not as an
1533
+ installed npm package. Fresh npm installs of `0.8.2`, and probably of every
1534
+ version that pins the Pi SDK `1.1.0`, crash at startup.
1535
+
1536
+ ### v0.8.3 pre-release acceptance
1537
+
1538
+ Before its release, `v0.8.3` passed Level 1, the working-tree Level 2 and the
1539
+ new packed-tarball Level 2 on its release candidate `35091eb` on Linux
1540
+ (`x64`), with Node.js `26.11.1`, npm `12.2.0`, Codex CLI `0.162.1` and Claude
1541
+ Code `2.1.299`, on 2026-10-15:
1542
+ - Level 1 on the release branch: every command exited with `0`.
1543
+ - The test run, with `NODE_OPTIONS=--unhandled-rejections=strict`, reported
1544
+ 55 files, 1425 passed and 6 skipped, and no unhandled error.
1545
+ - `npm audit` and `npm audit --omit=dev` reported 0 vulnerabilities.
1546
+ - `npm pack --dry-run` listed 136 files, including the three
1547
+ skills, and no acceptance harness, sources, tests, lockfile or
1548
+ implementation plan.
1549
+ - Doctor reported `packageVersion` `0.8.3`. With the example configuration
1550
+ its only finding was the placeholder workspace.
1551
+ - Level 2 through `scripts/setup-acceptance.mjs` on the candidate's working
1552
+ tree: 160 of 160 checks passed. All nine steps passed on all four targets.
1553
+ The real client registrations were unchanged, no process remained, and the
1554
+ built files were unchanged.
1555
+ - Packed-tarball Level 2 (#78): the candidate's tarball, installed with
1556
+ `npm install -g --prefix` into a fresh prefix without the lockfile, resolved
1557
+ every `@earendil-works` package to `1.2.0` with a single copy each. The install
1558
+ smoke reported `smoke_passed`, and Level 2 against the installed package
1559
+ passed 160 of 160 checks, with the same unchanged registrations, process
1560
+ and build results.
1561
+
1562
+ Targeted live multi-session acceptance on the new Pi SDK `1.2.0`, with
1563
+ `scripts/multi-session-acceptance.mjs` (harness SHA-256 prefix `bb1620ad`) on a
1564
+ clean detached checkout of `16b2374`, the candidate before the review fixes:
1565
+ `dist/main.js` SHA-256 `47875d38…`, build digest `c5e91f70…`. Between `16b2374`
1566
+ and `35091eb` no runtime source changed; the lockfile gained only the root
1567
+ entry that pins `@earendil-works/pi-telemetry` at the `1.2.0` it already
1568
+ resolved. Strictly sequential runs on 2026-10-15 from 18:19 UTC, with
1569
+ synthetic fixtures and the worker profiles copied from the operator profiles
1570
+ without their external MCP grant:
1571
+
1572
+ | Profile source | Extension | Controller | Scenario | Result | Duration |
1573
+ | --- | --- | --- | --- | --- | --- |
1574
+ | DeepSeek `deepseek-flash`, `high` | none | Codex `0.162.1` | `abort` | passed, no failure | 101 s |
1575
+ | DeepSeek `deepseek-flash`, `high` | none | Claude Code `2.1.299` | `parallel` | passed, no failure | 66 s |
1576
+ | Cursor `grok-4.7@256k:fast`, `high` | `pi-cursor-sdk` `0.5.3` | Claude Code `2.1.299` | `abort` | passed, no failure | 156 s |
1577
+ | Cursor `grok-4.7@256k:fast`, `high` | `pi-cursor-sdk` `0.5.3` | Codex `0.162.1` | `parallel` | passed, no failure | 146 s |
1578
+
1579
+ Every run kept its scope, closed its sessions and left no residual process.
1580
+ The Cursor runs load the allowlisted `pi-cursor-sdk` `0.5.3`, which registers
1581
+ `before_agent_start`, whose semantics changed in SDK `1.2.0`; both passed.
1582
+
1583
+ Not established for `0.8.3`: the ten-task Level 3 cycle on SDK `1.2.0`, the
1584
+ `trio` scenario, the operator profiles' external MCP grant, macOS on real
1585
+ hardware (R10, R11), and other providers and models. The published-release
1586
+ acceptance follows after publication.
1587
+
1588
+ ## Sprint 1 correctness checks (2026-10-13)
1589
+
1590
+ These checks belong to [#59](https://github.com/plagor44-ux/pi-session-mcp/issues/59)
1591
+ (recovery keeps unprovable trash) and
1592
+ [#56](https://github.com/plagor44-ux/pi-session-mcp/issues/56) (verify
1593
+ diagnostics). They were run on 2026-10-13 against the Sprint 1 branch
1594
+ `fix/59-56-s1-correctness`, before merge and without a release. The
1595
+ [Sprint 1 file](sprints/2026-10-13-s1-correctness.md) holds the commands,
1596
+ source binding, before-fix evidence and review findings in full.
1597
+
1598
+ Source: base main `3e360dd`; runtime candidate
1599
+ `fa32c22b573ff0bb0b920813bd9520bb79b025f4`, the last commit that changes `src/`
1600
+ or `test/`. Native Linux (x64), Node.js `26.11.1`, npm `12.2.0`, Codex CLI
1601
+ `0.162.1`, Claude Code `2.1.296`. No provider, model or credential was used.
1602
+
1603
+ Provider-free (Level 1), on `fa32c22`:
1604
+
1605
+ | Check | Exit | Result |
1606
+ | --- | --- | --- |
1607
+ | `npm ci`, `npm run typecheck`, `npm run build:cli`, `npm run build` | 0 each | |
1608
+ | `NODE_OPTIONS=--unhandled-rejections=strict npm test` | 0 | 52 files passed; 1121 tests passed, 6 skipped, 0 failed; no unhandled error |
1609
+ | `npm audit`, `npm audit --omit=dev` | 0 each | 0 vulnerabilities |
1610
+ | `git diff --check`, `git status --short` | 0 each | clean |
1611
+ | #59 counterexamples for `apply`, `remove` and `rollback` (`test/setup-skills-trash-preservation.test.ts`) and the adapted SIGKILL recovery tests | 0 | All pass. On the unfixed base 24 of the 30 counterexamples failed on the defect itself (`skill_recovered` or `skill_removed` where `skill_recovery_retained` was required). |
1612
+ | #56 counterexamples (`test/setup-verify-diagnostics.test.ts`) | 0 | All 53 pass. On the unfixed base 19 failed on the defect itself (`registration_not_equivalent` for unsupported and throwing inspections, and inspection or handshake after a failed Doctor). |
1613
+
1614
+ On the documentation head that followed, `npm pack --dry-run` listed 132 files
1615
+ without `src/`, `test/`, lockfile or implementation plans, and a relative link
1616
+ and anchor check of the changed documentation found no problem.
1617
+
1618
+ Real clients without a model (Level 2), on the build of the same runtime
1619
+ sources (`dist/main.js` SHA-256 `47875d38886528ace6b242df2c6ad79d624c51e330e63c2f401576eadc449ed7`):
1620
+
1621
+ - `scripts/setup-acceptance.mjs`: 160 of 160 checks passed, exit `0`, for
1622
+ `codex:user` and `claude-code:user`, `project` and `local` in disposable
1623
+ homes. Real registrations unchanged, no remaining process, no path leak,
1624
+ build unchanged.
1625
+ - New #56 negative case, outside the harness: with the client CLI not on
1626
+ `PATH`, `--verify` reported `unsupported (unsupported)` in human and JSON
1627
+ form and `--dry-run` reported `unsupported (unsupported)`, each with exit
1628
+ `1`, for Codex `user` and Claude Code `user`. The registration was unchanged
1629
+ during these steps, and no output contained a path. The same steps on the
1630
+ built base reproduced #56 (`registration_not_equivalent`).
1631
+
1632
+ Not established by these checks: the result on macOS (only CI covers it
1633
+ there), the final pull-request head's CI matrix, a real operating-system crash
1634
+ during a skill update (the interruption tests use a checkpoint and SIGKILL,
1635
+ the counterexamples a scripted checkpoint), and any model behavior. A dry-run
1636
+ of a pending recovery can still announce a recovery that apply retains; that
1637
+ is tracked as [#60](https://github.com/plagor44-ux/pi-session-mcp/issues/60).
1638
+ Note added in Sprint 2: #60 changes this dry-run behavior; see the
1639
+ [Sprint 2 checks](#sprint-2-evidence-checks-2026-10-13). The Sprint 1 record
1640
+ above is unchanged.
1641
+
1642
+ Open gates that Sprint 1 does not close:
1643
+ - Level 3: no full ten-task cycle on Pi SDK `1.x`, and none for the profile
1644
+ intended for use.
1645
+ - Current macOS Level 2 on real hardware with both clients. CI covers macOS;
1646
+ it does not replace that.
1647
+ - Live discovery of the Codex home skill that setup installs.
1648
+ - Multi-session operation beyond two sessions, including a third concurrent
1649
+ worker and a `read-only` worker.
1650
+
1651
+ ## Sprint 2 evidence checks (2026-10-13)
1652
+
1653
+ These checks belong to [#60](https://github.com/plagor44-ux/pi-session-mcp/issues/60),
1654
+ [#62](https://github.com/plagor44-ux/pi-session-mcp/issues/62),
1655
+ [#63](https://github.com/plagor44-ux/pi-session-mcp/issues/63) and the harness
1656
+ issues [#66](https://github.com/plagor44-ux/pi-session-mcp/issues/66),
1657
+ [#67](https://github.com/plagor44-ux/pi-session-mcp/issues/67) and
1658
+ [#68](https://github.com/plagor44-ux/pi-session-mcp/issues/68). They ran on
1659
+ 2026-10-13 on branch `fix/s2-evidence`, before merge and without a release.
1660
+ The [Sprint 2 file](sprints/2026-10-13-s2-evidence.md) holds the commands,
1661
+ before-fix evidence, every gate run and the review rounds.
1662
+
1663
+ Source: base main `b145f8c`; final runtime candidate `923a393`, the last commit
1664
+ that changes `src/`, `scripts/`, `test/`, `skills/` or CI; native Linux
1665
+ (x64), Node.js `26.11.1`, npm `12.2.0`, Codex CLI `0.162.1`, Claude Code
1666
+ `2.1.296`. No provider, model or credential was used.
1667
+
1668
+ Provider-free (Level 1), on the documentation head `07f56b6` of that runtime:
1669
+ `npm ci`, typecheck, `build:cli`,
1670
+ `NODE_OPTIONS=--unhandled-rejections=strict npm test` (54 files; 1300 passed,
1671
+ 6 skipped, 0 failed; no unhandled error), build, `npm audit` and
1672
+ `npm audit --omit=dev` (0 vulnerabilities), `git diff --check` and a clean
1673
+ status all exited with `0`. On the unfixed base, the new #60 counterexamples
1674
+ failed 14 of 23 on the defect itself (`skill_recovery_planned` where
1675
+ `skill_recovery_retained` was required).
1676
+
1677
+ Pi SDK canary: the published `1.2.0` is compatible with the candidate's
1678
+ sources (typecheck and the 12 SDK-facing test files passed); the pin stays
1679
+ `1.1.0`. This is not an SDK update.
1680
+
1681
+ Real clients without a model (Level 2): `scripts/setup-acceptance.mjs` passed
1682
+ 160 of 160 checks, exit `0`, on the build that the final head also produces
1683
+ (`dist` JS tree SHA-256 `f85bf73ee8c0ddb2270d8d6040feffbc49f018d2e6ab6253fffb828654a389df`),
1684
+ for `codex:user` and `claude-code:user`, `project` and `local`; real
1685
+ registrations unchanged, no remaining process, no path leak.
1686
+
1687
+ The multi-session harness changes (#66, #67, #68) were verified with
1688
+ provider-free tests only: no live multi-session run used them yet. A live run
1689
+ belongs to Sprint 3.
1690
+
1691
+ Open gates that Sprint 2 does not close: the final-head CI of the pull request,
1692
+ a live run with the new harness bindings, and every Sprint 1 open gate above.
1693
+
1694
+ ## Sprint 3 live acceptance (2026-10-13)
1695
+
1696
+ Recorded on 2026-10-13 against main `0aae639` (package `0.8.1` plus the
1697
+ unreleased Sprint 1 and 2 changes; `dist/main.js` SHA-256 `47875d38…`), on
1698
+ native Linux x64 with Node.js `26.11.1`, Claude Code `2.1.296` and Codex CLI
1699
+ `0.162.1`. The [Sprint 3 file](sprints/2026-10-13-s3-live-usage.md) holds the
1700
+ pre-registration, every command and the review rounds. Worker profiles are
1701
+ the maintainer's intended pair, copied without its read-only external MCP
1702
+ grant: read-only OpenAI `gpt-6-luna` (`low`) and coding DeepSeek
1703
+ `deepseek-flash` (`high`).
1704
+
1705
+ Level 3 (R05, R09): one ten-task cycle with both controllers, pre-registered,
1706
+ strictly sequential. Accepted: 10 of 10 tasks reached their intended outcome
1707
+ and every gate condition held, including the coding barrier for both clients
1708
+ (in Codex's read-only sandbox too), read-only invariance, no change outside the
1709
+ approved diff, no public leak, no session or process left after a verified
1710
+ close, and Level 1 green for the release source. Every running turn was seen
1711
+ in at most one `pi_turn_get` poll. This is the first full cycle on Pi SDK `1.x`;
1712
+ it covers this provider pair on Linux only.
1713
+
1714
+ Targeted multi-session evidence (not Level 3), with
1715
+ `scripts/multi-session-acceptance.mjs`:
1716
+
1717
+ - R06, Codex `abort` (DeepSeek workers): passed, including the strict scope
1718
+ oracle that failed the v0.8.1 Codex abort run.
1719
+ - R08, `trio` (three concurrent sessions, a read-only reviewer of a frozen
1720
+ fixture, a neighbor abort): Codex passed; Claude Code failed only
1721
+ `neighborsNotRunningDuringAbort`, because the read-only review finished 6.7 s
1722
+ before the abort. The failed run stays on record
1723
+ ([#74](https://github.com/plagor44-ux/pi-session-mcp/issues/74)).
1724
+
1725
+ Real client discovery (R07): a real Codex run in an isolated home found the
1726
+ controller skill that setup had installed as a regular copy, named that copy's
1727
+ path and quoted a line that exists only in the revision under test; no manual
1728
+ link was needed.
1729
+
1730
+ Not established: macOS (R10, R11; runbook in the Sprint 3 file), other
1731
+ providers and models, the operator profiles' external MCP grant, larger tasks,
1732
+ more than three concurrent sessions, and the `trio` timing with Claude Code as
1733
+ controller.