@junghanacs/entwurf 0.17.2 → 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 +6 -5
- package/CHANGELOG.md +299 -0
- package/CONTRIBUTING.md +1 -1
- package/README.md +9 -5
- package/VERIFY.md +3 -3
- 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/mcp/entwurf-bridge/src/index.js +14 -9
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/acp/backend-adapter.js +2 -2
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/entwurf-deliverability.js +76 -0
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/entwurf-fact-provider.js +9 -6
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/entwurf-facts.js +11 -3
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/entwurf-peer-observe.js +66 -0
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/entwurf-peers-render.js +10 -1
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/entwurf-v2-decider.js +8 -2
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/entwurf-v2-production.js +25 -13
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/entwurf-v2-surface.js +6 -0
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/meta-session.js +38 -0
- package/mcp/entwurf-bridge/dist/pi-extensions/meta-bridge-hook.js +64 -4
- package/mcp/entwurf-bridge/src/index.ts +16 -8
- package/package.json +10 -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/pi-extensions/lib/entwurf-deliverability.ts +104 -0
- package/pi-extensions/lib/entwurf-fact-provider.ts +20 -6
- package/pi-extensions/lib/entwurf-facts.ts +52 -3
- package/pi-extensions/lib/entwurf-peer-observe.ts +77 -0
- package/pi-extensions/lib/entwurf-peers-render.ts +12 -1
- package/pi-extensions/lib/entwurf-v2-decider.ts +26 -8
- package/pi-extensions/lib/entwurf-v2-production.ts +32 -12
- package/pi-extensions/lib/entwurf-v2-surface.ts +6 -0
- package/pi-extensions/lib/meta-session.ts +44 -0
- package/pi-extensions/meta-bridge-hook.ts +72 -3
- package/run.sh +146 -56
- package/scripts/check-acp-usage-accounting.ts +9 -9
- package/scripts/check-bridge-delivery.ts +42 -1
- package/scripts/check-entwurf-fact-provider.ts +22 -1
- package/scripts/check-entwurf-facts.ts +17 -2
- package/scripts/check-entwurf-peers-surface.ts +20 -2
- package/scripts/check-entwurf-self-address.ts +20 -2
- package/scripts/check-entwurf-v2-decider.ts +6 -3
- package/scripts/check-entwurf-v2-matrix.ts +10 -5
- package/scripts/check-entwurf-v2-production.ts +72 -1
- package/scripts/check-gate-qualification.ts +63 -12
- package/scripts/check-meta-hook-session-switch.ts +560 -0
- package/scripts/check-release-gate-outcomes.ts +160 -3
- package/scripts/meta-bridge-doctor.sh +29 -4
- package/scripts/mutants/bridge-command-boot.json +3 -3
- package/scripts/mutants/gate-qualification.json +28 -0
- package/scripts/mutants/meta-hook-session-switch.json +223 -0
- package/scripts/mutants/pack-install.json +14 -3
- package/scripts/mutants/release-gate.json +22 -0
- package/scripts/raw-acp-compaction-measure/README.md +77 -0
- package/scripts/raw-acp-compaction-measure/probe.ts +196 -0
- package/scripts/raw-claude-session-switch/README.md +170 -0
- package/scripts/smoke-acp-cortex-live.ts +22 -2
- package/scripts/smoke-acp-raw-turn-live.ts +1 -1
- package/scripts/smoke-acp-v2-send-live.ts +23 -2
- package/scripts/smoke-entwurf-chain-live.ts +85 -13
- package/scripts/smoke-entwurf-v2-matrix-live.ts +23 -1
- package/scripts/smoke-mux-fresh-call-live.ts +13 -3
package/AGENTS.md
CHANGED
|
@@ -90,7 +90,7 @@ A `--entwurf-control` pi session is a citizen for the same reason a native bridg
|
|
|
90
90
|
|
|
91
91
|
- **control-socket domain (currently `pi`)**: socket liveness, per-target lock, live send, and a dormant cell that rejects.
|
|
92
92
|
- **No relaunch transport exists inside delivery.** `spawn-bg` — a detached, window-less resume child — was removed under the visible-first rule, not deprecated behind a reject, and `entwurf_v2` still starts no process: a dormant socket-domain citizen is refused as `dormant-fire-forget-unsupported`. Reopening one is the separate lifecycle verb `entwurf_resume_call`, which is pi-only (`target-not-pi` otherwise), returns a LAUNCH receipt and an OBSERVATION receipt that are never merged, releases its per-gid lock on every path, and on an unobserved socket leaves the visible window open rather than retrying. No watcher, no retry, no supervisor. Do not re-route it through `entwurf_v2` and do not describe a spawn domain that does not exist.
|
|
93
|
-
- **self-fetch domain (Claude Code, Copilot CLI)**: active receiver + mailbox deliverability; no resume authority. The two arm that receiver through different vendor surfaces — a Claude hook that emits watchPaths, a Copilot first-party extension that holds the watch in a forked child — and the marker records which, because the pid a reader verifies differs.
|
|
93
|
+
- **self-fetch domain (Claude Code, Copilot CLI)**: active receiver + mailbox deliverability; no resume authority. The two arm that receiver through different vendor surfaces — a Claude hook that emits watchPaths, a Copilot first-party extension that holds the watch in a forked child — and the marker records which, because the pid a reader verifies differs. A live marker is not by itself an armed doorbell: where the watch owner IS the process the sender marker is keyed to (`ownerKind: claude-code-cli`), that owner may switch sessions in place, so deliverability also requires its sender marker to still name the same garden. That join is `ownerKind`-scoped by construction — a Copilot watch lives in a forked child with its own pid, so the join does not exist there and must never be applied to it (#101).
|
|
94
94
|
- **native-push domain (currently Antigravity)**: adapter probe + direct injection; no mailbox and no resume authority.
|
|
95
95
|
- `origin: "pi-session" | "meta-session" | "external-mcp"` records sender provenance. It is not the citizen identity schema and not a hierarchy.
|
|
96
96
|
- `entwurf_peers` reports record citizens and liveness facts only. It never embeds routing verbs or socket addresses for peers.
|
|
@@ -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 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.
|
|
@@ -172,6 +172,7 @@ implement → affected focused gates → independent review → one amendment bu
|
|
|
172
172
|
| `pi-extensions/lib/entwurf-v2-*.ts` | v2 contract, decider, transports, runner, production wiring; visible resume keeps launch injected |
|
|
173
173
|
| `pi-extensions/lib/mux-*.ts` | same-tmux placement plus narrow fresh-call and visible-resume launch compositions |
|
|
174
174
|
| `pi-extensions/lib/entwurf-fact*.ts` | record citizens + transport-specific liveness facts |
|
|
175
|
+
| `pi-extensions/lib/entwurf-peer-observe.ts` | the IO half of the observed peer facts (receiver / transcript) |
|
|
175
176
|
| `pi-extensions/lib/native-push/` | native-push adapter/probe/register leaf |
|
|
176
177
|
| `pi-extensions/acp-provider.ts` | `entwurf` provider registration |
|
|
177
178
|
| `pi-extensions/lib/acp/` | ACP adapter rail, config/overlay, augment, turn loop, event mapping |
|
|
@@ -184,8 +185,8 @@ implement → affected focused gates → independent review → one amendment bu
|
|
|
184
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`.
|
|
185
186
|
- Root pi extensions import TypeBox through `@earendil-works/pi-ai`; do not mix direct `@sinclair/typebox` types.
|
|
186
187
|
- MCP/scripts use explicit `.ts` imports where Node strip-types requires them. Installed operator surfaces route to compiled JS.
|
|
187
|
-
- pi runtime range is `>=0.
|
|
188
|
-
- 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.
|
|
189
190
|
|
|
190
191
|
## Working Style
|
|
191
192
|
|
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,305 @@ 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
|
+
|
|
179
|
+
## 0.18.0 - 2026-09-04
|
|
180
|
+
|
|
181
|
+
### Fixed
|
|
182
|
+
|
|
183
|
+
- **A Claude window that changes which session it serves no longer leaves an armed receiver behind
|
|
184
|
+
(#101).** One process serves one garden at a time but can change which: open a bare `claude` and
|
|
185
|
+
then `/resume` or `/clear` inside it, and a second `SessionStart` arrives under the same pid,
|
|
186
|
+
seconds later, naming a different session. The garden it stopped serving kept a receiver marker
|
|
187
|
+
naming a LIVE owner, so dispatch read an armed doorbell nobody held — a sibling's message was
|
|
188
|
+
reported as sent and then sat unread in that mailbox for over 50 minutes (oracle, 2026-09-04; that
|
|
189
|
+
unread letter is what opened the issue).
|
|
190
|
+
- **Deliverability now asks about *now*, not *ever*.** `watchArmed` was a copy of the identity
|
|
191
|
+
match; it is a measurement — the receiver owner's own sender marker
|
|
192
|
+
(`meta-senders/<backend>/<pid>.json`) must still name the same garden. Both consumers, the v2
|
|
193
|
+
production seam and `entwurf_self`, go through one shared composition, so a citizen's
|
|
194
|
+
self-report and dispatch cannot disagree.
|
|
195
|
+
- **The hook retires what it stopped serving** — the marker only, never the record (a record is a
|
|
196
|
+
citizen's identity, not sweepable state), only a marker its own pid owns, and only on an
|
|
197
|
+
arm-capable event. `UserPromptSubmit` cannot emit `watchPaths`, so retiring on a keystroke would
|
|
198
|
+
disarm the session the operator is sitting in with no way to re-arm. The vendor's `source` is
|
|
199
|
+
logged on every line and branched on nowhere: the switch is settled by what is on disk.
|
|
200
|
+
- **The join is scoped by the marker's `ownerKind`, not by backend** — today that is
|
|
201
|
+
`claude-code-cli`. A Copilot watch lives in a forked extension child with its own pid while its
|
|
202
|
+
sender marker carries the CLI's `process.ppid`, so applying the same check there would make
|
|
203
|
+
every Copilot citizen permanently `mailbox-undeliverable`. That is a scope decision with a
|
|
204
|
+
measured reason, not an omission.
|
|
205
|
+
|
|
206
|
+
### Added
|
|
207
|
+
|
|
208
|
+
- **A rejected delivery now names which receiver axis failed (#101).** A bare `mailbox-undeliverable`
|
|
209
|
+
sent one sibling hunting for a live session it had read as dead. The rejection now says whether
|
|
210
|
+
the doorbell is not armed, the owner is not alive, or there is no record.
|
|
211
|
+
- **`entwurf_peers` separates a live citizen from a phantom (#101).** Every claude-code row reads
|
|
212
|
+
`liveness=unsupported`, so two rows were byte-identical whether or not anyone was home. Each row
|
|
213
|
+
now carries two observed facts — `receiver=` (doorbell state) and `transcript=` (whether a
|
|
214
|
+
conversation was ever written):
|
|
215
|
+
|
|
216
|
+
```text
|
|
217
|
+
- 20260904T072015-e09b66 liveness=unsupported receiver=active transcript=exists
|
|
218
|
+
- 20260904T093135-ac7a1a liveness=unsupported receiver=inactive transcript=absent
|
|
219
|
+
```
|
|
220
|
+
|
|
221
|
+
- **`check-meta-hook-session-switch` (28 assertions) and the first mutant lane the Claude hook has
|
|
222
|
+
ever had (#101).** The gate drives the shipped launcher twice under one fake owner pid and
|
|
223
|
+
requires that exactly one of the two gardens is deliverable — and that it is the one the operator
|
|
224
|
+
is sitting in. `scripts/mutants/meta-hook-session-switch.json` carries **17 claims**, 1:1 with the
|
|
225
|
+
gate's `[QK:…]` labels, each re-planting the defect this lane closed and requiring the gate to go
|
|
226
|
+
red at its claimed signature. Three of those six new mutants exist because cross-review found two
|
|
227
|
+
QK labels with no mutant behind them and three real weakenings walking straight through: the
|
|
228
|
+
join's `ownerKind` scope, the sender marker's start-key guard, and its backend equality.
|
|
229
|
+
|
|
230
|
+
### Changed
|
|
231
|
+
|
|
232
|
+
- **One inherited sentence about the resume picker is retired, and it was retired by measurement
|
|
233
|
+
(#101).** The diagnosis said the picker fires `SessionStart` twice — a placeholder id, then the
|
|
234
|
+
picked one. Six LIVE cells on this host (Claude Code 2.1.260, hook log verbatim in
|
|
235
|
+
`scripts/raw-claude-session-switch/README.md`) show it fires **once**, carrying the real id,
|
|
236
|
+
whether the id comes from the picker or from argv. The two-`SessionStart` shape is a bare `claude`
|
|
237
|
+
followed by an in-session `/resume` or `/clear` — which is exactly what the field case did, four
|
|
238
|
+
seconds before its second envelope. The repair is unaffected (either way one pid stops serving one
|
|
239
|
+
garden), so only the prose moved, in four places. Compaction, manual and automatic, re-fires
|
|
240
|
+
`SessionStart` for the **same** native id and retires nothing; the same-garden rule already
|
|
241
|
+
covered it.
|
|
242
|
+
- **A `UserPromptSubmit` envelope is trusted for the receiver join, on a measured footing.** The
|
|
243
|
+
cross-review threat model ("a stale or out-of-order UPS") was withdrawn rather than defended: it
|
|
244
|
+
claimed the sender pointer is untrustworthy for the join while the same pointer stays authoritative
|
|
245
|
+
for sender identity — two incompatible readings of one file. Across the raw lab's four pids, every
|
|
246
|
+
`UserPromptSubmit` named the native id its own pid's preceding `SessionStart` had established,
|
|
247
|
+
**8 of 8**. The arm-capable restriction stays on its own footing.
|
|
248
|
+
- **Three LIVE smokes stopped depending on a fixture the new join reads as retired.** Five smokes
|
|
249
|
+
seeded a receiver marker with no sender marker beside it — three of them release MUSTs — so each
|
|
250
|
+
would have failed on its own fixture rather than on the rail it exists to prove. They now seed
|
|
251
|
+
both and sandbox the senders root, the shape `smoke-mux-lifecycle-live` and `smoke-omp-fresh-live`
|
|
252
|
+
already had. `smoke-entwurf-chain-live` additionally gives its terminus an owner **outside hop 1's
|
|
253
|
+
ancestry**: seeding it under the smoke's own pid put two garden citizens on one host process and
|
|
254
|
+
the bridge refused the hop outright with `ambiguous sender identity`.
|
|
255
|
+
|
|
256
|
+
### Upgrade note
|
|
257
|
+
|
|
258
|
+
**Run `entwurf setup` once after upgrading — every rail, not just Claude.** This release changes
|
|
259
|
+
`pi-extensions/lib/meta-session.ts` and the Claude hook, and **four install paths deploy that
|
|
260
|
+
file** — `install-meta-bridge` (Claude), `install-omp-bridge` and `install-omp-receive` (OMP),
|
|
261
|
+
`install-copilot-bridge` (Copilot). Every one of them present on the host now carries a STALE
|
|
262
|
+
writer until it is re-installed, and its own doctor says so by name. Re-installing only the Claude
|
|
263
|
+
rail leaves the others stale, and that does not surface until a LIVE gate turns red — measured in
|
|
264
|
+
the 0.17.2 cut, where it blocked `smoke-omp-receive-live` and made the first `--cut` run BLOCKED.
|
|
265
|
+
|
|
266
|
+
`entwurf setup` is presence-driven and re-synthesizes exactly the units this host has, which is why
|
|
267
|
+
it is the upgrade command rather than any single `install-*`. An already-open Claude Code session
|
|
268
|
+
keeps the old manifest until it restarts — and, for this release specifically, an already-open
|
|
269
|
+
session also keeps the old hook, which is the code that retires a switched-away receiver.
|
|
270
|
+
|
|
271
|
+
### Verification
|
|
272
|
+
|
|
273
|
+
All of the following ran on oracle (Linux, Claude Code 2.1.260, node 24.18.1, pi 0.84.4, omp 18.0.0).
|
|
274
|
+
|
|
275
|
+
- **`pnpm run check:full` — exit 0**, 440s on the prepared tree and 446s inside the release gate.
|
|
276
|
+
- **`LIVE=1 ./run.sh release-gate /tmp/entwurf-release-gate-0.18.0c.xZlKjZ --cut` — `cut: OK`,
|
|
277
|
+
exit 0.** **MUST PASS=23 FAIL=0 SKIP=0**, **BEHAVIOR PASS=1 FAIL=0 SKIP=0**. Run 18:57→19:48 KST
|
|
278
|
+
on `faee8f6`, with `env -u CLAUDE_CONFIG_DIR -u PI_SESSION_ID -u PI_AGENT_ID`. Log:
|
|
279
|
+
`/tmp/entwurf-release-gate-0.18.0c.xZlKjZ/release-gate.log`. It carried `check:full` and
|
|
280
|
+
`check-gate-qualification` (**364/364 KILLED**, up from 347 — the 17 new claims are this lane's
|
|
281
|
+
`MHSS-*`) as MUST steps.
|
|
282
|
+
- **This lane's own gate: `check-meta-hook-session-switch` — 28 assertions passed**, and all 17
|
|
283
|
+
`MHSS-*` mutants killed at their claimed signatures inside that qualification run.
|
|
284
|
+
- **The three LIVE smokes whose fixtures this lane changed are green**, including
|
|
285
|
+
`smoke-entwurf-chain-live` — **24 assertions**, four citizens across three harnesses, and its new
|
|
286
|
+
pre-flight cell `fixture: the terminus is a deliverable citizen at the moment the chain starts`
|
|
287
|
+
passed before the chain ran.
|
|
288
|
+
- **One unattributed `smoke-entwurf-chain-live` failure is on the record and is NOT closed.** During
|
|
289
|
+
the lane (2026-09-04 16:58 KST) one run rejected at hop 3 with `mailbox-undeliverable (observed
|
|
290
|
+
liveness: unsupported)`; the runs before and after it passed and it has not reproduced. A
|
|
291
|
+
start-key race and an early idle-owner exit were excluded by measurement; a memory-pressure
|
|
292
|
+
hypothesis is neither confirmed nor refuted (no OOM or kill entries in the host journal for that
|
|
293
|
+
window). The instrument that will split the next occurrence shipped in this release — the fixture
|
|
294
|
+
pre-flight assertion above, plus a `terminus fixture at timeout:` line naming owner liveness and
|
|
295
|
+
both receiver facts.
|
|
296
|
+
- **The first `--cut` attempt of this cut was BLOCKED, and the cause was operator error, not the
|
|
297
|
+
product.** `check-gate-qualification` aborted with `origin HEAD changed during qualification`
|
|
298
|
+
because a commit was created while the gate was running. Every other MUST step in that run passed
|
|
299
|
+
(`MUST PASS=22 FAIL=1 SKIP=0`). The run above is the re-measurement on a frozen HEAD. One LIVE
|
|
300
|
+
gate run before that was killed by the host harness's low-memory watchdog rather than by any
|
|
301
|
+
assertion, and was re-run under tmux.
|
|
302
|
+
- **Exact-SHA CI on the pre-version HEAD `e56eee0`** — `check`, `install-surface`,
|
|
303
|
+
`artifact-consumer` all `success`.
|
|
304
|
+
Run: https://github.com/junghan0611/entwurf/actions/runs/33853363923
|
|
305
|
+
|
|
7
306
|
## 0.17.2 - 2026-09-03
|
|
8
307
|
|
|
9
308
|
### Added
|
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 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.
|
|
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,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
|
|
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 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.
|
|
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.
|
|
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;
|