@junghanacs/entwurf 0.18.0 → 0.18.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/AGENTS.md +4 -4
- package/CHANGELOG.md +241 -0
- package/CONTRIBUTING.md +1 -1
- package/README.md +11 -5
- package/VERIFY.md +4 -4
- package/demo/README.md +1 -1
- package/docs/acp-backend-rail.md +46 -12
- package/docs/setup-clean-host.md +35 -3
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/acp/backend-adapter.js +2 -2
- package/package.json +9 -9
- package/pi-extensions/entwurf-control.ts +12 -2
- package/pi-extensions/lib/acp/acp-client.ts +3 -3
- package/pi-extensions/lib/acp/backend-adapter.ts +3 -3
- package/pi-extensions/lib/acp/backend.ts +3 -3
- package/pi-extensions/lib/acp/event-mapper.ts +5 -5
- package/run.sh +125 -56
- package/scripts/check-acp-usage-accounting.ts +9 -9
- package/scripts/check-gate-qualification.ts +62 -12
- package/scripts/check-release-gate-outcomes.ts +382 -10
- package/scripts/ci-qualify-decide.sh +159 -0
- package/scripts/fixtures/qualify-replay.json +149 -0
- package/scripts/mutants/bridge-command-boot.json +3 -3
- package/scripts/mutants/gate-qualification.json +28 -0
- package/scripts/mutants/pack-install.json +14 -3
- package/scripts/mutants/release-gate.json +67 -1
- package/scripts/raw-acp-compaction-measure/README.md +77 -0
- package/scripts/raw-acp-compaction-measure/probe.ts +196 -0
- package/scripts/smoke-acp-raw-turn-live.ts +1 -1
package/AGENTS.md
CHANGED
|
@@ -139,7 +139,7 @@ LIVE=1 ENTWURF_ACP_CORTEX_CONNECTION=<conn> ./run.sh smoke-acp-cortex-live # o
|
|
|
139
139
|
LIVE=1 AGY_CONVERSATION_ID=<id> ./run.sh smoke-agy-native-push-live
|
|
140
140
|
```
|
|
141
141
|
|
|
142
|
-
- The deterministic floor is tiered (#70). `pnpm check` is the everyday core — toolchain (lint + typecheck), the vitest lanes, and the pure-unit / behavioral-contract / source-topology gates plus the cheap static coherence checks. It prints its own total wall time; acceptance is ≤60s on the reference host `oracle` (an operator measurement, never a hard wall-clock gate on arbitrary hosts). `pnpm run check:full` is the full deterministic floor — the core plus the hermetic-integration and package/install tiers — and is what the candidate protocol, push CI, release-gate, and `prepublishOnly` run. Exact membership is the named `check:*` group scripts in `package.json` (the executable SSOT); a gate changes tier by semantic-class decision, never because it happened to get faster or slower.
|
|
142
|
+
- The deterministic floor is tiered (#70). `pnpm check` is the everyday core — toolchain (lint + typecheck), the vitest lanes, and the pure-unit / behavioral-contract / source-topology gates plus the cheap static coherence checks. It prints its own total wall time; acceptance is ≤60s on the reference host `oracle` (an operator measurement, never a hard wall-clock gate on arbitrary hosts). `pnpm run check:full` is the full deterministic floor — the core plus the hermetic-integration and package/install tiers — and is what the candidate protocol, push CI, release-gate, and `prepublishOnly` run. Exact membership is the named `check:*` group scripts in `package.json` (the executable SSOT); a gate changes tier by semantic-class decision, never because it happened to get faster or slower. The full tier carries `check-gate-manifests` (the qualification HEAD, through `check:hermetic`); the everyday core does not, and neither tier carries the mutant-executing `check-gate-qualification`, which is scheduled separately (below).
|
|
143
143
|
- **Kill-proof discipline (gate qualification).** A gate is a test only if re-planting a closed defect turns it red for the claimed reason. `check-gate-qualification` proves that automatically: committed mutants in `scripts/mutants/` must be KILLED at their `[QK:<claim>]` signature inside an isolated snapshot repo (control→mutant→restore→control; the real checkout is never written). Gates a release touches carry such manifests; assertion counts are never evidence — claim IDs + killed mutant IDs are. `check-agy-permission-matrix` holds the enumerated permission contract space; matrix cells change by axis/rule edits, never by appending cases.
|
|
144
144
|
- **When changing a contract/gate:** name the production subject and an oracle independent of it; give the failing assertion a stable `[QK:<claim>]` label and add/update the exact-once mutant in `scripts/mutants/*.json`; if the contract is combinatorial, update the literal matrix axes/cells/exclusions together with their declared counts; then verify the focused gate, and let qualification and the full floor follow the scheduling contract below — once on the frozen candidate, not once per amendment. `MUTANT-STALE`/`SURVIVED`/`WRONG-REASON`/`CONTROL-RED`/`HANG`/`IMPURE` are red — never substitute an assertion count for a kill.
|
|
145
145
|
- Run LIVE gates with `PWD` in scratch so session artifacts do not land in the repo. Strip `CLAUDE_CONFIG_DIR`, `PI_SESSION_ID`, and `PI_AGENT_ID` from the gate process — a live pi/ACP session exports them into children, where they strip Claude hooks or capture a fresh-call callback.
|
|
@@ -157,7 +157,7 @@ implement → affected focused gates → independent review → one amendment bu
|
|
|
157
157
|
|
|
158
158
|
- **Inner loop:** run only the gates whose subject changed. Do not open the full floor to learn what a focused gate already answers.
|
|
159
159
|
- **Review before floor:** independent review and its corrections close as one bundle before the full floor runs.
|
|
160
|
-
- **Qualification is scheduled, not ambient.** `check-gate-qualification
|
|
160
|
+
- **Qualification is scheduled, not ambient — but its HEAD is not.** The mutant-EXECUTING body, `check-gate-qualification`, is not in the default check chains (core or full), so the operator inner loop never re-pays the full mutant inventory. It runs standalone once when a lane changed a gate, mutant, or matrix; machine time re-proves it everywhere else — the CI `check` job runs it on a branch push whose two-dot range touched the qualification surface (`scripts/ci-qualify-decide.sh` derives that path set from the manifests themselves), unconditionally on `workflow_dispatch -f qualify=true` and a weekly schedule, and release-gate carries it as a MUST step. The exact-SHA release oracle refuses a SHA whose body step did not conclude success, so a filtered-out release commit is a named failure with a documented dispatch recovery, never a quiet pass. Its head — runner self-test, manifest-set validation, declared lane inventory — is `check-gate-manifests`, which executes no mutant and never snapshots the repo, and it IS in `check:hermetic`: three of the five reds qualification has ever produced in CI died there in under five seconds. A tag push runs no CI at all, and the exact-SHA evidence a release quotes is whichever run at that commit carries the body concluding success — the branch run when the push moved the qualification surface, else the dispatch run the release skill's recovery creates.
|
|
161
161
|
- **Full floor once** (`pnpm run check:full`), on the frozen commit candidate. While it runs, nothing edits the worktree or index — including the NEXT boot sectors; a moved candidate voids the run's evidence.
|
|
162
162
|
- **pre-commit is not the floor.** `.husky/pre-commit` carries only fast static checks (whitespace, lint, typecheck); the full floor is owned by this protocol, not by the hook. Do not grow the hook back, and do not build receipt/cache machinery to prove the protocol was followed.
|
|
163
163
|
- **Release/LIVE acceptance is untouched.** VERIFY.md floors keep full strength; a shorter inner loop never lowers release evidence.
|
|
@@ -185,8 +185,8 @@ implement → affected focused gates → independent review → one amendment bu
|
|
|
185
185
|
- Every `.ts` file belongs to one typecheck fence: root emit-capable config, MCP strip-types config, or scripts strip-types config. Do not hide files with `exclude`.
|
|
186
186
|
- Root pi extensions import TypeBox through `@earendil-works/pi-ai`; do not mix direct `@sinclair/typebox` types.
|
|
187
187
|
- MCP/scripts use explicit `.ts` imports where Node strip-types requires them. Installed operator surfaces route to compiled JS.
|
|
188
|
-
- pi runtime range is `>=0.
|
|
189
|
-
- ACP pins are recorded in `package.json` and
|
|
188
|
+
- pi runtime range is `>=0.85.1 <0.86` with devDep exact `0.85.1`; re-evaluate loader aliases and `/compat` at every minor ceiling. The ceiling moves on measurement, never on assumption, and a previous bump's argument is never reused: at 0.83.0→0.84.0 `compat.ts` was still byte-identical but `loader.ts` was NOT, so the diff itself had to be read and judged reachable-or-not. Per-bump hashes, diff judgments, and reachability findings live in the ROADMAP **Dep bump(별도 트랙)** ledger — keep them there, not here.
|
|
189
|
+
- ACP pins are recorded in `package.json` and owned by `check-acp-sdk-surface`, which is the vitest contract `test/acp-sdk-surface.contract.test.ts` (`./run.sh check-acp-sdk-surface` is a transition shim into it, not a `scripts/` gate). `check-dep-versions` is the **pi** pin's oracle and reads no ACP pin — do not cite it for one. Do not describe a dependency bump as a behavioral fix without evidence.
|
|
190
190
|
|
|
191
191
|
## Working Style
|
|
192
192
|
|
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,247 @@ All notable changes to this project will be documented here. Format follows [Kee
|
|
|
4
4
|
|
|
5
5
|
## Unreleased
|
|
6
6
|
|
|
7
|
+
## 0.18.2 - 2026-09-07
|
|
8
|
+
|
|
9
|
+
One lane: #103, the second stage of the CI evidence budget (#99). The mutant body — 373 replants,
|
|
10
|
+
~30 minutes — stops running on every branch push, and the release oracle stops accepting a run that
|
|
11
|
+
did not carry it. Nothing in the runtime surface moves.
|
|
12
|
+
|
|
13
|
+
### Changed
|
|
14
|
+
|
|
15
|
+
- **The exact-SHA release oracle requires the qualification BODY, not three green job names (#103
|
|
16
|
+
piece 1).** `verify-exact-ci.sh` reads a fourth axis over one guard: the `check` job's
|
|
17
|
+
`Run ./run.sh check-gate-qualification` step must conclude `success`, with absent, skipped and
|
|
18
|
+
failed each named separately in the refusal. It also stops filtering to `--event push`, so a
|
|
19
|
+
`workflow_dispatch` run at the same SHA is admissible evidence — which is exactly when the
|
|
20
|
+
always-present `headSha` check starts carrying load, because `gh workflow run --ref` takes a
|
|
21
|
+
branch and never a SHA. A skipped body is not evidence: the oracle refuses that SHA and prints the
|
|
22
|
+
dispatch command that fixes it. This landed BEFORE the skip could exist.
|
|
23
|
+
- **The body runs only on a branch push that moved the qualification surface (#103 piece 2).**
|
|
24
|
+
`scripts/ci-qualify-decide.sh` diffs the two-dot push range GitHub itself compares and intersects
|
|
25
|
+
it with a path set **derived from `scripts/mutants/*.json` at runtime** — no copy in YAML, so a new
|
|
26
|
+
mutant subject cannot land outside the filter. Five numbered fail-opens, each naming itself in the
|
|
27
|
+
log: an all-zero base, a forced push (whose base GitHub does not document), a dispatch without
|
|
28
|
+
`qualify=true` or a schedule, an unreadable range, and `pull_request`. `workflow_dispatch -f
|
|
29
|
+
qualify=true` and a weekly schedule run the body unconditionally; `fetch-depth: 0` on the check job
|
|
30
|
+
is what keeps the base readable, and it measured free (2s checkout, the same as depth 1).
|
|
31
|
+
- **Measured on real runs, not argued.** A code push ran the body and took 36m24s
|
|
32
|
+
([34047559085](https://github.com/junghan0611/entwurf/actions/runs/34047559085)); a docs-only push
|
|
33
|
+
skipped it and took 6m13s
|
|
34
|
+
([34065841309](https://github.com/junghan0611/entwurf/actions/runs/34065841309)); the four-axis
|
|
35
|
+
oracle **refused** that second SHA while all three of its jobs were green, and the documented
|
|
36
|
+
dispatch recovery turned the refusal back into a pass
|
|
37
|
+
([34066181211](https://github.com/junghan0611/entwurf/actions/runs/34066181211)). The historical
|
|
38
|
+
justification is replayed rather than remembered: all five qualification reds this repo's CI has
|
|
39
|
+
ever produced still run the body under the filter.
|
|
40
|
+
|
|
41
|
+
### Added
|
|
42
|
+
|
|
43
|
+
- Three kill-qualified claims and their exact-once replants, inventory 370 → 373:
|
|
44
|
+
`RELEASE-SHA-QUALIFIED-IN-CI` (the fourth axis), `QUALIFY-FILTER-COVERS-SUBJECTS` (every manifest
|
|
45
|
+
subject and signatureSource decides `run_body=true`, asserted behaviourally against the shipped
|
|
46
|
+
script), and `QUALIFY-FILTER-READS-PUSH-RANGE` (a hermetic throwaway repo with a docs-only tip over
|
|
47
|
+
a commit that touched a subject — the two-dot reading, proven without repo history).
|
|
48
|
+
`QUALIFY-FILTER-REPLAYS-PAST-CATCHES` replays the five reds from recorded file lists.
|
|
49
|
+
- `scripts/fixtures/qualify-replay.json` — the five historical reds as the push ranges GitHub
|
|
50
|
+
compared, measured once here because history is not readable everywhere the gate runs.
|
|
51
|
+
|
|
52
|
+
### Verification
|
|
53
|
+
|
|
54
|
+
All on oracle (Linux, node 24.18.1, pi 0.85.1, omp 18.1.12 — updated from 18.0.0 during this lane).
|
|
55
|
+
|
|
56
|
+
- **`LIVE=1 ./run.sh release-gate /tmp/entwurf-release-gate-0.18.2.JlEU88 --cut` → `cut: OK`.**
|
|
57
|
+
**MUST: PASS=23 FAIL=0 SKIP=0**, BEHAVIOR: PASS=1 FAIL=0 SKIP=0, exit 0, 3305s (55m05s).
|
|
58
|
+
`check-gate-qualification` as its MUST step: **373/373 KILLED**.
|
|
59
|
+
- `pnpm run check:full` on the prepared tree: exit 0, 504s.
|
|
60
|
+
- Pre-version landing run for `0f6667d`: CI run
|
|
61
|
+
[34070192960](https://github.com/junghan0611/entwurf/actions/runs/34070192960), all three jobs
|
|
62
|
+
success — and this is the first release landing judged by the fourth axis the same release adds:
|
|
63
|
+
the oracle read that run's qualification step, not just its job names.
|
|
64
|
+
|
|
65
|
+
### Notes
|
|
66
|
+
|
|
67
|
+
- **A gate that reads repo history cannot live in the qualification snapshot.** The replay cell first
|
|
68
|
+
read live git objects and went CONTROL-RED inside the snapshot's fresh baseline, costing the whole
|
|
69
|
+
release-gate lane its 17 kills. That is why the fixture carries file lists and the range semantics
|
|
70
|
+
are proven hermetically instead.
|
|
71
|
+
- **Key order in `ci.yml` is a contract.** The body step keeps `run:` as its leading key: cell 8a
|
|
72
|
+
counts that sequence-item form exactly once, and the oracle matches GitHub's rendered
|
|
73
|
+
`Run <command>` step name, so an `if:` placed first — or any `name:` — would break both. Confirmed
|
|
74
|
+
on a real run after the filter landed.
|
|
75
|
+
|
|
76
|
+
## 0.18.1 - 2026-09-06
|
|
77
|
+
|
|
78
|
+
Two lanes, both landing on `main` after `v0.18.0`: the CI evidence-budget stage 1 (#102, from
|
|
79
|
+
research #99) and the dependency bump (#104 — pi, claude-agent-acp, and the OMP adoption rule
|
|
80
|
+
GLG decided to carry with them). They are not one cause; they are one release.
|
|
81
|
+
|
|
82
|
+
### Upgrade note — this one asks something of the operator
|
|
83
|
+
|
|
84
|
+
**The pi floor moved, and entwurf does not install harnesses.** The supported range is now
|
|
85
|
+
`>=0.85.1 <0.86`, so a host still carrying pi 0.84.x is BELOW it. `entwurf setup` says so by
|
|
86
|
+
name — `pi FAIL — detected pi <version> is outside the supported range >=0.85.1 <0.86 — Pi
|
|
87
|
+
wiring not written` — and writes no pi wiring rather than wiring a runtime it cannot vouch
|
|
88
|
+
for. That refusal is the design (Hard Rule 17), not a bug to work around.
|
|
89
|
+
|
|
90
|
+
The order matters:
|
|
91
|
+
|
|
92
|
+
1. **Upgrade pi yourself first.** `pi update`, or `pnpm add -g @earendil-works/pi-coding-agent@0.85.1`
|
|
93
|
+
for a pnpm-global install. entwurf never does this for you.
|
|
94
|
+
2. **Then `entwurf setup`** — one command, as always. This release changes no deployment
|
|
95
|
+
writer (`pi-extensions/lib/meta-session.ts`, the four `install-*` paths and the packaged
|
|
96
|
+
plugins are byte-identical to 0.18.0), so unlike the 0.17.2 and 0.18.0 upgrades there is no
|
|
97
|
+
stale-writer trap here. What setup does need to redo is the pi wiring it refused to write
|
|
98
|
+
while the runtime was below floor.
|
|
99
|
+
3. **Restart any pi session you had open.** A running pi process keeps the binary it started
|
|
100
|
+
with, and this release's changed extension surfaces (`entwurf-control.ts` and four ACP
|
|
101
|
+
modules) are loaded at session start. A live 0.84.4 session stays a 0.84.4 session.
|
|
102
|
+
|
|
103
|
+
Hosts without pi are unaffected: absence is still an explicit setup SKIP, not a failure.
|
|
104
|
+
|
|
105
|
+
### Verification
|
|
106
|
+
|
|
107
|
+
All of the following ran on oracle (Linux, Claude Code 2.1.263, node 24.18.1, pi 0.85.1,
|
|
108
|
+
omp 18.0.0).
|
|
109
|
+
|
|
110
|
+
- **`LIVE=1 ./run.sh release-gate /tmp/entwurf-release-gate-0.18.1.PtUm0r --cut` → `cut: OK`.**
|
|
111
|
+
**MUST: PASS=23 FAIL=0 SKIP=0**, BEHAVIOR: PASS=1 FAIL=0 SKIP=0, exit 0.
|
|
112
|
+
2026-09-06 18:30:51 → 19:23:40 KST (52m49s). Log preserved at
|
|
113
|
+
`<scratch>/release-gate.log`.
|
|
114
|
+
- `check-gate-qualification` as its MUST step: **369/369 KILLED**.
|
|
115
|
+
- `smoke-acp-raw-turn-live` — the Dep-bump track's designated lock for an ACP adapter
|
|
116
|
+
move — PASS on 0.75.1: launch source `package:@agentclientprotocol/claude-agent-acp`
|
|
117
|
+
(not a PATH fallback), model `claude-sonnet-5`, `protocolVersion=1`,
|
|
118
|
+
`stopReason=end_turn`, 65,780 bytes of NDJSON captured.
|
|
119
|
+
- Both #91 drift sentinels green: `smoke-omp-receive-live`, and `smoke-omp-fresh-live`
|
|
120
|
+
with 21 assertions (step 9 clause 7) — on omp **18.0.0**, below the documented weak
|
|
121
|
+
floor of 18.1.10, which is exactly what "the floor records what was proven, not what is
|
|
122
|
+
permitted" means.
|
|
123
|
+
- `pnpm run check:full` on the prepared tree: exit 0, 480s.
|
|
124
|
+
- Pre-push landing run for the implementation HEAD `c247594`: CI run `34018205091`,
|
|
125
|
+
`check` + `install-surface` + `artifact-consumer` all `success` (`check` 34m14s,
|
|
126
|
+
`check:full` 328s, qualification 369/369).
|
|
127
|
+
|
|
128
|
+
**The first `--cut` was BLOCKED, and the reason was not this release.** MUST PASS=20 FAIL=3
|
|
129
|
+
SKIP=0: `smoke-entwurf-chain-live`, `smoke-mux-lifecycle-live` and `smoke-omp-fresh-live`
|
|
130
|
+
each failed waiting on a sibling that never took its turn, and all three drive their sibling
|
|
131
|
+
on `openai-codex/*` while every Claude-rail step passed. Measured at the time: the codex
|
|
132
|
+
weekly window was at **100%**. The chain's own timeout instrumentation is what made this
|
|
133
|
+
readable rather than mysterious — it printed `terminus fixture at timeout: ownerPid=… alive=true
|
|
134
|
+
ownerAlive=true watchArmed=true`, so the mailbox was provably healthy and the chain had simply
|
|
135
|
+
stalled upstream. After the quota reset the same gate went green with no code change. Recorded
|
|
136
|
+
because an exhausted subscription rail looks exactly like a broken product until someone
|
|
137
|
+
measures it.
|
|
138
|
+
|
|
139
|
+
### Changed
|
|
140
|
+
|
|
141
|
+
- **The qualification HEAD runs in the everyday floor; the mutant BODY stays scheduled (#102).**
|
|
142
|
+
Across 549 CI runs the qualification step went red five times and **none of the five came from
|
|
143
|
+
mutant execution** — three died in the head in four or five seconds, two were a gate already red
|
|
144
|
+
on a clean tree (#99 B-3). So the head stops waiting behind the ~28-minute body.
|
|
145
|
+
`check-gate-qualification` gains a `--manifests-only` entrypoint, shipped as
|
|
146
|
+
`run.sh check-gate-manifests` and placed in `check:hermetic` (~8s): runner self-test, manifest-set
|
|
147
|
+
validation against the origin index, and the declared lane inventory — **zero mutants executed and
|
|
148
|
+
no snapshot of this repo**. The body runs the same head first; its contract, output and
|
|
149
|
+
mutant-execution semantics are unchanged.
|
|
150
|
+
- **CI push is filtered to branch refs (#102).** All 66 semver-tag runs in this repo's history
|
|
151
|
+
rebuilt a SHA a branch push had already built, and not one reported a fact its branch run had not
|
|
152
|
+
(the single non-green tag run failed at the same step as its main run, two seconds later). The
|
|
153
|
+
exact-SHA evidence a release quotes is the branch run, which is what the release skill's oracle
|
|
154
|
+
already selects.
|
|
155
|
+
- **`check-omp-birth-hook` joins `check:hermetic` (#102).** It was the one gate a committed mutant
|
|
156
|
+
named that ran nowhere else, so the control-pre of a 28-minute run was the only thing in the repo
|
|
157
|
+
that could notice it going red. `check-release-gate-outcomes` cell 9 now owns that as a contract:
|
|
158
|
+
every mutant-named gate is inside `check:full` **or** states its exclusion in prose an operator
|
|
159
|
+
reads (`scripts/check-setup-qualification.sh` takes the second arm, as its own header declared).
|
|
160
|
+
- **pi runtime 0.84.4 → 0.85.1** (#104): devDep exact ×3, peer range `>=0.85.1 <0.86` ×3, the
|
|
161
|
+
`run.sh` pack-install pins, `pnpm-workspace.yaml`, the lockfile, and the five baseline docs
|
|
162
|
+
`check-dep-versions` binds. **0.85.0 is deliberately skipped**: its published `exports` advertised
|
|
163
|
+
`./client` and `./experimental/plugin` at `dist/*` paths the tarball does not contain, which
|
|
164
|
+
upstream named and fixed in 0.85.1 ("SDK import failures caused by unintentionally publishing
|
|
165
|
+
internal experimental code and dependencies in 0.85.0") by making both subpaths source-only.
|
|
166
|
+
entwurf imports neither, so it never reached us — but the landing coordinate is 0.85.1.
|
|
167
|
+
- **`@agentclientprotocol/claude-agent-acp` 0.73.0 → 0.75.1** (#104). The other two ACP pins do
|
|
168
|
+
**not** move: all four tags v0.73.0–v0.75.1 declare the same `@agentclientprotocol/sdk 1.4.0`,
|
|
169
|
+
`@anthropic-ai/claude-agent-sdk 0.3.257`, `zod ^4.0.0` and `engines.node >=22`, so
|
|
170
|
+
`@anthropic-ai/sdk` stays pinned at `0.100.1` against an unchanged `>=0.93.0` peer floor.
|
|
171
|
+
- **Compaction now reaches operators as a tool lifecycle, not assistant text** (upstream #991, in
|
|
172
|
+
0.75.0). A compacting turn shows a `[tool:start] Compact conversation` / `[tool:…]` notice pair
|
|
173
|
+
where 0.73.0 wrote `Compacting completed.` into the assistant's own text. No mapper change was
|
|
174
|
+
needed and no accounting path is touched; the measurement, the join through the production event
|
|
175
|
+
mapper, and the limits are in `scripts/raw-acp-compaction-measure/README.md` and
|
|
176
|
+
`docs/acp-backend-rail.md` §11-8.
|
|
177
|
+
- **OMP gets a documented *weak* floor instead of a version gate (#91).** entwurf still detects omp
|
|
178
|
+
by presence alone — no `entwurf.ompFloor`, no coherence gate, no exact pin — because a floor is
|
|
179
|
+
the answer to a vendor that fails SILENTLY, which OMP has never been observed to do, and its
|
|
180
|
+
contact surface is guarded by two release-gate MUST smokes that go loudly red. What is recorded
|
|
181
|
+
instead is the last version with a LIVE receipt (**18.1.10**, 2026-09-04 thinkpad), the rule that
|
|
182
|
+
the number moves only when a new receipt exists, and the two sentinels
|
|
183
|
+
(`smoke-omp-fresh-live`, `smoke-omp-receive-live`). Code change: none.
|
|
184
|
+
`docs/setup-clean-host.md` §4b.
|
|
185
|
+
|
|
186
|
+
### Fixed
|
|
187
|
+
|
|
188
|
+
- **An undeclared pi 0.85.x break, caught by our own typecheck (#104).** `pi-tui`'s `Container`
|
|
189
|
+
gained a `private mouseLayout?` in the 0.85.0 mouse work (0.84.4's `Container` had no private
|
|
190
|
+
member at all) while `Box` declares a separate private field of the same name, so TypeScript's
|
|
191
|
+
private-member identity rule broke the `Box → Container` structural assignment that had held
|
|
192
|
+
through 0.84.4 (`TS2322` at `entwurf-control.ts`). Upstream's Breaking section names only
|
|
193
|
+
`createGatewayBindingFetch`. The repair narrows the annotation to what the vendor contract
|
|
194
|
+
actually asks for — `MessageRenderer` returns `Component | undefined` — which is what the helper
|
|
195
|
+
always needed.
|
|
196
|
+
- **The pack-install pin-leak matcher was blind to a new closure member (#104).** pi 0.85.0 added
|
|
197
|
+
`@earendil-works/chord` as a runtime dependency of pi-coding-agent, pi-agent-core, pi-client and
|
|
198
|
+
pi-protocol — inside the runtime closure, with a name carrying no `pi-` prefix. Measured on a real
|
|
199
|
+
0.85.1 install tree, `@earendil-works+chord@0.85.1` sits beside the seven pi entries and the
|
|
200
|
+
`^@earendil-works+pi-` filter did not see it, so an unpinned caret would have floated while
|
|
201
|
+
`check-pack-install` printed a verified pin — the same class as the 2026-07-21 `pi-agent-core`
|
|
202
|
+
incident, and it made the "covers every other pi package" comment false. The matcher now filters on
|
|
203
|
+
the org prefix, chord is pinned explicitly, and the self-test splits into two cells so each
|
|
204
|
+
property fails under its own name. New claim `[QK:PACK-INSTALL-PIN-MATCHER-COVERS-CLOSURE]` with
|
|
205
|
+
its exact-once replant; inventory **368 → 369 mutants across 40 lanes**.
|
|
206
|
+
- **`check-pack-install`'s "every harness absent" row was not actually absent of OMP.** The row
|
|
207
|
+
pins harness probes away with explicit `*_BIN` seams, and `OMP_BIN` was never added when 0.16.0
|
|
208
|
+
admitted OMP — the two sibling fixtures (`smoke-setup-verdict.sh`,
|
|
209
|
+
`check-setup-qualification.sh`) both got it. On a host that HAS `omp` on PATH the row's premise
|
|
210
|
+
was therefore false: setup detected omp, and the omp config/receiver installers refused —
|
|
211
|
+
correctly — because the row also exports `PI_CODING_AGENT_DIR`, which omp reads too, leaving the
|
|
212
|
+
target directory ambiguous. The product was right and the fixture was wrong. It stayed invisible
|
|
213
|
+
because CI runners carry no omp **and** `release_gate()` does not run this gate (it is
|
|
214
|
+
`prepublishOnly` plus the CI install-surface job), so no green floor ever covered it. Measured
|
|
215
|
+
here with a control: a clean clone of the pre-bump HEAD fails at the same row for the same
|
|
216
|
+
reason. The seam is added to both setup rows, and the zero-state probe now requires **five**
|
|
217
|
+
SKIPs so a sixth harness cannot be admitted while this seam is left behind again.
|
|
218
|
+
- **`VERIFY.md` still advertised a pi range two bumps stale, and now nothing can leave it there.**
|
|
219
|
+
It sat outside `check-dep-versions`' `BASELINE_DOCS`, so nothing read it; it has joined that
|
|
220
|
+
list (six docs). Its declaration is a plain range, so the existing range scan binds it — no new
|
|
221
|
+
prose pattern was added for it.
|
|
222
|
+
- **`AGENTS.md` claimed `check-dep-versions` checks the ACP pins.** It does not — it is the **pi**
|
|
223
|
+
pin's oracle and reads no ACP pin (`run.sh:1820-1919`). The ACP pins are owned by
|
|
224
|
+
`check-acp-sdk-surface`, which is the vitest contract `test/acp-sdk-surface.contract.test.ts`;
|
|
225
|
+
the `run.sh` name is a transition shim into it.
|
|
226
|
+
|
|
227
|
+
### Added
|
|
228
|
+
|
|
229
|
+
- **`scripts/raw-acp-compaction-measure/`** — a raw measurement probe (not a gate, in no check
|
|
230
|
+
tier) that drives one live `/compact` turn on the pinned adapter and replays the captured
|
|
231
|
+
notifications through the production event mapper, so the vendor wire and our rendered notice sit
|
|
232
|
+
in one receipt.
|
|
233
|
+
- Four new qualification claims from #102, each with its exact-once replant:
|
|
234
|
+
`MANIFEST-SET-INTEGRITY-REFUSED` and `LANE-INVENTORY-DECLARED` (new `gate-qualification` lane,
|
|
235
|
+
replanting the 08-20 / 08-21 / 08-28 catches), `MUTANT-GATES-INSIDE-FULL-FLOOR` and
|
|
236
|
+
`CI-TAG-PUSH-NOT-REBUILT` (`release-gate` lane).
|
|
237
|
+
|
|
238
|
+
### Notes
|
|
239
|
+
|
|
240
|
+
- **`allowBuilds: esbuild: false`.** chord's only dependency is esbuild, and its arrival made
|
|
241
|
+
`pnpm install` stop on `ERR_PNPM_IGNORED_BUILDS` until the key carried a decision. Denied like the
|
|
242
|
+
other two entries: nothing here executes esbuild.
|
|
243
|
+
- **`bridge-command-boot`'s three agy gates moved to the `run.sh` argv the other manifests use**,
|
|
244
|
+
merging a duplicate group (#102). Group count is unchanged at 52 — the merge removes one and the
|
|
245
|
+
new head gate adds one — so the saving is a 66s control pair traded for a 16s one, not fewer
|
|
246
|
+
groups.
|
|
247
|
+
|
|
7
248
|
## 0.18.0 - 2026-09-04
|
|
8
249
|
|
|
9
250
|
### Fixed
|
package/CONTRIBUTING.md
CHANGED
|
@@ -30,7 +30,7 @@ pnpm check # everyday core (prints wall time; <=60s on the referenc
|
|
|
30
30
|
pnpm run check:full # full deterministic floor — the required PR gate
|
|
31
31
|
```
|
|
32
32
|
|
|
33
|
-
The deterministic floor is tiered (#70). `pnpm check` is the everyday core (biome, tsc, the vitest lanes, and the fast contract gates); `pnpm run check:full` adds the hermetic-integration and package/install tiers —
|
|
33
|
+
The deterministic floor is tiered (#70). `pnpm check` is the everyday core (biome, tsc, the vitest lanes, and the fast contract gates); `pnpm run check:full` adds the hermetic-integration and package/install tiers — including `check-gate-manifests`, the qualification HEAD (runner self-test, manifest-set validation, declared lane inventory, zero mutants executed, ~8s), but not the separately scheduled mutant-EXECUTING body `check-gate-qualification`, which CI runs on a branch push whose diff touched the qualification surface (and unconditionally on dispatch or the weekly schedule) and a gate-changing PR must run once itself. Exact membership is the named `check:*` scripts in `package.json`. Run `check:full` once on your frozen commit candidate — the pre-commit hook (`.husky/pre-commit`) carries only fast static checks (whitespace, lint, typecheck), not the full floor, so a green `pnpm run check:full` before commit is the evidence that your change holds (scheduling contract: AGENTS.md "Verification scheduling").
|
|
34
34
|
|
|
35
35
|
For changes that touch backend launch, session lifecycle, or `_meta` shape, also run
|
|
36
36
|
the live ACP smokes that cover the touched rail — at minimum:
|
package/README.md
CHANGED
|
@@ -157,7 +157,7 @@ cd ~/repos/gh/entwurf
|
|
|
157
157
|
|
|
158
158
|
The full source setup requires Node 24, pnpm, and Python 3 on PATH. Harnesses are
|
|
159
159
|
optional-by-presence: `setup` runs the frozen dependency install, then composes what the operator
|
|
160
|
-
already installed — a compatible `pi` (`>=0.
|
|
160
|
+
already installed — a compatible `pi` (`>=0.85.1 <0.86`), Claude Code, agy, and the Copilot CLI
|
|
161
161
|
each get their wiring completed when detected, an absent harness is an explicit zero-state SKIP,
|
|
162
162
|
and a detected harness that cannot be completed (including a below-floor `pi`) is a named FAIL
|
|
163
163
|
that makes setup exit nonzero. `setup` never installs a harness binary or touches a credential
|
|
@@ -188,7 +188,7 @@ gitignored and may be absent or stale immediately after a checkout or pull.
|
|
|
188
188
|
### Pi adapter / ACP plugin lane
|
|
189
189
|
|
|
190
190
|
To use the `entwurf` provider inside pi, install a compatible pi binary
|
|
191
|
-
separately (`@earendil-works/pi-coding-agent >=0.
|
|
191
|
+
separately (`@earendil-works/pi-coding-agent >=0.85.1 <0.86`). Then point pi at
|
|
192
192
|
the npm-installed package or development clone:
|
|
193
193
|
|
|
194
194
|
```bash
|
|
@@ -433,6 +433,7 @@ pnpm run check:full # full deterministic floor (adds the her
|
|
|
433
433
|
# source-maintainer only — qualification snapshots the git work surface, and both
|
|
434
434
|
# commands are source-contract gates rather than installed operator checks:
|
|
435
435
|
./run.sh check-agy-permission-matrix # AGY permission contract space as a literal table (declared cells + stated exclusions)
|
|
436
|
+
./run.sh check-gate-manifests # the qualification HEAD alone: self-test + manifest-set validation + declared lane inventory, zero mutants run (in check:hermetic)
|
|
436
437
|
./run.sh check-gate-qualification # kill-proof: committed defect mutants must turn their gates red for the claimed reason
|
|
437
438
|
|
|
438
439
|
# agy LIVE acceptance — requires an already-running conversation:
|
|
@@ -450,9 +451,14 @@ LIVE=1 ./run.sh release-gate /tmp/scratch --cut # the single cut gate (MUST + BE
|
|
|
450
451
|
LIVE=1 ENTWURF_ACP_CORTEX_CONNECTION=<conn> ./run.sh smoke-acp-cortex-live # Cortex is on-demand: the aggregate does not re-certify it
|
|
451
452
|
```
|
|
452
453
|
|
|
453
|
-
`pnpm run check:full` includes the AGY permission contract matrix
|
|
454
|
-
|
|
455
|
-
|
|
454
|
+
`pnpm run check:full` includes the AGY permission contract matrix and the qualification
|
|
455
|
+
HEAD (`check-gate-manifests` — runner self-test, manifest-set validation, declared lane
|
|
456
|
+
inventory, zero mutants executed); the committed-mutant EXECUTION is scheduled separately
|
|
457
|
+
(`./run.sh check-gate-qualification` — the CI `check` job runs it on a branch push that touched the qualification surface,
|
|
458
|
+
unconditionally on `workflow_dispatch -f qualify=true` and a weekly schedule, and release-gate
|
|
459
|
+
carries it as a MUST step; a tag push runs no CI at all). A branch run whose body was filtered out
|
|
460
|
+
is not release evidence: the exact-SHA oracle requires the run it reads to carry that step
|
|
461
|
+
concluding success. A gate a
|
|
456
462
|
release touches must kill its known defect for the claimed `[QK:<claim>]` reason —
|
|
457
463
|
the descriptions above name what each smoke covers, and no check count is quality
|
|
458
464
|
evidence on its own. Gate qualification needs the git work surface, while the matrix
|
package/VERIFY.md
CHANGED
|
@@ -40,8 +40,8 @@ Verification here is not a benchmark. In production we exchange short turns and
|
|
|
40
40
|
|
|
41
41
|
### The canonical floor — two entry points
|
|
42
42
|
|
|
43
|
-
- **Deterministic floor — two tiers (#70):** `pnpm check` is the everyday CORE — toolchain (lint + typecheck), the vitest lanes, and the pure-unit / behavioral-contract / source-topology gates plus the cheap static coherence checks. It prints its own total wall time; acceptance is ≤60s on the reference host `oracle` (an operator measurement, never a hard wall-clock gate on arbitrary hosts). `pnpm run check:full` is the FULL deterministic floor — the core plus the hermetic-integration and package/install tiers — and is what the frozen-candidate protocol, push CI, release-gate, and `prepublishOnly` run. Exact membership is the named `check:*` group scripts in `package.json` (the executable SSOT — this document records meaning and principles, not the command list); a gate changes tier by semantic-class decision, never by getting faster or slower.
|
|
44
|
-
- **Discriminating power of that floor:** `./run.sh check-gate-qualification` (scheduled, not ambient: standalone when a lane changes a gate/mutant/matrix, in the CI `check` job on
|
|
43
|
+
- **Deterministic floor — two tiers (#70):** `pnpm check` is the everyday CORE — toolchain (lint + typecheck), the vitest lanes, and the pure-unit / behavioral-contract / source-topology gates plus the cheap static coherence checks. It prints its own total wall time; acceptance is ≤60s on the reference host `oracle` (an operator measurement, never a hard wall-clock gate on arbitrary hosts). `pnpm run check:full` is the FULL deterministic floor — the core plus the hermetic-integration and package/install tiers — and is what the frozen-candidate protocol, push CI, release-gate, and `prepublishOnly` run. Exact membership is the named `check:*` group scripts in `package.json` (the executable SSOT — this document records meaning and principles, not the command list); a gate changes tier by semantic-class decision, never by getting faster or slower. The FULL tier carries the qualification HEAD (`check-gate-manifests`, through `check:hermetic`); the everyday core does not, and neither tier carries the separately scheduled mutant-executing body (`check-gate-qualification`).
|
|
44
|
+
- **Discriminating power of that floor:** `./run.sh check-gate-qualification` (scheduled, not ambient: standalone when a lane changes a gate/mutant/matrix, in the CI `check` job on a branch push that touched the qualification surface, and as a release-gate MUST step — no longer inside the default check chains; a semver TAG push triggers no CI at all, and the exact-SHA evidence a release quotes is whichever run at that commit CARRIES the body — the branch run when the push touched the qualification surface, else a dispatch run; a push that touched none of the qualification surface skips the body, and `workflow_dispatch -f qualify=true` plus a weekly `schedule` run it unconditionally — the exact-SHA release oracle refuses a SHA whose body step did not conclude success) re-plants committed defect mutants (`scripts/mutants/*.json`, one per closed defect class) in an isolated snapshot repo and requires each to turn its gate red **bounded and at its claimed `[QK:<claim>]` signature** — a wrong-reason red fails, a baseline-red control voids the whole group, and the runner is negative-controlled on every run (zero-match/multi-match/survived/wrong-reason/hang/control-red/impurity). This measures whether the deterministic gates still *block* what they claim to block; it is **not a new evidence level** (L0–L5 are untouched) and never substitutes for LIVE evidence. Per-cut records cite claim IDs + killed mutant IDs — "N checks passed" alone is not evidence. `check-agy-permission-matrix` complements it with the enumerated permission contract space (literal cells + stated exclusion rules, oracle independent of the SUT). The gate's HEAD is separable and IS in the floor: `check-gate-manifests` runs the runner self-test, validates the committed manifest set against the origin index, and asserts the declared lane inventory, while executing zero mutants and never snapshotting the repo — three of the five reds qualification has ever produced in CI died in that head, in under five seconds.
|
|
45
45
|
- **Live floor:** `LIVE=1 ./run.sh release-gate <scratch-project-dir> --cut` — `pnpm run check:full` + the v2-native live gates + the ACP plugin acceptance floor. It reports a **two-tier summary**:
|
|
46
46
|
- **MUST tier** (release-blocking — owns the exit code; "green" applies only here): `pnpm run check:full`, `check-gate-qualification`, `smoke-entwurf-v2-matrix-live`, `check-bridge`, `doctor-pi-provider` (#81 — `check-bridge` proves the launcher this checkout SHIPS; this proves the invocation the operator's pi provider actually EXECS, by booting it and requiring the entwurf verb set back, because `command -v` answers yes for a command that exits 127; wired as a step on 2026-08-19 after a relocated pnpm cmd-shim cost a cut sixteen LIVE steps before the same fact surfaced at `smoke-acp-bundled-mcp-live`), the resident-garden-guard zero-token half (record birth / record-keyed socket / attach-on-reopen), the `smoke-acp-*-live` ACP plugin smokes (socket-citizen / raw-turn / overlay / provider / session-reuse / carrier-augment / memory-containment / rgg / mcp / skill / bundled-mcp / v2-send), the axis wired in on 2026-07-31 that the aggregate had simply never listed (`smoke-claude-native-resume-live`), `smoke-entwurf-chain-live` — the cross-harness delivery chain (native Claude Code → pi GPT → pi ACP Sonnet → mailbox terminus) proving sender identity and replyability at every hop plus a real read receipt at the end — the integrated `smoke-mux-lifecycle-live` (its own note below), and the two OMP steps 0.16.0 wired: `smoke-omp-receive-live` (the addressed roundtrip into a live omp citizen; it reads the capability registry and decides its own outcome rather than passing by default) and `smoke-omp-fresh-live` (the clause 7 receipt the release stop now requires). (`smoke-session-id-name` is gone — #50 C3: its `--session-id`/`--name` substrate has no entwurf consumer anymore.)
|
|
47
47
|
- **BEHAVIOR tier** (advisory, non-blocking): the resident-garden-guard positive (a model-in-loop `entwurf_self` turn). A BEHAVIOR FAIL is surfaced with its artifact path but **never blocks the cut**. The lane holds what the model *chooses*, never what our wiring fails to deliver — a gate that TELLS the model which tool to call stays MUST, because its failure is ours — measured 2026-07-24, when the tool turned out to be absent from the session schema in both observed failures (the bundled-MCP readiness gap recorded in `scripts/smoke-acp-v2-send-live.ts`).
|
|
@@ -76,7 +76,7 @@ Do not collapse source, package, fixture, and native-host evidence into one “g
|
|
|
76
76
|
| Source | `pnpm run check:full` + `./run.sh check-gate-qualification` | Does not prove an installed consumer. |
|
|
77
77
|
| Packed install | `check-pack-install` | Real tarball, but checkout-visible. |
|
|
78
78
|
| Linux artifact consumer | required `check-install-container` CI job against one preserved candidate | Fixtures prove package/oracle shape, not a real Claude lifecycle. |
|
|
79
|
-
| Exact release commit | all required CI jobs green at the exact SHA | A different green SHA is not transferable evidence. |
|
|
79
|
+
| Exact release commit | all required CI jobs green, and the `check` job's qualification body step concluded success, at the exact SHA | A different green SHA is not transferable evidence. |
|
|
80
80
|
| LIVE runtime | `LIVE=1 ./run.sh release-gate <scratch> --cut` plus any shipped on-demand backend axis | `--cut` enforces `SKIP=0`; a red wired gate blocks the cut. |
|
|
81
81
|
| Native Claude host | installed strict doctor against a new real session | Missing live join is `NOT CERTIFIED`, not a fixture PASS. |
|
|
82
82
|
| Native agy host | three doctors plus conversation-id-gated native-push round trip | Aggregate release-gate does not own an agy conversation id. |
|
|
@@ -137,7 +137,7 @@ The goal is not merely "invoke Claude Code." We want:
|
|
|
137
137
|
**One install command to remember: `./run.sh setup <project>`.** It is idempotent — re-run the exact same command whenever anything looks wrong. There is no second install surface to juggle: from a clone `setup` runs the whole floor in order.
|
|
138
138
|
|
|
139
139
|
1. `pnpm install` — installs the pinned development dependencies and builds the bridge (source-checkout bootstrap only; an installed package never runs npm/pnpm inside `node_modules`)
|
|
140
|
-
2. pi wiring → `<project>/.pi/settings.json` + user-scope registration — only when a `pi` inside the supported range (`>=0.
|
|
140
|
+
2. pi wiring → `<project>/.pi/settings.json` + user-scope registration — only when a `pi` inside the supported range (`>=0.85.1 <0.86`) is on PATH; absent pi is an explicit zero-state SKIP, a below-floor pi is a detected FAIL. The user-scope entry is owner-recorded (#86 C2): another root's live-or-missing ownership makes this step a zero-write refusal (setup: pi FAIL) that names `takeover-user-scope`; the install-states bind the exact managed settings path (a drifted/symlinked/corrupt target is a zero-write refusal) and the inverse removes only the recorded owner's exact entry; `doctor-pi-package` reports the verdict
|
|
141
141
|
3. Claude meta-bridge global plugin — only when `claude` is on PATH; otherwise skipped cleanly
|
|
142
142
|
4. source stable-bin exposure — including certified `entwurf` → this checkout's `run.sh`, the managed runtime Copilot fresh resolves; helper units are attempted independently and a foreign helper is a named FAIL
|
|
143
143
|
5. agy bridge + exact permission + statusline + `PreInvocation` hook — only when `agy` is on PATH; each adapter is idempotent and independently doctorable
|
package/demo/README.md
CHANGED
|
@@ -139,7 +139,7 @@ SCENE_DELAY=30 FINAL_PAUSE=10 bash demo.sh
|
|
|
139
139
|
|
|
140
140
|
## Prerequisites
|
|
141
141
|
|
|
142
|
-
- `pi` on PATH (current floor 0.
|
|
142
|
+
- `pi` on PATH (current floor 0.85.1)
|
|
143
143
|
- `entwurf` provider configured + auth ready for the selected sender/peer models
|
|
144
144
|
- `asciinema` installed
|
|
145
145
|
- `agg` installed (optional — only for GIF conversion)
|
package/docs/acp-backend-rail.md
CHANGED
|
@@ -93,9 +93,9 @@ undifferentiated "supported" column is what let a Claude PASS read as if it also
|
|
|
93
93
|
| Surface | Declaration | Class | What a green actually says |
|
|
94
94
|
|---|---|---|---|
|
|
95
95
|
| Entwurf package | `0.17.0` | shipped baseline | the package contract these rows belong to |
|
|
96
|
-
| pi runtime | devDep exact `0.
|
|
96
|
+
| pi runtime | devDep exact `0.85.1`, peer `>=0.85.1 <0.86` | **exact** oracle + **closed range** | built and certified against 0.85.1; hosts inside the range are accepted, and the ceiling moves only on measurement |
|
|
97
97
|
| ACP wire SDK | `@agentclientprotocol/sdk 1.4.0` | **exact** | the shared wire oracle both adapters speak |
|
|
98
|
-
| Claude ACP adapter | `@agentclientprotocol/claude-agent-acp 0.
|
|
98
|
+
| Claude ACP adapter | `@agentclientprotocol/claude-agent-acp 0.75.1` | **exact**, bundled | the adapter we ship and certify; resolved before any PATH fallback |
|
|
99
99
|
| Claude Agent SDK | `0.3.257` (transitive) | **exact** oracle | the runtime risk surface behind the adapter |
|
|
100
100
|
| Anthropic SDK | `0.100.1` | **exact**, peer-resolution only | satisfies the Agent SDK peer floor (0.93.0+); never an API client here (gate L4) |
|
|
101
101
|
| Claude Code runtime | `>=2.1.217` (`entwurf.claudeCodeFloor`) | **floor** | below it, hook args are silently dropped; entwurf enforces this itself |
|
|
@@ -144,9 +144,19 @@ different reasons, and collapsing them would hide a real risk**:
|
|
|
144
144
|
- **Advertised but never called.** Some surfaces carry no capability prerequisite at all — the
|
|
145
145
|
`providers/list` / `providers/set` / `providers/disable` trio added in 0.70.0 is advertised
|
|
146
146
|
unconditionally, and 0.71.0–0.73.0 add native subagents, async tasks, message-specific session
|
|
147
|
-
forks, AI-generated session titles and permission-mode kinds on the same footing.
|
|
147
|
+
forks, AI-generated session titles and permission-mode kinds on the same footing. 0.74.0–0.75.1
|
|
148
|
+
extend the same list: the `authStatus` extension (0.75.0, #1080), Markdown-rendered usage
|
|
149
|
+
statistics (0.75.0, #1085) and restored session forks (0.75.1, #1089). The `--hide-claude-auth`
|
|
150
|
+
subscription refusal (0.74.0, #1079) is unreachable for a second reason — `[측정 2026-09-06]`
|
|
151
|
+
entwurf passes that flag nowhere (repo grep, 0 hits). They are
|
|
148
152
|
unreachable only because the common loop never invokes them (nor `logout`). Nothing upstream
|
|
149
153
|
enforces that; it is our own call-site discipline, and it stops holding the moment we use one.
|
|
154
|
+
- **The one 0.73.0 → 0.75.1 change that DOES reach us:** context compaction is now surfaced as a
|
|
155
|
+
synthetic ACP tool lifecycle (0.75.0, #991) — a `tool_call` with `kind: "think"`, title
|
|
156
|
+
`Compact conversation`, and `_meta.contextCompaction` schema v1 — where it used to arrive as
|
|
157
|
+
assistant text. Our mapper routes every `tool_call`/`tool_call_update` through
|
|
158
|
+
`renderToolUpdate` (`event-mapper.ts`), so this is not a type break; what changes is what an
|
|
159
|
+
operator SEES in a compacting turn. See §11-8 for the measurement.
|
|
150
160
|
|
|
151
161
|
Adopting either class requires a separate observed need plus a complete rendering/lifecycle/evidence
|
|
152
162
|
contract. An optional upstream feature is not a core-value gap.
|
|
@@ -257,17 +267,19 @@ caller-session `_meta`, and cross-machine certification.
|
|
|
257
267
|
|
|
258
268
|
A backend can return `newSession` before its declared MCP server is callable. This was
|
|
259
269
|
observed intermittently on the Claude rail and directly on Cortex's private `mcp.json`
|
|
260
|
-
path. Neither `claude-agent-acp` 0.
|
|
270
|
+
path. Neither `claude-agent-acp` 0.75.1 nor the Cortex landing adds a client-side
|
|
261
271
|
readiness fence over a session's declared MCP servers, and entwurf's common loop
|
|
262
272
|
calls `mcpServerStatus()` nowhere.
|
|
263
|
-
(Re-measured at the 0.
|
|
264
|
-
|
|
265
|
-
`
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
`
|
|
270
|
-
|
|
273
|
+
(Re-measured at the 0.73.0 → 0.75.1 bump, not inherited from the previous one — and the
|
|
274
|
+
0.70.0 → 0.73.0 argument is not reused either. `mcpServerStatus` call sites in
|
|
275
|
+
`src/acp-agent.ts` are **2 at both v0.73.0 and v0.75.1** `[측정 2026-09-06, git grep -c]`;
|
|
276
|
+
they first appeared in 0.71.0 via `0cbbaf3` (MCP OAuth, LLM-25012), so the ADAPTER calls it
|
|
277
|
+
where it once did not. Both were re-read at `v0.75.1 src/acp-agent.ts:1736` and `:1829`
|
|
278
|
+
(the 0.73.0 coordinates were `:1618` and `:1711`): the first sits inside
|
|
279
|
+
`authenticateMcpServers` behind `supportsMcpOAuth(query)` and skips every status that is not
|
|
280
|
+
`needs-auth`; the second polls a SINGLE named server to `connected` under an OAuth deadline.
|
|
281
|
+
Neither waits on every declared server before `newSession` returns. That is an auth
|
|
282
|
+
handshake, not a readiness fence, so the boundary below is unchanged. The other reachable-surface findings also re-measured:
|
|
271
283
|
AIR typed failures and the AIR file-change report stay capability-gated and
|
|
272
284
|
unadvertised by entwurf; `providers/set` / `providers/disable` stay advertised
|
|
273
285
|
unconditionally and uncalled; native subagents, async tasks, session forks, session
|
|
@@ -338,6 +350,28 @@ a cut that changes or ships the Cortex rail must run and read its dedicated smok
|
|
|
338
350
|
Per-cut counts, digests, versions, and host observations belong in BASELINE/CHANGELOG,
|
|
339
351
|
not this standing contract.
|
|
340
352
|
|
|
353
|
+
## 11-8. Compaction is a tool lifecycle (0.75.0 onward)
|
|
354
|
+
|
|
355
|
+
The one change in the `0.73.0 → 0.75.1` bump that REACHES the common loop. Upstream #991
|
|
356
|
+
(`f74a517`) replaced compaction's assistant text with a synthetic ACP tool call: `kind:
|
|
357
|
+
"think"`, title `Compact conversation`, `_meta.contextCompaction` schema v1.
|
|
358
|
+
|
|
359
|
+
`[측정 2026-09-06, oracle, adapter 0.75.1, claude-sonnet-5]` one live `/compact` turn emitted
|
|
360
|
+
exactly two notifications (`tool_call` in-progress → `tool_call_update`), and those verbatim
|
|
361
|
+
objects replayed through the production `applyAcpSessionUpdate` produced a
|
|
362
|
+
`[tool:start] Compact conversation` / `[tool:…] Compact conversation` notice pair. No new
|
|
363
|
+
mapper branch is needed — `renderToolUpdate` routes every tool call regardless of `kind` —
|
|
364
|
+
and `_meta.contextCompaction` is dropped by the mapper, so no accounting path sees it.
|
|
365
|
+
|
|
366
|
+
What changed is therefore what an OPERATOR sees in a compacting turn, not what entwurf
|
|
367
|
+
computes. The post-compaction occupancy refresh is NOT new: `v0.73.0 src/acp-agent.ts:3460`
|
|
368
|
+
already emitted a `usage_update` at `compact_boundary` and 0.75.1 still does
|
|
369
|
+
(`dist/acp-agent.js:2740-2752`, now reading `compact_metadata.post_tokens` instead of a
|
|
370
|
+
`getContextUsage` control request), so the shrinking-`used_end` case that
|
|
371
|
+
`backend.ts:1286-1288` names as #96's weak floor gains no new trigger here.
|
|
372
|
+
|
|
373
|
+
Receipt, limits and the `completed`-branch gap: `scripts/raw-acp-compaction-measure/README.md`.
|
|
374
|
+
|
|
341
375
|
## Open work
|
|
342
376
|
|
|
343
377
|
- causal MCP-readiness diagnosis and, only with proof, a backend-invariant fence;
|
package/docs/setup-clean-host.md
CHANGED
|
@@ -12,7 +12,7 @@ only on Linux because its strict live-owner join uses `/proc`.
|
|
|
12
12
|
| npm/pnpm | npm is bundled with Node; pnpm is required for source setup | package or source installation |
|
|
13
13
|
| Python 3 | required by `setup`/`install` (project-path normalization + settings writers); `--help`/`check-bridge` stay Python-free | pi/Claude/agy/Copilot wiring writers |
|
|
14
14
|
| entwurf | global/project-local `@junghanacs/entwurf`, or a source checkout | operator command and garden capability |
|
|
15
|
-
| pi | optional-by-presence, `>=0.
|
|
15
|
+
| pi | optional-by-presence, `>=0.85.1 <0.86` — absent is an explicit setup SKIP, below-floor is a named FAIL | ACP provider, control sockets |
|
|
16
16
|
| Claude Code | optional, **`>=2.1.217`** — the exec-form hook floor | Claude ACP auth/runtime and mailbox-backed native citizen |
|
|
17
17
|
| GitHub Copilot CLI | optional-by-presence, operator-installed and authenticated — absent is an explicit setup SKIP; detected composes all four units (birth/MCP/receiver/footer) | self-fetch citizen and visible fresh |
|
|
18
18
|
| OMP (`omp`) | optional-by-presence, operator-installed — absent is an explicit setup SKIP; detected composes all four units (birth/MCP/`tools.xdev` setting/receiver) | self-fetch citizen and visible fresh (accepted on one host — see §4b) |
|
|
@@ -110,7 +110,7 @@ packageRoot↔installerRoot coupling mismatch and a package/provider managed-pat
|
|
|
110
110
|
Install the exact release floor, then wire the project:
|
|
111
111
|
|
|
112
112
|
```bash
|
|
113
|
-
npm install -g @earendil-works/pi-coding-agent@0.
|
|
113
|
+
npm install -g @earendil-works/pi-coding-agent@0.85.1
|
|
114
114
|
pi --version
|
|
115
115
|
|
|
116
116
|
cd ~/entwurf-smoke
|
|
@@ -118,7 +118,7 @@ entwurf install .
|
|
|
118
118
|
pi -e "$(npm root -g)/@junghanacs/entwurf" --list-models entwurf
|
|
119
119
|
```
|
|
120
120
|
|
|
121
|
-
The supported range is `>=0.
|
|
121
|
+
The supported range is `>=0.85.1 <0.86`. It is a hard minimum: installing this
|
|
122
122
|
release onto a 0.83.x pi host upgrades the runtime rather than keeping the older
|
|
123
123
|
minor. A host using only the external MCP bridge can skip pi until it needs a
|
|
124
124
|
control socket; no delivery rail launches a pi process.
|
|
@@ -239,6 +239,38 @@ announces a tool the MCP hand provides. Install it without them and it will log
|
|
|
239
239
|
`arm-deferred`, give up after ~20s, and `doctor-omp-receive` will name the missing sibling
|
|
240
240
|
as a note rather than a fault.
|
|
241
241
|
|
|
242
|
+
### The OMP version rule — a weak floor, deliberately (#91)
|
|
243
|
+
|
|
244
|
+
**entwurf sets no OMP version floor in code, and will not grow one on schedule.** Detection is
|
|
245
|
+
presence-only (`command -v "${OMP_BIN:-omp}"`); there is no `entwurf.ompFloor`, no coherence
|
|
246
|
+
gate, and no exact pin — unlike Node (`engines.node`), pi (`>=0.85.1 <0.86`) and Claude Code
|
|
247
|
+
(`entwurf.claudeCodeFloor`), each of which has an enforcement point. That asymmetry is a
|
|
248
|
+
decision, not an omission. A floor is the answer to a vendor that fails SILENTLY — Claude Code
|
|
249
|
+
earned one because an older binary validates the exec manifest, drops `args` at runtime, and
|
|
250
|
+
reports success. OMP has never been observed to fail that way, it publishes at close to a
|
|
251
|
+
daily cadence, and when its contact surface breaks the two LIVE smokes go loudly red.
|
|
252
|
+
|
|
253
|
+
What stands instead is a **weak floor: the last version with a LIVE receipt.**
|
|
254
|
+
|
|
255
|
+
> **OMP minimum: `18.1.10`** — `[측정 2026-09-04, thinkpad, Linux x86-64, omp/18.1.10]`
|
|
256
|
+
> `smoke-omp-receive-live` 11 assertions ok (garden `20260904T224103-d36fed`) and
|
|
257
|
+
> `smoke-omp-fresh-live` 21 assertions ok (garden `20260904T224132-351877`, model
|
|
258
|
+
> `openai-codex/gpt-5.6-sol`), with `doctor-omp-receive` PASS and `doctor-omp-mcp` ok. That
|
|
259
|
+
> update skipped one minor and ten patches from 18.0.0 and broke nothing.
|
|
260
|
+
>
|
|
261
|
+
> **This number moves only when a NEW LIVE receipt exists** — never on a release cadence, a
|
|
262
|
+
> changelog read, or a static gate. Run newer OMP freely; the floor records what was proven,
|
|
263
|
+
> not what is permitted.
|
|
264
|
+
>
|
|
265
|
+
> **The drift sentinels are `smoke-omp-fresh-live` and `smoke-omp-receive-live`**, both
|
|
266
|
+
> release-gate MUST steps. Green after an update means keep going. Red means open a NEW issue
|
|
267
|
+
> carrying the first vendor contact point that broke and its reproduction receipt — do not
|
|
268
|
+
> reopen the closed adoption question. If a SILENT failure is ever observed (green smokes over
|
|
269
|
+
> a dead contact point), that is the evidence a real floor needs, and it earns its own issue
|
|
270
|
+
> for the same reason Claude Code's floor exists.
|
|
271
|
+
|
|
272
|
+
The evidence and the reasoning are in **#91**; this paragraph is its durable form.
|
|
273
|
+
|
|
242
274
|
**The receiver arms per session, and only for the visible TUI host.** Opening omp arms it;
|
|
243
275
|
`/new` re-arms it for the replacement citizen and retires the previous one; closing omp
|
|
244
276
|
retires it. A task subagent arms nothing. While nothing is armed, dispatch to that garden
|
|
@@ -123,8 +123,8 @@ export const claudeAdapter = {
|
|
|
123
123
|
},
|
|
124
124
|
// MEASURED (2026-09-02, #93): claude-agent-acp's `usage_update` carries a
|
|
125
125
|
// session-cumulative ESTIMATED cost (`cost.amount = message.total_cost_usd`)
|
|
126
|
-
// and a context-occupancy scalar (`used`; both read at 0.
|
|
127
|
-
// `dist/acp-agent.js:
|
|
126
|
+
// and a context-occupancy scalar (`used`; both read at 0.75.1
|
|
127
|
+
// `dist/acp-agent.js:3467-3482`). Both are measured, so backend.ts seals them.
|
|
128
128
|
// The token partition is NOT declared here: ACP's only token carrier is a
|
|
129
129
|
// per-turn round-trip aggregate, which is not what pi's four fields mean.
|
|
130
130
|
sealsTurnAccounting: true,
|