@junghanacs/entwurf 0.51.0 → 0.52.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -4,6 +4,44 @@ All notable changes to this project will be documented here. Format follows [Kee
4
4
 
5
5
  ## Unreleased
6
6
 
7
+ ## 0.52.0 — 2026-11-12
8
+
9
+ ### Pi SDK 1.5.2 (#158)
10
+
11
+ Entwurf 0.52.0 moves the exact ten-member Pi SDK set from 1.5.0 to 1.5.2 and declares host Pi `>=1.5.2 <1.6` (#158). At preparation time, the published npm baseline remains 0.51.0 / SDK 1.5.0; its marked installation recipes remain independent of this source candidate. The checkout's Herdr lock returns to the existing verification carrier rather than claiming unpublished npm 0.52.0 bytes. Source-checkpoint, preparation, operating and final-artifact evidence remain distinct, and no #155 receipt transfers to this release.
12
+
13
+ - **Exact SDK set.** All ten `@earendil-works/*` members move from 1.5.0 to exactly 1.5.2, with the lockfile, the carrier's SDK manifest, the `run.sh` pin and probes, and the mutant pin literals. Measured on the registry tarballs: SHA-512 and SHA-1 match for all ten, and every one of the 16 member-to-member production edges is exactly 1.5.2. Two non-member dependency changes against 1.5.0: `pi-coding-agent` drops `grok-mermaid` 0.2.3 for `lovely-mermaid` 0.3.3, and `chord` adds an optional peer `react` 19.3.0. Whether either reaches an Entwurf consumer is not measured.
14
+ - **Release-age exception.** The operator explicitly approved on 2026-11-11 an exception for exactly the ten SDK members at 1.5.2, added to `minimumReleaseAgeExclude`. The global release-age policy and the release-age treatment of other dependencies are unchanged.
15
+ - **Maintainer: Chord `Context`.** The two owned type imports move from `@earendil-works/chord` to `@earendil-works/chord/context` for Chord's new root export; the carrier is regenerated with the official emitter, not edited by hand. Typecheck and consumer results belong to this candidate's own receipts.
16
+ - **Scheduler.** SDK 1.5.2 carries the 1.5.1 scheduler notification fix. In an isolated six-member comparison using a faux provider, with no vendor-model calls or authentication, the unchanged upstream repro stayed stuck in 10 of 10 SDK 1.5.0 runs and settled in 10 of 10 SDK 1.5.2 runs. The public-API-only variants settled on both versions and did not reproduce the old race. This is bounded fixture evidence, not Entwurf carrier, operating-session, native SQLite or load-sweep acceptance.
17
+ - **Native SQLite.** In an isolated cross-version fixture, 1.5.2 reopened a 1.5.0-written database without changing its bytes, appended 60 parallel tool calls and compacted, and a close and reopen stayed consistent; the schema version stayed 2. Operating-scale sessions, an interrupted write, a non-checkpointed WAL and concurrent access are not measured. A package downgrade is still not a data rollback.
18
+ - **Documentation.** The install guide and Herdr README retain narrow published-scope regions for npm 0.51.0 (SDK 1.5.0), while the ACP row explicitly labels the source candidate's SDK 1.5.2 declaration. The durable guide gains a short candidate boundary covering ordinary Pi cache warming and the durable edit path, which this candidate does not change. The guide's `unreadable generation` advice now distinguishes reader-version skew from a genuinely unreadable generation.
19
+ - **Herdr preparation.** An npm lock must name the checkout's own package version. While 0.52.0 is unpublished, this preparation returns `runtime-lock.json` to the existing closed `herdr-checkout` verification carrier, without inventing npm 0.52.0 bytes or integrity and without changing the plugin manifest version. Published 0.51.0 recipes retain their SDK 1.5.0 subject. An installed npm host keeps its existing runtime until an explicit source switch; deactivate before selecting the checkout source. A later re-pin to measured npm 0.52.0 bytes is separate work after publication.
20
+ - **Preparation status.** The pre-version source checkpoint and later #159 candidates have separate frozen floors and receipts. An addon-less validation tarball was installed on one operating host; the operating coordinator returned under the same identity and exchanged a nonce. The subsequent P5 Native/LIVE run and final carrier-bearing artifact acceptance remain separate. Operating-scale or interrupted sessions and all-rail behavior are not certified by the bounded SDK fixtures.
21
+
22
+ ### Peer message replies (#159)
23
+
24
+ Peer messages distinguish a requested result sent to its routed recipient from a final answer in the local session. Reply guidance preserves no-send instructions and does not impose an acknowledgment merely because an address is replyable.
25
+
26
+ ### Release evidence
27
+
28
+ - Pre-version checkpoint: `b9fa0d2`. Its CI status is not recorded here. The preceding source worktree over `669315ccb22a` took frozen FULL r2, 971s, exit 0, after the initial stale-dist refusal was preserved and a managed bridge build completed. Its recorded index is `800cce5f40a67808145810ef14e5852ea091d1c5`, patch `e006e8032c045c40e6c06b1a94421348bbd2eedaa6a7a9eedcea8bbad7c022e8`; this is not the versioned 0.52.0 preparation's P4 or prepared-SHA CI. The branch handoff update followed that floor.
29
+ - #159 candidate on `b9fa0d2` with tracked diff `7f523c44042a` and fixture `217e8ef8920c`: frozen FULL 977s exit 0; carrier S/H contact 91, send 20, native-module 15 and receive 22; addon-less validation-TGZ Linux container and private ownership rehearsal passed. These receipts bind that earlier candidate, not later edits.
30
+ - Reviewed preparation candidate: HEAD `b9fa0d2aa43e`, tracked diff `8cbd3a3c9406e0f5c2c50878a23e52b088816f8feb0e0be9484cb462faf081d4`, untracked revision-20 fixture `217e8ef8920c09abe90cd2fe141a5b671ac94600ba6d2431fa056ea37c8fee42`. Frozen FULL ran 979s, exit 0, with unchanged seal; checkout carrier contact 91, send 19, native-module 14 and receive 21 passed (S/H only, vendor V not run). Addon-less validation TGZ `6c29185842806e3e14e28d3c2efd2da24c09e581772ed0a642277506565a60a1` passed Linux container acceptance; it is not the installed `d72afb…` TGZ or the final carrier artifact.
31
+ - Native LIVE (P5): on the same reviewed dirty candidate, `release-gate --cut` ran on 2026-11-12 13:03–13:24 KST, MUST 24 PASS / 0 FAIL / 0 SKIP and BEHAVIOR 1 PASS / 0 FAIL / 0 SKIP, exit 0, unchanged seal. Codex app-server A and fixture seat S were separate tmux sessions; models were `gpt-6-luna` and `openai-codex/gpt-6.1-terra`. Preserved log SHA-256 `e37c9e103be830e9446df5f981ae54d8078141bee5ca83fdd5b65d20188b656d`. The P9 immediate census observed one reparented `/tmp` process: a pre-existing Emacs daemon from November 9, not a P5 child; evidence and unclassified roots were preserved. This is not prepared-SHA CI or final artifact acceptance.
32
+ - Native Claude host: a fresh test-owned Claude Code session on the installed `d72afb…` validation root returned its exact callback and `entwurf_self`; its direct MCP child ran the installed 0.52.0 bridge, and installed `doctor-meta-bridge` passed while it was alive. Its own fixture was retired, with the record preserved. Sonnet was requested at launch; model usage for this particular turn was not independently extracted. The separate native-resume LIVE used `claude-sonnet-5-5` for both turns and passed 13 checks, with same-native-session marker recall.
33
+ - Installation-validation tarball (unpublished, addon-less): SHA-256 `d72afb38425c1dab8dd9a7c489274e1a76071aab73874d8ba94a896f55d8a3fd`; distinct from the final carrier-bearing artifact.
34
+ - Operating installation (2026-11-12): after normal owner exit and a consistent durable/ordinary-Pi backup, host Pi 1.5.2 and the addon-less validation tarball were installed; user-scope ownership moved to its root. The operating coordinator returned under the same garden/native ID with its original module and exchanged a nonce. This is one operating return, not all-rail or release acceptance.
35
+ - Windows and final artifact: at preparation time, the carrier-bearing artifact had not yet been produced or accepted; M3w follows green exact prepared-SHA push CI in make.
36
+ - Publication and Herdr npm re-pin: at preparation time, npm publication and its later Herdr re-pin remained separate human decisions.
37
+ - Kill-power re-measured at this shipped SHA: none (all 1516 committed claims not re-proved, #144).
38
+ - Earlier-candidate PARTIAL (operator-attested, not this SHA): head 669315ccb22a surface 3bceca54266b -- ["bash","run.sh","check-dep-versions"] 5/5 receipt 2280c96ec0a3
39
+ - Earlier-candidate PARTIAL (operator-attested, not this SHA): head 669315ccb22a surface 3bceca54266b -- ["bash","run.sh","check-pack-pin-matcher"] 2/2 receipt 7e64ab9bff6e
40
+ - Earlier-candidate PARTIAL (operator-attested, not this SHA): head b9fa0d2aa43e surface 60e424985df9 -- ["bash","run.sh","check-control-send-receipt"] 7/7 receipt 4df44c1e3e40
41
+ - Earlier-candidate PARTIAL (operator-attested, not this SHA): head b9fa0d2aa43e surface 60e424985df9 -- ["bash","run.sh","check-entwurf-v2-surface"] 20/20 receipt 490e9f96b8bd
42
+ - Earlier-candidate PARTIAL (operator-attested, not this SHA): head b9fa0d2aa43e surface 60e424985df9 -- ["bash","run.sh","check-mux-fresh-call"] 161/161 receipt fd3f4e91af7c
43
+ - Earlier-candidate PARTIAL (operator-attested, not this SHA): head b9fa0d2aa43e surface 60e424985df9 -- ["bash","run.sh","check-agent-guidance-beside"] 14/14 receipt d34e4f436e4a
44
+
7
45
  ## 0.51.0 — 2026-11-04
8
46
 
9
47
  Entwurf now runs on the Pi 1.5.0 SDK set (#155). The exact SDK closure grows from nine to ten members, the supported host Pi range moves to `>=1.5.0 <1.6`, and the pi-durable carrier follows the 1.5 durable API. An operating host moves to this version only through a planned cutover, because SDK 1.5's first write to a durable session is not readable by SDK 1.4.
@@ -84,6 +122,28 @@ The first five bullets record the plugin's re-pin to the published npm 0.50.0 ru
84
122
  - Earlier-candidate PARTIAL (operator-attested, not this SHA): head fe4780ee5c82 surface 811db89aeab8 -- ["bash","run.sh","check-pi-durable-carrier"] 59/59 receipt 0558e6e723a7
85
123
  - Earlier-candidate PARTIAL (operator-attested, not this SHA): head 434874ef6d6e surface b6cee8925072 -- ["bash","run.sh","check-pi-durable-carrier"] 66/66 receipt 822f2d8b950e
86
124
 
125
+ ### Final publication receipts — 2026-11-04 update
126
+
127
+ These receipts complete publication after the earlier-candidate measurements above. The core tag and published npm bytes remain unchanged; the Herdr follow-up below is a later source commit, not part of the tagged core artifact.
128
+
129
+ - **Shipping identity and CI.** Core `v0.51.0` is fixed at `32c31ea16487f9c8defa1ac07268b94d30ca5b27`. Its [push CI run 41704213407](https://github.com/junghan0611/entwurf/actions/runs/41704213407) passed all four required jobs: check, install-surface, artifact-consumer and macos-install-surface.
130
+ - **One accepted artifact.** [Windows producer run 41706422290](https://github.com/junghan0611/entwurf/actions/runs/41706422290) produced the canonical Windows-carrier TGZ, 11,710,142 bytes, SHA-256 `04fcce26d0a6dec8b8bb9a7f14a843eee0defb313aedafa34080600853d36e4d`. The producer's packed artifact, Windows-installed artifact and preserved download have the same hash. Linux accepted that same file without repacking. The candidate and its original acceptance receipts remain preserved; a carrier-bearing macOS install was not measured.
131
+ - **Human publication and registry proof.** npm records 0.51.0 at `2026-11-03T20:59:20.652Z`, after the operator's own publication. U2 restored the original pre-publication receipt (latest 0.50.0, repair 0.12.8-repair.1) and measured latest 0.51.0 with repair unchanged. The registry download is byte-identical to the accepted TGZ; its computed SHA-512 equals `dist.integrity`, and its SHA-1 equals `dist.shasum`. A private registry-installed Pi 1.5 consumer carried the same 668 files and listed the seven curated models without a model turn.
132
+ - **Evidence correction, not a hidden retry.** The post-publication wrapper sealed its log before appending a final 203-byte line. The original manifest remains 27 OK / 1 FAIL; its expected hash equals the current log with that final line removed. A separate, self-excluding correction receipt binds the current 31 files (SHA-256 `394becc3371c384fa96554b53e82c5a50cda8721424f54b21cedd2cd276d51cd`). No registry/install run or publication was repeated to conceal the seal-ordering defect.
133
+
134
+ ### Herdr post-publication follow-up — ce5a720
135
+
136
+ - **Published npm pairing.** [`ce5a720`](https://github.com/junghan0611/entwurf/commit/ce5a720) pins `@junghanacs/entwurf@0.51.0` with its measured registry SHA-512 and sets the plugin manifest to 0.51.0. The guides now describe the Pi 1.5.0 SDK set and host range `>=1.5.0 <1.6`; the README introduction includes retirement only on explicit request. Existing source-switch and same-source ownership conditions remain unchanged. The older prepare-time checkout-carrier statements above are historical, not the current main pin.
137
+ - **Source-specific private proof.** The registry-installed helper acquired real npm 0.50.0, swapped to 0.51.0, checked the compiled bridge, three executable bins, nine verbs and 668 byte-identical files, skipped acquisition on an exact re-request and removed its owned state. A separate manually seeded torn-state test restored the previous runtime before acquiring 0.51.0; it is not a real-kill experiment. A private build-runner journey activated pi/Claude Code through the installed package and its inverse removed the owned wiring/runtime, leaving the contracted empty Pi settings shell. This is not a public-ref Herdr plugin-registry journey.
138
+ - **Follow-up verification.** Sequential independent reviews and focused checks closed the six-file product/proof/documentation candidate over 32c31ea. The affected check-dep-versions PARTIAL killed 5/5 exactly once with their own QKs, both controls green and origin unchanged (receipt `c2edc00f5670a3915f0510b5b64eecd59119ed14e9691e05e0f1f7bc51ae1e44`); the other 1508 committed mutants were not executed. The frozen local FULL ran 963s, exit 0 / tee 0, with the seal unchanged; NEXT bookkeeping was reviewed afterwards. [Exact ce5a720 push CI run 41728277499](https://github.com/junghan0611/entwurf/actions/runs/41728277499) passed the four required jobs.
139
+ - **Not an operating rollout.** The operating GR208e remains the pre-D1 validation installation until the operator installs the accepted bytes and normally restarts the affected processes. Public-ref Herdr install/use/deactivation, a new plugin snapshot/tag and operating loaded-app acceptance remain separate, unmeasured steps. Neither this follow-up nor the release-note update moves the core tag, republishes npm or changes working citizens automatically.
140
+
141
+ ### Install-handoff incident and recovery — ThinkPad, 2026-11-04
142
+
143
+ - **Prepared is not installed.** The operator reported that the developer checkout had pulled `ce5a720` (SDK 1.5.0 source) while its dependencies were still SDK 1.4.0 and the prepared installation window was waiting for Enter. A local launch refused with `pi-durable-sdk-absent: carrier → @earendil-works/pi-schema wants 1.5.0, resolves nothing`. The installation had not run: its result file and backup did not yet exist. This was an approval-wait/install-completion handoff gap, not evidence of an SDK regression or lost conversation. The launcher correctly refused incomplete supply instead of opening the session with a mixed SDK set.
144
+ - **Recovery evidence, reported from that host.** After the operator explicitly authorized the installation, the ThinkPad coordinator reported `result.exit=0`, a complete 41-file native-profile backup whose source-before/backup/source-after manifests matched, unchanged global policy, host Pi 1.5.0 and a verified exact SDK 1.5.0 closure (27 physical edges). It returned under the same garden/native session identities; the old owner was absent, and the new owner and direct compiled bridge resolved through the intended checkout. The receipt states that the installer itself opened no operating session. The actual invocation of the prepared resume script was not asserted. These are the remote host's measurements, not an Oracle re-run or general rollout proof; the over-50-active-entry and conversation-switch UI cases were not re-measured there.
145
+ - **Reusable handoff rule.** Say prominently whether the installer has actually run or is still waiting for approval. A prepared window, a pulled source tree or a printed resume command is not installation success. Before presenting reopening as ready, require the installation's recorded exit 0 and coherent carrier/SDK verification; then use the intended same-session selector and original explicit native module. Keep normal old-owner exit and the consistent complete backup before the first new-SDK write. Never send Enter or install automatically to bypass the operator's approval.
146
+
87
147
  ## 0.50.0 — 2026-11-02
88
148
 
89
149
  Same-id resume now reaches every resumable backend on both launch rails. A dormant pi, pi-durable or Claude Code citizen reopens under its own garden id in a visible tmux window or, inside Herdr, a new Herdr tab, with no fallback from one rail to the other (#157). The CLI gains one description source, safe help and a thin `entwurf claude` entry (#153, continued in #157).
package/ENTWURF.json CHANGED
@@ -6,8 +6,14 @@
6
6
  "editing": "Preserve decoded strings exactly unless an explicit semantic amendment is intended. Review related consumers and independent oracles atomically. Accepted payload changes advance revision; history-only edits, routine releases and unrelated code changes do not. schemaVersion tracks reader/structural compatibility. A slotted hint holds only the text around its slot: the slot value (for record-less-socket, the fresh-cut command in both invocation forms) is supplied by its code owner and never copied here. Metadata is not delivered to models."
7
7
  },
8
8
  "schemaVersion": 6,
9
- "revision": 19,
9
+ "revision": 20,
10
10
  "history": [
11
+ {
12
+ "revision": 20,
13
+ "source": "b9fa0d2aa43ebefc1c3bd5bc864c84965b52289a",
14
+ "issue": "https://github.com/junghan0611/entwurf/issues/159",
15
+ "change": "Align delivery descriptions with completion and reply routing while preserving receipt, rail, and lifecycle boundaries."
16
+ },
11
17
  {
12
18
  "revision": 19,
13
19
  "source": "2734f524bfeca6eb1a0ae092494d45576af9ebef",
@@ -126,11 +132,11 @@
126
132
  "tools": {
127
133
  "entwurf_v2": {
128
134
  "descriptions": {
129
- "mcp": "CANONICAL DELIVERY SURFACE for garden ids: message, reply, or hand off to whoever an id names. The id alone does not say which rail that citizen answers on. Give target + intent; the decider picks transport from liveness (live socket citizen → control-socket send; deliverable self-fetch citizen → meta-bridge mailbox; probe-alive native-push citizen → direct injection into its conversation) and reports ONE outcome, named per rail: a control receiver's acceptance boundary (`sent` / `queued-steer` / `queued-follow-up` / `accepted-unknown-boundary` — those four, or `mailbox-enqueued` on a re-resolved mailbox leg), a mailbox ENQUEUE receipt, a native-push INJECTION, a rejection, or lock-dirty. This receipt is not the colleague's reply or evidence of reading. EXISTING targets only; discover with entwurf_peers. A live socket can receive fire-and-forget. unsupported means only \"no control-socket probe,\" not reachability. The decider resolves the actual rail at dispatch time: a self-fetch mailbox only while deliverable, native-push direct injection only while its adapter probe is alive, or a THIRD RESULT: rejection when neither holds. An inactive self-fetch citizen is mailbox-undeliverable; native-push has NO mailbox: dead → native-push-target-dead; indeterminate → native-push-probe-indeterminate; agy (paused, #152) → native-push-paused, no probe. A dormant socket rejects this delivery verb as dormant-fire-forget-unsupported. owned-outcome was withdrawn. Only on an explicit operator request, entwurf_resume_call may visibly reopen a proven-dormant Pi, pi-durable or Claude Code citizen under the same id, submitting no prompt; that lifecycle is separate from delivery. LOCK: taken for a control-socket-DOMAIN dispatch. The mailbox and native-push rails are lock-free — deliverability and the adapter probe guard them. mode applies to a CONTROL-SOCKET send only; other plans carry no mode. wants_reply rides every rail. message caps at 16000 chars; send an artifact path + digest for more.",
130
- "durable": "Send a message to an existing garden citizen by garden id through the entwurf-bridge (intent fire-and-forget). Returns the bridge's delivery receipt, or fails with its named rejection. This receipt is not the colleague's reply."
135
+ "mcp": "Send, reply or hand off to an existing garden id; the decider selects the live rail (live socket citizen → control-socket send; deliverable self-fetch citizen → meta-bridge mailbox; probe-alive native-push citizen → direct injection into its conversation) and reports ONE outcome, named per rail: a control receiver's acceptance boundary (`sent` / `queued-steer` / `queued-follow-up` / `accepted-unknown-boundary` — those four, or `mailbox-enqueued` on a re-resolved mailbox leg), a mailbox ENQUEUE receipt, a native-push INJECTION, a rejection, or lock-dirty. A receipt is not a reply or proof of reading. A local final is not delivery: when asked to reply, call entwurf_v2 for the requested recipient (normally the replyable sender); honor routing and no-send instructions. Discover existing targets with entwurf_peers. A live socket can receive fire-and-forget; unsupported means only \"no control-socket probe,\" not reachability. For a target without a live socket, the THIRD RESULT is rejection if neither mailbox nor native-push is available. An inactive self-fetch citizen is mailbox-undeliverable; native-push has NO mailbox: dead → native-push-target-dead; indeterminate → native-push-probe-indeterminate; agy (paused) → native-push-paused, no probe. A dormant socket rejects this delivery verb as dormant-fire-forget-unsupported. This delivery verb never launches or resumes a process. Only on an explicit operator request, entwurf_resume_call may visibly reopen a proven-dormant Pi, pi-durable or Claude Code citizen under the same id, submitting no prompt; that lifecycle is separate from delivery. A control-socket-DOMAIN dispatch takes a target lock; mailbox and native-push rails are lock-free. mode applies only to a CONTROL-SOCKET send. wants_reply requests a response without authorizing an action or requiring an automatic acknowledgment; an absent or false marker does not cancel a request in the message. message caps at 16000 chars; send an artifact path + digest for more.",
136
+ "durable": "Send, reply or hand off to an existing garden id through entwurf-bridge (intent fire-and-forget), returning a delivery receipt or named rejection. The receipt is not a reply or proof of reading. For a requested reply, send to the authorized recipient, normally the replyable sender; a local final is not delivery. Honor routing and no-send instructions; an absent or false wants_reply does not cancel a request, and an address alone needs no ACK."
131
137
  },
132
138
  "parameters": {
133
- "intent": "fire-and-forget = send/reply/hand-off to an existing target after a current rail check. unsupported is not a reachability verdict; the decider picks a rail or REJECTS (self-fetch → mailbox when deliverable, else mailbox-undeliverable; native-push → alive: direct injection, dead: native-push-target-dead, indeterminate: native-push-probe-indeterminate; a paused backend — agy, #152 — rejects as native-push-paused before any probe); set wants_reply to request an answer, not to wait for one. This is the ONLY intent: owned-outcome, which resumed a dormant citizen by launching a hidden background child, was withdrawn under the visible-first rule. It is not selectable, not deprecated-but-tolerated; a dormant socket citizen is currently unreachable by this verb and rejects as dormant-fire-forget-unsupported.",
139
+ "intent": "fire-and-forget sends, replies or hands off to an existing target after a current rail check. unsupported is not a reachability verdict: self-fetch uses a deliverable mailbox or rejects as mailbox-undeliverable; native-push injects when alive, rejects dead as native-push-target-dead and indeterminate as native-push-probe-indeterminate; paused agy rejects as native-push-paused before probing. wants_reply requests a response, not a wait. This delivery verb never launches or resumes a process; a dormant socket rejects as dormant-fire-forget-unsupported.",
134
140
  "message": "Message / prompt to the colleague. In familiar language and natural sentences, convey what matters now and the context they need. Keep identifiers and evidence exact; trim repetition, not meaning. Hard cap 16000 chars; for larger payloads send a file/artifact path plus digest.",
135
141
  "mode": "Injection style for a CONTROL-SOCKET send only: steer (ask the receiver's steering queue) or follow_up (ask its follow-up queue). NEITHER is an interrupt: a busy receiver drains steering after each turn and follow-ups only when its inner loop ends, so a later steer overtakes every earlier follow_up and there is no order between the two. Both queues are volatile process memory — an abort drops what is in them. The receipt names which queue accepted the message (`queued-steer` / `queued-follow-up`); an idle receiver answers `sent`, meaning the turn was TRIGGERED, not that the model has seen the text. The mailbox and native-push plans carry no mode, so it has no effect on those rails.",
136
142
  "target": "Target garden id (use entwurf_peers to discover)",
package/README.md CHANGED
@@ -1,9 +1,9 @@
1
1
  # entwurf
2
2
 
3
- `entwurf` connects independent agent harnesses as visible siblings. Open a fresh sibling, or reopen
4
- or message an existing one by its **garden id**. Every harness keeps its own runtime,
5
- authentication, tools and transcript; Entwurf adds identity, delivery, receipts and named
6
- lifecycle verbs.
3
+ `entwurf` connects independent agent harnesses as visible siblings. Open a fresh sibling, or reopen,
4
+ message or retire an existing one by its **garden id**—retirement only on your explicit request.
5
+ Every harness keeps its own runtime, authentication, tools and transcript; Entwurf adds identity,
6
+ delivery, receipts and named lifecycle verbs.
7
7
 
8
8
  ![entwurf — a forged screwdriver for visible sibling sessions](docs/assets/entwurf-hero.jpg)
9
9
 
package/VERIFY.md CHANGED
@@ -381,7 +381,7 @@ The goal is not merely "invoke Claude Code." We want:
381
381
  **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.
382
382
 
383
383
  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`)
384
- 2. pi wiring → `<project>/.pi/settings.json` + user-scope registration — only when a `pi` inside the supported range (`>=1.5.0 <1.6`) 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
384
+ 2. pi wiring → `<project>/.pi/settings.json` + user-scope registration — only when a `pi` inside the supported range (`>=1.5.2 <1.6`) 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
385
385
  3. Claude meta-bridge global plugin — only when `claude` is on PATH; otherwise skipped cleanly
386
386
  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
387
387
  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
@@ -24,7 +24,7 @@ takes/helpers/tests are maintainer tooling and are deliberately excluded from th
24
24
 
25
25
  - Node at the `package.json#engines.node` floor; the checkout's pinned dependencies and
26
26
  current compiled bridge. After a source/bootstrap change, build with `pnpm run build-bridge`.
27
- - Pi at the checkout's supported floor (**current floor 1.5.0**); `entwurf` on PATH must be
27
+ - Pi at the checkout's supported floor (**current floor 1.5.2**); `entwurf` on PATH must be
28
28
  the intended source stable-bin. Source evidence is not registry-package acceptance.
29
29
  - `herdr` on PATH at exactly `scripts/fixtures/herdr-supply.json#version`; `asciinema` v3.
30
30
  - Herdr's existing Pi integration at
@@ -135,7 +135,7 @@ Dep bump ledger. 0.38.0 (#145) changes only the pi SDK set; the ACP rows are unc
135
135
  | Surface | Declaration | Class | What a green actually says |
136
136
  |---|---|---|---|
137
137
  | Entwurf package | `package.json` `version` | checkout declaration, not a release receipt | names the package label these rows sit beside; whether that label shipped, and with which rows, is CHANGELOG's record |
138
- | pi runtime | SDK exact `1.5.0`, host `>=1.5.0 <1.6` | **exact** oracle + **closed range** | the #155 development checkout's declared SDK set and derived host range, not a release or operating-host acceptance; an ordinary Pi host inside the range is accepted by the source's version predicate, and the ceiling moves only on measurement. The published 0.36.0 through 0.37.1 shipped the 1.2.0 set (#141); 0.38.0 (#145) is the first to carry 1.3.0. Historical: the published 0.33.0 through 0.35.1 ship SDK exact 1.1.0, 0.32.0 ships SDK exact 1.0.4 with the next-minor ceiling (ROADMAP's 2026-10-07 bump entry), and 0.31.0 declared the earlier peer floor 1.0.2 |
138
+ | pi runtime | SDK exact `1.5.2`, host `>=1.5.2 <1.6` | **exact** oracle + **closed range** | the #158 source candidate's declared SDK set and derived host range (the published 0.51.0 shipped SDK 1.5.0, #155), not a release or operating-host acceptance; an ordinary Pi host inside the range is accepted by the source's version predicate, and the ceiling moves only on measurement. The published 0.36.0 through 0.37.1 shipped the 1.2.0 set (#141); 0.38.0 (#145) is the first to carry 1.3.0. Historical: the published 0.33.0 through 0.35.1 ship SDK exact 1.1.0, 0.32.0 ships SDK exact 1.0.4 with the next-minor ceiling (ROADMAP's 2026-10-07 bump entry), and 0.31.0 declared the earlier peer floor 1.0.2 |
139
139
  | ACP wire SDK | `@agentclientprotocol/sdk 1.8.0` | **exact** | the shared wire oracle both adapters speak |
140
140
  | Claude ACP adapter | `@agentclientprotocol/claude-agent-acp 0.90.0` | **exact**, bundled | shipped since 0.36.1; resolved before any PATH fallback; declaration is not compatibility evidence |
141
141
  | Claude Agent SDK | `0.3.296` (transitive) | **exact** oracle | the runtime risk surface behind the adapter |
@@ -23,26 +23,26 @@ evidence split, and its three states must not collapse into "macOS is supported"
23
23
 
24
24
  ## Requirements
25
25
 
26
- This table and the 1.4-specific install examples below describe the published `@junghanacs/entwurf@0.50.0`, which ships the Pi 1.4.0 SDK set. The #155 0.51.0 preparation at `434874ef6d6e399a0ae6813c850d01c5232eb1d9` pins SDK 1.5.0; its separate validation TGZ was installed in the approved operating window, but is not the still-unpublished final shipping artifact. npm publication requires its own authority. See the [SDK 1.5 boundary](#sdk-15-development-boundary-155) below; these 0.50 instructions do not select or prove 0.51 bytes.
27
- The previous package, `0.41.0`, ships the Pi 1.3.0 SDK set and requires Pi 1.3.x; the setup guide
28
- inside that tarball is its contract.
26
+ The requirements table and pinned npm examples describe published Entwurf 0.51.0, whose exact SDK set is 1.5.0. The unpublished 0.52.0 source candidate (#158) instead pins SDK 1.5.2 and declares host Pi `>=1.5.2 <1.6`. Source validation, publication and a running host's loaded bytes are separate evidence; an addon-less validation tarball has been installed on one operating host, with same-identity return observed for the operating coordinator; that bounded observation is not full release or all-rail acceptance (see the [#158 candidate boundary](#sdk-152-candidate-boundary-158)).
27
+
28
+ The validation TGZ installed in #155's operating window before the D1 display repair is an earlier, separate artifact, not the published one; see the [SDK 1.5 boundary](#sdk-15-development-boundary-155) below.
29
+
30
+ The previous package, `0.50.0`, ships the Pi 1.4.0 SDK set and requires a Pi 1.4.x host; the setup guide inside that tarball is its contract.
29
31
 
30
- <!-- entwurf:published @junghanacs/entwurf@0.50.0 pi 1.4.0 -->
31
32
  | Component | Requirement | Needed for |
32
33
  |---|---|---|
33
34
  | Node | **`>=24.0.0`** | package and bridge runtime |
34
35
  | npm/pnpm | npm is bundled with Node; pnpm is required for source setup | package or source installation |
35
36
  | Python 3 | required by `setup`/`install` (project-path normalization + settings writers); `--help`/`check-bridge` stay Python-free | pi/Claude/agy/Copilot/Codex wiring writers |
36
37
  | entwurf | global/project-local `@junghanacs/entwurf`, or a source checkout | operator command and garden capability |
37
- | pi | optional-by-presence, `>=1.4.0 <1.5` — absent is an explicit setup SKIP, below-floor is a named FAIL | ACP provider, control sockets |
38
- | Native durable (`pi-durable`) | supplied by the Entwurf package (#130): Entwurf's owned app carrier plus the exact 1.4.0 pi SDK set as production dependencies — setup PASS when they verify, a named FAIL otherwise (never SKIP) | the `entwurf pi-durable` contact; native birth/LIVE on this supply surface is a separate release proof (§2b) |
38
+ | pi | optional-by-presence — published 0.51.0: <!-- entwurf:published @junghanacs/entwurf@0.51.0 pi 1.5.0 -->`>=1.5.0 <1.6`<!-- /entwurf:published -->; #158 source candidate: `>=1.5.2 <1.6`. Absent is an explicit setup SKIP, below-floor is a named FAIL | ACP provider, control sockets |
39
+ | Native durable (`pi-durable`) | supplied by the Entwurf package (#130): Entwurf's owned app carrier plus its exact pi SDK set (1.5.0 in published 0.51.0; 1.5.2 in the #158 source candidate) as production dependencies — setup PASS when they verify, a named FAIL otherwise (never SKIP) | the `entwurf pi-durable` contact; native birth/LIVE on this supply surface is a separate release proof (§2b) |
39
40
  | Claude Code | optional, **`>=2.1.306`** — the exec-form hook floor | Claude ACP auth/runtime and mailbox-backed native citizen |
40
41
  | GitHub Copilot CLI | optional-by-presence, operator-installed and authenticated — absent is an explicit setup SKIP; detected composes all four units (birth/MCP/receiver/footer) | self-fetch citizen and visible fresh |
41
42
  | OMP (`omp`) | optional-by-presence, operator-installed — absent is an explicit setup SKIP; detected composes all four units (birth/MCP/`tools.xdev` setting/receiver) | self-fetch citizen and visible fresh (accepted on one host — see §4b) |
42
43
  | Antigravity `agy` | optional, operator-installed and authenticated | legacy citizen; native push paused (#152) |
43
44
  | OpenAI Codex CLI | optional-by-presence, operator-installed and authenticated; detected composes all four operator-owned units (birth/MCP/status-line/terminal-title) and stays non-green until the operator trusts the birth declaration once in a visible Codex; visible fresh also requires the operator-owned app-server, started with `entwurf codex-app-server` in a tmux session of the operator's choosing (#95 D1 retired the fixed `codex` home) | native-push and visible fresh, supported in 0.21.0 |
44
45
  | Cortex Code | optional, operator-installed and authenticated | Cortex ACP backend |
45
- <!-- /entwurf:published -->
46
46
 
47
47
  Claude Code >=2.1.306 is required for the managed exec-hook lifecycle and same-id resume. The package
48
48
  never supplies or proxies backend credentials.
@@ -85,8 +85,8 @@ node --version
85
85
  npm --version
86
86
  ```
87
87
 
88
- The two npm forms below install the **published** package, `0.50.0` (Pi 1.4.x, the Pi 1.4.0 SDK
89
- set). The [product entry](../README.md#install)'s unpinned `npm install -g @junghanacs/entwurf`
88
+ The two npm forms below install the **published** package, `0.51.0` (Pi 1.5.x, the Pi 1.5.0 SDK
89
+ set); they do not install the #158 source candidate (SDK 1.5.2), which is not published — a developer runs that from a source checkout (below). The [product entry](../README.md#install)'s unpinned `npm install -g @junghanacs/entwurf`
90
90
  takes whichever version npm's `latest` dist-tag names; pin `@<version>` as below when you mean the
91
91
  exact artifact the [Requirements](#requirements) table describes.
92
92
 
@@ -94,7 +94,7 @@ Global install is simplest when native harnesses should find stable bins from ev
94
94
  working directory:
95
95
 
96
96
  ```bash
97
- npm install -g @junghanacs/entwurf@0.50.0
97
+ npm install -g @junghanacs/entwurf@0.51.0
98
98
  entwurf --help
99
99
  entwurf setup /path/to/your-project
100
100
  entwurf check-bridge
@@ -105,7 +105,7 @@ A project-local installation is also supported:
105
105
  ```bash
106
106
  mkdir -p ~/entwurf-smoke && cd ~/entwurf-smoke
107
107
  npm init -y
108
- npm install --save-dev @junghanacs/entwurf@0.50.0
108
+ npm install --save-dev @junghanacs/entwurf@0.51.0
109
109
  npx entwurf setup .
110
110
  npx entwurf check-bridge
111
111
  ```
@@ -115,7 +115,7 @@ project-local install, or `./run.sh <command>` from a source checkout. Keep that
115
115
  same scope when upgrading and checking; native process restarts are separate (§7).
116
116
 
117
117
  `check-bridge` is auth-free. It proves the installed prebuilt MCP server boots and
118
- lists the nine garden tools (0.50.0); it does not prove a backend model turn, native hook or retirement permission.
118
+ lists the nine garden tools (0.51.0); it does not prove a backend model turn, native hook or retirement permission.
119
119
 
120
120
  Neither npm form installs a harness runtime. `pi`, Claude Code, Copilot CLI, Codex CLI, agy,
121
121
  Cortex, and their authentication remain operator-owned optional prerequisites for the
@@ -226,13 +226,12 @@ physical-Darwin receipt. `entwurf install` may write `.pi/settings.json`
226
226
  on Darwin; that is wiring, not a rail receipt. If `pi` is on PATH,
227
227
  `setup` names the pi row FAIL with the §1 Darwin wording.
228
228
 
229
- Install the exact release floor, then wire the project. The previous 0.41.0 instead takes the
230
- Pi 1.3.x its own setup guide names. A source checkout passes its checkout path to `-e` in place of
231
- the global package root:
229
+ <!-- entwurf:published @junghanacs/entwurf@0.51.0 pi 1.5.0 -->
230
+ For published Entwurf 0.51.0, install its exact host Pi floor and wire the project as shown below.
231
+ The previous 0.50.0 uses the Pi 1.4.x host named in its own setup guide:
232
232
 
233
- <!-- entwurf:published @junghanacs/entwurf@0.50.0 pi 1.4.0 -->
234
233
  ```bash
235
- npm install -g @earendil-works/pi-coding-agent@1.4.0
234
+ npm install -g @earendil-works/pi-coding-agent@1.5.0
236
235
  pi --version
237
236
 
238
237
  cd ~/entwurf-smoke
@@ -240,12 +239,14 @@ entwurf install .
240
239
  pi -e "$(npm root -g)/@junghanacs/entwurf" --list-models entwurf
241
240
  ```
242
241
 
243
- The supported range is `>=1.4.0 <1.5`. It is a hard minimum: installing this
244
- release onto a 0.83.x pi host upgrades the runtime rather than keeping the older
245
- minor. A host using only the external MCP bridge can skip pi until it needs a
242
+ The supported host Pi range for published Entwurf 0.51.0 is `>=1.5.0 <1.6`.
243
+ A detected host outside that range is refused for Pi wiring; Entwurf does not upgrade it.
244
+ Align the host explicitly, for example with the exact npm command above, before wiring Pi. A host using only the external MCP bridge can skip pi until it needs a
246
245
  control socket; no delivery rail launches a pi process.
247
246
  <!-- /entwurf:published -->
248
247
 
248
+ The #158 source candidate instead requires host Pi `>=1.5.2 <1.6`; checkout `setup` reports a detected older host as FAIL. Prepare host Pi 1.5.2 before wiring this checkout, and use the checkout path rather than the global npm package for a direct `pi -e` invocation. Host Pi 1.5.2 also falls within published 0.51.0's declared range, but #158 has not measured that pairing; range eligibility does not replace installation, validation or operating approval. Ordinary Pi 1.5.2 defaults its global `cacheWarming` setting to `idle`, which may send additional provider requests; pi-durable does not map that setting. See the [#158 durable boundary](./durable-native-support.md#sdk-152-candidate-boundary-158).
249
+
249
250
  For daily garden-native pi sessions:
250
251
 
251
252
  ```bash
@@ -263,7 +264,7 @@ A plain `pi` can load the package without becoming a citizen.
263
264
  In that session ask for `entwurf_self`, then `entwurf_peers`. Pick an existing
264
265
  live garden id and ask for `entwurf_v2` with `intent: "fire-and-forget"` and your
265
266
  message. These are harness tools, not shell subcommands; pi exposes them through
266
- Pi's built-in MCP as `mcp__entwurf_bridge__<verb>`. The 0.50.0 bridge has nine tools;
267
+ Pi's built-in MCP as `mcp__entwurf_bridge__<verb>`. The 0.51.0 bridge has nine tools;
267
268
  pi hides `entwurf_inbox_read` and `entwurf_register_native`, leaving seven active.
268
269
  The added `entwurf_retire_call` is only for one target/action explicitly requested by the
269
270
  human operator, never autonomous cleanup. Where a host provides or is configured with an approval
@@ -348,11 +349,12 @@ by `entwurf pi` or by registering ordinary Pi's adapter.
348
349
 
349
350
  What the Entwurf package supplies:
350
351
 
351
- 1. **The pi SDK set** — in the 0.51.0 prepared checkout, `@earendil-works/{pi-coding-agent, pi-ai, pi-tui, pi-agent-core,
352
+ 1. **The pi SDK set** — published 0.51.0 supplies `@earendil-works/{pi-coding-agent, pi-ai, pi-tui, pi-agent-core,
352
353
  pi-durable, chord, pi-mcp, pi-codemode, pi-telemetry, pi-schema}` at exactly `1.5.0`, plus
353
- `proper-lockfile`, as Entwurf's own production dependencies. The authoritative current set is
354
- the [SDK pin](../pi/pi-durable/overlay/upstream-pin.json) and [package manifest](../package.json);
355
- for this candidate, model data rides `@earendil-works/pi-ai@1.5.0`, not a catalog copy.
354
+ `proper-lockfile`, as Entwurf's own production dependencies; its model data rides <!-- entwurf:published @junghanacs/entwurf@0.51.0 pi 1.5.0 -->`@earendil-works/pi-ai@1.5.0`<!-- /entwurf:published -->, not a catalog copy.
355
+ The #158 source candidate supplies the same ten-member set at exactly `1.5.2` (its model data rides the 1.5.2 pi-ai). The
356
+ [SDK pin](../pi/pi-durable/overlay/upstream-pin.json) and [package manifest](../package.json) are the authority
357
+ for the checkout you hold: they describe the source candidate, not the immutable published 0.51.0 bytes.
356
358
  2. **The native app/TUI carrier** — upstream does not publish the experimental durable
357
359
  app (`pi-coding-agent` excludes `dist/experimental`; `pi-durable` on npm is the
358
360
  library). Entwurf owns the six app files as canonical source (`pi/pi-durable/src`,
@@ -362,9 +364,9 @@ What the Entwurf package supplies:
362
364
  (`pi/pi-durable/carrier-resolver.mjs`), which maps them to the published package's
363
365
  own `dist/` as installed — never through a source checkout.
364
366
 
365
- The upstream [library guide](https://github.com/earendil-works/pi/blob/v1.5.0/packages/durable/README.md)
366
- and the [experimental app guide](https://github.com/earendil-works/pi/blob/v1.1.0/packages/coding-agent/src/experimental/durable/README.md)
367
- (last published at v1.1.0) describe what the carrier is. Running the bare upstream app does not attach Entwurf's
367
+ The upstream library guide for the published 0.51.0 pairing is [v1.5.0](https://github.com/earendil-works/pi/blob/v1.5.0/packages/durable/README.md); for the #158 candidate's SDK APIs use [v1.5.2](https://github.com/earendil-works/pi/blob/v1.5.2/packages/durable/README.md).
368
+ The [experimental app guide](https://github.com/earendil-works/pi/blob/v1.1.0/packages/coding-agent/src/experimental/durable/README.md)
369
+ (last published at v1.1.0) records the app's origin: Entwurf's maintained app source, not a newer upstream app, is the current composition authority. Both guides describe what the carrier is. Running the bare upstream app does not attach Entwurf's
368
370
  garden contact. Entwurf does not rebuild the controller/model/auth/storage system or
369
371
  proxy a subscription; native execution, models, auth, queues, SQLite and recovery stay
370
372
  upstream-owned.
@@ -377,7 +379,7 @@ carrier file, the license, the resolver and its relocation grammar are present
377
379
  (`pi-durable-carrier-drift`); every declared SDK package resolves from the carrier
378
380
  (`pi-durable-sdk-absent`); and every reachable physical edge — from the carrier to each package,
379
381
  and from every package copy it reaches, at any depth, to its own `@earendil-works` dependencies —
380
- lands on a package of the declared name at exactly the pinned version (`pi-durable-sdk-mismatch`). The members' declarations are exact in the prepared 1.5.0 set; even so, the physical package each import binds must be checked. Sharing
382
+ lands on a package of the declared name at exactly the pinned version (`pi-durable-sdk-mismatch`). The members' declarations are exact in the published 1.5.0 set and, measured on the registry tarballs (#158), in the 1.5.2 candidate set; even so, the physical package each import binds must be checked. Sharing
381
383
  one copy with an aligned host install of the same version is an ordinary layout. A mixed
382
384
  tree (for example an override that binds pi-durable's `pi-ai` to an older published version) still
383
385
  *imports* — which is why the edge check exists — and is refused by name.
@@ -459,9 +461,9 @@ tree (for example an override that binds pi-durable's `pi-ai` to an older publis
459
461
  manifest field; it is a known constraint of supplying both from one package, accepted for 0.32,
460
462
  not a claim that every load path is harmless.
461
463
 
462
- The ordinary Pi CLI on PATH is a separate subject (§2, range <!-- entwurf:published @junghanacs/entwurf@0.50.0 pi 1.4.0 -->`>=1.4.0 <1.5`<!-- /entwurf:published -->): a host Pi is
464
+ The ordinary Pi CLI on PATH is a separate subject (§2; published 0.51.0 range <!-- entwurf:published @junghanacs/entwurf@0.51.0 pi 1.5.0 -->`>=1.5.0 <1.6`<!-- /entwurf:published -->, #158 source candidate range `>=1.5.2 <1.6`): a host Pi is
463
465
  not needed to run pi-durable, and a host inside the range need not be the same copy as the
464
- carrier's. Native Pi owns credentials, model settings and durable SQLite sessions; keep them
466
+ carrier's. The native harnesses own credentials, model settings and their respective session stores — ordinary Pi JSONL and pi-durable SQLite; keep them
465
467
  in place rather than copying credentials or migrating ordinary Pi transcripts. Native
466
468
  recovery does not prove exactly-once Entwurf dispatch or inbox read recovery. The contact
467
469
  provides garden attachment, visible identity and announce-only root-directed self-fetch.
@@ -472,12 +474,18 @@ proof ([#130](https://github.com/junghan0611/entwurf/issues/130)).
472
474
 
473
475
  ### SDK 1.5 development boundary (#155)
474
476
 
475
- The published 0.50.0 / SDK 1.4.0 instructions above and the #155 SDK 1.5 development
476
- candidates are distinct subjects. Synthetic migration and downgrade-refusal fixtures on `0408a66`
477
- did not authorize an operating first write. A separately approved 1.5 operating window and Native
478
- LIVE were later measured as described below; neither makes the validation TGZ the final release
479
- artifact. Installing an older package is not a data rollback. Follow the current evidence in
480
- [#155](https://github.com/junghan0611/entwurf/issues/155), not the 1.3→1.4 receipt below.
477
+ The published-0.51.0 instructions above describe the SDK 1.5.0 set that #155 shipped; the #155 SDK
478
+ 1.5 development candidates that preceded it were distinct subjects. Synthetic migration and
479
+ downgrade-refusal fixtures on `0408a66` did not authorize an operating first write. A separately
480
+ approved 1.5 operating window and Native LIVE were later measured as described below; neither made
481
+ the validation TGZ the published artifact. Installing an older package is not a data rollback. Follow the current evidence in
482
+ [#155](https://github.com/junghan0611/entwurf/issues/155), not the 1.3→1.4 receipt below. The #158 source candidate is a separate boundary, next.
483
+
484
+ ### SDK 1.5.2 candidate boundary (#158)
485
+
486
+ The 0.52.0 source candidate (#158) pins the Pi SDK at exactly 1.5.2 (ten members) and declares host Pi `>=1.5.2 <1.6`. Assigning that version does not publish or install it: the published instructions above still describe 0.51.0 / SDK 1.5.0, and an operating move requires its own installation and same-identity return receipts. The #155 receipts above prove their own subject only; none is inherited by 1.5.2.
487
+
488
+ What #158 measured so far and what it did not is recorded in [the durable-native boundary](./durable-native-support.md#sdk-152-candidate-boundary-158) and in the #158 thread: registry tarball integrity and member edges, an isolated six-member scheduler comparison and a native SQLite cross-version read/append check. The pre-version checkpoint's frozen FULL belongs to its own recorded worktree. The earlier validation candidate has its own floor and installation receipts; later source edits and the final carrier-bearing artifact require their own acceptance. Operating-scale and interrupted sessions are not certified by the bounded fixtures. An operating move follows the default radius below, each step with its own receipt.
481
489
 
482
490
  ### Default radius for a requested Pi SDK upgrade
483
491
 
@@ -493,17 +501,19 @@ The measured precedent is [#148's pre-cutover hold](https://github.com/junghan06
493
501
 
494
502
  Push, release/tag/npm publication and retirement of any other citizen retain their separate authorization boundaries. This decision fixes the repeatable method; it does not pre-authorize those actions.
495
503
 
504
+ **Installation handoff: prepared is not installed.** State prominently whether the installer has actually run or is still waiting for the operator's approval. A prepared terminal, a pulled checkout or a printed resume command is not success. Keep the normal old-owner exit and consistent complete backup gates; before presenting the reopen step as ready, require the recorded installation exit 0 and coherent carrier/SDK verification. Then reopen the intended same session with its original explicit native module. Do not automatically send Enter, install or switch ownership to bridge an approval wait. The [0.51.0 ThinkPad incident](../CHANGELOG.md#install-handoff-incident-and-recovery--thinkpad-2026-11-04) records a new-source/old-dependency launch refusal and the separately authorized recovery; it is not evidence of data loss or an SDK regression.
505
+
496
506
  **Recurring SDK rail.** At task start, agree the exact SDK and the scope of development, review and verification once; do not repeatedly ask for the existing-auth strategy. Inspect the published SDK set and upstream changes, isolate the development checkout from operating runtimes, and implement against the coherent pinned set in private HOME, PI and writable XDG roots. Use the gate's own temporary-directory constraints: the #155 FULL's deeper scratch produced 117/109-byte socket paths and EINVAL; run3 used `TMPDIR=/tmp` with each gate creating its own private scratch and passed. Preserve both `pnpm_config_verify_deps_before_run=error` and `npm_config_verify_deps_before_run=error`, managed builds and candidate seals; do not run offline gates under ambient CI.
497
507
 
498
508
  The owned canonical app/TUI source is production responsibility; the SDK owns the execution engine. In independent upgrade review, compare old and new app-visible payload semantics against known fixtures and a separate official SDK oracle: more than 50 active entries on reopen and same-process conversation switch, head/reset and background-compaction retention, and the distinction from model memory. API names, typechecks or a QK that only fixes the new SDK's window can all be green while older display compatibility regresses. When official emission changes a generated digest, check its pin-linked mutant find literal and the existing manifest inventory together; this is not a new gate.
499
509
 
500
- Freeze for sequential independent review, then affected PARTIAL groups, frozen FULL and applicable scripted/native-H carrier cells. Accept the **same reviewed validation TGZ** in the Linux container and rehearse ownership refusal/takeover in isolation. Measure SDK publication age early to plan the window, then recheck it fresh before installation; never automatically exempt the global policy.
510
+ Freeze for sequential independent review, then affected PARTIAL groups, frozen FULL and applicable scripted/native-H carrier cells. Accept the **same reviewed validation TGZ** in the Linux container and rehearse ownership refusal/takeover in isolation. Measure SDK publication age early to plan the window, then recheck it fresh before installation; never automatically exempt the global policy. Any operator-approved exception must name the exact packages and versions and be recorded with that upgrade's decision; it is not a standing patch-release exemption and not permission for an operating cutover. For #158 the operator explicitly approved the exact SDK 1.5.2 release-age exception on 2026-11-11: only those ten member/version terms are added to `minimumReleaseAgeExclude`, and the global policy and every other dependency remain subject to their own checks. That differs from #155's dated no-exception installation and authorises no operating write or publication.
501
511
 
502
512
  In the named operating window, identify owners, obtain their normal exit and prove it, then take a consistent complete session backup including WAL/SHM before the first new-SDK write. Install a coherent host and validation TGZ, verify installed global root (GR), runtime and ownership independently, and perform only the approved takeover. Reopen the same identities with their original explicitly named native modules and existing auth; observe real turns and round trips before the Native LIVE floor. Public pi-durable `entwurf_resume_call` is bridge-only: it does not save or restore operator native modules. If one is needed, use the original explicit CLI entry; do not infer a profile or kill a citizen automatically. One approval can cover the named scope, sibling roles and fixture work, but not bypass normal exit, the first-write decision, or separate push/npm authority.
503
513
 
504
514
  For each named Native fixture, record the runtime root and SDK actually selected separately from the operator installation: a private PATH can select the genuine source CLI while an ordinary Pi extension still comes from an older installed GR. Do not substitute a wrapper or rewire the operating host to make the evidence agree. A planned source-CLI Native run is not a completed receipt.
505
515
 
506
- **#155 measured example (2026-11-03; before the D1 display repair):** at 20:47 KST host Pi 1.5.0 and the unpublished, addon-less 0.51.0 validation TGZ (SHA-256 `199e5f41d20e5b2665125868b7e3e27740e5985f7a25ac61902126b7ed638bf5`) were installed, not the final publication artifact. Four owners exited normally; the 171-file durable backup's source-before/backup/source-after manifests matched (`5c08bed1968fd1e26baa58112f0ce5c36874e147ccc5e9b4c69ec1a0d9070a46`); two Pi transcripts were also backed up. All ten SDK members were freshly measured at 24.70–24.84 hours old, without a policy exception. The P5 Native LIVE cut recorded MUST 24/0/0 and BEHAVIOR 1/0/0 (pass/fail/skip) on its own sealed candidate, not the prepared SHA. Native-host criterion 4 separately measured a fresh Claude Code fixture's actual installed 0.51 MCP child and strict doctor; existing pre-cutover Claude sessions retained their loaded 0.50 bridge. Neither the 20:47 installation nor P5 proves that the later D1 display repair is operating: the D1-bearing artifact must first be installed, and the human must then restart the process; restarting against the earlier artifact still loads the old app. See [0.51.0 release evidence](../CHANGELOG.md#release-evidence) for scopes and receipts.
516
+ **#155 measured example (2026-11-03; before the D1 display repair):** at 20:47 KST host Pi 1.5.0 and the unpublished, addon-less 0.51.0 validation TGZ (SHA-256 `199e5f41d20e5b2665125868b7e3e27740e5985f7a25ac61902126b7ed638bf5`) were installed, not the final publication artifact. Four owners exited normally; the 171-file durable backup's source-before/backup/source-after manifests matched (`5c08bed1968fd1e26baa58112f0ce5c36874e147ccc5e9b4c69ec1a0d9070a46`); two Pi transcripts were also backed up. All ten SDK members were freshly measured at 24.70–24.84 hours old, without a policy exception. The P5 Native LIVE cut recorded MUST 24/0/0 and BEHAVIOR 1/0/0 (pass/fail/skip) on its own sealed candidate, not the prepared SHA. Native-host criterion 4 separately measured a fresh Claude Code fixture's actual installed 0.51 MCP child and strict doctor; existing pre-cutover Claude sessions retained their loaded 0.50 bridge. Neither the 20:47 installation nor P5 proves that the later D1 display repair is operating: the D1-bearing artifact must first be installed, and the human must then restart the process; restarting against the earlier artifact still loads the old app. See [0.51.0 release evidence](../CHANGELOG.md#0510--2026-11-04) for scopes and receipts.
507
517
 
508
518
  The Windows-bearing release TGZ, its Linux acceptance, exact prepared-SHA CI, installed-host acceptance and publication/registry proof are separate later evidence. Re-measure owners, loaded bytes, version/integrity, backup and candidate evidence on every upgrade; this ordering does not guarantee success for a future SDK.
509
519
 
@@ -773,7 +783,7 @@ as a note rather than a fault.
773
783
 
774
784
  **entwurf sets no OMP version floor in code, and will not grow one on schedule.** Detection is
775
785
  presence-only (`command -v "${OMP_BIN:-omp}"`); there is no `entwurf.ompFloor`, no coherence
776
- gate, and no exact pin — unlike Node (`engines.node`), pi (<!-- entwurf:published @junghanacs/entwurf@0.50.0 pi 1.4.0 -->`>=1.4.0 <1.5`<!-- /entwurf:published --> for published 0.50.0) and Claude Code
786
+ gate, and no exact pin — unlike Node (`engines.node`), pi (the #158 checkout's predicate, `>=1.5.2 <1.6`) and Claude Code
777
787
  (`entwurf.claudeCodeFloor`), each of which has an enforcement point. That asymmetry is a
778
788
  decision, not an omission. A floor is the answer to a vendor that fails SILENTLY — Claude Code
779
789
  earned one because an older binary validates the exec manifest, drops `args` at runtime, and
@@ -1266,7 +1276,7 @@ harness unit FAIL with the §1 Darwin wording — upgrade does not mint a
1266
1276
  rail receipt. Doctors refuse on Darwin until a physical-host receipt
1267
1277
  exists.
1268
1278
 
1269
- If install or doctor reports an unreadable/old active citizen generation, do not edit
1279
+ If install or doctor reports an active citizen generation it cannot read, first distinguish reader-version skew from a genuinely unreadable generation. Roll a stale reader forward and preserve identities and records; only a genuinely unreadable generation, as the [fresh-cut policy](./fresh-cut-policy.md) prescribes, takes the procedure below. Do not fresh-cut merely because an SDK or checkout changed. For a genuinely unreadable generation, do not edit
1270
1280
  records by hand. Close pi, Claude, Copilot, OMP, agy, and Codex sessions first, run
1271
1281
  `entwurf meta-bridge-fresh-cut`, and read its exit status before any install. Then choose the
1272
1282
  installation mode you actually own:
@@ -1316,7 +1326,7 @@ An already-running process keeps the modules it loaded, whatever is on disk. So,
1316
1326
 
1317
1327
  1. Build once from the checkout (`pnpm run build-bridge`, or its body `bash scripts/with-dist-lock.sh bash scripts/build-bridge.sh` when no package lifecycle should run).
1318
1328
  2. Compare the whole compiled output with the accepted candidate's, as a file-set and hash manifest. A hash of the selected entry alone is not enough: the entry can stay identical while a helper it loads differs. Check the pinned SDK set separately, and that the new process started after the build.
1319
- 3. Close the visible session and reopen it with its own native same-id resume. Closing a working sibling is an operator decision for that session, not something an agent does because new bytes landed.
1329
+ 3. Close the visible session and reopen it with its own native same-id resume. Closing a working sibling is an operator decision for that session, not something an agent does because new bytes landed. For a pi-durable session launched with an operator module, reopen the intended native session with its original explicit CLI and module after verifying the installation; garden-id resume does not restore modules.
1320
1330
  4. Confirm `entwurf_self` names the same garden id, and that the receiver/owner join points at the new process, whose bridge child started after the build.
1321
1331
 
1322
1332
  A per-component setup PASS or a `git pull` does not show which bytes a running bridge loaded. On 2026-10-20 one host of the #107 pair still selected a pre-feature dist after a pull and a green setup. The cause was not traced. A hash check caught it before the first message, and a manual build and visible resume fixed it. Entwurf adds no auto-build, reload or watcher for this.
@@ -6,8 +6,14 @@
6
6
  "editing": "Preserve decoded strings exactly unless an explicit semantic amendment is intended. Review related consumers and independent oracles atomically. Accepted payload changes advance revision; history-only edits, routine releases and unrelated code changes do not. schemaVersion tracks reader/structural compatibility. A slotted hint holds only the text around its slot: the slot value (for record-less-socket, the fresh-cut command in both invocation forms) is supplied by its code owner and never copied here. Metadata is not delivered to models."
7
7
  },
8
8
  "schemaVersion": 6,
9
- "revision": 19,
9
+ "revision": 20,
10
10
  "history": [
11
+ {
12
+ "revision": 20,
13
+ "source": "b9fa0d2aa43ebefc1c3bd5bc864c84965b52289a",
14
+ "issue": "https://github.com/junghan0611/entwurf/issues/159",
15
+ "change": "Align delivery descriptions with completion and reply routing while preserving receipt, rail, and lifecycle boundaries."
16
+ },
11
17
  {
12
18
  "revision": 19,
13
19
  "source": "2734f524bfeca6eb1a0ae092494d45576af9ebef",
@@ -126,11 +132,11 @@
126
132
  "tools": {
127
133
  "entwurf_v2": {
128
134
  "descriptions": {
129
- "mcp": "CANONICAL DELIVERY SURFACE for garden ids: message, reply, or hand off to whoever an id names. The id alone does not say which rail that citizen answers on. Give target + intent; the decider picks transport from liveness (live socket citizen → control-socket send; deliverable self-fetch citizen → meta-bridge mailbox; probe-alive native-push citizen → direct injection into its conversation) and reports ONE outcome, named per rail: a control receiver's acceptance boundary (`sent` / `queued-steer` / `queued-follow-up` / `accepted-unknown-boundary` — those four, or `mailbox-enqueued` on a re-resolved mailbox leg), a mailbox ENQUEUE receipt, a native-push INJECTION, a rejection, or lock-dirty. This receipt is not the colleague's reply or evidence of reading. EXISTING targets only; discover with entwurf_peers. A live socket can receive fire-and-forget. unsupported means only \"no control-socket probe,\" not reachability. The decider resolves the actual rail at dispatch time: a self-fetch mailbox only while deliverable, native-push direct injection only while its adapter probe is alive, or a THIRD RESULT: rejection when neither holds. An inactive self-fetch citizen is mailbox-undeliverable; native-push has NO mailbox: dead → native-push-target-dead; indeterminate → native-push-probe-indeterminate; agy (paused, #152) → native-push-paused, no probe. A dormant socket rejects this delivery verb as dormant-fire-forget-unsupported. owned-outcome was withdrawn. Only on an explicit operator request, entwurf_resume_call may visibly reopen a proven-dormant Pi, pi-durable or Claude Code citizen under the same id, submitting no prompt; that lifecycle is separate from delivery. LOCK: taken for a control-socket-DOMAIN dispatch. The mailbox and native-push rails are lock-free — deliverability and the adapter probe guard them. mode applies to a CONTROL-SOCKET send only; other plans carry no mode. wants_reply rides every rail. message caps at 16000 chars; send an artifact path + digest for more.",
130
- "durable": "Send a message to an existing garden citizen by garden id through the entwurf-bridge (intent fire-and-forget). Returns the bridge's delivery receipt, or fails with its named rejection. This receipt is not the colleague's reply."
135
+ "mcp": "Send, reply or hand off to an existing garden id; the decider selects the live rail (live socket citizen → control-socket send; deliverable self-fetch citizen → meta-bridge mailbox; probe-alive native-push citizen → direct injection into its conversation) and reports ONE outcome, named per rail: a control receiver's acceptance boundary (`sent` / `queued-steer` / `queued-follow-up` / `accepted-unknown-boundary` — those four, or `mailbox-enqueued` on a re-resolved mailbox leg), a mailbox ENQUEUE receipt, a native-push INJECTION, a rejection, or lock-dirty. A receipt is not a reply or proof of reading. A local final is not delivery: when asked to reply, call entwurf_v2 for the requested recipient (normally the replyable sender); honor routing and no-send instructions. Discover existing targets with entwurf_peers. A live socket can receive fire-and-forget; unsupported means only \"no control-socket probe,\" not reachability. For a target without a live socket, the THIRD RESULT is rejection if neither mailbox nor native-push is available. An inactive self-fetch citizen is mailbox-undeliverable; native-push has NO mailbox: dead → native-push-target-dead; indeterminate → native-push-probe-indeterminate; agy (paused) → native-push-paused, no probe. A dormant socket rejects this delivery verb as dormant-fire-forget-unsupported. This delivery verb never launches or resumes a process. Only on an explicit operator request, entwurf_resume_call may visibly reopen a proven-dormant Pi, pi-durable or Claude Code citizen under the same id, submitting no prompt; that lifecycle is separate from delivery. A control-socket-DOMAIN dispatch takes a target lock; mailbox and native-push rails are lock-free. mode applies only to a CONTROL-SOCKET send. wants_reply requests a response without authorizing an action or requiring an automatic acknowledgment; an absent or false marker does not cancel a request in the message. message caps at 16000 chars; send an artifact path + digest for more.",
136
+ "durable": "Send, reply or hand off to an existing garden id through entwurf-bridge (intent fire-and-forget), returning a delivery receipt or named rejection. The receipt is not a reply or proof of reading. For a requested reply, send to the authorized recipient, normally the replyable sender; a local final is not delivery. Honor routing and no-send instructions; an absent or false wants_reply does not cancel a request, and an address alone needs no ACK."
131
137
  },
132
138
  "parameters": {
133
- "intent": "fire-and-forget = send/reply/hand-off to an existing target after a current rail check. unsupported is not a reachability verdict; the decider picks a rail or REJECTS (self-fetch → mailbox when deliverable, else mailbox-undeliverable; native-push → alive: direct injection, dead: native-push-target-dead, indeterminate: native-push-probe-indeterminate; a paused backend — agy, #152 — rejects as native-push-paused before any probe); set wants_reply to request an answer, not to wait for one. This is the ONLY intent: owned-outcome, which resumed a dormant citizen by launching a hidden background child, was withdrawn under the visible-first rule. It is not selectable, not deprecated-but-tolerated; a dormant socket citizen is currently unreachable by this verb and rejects as dormant-fire-forget-unsupported.",
139
+ "intent": "fire-and-forget sends, replies or hands off to an existing target after a current rail check. unsupported is not a reachability verdict: self-fetch uses a deliverable mailbox or rejects as mailbox-undeliverable; native-push injects when alive, rejects dead as native-push-target-dead and indeterminate as native-push-probe-indeterminate; paused agy rejects as native-push-paused before probing. wants_reply requests a response, not a wait. This delivery verb never launches or resumes a process; a dormant socket rejects as dormant-fire-forget-unsupported.",
134
140
  "message": "Message / prompt to the colleague. In familiar language and natural sentences, convey what matters now and the context they need. Keep identifiers and evidence exact; trim repetition, not meaning. Hard cap 16000 chars; for larger payloads send a file/artifact path plus digest.",
135
141
  "mode": "Injection style for a CONTROL-SOCKET send only: steer (ask the receiver's steering queue) or follow_up (ask its follow-up queue). NEITHER is an interrupt: a busy receiver drains steering after each turn and follow-ups only when its inner loop ends, so a later steer overtakes every earlier follow_up and there is no order between the two. Both queues are volatile process memory — an abort drops what is in them. The receipt names which queue accepted the message (`queued-steer` / `queued-follow-up`); an idle receiver answers `sent`, meaning the turn was TRIGGERED, not that the model has seen the text. The mailbox and native-push plans carry no mode, so it has no effect on those rails.",
136
142
  "target": "Target garden id (use entwurf_peers to discover)",
@@ -29,7 +29,10 @@ import { win32Native } from "./win32-native.js";
29
29
  * renders nothing (etiquette marker, not transport contract).
30
30
  */
31
31
  export function formatSenderInfoBlock(sender, wantsReply = false) {
32
- return `\n\n<sender_info>${JSON.stringify({
32
+ const replyGuidance = sender.replyable === true
33
+ ? "\n\n[entwurf: When a reply is requested, send the result via entwurf_v2 to the requested recipient (default: sender_info.sessionId); a local final is not delivery. Honor routing and no-send instructions; an absent or false wants_reply does not cancel a request. A replyable address alone needs no acknowledgment.]"
34
+ : "";
35
+ return `${replyGuidance}\n\n<sender_info>${JSON.stringify({
33
36
  sessionId: sender.sessionId,
34
37
  agentId: sender.agentId,
35
38
  cwd: sender.cwd,
@@ -64,7 +64,7 @@ export function formatMetaMailboxBody(sender, message, wantsReply) {
64
64
  // SENDING host, so it is neither abbreviated against this host's HOME nor shown as a local path.
65
65
  const remote = !replyable ? sender.remote : undefined;
66
66
  const sessionLine = replyable
67
- ? `${sender.sessionId} (${kind}replyable — reply via entwurf_v2 to this sessionId, intent=fire-and-forget)`
67
+ ? `${sender.sessionId} (${kind}replyable — when a reply is requested, send the result via entwurf_v2 (intent=fire-and-forget) to the requested recipient, defaulting to this sessionId; a local final is not delivery. Honor routing and no-send instructions; an absent or false wants_reply does not cancel a request. A replyable address alone needs no acknowledgment)`
68
68
  : remote
69
69
  ? `${sender.sessionId} (remote via ${remote.via}; ${remote.replyRoute === "declared" ? "reply route declared, not probed" : "no reply route declared"})`
70
70
  : isMeta
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@junghanacs/entwurf",
3
- "version": "0.51.0",
3
+ "version": "0.52.0",
4
4
  "description": "Visible sibling sessions across independent agent harnesses: launch in Herdr or tmux, retire on request, visibly reopen supported sessions under the same id, and deliver messages by garden id; native bridges and Claude/Cortex ACP adapters.",
5
5
  "license": "MIT",
6
6
  "author": {
@@ -105,16 +105,16 @@
105
105
  "@agentclientprotocol/claude-agent-acp": "0.90.0",
106
106
  "@agentclientprotocol/sdk": "1.8.0",
107
107
  "@anthropic-ai/sdk": "0.100.1",
108
- "@earendil-works/chord": "1.5.0",
109
- "@earendil-works/pi-agent-core": "1.5.0",
110
- "@earendil-works/pi-ai": "1.5.0",
111
- "@earendil-works/pi-codemode": "1.5.0",
112
- "@earendil-works/pi-coding-agent": "1.5.0",
113
- "@earendil-works/pi-durable": "1.5.0",
114
- "@earendil-works/pi-mcp": "1.5.0",
115
- "@earendil-works/pi-schema": "1.5.0",
116
- "@earendil-works/pi-telemetry": "1.5.0",
117
- "@earendil-works/pi-tui": "1.5.0",
108
+ "@earendil-works/chord": "1.5.2",
109
+ "@earendil-works/pi-agent-core": "1.5.2",
110
+ "@earendil-works/pi-ai": "1.5.2",
111
+ "@earendil-works/pi-codemode": "1.5.2",
112
+ "@earendil-works/pi-coding-agent": "1.5.2",
113
+ "@earendil-works/pi-durable": "1.5.2",
114
+ "@earendil-works/pi-mcp": "1.5.2",
115
+ "@earendil-works/pi-schema": "1.5.2",
116
+ "@earendil-works/pi-telemetry": "1.5.2",
117
+ "@earendil-works/pi-tui": "1.5.2",
118
118
  "@modelcontextprotocol/sdk": "^1.12.1",
119
119
  "proper-lockfile": "4.1.2",
120
120
  "smol-toml": "^1.8.0",
@@ -1,4 +1,4 @@
1
-
1
+
2
2
 
3
3
  import {
4
4
  createRegistry,
@@ -1,4 +1,4 @@
1
-
1
+
2
2
 
3
3
  import {
4
4
  AssistantEntry,