@junghanacs/entwurf 0.24.0 → 0.25.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.
Files changed (75) hide show
  1. package/CHANGELOG.md +564 -0
  2. package/CONTRIBUTING.md +1 -1
  3. package/DELIVERY.md +24 -1
  4. package/README.md +2 -2
  5. package/VERIFY.md +20 -2
  6. package/demo/README.md +5 -2
  7. package/docs/acp-backend-rail.md +49 -2
  8. package/docs/setup-clean-host.md +4 -4
  9. package/mcp/entwurf-bridge/dist/mcp/entwurf-bridge/src/index.js +5 -4
  10. package/mcp/entwurf-bridge/dist/pi-extensions/lib/control-send-receipt.js +101 -0
  11. package/mcp/entwurf-bridge/dist/pi-extensions/lib/entwurf-v2-contract.js +6 -2
  12. package/mcp/entwurf-bridge/dist/pi-extensions/lib/entwurf-v2-production.js +17 -1
  13. package/mcp/entwurf-bridge/dist/pi-extensions/lib/entwurf-v2-runner.js +4 -0
  14. package/mcp/entwurf-bridge/dist/pi-extensions/lib/entwurf-v2-send.js +53 -6
  15. package/mcp/entwurf-bridge/dist/pi-extensions/lib/entwurf-v2-surface.js +38 -3
  16. package/mcp/entwurf-bridge/dist/pi-extensions/lib/herdr-fresh-call.js +13 -3
  17. package/mcp/entwurf-bridge/dist/pi-extensions/lib/herdr-placement.js +11 -0
  18. package/mcp/entwurf-bridge/dist/protocol.js +0 -7
  19. package/mcp/entwurf-bridge/dist/scripts/doctor-pi-provider.js +40 -3
  20. package/mcp/entwurf-bridge/dist/scripts/herdr-rails.mjs +72 -0
  21. package/mcp/entwurf-bridge/src/index.ts +5 -4
  22. package/package.json +10 -9
  23. package/pi-extensions/entwurf-control.ts +27 -154
  24. package/pi-extensions/lib/compaction-send-guard.ts +5 -3
  25. package/pi-extensions/lib/control-send-receipt.ts +108 -0
  26. package/pi-extensions/lib/entwurf-v2-contract-schema.ts +1 -1
  27. package/pi-extensions/lib/entwurf-v2-contract.ts +6 -2
  28. package/pi-extensions/lib/entwurf-v2-production.ts +19 -1
  29. package/pi-extensions/lib/entwurf-v2-runner.ts +23 -1
  30. package/pi-extensions/lib/entwurf-v2-send.ts +82 -6
  31. package/pi-extensions/lib/entwurf-v2-surface.ts +42 -3
  32. package/pi-extensions/lib/herdr-fresh-call.ts +13 -3
  33. package/pi-extensions/lib/herdr-placement.ts +11 -0
  34. package/protocol.js +0 -8
  35. package/run.sh +202 -33
  36. package/scripts/check-entwurf-v2-surface.ts +289 -10
  37. package/scripts/check-gate-qualification.ts +2354 -11
  38. package/scripts/check-herdr-fresh-call.ts +10 -2
  39. package/scripts/check-herdr-placement.ts +51 -0
  40. package/scripts/check-herdr-plugin-build.ts +11 -4
  41. package/scripts/check-herdr-plugin.ts +745 -38
  42. package/scripts/check-mux-launcher-fence.ts +37 -0
  43. package/scripts/check-pi-launch.ts +7 -4
  44. package/scripts/check-release-gate-outcomes.ts +165 -0
  45. package/scripts/doctor-pi-provider.ts +44 -4
  46. package/scripts/herdr-rails.mjs +75 -0
  47. package/scripts/lib/qualification-acceptance.ts +146 -0
  48. package/scripts/lib/qualification-artifact.ts +359 -0
  49. package/scripts/lib/qualification-collection.ts +384 -0
  50. package/scripts/lib/qualification-gh.ts +231 -0
  51. package/scripts/lib/qualification-ledger.ts +669 -0
  52. package/scripts/lib/qualification-oracle-core.ts +279 -0
  53. package/scripts/lib/qualification-receipt.ts +561 -0
  54. package/scripts/lib/qualification-release.ts +271 -0
  55. package/scripts/meta-bridge-state.py +18 -1
  56. package/scripts/mutants/bridge-command-boot.json +38 -0
  57. package/scripts/mutants/control-send-receipt.json +235 -0
  58. package/scripts/mutants/herdr-fresh-call.json +4 -4
  59. package/scripts/mutants/herdr-plugin-build.json +7 -11
  60. package/scripts/mutants/herdr-plugin.json +177 -9
  61. package/scripts/mutants/meta-retire.json +22 -0
  62. package/scripts/mutants/pack-install.json +4 -4
  63. package/scripts/mutants/pi-floor.json +17 -0
  64. package/scripts/mutants/qualification-ledger.json +489 -0
  65. package/scripts/mutants/release-gate.json +48 -0
  66. package/scripts/mutants/retired-sent-surface.json +32 -0
  67. package/scripts/mutants/v2-surface.json +7 -7
  68. package/scripts/qualification-oracle.ts +124 -0
  69. package/scripts/smoke-codex-fresh-live.ts +94 -13
  70. package/scripts/smoke-herdr-fresh-call-live.ts +15 -8
  71. package/scripts/smoke-herdr-raw-install-live.sh +66 -4
  72. package/scripts/smoke-meta-install-state.sh +107 -1
  73. package/scripts/smoke-mux-lifecycle-live.ts +9 -2
  74. package/scripts/smoke-pi-provider-state.sh +106 -0
  75. package/scripts/smoke-setup-verdict.sh +18 -2
package/CHANGELOG.md CHANGED
@@ -4,6 +4,570 @@ All notable changes to this project will be documented here. Format follows [Kee
4
4
 
5
5
  ## Unreleased
6
6
 
7
+ ## 0.25.1 - 2026-09-30
8
+
9
+ ### Added
10
+
11
+ - **Per-group qualification receipts, a composite ledger, and an offline exact-SHA oracle (#124,
12
+ development tooling — not release policy).** `check-gate-qualification --group <argv> --receipt
13
+ <path>` runs one exact-argv group through the unchanged control → mutant → restore → control body
14
+ and writes a sealed `PARTIAL/local` receipt; `--groups <JSON|all> --collect <dir>` runs several in
15
+ one process and writes an inventory (`collection.json` + `gNNN.json`), never a verdict;
16
+ `--compose` builds a local ledger whose groups are MEASURED, FAIL, INHERITED-UNVERIFIED or UNRUN
17
+ (CARRIED is defined and never populated — no audited dependency projection exists), with verdicts
18
+ RED / NOT-QUALIFIED / RISK-PENDING / COMPOSITE-GREEN. A dispatch-only `ci.yml` step
19
+ (`workflow_dispatch -f composite_groups=…`) uploads a collection artifact, and
20
+ `scripts/qualification-oracle.ts` composes an exact-SHA ledger from GitHub run, job and artifact
21
+ evidence inside a clean clone of that SHA. **Release acceptance is unchanged:**
22
+ `verify-exact-ci.sh` plus the full qualification body stay the release MUST until #124 P3, and no
23
+ release path calls the composite oracle. **Unobserved:** no collection artifact has been uploaded
24
+ yet, so the real GitHub zip layout, the CI work-surface cross-check and the collector's CI
25
+ environment are unmeasured; the reader fails closed on anything it does not recognize. New mutant
26
+ lane `qualification-ledger` (42 QK claims); the committed set is 824 mutants across 63 lanes.
27
+ Frozen-candidate evidence before commit (host `oracle`, work surface `ccfb8bbe9cd2…`):
28
+ qualification body 824/824 killed in 5,053 s, `check:full` exit 0 in 617 s. Issue #124 stays open.
29
+
30
+ ### Changed
31
+
32
+ - **Herdr plugin runtime lock returns to `herdr-checkout` for the 0.25.1 candidate window.** An npm
33
+ lock must name a version that is already published and coherent with the checkout's
34
+ `package.json` (`check-herdr-runtime-bootstrap` `[QK:HRB-LOCK-SOURCE-CLOSED]`), so the 0.25.0 npm
35
+ pin cannot ride a 0.25.1 cut. The npm pin returns as a follow-up once 0.25.1 is on the registry
36
+ (the dd84ac0 pattern).
37
+ - **GitHub release notes are soft-wrapped at M6 extraction** (`entwurf-release`): paragraphs and
38
+ list items are joined, fenced code stays byte-for-byte, and the extraction refuses notes whose text
39
+ differs from the CHANGELOG section by anything beyond whitespace.
40
+
41
+ - **Herdr plugin 0.5.1 is the follow-up for the #120-aware raw-install LIVE oracle.**
42
+ Plugin 0.5.0 already shipped on the `v0.25.0` tag and its npm-pinned follow-up commit
43
+ `113ca5327074b77eb5d81453b1a277afcdf4ddca` was publicly reachable. The first clean-host
44
+ test of that commit completed install, npm integrity, pi/Claude activation and record-backed
45
+ birth, then falsely marked the status pane red: it still required `herdr-agent-list-failed` at
46
+ column zero, while #120 moved that name into the owner-labelled `[4] CITIZENS` block. The
47
+ corrected assertion anchors both that block and its indented failure line; the same remote
48
+ 0.5.0 commit then passed the full first-user path without production-code changes (receipt
49
+ below). The manifest alone advances to 0.5.1 here to distinguish this verified follow-up from
50
+ the already public 0.5.0. **This is not yet a LIVE acceptance claim for 0.5.1**; its remote
51
+ commit must be tested separately before a physical-host install is handed to GLG.
52
+
53
+ - **Herdr plugin 0.5.0 pins its runtime to the published npm `@junghanacs/entwurf@0.25.0`.**
54
+ The `v0.25.0` tag already carries `plugins/herdr/herdr-plugin.toml` at 0.5.0; this post-publish
55
+ follow-up replaces its candidate-window `herdr-checkout` lock with the exact published npm
56
+ version and sha512. `npm view @junghanacs/entwurf@0.25.0 dist.integrity` and an independent
57
+ SHA-512 over the preserved accepted candidate
58
+ (`/tmp/entwurf-release-candidate-0.25.0.pyaGKq/junghanacs-entwurf-0.25.0.tgz`, sha256
59
+ `6ed3d67c8db30b71572738b9cddce38c9cf12d73c4f494b48b1475235918a968`) agree on
60
+ `sha512-6Cm5qFZiR8OtqSszcfv/bhxhFlLL0dmeBOnBp3wnnL5JOI6e68anEG3SUuUXKK7CuCaM4S+ft7H8vgVKw4vDhg==`;
61
+ npm's published `dist.shasum` matches the accepted candidate's SHA-1, and registry `latest` is
62
+ 0.25.0 while `repair` remains 0.12.8-repair.1. The lock and its three committed-lock gate cells
63
+ move together (forward of the 0.25.0 candidate inverse); source switches still require explicit
64
+ deactivation. Focused `check-herdr-plugin-build`, `check-herdr-runtime-bootstrap`,
65
+ `check-herdr-plugin`, `check-herdr-plugin-profile`, `check-dep-versions`, and
66
+ `check-gate-manifests` passed; the last confirms 782 mutants across 62 lanes without executing
67
+ qualification. These are local pin/protocol receipts, **not** a public-remote first-user-path
68
+ receipt: that journey needs the committed pin on a reachable ref and must be measured separately.
69
+ - **Public-remote first-user path (2026-09-23, after pin push).** In a clean `node:24` container,
70
+ `LIVE=1 ENTWURF_REQUIRE_DOCKER=1 ./run.sh smoke-herdr-raw-install-live --ref main`
71
+ resolved `main` to `113ca5327074b77eb5d81453b1a277afcdf4ddca`, read plugin manifest 0.5.0,
72
+ fetched `kind=npm @junghanacs/entwurf@0.25.0` at tarball SHA-256
73
+ `6ed3d67c8db30b71572738b9cddce38c9cf12d73c4f494b48b1475235918a968`, wired pi and
74
+ Claude, born a record-backed pi citizen without a model turn, read the status fan with and
75
+ without a Herdr server, and deactivated/reinstalled successfully. **PASS**; full log
76
+ `/tmp/entwurf-herdr050-raw-install-113ca53-amended.log`, sha256
77
+ `406ff681166e596c9b358ffbac9129fe32c9c7878c874d177ebc3f1cab661788` (decisive lines
78
+ above are reproduced here for cross-host readers). The first attempt on this same remote SHA
79
+ failed only at the fan oracle: #120 now reports `herdr-agent-list-failed` inside the `[4] CITIZENS`
80
+ block, not at column zero. `scripts/smoke-herdr-raw-install-live.sh` now anchors that block and
81
+ its indented failure line; the corrected run passed with no product-source change. The older
82
+ `smoke-herdr-plugin-build-live` still asserts the **checkout** carrier and is not evidence for
83
+ this npm pin — running it here reported the expected source mismatch, not an install failure.
84
+
85
+ ### Verification
86
+
87
+ Prepared tree over `8b92e09` (CHANGELOG + `package.json` 0.25.1, uncommitted and frozen while the
88
+ gates ran), host `oracle`, 2026-09-30 KST, ambient identity carriers stripped (`ENTWURF_*`,
89
+ `CLAUDE*`, `PI_SESSION_ID`, `PI_AGENT_ID`).
90
+
91
+ - **Deterministic floor (P4):** `pnpm run build-bridge` then `pnpm run check:full`,
92
+ `[check:full] total elapsed 624s exit 0`, `[check-pack] 550 files in tarball`.
93
+ - **Aggregate LIVE floor (P5):** `LIVE=1 ./run.sh release-gate <scratch> --cut`, scratch
94
+ `/tmp/entwurf-release-gate-0.25.1.pDnZeR`, log `release-gate.log` sha256
95
+ `9a7e698cafa4fd476301be2e61b291c88ec40b059955c97aae8d829c3d213a7c`, 6,022 s:
96
+ **MUST PASS=24 FAIL=0 SKIP=0**, **BEHAVIOR PASS=1 FAIL=0 SKIP=0**, `cut: OK`. Inside it,
97
+ `check-gate-qualification` reported `qualified claims: 824/824 killed` and
98
+ `[gate-qualification] ok` (824 mutants, 63 lanes), and `smoke-codex-fresh-live` ran inside the
99
+ aggregate for the first time with the operator-supplied triple: app-server PID `2786140`,
100
+ started by this release lane with `./run.sh codex-app-server` in its own tmux session `$261`
101
+ (the native process owning the control socket, read from that pane's own process tree, never a
102
+ search), Codex `gpt-5.6-luna`, Pi `openai-codex/gpt-5.6-terra` →
103
+ `64 assertions ok`. The app-server was stopped after the gate.
104
+ - **Pre-LIVE doctors:** meta-bridge, pi-package, the four Codex doctors, the three OMP doctors and
105
+ agy-bridge exit 0; `doctor-copilot-bridge` exits 1 with `copilot CLI missing from PATH` (Copilot is
106
+ not a release MUST rail on this host).
107
+ - **Host residue (P9, at the gate's verdict):** 628 → 619 owned `/tmp` dirs; 9 roots / 1.1 G
108
+ reclaimed, none minted by this run (7 `check-probe-ordering` roots dated 2026-09-23..29, one
109
+ `entwurf-s2b-overlay`, one 1.1 G `entwurf-hpbl` from 2026-09-23). The recurring
110
+ `check-probe-ordering` residue names a gate that still leaks on some path. One reparented process
111
+ holds a `/tmp` path and was named, not killed: the operator's own
112
+ `emacs --init-directory=/tmp/agent-emacs-init --daemon`.
113
+ - **Not claimed:** exact-SHA CI and the preserved-artifact acceptance belong to `make`; the #124
114
+ composite collection has not been dispatched, so no composite ledger exists for this release.
115
+
116
+ ## 0.25.0 - 2026-09-23
117
+
118
+ ### Added
119
+
120
+ - **The Herdr status pane stopped reporting presence and started reporting capability, in four
121
+ blocks that never merge (#120 P1-A).** `herdr plugin pane open --plugin junghan0611.entwurf
122
+ --entrypoint status` now draws HERDR INTEGRATION, ACTIVATION, RAILS and CITIZENS, and each block
123
+ carries three things that do not merge: `owner` (who is speaking — Herdr's listing is Herdr's
124
+ word about Herdr, the ledger is Entwurf's word about its own install, the rails table is this
125
+ package's own declaration), `observedAt` (`now`, `install-time`, or `static`) and its own
126
+ `outcome`. **There is deliberately no aggregate** — no reducer, no `overall`, no readiness word:
127
+ three of the four blocks answer at different times, so one token over them would have to pick one
128
+ time and lie about the other two, and a host whose Herdr integration is current, whose ledger was
129
+ written last week, and whose runtime has since been deleted is exactly the case a summary word
130
+ erases. A block that could not be read says so in its own voice with the gatherer's named code
131
+ rather than degrading to an empty section, because an empty section and a failed read look
132
+ identical on a screen and only one of them is safe to act on. The render is a pure data-to-data
133
+ leaf (`plugins/herdr/lib/capability-report.mjs`: no `fs`, no `spawnSync`, no `process.env`, no
134
+ dynamic import, no clock) and the gathering that must open files and import an installed module
135
+ lives in `activation-evidence.mjs`, so it stays visible WHICH artifact answered — the checkout or
136
+ the runtime. The measured blocker repaired on the way in: the writer's ledger is XDG **state**,
137
+ not XDG **data**, and the first candidate crashed before drawing any block on a normal
138
+ writer-produced ledger. Herdr `outdated|needs-repair` is block [1]'s own named red while
139
+ `not-installed` stays a reported skip; only `phase=active` grants a runtime fallback, and
140
+ `activating|deactivating` remain visible install-time receipts that grant no binary. THREE READS
141
+ / ONE OPEN is restored behind exactly one spawn callsite. Receipts: `check-herdr-plugin` 48
142
+ assertions, and that lane 24/24 mutants killed in the implementer's scratch mirror and again in
143
+ the coordinator's body.
144
+
145
+ ### Changed
146
+
147
+ - **A control-socket send now reports the acceptance boundary it actually got, and that
148
+ vocabulary is closed (#120 P2).** `entwurf_v2` answered `sent` whether the receiver was idle or
149
+ busy, and prose in four places called the busy path an interrupt or an immediate delivery.
150
+ Neither queue is an interrupt: a busy receiver drains steering after each turn and follow-ups
151
+ only when its inner loop ends, so a later steer overtakes every earlier follow-up and there is no
152
+ order between the two. Sender-visible acceptance is now its own closed axis — `sent |
153
+ queued-steer | queued-follow-up | accepted-unknown-boundary` — preserved through send →
154
+ structured error → runner → surface, while the route/release `SendFinalOutcome` is unchanged.
155
+ `sent` means the turn was TRIGGERED, not that the model has seen the text, and both queues are
156
+ volatile process memory an abort drops. A fallback socket preserves that boundary; a fallback
157
+ mailbox names its own durable enqueue receipt; dirty-lock receipts keep the actual boundary, file
158
+ and refusal reason instead of flattening them. The receiver wire no longer emits a bare
159
+ `delivered:true` or the unused `deliveredAs`. The oracle is the installed `pi-agent-core` itself
160
+ (`test/pi-queue.oracle.test.ts`, now on `check:full` with its exact core pin gated to the pi
161
+ floor): cross-mode overtaking, one-at-a-time drain, no mid-flight merge, and abort loss, proven
162
+ with zero model, network or ACP child turn. `DELIVERY.md`, `docs/acp-backend-rail.md`, the demo
163
+ README and the `entwurf-dev` skill were corrected to those same four words. Three proof holes
164
+ were closed before acceptance: dirty-lock end-to-end field loss, a `test/**` oracle that was not
165
+ on the public floor, and a reachability checker a comment could satisfy.
166
+
167
+ - **pi runtime floor 0.86.0 → 0.87.1 (#120 P4, landed in two measured steps).** Four exact dev
168
+ pins (including P2's direct `pi-agent-core` queue oracle), three closed peer ranges
169
+ (`>=0.87.1 <0.88`), the
170
+ eight-package install/workspace constellation (seven `pi-*` packages plus `chord`), the
171
+ pack-install version matcher, and the support declarations in README, the Herdr install docs, mux
172
+ docs, setup docs, VERIFY and the ACP support matrix now name one floor.
173
+ `[QK:PI-FLOOR-SINGLE-SOURCE]` closes a measured static hole: before this, `check-dep-versions`
174
+ did not read `pnpm-workspace.yaml`, so one stale release-age row failed only later, during
175
+ installation. The five declared 0.87 breaking changes were re-measured rather than relabelled and
176
+ production contact is zero — and the three type fences are what confirm that, not grep
177
+ (`tsc --noEmit`, `-p scripts`, `-p mcp`, all rc=0). The installed 0.87 extension context still
178
+ exposes `isIdle()` / `signal` at the same coordinates and still has no `isCompacting`; the
179
+ `pi-agent-core` queue drain coordinates MOVED (`agent.js` `:98-99` → `:96-97`, `agent-loop.js`
180
+ steering drain `:159` → `:186`, follow-up drain `:162-166` → `:191-197`) while all four
181
+ queue-behaviour QKs stayed green; the sandbox CLI still refuses an unregistered
182
+ `--entwurf-control`. A deterministic gate now writes a REAL 0.87 session JSONL through the
183
+ installed public `SessionManager` with zero model, network or child process and proves basename
184
+ id = header id = manager id, so `check-herdr-placement` re-measures that axis on every run rather
185
+ than carrying a hand-made receipt. **0.86.1 was skipped with a reason:** its coding-agent
186
+ CHANGELOG has no Breaking Changes section at all and `packages/agent` 0.86.1 is an empty entry,
187
+ so it touches none of our surfaces and its provider/CLI improvements arrive inside 0.87.0 anyway.
188
+ ROADMAP's dated ledger carries the per-file sha256 pairs (written with real `packages/...`
189
+ paths, after a prior entry recorded an empty-file hash for a path that did not exist) and the
190
+ per-breaking-change contact receipts.
191
+ **The second step, 2026-09-23: 0.87.0 → 0.87.1, and it is the floor this release declares.**
192
+ 0.87.0 was already superseded on npm (`dist-tags.latest` said 0.87.1) while the prepared
193
+ candidate still named 0.87.0, and no gate reads upstream `latest`, so a person found the gap
194
+ rather than a check. The patch carries **no Breaking Changes section in any of the seven
195
+ package changelogs**, and the contact measurement says why: all six load-bearing files this
196
+ repo tracks are byte-identical across the two tags (their sha256 pairs match the values the
197
+ 0.87.0 entry above recorded, so the ledger cross-checks itself), `packages/agent` changed only
198
+ its CHANGELOG and `package.json`, and the whole `coding-agent/src` diff is three files. Each
199
+ was judged, not skimmed: `--mode` now rejects an invalid value instead of ignoring it, and
200
+ every `--mode` this repo passes pi is `rpc` or `json` (the other `--mode` hits are OMP's CLI,
201
+ a different vendor under the same flag name); the xAI default moved to Grok 4.7 and nothing
202
+ here depends on a provider default; the third is compaction summary wording, which entwurf
203
+ does not own on any rail (#94). Because `pi-agent-core` shipped no source change, the P2
204
+ queue coordinates could not move — and that was re-measured on the installed 0.87.1 rather
205
+ than inferred: `agent.js:96-97`, `agent-loop.js:186` and `:191-197` are where they were. The
206
+ per-floor hand receipts were re-taken too, additively: the sandbox CLI still refuses an
207
+ unregistered `--entwurf-control` byte-identically, and the extension context still declares
208
+ `isIdle()` at `:233` and `signal` at `:237` with no `isCompacting`. **The floor has exactly one
209
+ knob**, which is what made this a small change: `check-dep-versions` derives the peer range
210
+ and `check_pi_runtime_version` derives its FLOOR from the same exact devDep pin, so a
211
+ candidate cannot pin 0.87.1 while advertising 0.87.0. Moving it reddened four surfaces on cue
212
+ — and the gates named two omissions the author had missed: `[QK:MUTANT-FIND-MATCHES-SUBJECT]`
213
+ caught two `pack-install` pin-matcher mutants at `matched 0×`, and the prose scan caught
214
+ `demo/README.md`'s `current floor` and ROADMAP's `pi <version> fence`. The 0.87.0 numbers
215
+ above and in ROADMAP's two dated ledgers are preserved as the measurements of their own day;
216
+ one blind pass had rewritten two ledger receipts and was reverted.
217
+
218
+ - **The Codex first-admission acceptance stays a release MUST, and what a cut must supply to it is
219
+ now written where a cut is taken from.** Reclassifying its absent prerequisite as a SKIP (see
220
+ Fixed) could have been read as demoting the step to an on-demand axis; that boundary is decided
221
+ the other way and gated. #87 made a newly admitted harness's visible-fresh receipt a MUST **after
222
+ measuring what the on-demand wording permitted** — a harness could be admitted as a full citizen
223
+ that `entwurf_fresh_call` cannot open and still pass the whole floor — so demoting Codex would
224
+ reopen exactly that hole. (VERIFY's standing "on-demand host axis" sentence is about
225
+ `smoke-codex-native-push-live`, the operator-loaded-thread probe, and is unchanged.) A SKIP is
226
+ therefore not a softening: `--cut` refuses it as `cut: BLOCKED (MUST SKIP)`, asked of the shared
227
+ shell authority rather than re-implemented, so a cut without this receipt is still impossible and
228
+ a host with no Codex app-server cannot take one — the intended cost of that release stop rather
229
+ than an accident. What changed is that the reproducible green is now stated: VERIFY says
230
+ `release-gate --cut` inherits the operator-supplied triple, and the release skill's P5 carries it
231
+ on the invocation (measured: `release_gate` exports no scrub and unsets nothing, so an exported
232
+ triple already reaches the step — no plumbing was added). **The instructions obey the
233
+ no-inference rule they teach.** The first draft of that P5 derived the pid with
234
+ `pgrep -f 'codex.*app-server' | head -1`, which is the inference the step exists to refuse,
235
+ written onto the page an operator follows, and on a host running several app-servers it hands the
236
+ gate an arbitrary process to verify as "the operator's answer". Each value is now STATED and
237
+ guarded by an explicit `: "${VAR:?...}"` required-value check before any LIVE cost. Three claims
238
+ keep the boundary from drifting back, one per direction, each with its own exact-once mutant:
239
+ `[QK:CODEX-OPERATOR-PREREQ-ABSENT-SKIPS]` (which pins the filter → guard → `skipLive` shape as one
240
+ contiguous sequence, reading the source with comments stripped — a promise in prose is precisely
241
+ where this defect hid for a release, and a first candidate mutant SURVIVED a weaker regex before
242
+ that cell was tightened), `[QK:CODEX-OPERATOR-PREREQ-WRONG-FAILS]`, and
243
+ `[QK:CODEX-OPERATOR-PREREQ-STATED-NOT-SEARCHED]`. The installed-config preflights are
244
+ deliberately OUTSIDE this split and still FAIL on absence: a missing Codex birth, user
245
+ MCP/status/terminal-title config, runtime, bridge, tmux seat or an unanswered launch directory is
246
+ host state `setup` and the Codex doctors own, not a per-invocation input.
247
+
248
+ - **The Herdr plugin manifest version moves 0.4.1 → 0.5.0 for this cut, and nothing else reads
249
+ that literal.** `plugins/herdr/herdr-plugin.toml` is the sole declaration (measured: one hit
250
+ repository-wide); `check-herdr-plugin` asserts semver SHAPE, not a value
251
+ (`scripts/check-herdr-plugin.ts:82`), and `min_herdr_version` stays the measured 0.9.0 floor.
252
+ `plugins/herdr/runtime-lock.json` returns to the `herdr-checkout` candidate carrier for the cut,
253
+ because `certifyLockCoherence` requires an npm lock to name a version that is BOTH already
254
+ published and equal to this checkout's `package.json` — and the version bump lands before the
255
+ publish. That is the same order `dd84ac0`/`3c3a67d`/`47f6d36` recorded: `v0.23.1` and `v0.24.0`
256
+ were both tagged on that carrier and the npm pin returned afterwards. The lock never moves onto an
257
+ unpublished version, and the 0.25.0 npm pin plus its published sha512 is a follow-up commit, not
258
+ part of this cut. The build gate and the README's release sentence move with it, because they read
259
+ the committed lock beside it.
260
+
261
+ - **The Herdr plugin README is rebuilt around the two questions a visitor actually
262
+ arrives with: which route do I want, and what do I type first.** It now opens by saying what the
263
+ plugin is *not* (a second workbench), then a route chooser, the Herdr built-ins this plugin
264
+ depends on versus what Entwurf adds, a quick start that runs from a raw box in nine steps to the
265
+ first status pane, and only then the direct/mux comparison, boundaries, runtime and developer
266
+ detail. Four facts were repaired against source while re-reading it: the install narration is
267
+ four usage notes, not two (`lib/build.mjs:217-227,292-294`); the receipt section named the
268
+ superseded npm 0.23.1 pin instead of the 0.24.0 lock at `deb73f1`; `check-bridge` asserts
269
+ **eight** garden verbs, not seven (`run.sh:4708` `EXPECT_TOOLS`); and an unmeasured "~45 s,
270
+ hundreds of MB" claim was dropped. The route paragraph no longer says the two routes install the
271
+ same *runtime* — they install the same capability package, but this plugin pins an exact
272
+ `@junghanacs/entwurf@<version>` plus its published sha512 while a direct `npm install -g`
273
+ follows whatever version npm is asked for. The neighbouring-plugin table is now explicitly
274
+ "observed mechanism families, not a census or a compatibility matrix", and every family-wide
275
+ property assertion in it (pane-bound addresses, workspace-scoped identity, receipts as a
276
+ non-goal, "structurally the closest to Entwurf") was narrowed to implementation-specific: the
277
+ differentiator stated in prose is Entwurf's record-backed garden id and the no-argument same-id
278
+ `entwurf_resume_call`, not a uniqueness claim about durable addresses. Docs ship with the
279
+ plugin, so the manifest moves with them. Receipts: `check-herdr-plugin` 32 ok,
280
+ `check-herdr-plugin-build` 14 ok, `check-herdr-plugin-profile` 14 ok, `check-dep-versions` ok
281
+ (pi 0.86.0 across 9 ranges, unchanged), `check-node-floor-coherence` ok, all four relative links
282
+ resolve, `git diff --check` clean.
283
+ - **The plugin runtime lock is pinned to npm `@junghanacs/entwurf@0.24.0`** and its published
284
+ sha512, closing the candidate window 0.24.0 shipped in — the second of the two steps the 0.24.0
285
+ entry below names. The integrity was measured here twice, independently: `npm view
286
+ @junghanacs/entwurf@0.24.0 dist.integrity` and `openssl dgst -sha512` over the preserved
287
+ candidate `make` accepted (`/tmp/entwurf-release-candidate-0.24.0.LXYL1S`, sha256
288
+ `fd750bcb…`) agree, and the registry tarball's sha256 equals the candidate's, so the lock names
289
+ the exact bytes the release gate consumed. Lock and `check-herdr-plugin-build` moved together
290
+ (the measured forward of `47f6d36`, version literals and the `IDENTITY` fixture's sha512 moved
291
+ to 0.24.0), the plugin README drops the candidate sentence, and `herdr-plugin.toml` already says
292
+ 0.4.0. Receipts: `check-herdr-plugin-build` 14/14, `check-herdr-runtime-bootstrap` 31 ok with
293
+ `source=npm … version 0.24.0 … npm-coherent=true`, `check-herdr-plugin` 32 ok,
294
+ `check-gate-manifests` 739/59 unchanged, `pnpm check` exit 0 (57 s). Registry smoke: a
295
+ sandboxed `pi install npm:@junghanacs/entwurf@0.24.0` resolves the bridge to the registry
296
+ install and `--list-models entwurf` lists the curated Claude and Cortex anchors; dist-tags
297
+ `latest=0.24.0`, `repair=0.12.8-repair.1` preserved.
298
+ - **`smoke-herdr-raw-install-live` says the eighth verb too.** Its verb cell keeps an
299
+ independent copy of the shipped `EXPECT_TOOLS` set on purpose, so an upstream verb reddens it
300
+ until somebody says so there — and `entwurf_callback` had not been said. First run on the
301
+ public remote at `deb73f1` with the npm 0.24.0 runtime: every acquisition, identity, [7]/[8a]
302
+ 0-token citizen and teardown/reinstall cell green, only that copy red; with the eighth verb
303
+ named the smoke is PASS (`ref=main`, runtime `@junghanacs/entwurf@0.24.0`, observed sha256
304
+ `fd750bcb…`). The comment's stale `run.sh:5187` line reference now names the constant instead.
305
+
306
+ ### Removed
307
+
308
+ - **The sender-side `entwurf-sent` transcript box, which had no producer (#120 P3).** Repository
309
+ measurement found one definition, one renderer registration and **zero** producers, while two
310
+ live comments named producers that did not exist. The shipped `ENTWURF_SENT_MESSAGE_TYPE` export
311
+ and the dead `SentBoxData` / builder / renderer / registration are gone; the independent
312
+ receive-side `entwurf-message` producer and renderer are untouched. The remaining receive-side
313
+ comment now states the true boundary — a sender receives an acceptance-boundary text receipt, and
314
+ only a receiver can claim a transcript box was rendered. Two claims keep it retired: AST-based
315
+ `[QK:NO-RENDERER-WITHOUT-PRODUCER]`, so a comment or a string literal cannot satisfy the producer
316
+ proof, and `[QK:RETIRED-SENT-SURFACE-ABSENT]`, which seals both identifiers and the stale
317
+ `entwurf sent` / `sender-side UI box` prose. The two mutants went into their own
318
+ `retired-sent-surface` lane rather than mixing into P2 receipt semantics, and historical
319
+ ROADMAP/demo evidence was kept as history with a dated correction rather than rewritten.
320
+
321
+ ### Fixed
322
+
323
+ - **`showTurnDuration` was never ours, and entwurf had been forcing the operator's own display
324
+ off.** The native meta-bridge install owned a list of Claude Code policy scalars that close
325
+ background autonomy and suggestion surfaces — and this one had been sitting in it, pinned to
326
+ `false`. It closes nothing: it reports how long a turn took, which is operator INFORMATION, so the
327
+ policy reason the rest of that list stands on never applied to it. GLG's ruling is that the
328
+ operator owns the scalar and entwurf must neither own it nor force it. The symptom had been
329
+ misread as drift: `./run.sh doctor-meta-bridge` was FAIL on the source host for exactly one
330
+ managed scalar, with `~/.claude/settings.json` saying `true` and the writer requiring `false`, and
331
+ the install-state carries no per-scalar provenance to say whose value that was. The actual cause
332
+ is measurable and is **two owners on one key**: `check-keyset-overlap` against the operator's own
333
+ `agent-config` settings fragment failed on `showTurnDuration` and on nothing else, because both
334
+ sides claimed it. Dropping our claim is what resolves that collision, with **zero change to
335
+ agent-config**. The key is RETIRED rather than deleted, through the same one-shot path #94 built
336
+ for compaction, because an existing install-state already carries its entry — measured on the
337
+ source host, `original {existed: true, value: false}` under a live `true`, i.e. the operator
338
+ turned the display on after our install — and `uninstall()` walks every ledger entry through
339
+ `restore_entry`, so deleting the constant would have written `false` back over that choice.
340
+ `[QK:META-RETIRE-TURN-DURATION-OPERATOR-OWNED]` measures the premise instead of quoting it: it
341
+ asks the SSOT whether the key is claimed, pins the retired comparison value by type as well as
342
+ equality, drives the real relinquish leaf on the exact host shape above, and proves the ledger row
343
+ is consumed so no later inverse can reach the key. Its mutant drifts the scalar back under
344
+ management. **The migration ran on the host and was measured on both sides:** before
345
+ `showTurnDuration=true`, after `showTurnDuration=true`, the ledger entry gone (15 managed keys
346
+ → 14), and `doctor-meta-bridge` now PASS with 33 ok where it had been exit 1 on that one axis.
347
+
348
+ - **A release MUST step reported a missing operator input as a FAILURE, so the aggregate gate was
349
+ structurally red on every host at every cut.** `smoke-codex-fresh-live` takes three values only
350
+ the operator can supply — the app-server pid and two model tiers — and `release_gate()` supplies
351
+ none of them, by design: entwurf neither starts nor supervises that app-server. Its own skip line
352
+ promised four prerequisites in one breath (`LIVE=1` plus the three env names), but only the first
353
+ could produce a SKIP; the other three were `ok()` assertions, and `ok()` throws. So the step
354
+ declined as a defect. `scripts/lib/step-outcome.sh` had already written the rule this broke —
355
+ *"a step that RAN AND BROKE and a step that NEVER RAN are different facts, and a release record
356
+ that blurs them is worthless: the first is a defect to fix, the second is a prerequisite to
357
+ supply"* — and the candidate receipt below shows the cost: `MUST PASS=23 FAIL=1`,
358
+ `cut: BLOCKED (MUST FAIL)`, with a prose classification standing in for a floor. **The repair is
359
+ the classification, not the requirement.** An ABSENT input is now a protocol SKIP naming each
360
+ missing one; a PRESENT but wrong one — a malformed or dead pid, a process whose argv is not a
361
+ Codex app-server, a foreign uid, an app-server sharing the gate's own session — stays a FAIL.
362
+ Both arms were measured, and neither opens a window or spends a turn: unset triple under `LIVE=1`
363
+ exits 97 with its `[entwurf:skip]` line, `ENTWURF_CODEX_APP_SERVER_PID=abc` exits 1 naming the
364
+ value. No inference was added and no default invented for a value nobody gave.
365
+
366
+ - **The Herdr status pane died before drawing a single block on the carrier every candidate window
367
+ rides.** `plugins/herdr/lib/activation-evidence.mjs` located the installed ledger reader by
368
+ reading the package directory name off `runtime-lock.json` — but that file is a discriminated
369
+ union and only its `npm` arm carries a `name`, so on the `herdr-checkout` arm
370
+ (`{source, repository}`) the name was `undefined` and `path.join` answered it with a `TypeError`
371
+ raised OUTSIDE the `try` that was supposed to name every failure this module can have. Measured on
372
+ this cut: with that lock committed, `check-herdr-plugin` reported `block was ""` and every one of
373
+ its 48 assertions stood on a pane that had crashed. The carrier is not an edge case — `v0.23.1`
374
+ and `v0.24.0` were both tagged on it. The gatherer now takes `checkoutRoot` and asks
375
+ `readCheckoutPackageSpec`: the manifest is the one name both lock arms already agree about, since
376
+ the npm arm is certified coherent with it and the checkout arm packs that very manifest. The join
377
+ moved inside the same `try`, so a locator that ever yields a non-string is a named
378
+ `activation-reader-unavailable` rather than a process death. `VERIFY.md` had already written this
379
+ rule down for `smoke-herdr-raw-install-live`; the lesson had not crossed to the gatherer `79391fb`
380
+ added. `[QK:HPL-PACKAGE-NAME-FROM-MANIFEST]` measures the premise instead of quoting it — it
381
+ writes a checkout-arm lock and asks the real reader what `.name` is — then requires the module to
382
+ ask the manifest and never the lock, with comments stripped first so prose cannot satisfy it; its
383
+ mutant drifts the call back to `readRuntimeLock`.
384
+
385
+ - **`doctor-pi-provider` called every Herdr-plugin host red while its bridge booted and served all
386
+ eight verbs (#120 P1-B).** The install-state's `ownership` field is a PREIMAGE classification —
387
+ what stood at the key BEFORE that install — so `absent` means "we created it", not "nobody owns
388
+ it"; reading it as an ownership verdict is what produced the false red. The doctor now reads the
389
+ recorded `command` beside it, because that string and not the bare name is the canonical managed
390
+ command (`register-pi-provider.py` writes the same string into the settings entry and into the
391
+ record), and in plugin mode it is an absolute bridge under the certified stable runtime, since a
392
+ Herdr-plugin host has nothing `entwurf` on PATH. For a known managed preimage carrying a recorded
393
+ command the comparison now runs REGARDLESS of whether the effective command happens to be the
394
+ bare name: keeping that decision inside a `!isBare` branch is how real drift escaped — a record
395
+ naming the absolute plugin bridge with the settings repointed at bare `entwurf-bridge` is drift,
396
+ and a bare bridge that boots would otherwise have carried it to green. A record that names no
397
+ command, or one whose ownership is a word this doctor does not know, falls through to the
398
+ original logic unchanged; the state is rewritten by `./run.sh setup`, never by its reader.
399
+
400
+ - **Three qualification control reds, which were gate defects rather than product ones (#120).**
401
+ The first committed body at `bad2677` ran 69m42s and ended 746/777, with the remaining 31 voided
402
+ only by baseline-red controls. `[QK:MUTANT-GATES-INSIDE-FULL-FLOOR]`: `check-control-send-receipt`
403
+ and `check-entwurf-v2-runner` were valid narrow mutant coordinates but absent from `check:full`,
404
+ so they are now wired into `check:contracts` (~1.5 s combined, measured) while keeping their
405
+ source-adjacent discovery. `[QK:LAUNCHFENCE-EXPOSED-SMOKE-WIRED]`: P1's new XDG data-root cell
406
+ moved `smoke-herdr-raw-install-live.sh` into launcher-fence scrutiny, and the fence's env-block
407
+ parser understood only TypeScript object literals, not a continued shell `env` command — it now
408
+ reads that actual invocation and grants the exemption only when `HOME=` is relocated in the same
409
+ block, with a negative cell deleting that assignment to prove the exemption disappears.
410
+ `smoke-setup-verdict` S-8's intermittent second-run idempotence red had its output discarded by a
411
+ `| grep -q`, leaving no causal receipt; the second setup output is now captured and printed on
412
+ failure. No retry, sleep, enlarged timeout or speculative behaviour change was added, and S-8 is
413
+ explicitly NOT claimed fixed — it did not recur in the accepted body, and if it returns the next
414
+ receipt carries the output instead of one context-free FAIL line.
415
+
416
+ - **Two stale oracles in `smoke-codex-fresh-live`, both surfaced by the LIVE floor of this cut.**
417
+ (a) The step read a control-socket receipt as successful only when it said `sent|delivered`.
418
+ `6d90d73` widened two sibling LIVE smokes to the closed four-value axis and named the reason in
419
+ `smoke-herdr-fresh-call-live.ts:89` — *"the old literal `→ sent` pin would have gone red on the
420
+ common case and passed only when the caller happened to be idle"* — and this third one was missed.
421
+ Measured on this exact step: the fixture addresses the initial Pi mid-turn, the rail answered
422
+ `queued-follow-up`, and a release-gate MUST went red on a delivery that had succeeded. Before P2
423
+ it passed on the busy path only because the rail said `sent` either way, which is the dishonesty
424
+ P2 removed; `delivered` was never a member of the set. (b) The initial-Pi exact-once audit still
425
+ expected the PRE-0.24.0 callback shape — an `entwurf_v2` carrying the nonce as arguments — while a
426
+ pi sibling's first action has been the zero-argument `entwurf_callback` since 0.24.0, as this
427
+ smoke's own launch receipt says in the same run: *"its first action is the zero-argument callback
428
+ verb (codex is the one arm that still sends the nonce as arguments)"*. A sibling obeying the
429
+ shipped framing was therefore reported as an unexpected call. Only the pi branch moved; the Codex
430
+ audit keeps `entwurf_v2`, because codex really is still the argument-carrying arm
431
+ (`codex-callback-env-unsupported`). This is the class `e506716` closed for
432
+ `smoke-herdr-raw-install-live`, and it stayed hidden in 0.24.0 because that cut's run died earlier
433
+ at the Pi→Codex template relay. Neither repair weakens an assertion: `{}` is matched by
434
+ `isDeepStrictEqual`, so it pins the verb's zero-argument contract rather than accepting any
435
+ arguments, the exact-once count is unchanged, a refusal still fails, and the callback-nonce
436
+ correlation was never carried by that audit — it is proven earlier and from the DELIVERED body by
437
+ `the initial Pi callback carries the exact launch nonce`, which reads the fixture's own mailbox,
438
+ requires exactly one exact match and refuses duplicates.
439
+
440
+ ### Verification
441
+
442
+ Frozen candidate `69a6f1d`, host `oracle`, 2026-09-23 KST. Two receipts, kept apart on purpose.
443
+
444
+ - **Deterministic floor:** `pnpm run check:full` exit 0, 607 s.
445
+ - **Aggregate LIVE floor**, `LIVE=1 ./run.sh release-gate <scratch> --cut` with ambient identity
446
+ carriers stripped, scratch `/tmp/entwurf-release-gate-0.25.0-final.HghiXh`:
447
+ **MUST PASS=23 FAIL=1 SKIP=0**, **BEHAVIOR PASS=1 FAIL=0 SKIP=0**, `cut: BLOCKED (MUST FAIL)`.
448
+ Inside it, `check-gate-qualification` killed **778/778** with `[gate-qualification] ok` and both
449
+ purity axes green — measured on these exact bytes, which is why the aggregate was re-run after the
450
+ two gate commits above: `scripts/smoke-codex-fresh-live.ts` is the subject of three committed
451
+ mutants (`CODEX-LIVE-EVIDENCE-RECORD-PATH`, `CODEX-LIVE-EVIDENCE-RECOVERY-FAILSAFE`,
452
+ `CODEX-LIVE-RECOVERY-SOURCE-ONLY`), and all three killed at `sha256=40c7852fc273…`.
453
+ - **The one MUST red is the shape of that step, not a defect.** `release_gate()` supplies no
454
+ `ENTWURF_CODEX_APP_SERVER_PID`, and `smoke-codex-fresh-live` refuses to infer one — VERIFY: *"The A
455
+ cell takes no inferred server or models"* — so it declines inside every aggregate on every host.
456
+ Its pair is the standalone run on the SAME frozen `69a6f1d`: `LIVE=1
457
+ ENTWURF_CODEX_APP_SERVER_PID=3969303 ENTWURF_CODEX_FRESH_MODEL=gpt-5.6-luna
458
+ ENTWURF_CODEX_FRESH_PI_MODEL=openai-codex/gpt-5.6-terra ./run.sh smoke-codex-fresh-live` →
459
+ **66 assertions ok, exit 0**, `initial-pi=3/3 completed exact`, `codex=3/3 completed exact`.
460
+ The Pi tier is terra rather than luna, and that is a recorded tier choice, not a gate change: the
461
+ 0.23.1 follow-up already measured luna losing relay fidelity where terra preserves it, and on this
462
+ cut luna pre-substituted the `<placeholder>` template the smoke audits for byte equality
463
+ (ROADMAP 0.24.0 follow-up 3). The receipt this cell is accepted on is the run that actually ran.
464
+ - **Host residue (P9, run at the gate's verdict and again at the end of prepare):** 588 → 586 dirs,
465
+ 2 roots / 112 K reclaimed, by prefix `entwurf-s2b-overlay` and `check-probe-ordering`. One
466
+ reparented process holds a `/tmp` path and was named rather than killed: pid 489788, the
467
+ operator's own `emacs --init-directory=/tmp/agent-emacs-init --daemon`, which no gate mints.
468
+ - **Open, pre-cut, not resolved by this candidate:** `./run.sh doctor-meta-bridge` is FAIL on this
469
+ host for exactly one managed scalar — `settings showTurnDuration missing/drifted`, where
470
+ `~/.claude/settings.json` says `true` and `scripts/meta-bridge-state.py:90` requires `false`.
471
+ Every other axis of that doctor reads ok (hook launch form, doorbell static contract, statusline,
472
+ user-scope MCP reachability, cached artifact). The install-state carries no per-scalar provenance,
473
+ so whether this is drift from our write or the operator's own UI choice is not decided here, and
474
+ the host was deliberately left untouched.
475
+
476
+ - **Resolved 2026-09-23, after the paragraph above was written.** That doctor red was not drift and
477
+ not undecidable: the key had two owners, and GLG ruled the operator owns it. The scalar is retired
478
+ (see Fixed), and the host migration was measured on both sides — `showTurnDuration=true` before
479
+ and after, the install-state ledger entry consumed (15 managed keys → 14), and
480
+ `./run.sh doctor-meta-bridge` now **exit 0, PASS, 33 ok**. The paragraph above is kept as what was
481
+ true when the frozen candidate was measured.
482
+
483
+ **Post-prepare release-fix candidate (2026-09-23, host `oracle`) — source, focused and host
484
+ receipts only.** This is not a cut receipt. `check-gate-qualification`'s body (`782/782` killed,
485
+ `[gate-qualification] ok`) and `pnpm run check:full` (`total elapsed 603s exit 0`) ran on the earlier
486
+ frozen seal (`git diff --cached --binary | sha256sum` =
487
+ `ee478d4eac77aae6db187eeb5da2d357ab275c00e6d1eb9463ca04f29bf42425`), before this paragraph and two
488
+ documentation lines were amended; they are not re-attributed to the amended bytes. When this
489
+ paragraph was written (2026-09-23, before 09:44 KST) the LIVE release gate (`--cut`) had not been run
490
+ on this candidate, so this paragraph by itself does not speak to releasability; the LIVE receipt is
491
+ the dated addendum below, and it belongs to the `00264f…` seal only. What was measured:
492
+
493
+ - **Focused gates, green on the working candidate:** `check-dep-versions`
494
+ (`ok — pi 0.87.1 is coherent … 9 range + 1 exact + 3 prose declarations`), `check-gate-manifests`
495
+ (**782** committed mutants across 62 lanes, every `find` still matching its subject exactly once,
496
+ lane inventory matching its declared contract), `check-release-gate-outcomes`,
497
+ `smoke-meta-install-state`, `smoke-meta-keyset-guard`, `check-keyset-overlap` against the
498
+ operator's own agent-config fragment (exit 1 → exit 0, `keyset disjoint ok: 1 fragment vs 15
499
+ pi-owned key(s)`), `check-meta-doctor-oracle`, `check-meta-manifest-schema`, `smoke-meta-honesty`,
500
+ `smoke-setup-verdict`, `smoke-user-scope-citizen`, `smoke-meta-prune`, `check-pi-runtime-version`,
501
+ `check-pi-import-surface`, `check-model-lock`, `check-node-floor-coherence`, `check-pi-preflight`,
502
+ `check-pi-launch`, `check-pack-pin-matcher`, `check-pack` (540 files), `check-herdr-activation`,
503
+ `check-herdr-placement`, `check-pi-queue-oracle`, `check-entwurf-v2-surface`,
504
+ `check-control-send-receipt`, `check-compaction-send-guard`, `check-mux-launcher-fence`,
505
+ `check-codex-bridge-identity`, `check-codex-native-push`, `check-env-namespace`,
506
+ `check-shell-quote`, `check-tests-beside-behavior`, `check-install-surface`,
507
+ `smoke-agy-install-state`, `check-acp-sdk-surface`, `check-mux-fresh-call`. Three type fences
508
+ `tsc --noEmit` / `-p scripts` / `-p mcp` rc=0, and `pnpm lint` at 0 errors / 22 warnings — the
509
+ same counts a pristine HEAD produces, measured in its own snapshot for the comparison.
510
+ - **Four new mutants, each killed at its own claimed signature** in a scratch snapshot mirror with
511
+ control-pre and control-post green, because the shared checkout is never mutated in place:
512
+ `META-RETIRE-TURN-DURATION-OPERATOR-OWNED`, `CODEX-OPERATOR-PREREQ-ABSENT-SKIPS`,
513
+ `CODEX-OPERATOR-PREREQ-WRONG-FAILS`, `CODEX-OPERATOR-PREREQ-STATED-NOT-SEARCHED`. The
514
+ release-gate lane inventory moves 19 → 22 and meta-retire 3 → 4.
515
+ - **`check-install-surface` was re-run the only way it can tell the truth about an unstaged
516
+ edit, and that mattered.** It reads the candidate through `git show :<file>`, so a first run over
517
+ a working-tree-only change is a false green — a trap `NEXT.md` already documented from the
518
+ previous release. Two U+2014 em dashes had in fact landed in the ASCII-only release skill at
519
+ `(334,64)` and `(347,9)`. They are gone, and the proof was taken in a scratch snapshot where the
520
+ whole candidate was `git add -A`ed (**exit 0**, S7e and S6's 494 NUL-free sources included), with
521
+ a negative control planting one em dash back to confirm S7e really reddens rather than passing
522
+ vacuously. No staging was performed in the shared checkout.
523
+ - **Host receipts (operator-owned steps, run by the coordinator under GLG's authority and verified
524
+ independently here):** the retired-scalar migration applied with the operator's `true` intact and
525
+ the ledger entry consumed; `doctor-meta-bridge` PASS; the global pi CLI moved 0.87.0 → **0.87.1**
526
+ and this repo's installed `pi-coding-agent` reads **0.87.1**. The running pi coordinator process
527
+ may predate that upgrade, so it is not used as evidence for it — the versions above were read from
528
+ the CLI and the installed package.
529
+
530
+ **LIVE release gate on the amended candidate (2026-09-23 09:44–11:15 KST, host `oracle`) — dated
531
+ addendum.** Candidate seal: HEAD `61cde06755c1eb353c2338c314cdf1eed384b26e`, `git diff HEAD --binary |
532
+ sha256sum` = `git diff --cached --binary | sha256sum` =
533
+ `00264f9177cfc2fde16d468299f12a4d00abc8d54fad1fd3c6c70df06d56478f`, unstaged 0, untracked 0. The
534
+ coordinator's launcher refused to start unless HEAD and both seals matched, and printed them again
535
+ after the run: pre and post identical. That seal is the bytes with the D1/D2/O2 documentation
536
+ amendment above and WITHOUT this addendum; the result is not re-attributed to the documentation-only
537
+ seal that adds these lines. The 69a6f1d `FAIL=1` receipt and the `ee478d…` seal receipts above stay
538
+ as history.
539
+
540
+ - **Command:** `env -u CLAUDE_CONFIG_DIR -u PI_SESSION_ID -u PI_AGENT_ID LIVE=1
541
+ ENTWURF_CODEX_APP_SERVER_PID=3067196 ENTWURF_CODEX_FRESH_MODEL=gpt-5.6-luna
542
+ ENTWURF_CODEX_FRESH_PI_MODEL=openai-codex/gpt-5.6-terra ./run.sh release-gate
543
+ /tmp/entwurf-release-gate-0.25.0-00264f --cut`, exit 0. The app-server pid is the pane pid of the
544
+ one the coordinator started (on GLG's direct instruction) in its own tmux session
545
+ `entwurf025_codex_server`; it was stated, not searched. Its uid and exact `app-server --listen`
546
+ argv were checked through `/proc`, and its session differs from the gate's.
547
+ - **Log (cross-host artifact):** `/tmp/entwurf-release-gate-0.25.0-00264f/release-gate.log`, sha256
548
+ `100c61a5721dee3e693a5f6d4851138d52172ad5301a231431a10478237bf20d`. The decisive lines, verbatim:
549
+
550
+ ```text
551
+ [check:full] total elapsed 621s exit 0
552
+ [gate-qualification] origin checkout: HEAD + work-surface content hash identical before/after
553
+ [gate-qualification] qualified claims: 782/782 killed — …
554
+ [gate-qualification] ok
555
+ [smoke-codex-fresh-live] 64 assertions ok — fixture -> initial visible Pi -> visible Codex/exact callback -> Pi-addressed native-push v2 -> Codex outbound v2 -> visible Pi/exact callback
556
+ MUST: PASS=24 FAIL=0 SKIP=0
557
+ BEHAVIOR: PASS=1 FAIL=0 SKIP=0
558
+ mode: --cut (a MUST SKIP is a BLOCKER — this run is being read as release acceptance)
559
+ cut: OK
560
+ ```
561
+
562
+ - **Claude Code host:** `claude --version` = 2.1.280, which is above the `>=2.1.217` floor. Host
563
+ doctor log `/tmp/entwurf-0251-claude-280-doctor.log`, sha256
564
+ `568f73883a60025e370b5f45cba111620a60c45af351165bab25ddfa0d5be1e7`, exit 0, PASS.
565
+ - **P9, run right after the verdict:** the prefix-blind census found one reparented process holding
566
+ a `/tmp` path (pid 489788, the operator's own emacs). It is not gate residue and was left alone.
567
+ `OWNED` derived 107 prefixes. Idle roots older than 60 minutes: 3 (128K). Two were
568
+ `check-probe-ordering` and one `entwurf-s2b-overlay`; they were inspected, then removed. After P9,
569
+ the operator owned 592 directories under `/tmp`.
570
+
7
571
  ## 0.24.0 - 2026-09-20
8
572
 
9
573
  ### 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 — including `check-gate-manifests`, the qualification HEAD (runner self-test, manifest-set validation, declared lane inventory, zero mutants executed, ~8s), but not the separately scheduled mutant-EXECUTING body `check-gate-qualification`, which CI runs on a branch push whose diff touched the qualification surface (and unconditionally on dispatch or the weekly schedule) and a gate-changing PR must run once itself. Exact membership is the named `check:*` scripts in `package.json`. Run `check:full` once on your frozen commit candidate — the pre-commit hook (`.husky/pre-commit`) carries only fast static checks (whitespace, lint, typecheck), not the full floor, so a green `pnpm run check:full` before commit is the evidence that your change holds (scheduling contract: AGENTS.md "Verification scheduling").
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 COMMITTED mutants executed — the self-test runs only its synthetic fixture mutants in tmp fixture repos — ~20s), but not the separately scheduled mutant-EXECUTING body `check-gate-qualification`, which CI runs on a branch push whose diff touched the qualification surface (and unconditionally on dispatch or the weekly schedule) and a gate-changing PR must run once itself. Exact membership is the named `check:*` scripts in `package.json`. Run `check:full` once on your frozen commit candidate — the pre-commit hook (`.husky/pre-commit`) carries only fast static checks (whitespace, lint, typecheck), not the full floor, so a green `pnpm run check:full` before commit is the evidence that your change holds (scheduling contract: AGENTS.md "Verification scheduling").
34
34
 
35
35
  For changes that touch backend launch, session lifecycle, or `_meta` shape, also run
36
36
  the live ACP smokes that cover the touched rail — at minimum:
package/DELIVERY.md CHANGED
@@ -27,7 +27,7 @@ API. The levels compare capabilities, not implementation shapes.
27
27
 
28
28
  | State | Meaning |
29
29
  |---|---|
30
- | `queued` | A message is durable; the backend may not have seen it. |
30
+ | `queued` | A receiver queue accepted the message; the backend may not have seen it. Durability is a property of the RAIL, not of this word — see the acceptance table below. |
31
31
  | `triggered` | A supported event/API accepted the signal. |
32
32
  | `woke` | An idle interactive session began a turn without user typing. |
33
33
  | `injected` | The message reached model-visible context. |
@@ -36,6 +36,29 @@ API. The levels compare capabilities, not implementation shapes.
36
36
 
37
37
  Avoid bare `delivered`; name the observed boundary.
38
38
 
39
+ ### Control-socket acceptance boundaries (#120)
40
+
41
+ A control-socket send answers with ONE of these, and the sender renders that word rather than the
42
+ internal route it took. They are not four spellings of success: they differ on every axis an
43
+ operator has to reason about.
44
+
45
+ | Boundary | Order | Durability | Visibility | Rejection |
46
+ |---|---|---|---|---|
47
+ | `sent` | n/a — the receiver was idle and the turn was TRIGGERED directly | none needed; the turn started | the turn is running, but the model has NOT necessarily read the text yet, and nothing here says the turn completed | an in-band refusal is `rejected`, never this |
48
+ | `queued-steer` | drained after each turn; overtakes every `queued-follow-up` already waiting | **none** — volatile receiver process memory | nothing shows it: it is not in the TUI's pending-message count | an abort clears the queue and the message is gone, silently |
49
+ | `queued-follow-up` | drained only when the receiver's inner loop ends; a steer arriving later still goes first | **none** — volatile receiver process memory | same: invisible in the receiver's own queue display | same: an abort drops it |
50
+ | `accepted-unknown-boundary` | unknown | unknown | unknown | the receiver ACCEPTED; this names our inability to classify its answer (version skew), and it must never be retried or rendered as `sent` |
51
+
52
+ `[측정 2026-09-22, pi-agent-core 0.87.0; 재측정 2026-09-23, 0.87.1 — 좌표 동일]` `dist/agent.js:60-71,96-97,137-138`
53
+ (two independent `one-at-a-time` queues, no FIFO between them)
54
+ and `dist/agent-loop.js:85,186,191-197`
55
+ (steering drained every turn, follow-ups only once the inner loop ends).
56
+
57
+ The **meta-mailbox** rail is the contrast, not a fifth boundary: it writes a durable `*.msg` before
58
+ ringing any doorbell, its filenames are ISO stamps so a drain is a global FIFO, an undrained inbox
59
+ is an honest `mailbox-undeliverable` refusal, and its receipt is that FILE. A mailbox enqueue is a
60
+ durable file receipt; a control-socket queue is process memory.
61
+
39
62
  ## Levels (D0–D8)
40
63
 
41
64
  These are independent of VERIFY's `L0–L5` evidence levels and BASELINE's question