@junghanacs/entwurf 0.18.0 → 0.18.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/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. Neither tier includes `check-gate-qualification`, which is scheduled separately (below).
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` 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 every push, and release-gate carries it as a MUST step.
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 every branch push, and release-gate carries it as a MUST step. 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; the same SHA's branch run already carries every job, and that branch run is the exact-SHA evidence a release quotes.
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.84.4 <0.85` with devDep exact `0.84.4`; 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 checked by `check-dep-versions`/`check-acp-sdk-surface`; do not describe a dependency bump as a behavioral fix without evidence.
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,178 @@ All notable changes to this project will be documented here. Format follows [Kee
4
4
 
5
5
  ## Unreleased
6
6
 
7
+ ## 0.18.1 - 2026-09-06
8
+
9
+ Two lanes, both landing on `main` after `v0.18.0`: the CI evidence-budget stage 1 (#102, from
10
+ research #99) and the dependency bump (#104 — pi, claude-agent-acp, and the OMP adoption rule
11
+ GLG decided to carry with them). They are not one cause; they are one release.
12
+
13
+ ### Upgrade note — this one asks something of the operator
14
+
15
+ **The pi floor moved, and entwurf does not install harnesses.** The supported range is now
16
+ `>=0.85.1 <0.86`, so a host still carrying pi 0.84.x is BELOW it. `entwurf setup` says so by
17
+ name — `pi FAIL — detected pi <version> is outside the supported range >=0.85.1 <0.86 — Pi
18
+ wiring not written` — and writes no pi wiring rather than wiring a runtime it cannot vouch
19
+ for. That refusal is the design (Hard Rule 17), not a bug to work around.
20
+
21
+ The order matters:
22
+
23
+ 1. **Upgrade pi yourself first.** `pi update`, or `pnpm add -g @earendil-works/pi-coding-agent@0.85.1`
24
+ for a pnpm-global install. entwurf never does this for you.
25
+ 2. **Then `entwurf setup`** — one command, as always. This release changes no deployment
26
+ writer (`pi-extensions/lib/meta-session.ts`, the four `install-*` paths and the packaged
27
+ plugins are byte-identical to 0.18.0), so unlike the 0.17.2 and 0.18.0 upgrades there is no
28
+ stale-writer trap here. What setup does need to redo is the pi wiring it refused to write
29
+ while the runtime was below floor.
30
+ 3. **Restart any pi session you had open.** A running pi process keeps the binary it started
31
+ with, and this release's changed extension surfaces (`entwurf-control.ts` and four ACP
32
+ modules) are loaded at session start. A live 0.84.4 session stays a 0.84.4 session.
33
+
34
+ Hosts without pi are unaffected: absence is still an explicit setup SKIP, not a failure.
35
+
36
+ ### Verification
37
+
38
+ All of the following ran on oracle (Linux, Claude Code 2.1.263, node 24.18.1, pi 0.85.1,
39
+ omp 18.0.0).
40
+
41
+ - **`LIVE=1 ./run.sh release-gate /tmp/entwurf-release-gate-0.18.1.PtUm0r --cut` → `cut: OK`.**
42
+ **MUST: PASS=23 FAIL=0 SKIP=0**, BEHAVIOR: PASS=1 FAIL=0 SKIP=0, exit 0.
43
+ 2026-09-06 18:30:51 → 19:23:40 KST (52m49s). Log preserved at
44
+ `<scratch>/release-gate.log`.
45
+ - `check-gate-qualification` as its MUST step: **369/369 KILLED**.
46
+ - `smoke-acp-raw-turn-live` — the Dep-bump track's designated lock for an ACP adapter
47
+ move — PASS on 0.75.1: launch source `package:@agentclientprotocol/claude-agent-acp`
48
+ (not a PATH fallback), model `claude-sonnet-5`, `protocolVersion=1`,
49
+ `stopReason=end_turn`, 65,780 bytes of NDJSON captured.
50
+ - Both #91 drift sentinels green: `smoke-omp-receive-live`, and `smoke-omp-fresh-live`
51
+ with 21 assertions (step 9 clause 7) — on omp **18.0.0**, below the documented weak
52
+ floor of 18.1.10, which is exactly what "the floor records what was proven, not what is
53
+ permitted" means.
54
+ - `pnpm run check:full` on the prepared tree: exit 0, 480s.
55
+ - Pre-push landing run for the implementation HEAD `c247594`: CI run `34018205091`,
56
+ `check` + `install-surface` + `artifact-consumer` all `success` (`check` 34m14s,
57
+ `check:full` 328s, qualification 369/369).
58
+
59
+ **The first `--cut` was BLOCKED, and the reason was not this release.** MUST PASS=20 FAIL=3
60
+ SKIP=0: `smoke-entwurf-chain-live`, `smoke-mux-lifecycle-live` and `smoke-omp-fresh-live`
61
+ each failed waiting on a sibling that never took its turn, and all three drive their sibling
62
+ on `openai-codex/*` while every Claude-rail step passed. Measured at the time: the codex
63
+ weekly window was at **100%**. The chain's own timeout instrumentation is what made this
64
+ readable rather than mysterious — it printed `terminus fixture at timeout: ownerPid=… alive=true
65
+ ownerAlive=true watchArmed=true`, so the mailbox was provably healthy and the chain had simply
66
+ stalled upstream. After the quota reset the same gate went green with no code change. Recorded
67
+ because an exhausted subscription rail looks exactly like a broken product until someone
68
+ measures it.
69
+
70
+ ### Changed
71
+
72
+ - **The qualification HEAD runs in the everyday floor; the mutant BODY stays scheduled (#102).**
73
+ Across 549 CI runs the qualification step went red five times and **none of the five came from
74
+ mutant execution** — three died in the head in four or five seconds, two were a gate already red
75
+ on a clean tree (#99 B-3). So the head stops waiting behind the ~28-minute body.
76
+ `check-gate-qualification` gains a `--manifests-only` entrypoint, shipped as
77
+ `run.sh check-gate-manifests` and placed in `check:hermetic` (~8s): runner self-test, manifest-set
78
+ validation against the origin index, and the declared lane inventory — **zero mutants executed and
79
+ no snapshot of this repo**. The body runs the same head first; its contract, output and
80
+ mutant-execution semantics are unchanged.
81
+ - **CI push is filtered to branch refs (#102).** All 66 semver-tag runs in this repo's history
82
+ rebuilt a SHA a branch push had already built, and not one reported a fact its branch run had not
83
+ (the single non-green tag run failed at the same step as its main run, two seconds later). The
84
+ exact-SHA evidence a release quotes is the branch run, which is what the release skill's oracle
85
+ already selects.
86
+ - **`check-omp-birth-hook` joins `check:hermetic` (#102).** It was the one gate a committed mutant
87
+ named that ran nowhere else, so the control-pre of a 28-minute run was the only thing in the repo
88
+ that could notice it going red. `check-release-gate-outcomes` cell 9 now owns that as a contract:
89
+ every mutant-named gate is inside `check:full` **or** states its exclusion in prose an operator
90
+ reads (`scripts/check-setup-qualification.sh` takes the second arm, as its own header declared).
91
+ - **pi runtime 0.84.4 → 0.85.1** (#104): devDep exact ×3, peer range `>=0.85.1 <0.86` ×3, the
92
+ `run.sh` pack-install pins, `pnpm-workspace.yaml`, the lockfile, and the five baseline docs
93
+ `check-dep-versions` binds. **0.85.0 is deliberately skipped**: its published `exports` advertised
94
+ `./client` and `./experimental/plugin` at `dist/*` paths the tarball does not contain, which
95
+ upstream named and fixed in 0.85.1 ("SDK import failures caused by unintentionally publishing
96
+ internal experimental code and dependencies in 0.85.0") by making both subpaths source-only.
97
+ entwurf imports neither, so it never reached us — but the landing coordinate is 0.85.1.
98
+ - **`@agentclientprotocol/claude-agent-acp` 0.73.0 → 0.75.1** (#104). The other two ACP pins do
99
+ **not** move: all four tags v0.73.0–v0.75.1 declare the same `@agentclientprotocol/sdk 1.4.0`,
100
+ `@anthropic-ai/claude-agent-sdk 0.3.257`, `zod ^4.0.0` and `engines.node >=22`, so
101
+ `@anthropic-ai/sdk` stays pinned at `0.100.1` against an unchanged `>=0.93.0` peer floor.
102
+ - **Compaction now reaches operators as a tool lifecycle, not assistant text** (upstream #991, in
103
+ 0.75.0). A compacting turn shows a `[tool:start] Compact conversation` / `[tool:…]` notice pair
104
+ where 0.73.0 wrote `Compacting completed.` into the assistant's own text. No mapper change was
105
+ needed and no accounting path is touched; the measurement, the join through the production event
106
+ mapper, and the limits are in `scripts/raw-acp-compaction-measure/README.md` and
107
+ `docs/acp-backend-rail.md` §11-8.
108
+ - **OMP gets a documented *weak* floor instead of a version gate (#91).** entwurf still detects omp
109
+ by presence alone — no `entwurf.ompFloor`, no coherence gate, no exact pin — because a floor is
110
+ the answer to a vendor that fails SILENTLY, which OMP has never been observed to do, and its
111
+ contact surface is guarded by two release-gate MUST smokes that go loudly red. What is recorded
112
+ instead is the last version with a LIVE receipt (**18.1.10**, 2026-09-04 thinkpad), the rule that
113
+ the number moves only when a new receipt exists, and the two sentinels
114
+ (`smoke-omp-fresh-live`, `smoke-omp-receive-live`). Code change: none.
115
+ `docs/setup-clean-host.md` §4b.
116
+
117
+ ### Fixed
118
+
119
+ - **An undeclared pi 0.85.x break, caught by our own typecheck (#104).** `pi-tui`'s `Container`
120
+ gained a `private mouseLayout?` in the 0.85.0 mouse work (0.84.4's `Container` had no private
121
+ member at all) while `Box` declares a separate private field of the same name, so TypeScript's
122
+ private-member identity rule broke the `Box → Container` structural assignment that had held
123
+ through 0.84.4 (`TS2322` at `entwurf-control.ts`). Upstream's Breaking section names only
124
+ `createGatewayBindingFetch`. The repair narrows the annotation to what the vendor contract
125
+ actually asks for — `MessageRenderer` returns `Component | undefined` — which is what the helper
126
+ always needed.
127
+ - **The pack-install pin-leak matcher was blind to a new closure member (#104).** pi 0.85.0 added
128
+ `@earendil-works/chord` as a runtime dependency of pi-coding-agent, pi-agent-core, pi-client and
129
+ pi-protocol — inside the runtime closure, with a name carrying no `pi-` prefix. Measured on a real
130
+ 0.85.1 install tree, `@earendil-works+chord@0.85.1` sits beside the seven pi entries and the
131
+ `^@earendil-works+pi-` filter did not see it, so an unpinned caret would have floated while
132
+ `check-pack-install` printed a verified pin — the same class as the 2026-07-21 `pi-agent-core`
133
+ incident, and it made the "covers every other pi package" comment false. The matcher now filters on
134
+ the org prefix, chord is pinned explicitly, and the self-test splits into two cells so each
135
+ property fails under its own name. New claim `[QK:PACK-INSTALL-PIN-MATCHER-COVERS-CLOSURE]` with
136
+ its exact-once replant; inventory **368 → 369 mutants across 40 lanes**.
137
+ - **`check-pack-install`'s "every harness absent" row was not actually absent of OMP.** The row
138
+ pins harness probes away with explicit `*_BIN` seams, and `OMP_BIN` was never added when 0.16.0
139
+ admitted OMP — the two sibling fixtures (`smoke-setup-verdict.sh`,
140
+ `check-setup-qualification.sh`) both got it. On a host that HAS `omp` on PATH the row's premise
141
+ was therefore false: setup detected omp, and the omp config/receiver installers refused —
142
+ correctly — because the row also exports `PI_CODING_AGENT_DIR`, which omp reads too, leaving the
143
+ target directory ambiguous. The product was right and the fixture was wrong. It stayed invisible
144
+ because CI runners carry no omp **and** `release_gate()` does not run this gate (it is
145
+ `prepublishOnly` plus the CI install-surface job), so no green floor ever covered it. Measured
146
+ here with a control: a clean clone of the pre-bump HEAD fails at the same row for the same
147
+ reason. The seam is added to both setup rows, and the zero-state probe now requires **five**
148
+ SKIPs so a sixth harness cannot be admitted while this seam is left behind again.
149
+ - **`VERIFY.md` still advertised a pi range two bumps stale, and now nothing can leave it there.**
150
+ It sat outside `check-dep-versions`' `BASELINE_DOCS`, so nothing read it; it has joined that
151
+ list (six docs). Its declaration is a plain range, so the existing range scan binds it — no new
152
+ prose pattern was added for it.
153
+ - **`AGENTS.md` claimed `check-dep-versions` checks the ACP pins.** It does not — it is the **pi**
154
+ pin's oracle and reads no ACP pin (`run.sh:1820-1919`). The ACP pins are owned by
155
+ `check-acp-sdk-surface`, which is the vitest contract `test/acp-sdk-surface.contract.test.ts`;
156
+ the `run.sh` name is a transition shim into it.
157
+
158
+ ### Added
159
+
160
+ - **`scripts/raw-acp-compaction-measure/`** — a raw measurement probe (not a gate, in no check
161
+ tier) that drives one live `/compact` turn on the pinned adapter and replays the captured
162
+ notifications through the production event mapper, so the vendor wire and our rendered notice sit
163
+ in one receipt.
164
+ - Four new qualification claims from #102, each with its exact-once replant:
165
+ `MANIFEST-SET-INTEGRITY-REFUSED` and `LANE-INVENTORY-DECLARED` (new `gate-qualification` lane,
166
+ replanting the 08-20 / 08-21 / 08-28 catches), `MUTANT-GATES-INSIDE-FULL-FLOOR` and
167
+ `CI-TAG-PUSH-NOT-REBUILT` (`release-gate` lane).
168
+
169
+ ### Notes
170
+
171
+ - **`allowBuilds: esbuild: false`.** chord's only dependency is esbuild, and its arrival made
172
+ `pnpm install` stop on `ERR_PNPM_IGNORED_BUILDS` until the key carried a decision. Denied like the
173
+ other two entries: nothing here executes esbuild.
174
+ - **`bridge-command-boot`'s three agy gates moved to the `run.sh` argv the other manifests use**,
175
+ merging a duplicate group (#102). Group count is unchanged at 52 — the merge removes one and the
176
+ new head gate adds one — so the saving is a 66s control pair traded for a 16s one, not fewer
177
+ groups.
178
+
7
179
  ## 0.18.0 - 2026-09-04
8
180
 
9
181
  ### 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 — all but the separately scheduled `check-gate-qualification`, which CI runs on every push 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").
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 every branch push 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.84.4 <0.85`), Claude Code, agy, and the Copilot CLI
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.84.4 <0.85`). Then point pi at
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,12 @@ 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; the committed-mutant
454
- gate qualification is scheduled separately (`./run.sh check-gate-qualification` — the CI
455
- `check` job runs it on every push, and release-gate carries it as a MUST step). A gate a
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 every branch push,
458
+ and release-gate carries it as a MUST step; a tag push runs no CI, since the same SHA's
459
+ branch run already carries every job). A gate a
456
460
  release touches must kill its known defect for the claimed `[QK:<claim>]` reason —
457
461
  the descriptions above name what each smoke covers, and no check count is quality
458
462
  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. Both tiers exclude the separately scheduled `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 every push, and as a release-gate MUST step — no longer inside the default check chains) 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).
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 every branch push, and as a release-gate MUST step — no longer inside the default check chains; a semver TAG push triggers no CI at all, because the same SHA's branch run already carries every job and is the exact-SHA evidence a release quotes) 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`).
@@ -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.84.3 <0.85`) 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
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.84.4)
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)
@@ -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.84.4`, peer `>=0.84.4 <0.85` | **exact** oracle + **closed range** | built and certified against 0.84.4; hosts inside the range are accepted, and the ceiling moves only on measurement |
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.73.0` | **exact**, bundled | the adapter we ship and certify; resolved before any PATH fallback |
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. They are
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.73.0 nor the Cortex landing adds a client-side
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.70.0 → 0.73.0 bump, not inherited from the previous one.
264
- `mcpServerStatus` call sites in `src/acp-agent.ts` went 0 2, new in 0.71.0 via
265
- `0cbbaf3` (MCP OAuth, LLM-25012) so the ADAPTER now calls it where it previously
266
- did not. Both sites were read at `v0.73.0 src/acp-agent.ts:1618` and `:1711`: each is
267
- gated behind `supportsMcpOAuth(query)`, and the polling one waits only on a server
268
- that already reported `needs-auth`, never on every declared server before
269
- `newSession` returns. That is an auth handshake, not a readiness fence, so the
270
- boundary below is unchanged. The other reachable-surface findings also re-measured:
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;
@@ -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.84.4 <0.85` — absent is an explicit setup SKIP, below-floor is a named FAIL | ACP provider, control sockets |
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.84.4
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.84.4 <0.85`. It is a hard minimum: installing this
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.73.0
127
- // `dist/acp-agent.js:2918-2924`). Both are measured, so backend.ts seals them.
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,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@junghanacs/entwurf",
3
- "version": "0.18.0",
3
+ "version": "0.18.1",
4
4
  "description": "Garden-citizen dispatch substrate and meta-bridge for Claude Code, Codex, Antigravity, and pi harnesses.",
5
5
  "license": "MIT",
6
6
  "author": {
@@ -82,23 +82,23 @@
82
82
  "claudeCodeFloor": ">=2.1.217"
83
83
  },
84
84
  "dependencies": {
85
- "@agentclientprotocol/claude-agent-acp": "0.73.0",
85
+ "@agentclientprotocol/claude-agent-acp": "0.75.1",
86
86
  "@agentclientprotocol/sdk": "1.4.0",
87
87
  "@anthropic-ai/sdk": "0.100.1",
88
88
  "@modelcontextprotocol/sdk": "^1.12.1",
89
89
  "zod": "^3.25.0 || ^4.0.0"
90
90
  },
91
91
  "peerDependencies": {
92
- "@earendil-works/pi-ai": ">=0.84.4 <0.85",
93
- "@earendil-works/pi-coding-agent": ">=0.84.4 <0.85",
94
- "@earendil-works/pi-tui": ">=0.84.4 <0.85",
92
+ "@earendil-works/pi-ai": ">=0.85.1 <0.86",
93
+ "@earendil-works/pi-coding-agent": ">=0.85.1 <0.86",
94
+ "@earendil-works/pi-tui": ">=0.85.1 <0.86",
95
95
  "typebox": "*"
96
96
  },
97
97
  "devDependencies": {
98
98
  "@biomejs/biome": "^2.4.13",
99
- "@earendil-works/pi-ai": "0.84.4",
100
- "@earendil-works/pi-coding-agent": "0.84.4",
101
- "@earendil-works/pi-tui": "0.84.4",
99
+ "@earendil-works/pi-ai": "0.85.1",
100
+ "@earendil-works/pi-coding-agent": "0.85.1",
101
+ "@earendil-works/pi-tui": "0.85.1",
102
102
  "@types/node": "^24.3.0",
103
103
  "husky": "^9.1.7",
104
104
  "rregex": "1.13.1",
@@ -166,7 +166,7 @@
166
166
  "check:toolchain": "pnpm lint && pnpm typecheck",
167
167
  "check:vitest": "./run.sh check-mux-fresh-call && ./run.sh check-acp-sdk-surface",
168
168
  "check:contracts": "./run.sh check-shell-quote && ./run.sh check-entwurf-session-identity && ./run.sh check-meta-session && ./run.sh check-meta-v3-record && ./run.sh check-mailbox-receipt-state && ./run.sh check-entwurf-capabilities && ./run.sh check-harness-admission-parity && ./run.sh check-capability-bundle-reach && ./run.sh check-meta-mailbox-state-write && ./run.sh check-meta-receiver-marker && ./run.sh check-meta-capability-source && ./run.sh check-model-lock && ./run.sh check-dep-versions && ./run.sh check-node-floor-coherence && ./run.sh check-claude-floor-coherence && ./run.sh check-copilot-statusline && ./run.sh check-pi-import-surface && ./run.sh check-env-namespace && ./run.sh check-pi-runtime-version && ./run.sh check-pi-preflight && ./run.sh check-project-trust-handler && ./run.sh check-entwurf-v2-contract && ./run.sh check-entwurf-v2-lock && ./run.sh check-entwurf-v2-decider && ./run.sh check-entwurf-v2-matrix && ./run.sh check-entwurf-v2-release && ./run.sh check-entwurf-v2-send && ./run.sh check-entwurf-v2-send-fallback && ./run.sh check-entwurf-v2-mailbox && ./run.sh check-entwurf-v2-native-push && ./run.sh check-entwurf-v2-runner && ./run.sh check-entwurf-v2-production && ./run.sh check-entwurf-v2-surface && ./run.sh check-entwurf-bridge-pi-free && ./run.sh check-entwurf-resume-args && ./run.sh check-resume-launch-identity && ./run.sh check-mux-placement && ./run.sh check-mux-launch && ./run.sh check-mux-resume-call && ./run.sh check-mux-parent-artifact && ./run.sh check-mux-launcher-fence && ./run.sh check-entwurf-v2-visible-resume && ./run.sh check-entwurf-facts && ./run.sh check-control-socket-path && ./run.sh check-socket-discovery && ./run.sh check-meta-listing && ./run.sh check-entwurf-fact-provider && ./run.sh check-entwurf-peers-surface && ./run.sh check-entwurf-self-address && ./run.sh check-entwurf-deliverability && ./run.sh check-native-push-adapter && ./run.sh check-native-push-register && ./run.sh check-auth-boundary && ./run.sh check-acp-overlay && ./run.sh check-acp-tool-surface && ./run.sh check-acp-event-mapper && ./run.sh check-acp-prompt-builder && ./run.sh check-acp-config && ./run.sh check-acp-session-store && ./run.sh check-acp-carrier-augment",
169
- "check:hermetic": "./run.sh check-bridge-delivery && ./run.sh smoke-pi-attach && ./run.sh check-fresh-cut-gate && ./run.sh check-hook-launch-topology && ./run.sh check-meta-hook-session-switch && ./run.sh check-copilot-birth-hook && ./run.sh check-copilot-receive-arm && ./run.sh check-copilot-launch && ./run.sh check-meta-identity-consumers && ./run.sh check-socket-probe && ./run.sh smoke-meta-honesty && ./run.sh check-meta-doctor-oracle && ./run.sh check-agy-permission-matrix && ./run.sh smoke-agy-statusline-state && ./run.sh smoke-copilot-statusline-state && ./run.sh smoke-copilot-mcp-state && ./run.sh smoke-omp-bridge-state && ./run.sh smoke-omp-mcp-state && ./run.sh smoke-omp-receive-state && ./run.sh check-omp-receive-arm && ./run.sh check-omp-fresh-preflight && ./run.sh smoke-agy-hooks-state && ./run.sh smoke-pi-provider-state && ./run.sh smoke-user-scope-citizen && ./run.sh smoke-meta-prune && ./run.sh smoke-meta-keyset-guard && ./run.sh check-meta-manifest-schema && ./run.sh check-entwurf-control-rpc && ./run.sh check-entwurf-bridge-boot && ./run.sh check-probe-bridge-command && ./run.sh check-meta-facts && ./run.sh check-agy-sender-identity && ./run.sh check-acp-provider-surface && ./run.sh check-acp-stop-reason && ./run.sh check-acp-prompt-lifecycle && ./run.sh check-acp-usage-accounting && ./run.sh check-acp-launch-namespace && ./run.sh check-acp-stream-hooks && ./run.sh check-acp-backend-preflight && ./run.sh check-acp-session-reuse && ./run.sh check-release-gate-outcomes && ./run.sh check-probe-ordering && ./run.sh check-probe-cli-shim && ./run.sh check-acp-cortex",
169
+ "check:hermetic": "./run.sh check-bridge-delivery && ./run.sh smoke-pi-attach && ./run.sh check-fresh-cut-gate && ./run.sh check-hook-launch-topology && ./run.sh check-meta-hook-session-switch && ./run.sh check-copilot-birth-hook && ./run.sh check-copilot-receive-arm && ./run.sh check-copilot-launch && ./run.sh check-meta-identity-consumers && ./run.sh check-socket-probe && ./run.sh smoke-meta-honesty && ./run.sh check-meta-doctor-oracle && ./run.sh check-agy-permission-matrix && ./run.sh smoke-agy-statusline-state && ./run.sh smoke-copilot-statusline-state && ./run.sh smoke-copilot-mcp-state && ./run.sh smoke-omp-bridge-state && ./run.sh smoke-omp-mcp-state && ./run.sh smoke-omp-receive-state && ./run.sh check-omp-birth-hook && ./run.sh check-omp-receive-arm && ./run.sh check-omp-fresh-preflight && ./run.sh smoke-agy-hooks-state && ./run.sh smoke-pi-provider-state && ./run.sh smoke-user-scope-citizen && ./run.sh smoke-meta-prune && ./run.sh smoke-meta-keyset-guard && ./run.sh check-meta-manifest-schema && ./run.sh check-entwurf-control-rpc && ./run.sh check-entwurf-bridge-boot && ./run.sh check-probe-bridge-command && ./run.sh check-meta-facts && ./run.sh check-agy-sender-identity && ./run.sh check-acp-provider-surface && ./run.sh check-acp-stop-reason && ./run.sh check-acp-prompt-lifecycle && ./run.sh check-acp-usage-accounting && ./run.sh check-acp-launch-namespace && ./run.sh check-acp-stream-hooks && ./run.sh check-acp-backend-preflight && ./run.sh check-acp-session-reuse && ./run.sh check-gate-manifests && ./run.sh check-release-gate-outcomes && ./run.sh check-probe-ordering && ./run.sh check-probe-cli-shim && ./run.sh check-acp-cortex",
170
170
  "check:package": "./run.sh check-install-surface && ./run.sh smoke-meta-install-state && ./run.sh smoke-agy-install-state && ./run.sh smoke-setup-verdict && ./run.sh check-pack-pin-matcher && ./run.sh check-package-source-routing && ./run.sh check-install-preflight && ./run.sh check-pack"
171
171
  },
172
172
  "pi": {
@@ -79,7 +79,7 @@ import type {
79
79
  MessageRenderer,
80
80
  } from "@earendil-works/pi-coding-agent";
81
81
  import { getMarkdownTheme, type Theme } from "@earendil-works/pi-coding-agent";
82
- import { Box, type Container, Markdown, Spacer, Text } from "@earendil-works/pi-tui";
82
+ import { Box, type Component, Markdown, Spacer, Text } from "@earendil-works/pi-tui";
83
83
  import { ENTWURF_SENT_MESSAGE_TYPE } from "../protocol.js";
84
84
  import { CONTROL_SOCKET_SUFFIX, controlSocketPathIn, defaultControlSocketDir } from "./lib/control-socket-path.js";
85
85
  import {
@@ -548,7 +548,17 @@ interface SentBoxData {
548
548
  // `expanded` truncates the body the same way as renderSessionMessage so a
549
549
  // large send shows the same preview shape as a large receive. operators
550
550
  // reading the transcript should not need different mental models.
551
- const buildSentMessageBox = (data: SentBoxData, expanded: boolean, theme: Theme): Container => {
551
+ // Return type is `Component`, the interface `MessageRenderer` actually asks for
552
+ // (`Component | undefined`, read at pi-coding-agent
553
+ // `dist/core/extensions/types.d.ts:889`) — NOT the concrete `Container`.
554
+ // `[측정 2026-09-06]` pi 0.85.0's mouse work gave `Container` a `private mouseLayout?`
555
+ // (`pi-tui dist/tui.d.ts:198`; 0.84.4's `Container` had no private member at all), and
556
+ // `Box` declares a SEPARATE private `mouseLayout` of its own. TypeScript only accepts a
557
+ // private member from the same declaration, so the structural assignment `Box -> Container`
558
+ // that held through 0.84.4 became TS2322 at 0.85.x. This was an UNDECLARED break — the
559
+ // upstream Breaking section names only `createGatewayBindingFetch`. Annotating the shared
560
+ // interface is the honest fix: nothing here ever needed Container's own surface.
561
+ const buildSentMessageBox = (data: SentBoxData, expanded: boolean, theme: Theme): Component => {
552
562
  let body = data.body || "(no content)";
553
563
  if (!expanded) {
554
564
  const lines = body.split("\n");
@@ -46,8 +46,8 @@ import type { AcpTextBlock } from "./context.js";
46
46
  * shape) and never onto those four. A field rename upstream fails the typecheck
47
47
  * here rather than silently zeroing the operator's cache-effect badge.
48
48
  */
49
- /** One `_meta.quota.token_count` row (claude-agent-acp 0.73.0
50
- * `dist/acp-agent.js:5750-5765`). `cachedInputTokens` is cache READS — the name
49
+ /** One `_meta.quota.token_count` row (claude-agent-acp 0.75.1
50
+ * `dist/acp-agent.js:6493-6502`). `cachedInputTokens` is cache READS — the name
51
51
  * differs from `usage.cachedReadTokens` because the shape is shared with
52
52
  * codex-acp; `cachedWriteTokens` is Claude's extra sibling. */
53
53
  export type AcpQuotaTokenCount = {
@@ -64,7 +64,7 @@ export type AcpPromptResponse = {
64
64
  /** Vendor-private, version-pinned. `_meta` is a standard ACP extension slot
65
65
  * whose values a client may not assume, and `quota` is NOT in
66
66
  * claude-agent-acp's exported types — it is produced by the private
67
- * `turnQuotaMeta()` (read at 0.73.0 `dist/acp-agent.js:5738-5748`). Read
67
+ * `turnQuotaMeta()` (read at 0.75.1 `dist/acp-agent.js:6476-6485`). Read
68
68
  * defensively, never structurally required, and re-measure on a pin move. */
69
69
  _meta?: {
70
70
  quota?: {