pi-legion 2.0.0 → 2.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +117 -0
- package/CONTRIBUTING.md +51 -18
- package/README.md +93 -7
- package/agents/planner.md +1 -1
- package/agents/reviewer.md +2 -3
- package/agents/worker.md +2 -3
- package/docs/contracts/esc-cascade-v2.md +2 -1
- package/docs/design.md +33 -16
- package/docs/vexillatio-contract.md +1 -1
- package/index.ts +125 -21
- package/package.json +8 -4
- package/skills/pi-legion/SKILL.md +22 -8
- package/src/agents/agents.ts +60 -5
- package/src/api.ts +2 -0
- package/src/extension/legion-commands.ts +63 -9
- package/src/extension/legion-doctor.ts +127 -40
- package/src/extension/legion-status.ts +172 -0
- package/src/extension/playbook.ts +3 -3
- package/src/extension/runtime.ts +93 -14
- package/src/extension/scout-guard.ts +12 -3
- package/src/runs/args.ts +69 -13
- package/src/runs/orchestrator.ts +22 -2
- package/src/runs/provider-pin.ts +59 -0
- package/src/runs/role-tool-gates.ts +103 -0
- package/src/shared/session.ts +37 -2
- package/src/shared/types.ts +8 -0
- package/src/tui/viz/panels.ts +3 -1
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to this project are documented in this file.
|
|
4
|
+
|
|
5
|
+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|
6
|
+
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
|
+
|
|
8
|
+
Published GitHub Release notes remain available at
|
|
9
|
+
https://github.com/zzjcool/pi-legion/releases — this file is the in-repo
|
|
10
|
+
summary so you can see **2.x vs 0.16** without leaving the tree.
|
|
11
|
+
|
|
12
|
+
## [Unreleased]
|
|
13
|
+
|
|
14
|
+
### Fixed
|
|
15
|
+
|
|
16
|
+
- Dispatched children now receive `--provider` pinned from the parent's model
|
|
17
|
+
registry, so a bare model id (`workbuddy/…`) that also exists under a static
|
|
18
|
+
auth-less provider in `models.json` can no longer hijack the child start
|
|
19
|
+
(`No API key found for …`) (#123).
|
|
20
|
+
- Scout-guard now counts first-class `grep` / `find` / `ls` tool calls as reads (#87).
|
|
21
|
+
- Doctor diagnose help no longer repeats itself; storage section shows hygiene sweep state (#86).
|
|
22
|
+
- Bundled roles no longer advertise unloaded `lens_*` tools (#75).
|
|
23
|
+
- Non-interactive `pi --print` waits for async children before cascade retire (#77).
|
|
24
|
+
- Roles load `builtin:codemode`; doctor diagnose shows a dedicated section (#89 / #90 → #93).
|
|
25
|
+
- Doctor role-tool→extension gates are data-driven / extensible (#97 / #99).
|
|
26
|
+
- Launch honors `name=` so `/legion status <name>` matches the railway label (#101 / #104).
|
|
27
|
+
- Galaxy legend shows failed/retired glyphs only when those states are present (#102 / #103).
|
|
28
|
+
- Live child status leads with `alive · quiet Ns`; long quiet emphasizes living over a stale execution snapshot (#81 / #92 / #105).
|
|
29
|
+
- npm `package.json` description/keywords aligned with Legion 2.x RPC (no Herdr panes) (#106 / #111).
|
|
30
|
+
|
|
31
|
+
### Added
|
|
32
|
+
|
|
33
|
+
- `/legion status` human-readable summary; doctor slash list covers team / agents / on|off / summary (#76).
|
|
34
|
+
- README documents scout-guard settings and `/scout-guard` / `/no-scout-guard` (#74 / #71).
|
|
35
|
+
- Scout-guard mock-llm e2e: notify ×1, cooldown, and dispatch clear (#108 / #113).
|
|
36
|
+
|
|
37
|
+
### Changed
|
|
38
|
+
|
|
39
|
+
- Prefer `PI_LEGION_EXTRA_AGENT_DIRS` over legacy `PI_HERDR_SUBAGENTS_*` (alias; new name wins if both set) (#109 / #114).
|
|
40
|
+
- CONTRIBUTING/CI docs aligned with 2.x RPC; verify-12/13 paths point at `test/legacy/docker/` (#95 / #100, #107 / #112).
|
|
41
|
+
- README: remove duplicate Child extensions heading (#94 / #98).
|
|
42
|
+
- `design.md` historical banner; landed F38–F46 marked ✅ / Historical (#80 / #83 → #91).
|
|
43
|
+
- CI PR job runs `test:integration` (#79 / #88).
|
|
44
|
+
|
|
45
|
+
## [2.0.0] - 2026-10-14
|
|
46
|
+
|
|
47
|
+
First **Pi Legion** line on headless Pi RPC. Relative to the final Herdr-era
|
|
48
|
+
**0.16.x** packages, this is a breaking transport and packaging change.
|
|
49
|
+
|
|
50
|
+
### Breaking
|
|
51
|
+
|
|
52
|
+
- **RPC-only transport:** children run as headless `pi --mode rpc` processes
|
|
53
|
+
under `LegionSupervisor`. Herdr pane execution is archived under
|
|
54
|
+
`src/backends/legacy/` and is **not** a v2 runtime option.
|
|
55
|
+
- **Kinds:** only `kind: pi` is supported. Migrate non-Pi roles or stay on
|
|
56
|
+
`pi-legion@0.16.x`.
|
|
57
|
+
- **Shared tree ledger:** squad state lives in SQLite WAL `legion.db` (phases,
|
|
58
|
+
mail, resume), not pane-centric session bookkeeping alone.
|
|
59
|
+
- Bundled agent playbooks aligned with local RPC practice (#66).
|
|
60
|
+
|
|
61
|
+
### Added
|
|
62
|
+
|
|
63
|
+
- Recursive centurion trees, four-phase
|
|
64
|
+
planning / implementing / reviewing / verifying machine, `legion_mail`,
|
|
65
|
+
three-layer `/legion` UI (resident tree, full view, live overlay), railway
|
|
66
|
+
strip, tok/s / galaxy / log panels.
|
|
67
|
+
- Scout-guard: remind the main session after a streak of read-class tools (#64).
|
|
68
|
+
- Storage hygiene sweep on startup: prune idle runs, orphan temp dirs, abandoned
|
|
69
|
+
nodes, event retention, WAL checkpoint (#37 / #38 / #40 → #47).
|
|
70
|
+
- `/legion doctor` (+ diagnose) self-check; auto-doctor snippets on gated spawn
|
|
71
|
+
failures (#52).
|
|
72
|
+
- Child memory gate (`NODE_OPTIONS` V8 flags, pre-spawn gate) and tree-wide
|
|
73
|
+
verify concurrency limit (#50).
|
|
74
|
+
- Children default to `--no-extensions` with explicit/role escape hatches (#43 / #48).
|
|
75
|
+
- User stop controls for async children (`/legion stop`, idle Esc, `x` in view) (#41).
|
|
76
|
+
- Mock LLM server for offline pi / legion smoke (`test/mock-llm`, #54 / #56).
|
|
77
|
+
- GitHub Actions CI (typecheck + unit + integration) and stage-only npm publish
|
|
78
|
+
on tag (#65 / #68).
|
|
79
|
+
- Project workflow docs in CONTRIBUTING (#69).
|
|
80
|
+
|
|
81
|
+
### Changed
|
|
82
|
+
|
|
83
|
+
- Slash commands consolidated under `/legion` (#57).
|
|
84
|
+
- Status bar shows current-turn elapsed beside lifetime total (#62).
|
|
85
|
+
- tok/s uses output tokens / generationMs (decode throughput) (#61).
|
|
86
|
+
|
|
87
|
+
### Fixed
|
|
88
|
+
|
|
89
|
+
- Railway: pin live spawn verticals when the strip scrolls left (#67); retire /
|
|
90
|
+
downward spawn connector regressions (#46).
|
|
91
|
+
- Live worker no longer marked retired on a transient Connection blip (#63).
|
|
92
|
+
- Session JSONL streamed + incrementally parsed (no full-file `readFileSync`) (#36 / #45).
|
|
93
|
+
- Per-stream child output byte cap; kill on overflow (#35 / #44).
|
|
94
|
+
- Bun SQLite `.get()` null treated as miss on root insert (#53).
|
|
95
|
+
- Vexillatio sibling naming scoped to the current parent (#42 / #51).
|
|
96
|
+
|
|
97
|
+
### Security / robustness (design.md F38–F46, already on master)
|
|
98
|
+
|
|
99
|
+
- Model-scope globs use non-RegExp matching (ReDoS).
|
|
100
|
+
- Session create uses `writeFileSync` with `wx` (no fd leak / TOCTOU).
|
|
101
|
+
- Session decode swallows scalar JSON lines as torn.
|
|
102
|
+
- `tasks[]` / blank task validated before launch.
|
|
103
|
+
- Per-agent `timeoutMs`, pending criteria, nested YAML acceptance parsing;
|
|
104
|
+
`UNENFORCED_FIELDS` empty.
|
|
105
|
+
|
|
106
|
+
## [0.16.x] - Herdr-era (final)
|
|
107
|
+
|
|
108
|
+
Last line that runs children in Herdr panes. Not developed further on this
|
|
109
|
+
branch — pin `pi-legion@0.16.x` if you still need that model. See
|
|
110
|
+
[Herdr transition](README.md#herdr-transition-and-role-migration) in the README.
|
|
111
|
+
|
|
112
|
+
Earlier 0.11–0.15 history (including the `pi-herdr-swarm` /
|
|
113
|
+
`@zzjcool/pi-herdr-subagents` renames) lives in git tags and older Releases.
|
|
114
|
+
|
|
115
|
+
[Unreleased]: https://github.com/zzjcool/pi-legion/compare/v2.0.0...HEAD
|
|
116
|
+
[2.0.0]: https://github.com/zzjcool/pi-legion/releases/tag/v2.0.0
|
|
117
|
+
[0.16.x]: https://github.com/zzjcool/pi-legion/releases
|
package/CONTRIBUTING.md
CHANGED
|
@@ -23,8 +23,14 @@ directly to `master`. Implementers do not merge their own pull requests.
|
|
|
23
23
|
```bash
|
|
24
24
|
npm run typecheck
|
|
25
25
|
npm test
|
|
26
|
+
npm run test:integration # or npm run test:all
|
|
26
27
|
```
|
|
27
28
|
|
|
29
|
+
The required GitHub Actions check `ci` runs typecheck, unit, integration, and
|
|
30
|
+
mock-llm. Run `npm run test:integration` (or `npm run test:all`) locally
|
|
31
|
+
before you push, especially when the change touches `src/runs/`, `src/legion/`,
|
|
32
|
+
or `src/extension/runtime.ts`.
|
|
33
|
+
|
|
28
34
|
Add the unit tests the change needs. Prefer **TDD** (see [Checks](#checks)):
|
|
29
35
|
a failing test in `test/unit` or `test/integration` first, then the production
|
|
30
36
|
code.
|
|
@@ -59,20 +65,36 @@ there is no compile step to ship).
|
|
|
59
65
|
|
|
60
66
|
## Checks
|
|
61
67
|
|
|
68
|
+
The required GitHub Actions check `ci` (`.github/workflows/ci.yml`, on pull
|
|
69
|
+
requests and pushes to `master`) runs, in order:
|
|
70
|
+
|
|
71
|
+
1. `npm run typecheck`
|
|
72
|
+
2. `npm test` (unit)
|
|
73
|
+
3. `npm run test:integration`
|
|
74
|
+
4. `npm run test:mock-llm`
|
|
75
|
+
|
|
76
|
+
A failing integration step fails `ci`, so nesting and orchestrator regressions
|
|
77
|
+
are blocked before merge. `test:live` and `test:docker` stay out of that job.
|
|
78
|
+
|
|
62
79
|
```bash
|
|
63
80
|
npm run typecheck
|
|
64
81
|
npm test # test/unit/*.test.ts
|
|
65
|
-
npm run test:integration #
|
|
82
|
+
npm run test:integration # FakeSupervisor / nested fakes; no live `pi` binary
|
|
66
83
|
npm run test:all # typecheck + unit + integration
|
|
84
|
+
npm run test:mock-llm # also part of the required ci check
|
|
67
85
|
```
|
|
68
86
|
|
|
69
|
-
`npm run test:live`
|
|
70
|
-
|
|
87
|
+
`npm run test:live` is a **pi RPC live** smoke (`test/live/rpc-live.test.ts`).
|
|
88
|
+
It skips itself when the `pi` binary is missing from `PATH` (see the probe at
|
|
89
|
+
the top of that file). Do not fail CI on it.
|
|
71
90
|
|
|
72
91
|
Prefer **TDD** for behaviour changes: a failing test in `test/unit` or
|
|
73
92
|
`test/integration` first, then the production code. Integration tests should
|
|
74
|
-
|
|
75
|
-
|
|
93
|
+
drive the orchestrator through `FakeSupervisor` (`test/helpers/fake-supervisor.ts`)
|
|
94
|
+
so nesting / launch / collect stay covered without a live `pi`. The herdr-era
|
|
95
|
+
helpers `createHerdrClient` / `createFakeRunner` remain as **deprecated legacy**
|
|
96
|
+
exports (see `src/api.ts` and `test/legacy/`); use them only when touching the
|
|
97
|
+
archived Herdr backend.
|
|
76
98
|
|
|
77
99
|
## Mock LLM
|
|
78
100
|
|
|
@@ -91,16 +113,20 @@ dummy key is always the literal `mock`.
|
|
|
91
113
|
|
|
92
114
|
## Docker verification
|
|
93
115
|
|
|
94
|
-
`test/docker/` runs the package inside
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
116
|
+
`test/docker/` runs the package inside the RPC / pi-legion sandbox image.
|
|
117
|
+
Default image and staging path names are **historical** (`pi-herdr-sandbox:latest`,
|
|
118
|
+
`/tmp/pi-herdr-docker-home`; override with `PI_DOCKER_IMAGE` / `DOCKER_PI_HOME`).
|
|
119
|
+
Content is the 2.x RPC sandbox, not a live herdr pane host. The scripts copy
|
|
120
|
+
the **host** Pi config (`~/.pi/agent/settings.json`, `models.json`, `auth.json`
|
|
121
|
+
if present) into that disposable home; the container cannot write back to your
|
|
122
|
+
real `~/.pi`.
|
|
98
123
|
|
|
99
124
|
```bash
|
|
100
|
-
# image must already exist
|
|
125
|
+
# image must already exist (historical default name; do not rename a local tag
|
|
126
|
+
# just to match docs — override with PI_DOCKER_IMAGE if yours differs)
|
|
101
127
|
docker image inspect pi-herdr-sandbox:latest >/dev/null
|
|
102
128
|
|
|
103
|
-
bash test/docker/verify-1-child-guard.sh # child
|
|
129
|
+
bash test/docker/verify-1-child-guard.sh # RPC child-guard / ledger block
|
|
104
130
|
bash test/docker/verify-2-task-appendix.sh # frozen task appendix
|
|
105
131
|
bash test/docker/verify-3-readonly.sh # read-only bash denylist
|
|
106
132
|
bash test/docker/verify-4-acceptance.sh # collect → verified
|
|
@@ -111,19 +137,26 @@ bash test/docker/verify-8-verify-command.sh # criterion.command + timeout
|
|
|
111
137
|
bash test/docker/verify-9-worktree.sh # git worktree cwd
|
|
112
138
|
bash test/docker/verify-10-fallback.sh # fallbackModels
|
|
113
139
|
bash test/docker/verify-11-nested-alias.sh # nested + alias + completionGuard
|
|
114
|
-
bash test/docker/verify-12-workspace.sh # pi install + child pinned to parent Space
|
|
115
|
-
bash test/docker/verify-13-kinds.sh # kind/model matrix; live CodeBuddy when mounted
|
|
116
140
|
```
|
|
117
141
|
|
|
118
|
-
Or all at once:
|
|
142
|
+
Or all at once (RPC mainline **1–11** only):
|
|
119
143
|
|
|
120
144
|
```bash
|
|
121
145
|
npm run test:docker
|
|
122
146
|
```
|
|
123
147
|
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
148
|
+
**Legacy Herdr / Space / kind checks** live under `test/legacy/docker/` (need
|
|
149
|
+
pi-legion **0.16.x** Herdr-era setup). They are **not** part of
|
|
150
|
+
`npm run test:docker`:
|
|
151
|
+
|
|
152
|
+
```bash
|
|
153
|
+
bash test/legacy/docker/verify-12-workspace.sh # Herdr Space pin (legacy)
|
|
154
|
+
bash test/legacy/docker/verify-13-kinds.sh # kind/model matrix; live CodeBuddy when mounted
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
`verify-13-kinds.sh` also bind-mounts host `codebuddy` / `cursor-agent` and
|
|
158
|
+
(unless `LIVE_KIND_PROBES=0`) calls live CodeBuddy. The numbered 1–11 scripts
|
|
159
|
+
under `test/docker/` stay offline/mock.
|
|
127
160
|
|
|
128
161
|
Override paths with `HOST_PI_AGENT`, `DOCKER_PI_HOME`, `PI_DOCKER_IMAGE`.
|
|
129
162
|
|
|
@@ -145,7 +178,7 @@ them by hand.
|
|
|
145
178
|
| `src/runs/acceptance.ts` | `verification-output` command |
|
|
146
179
|
| `test/mock-llm/` | Scriptable OpenAI mock for offline pi / legion |
|
|
147
180
|
| `agents/*.md` | bundled roles |
|
|
148
|
-
| `docs/design.md` |
|
|
181
|
+
| `docs/design.md` | design notes / F1–F46 (incl. historical herdr-era measurements; see file banner) |
|
|
149
182
|
| `README.md` | what is actually wired today |
|
|
150
183
|
|
|
151
184
|
Do not import from `src/` in downstream packages — use
|
package/README.md
CHANGED
|
@@ -14,6 +14,8 @@ shared SQLite ledger records the whole tree.
|
|
|
14
14
|
> `@zzjcool/pi-herdr-subagents` (through 0.14.3; renamed after an npm name
|
|
15
15
|
> collision), then as `pi-herdr-swarm` (0.15.0), before becoming `pi-legion`
|
|
16
16
|
> in 0.16.0. **2.0.0: the legion era — recursive centurion tree on pi RPC transport; herdr pane execution archived to legacy**
|
|
17
|
+
>
|
|
18
|
+
> **What changed in 2.x?** See [CHANGELOG.md](CHANGELOG.md) (Keep a Changelog). Published notes also land on [GitHub Releases](https://github.com/zzjcool/pi-legion/releases).
|
|
17
19
|
|
|
18
20
|
## Contents
|
|
19
21
|
|
|
@@ -22,10 +24,12 @@ shared SQLite ledger records the whole tree.
|
|
|
22
24
|
- [Legion tools and phases](#legion-tools-and-phases)
|
|
23
25
|
- [Three-layer visualization](#three-layer-visualization)
|
|
24
26
|
- [Settings and budget gates](#settings-and-budget-gates)
|
|
27
|
+
- [Scout guard](#scout-guard)
|
|
25
28
|
- [Team 配置](#team-配置)
|
|
26
29
|
- [Parent/child context conventions](#parentchild-context-conventions)
|
|
27
30
|
- [Delivery and resume](#delivery-and-resume)
|
|
28
31
|
- [Herdr transition and role migration](#herdr-transition-and-role-migration)
|
|
32
|
+
- [Changelog](CHANGELOG.md)
|
|
29
33
|
- [Development](#development)
|
|
30
34
|
|
|
31
35
|
## Architecture
|
|
@@ -87,12 +91,22 @@ subagent({ agent: "scout", task: "Map the export code path and report relevant f
|
|
|
87
91
|
|
|
88
92
|
No manual child-process launch is needed. Use `/legion` to inspect the tree;
|
|
89
93
|
see [Three-layer visualization](#three-layer-visualization) for navigation.
|
|
94
|
+
`/legion status` prints that tree in the chat, and `/legion status <name>`
|
|
95
|
+
prints one node — see [Status](#status-legion-status).
|
|
90
96
|
|
|
91
97
|
The `subagent` control actions include event-driven `wait` and graceful `stop`:
|
|
92
98
|
`subagent({ action: "wait", name: "worker-0" })` returns as soon as the child
|
|
93
99
|
settles (or the parent turn is interrupted with Esc). Aborting a parent turn
|
|
94
100
|
with Esc gracefully retires its tracked children, including those being waited
|
|
95
|
-
on or collected; the cascade is silent.
|
|
101
|
+
on or collected; the cascade is silent. Launch stays async by default. Under
|
|
102
|
+
`pi --print` or JSON mode the process would otherwise exit at the end of the
|
|
103
|
+
parent turn and retire those children before they write an assistant message.
|
|
104
|
+
That shutdown waits for each live async child to settle, bounded by the
|
|
105
|
+
child's turn timeout, and only then retires whatever is still running. A
|
|
106
|
+
child killed by that shutdown is recorded as aborted because the parent
|
|
107
|
+
session shut down, not because the model produced no reply. To include the
|
|
108
|
+
child's result in the same print turn, call `wait` or `collect` before the
|
|
109
|
+
turn ends, or launch with `async: false`. To stop children explicitly, use
|
|
96
110
|
`subagent({ action: "stop", name: "worker-0" })` or
|
|
97
111
|
`subagent({ action: "stop", all: true })`; this runs the normal graceful-retire
|
|
98
112
|
sequence for each selected child.
|
|
@@ -117,6 +131,28 @@ While the main agent is idle and subagents are live, the railway header shows
|
|
|
117
131
|
a dim `esc stop all · /legion stop [name]` hint (shortened on narrow terminals,
|
|
118
132
|
hidden while the main agent is working).
|
|
119
133
|
|
|
134
|
+
### Status (`/legion status`)
|
|
135
|
+
|
|
136
|
+
The railway and `/legion` view are TUI surfaces. `/legion status` is the chat
|
|
137
|
+
snapshot of the same tree:
|
|
138
|
+
|
|
139
|
+
- `/legion status` prints every node with the same lines as `legion_tree`
|
|
140
|
+
(`id role=… status=… phase=… model=… depth=…`), plus a count of each status.
|
|
141
|
+
Live jobs that are not in the tree yet are listed under that summary.
|
|
142
|
+
- `/legion status <name>` prints one node with the same text as
|
|
143
|
+
`subagent({ action: "status", name })`. Living children lead with
|
|
144
|
+
`alive · quiet Ns` (session JSONL mtime); after ~30s of silence the line
|
|
145
|
+
becomes `alive · quiet Ns (living)` so 「活着但安静」is obvious. Run-store
|
|
146
|
+
execution/acceptance fields are labeled snapshots, and collect-deadline /
|
|
147
|
+
transient-connection reasons are omitted from the snapshot line while the
|
|
148
|
+
child is alive so they do not steal attention from quiet age. A ledger-only
|
|
149
|
+
node still uses the same renderer with the fields the tree has.
|
|
150
|
+
- Quiet age is not a heartbeat: there is no child-side progress ping. Minutes
|
|
151
|
+
of silence can still mean the model is reasoning (especially high-thinking
|
|
152
|
+
turns). Quiet alone does not mean the child is stuck; pair it with `alive`.
|
|
153
|
+
- Both forms work outside the TUI. A short name that matches more than one
|
|
154
|
+
node needs the full node id (`/legion status <node-id>`).
|
|
155
|
+
|
|
120
156
|
## Legion tools and phases
|
|
121
157
|
|
|
122
158
|
Child nodes receive these tree-aware tools:
|
|
@@ -208,6 +244,38 @@ subtree, including itself; when launched by a parent at depth `d`, it inherits
|
|
|
208
244
|
`C_child = min(C_parent, d + R, 4)` (`R = 1` makes it a leaf), so it can tighten
|
|
209
245
|
the inherited cap but cannot widen it.
|
|
210
246
|
|
|
247
|
+
### Scout guard
|
|
248
|
+
|
|
249
|
+
`subagents.scoutGuard` watches the main session. After `threshold` consecutive
|
|
250
|
+
read-like tool calls with no `subagent` launch or `vexillatio` call in
|
|
251
|
+
between, it injects one follow-up reminder and then waits out `cooldownMs`.
|
|
252
|
+
It is on by default. Set it in `~/.pi/agent/settings.json` or the project
|
|
253
|
+
`.pi/settings.json`; a project file overrides the same fields from the user
|
|
254
|
+
file.
|
|
255
|
+
|
|
256
|
+
```json
|
|
257
|
+
{
|
|
258
|
+
"subagents": {
|
|
259
|
+
"scoutGuard": {
|
|
260
|
+
"enabled": true,
|
|
261
|
+
"threshold": 8,
|
|
262
|
+
"cooldownMs": 120000
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
```
|
|
267
|
+
|
|
268
|
+
| Field | Default | Meaning |
|
|
269
|
+
| --- | ---: | --- |
|
|
270
|
+
| `enabled` | `true` | Count and remind. `false` skips the guard until it is turned back on. |
|
|
271
|
+
| `threshold` | `8` | Consecutive read-like calls before one reminder. Positive integer. |
|
|
272
|
+
| `cooldownMs` | `120000` | Quiet period after a reminder, in milliseconds. Integer ≥ 0. |
|
|
273
|
+
|
|
274
|
+
`/scout-guard` turns the guard on for this session and `/no-scout-guard`
|
|
275
|
+
turns it off. Both override `enabled` in memory only; settings files stay
|
|
276
|
+
unchanged. Child sessions do not register these commands. Behavior in full
|
|
277
|
+
is in [docs/design.md §6.4.1](docs/design.md#641-scout-guard-subagentsscoutguard).
|
|
278
|
+
|
|
211
279
|
### Team 配置
|
|
212
280
|
|
|
213
281
|
Use `subagents.team` to select the default named team from `subagents.teams`.
|
|
@@ -245,10 +313,11 @@ gate, missing lens tools, orphan temps, …), ask Legion rather than guessing
|
|
|
245
313
|
same idea as `pi list` / `pi auth check`.
|
|
246
314
|
|
|
247
315
|
- `/legion doctor` — full report in the chat (works outside TUI too).
|
|
248
|
-
- `/legion doctor
|
|
316
|
+
- `/legion doctor [section]` — one of: `summary`, `extensions`, `models`,
|
|
249
317
|
`spawn`, `memory`, `tools`, `storage`, `runtime`, `next`.
|
|
250
318
|
- `subagent({ action: "diagnose" })` — same full report as tool output so the
|
|
251
|
-
main agent can call it without waiting for you.
|
|
319
|
+
main agent can call it without waiting for you. The tool has no section
|
|
320
|
+
field; filter with `/legion doctor [section]`.
|
|
252
321
|
|
|
253
322
|
The report is structured for the model: each section ends in **Issues** /
|
|
254
323
|
**Next steps** with copy-pasteable fixes (env exports, role frontmatter,
|
|
@@ -268,11 +337,10 @@ Coverage:
|
|
|
268
337
|
| models | Host vs child model lists, which package restores providers, team/roster gaps |
|
|
269
338
|
| spawn | Sample child argv, recent spawn failures + stderr, nested-spawn flags |
|
|
270
339
|
| memory | Free RAM, memory gate, child V8 flags, verify concurrency slots in use |
|
|
271
|
-
| tools | `/legion`
|
|
272
|
-
| storage | `legion.db` sizes, orphan `rpc-child-*` temps,
|
|
340
|
+
| tools | `/legion` slash list (status, team, agents, summary, on/off, scout-guard, doctor, stop), idle-Esc / strip hints, tool names |
|
|
341
|
+
| storage | `legion.db` sizes, orphan `rpc-child-*` temps, effective hygiene limits (default vs env), last sweep marker plus a hint when it is missing or stale |
|
|
273
342
|
| runtime | Live children, tree statuses, acceptance-ish / active nodes |
|
|
274
343
|
|
|
275
|
-
### Child extensions
|
|
276
344
|
### Child extensions
|
|
277
345
|
|
|
278
346
|
Children start with `--no-extensions`, so they do not load the host's
|
|
@@ -288,6 +356,20 @@ itself (guard and nested spawning) and every path listed in the role's
|
|
|
288
356
|
| `PI_LEGION_CHILD_INHERIT_EXTENSIONS=1` | Every child loads all host extensions, as before. |
|
|
289
357
|
| `PI_LEGION_CHILD_EXTENSIONS=/a.ts,/b.ts` | Extra extension paths every child loads explicitly, e.g. a provider extension the child's model needs. |
|
|
290
358
|
|
|
359
|
+
Bundled planner, reviewer, and worker do not list `lens_*` tools. pi-lens starts an LSP stack (~1 GB per child, #43) and is not part of the default `--no-extensions` child. To give a role those tools, add the tool names to its `tools:` list and point `extensions:` / `subagentOnlyExtensions` (or `PI_LEGION_CHILD_EXTENSIONS`) at the pi-lens extension file. `/legion doctor` reports `ROLE_MISSING_LENS` when a role lists the tools without that path.
|
|
360
|
+
|
|
361
|
+
### Extra agent directories
|
|
362
|
+
|
|
363
|
+
PATH-style directories scanned for agent `*.md` definitions. They load as
|
|
364
|
+
user-level, **below** the real user agents dir in precedence (a same-name file
|
|
365
|
+
in `~/.pi/agent/agents` still wins). Useful for hermetic installs (Nix store,
|
|
366
|
+
container, read-only mount).
|
|
367
|
+
|
|
368
|
+
| Env | Effect |
|
|
369
|
+
| --- | --- |
|
|
370
|
+
| `PI_LEGION_EXTRA_AGENT_DIRS` | Canonical name. Colon-/semicolon-separated absolute dirs (`path.delimiter`). |
|
|
371
|
+
| `PI_HERDR_SUBAGENTS_EXTRA_AGENT_DIRS` | Deprecated compatibility alias (kept for at least one minor version). If **both** are set, `PI_LEGION_EXTRA_AGENT_DIRS` wins and the legacy value is ignored (one stderr warning). |
|
|
372
|
+
|
|
291
373
|
### Child memory controls
|
|
292
374
|
|
|
293
375
|
| Env | Default | Effect |
|
|
@@ -341,7 +423,8 @@ Version **0.16.x is the final Herdr-era line**. Pi Legion 2.x is RPC-only:
|
|
|
341
423
|
child execution uses headless `pi --mode rpc` processes, and the legacy backend
|
|
342
424
|
is archived under `src/backends/legacy/`, not offered as a v2 runtime option.
|
|
343
425
|
Pin to `pi-legion` 0.16.x if a workflow must stay on the former Herdr-based
|
|
344
|
-
execution model.
|
|
426
|
+
execution model. A short breaking-change summary lives in
|
|
427
|
+
[CHANGELOG.md](CHANGELOG.md#200---2026-10-14).
|
|
345
428
|
|
|
346
429
|
Pi Legion 2.x supports `kind: pi` only. Migrate a custom role that uses another
|
|
347
430
|
CLI kind by changing its frontmatter, for example:
|
|
@@ -385,4 +468,7 @@ Use `writeMockPiHome()` from `test/mock-llm` to generate an isolated
|
|
|
385
468
|
See [CONTRIBUTING.md](CONTRIBUTING.md#project-workflow) for the project
|
|
386
469
|
workflow: issues, pull requests, the merge gate, and npm releases.
|
|
387
470
|
|
|
471
|
+
Version history for consumers: [CHANGELOG.md](CHANGELOG.md). Tag-by-tag
|
|
472
|
+
release bodies: [GitHub Releases](https://github.com/zzjcool/pi-legion/releases).
|
|
473
|
+
|
|
388
474
|
MIT. See [LICENSE](LICENSE).
|
package/agents/planner.md
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: planner
|
|
3
3
|
description: 规划员:把任务拆成可并行/可验收的实施计划,冻结接口,指定文件归属
|
|
4
|
-
tools: read, grep, find, ls, bash, codemode
|
|
4
|
+
tools: read, grep, find, ls, bash, codemode
|
|
5
5
|
systemPromptMode: replace
|
|
6
6
|
inheritProjectContext: true
|
|
7
7
|
inheritSkills: false
|
package/agents/reviewer.md
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: reviewer
|
|
3
3
|
description: 审查员:只读对抗式审查一个指定范围的改动——对照需求查漏、查正确性与测试覆盖,输出带路径与严重级别的发现
|
|
4
|
-
tools: read, grep, find, ls, bash, codemode
|
|
4
|
+
tools: read, grep, find, ls, bash, codemode
|
|
5
5
|
systemPromptMode: replace
|
|
6
6
|
inheritProjectContext: true
|
|
7
7
|
inheritSkills: false
|
|
@@ -31,9 +31,8 @@ maxSubagentDepth: 1
|
|
|
31
31
|
|
|
32
32
|
## 工具纪律(读代码的正确姿势)
|
|
33
33
|
|
|
34
|
-
- 你有 pi-lens 工具:看模块结构用 `module_report`,读单个函数/类的完整源码用 `read_symbol`(比 grep 片段读快且省 token),找符号位置用 `symbol_search`,改完的类型/错误检查用 `lens_diagnostics`。
|
|
35
34
|
- `grep`/`find` 工具底层就是 ripgrep/fd,优先于 bash 管道。只在需要管道(如 `git show X | grep`)时才用 bash。
|
|
36
|
-
- **禁止对同一文件碎片化 grep 超过 3
|
|
35
|
+
- **禁止对同一文件碎片化 grep 超过 3 次**——超过就用 `read` 把相关段落整段读完。
|
|
37
36
|
- 多个独立的读操作(批量读文件、批量检查)用 `codemode` 的 `Promise.allSettled` 并行发,不要串行。
|
|
38
37
|
|
|
39
38
|
## 先确定范围
|
package/agents/worker.md
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: worker
|
|
3
3
|
description: 实现者:按冻结计划写代码、跑测试,完成后自报 verdict
|
|
4
|
-
tools: read, edit, write, grep, find, ls, bash, subagent, codemode
|
|
4
|
+
tools: read, edit, write, grep, find, ls, bash, subagent, codemode
|
|
5
5
|
systemPromptMode: replace
|
|
6
6
|
inheritProjectContext: true
|
|
7
7
|
inheritSkills: false
|
|
@@ -27,9 +27,8 @@ maxSubagentDepth: 3
|
|
|
27
27
|
|
|
28
28
|
## 工具纪律(读代码的正确姿势)
|
|
29
29
|
|
|
30
|
-
- 你有 pi-lens 工具:看模块结构用 `module_report`,读单个函数/类的完整源码用 `read_symbol`(比 grep 片段读快且省 token),找符号位置用 `symbol_search`,改完后对涉及文件跑 `lens_diagnostics` 查类型/错误。
|
|
31
30
|
- `grep`/`find` 工具底层就是 ripgrep/fd,优先于 bash 管道。只在需要管道(如 `git diff | grep`)时才用 bash。
|
|
32
|
-
- **禁止对同一文件碎片化 grep 超过 3
|
|
31
|
+
- **禁止对同一文件碎片化 grep 超过 3 次**——超过就用 `read` 把相关段落整段读完。
|
|
33
32
|
- 多个独立的读操作(批量读文件、批量检查)用 `codemode` 的 `Promise.allSettled` 并行发,不要串行。
|
|
34
33
|
|
|
35
34
|
## 职责边界
|
|
@@ -57,7 +57,8 @@ vexillatio 工具 execute 也要把 signal 传进来(找到它的 registerTool
|
|
|
57
57
|
## 语义边界(不变)
|
|
58
58
|
|
|
59
59
|
- **stop action 不变**:显式停止仍走全链。
|
|
60
|
-
- **主 pi 正常退出(quit
|
|
60
|
+
- **主 pi 正常退出(quit)不变**:交互 TUI 的 session_shutdown 仍立即级联 retire。
|
|
61
|
+
- **非交互 print/JSON(#72)**:`ctx.mode` 为 `print` 或 `json` 时,session_shutdown 先等仍活着的 async 子 agent 结算(上限为各子的 turn timeout),再 retire 尚未结束的。避免 `--print` 在首包前把刚 spawn 的子进程记成 `no assistant message for the last prompt`。父会话关机导致的无 assistant abort 原因改为 parent session shutdown,与模型自己没写出 assistant 区分。
|
|
61
62
|
- **SIGKILL/崩溃不覆盖**:孤儿扫描 + resume 语义不变(这是既定接受的风险)。
|
|
62
63
|
- **children 的 children**:retire 链本身递归(孙进程 sweep 在 rpc-supervisor 的 retireChild 里),无需额外处理。
|
|
63
64
|
- **blocked children**:一并 retire(stop 语义一致)。
|
package/docs/design.md
CHANGED
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
# pi-legion 设计文档
|
|
2
2
|
|
|
3
|
+
> **⚠️ 历史实验笔记(非现行契约)**
|
|
4
|
+
> 本文记录 herdr / pane 时代的实测与设计推演。**运行时契约以 [README](../README.md) 与 [CONTRIBUTING](../CONTRIBUTING.md) 为准**(Pi Legion 2.x = headless Pi RPC + `legion.db`;herdr pane 执行已归档到 `src/backends/legacy/`)。
|
|
5
|
+
> 下文 F 条中标 **✅ landed** 的是已在当前 master 落地的修复;未标注的早期结论仍有参考价值,但不要当作「今日仍坏」的缺口清单。
|
|
6
|
+
|
|
3
7
|
> 基于 10 组实测实验(exp1–exp10)得出的设计。所有结论都标注了实验依据,
|
|
4
8
|
> 未经验证的假设明确标记为「待验证」。
|
|
5
9
|
|
|
@@ -20,7 +24,7 @@
|
|
|
20
24
|
|
|
21
25
|
### 实现状态(相对本文档)
|
|
22
26
|
|
|
23
|
-
下面 F
|
|
27
|
+
下面 F 条目里不少写的是「当时的缺口」(文首 banner 已说明:契约以 README + CONTRIBUTING 为准)。当前运行时已经钉死:
|
|
24
28
|
|
|
25
29
|
- 子进程强制加载 child-guard:拦 `herdr agent prompt|wait|send-keys|start`、外 pane read、只读角色写操作
|
|
26
30
|
- 任务卡自动附录(禁止 wakeup、必须 `{"ok":…}`)
|
|
@@ -654,10 +658,11 @@ system prompt 不再注入 playbook/roster;bash 派发 guard 放行手动 herd
|
|
|
654
658
|
### 6.4.1 Scout guard `subagents.scoutGuard`
|
|
655
659
|
|
|
656
660
|
只在主会话生效(子进程带 `PI_SUBAGENT_ROLE`,不计数、不注入)。连续 N 次
|
|
657
|
-
|
|
658
|
-
`rg`/`grep`/`find`/`ls`/`stat`/`wc`/`file`/`jq
|
|
659
|
-
|
|
660
|
-
|
|
661
|
+
读类工具调用(first-class `read`/`grep`/`find`/`ls`,以及可判定为只读的 bash:
|
|
662
|
+
`cat`/`head`/`tail`/`less`/`rg`/`grep`/`find`/`ls`/`stat`/`wc`/`file`/`jq`、
|
|
663
|
+
`git show|log|diff|status|blame`、不带 `-i` 的 `sed`)且中间没有成功的
|
|
664
|
+
`subagent` / `vexillatio` 派发时,异步注入一条 follow-up 提醒,不挡住当前
|
|
665
|
+
`tool_call`。
|
|
661
666
|
|
|
662
667
|
```json
|
|
663
668
|
{ "subagents": { "scoutGuard": { "enabled": true, "threshold": 8, "cooldownMs": 120000 } } }
|
|
@@ -1132,12 +1137,24 @@ index.ts(132,4): error TS7006: Parameter 'signal' implicitly has an 'any' type.
|
|
|
1132
1137
|
|
|
1133
1138
|
---
|
|
1134
1139
|
|
|
1135
|
-
## 16. 交付前安全/健壮性审计(F38–
|
|
1140
|
+
## 16. 交付前安全/健壮性审计(F38–F46)— Historical findings(✅ landed)
|
|
1136
1141
|
|
|
1137
1142
|
对全部模块做了对抗式输入扫描(畸形会话文件、路径穿越、恶意配置、并发写)。
|
|
1138
|
-
|
|
1143
|
+
以下条目**当时**是真缺陷;对照当前 master 均已落地(见各条 ✅),勿再当 open gap。
|
|
1139
1144
|
|
|
1140
|
-
|
|
1145
|
+
| # | 当时缺口 | master 落点(摘要) |
|
|
1146
|
+
| --- | --- | --- |
|
|
1147
|
+
| F38 | glob→RegExp ReDoS | `matchesScopePattern` 双指针 glob,**不用 RegExp** |
|
|
1148
|
+
| F39 | `openSync`/`closeSync` fd 泄漏 | session 预创建改 `writeFileSync(..., { flag: "wx" })` |
|
|
1149
|
+
| F40 | `JSON.parse` 标量拖垮会话解析 | `decodeEvent` 非对象计入 `tornLines` |
|
|
1150
|
+
| F41 | `tasks[]` 条目未校验 | `firstInvalidStep` / 启动前校验 agent+task |
|
|
1151
|
+
| F42 | 空白 `task` 被 `Boolean` 放行 | 存在性按 `trim()` |
|
|
1152
|
+
| F43 | 角色 `timeoutMs` 被忽略 | launch 记入 `timeoutByName`,follow/wait 使用 |
|
|
1153
|
+
| F44 | `acceptance.criteria` 静默丢弃 | `pendingCriteria` + command 才升 `verified` |
|
|
1154
|
+
| F45 | 未生效配置看起来生效 | `UNENFORCED_FIELDS` 现为空;list 不再假警告 |
|
|
1155
|
+
| F46 | 嵌套 YAML acceptance 未解析 | `parseAcceptance` + `parseIndentedBlock` |
|
|
1156
|
+
|
|
1157
|
+
### F38 — ✅ landed — ReDoS:glob → RegExp 的嵌套量词(安全)
|
|
1141
1158
|
|
|
1142
1159
|
`modelScope.allow` 的 glob 被翻译成 `.*`,于是 `*a*a*a…b` 变成 `.*a.*a.*a…b`——
|
|
1143
1160
|
嵌套量词在**不匹配**的输入上指数回溯。
|
|
@@ -1152,7 +1169,7 @@ index.ts(132,4): error TS7006: Parameter 'signal' implicitly has an 'any' type.
|
|
|
1152
1169
|
**修法**:不用正则,改用双指针贪心 glob 匹配(只回溯最近一个 `*`)。
|
|
1153
1170
|
修复后 n=6400 仅 2ms。
|
|
1154
1171
|
|
|
1155
|
-
### F39 — fd 泄漏:`openSync`/`closeSync` 无保护
|
|
1172
|
+
### F39 — ✅ landed — fd 泄漏:`openSync`/`closeSync` 无保护
|
|
1156
1173
|
|
|
1157
1174
|
```ts
|
|
1158
1175
|
const fd = fs.openSync(file, "w", 0o600);
|
|
@@ -1165,7 +1182,7 @@ launcher 为**每个 child** 创建一个 session 文件,所以泄漏会随 fa
|
|
|
1165
1182
|
**修法**:`fs.writeFileSync(file, "", { flag: "wx", mode: 0o600 })`——
|
|
1166
1183
|
由 Node 自己管理描述符,并且 `wx` 顺带消除了 `existsSync` 检查留下的 TOCTOU 窗口。
|
|
1167
1184
|
|
|
1168
|
-
### F40 — `JSON.parse("null")` 拖垮整个会话解析
|
|
1185
|
+
### F40 — ✅ landed — `JSON.parse("null")` 拖垮整个会话解析
|
|
1169
1186
|
|
|
1170
1187
|
`JSON.parse` 对标量是成功的:`null` / `42` / `true` / `"x"`。
|
|
1171
1188
|
随后 `event.type` 在 `null` 上抛异常,**整个 `parseSessionText` 崩溃**,
|
|
@@ -1173,7 +1190,7 @@ launcher 为**每个 child** 创建一个 session 文件,所以泄漏会随 fa
|
|
|
1173
1190
|
|
|
1174
1191
|
**修法**:非对象、非数组的标量按损坏行计入 `tornLines`,继续解析其余行。
|
|
1175
1192
|
|
|
1176
|
-
### F41 — `tasks[]` 的条目未校验
|
|
1193
|
+
### F41 — ✅ landed — `tasks[]` 的条目未校验
|
|
1177
1194
|
|
|
1178
1195
|
单任务路径用 `Boolean(params.agent && params.task)` 把关,但数组路径直接放行:
|
|
1179
1196
|
|
|
@@ -1184,12 +1201,12 @@ tasks:[{task:"do it"}] → 放行,agent 名为 undefined
|
|
|
1184
1201
|
|
|
1185
1202
|
**修法**:每个 step 在分配任何资源之前校验 `agent` 与 `task`。
|
|
1186
1203
|
|
|
1187
|
-
### F42 — `Boolean(" ")` 为真:纯空白 task 被放行
|
|
1204
|
+
### F42 — ✅ landed — `Boolean(" ")` 为真:纯空白 task 被放行
|
|
1188
1205
|
|
|
1189
1206
|
即使单任务路径,`task: " "` 也会通过,生成一个毫无意义的 `Task:` prompt。
|
|
1190
1207
|
**修法**:存在性按 `trim()` 后的内容判定,而非 `Boolean()`。
|
|
1191
1208
|
|
|
1192
|
-
### F43 — `timeoutMs` 被解析却从不生效
|
|
1209
|
+
### F43 — ✅ landed — `timeoutMs` 被解析却从不生效
|
|
1193
1210
|
|
|
1194
1211
|
5 个自带角色都声明了预算,运行时却全部忽略,永远用全局默认 15 分钟:
|
|
1195
1212
|
|
|
@@ -1201,7 +1218,7 @@ DEFAULTS.turnTimeoutMs: 900000 (15min) ← 实际生效
|
|
|
1201
1218
|
|
|
1202
1219
|
**修法**:`collect` 采用 `agent.timeoutMs`(按 child 记录,逐个子 agent 生效)。
|
|
1203
1220
|
|
|
1204
|
-
### F44 — `acceptance.criteria` 被静默丢弃
|
|
1221
|
+
### F44 — ✅ landed — `acceptance.criteria` 被静默丢弃
|
|
1205
1222
|
|
|
1206
1223
|
角色可以声明 `must: "测试通过"` 这类**语义**验收条件,代码解析后就不管了。
|
|
1207
1224
|
调用方无法知道「没有任何东西验证过它」。
|
|
@@ -1212,7 +1229,7 @@ DEFAULTS.turnTimeoutMs: 900000 (15min) ← 实际生效
|
|
|
1212
1229
|
**修法**:criteria 作为**待验证清单**回传调用方(`pendingCriteria`),
|
|
1213
1230
|
且 `level` 保持 `attested`——**`verified` 只留给真正被人核对过的证据**。
|
|
1214
1231
|
|
|
1215
|
-
### F45 — 配置字段「看起来生效、实际无效」
|
|
1232
|
+
### F45 — ✅ landed — 配置字段「看起来生效、实际无效」
|
|
1216
1233
|
|
|
1217
1234
|
自带角色携带 `onBlocked` / `allowNestedSubagents` / `fallbackModels` / `toolTimeoutMs`,
|
|
1218
1235
|
全部被解析、全部不生效。其中 `allowNestedSubagents: false` 最危险——
|
|
@@ -1227,7 +1244,7 @@ DEFAULTS.turnTimeoutMs: 900000 (15min) ← 实际生效
|
|
|
1227
1244
|
**原则**:**一个被接受却不做事的键,比一个未知的键更危险**——
|
|
1228
1245
|
用户会相信它已经在保护自己。
|
|
1229
1246
|
|
|
1230
|
-
### F46 — 嵌套 YAML 块从未被解析:自带角色的 acceptance 全部丢失
|
|
1247
|
+
### F46 — ✅ landed — 嵌套 YAML 块从未被解析:自带角色的 acceptance 全部丢失
|
|
1231
1248
|
|
|
1232
1249
|
frontmatter 解析器是**扁平的**(只处理 `key: value`);一个嵌套块会以
|
|
1233
1250
|
**剥掉公共缩进后的原始文本**返回:
|
|
@@ -121,7 +121,7 @@ const VexillatioParams = Type.Object({
|
|
|
121
121
|
|
|
122
122
|
**既有测试文件除 §3 明确授权的 `test/unit/child-mode.test.ts` 两处断言数字修订外一律不修改**;§4 要求的新增测试全部落在两个新文件里。
|
|
123
123
|
|
|
124
|
-
**断言影响总则(REV-17.5)**:契约导致的注册行为变化若使某既有断言失效,属于本契约的影响面;授权范围以本 §3 该行所列为准,本行已全量扫描(grep `pi.tools\|tools.length\|tools.find\|tools.get\|
|
|
124
|
+
**断言影响总则(REV-17.5)**:契约导致的注册行为变化若使某既有断言失效,属于本契约的影响面;授权范围以本 §3 该行所列为准,本行已全量扫描(grep `pi.tools\|tools.length\|tools.find\|tools.get\|piLegion(` 全测试目录)并一次列尽。后续若再发现同类冲突,上报照旧。
|
|
125
125
|
|
|
126
126
|
## 4. 验收清单(可机器检查)
|
|
127
127
|
|