pi-session-mcp 0.14.0 → 0.14.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.pi-session-mcp-cli/writer-boundary.js +2 -1
- package/.pi-session-mcp-cli/writer-lifecycle.js +99 -18
- package/.pi-session-mcp-cli/writer-models-store.js +64 -0
- package/.pi-session-mcp-cli/writer-tree-removal.js +75 -0
- package/CHANGELOG.md +95 -0
- package/README.md +1 -1
- package/dist/capabilities.d.ts +13 -0
- package/dist/capabilities.js +17 -13
- package/dist/model-catalog.d.ts +18 -5
- package/dist/model-catalog.js +8 -5
- package/dist/sdk-pi-adapter.d.ts +6 -1
- package/dist/sdk-pi-adapter.js +35 -7
- package/dist/writer-boundary.d.ts +1 -1
- package/dist/writer-boundary.js +2 -1
- package/dist/writer-guard.js +1 -1
- package/dist/writer-launch.d.ts +2 -0
- package/dist/writer-launch.js +3 -0
- package/dist/writer-lifecycle.d.ts +8 -0
- package/dist/writer-lifecycle.js +99 -18
- package/dist/writer-models-store.d.ts +16 -0
- package/dist/writer-models-store.js +64 -0
- package/dist/writer-relay.js +12 -1
- package/dist/writer-tree-removal.d.ts +16 -0
- package/dist/writer-tree-removal.js +75 -0
- package/docs/acceptance.md +314 -0
- package/docs/adr/0012-leased-writer-pool.md +10 -6
- package/docs/adr/0013-hardened-read-only-profiles.md +30 -0
- package/docs/adr/0014-profile-probe-and-model-catalog.md +1 -1
- package/docs/doctor-design.md +1 -1
- package/docs/execution-modes.md +66 -10
- package/docs/installation.md +9 -0
- package/docs/isolation-setup.md +12 -2
- package/docs/roadmap.md +21 -0
- package/docs/sprints/2026-10-24-s8-writer-migration.md +5 -3
- package/docs/sprints/2026-10-29-s12-audit-fixes.md +174 -0
- package/docs/sprints/2026-10-30-s13-index-only-work.md +199 -0
- package/docs/threat-model.md +10 -1
- package/docs/tool-contracts.md +1 -1
- package/package.json +1 -1
- package/skills/pi-session-orchestration/SKILL.md +1 -1
- package/skills/pi-session-profiles/SKILL.md +5 -1
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
# Sprint 12: audit findings F1–F3
|
|
2
|
+
|
|
3
|
+
Planning basis: main `9d9cf8ca49e6e34dc16be6846b9324ad26ad92b9` (merge of PR
|
|
4
|
+
#191), published 0.14.0, 2026-10-29. Entry: an external audit of that commit
|
|
5
|
+
reported three defects with reproductions. This file plans the work and records
|
|
6
|
+
it as it lands; it claims nothing that its progress log does not state with
|
|
7
|
+
evidence.
|
|
8
|
+
|
|
9
|
+
Branch: `fix/s12-audit-findings`, one pull request, no release.
|
|
10
|
+
|
|
11
|
+
## Preflight (2026-10-29)
|
|
12
|
+
|
|
13
|
+
- main and `origin/main` at `9d9cf8c`; open issues #79, #120, #144; no open
|
|
14
|
+
pull requests; clean operator checkout; no other worktree in use.
|
|
15
|
+
- Doctor: no errors; only the known `workspace_gitfile` and
|
|
16
|
+
`workspace_mode_unset` warnings of the host worktree aliases.
|
|
17
|
+
- Level 1 on `9d9cf8c` in a clean detached worktree on the workstation:
|
|
18
|
+
`npm ci`, `npm run typecheck`, `npm run build:cli`,
|
|
19
|
+
`NODE_OPTIONS=--unhandled-rejections=strict npm test` (527 files, 4005
|
|
20
|
+
passed, 14 skipped, 0 failed, no unhandled error) and `npm run build` all exit
|
|
21
|
+
0. The audit's cloud run of the same commit reported 70 failed tests and four
|
|
22
|
+
unhandled errors; they do not reproduce here, so they are not attributed to
|
|
23
|
+
the product. The audit environment is not available to separate them further.
|
|
24
|
+
- Both `pi-session-mcp` writers were at `baseline` on an older main and were
|
|
25
|
+
reset without `--discard` to `9d9cf8c` (`writer_reset`).
|
|
26
|
+
|
|
27
|
+
## Findings, re-checked on `9d9cf8c`
|
|
28
|
+
|
|
29
|
+
| Id | Issue | Reproduction by the controller | Result |
|
|
30
|
+
| --- | --- | --- | --- |
|
|
31
|
+
| F1 | [#192](https://github.com/plagor44-ux/pi-session-mcp/issues/192) | Synthetic workspace whose `AGENTS.md` links to an outside marker file; `PI_CODING_AGENT_DIR` isolated; faux provider | Confined `read` refuses; `getAgentsFiles()` contains the marker; the real `SdkPiSessionAdapter` sends it as `project_instructions` to the faux provider. Confirmed. |
|
|
32
|
+
| F2 | [#193](https://github.com/plagor44-ux/pi-session-mcp/issues/193) | Real Git; boundary scripts run by an injected runner | Detached `HEAD` commit, clean tree: remove before collect `writer_uncollected`; collect `nothing_to_collect`, 0 refs, digest stored; commit absent from the operator checkout; finish `writer_reset`; remove `writer_removed`. Feature-branch counterproof exports the commit. Confirmed; not yet a Podman result. |
|
|
33
|
+
| F3 | [#194](https://github.com/plagor44-ux/pi-session-mcp/issues/194) | Real relay over stdio, fake writer server fixture | Identical profiles admitted; model drift refused with `settingsChanged`; host `skills: ["pi-session-implementation"]` against inner `skills: []` admitted. Confirmed. |
|
|
34
|
+
|
|
35
|
+
## Decisions taken at planning
|
|
36
|
+
|
|
37
|
+
- F1: for read-only profiles every resource loader keeps only context files
|
|
38
|
+
whose real path lies inside the workspace's real path. Context files of
|
|
39
|
+
ancestor directories above the workspace, including a main repository above a
|
|
40
|
+
linked worktree, are no longer loaded for read-only profiles: they are outside
|
|
41
|
+
the read roots of ADR 0013. Coding profiles keep the SDK's behaviour.
|
|
42
|
+
- F2: smallest fix inside the existing collection contract; the export name for
|
|
43
|
+
a detached `HEAD` is a documented behaviour addition, no new public code.
|
|
44
|
+
- F3: the relay compares every public capability field a writer reports, with
|
|
45
|
+
set semantics for skills, extensions and granted extension tools.
|
|
46
|
+
- #120: still waiting for an SDK release (see below); no override, no
|
|
47
|
+
`npm audit fix --force`.
|
|
48
|
+
- No release on this branch.
|
|
49
|
+
|
|
50
|
+
## Roles and routing
|
|
51
|
+
|
|
52
|
+
`pi_capabilities_get` and `--list-models` on 2026-10-29 settle which requested
|
|
53
|
+
models exist as authenticated profiles:
|
|
54
|
+
|
|
55
|
+
| Requested | Profile used | Status |
|
|
56
|
+
| --- | --- | --- |
|
|
57
|
+
| GPT 6.1 Sol | `code` (openai `gpt-6.1-sol`) | available |
|
|
58
|
+
| GPT 6.1 Terra | none | unavailable: the catalog lists no `gpt-6.1-terra`; not substituted with another version |
|
|
59
|
+
| DeepSeek | `code-deepseek` (`deepseek-flash`) | available |
|
|
60
|
+
| GLM 5.3 | `review-glm`, `code-glm` (`zai-glm-5-3`) | available |
|
|
61
|
+
| Mistral Large 4 | `code-mistral` (`mistral-large-4`) | available |
|
|
62
|
+
| Sonnet 5.5 | no profile; provider `anthropic` authenticated | added only in an expendable test configuration (acceptance item D) |
|
|
63
|
+
| Grok 4.7 | `review-grok` (xai `grok-4.7`) | available: the R2 turn completed |
|
|
64
|
+
|
|
65
|
+
agy (Antigravity CLI, Gemini) plans the work packages, dependencies and review
|
|
66
|
+
routing; Pi workers implement and review; the controller integrates, verifies
|
|
67
|
+
and is the only editor of this file, the roadmap, `docs/acceptance.md` and the
|
|
68
|
+
CHANGELOG.
|
|
69
|
+
|
|
70
|
+
## Tasks
|
|
71
|
+
|
|
72
|
+
| Id | Task | Route | Change area |
|
|
73
|
+
| --- | --- | --- | --- |
|
|
74
|
+
| P1 | Work packages, dependencies, review routing | agy | none |
|
|
75
|
+
| P2 | Independent regression test plan | `review-glm` | none |
|
|
76
|
+
| T1 | F1, #192 | `pi-session-mcp` writer, `code` | `src/sdk-pi-adapter.ts`, `src/confined-tools.ts`, tests |
|
|
77
|
+
| T2 | F2, #193 | `pi-session-mcp` writer, `code-mistral` (agy's fallback for the unavailable Terra) | `src/writer-lifecycle.ts`, tests |
|
|
78
|
+
| T3 | F3, #194 | `pi-session-mcp` writer, `code-deepseek` | `src/writer-relay.ts`, `src/capabilities.ts`, tests, relay fixture |
|
|
79
|
+
| R1 | Security review of T1 and T3 | Sonnet 5.5, read-only | none |
|
|
80
|
+
| R2 | Adversarial review of T2 and the Git lifecycle checks | `review-grok` | none |
|
|
81
|
+
| D1 | Documentation and issue reconciliation (#120, ADR 0014 status, Sprint 8 status, #79, #144) | `pi-session-mcp` writer, `code-mistral`; controller as editor | `docs/`, `skills/pi-session-orchestration/SKILL.md` |
|
|
82
|
+
| A | Live acceptance A–E | controller | evaluation record |
|
|
83
|
+
|
|
84
|
+
## Progress log
|
|
85
|
+
|
|
86
|
+
Recorded as work lands on the branch.
|
|
87
|
+
|
|
88
|
+
- 2026-10-29: issues #192, #193 and #194 filed; this plan written before any
|
|
89
|
+
implementation.
|
|
90
|
+
- P1: agy (`gemini-3.8-flash-high`, plan mode) proposed the packages,
|
|
91
|
+
`code-mistral` as the F2 author in place of Terra, Sonnet for R1 and Grok
|
|
92
|
+
with a fallback for R2, and at most three review rounds. Adopted.
|
|
93
|
+
- P2: `review-glm` wrote the regression test plan; its edge cases (absent
|
|
94
|
+
against empty set fields, real-Git collection, a Podman case) went into the
|
|
95
|
+
task prompts.
|
|
96
|
+
- T3 (`code-deepseek`, writer w2): collected as
|
|
97
|
+
`writer-pi-session-mcp-w2/fix/f3-relay-profile-drift`; the controller ran the
|
|
98
|
+
new tests against the old source (7 fail) and the fix (all pass); integrated
|
|
99
|
+
as `230e60e`, writer finished (`writer_reset`).
|
|
100
|
+
- T1 (`code`, writer w1): collected as
|
|
101
|
+
`writer-pi-session-mcp-w1/fix/f1-context-files`; new tests against the old
|
|
102
|
+
source 9 of 12 fail, with the fix 148 of 148 pass; integrated as `a0a7d87`,
|
|
103
|
+
writer finished. The container-writer suite showed only the eight known
|
|
104
|
+
lock and hook timeouts (`override-lock`, `skill-customize-concurrency`,
|
|
105
|
+
`wake-hook`).
|
|
106
|
+
- R1 (Sonnet 5.5, read-only, through the test configuration of item D):
|
|
107
|
+
`NON_BLOCKING_ONLY`. Fixed by the controller: kept context files are read
|
|
108
|
+
again from their verified real path (`79e8a7a`), the set comparison is
|
|
109
|
+
symmetric with a duplicated-entry test (`3e14279`); the shadowing case is
|
|
110
|
+
covered by a test and documented. Not changed: synchronous `realpathSync` in
|
|
111
|
+
the loader override (the SDK hook is synchronous) and the trust in the
|
|
112
|
+
writer's own capability report, which is the boundary the relay already
|
|
113
|
+
assumes.
|
|
114
|
+
- T2 (`code-mistral`, writer w2): collected as
|
|
115
|
+
`writer-pi-session-mcp-w2/fix/f2-detached-collect`; the new real-Git tests
|
|
116
|
+
against the old source 3 of 8 fail, with the fix 8 of 8 pass, and the F2
|
|
117
|
+
reproduction now gets `writer_collected`; integrated as `236ca28`, writer
|
|
118
|
+
finished. The controller added the Podman case (`6ee7add`): with real
|
|
119
|
+
rootless Podman and the pinned Node image it passes, against the old source
|
|
120
|
+
it fails.
|
|
121
|
+
- D1 (`code-mistral`, writer w1): collected as
|
|
122
|
+
`writer-pi-session-mcp-w1/docs/s12-reconcile`; split by issue into
|
|
123
|
+
`f5a9712`, `58e0e7b`, `17845ff` and `ebe3c52`. Controller edits: the
|
|
124
|
+
shadowing and re-read rule in the ADR 0013 amendment, and the relay wording
|
|
125
|
+
(a mismatch counts as `settingsChanged`; `writer_unavailable` with
|
|
126
|
+
`none_admitted` only when no writer is admitted). Writer finished.
|
|
127
|
+
- R2 (`review-grok`, Grok 4.7, read-only): `NON_BLOCKING_ONLY`. Verified by
|
|
128
|
+
the controller and fixed in `1dfe4da`: a derived `-wip` or `-detached` name
|
|
129
|
+
that conflicts with an exported branch path aborted the export under
|
|
130
|
+
`set -eu` (reproduced with a branch `main-detached/topic`); a worker-made
|
|
131
|
+
`git replace --graft` made an unexported detached commit look reachable
|
|
132
|
+
(Grok's variant with a plain replacement did not reproduce, the graft did);
|
|
133
|
+
the reachability gate now also runs on `nothing_to_collect`. Recorded as
|
|
134
|
+
limits, not changed: an index-only staged change that the worktree reverted
|
|
135
|
+
(pre-existing; fixed later in
|
|
136
|
+
[#200](https://github.com/plagor44-ux/pi-session-mcp/issues/200), see
|
|
137
|
+
[Sprint 13](2026-10-30-s13-index-only-work.md)), a base name of 192 to 200 characters (fails closed), and a
|
|
138
|
+
runner that reports a fetch it did not do (outside the threat model).
|
|
139
|
+
- Final integration review (Sonnet 5.5, read-only, on `896e29d`):
|
|
140
|
+
`NON_BLOCKING_ONLY`. Fixed: the in-boundary guard probe now ignores replace
|
|
141
|
+
refs too (`9426682`, with a test that fails without it), the BOM pattern is an
|
|
142
|
+
escape (`5d9f15b`), and execution modes names the pruned-base case of the
|
|
143
|
+
digest gate. Not changed: `inspectWork.head` stays optional because required
|
|
144
|
+
would break type-checked mocks outside this change.
|
|
145
|
+
- Acceptance: see
|
|
146
|
+
[Sprint 12 candidate acceptance](../acceptance.md#sprint-12-candidate-acceptance-2026-10-30).
|
|
147
|
+
Level 1 green on `9426682`; Level 2 green on the packed `896e29d`; live items
|
|
148
|
+
B, C and D passed on expendable configurations and were rolled back; the
|
|
149
|
+
Level 3 ten-task cycle 2 passed (10 of 10) after cycle 1 failed on fixture and
|
|
150
|
+
harness design (5 of 10, kept unchanged).
|
|
151
|
+
|
|
152
|
+
## Results
|
|
153
|
+
|
|
154
|
+
| Finding | Status | Commits | Evidence |
|
|
155
|
+
| --- | --- | --- | --- |
|
|
156
|
+
| F1 #192 | fixed | `a0a7d87`, `79e8a7a`, `5d9f15b`; docs `f5a9712` | `test/read-only-context-files.test.ts` (fails on `9d9cf8c`), faux-provider context check, R1 and final review |
|
|
157
|
+
| F2 #193 | fixed | `236ca28`, `6ee7add`, `1dfe4da`, `9426682`; docs `58e0e7b`, `896e29d` | real-Git collect tests, Podman test, guard test (each fails on the source before), R2 and final review |
|
|
158
|
+
| F3 #194 | fixed | `230e60e`, `3e14279`; docs `17845ff` | `test/writer-relay.test.ts` drift tests (fail on `9d9cf8c`), live refusal with `settingsChanged`, R1 and final review |
|
|
159
|
+
|
|
160
|
+
Remaining risk: #120 is unchanged. `npm audit --omit=dev` on 2026-10-29 still
|
|
161
|
+
reports `undici` 8.10.2 (high) through `@earendil-works/pi-coding-agent` 1.4.0
|
|
162
|
+
(moderate), eight advisories fixed in `undici` >= 8.12.2; the only offered fix
|
|
163
|
+
is a semver-major downgrade. No override and no `npm audit fix --force`.
|
|
164
|
+
|
|
165
|
+
Kept open: #79 (Sprint 8 steps 5 to 7 are not done), #120 and #144 (no macOS
|
|
166
|
+
claim). The sandbox resource limits of ADR 0013 are the follow-up issue
|
|
167
|
+
[#195](https://github.com/plagor44-ux/pi-session-mcp/issues/195), not part of
|
|
168
|
+
this sprint.
|
|
169
|
+
|
|
170
|
+
Cleanup: all controller Pi sessions closed; both `pi-session-mcp` writers
|
|
171
|
+
finished (`writer_reset`); the test writer `s12-probe-w1` removed; expendable
|
|
172
|
+
configurations, the synthetic repository, the pack prefix and the
|
|
173
|
+
controller's worktrees removed.
|
|
174
|
+
|
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
# Sprint 13: work that exists only in the writer index
|
|
2
|
+
|
|
3
|
+
Planning basis: main `7752d3f1555d19fed06f43c0e046da07017a3320` (merge of PR
|
|
4
|
+
#197), published 0.14.1, 2026-10-30. Entry: issue
|
|
5
|
+
[#200](https://github.com/plagor44-ux/pi-session-mcp/issues/200), recorded as
|
|
6
|
+
an unchanged limit in [Sprint 12](2026-10-29-s12-audit-fixes.md), and the
|
|
7
|
+
published-release Level 2 of 0.14.1 that was still open. This file records the
|
|
8
|
+
work as it landed; it claims nothing that its progress log does not state with
|
|
9
|
+
evidence.
|
|
10
|
+
|
|
11
|
+
Branch: `fix/writer-index-only-work`, one pull request, no release. Merge,
|
|
12
|
+
tag, npm publication and the productive rollout are maintainer decisions.
|
|
13
|
+
|
|
14
|
+
## Preflight (2026-10-30)
|
|
15
|
+
|
|
16
|
+
- main and `origin/main` at `7752d3f`; open issues #79, #120, #144, #195,
|
|
17
|
+
#198, #199, #200; open pull request #201 (#198, #199).
|
|
18
|
+
- Both machines run `0.14.1`; on the workstation both client targets verified
|
|
19
|
+
and all 18 writers accepted earlier the same day.
|
|
20
|
+
- Reproduced on `7752d3f` with the real-Git harness: for a clone whose HEAD and
|
|
21
|
+
worktree hold `base` and whose index holds a staged blob (`git status` `MM`),
|
|
22
|
+
`inspectWork` reported `baseline: true, dirty: false`, collect reported
|
|
23
|
+
`nothing_to_collect`, and remove and finish without `--discard` destroyed
|
|
24
|
+
the staged blob.
|
|
25
|
+
|
|
26
|
+
## Decisions
|
|
27
|
+
|
|
28
|
+
- Inspection computes the original index tree with `write-tree` on a second
|
|
29
|
+
temporary copy of the index, before `git add -A` builds the worktree tree.
|
|
30
|
+
The clone stays read-only and its index is never written.
|
|
31
|
+
- `baseline` additionally requires the index tree to equal the base tree;
|
|
32
|
+
`dirty` is set when the index tree or the worktree tree differs from HEAD's.
|
|
33
|
+
- The collection digest is computed over a version tag and the inspection
|
|
34
|
+
output, which now includes the index tree. A digest recorded by 0.14.1 or
|
|
35
|
+
earlier can never match, so it never authorizes cleanup.
|
|
36
|
+
- Collection exports a staged tree that differs from both HEAD's tree and the
|
|
37
|
+
worktree tree as an extra `<branch>-index` commit, with the name rules of the
|
|
38
|
+
existing `-wip` export, rather than refusing: a refused writer could not be
|
|
39
|
+
admitted to a session or collected, so its work would only be recoverable by
|
|
40
|
+
`--discard`. The `-wip` and `-detached` exports are unchanged (#193).
|
|
41
|
+
- A digest is recorded only when the index and worktree tree objects exist in
|
|
42
|
+
the operator checkout, in addition to the #193 commit gate.
|
|
43
|
+
- An index that cannot be evaluated, such as an unmerged conflict, makes
|
|
44
|
+
inspection and collection fail closed (`writer_inspect_failed`,
|
|
45
|
+
`writer_collect_failed`); no cleanup without `--discard` proceeds.
|
|
46
|
+
- Pool admission needs no change: the in-boundary guard probe runs
|
|
47
|
+
`git status --porcelain=v1 -uall`, which reports staged changes. Doctor's
|
|
48
|
+
`writer_dirty` stays an offline ref-only hint and never authorizes cleanup;
|
|
49
|
+
its documentation now says so.
|
|
50
|
+
- #120: still waiting for an SDK release; no override, no
|
|
51
|
+
`npm audit fix --force`.
|
|
52
|
+
|
|
53
|
+
## Roles and routing
|
|
54
|
+
|
|
55
|
+
`pi_capabilities_get` on 2026-10-30 settles which requested models were
|
|
56
|
+
available as profiles:
|
|
57
|
+
|
|
58
|
+
| Requested | Profile used | Status |
|
|
59
|
+
| --- | --- | --- |
|
|
60
|
+
| GPT 6.1 Terra (implementation) | `code` (openai `gpt-6.1-sol`) | Terra has no profile: the installed 0.14.1 catalog does not see Pi's persisted model overlay (#199, fixed in #201, unreleased); the requested fallback Sol was used |
|
|
61
|
+
| Sol (call-path analysis) | done by the controller | the call paths were short (one function and its five callers) |
|
|
62
|
+
| DeepSeek (real-Git fixtures) | `code-deepseek` (`deepseek-flash`) | available |
|
|
63
|
+
| GLM 5.3 (test plan, counter-checks) | `review-glm` (`zai-glm-5-3`) | available |
|
|
64
|
+
| Grok 4.7 (adversarial review) | `review-glm` | not used: xAI requests fail with HTTP 402 since 2026-10-25 |
|
|
65
|
+
| Mistral Large 4 (release evidence, docs) | controller with a Claude runner subagent | the evidence needed only local commands; the controller is the only docs editor |
|
|
66
|
+
| Sonnet 5.5 (final integration review) | a read-only Claude Code subagent on `claude-sonnet-5-5` | used instead of `review-sonnet`, because a read-only Pi worker reads only the workspace on `main`, not the branch worktree |
|
|
67
|
+
|
|
68
|
+
agy (Antigravity CLI, Gemini) was not used: the controller's planning call was
|
|
69
|
+
declined in this session, so the controller planned the packages and the
|
|
70
|
+
review route. At most two coding workers ran at once; `src/writer-lifecycle.ts`
|
|
71
|
+
had one implementer, and `test/writer-collect-real-git.test.ts` one author.
|
|
72
|
+
|
|
73
|
+
## Tasks
|
|
74
|
+
|
|
75
|
+
| Id | Task | Route | Change area |
|
|
76
|
+
| --- | --- | --- | --- |
|
|
77
|
+
| P1 | Design counter-check and regression test plan | `review-glm` | none |
|
|
78
|
+
| T1 | Fix in inspection, collection and the digest | `pi-session-mcp` writer, `code` | `src/writer-lifecycle.ts`, unit tests and fakes |
|
|
79
|
+
| T2 | Real-Git regression matrix | `pi-session-mcp` writer, `code-deepseek` | `test/writer-collect-real-git.test.ts` |
|
|
80
|
+
| R1 | Adversarial review of the integrated diff | `review-glm` | none |
|
|
81
|
+
| R2 | Final integration review | Sonnet 5.5 subagent, read-only | none |
|
|
82
|
+
| A | Published-release Level 2 of 0.14.1, candidate Level 1 and 2, native Podman | controller, runner subagent | records |
|
|
83
|
+
|
|
84
|
+
## Progress log
|
|
85
|
+
|
|
86
|
+
- P1 (`review-glm`, 1m32s): `NON_BLOCKING_ONLY`. Its main finding, that
|
|
87
|
+
`write-tree` fails on intent-to-add entries, did not reproduce: Git 2.56
|
|
88
|
+
skips such entries, so the case shows as dirty through the worktree tree. It
|
|
89
|
+
is now pinned by a test. Skip-worktree and assume-unchanged entries stay
|
|
90
|
+
invisible, as for Git itself (recorded as a limit).
|
|
91
|
+
- T1 (`code`, writer w1, 4m56s): `DONE_WITH_CONCERNS`; the concerns were the
|
|
92
|
+
ten known lock, hook and live-token timeouts of the container suite
|
|
93
|
+
(`override-lock`, `skill-customize-concurrency`, `token-live`,
|
|
94
|
+
`wake-hook`). Collected as `writer-pi-session-mcp-w1/fix/200-index-only-work`
|
|
95
|
+
and integrated as `9b5c72c`; writer finished (`writer_reset`).
|
|
96
|
+
- T2 (`code-deepseek`, writer w2, 5m00s): `DONE`, 7 of its 10 new tests fail on
|
|
97
|
+
the base for the bug, 3 are guards. Collected as
|
|
98
|
+
`writer-pi-session-mcp-w2/test/200-index-only-real-git` and integrated as
|
|
99
|
+
`4acb4bf`; writer finished (`writer_reset`).
|
|
100
|
+
- Controller: against the source of `7752d3f` the real-Git file reports 7
|
|
101
|
+
failed and 13 passed; with the fix, 21 of 21 pass. Added the intent-to-add
|
|
102
|
+
test (`1aff988`) and a native Podman case of the exact `MM` state
|
|
103
|
+
(`1e1e694`), which fails on the base source (`baseline: true`) and passes
|
|
104
|
+
with the fix in the real container.
|
|
105
|
+
- R1 (`review-glm`, 4m59s, on the integrated diff): `NON_BLOCKING_ONLY`, no
|
|
106
|
+
finding in the new lines.
|
|
107
|
+
- Confirmed and filed as
|
|
108
|
+
[#202](https://github.com/plagor44-ux/pi-session-mcp/issues/202): a stash
|
|
109
|
+
entry is not exported, yet collection records a digest and remove without
|
|
110
|
+
`--discard` then deletes it; reproduced by the controller with the real-Git
|
|
111
|
+
harness (`nothing_to_collect`, `writer_removed`, blob absent). Pre-existing.
|
|
112
|
+
- Not reproduced: an alias that shadows a builtin Git command; Git ignores
|
|
113
|
+
such aliases. A clean filter configured by the worker runs only inside the
|
|
114
|
+
throwaway boundary container, and the worker can already destroy its own
|
|
115
|
+
clone, so it adds no loss beyond the threat model.
|
|
116
|
+
- Fail closed, recorded as limits: a clone configured for a split index makes
|
|
117
|
+
`add -A` fail on the read-only clone; a worker branch named
|
|
118
|
+
`<branch>-index` makes the export refuse with `ref_name_refused`.
|
|
119
|
+
- R2 (Sonnet 5.5, read-only, on the whole branch at `4670264`):
|
|
120
|
+
`NON_BLOCKING_ONLY`, no code defect. Fixed by the controller:
|
|
121
|
+
- The test for an index-only change after a collection also changed the
|
|
122
|
+
worktree, so it did not pin that the digest covers the index tree. It now
|
|
123
|
+
stages a second blob with `update-index --cacheinfo` and leaves the
|
|
124
|
+
worktree unchanged; with a digest that omits the index line it fails, with
|
|
125
|
+
the fix it passes.
|
|
126
|
+
- A test for a taken and a path-conflicting `<branch>-index` name.
|
|
127
|
+
- The code table in execution modes, the `pi-session-profiles` skill (Doctor
|
|
128
|
+
and the `--collect` dry run do not prove a clone clean; `--remove` without
|
|
129
|
+
`--discard` does), the unmerged-index consequence, the merge note and a
|
|
130
|
+
wrong direction in the acceptance record.
|
|
131
|
+
- Not changed: the verbatim issue reproduction stays as written although the
|
|
132
|
+
stricter collect, finish and remove test covers more; Doctor's
|
|
133
|
+
`writer_dirty` stays a documented offline ref-only hint (a maintainer
|
|
134
|
+
call against the issue's criterion 3).
|
|
135
|
+
|
|
136
|
+
## Checks
|
|
137
|
+
|
|
138
|
+
- Full suite on `1aff988` (the integrated fix and the intent-to-add test),
|
|
139
|
+
with `NODE_OPTIONS=--unhandled-rejections=strict`: 141 files, 4061 passed,
|
|
140
|
+
14 skipped, exit 0.
|
|
141
|
+
- Native Podman tests: `test/writer-lifecycle.podman.test.ts` 8 of 8 and
|
|
142
|
+
`test/writer-boundary.podman.test.ts` 1 of 1, none skipped, on `1e1e694`.
|
|
143
|
+
- Candidate Level 1, working-tree and packed-tarball Level 2 on `1e1e694`: see
|
|
144
|
+
[Issue #200 candidate acceptance](../acceptance.md#issue-200-candidate-acceptance-2026-10-30).
|
|
145
|
+
- Published-release Level 2 of 0.14.1: see
|
|
146
|
+
[v0.14.1 post-release evidence](../acceptance.md#v0141-post-release-evidence).
|
|
147
|
+
|
|
148
|
+
## Remaining risk and limits
|
|
149
|
+
|
|
150
|
+
- Work held only in a stash entry or in refs outside `refs/heads` is still lost
|
|
151
|
+
after a collection (#202).
|
|
152
|
+
- Skip-worktree and assume-unchanged entries hide worktree changes from Git and
|
|
153
|
+
therefore from inspection.
|
|
154
|
+
- The digest version means that a writer collected under 0.14.1 but not yet
|
|
155
|
+
reset must be collected once more before finish, reset or remove. Writers at
|
|
156
|
+
their baseline need no digest and are unaffected.
|
|
157
|
+
- The 18 workstation writers removed on 2026-10-30 for a profile change were
|
|
158
|
+
judged by the 0.14.1 inspection; whether any of them held index-only work
|
|
159
|
+
cannot be established afterwards.
|
|
160
|
+
- #120 is unchanged: Pi SDK 1.4.0 is still the newest release and pins `undici`
|
|
161
|
+
8.10.2.
|
|
162
|
+
|
|
163
|
+
## Rollout plan (maintainer decision)
|
|
164
|
+
|
|
165
|
+
After the maintainer has merged and published a release with this change:
|
|
166
|
+
|
|
167
|
+
1. Close the coding sessions on all writers. For every writer that is not at
|
|
168
|
+
its baseline, run `pi-session-mcp-setup --writer <name> --collect` as a dry
|
|
169
|
+
run and resolve uncollected work before anything else.
|
|
170
|
+
2. Upgrade each machine as [Installation](../installation.md#container-writers)
|
|
171
|
+
describes: client targets `--remove`, `npm install -g pi-session-mcp@<new>`,
|
|
172
|
+
then for every container repository the provisioning command with its full
|
|
173
|
+
settings and `--apply`, then client targets `--apply` and `--verify`,
|
|
174
|
+
`--writer <name> --verify` for every writer, and Doctor.
|
|
175
|
+
3. Collect every writer that holds collected but not yet reset work once more,
|
|
176
|
+
because its 0.14.1 digest no longer authorizes cleanup.
|
|
177
|
+
4. Second machine: the Anthropic profiles still need the maintainer's login
|
|
178
|
+
there. Until #198 (in #201) is released, removing a writer with
|
|
179
|
+
`--cache go` needs the documented `chmod -R u+w` workaround.
|
|
180
|
+
|
|
181
|
+
Rollback: a productive installation is not downgraded without the maintainer.
|
|
182
|
+
If the maintainer decides to return to `0.14.1`, the same steps install it; a
|
|
183
|
+
digest recorded by the new version does not match `0.14.1` either, so such a
|
|
184
|
+
writer has to be collected again, which fails safe. The source change itself is
|
|
185
|
+
reverted by reverting its commits.
|
|
186
|
+
|
|
187
|
+
Merge order with #201: both change `src/writer-lifecycle.ts` (#201 replaces the
|
|
188
|
+
recursive removal in `removeWriter`), `CHANGELOG.md` (`Unreleased`) and
|
|
189
|
+
`docs/execution-modes.md`, and #201's `test/writer-models-store.test.ts` fakes
|
|
190
|
+
the old three-tree inspection output. #201 merged first; the merge of `main`
|
|
191
|
+
into this branch keeps both `Unreleased` entries and adds the index tree line
|
|
192
|
+
to that fake.
|
|
193
|
+
|
|
194
|
+
Unmerged index: a writer whose index holds a merge conflict can no longer be
|
|
195
|
+
collected, and pool admission refuses it because it is not at its baseline; its
|
|
196
|
+
work stays in the clone until the operator explicitly decides on `--discard`.
|
|
197
|
+
Before this change `git add -A` collected such a state as `-wip` with conflict
|
|
198
|
+
markers. Exporting the worktree in that case without recording a digest would
|
|
199
|
+
keep it recoverable; that is a possible follow-up, not part of this change.
|
package/docs/threat-model.md
CHANGED
|
@@ -16,7 +16,16 @@ Pi Session MCP trusts the local process that launches and speaks MCP over inheri
|
|
|
16
16
|
(arguments the SDK would rewrite, such as a leading `@` or `~`, a `file:`
|
|
17
17
|
URL, Unicode spaces or NUL, are refused so both resolve the same path), and
|
|
18
18
|
the `*Operations` hooks of `read`, `grep` and `ls` check the absolute path
|
|
19
|
-
again. `rg` and `fd` do not follow symlinks during traversal.
|
|
19
|
+
again. `rg` and `fd` do not follow symlinks during traversal. For read-only
|
|
20
|
+
profiles the resource loader likewise keeps only Pi context files
|
|
21
|
+
(`AGENTS.override.md`, `AGENTS.md`, `AGENTS.MD`, `CLAUDE.md`, `CLAUDE.MD`)
|
|
22
|
+
whose real path lies inside the workspace's real path, on every reload and
|
|
23
|
+
before the first provider request: a symlinked context file that resolves
|
|
24
|
+
outside the workspace, a dangling one and the context files of ancestor
|
|
25
|
+
directories above the workspace (including a main repository above a linked
|
|
26
|
+
worktree) are not loaded, while the linked worktree's own file inside the
|
|
27
|
+
workspace is. Coding profiles keep the SDK behaviour (the working directory
|
|
28
|
+
and its ancestors). A profile with
|
|
20
29
|
`shell: "sandboxed"` also gets `bash`, run as `/usr/bin/bwrap` (fixed path,
|
|
21
30
|
root-owned and not group- or world-writable, no `PATH` lookup) with
|
|
22
31
|
`--unshare-all`, `--disable-userns`, a cleared environment, no network, `/usr`
|
package/docs/tool-contracts.md
CHANGED
|
@@ -40,7 +40,7 @@ records name the package version and the build they ran on, see
|
|
|
40
40
|
```json
|
|
41
41
|
{
|
|
42
42
|
"ok": true,
|
|
43
|
-
"server": { "name": "pi-session-mcp", "version": "0.14.
|
|
43
|
+
"server": { "name": "pi-session-mcp", "version": "0.14.2" },
|
|
44
44
|
"configuration": {
|
|
45
45
|
"fingerprint": "sha256:0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef",
|
|
46
46
|
"reloadPolicy": "restart-required"
|
package/package.json
CHANGED
|
@@ -122,7 +122,7 @@ You integrate. Workers never integrate each other's changes. Resolve conflicts b
|
|
|
122
122
|
|
|
123
123
|
After taking over the result and closing its coding session, before the next task:
|
|
124
124
|
|
|
125
|
-
1. Run `pi-session-mcp-setup --writer <name> --collect --apply` from the operator environment. Review the collected refs in the operator's checkout: `refs/remotes/writer-<name>/<branch>`, with uncommitted work as `<branch>-wip
|
|
125
|
+
1. Run `pi-session-mcp-setup --writer <name> --collect --apply` from the operator environment. Review the collected refs in the operator's checkout: `refs/remotes/writer-<name>/<branch>`, with uncommitted work as `<branch>-wip`, staged work that differs from both HEAD and the worktree as `<branch>-index`, a clean detached HEAD as `<base>-detached`, and each stash entry as `<base>-stash-<n>`. They are untrusted until reviewed. Integrate only verified work yourself.
|
|
126
126
|
2. Run `pi-session-mcp-setup --writer <name> --finish --apply`. It collects again, then resets a persistent writer or recreates an ephemeral writer. Do not reuse it until this succeeds. A refused branch name makes collection incomplete and finish stops: ask the operator to resolve it by renaming inside the boundary or explicitly discarding with `--reset --discard --apply`. Finish returns it to the workspace default base. No reconnect is needed after reset, finish or recreate. A setup operation on a writer held by a session fails with `writer_busy` after a short wait; close the session and allow launcher cleanup to finish.
|
|
127
127
|
3. A coding start needs the writer's clone at its baseline, even after a complete collection; otherwise it fails with the controller-action code for uncollected work in [references/start-errors.md](references/start-errors.md). To let a fresh session continue from collected work, for example after a failed turn or for a review fix round, create a local branch at the collected ref and run `pi-session-mcp-setup --writer <name> --reset --base <branch> --apply`, then call `pi_session_start` on `pi-session-mcp` with the coding profile and `base: "<branch>"`. Read `writer` from that result for collection. Default starts cannot use a writer moved to the fix branch.
|
|
128
128
|
4. Never run Git inside the writer's clone as the host user, including direct fetch from that clone. Use setup's bundle collection and inspect the imported refs in your own checkout. Never discard unreviewed work just to admit the next task.
|
|
@@ -84,8 +84,12 @@ For each container repository whose selected profiles or settings change,
|
|
|
84
84
|
determine every writer's state using the documented read-only checks:
|
|
85
85
|
Doctor's `writer_dirty` and `writer_uncollected_bundle`, and
|
|
86
86
|
`pi-session-mcp-setup --writer <name> --collect` (dry run).
|
|
87
|
+
Neither proves a clone clean: Doctor reads only `HEAD` and refs, and the dry
|
|
88
|
+
run inspects nothing. The authoritative check is `--remove` without
|
|
89
|
+
`--discard`, which inspects the clone, including its index, and refuses with
|
|
90
|
+
`writer_uncollected` when it holds work.
|
|
87
91
|
If a writer to remove or re-provision has uncollected work or a dirty clone,
|
|
88
|
-
stop and ask before anything goes live. Never run `--collect --apply` in this
|
|
92
|
+
or `--remove` refuses, stop and ask before anything goes live. Never run `--collect --apply` in this
|
|
89
93
|
workflow, and never discard work to get past a refusal.
|
|
90
94
|
|
|
91
95
|
Stop and report `writer_busy`, `podman_unavailable`, `registration_divergent`
|