@junghanacs/entwurf 0.12.8-repair.1 → 0.12.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +49 -21
- package/BASELINE.md +86 -3
- package/CHANGELOG.md +47 -0
- package/DELIVERY.md +3 -3
- package/README.md +227 -50
- package/VERIFY.md +44 -48
- package/demo/README.md +2 -2
- package/docs/setup-clean-host.md +74 -28
- package/mcp/entwurf-bridge/dist/mcp/entwurf-bridge/src/index.js +59 -55
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/acp/models.js +12 -12
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/control-socket-path.js +70 -0
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/entwurf-control-rpc.js +22 -0
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/entwurf-core.js +47 -1186
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/entwurf-fact-provider.js +37 -6
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/entwurf-facts.js +9 -17
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/entwurf-peers-render.js +69 -63
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/entwurf-resume-args.js +2 -2
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/entwurf-v2-contract.js +6 -3
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/entwurf-v2-decider.js +19 -33
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/entwurf-v2-mailbox.js +3 -2
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/entwurf-v2-production.js +38 -19
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/entwurf-v2-send-fallback.js +9 -10
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/entwurf-v2-spawn-production.js +56 -22
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/entwurf-v2-surface.js +9 -0
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/meta-sender-identity.js +57 -14
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/meta-session.js +909 -498
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/native-push/adapter.js +40 -5
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/socket-discovery.js +26 -56
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/socket-probe.js +16 -19
- package/mcp/entwurf-bridge/dist/pi-extensions/meta-bridge-hook.js +10 -6
- package/mcp/entwurf-bridge/dist/scripts/agy-imprint.js +14 -2
- package/mcp/entwurf-bridge/dist/scripts/meta-bridge-fresh-cut.js +673 -0
- package/mcp/entwurf-bridge/dist/scripts/meta-bridge-prune.js +5 -4
- package/mcp/entwurf-bridge/dist/scripts/meta-bridge-store-doctor.js +52 -45
- package/mcp/entwurf-bridge/src/index.ts +60 -52
- package/mcp/entwurf-bridge/test.sh +1 -1
- package/mcp/entwurf-bridge/tsconfig.build.json +11 -0
- package/package.json +13 -15
- package/pi-extensions/entwurf-control.ts +213 -438
- package/pi-extensions/lib/acp/models.ts +12 -12
- package/pi-extensions/lib/control-socket-path.js +74 -0
- package/pi-extensions/lib/entwurf-control-rpc.ts +23 -0
- package/pi-extensions/lib/entwurf-core.ts +64 -1454
- package/pi-extensions/lib/entwurf-fact-provider.ts +63 -13
- package/pi-extensions/lib/entwurf-facts.ts +34 -58
- package/pi-extensions/lib/entwurf-mailbox-guard.ts +2 -2
- package/pi-extensions/lib/entwurf-peers-render.ts +74 -80
- package/pi-extensions/lib/entwurf-resume-args.ts +11 -5
- package/pi-extensions/lib/entwurf-v2-contract.ts +6 -3
- package/pi-extensions/lib/entwurf-v2-decider.ts +38 -53
- package/pi-extensions/lib/entwurf-v2-mailbox.ts +3 -2
- package/pi-extensions/lib/entwurf-v2-production.ts +36 -14
- package/pi-extensions/lib/entwurf-v2-send-fallback.ts +9 -10
- package/pi-extensions/lib/entwurf-v2-spawn-production.ts +73 -39
- package/pi-extensions/lib/entwurf-v2-surface.ts +11 -0
- package/pi-extensions/lib/meta-sender-identity.ts +59 -14
- package/pi-extensions/lib/meta-session.ts +1025 -612
- package/pi-extensions/lib/native-push/adapter.ts +42 -4
- package/pi-extensions/lib/native-push/register.ts +2 -2
- package/pi-extensions/lib/pi-citizen-birth.ts +93 -0
- package/pi-extensions/lib/socket-discovery.ts +31 -65
- package/pi-extensions/lib/socket-probe.ts +16 -20
- package/pi-extensions/meta-bridge-hook.ts +10 -5
- package/run.sh +554 -301
- package/scripts/agy-imprint.ts +15 -1
- package/scripts/check-acp-prompt-builder.ts +5 -3
- package/scripts/check-acp-sdk-surface.ts +38 -24
- package/scripts/check-acp-session-reuse.ts +1 -1
- package/scripts/check-acp-session-store.ts +3 -3
- package/scripts/check-agy-sender-identity.ts +149 -1
- package/scripts/check-bridge-delivery.ts +253 -1
- package/scripts/check-capability-bundle-reach.ts +2 -2
- package/scripts/check-control-socket-path.ts +124 -0
- package/scripts/check-entwurf-capabilities.ts +19 -17
- package/scripts/check-entwurf-control-rpc.ts +38 -3
- package/scripts/check-entwurf-fact-provider.ts +59 -20
- package/scripts/check-entwurf-facts.ts +57 -45
- package/scripts/check-entwurf-mailbox-guard.ts +7 -5
- package/scripts/check-entwurf-peers-surface.ts +130 -91
- package/scripts/check-entwurf-resume-args.ts +23 -14
- package/scripts/check-entwurf-self-address.ts +13 -5
- package/scripts/check-entwurf-session-identity.ts +65 -548
- package/scripts/check-entwurf-v2-contract.ts +17 -25
- package/scripts/check-entwurf-v2-decider.ts +32 -109
- package/scripts/check-entwurf-v2-matrix.ts +3 -5
- package/scripts/check-entwurf-v2-production.ts +84 -35
- package/scripts/check-entwurf-v2-release.ts +1 -0
- package/scripts/check-entwurf-v2-runner.ts +1 -0
- package/scripts/check-entwurf-v2-send-fallback.ts +18 -38
- package/scripts/check-entwurf-v2-send.ts +1 -0
- package/scripts/check-entwurf-v2-spawn-production.ts +121 -26
- package/scripts/check-entwurf-v2-spawn.ts +1 -0
- package/scripts/check-entwurf-v2-surface.ts +11 -0
- package/scripts/check-fresh-cut-gate.sh +1494 -0
- package/scripts/check-install-container.sh +184 -2
- package/scripts/check-install-surface.ts +7 -6
- package/scripts/check-mailbox-receipt-state.ts +6 -3
- package/scripts/check-meta-capability-source.ts +16 -54
- package/scripts/check-meta-doctor-oracle.sh +2 -4
- package/scripts/check-meta-identity-consumers.ts +970 -0
- package/scripts/check-meta-listing.ts +94 -14
- package/scripts/check-meta-mailbox-state-write.ts +4 -4
- package/scripts/check-meta-manifest-schema.py +8 -5
- package/scripts/check-meta-receiver-marker.ts +144 -0
- package/scripts/check-meta-session.ts +19 -251
- package/scripts/check-meta-v3-record.ts +194 -0
- package/scripts/check-model-lock.ts +1 -1
- package/scripts/check-native-push-adapter.ts +47 -2
- package/scripts/check-socket-discovery.ts +13 -40
- package/scripts/check-socket-probe.ts +4 -28
- package/scripts/lib/pi-record-discovery.ts +44 -0
- package/scripts/meta-bridge-doctor.sh +31 -19
- package/scripts/meta-bridge-fresh-cut.ts +739 -0
- package/scripts/meta-bridge-install.sh +74 -13
- package/scripts/meta-bridge-prune.ts +5 -4
- package/scripts/meta-bridge-state.py +5 -6
- package/scripts/meta-bridge-store-doctor.ts +60 -50
- package/scripts/pi_settings_io.py +65 -0
- package/scripts/register-pi-package.py +183 -37
- package/scripts/register-pi-provider.py +68 -10
- package/scripts/resident-rpc-drive.ts +285 -0
- package/scripts/smoke-acp-bundled-mcp-live.ts +66 -33
- package/scripts/smoke-acp-raw-turn-live.ts +1 -1
- package/scripts/smoke-acp-socket-citizen-live.ts +33 -28
- package/scripts/smoke-acp-v2-send-live.ts +345 -0
- package/scripts/smoke-agy-statusline-state.sh +13 -8
- package/scripts/smoke-entwurf-v2-matrix-live.ts +83 -95
- package/scripts/smoke-entwurf-v2-spawn-live.ts +15 -2
- package/scripts/smoke-entwurf-v2-spawn-resume-live.ts +85 -44
- package/scripts/smoke-meta-install-state.sh +8 -14
- package/scripts/smoke-meta-prune.sh +12 -12
- package/scripts/smoke-pi-attach.ts +398 -0
- package/scripts/smoke-pi-provider-state.sh +12 -8
- package/scripts/smoke-resident-garden-guard.sh +216 -310
- package/scripts/smoke-user-scope-citizen.sh +177 -0
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/entwurf-v2-resume-marker.js +0 -33
- package/pi/entwurf-targets.json +0 -17
- package/pi-extensions/lib/entwurf-v2-resume-marker.ts +0 -34
- package/scripts/check-meta-dual-consumers.ts +0 -154
- package/scripts/check-meta-dual-read.ts +0 -158
- package/scripts/check-meta-migration.ts +0 -212
- package/scripts/check-meta-record-v2.ts +0 -191
- package/scripts/gnew-rpc-drive.ts +0 -211
- package/scripts/smoke-session-id-name.ts +0 -187
package/AGENTS.md
CHANGED
|
@@ -83,7 +83,7 @@ Warnings make agents blame themselves and flail. Broken tool state must surface
|
|
|
83
83
|
2. **Dispatch is a function of liveness, not session type.** `entwurf_v2` never asks "is this a resume or a send" up front — it probes the target on its own rail and routes: live pi→control-socket, dormant pi→spawn-bg resume, active self-fetch→meta-mailbox, live native conversation→native-push. State is computed, never stored (a stored liveness bit is a lie).
|
|
84
84
|
3. **A reject is honest, never cosmetic.** When a target cannot receive (dead, drifted identity, wrong state×intent), the decider returns a reject — no `✓ delivered`, no `.msg` written, no signal poke. Silent degraded "delivery" is forbidden.
|
|
85
85
|
4. **MCP injection**: only via explicit `mcpServers` wiring. No ambient `~/.mcp.json` scanning, no automatic retrieval.
|
|
86
|
-
5. **Meta-record authority is the record body, never the filename.** `
|
|
86
|
+
5. **Meta-record authority is the record body, never the filename — and the ACTIVE store is certified as a whole, by one contract.** Identity comes from the `.meta.json` body; no filename is ever parsed for authority. `certifyActiveStore` is the single contract the install doctor and all four identity writers (pi birth, Claude hook, agy imprint, `entwurf_register_native`) share: every `.meta.json` entry is a **regular file** (a symlink is refused, never followed — its bytes live where this store has no ownership), **readable by the live schema**, **named by its own body**, and the **unique holder of its `nativeSessionId`**. Body-is-authority and name-must-agree are not in tension: the body decides *what a record says*, while a record parked under the wrong name is unreachable by garden id and so corrupts the *active store*. Any defect fails the whole write BEFORE it happens, naming the fresh-cut verb — including a defect involving neither of the writer's own ids, because a narrow "is there a record for MY native id" scan is how a store ends up certified by the doctor and written to by the runtime under two different contracts (the weaker one always wins at runtime). **The contract binds both directions, at the granularity each surface can afford:** the store-WIDE scan runs on identity writes and in the doctor, while the plain TARGETED read (`readMetaIdentityByGardenId`, used by `entwurf_self`, mailbox primitives and sender-marker trust) holds the per-entry half — a non-regular-file record is refused and never followed, and body/filename drift fails loud, both naming the verb. V2 dispatch and pi resume use the stronger `readAddressableMetaIdentity` described next. Certifying only on write while the read followed a symlink made the rule true exactly where nobody was addressed. Store-wide *uniqueness* is checked on the read snapshot wherever it is both affordable and load-bearing (#52, 0.12.9): the **discovery** scan (`listAllMetaIdentities` → `entwurf_peers`) already holds every record, so a duplicated `nativeSessionId` costs nothing to see and neither rival is listed as a citizen — a facts surface may not mint the ownership the certification refuses; and the **dispatch** read (`readAddressableMetaIdentity`, used by v2 `resolveTarget` and the pi resume) fails loud, because that is the moment a record becomes an ADDRESS and a duplicate there injects one live conversation twice or resumes one transcript under two garden-id locks. It is deliberately NOT held on the per-message relay path (mailbox poke, sender-marker trust, `entwurf_self`) — those keep the per-entry half, and a call-relay that re-scans the store per message is a design this repo does not have. A RIVAL is a record that could be ADDRESSED INSTEAD, which is narrower than a file whose bytes carry the same id: a symlinked entry is not a candidate and is NEVER READ (rule 1 — following it to judge it would break the rule while enforcing it), and a drifted or unparseable neighbour is not a candidate because no garden id can reach it; all three stay certification defects and listing diagnostics, they just may not blind a healthy citizen. The inverse is loud: a REGULAR `.meta.json` this process cannot read might BE the duplicate, so it refuses rather than skipping (ENOENT alone is absence — a file that vanished mid-scan is not in the store). Both store-wide read scans take entries WITH THEIR KIND from one shared `readActiveStoreEntries`; the former name-only bindings read each path without first carrying its kind, which is exactly how both `entwurf_peers` surfaces followed a symlinked record the doctor refused. A kind attached to a NAME is still only half the rule, because `lstat`-then-`readFileSync(path)` classifies one entry and reads another — swap the final component in between and the read follows the symlink while every settled-store test stays green. Record bytes therefore come from exactly one reader, `readStoreRecordFile`, shared by the store-wide reader and the targeted read: `O_NOFOLLOW` (a symlink fails the OPEN, before a byte is read), `O_NONBLOCK` (deciding on the fd would otherwise let a fifo block the open forever, a hazard classify-then-open never had), kind decided by `fstat` on THAT file description, and `closeSync` in a `finally`. It does not flatten errno — raced-away (`ENOENT`, skipped), unreadable (`EACCES`, loud) and swapped (`ELOOP`, refused) must stay distinguishable, because the rival scan's raced-away skip is built on that distinction and a wrapper that erased it would turn every concurrent birth into a refused dispatch. **That reader does not replace the `lstat` classification in front of the targeted read: the two layers hold different things, and merging them into "one enforcement point" is a regression, not a cleanup** (caught in cross-review before shipping). The classification decides POLICY on a settled store WITHOUT OPENING anything, which is what lets a socket, a device or a mode-000 directory earn the certification's own sentence — `open` answers `ENXIO`/`EACCES` there, errnos about availability and permission rather than regularity, so an fd-only read starts calling the host unreadable where the doctor calls the entry non-regular, and one store again has two contracts. The fd layer decides the RACE after a regular snapshot, and its errno verdicts collapse back onto the settled sentences through one PURE classifier (`classifyRecordReadFailure`: `ENOENT`→absent; `ELOOP`/`ENXIO`/not-regular-on-fstat→irregular; everything else→unreadable) so a race never teaches a second vocabulary for one state of the world. Those branches are unreachable from any settled store precisely because the classification answers first — so they are pinned with synthetic errnos on the pure function, never by a store on disk. A gate cell that claims to pin a branch nothing can reach is worse than no cell: it passed with the whole mapping deleted (2026-07-26 cross-review). The threat is not only foreign corruption: `upsertMetaSession` certifies and then writes, which is not a transaction, so two concurrent births can mint two garden ids for one native session on a host where nothing was ever corrupted. A meta-record is nullable-at-birth (`model`/`transcriptPath` null until known). Production reads schemaVersion-3 records only, and the repo carries NO legacy reader or migrator: a record the live schema cannot read fails loud naming the fresh-cut verb (`entwurf meta-bridge-fresh-cut` — archive the whole generation, open an empty one). The active store provides no cross-generation address or resume continuity; sessions flow, and memory lives in the native transcripts and the embedding axes, never in the bridge.
|
|
87
87
|
6. **GC reclaims process resources only — never data.** meta-records and transcripts (the denote-id memory layer) are preserved; dormant/stale entries are archived/TTL'd, not deleted.
|
|
88
88
|
7. **This is not a second harness**: no prompt reconstruction, no transcript hydration, no tool result ledger, no harness emulation. Native bridges front only a garden id plus their narrow delivery rail (Claude mailbox or agy native-push); they do not scrape transcripts or run a replacement control daemon.
|
|
89
89
|
8. **Auth boundary is deployment-surface-agnostic**. This repo does not provide, copy, proxy, decrypt, or mediate any backend's credentials. Native-harness sessions read whatever auth state is visible in their own process filesystem; nothing here moves that.
|
|
@@ -91,7 +91,7 @@ Warnings make agents blame themselves and flail. Broken tool state must surface
|
|
|
91
91
|
10. **A green dev clone is not a working package — and a green package on the maintainer's host is not a working consumer.** Node refuses `--experimental-strip-types` below `node_modules`, so any surface an operator can invoke must reach compiled JS when installed. This class has shipped four times (start.sh 0.12.1, store-doctor 0.12.4, plugin hook 0.12.5, agy imprint + three operator commands 0.12.7) because the fence was crossed by hand, per surface, and the source-tree floor cannot see it. There is now exactly one crossing — `run_ts` in `run.sh` — and two gates that hold it: `check-install-surface` (structural) and `check-pack-install` (drives the real tarball, in CI). A new `.ts` entrypoint routes through `run_ts` or it does not ship. Dev-only gates have no compiled twin by design and must be REFUSED under an installed package, never silently skipped — a `.sh` dev gate refuses in its own body, since `scripts/` ships whole and run.sh's dispatch is not the only way in. **`check-pack-install` is still a maintainer-shaped proof**: the checkout is present, every tree is operator-owned, and the install is project-local, so a surface that writes beside the installed package or depends on the repo being nearby is green there and broken for a real consumer. `check-install-container` (#51 C, own required CI job) closes that: one candidate tarball, read-only, into a container that has never seen this repo — non-root `npm install -g`, resolution through the PATH shim, a frozen package root, and a regular-file path+sha256 manifest fence across `install-meta-bridge`; the evidence line records the canonical tarball path + sha256 and the Node image id/repository digest. Default CI packs once into a temp dir; release acceptance passes a caller-preserved tarball through `ENTWURF_CANDIDATE_TGZ` and the gate consumes that exact file without re-packing, so `npm publish <same.tgz> --tag repair` can publish the accepted bytes. The two are not redundant detectors of one defect: the **freeze is a permission-level consumer fact** (the cell actually refuses the write, EACCES, the way a real consumer's host would), while the **manifest fence is the detector** — and it is exactly a regular-file path+sha256 comparison, not a whole-tree guarantee: it reads no permissions, ownership or symlink targets. A freeze at the package root alone is demonstrably insufficient (a write one directory down sails past it and only the fence sees it). Model the consumer's world, never a stricter one: a blanket `chmod -R a-w` freeze produced false reds because `cp -r` propagates modes into the installer's own assembly target, which no `sudo npm i -g` consumer can reach.
|
|
92
92
|
11. **Verification must not rewire the operator's own install.** An offline smoke that writes a live `~/.claude` / `~/.gemini` / `~/.pi` path uninstalls the operator as a side effect of "testing". Swap `HOME` **and every already-exported writable `XDG_*` root** (`XDG_DATA_HOME`: install-state · `XDG_STATE_HOME`: the imprint log · `XDG_CACHE_HOME`: the statusline gid cache): moving HOME alone still writes below the inherited roots. This class struck three times in two days — hard-verify 2026-07-13 (DATA, scratch scripts), `check-pack-install`'s own drives 2026-07-14 (DATA + STATE, inside run.sh), and `smoke-user-scope-citizen` 2026-07-14 (fake `PI_CODING_AGENT_DIR` paired with the real XDG ownership state, so its inverse followed the real `managedSettingsPath` and removed the live MCP key). `check-install-surface` S5 is a static **tripwire** over `scripts/*.sh` source only: it catches a literal live path, one hop of aliasing, (S5b) HOME-without-XDG swaps, and (S5c) a mutating `run.sh` drive left unsandboxed at any root that command writes — the agent dir, `XDG_DATA_HOME`, and, for `install`/`setup`, `HOME` itself, because `ensure_agent_dir_symlinks` hard-codes `$HOME/.pi/agent` and never reads the agent-dir override (so sandboxing `PI_CODING_AGENT_DIR` is not isolation for those commands) — but it cannot see a path assembled across variables, an embedded heredoc, or run.sh itself. **A tripwire keyed to one syntactic form is not a tripwire**: S5c first shipped matching only the inline-env drive, and a review mutation walked the identical leak straight past it by hoisting the same override into an `export` one line up. Match the drive, then demand the isolation — never the other way round. The dynamic complement is `check-pack-install`'s **outer self-fence**, which runs after every success or early-failure path: the operator's real `$XDG_DATA_HOME/entwurf` tree must be byte-identical, and the gate-specific fake agy marker count in the real `$XDG_STATE_HOME/entwurf/agy-imprint.log` must not increase (mutation-checked). Read a green S5 as "no obvious destructive line", never as "verification is sandboxed" — the real guarantee is running the offline floor under a swapped HOME+XDG, which is still open. LIVE gates are the only surfaces that may drive the real host, and they say so in their name.
|
|
93
93
|
12. **A doctor reports runtime truth and ownership truth separately.** Read the target's own semantics before calling a host broken. agy matches `mcp(*)` and `mcp(<server>)` against our tool wherever those rules appear, so an operator's broad `allow` already grants `entwurf_v2` — reporting that host as "NOT granted, agy prompts on every call" was a false red about a working surface. Installers still take the narrowest rule they need; doctors distinguish **we own this** from **someone else's rule is carrying it** from **it is genuinely broken**. Install-state is evidence only when it parses, names its required managed-path field as an absolute path, and that normalized path equals the live target this host reads; corrupt or foreign-target state is a failure even when the live command itself resolves. Ownership beats coverage: an element the state records as ours that has since vanished stays a failure even while an operator's broader rule keeps the surface working (a whole-file settings relink produces exactly this shape). Conversely, broken ownership state does not justify saying a visibly configured runtime command is absent — report both axes honestly and keep the final verdict red.
|
|
94
|
-
13. **A native-hook owner is structural, not a topology guess — and the structure is the exec form.** Shell-form command hooks do not expose one portable process tree: under the same Claude Code version we observed both a direct hook→Claude join and a retained `/bin/bash -c` wrapper, and ordinary tail-exec tests never reproduced the trigger. That form is retired, not patched. The meta-bridge declares the **exec form** — `command` is the shipped `hook-launch.sh`, `args` is the real argv — so no shell exists on the launch path, the launcher `exec`s the payload and preserves the pid, and the hook's parent IS Claude on every host (#51 B2, measured at Claude Code 2.1.217). The hook therefore reads `process.ppid` directly; the `$PPID` carrier, the ancestry walk, and the missing-carrier contract are **gone**, and re-introducing any of them means the manifest stopped feeding the owner. **But `process.ppid` is only the owner when the launcher was actually on the path, so `hook-launch.sh` stamps a non-identity `ENTWURF_META_HOOK_LAUNCH` provenance token and the hook writes NO sender/receiver marker without it.** This is not the retired carrier wearing a new name: the carrier smuggled a *pid* that had to be ancestry-checked, while this token carries no identity at all and answers only "was the authorized launch path taken". It is what keeps the upgrade mismatch fail-closed — an already-open Claude session still holding the OLD cached command reaches the new hook with a shell wrapper as its parent, and without the token that wrapper would be minted as an owner. Deleting it is never a cleanup. **entwurf requires Claude Code `>=2.1.217` and enforces that floor itself, because upstream gives no fail-loud:** an older Claude passes `plugin validate` on the exec manifest (unknown-key passthrough), then at runtime drops `args`, runs `command` alone, and reports the hook as `exit_code: 0, outcome: success` — measured at 2.1.138. `hook-launch.sh` refusing an empty argv is that silence made loud; installer and doctor refuse the version outright; there is no shell-form fallback for older versions. `check-hook-launch-topology` drives the shipped argv for real — including a plugin path containing a space, `$`, a backtick, and `;&` — and `check-claude-floor-coherence` keeps the floor one number derived from `package.json` `entwurf.claudeCodeFloor`. Evidence stays tiered: B/B2 are direct-native observations from actual 2.1.138/2.1.217 sessions on one NixOS host; the Linux artifact-consumer's fake Claude, planted cache, stand-in owner and `/proc` bridge are fixtures that prove package/oracle behavior, never a second native-host acceptance. **The doctor is the release oracle, so its exit 0 must mean every required layer was measured, never that a layer was skipped.** It resolves the ONE artifact Claude loads (`claude plugin list --json`.installPath; an ambiguous multi-version cache is refused, never guessed), classifies the installed *launch form* by name across all three owner hooks — a shell-form or launcher-less exec manifest is refused by name, not reported as unreadable drift — and then requires the live MCP↔marker join. Missing live evidence is `NOT CERTIFIED`, a failure worded distinctly from a broken install. The #51 repair cut has **Linux as its only currently certified axis**: install refuses Darwin because `/proc`-based live bridge discovery cannot certify it yet, doctor stays `NOT CERTIFIED`/nonzero there, and uninstall alone retains Darwin support so legacy state is not stranded. This is an evidence boundary, not a permanent macOS impossibility; future native validation may reopen the lane. `check-meta-doctor-oracle` holds this: a healthy fixture must reach PASS and twenty-one planted defects must each turn it red *naming their own cause*. An oracle with an optional central evidence layer is not an oracle.
|
|
94
|
+
13. **A native-hook owner is structural, not a topology guess — and the structure is the exec form.** Shell-form command hooks do not expose one portable process tree: under the same Claude Code version we observed both a direct hook→Claude join and a retained `/bin/bash -c` wrapper, and ordinary tail-exec tests never reproduced the trigger. That form is retired, not patched. The meta-bridge declares the **exec form** — `command` is the shipped `hook-launch.sh`, `args` is the real argv — so no shell exists on the launch path, the launcher `exec`s the payload and preserves the pid, and the hook's parent IS Claude on every host (#51 B2, measured at Claude Code 2.1.217). The hook therefore reads `process.ppid` directly; the `$PPID` carrier, the ancestry walk, and the missing-carrier contract are **gone**, and re-introducing any of them means the manifest stopped feeding the owner. **But `process.ppid` is only the owner when the launcher was actually on the path, so `hook-launch.sh` stamps a non-identity `ENTWURF_META_HOOK_LAUNCH` provenance token and the hook writes NO sender/receiver marker without it.** **The authorized launch path is necessary, not sufficient: `process.ppid` must also be a pid that CAN own a session, and that question belongs to one shared predicate.** `isPlausibleOwnerPid` (safe integer, `> 1`, in `meta-session.ts` beside `classifyMarkerOwner`) is asked by both writers — the Claude hook and the agy imprint — by the `writeMetaSender/ReceiverMarker` boundary itself, by all three readers (fresh-cut inspect, sender-marker read, receiver-marker read) and by the sender-identity candidate filter. It is deliberately NOT part of `classifyMarkerOwner`, whose pure rule stays correct: asked about pid 1 that rule answers `live`, and honestly so. The layer above is where the claim fails. **That layer is a POLICY bound to the currently certified axis, not a law of processes**: on a Linux desktop/workstation host init is the service manager and every native harness descends from a login session, so `ownerPid <= 1` is always residue — but a container that runs the harness AS pid 1 is a real shape where it would name a genuine owner. Such a host is **unsupported and fails closed**: the writers refuse the marker, so that session keeps its meta-record and never claims reply-addressability. Widening the axis takes new evidence and a new contract, never a quiet loosening of the predicate. Splitting the two is what let the Claude hook refuse `<= 1` while the agy imprint still wrote `> 0` and every reader accepted `> 0`, and a single leftover `ownerPid: 1` marker — observed as a shell-form hook reparented to init before it read its own parent — then blocked that host's `meta-bridge-fresh-cut`: **the one action the refusal prescribes, quiescing the sessions, cannot refute an owner that is init**, and `0.12.8` named that same cut as the only repair for its pre-v3 store (#53 A, measured 2026-07-25). So a marker failing the predicate is **refuted by construction, not proven dead** — legacy (any pre-fix writer that was reparented) or corrupt (a non-integer pid no writer here ever produced), never claimed to have one single origin: the cut clears it as residue and reports it under its own `refuted:` line, never folded into the dead count. A new marker consumer asks the predicate or it reopens this. This is not the retired carrier wearing a new name: the carrier smuggled a *pid* that had to be ancestry-checked, while this token carries no identity at all and answers only "was the authorized launch path taken". It is what keeps the upgrade mismatch fail-closed — an already-open Claude session still holding the OLD cached command reaches the new hook with a shell wrapper as its parent, and without the token that wrapper would be minted as an owner. Deleting it is never a cleanup. **entwurf requires Claude Code `>=2.1.217` and enforces that floor itself, because upstream gives no fail-loud:** an older Claude passes `plugin validate` on the exec manifest (unknown-key passthrough), then at runtime drops `args`, runs `command` alone, and reports the hook as `exit_code: 0, outcome: success` — measured at 2.1.138. `hook-launch.sh` refusing an empty argv is that silence made loud; installer and doctor refuse the version outright; there is no shell-form fallback for older versions. `check-hook-launch-topology` drives the shipped argv for real — including a plugin path containing a space, `$`, a backtick, and `;&` — and `check-claude-floor-coherence` keeps the floor one number derived from `package.json` `entwurf.claudeCodeFloor`. Evidence stays tiered: B/B2 are direct-native observations from actual 2.1.138/2.1.217 sessions on one NixOS host; the Linux artifact-consumer's fake Claude, planted cache, stand-in owner and `/proc` bridge are fixtures that prove package/oracle behavior, never a second native-host acceptance. **The doctor is the release oracle, so its exit 0 must mean every required layer was measured, never that a layer was skipped.** It resolves the ONE artifact Claude loads (`claude plugin list --json`.installPath; an ambiguous multi-version cache is refused, never guessed), classifies the installed *launch form* by name across all three owner hooks — a shell-form or launcher-less exec manifest is refused by name, not reported as unreadable drift — and then requires the live MCP↔marker join. Missing live evidence is `NOT CERTIFIED`, a failure worded distinctly from a broken install. The #51 repair cut has **Linux as its only currently certified axis**: install refuses Darwin because `/proc`-based live bridge discovery cannot certify it yet, doctor stays `NOT CERTIFIED`/nonzero there, and uninstall alone retains Darwin support so legacy state is not stranded. This is an evidence boundary, not a permanent macOS impossibility; future native validation may reopen the lane. `check-meta-doctor-oracle` holds this: a healthy fixture must reach PASS and twenty-one planted defects must each turn it red *naming their own cause*. An oracle with an optional central evidence layer is not an oracle.
|
|
95
95
|
|
|
96
96
|
## ACP Plugin Boundary
|
|
97
97
|
|
|
@@ -127,7 +127,7 @@ pnpm typecheck # 3-config tsc fence (root + mcp + s
|
|
|
127
127
|
pnpm check # full static floor: lint + typecheck + every check-*/smoke-* below
|
|
128
128
|
./run.sh check-entwurf-v2-matrix # the decider's state×intent table, read as an SSOT (REAL decideDispatch)
|
|
129
129
|
./run.sh check-entwurf-v2-decider # + -contract / -lock / -release / -send / -send-fallback / -mailbox / -runner / -production / -surface / -spawn / -spawn-production
|
|
130
|
-
./run.sh check-meta-session # + -record
|
|
130
|
+
./run.sh check-meta-session # + -v3-record / -mailbox-state-write / -receiver-marker / -capability-source / -identity-consumers / -listing (one live schema; no legacy readers — see check-fresh-cut-gate for the generation boundary)
|
|
131
131
|
./run.sh check-meta-doctor-oracle # detection power of the release oracle: healthy fixture reaches `doctor: PASS`, 21 planted defects each turn it FAIL naming their own cause
|
|
132
132
|
./run.sh check-native-push-adapter # agy probe/route leaf; separate from pi socket and mailbox liveness
|
|
133
133
|
./run.sh check-agy-sender-identity # record-backed pid/start-key sender resolution + ambiguity refusal
|
|
@@ -164,26 +164,49 @@ If a gate fails or a claim drops below its needed evidence level, do not commit.
|
|
|
164
164
|
|
|
165
165
|
Uses `entwurf` instead of `delegate` to avoid ecosystem collisions. spawn-bg resume creates a sibling, not a worker.
|
|
166
166
|
|
|
167
|
-
- **Surface** — MCP `entwurf-bridge`: `entwurf_v2`, `entwurf_self`, `entwurf_peers`, `entwurf_inbox_read`, `entwurf_register_native` (explicit/manual fallback for an already-running native conversation). pi-native (`pi-extensions/entwurf-control.ts`): `entwurf_v2`, `entwurf_peers` tools
|
|
167
|
+
- **Surface** — MCP `entwurf-bridge`: `entwurf_v2`, `entwurf_self`, `entwurf_peers`, `entwurf_inbox_read`, `entwurf_register_native` (explicit/manual fallback for an already-running native conversation). pi-native (`pi-extensions/entwurf-control.ts`): `entwurf_v2`, `entwurf_peers` tools (#50 C4 removed the socket-scan `/entwurf-sessions` command). The v1 `entwurf` / `entwurf_resume` / `entwurf_send` tools and the `/entwurf` / `/entwurf-send` / `/entwurf-status` commands are **removed**.
|
|
168
168
|
- **`entwurf_v2` is the one delivery verb.** Given a garden id, it classifies the target (live pi vs. dormant pi vs. mailbox meta-session vs. native-push citizen — a bare garden id does not reveal this) and routes correctly. It does **not** mint a fresh sibling: spawn-bg resumes an *already-identified* citizen, while native-register binds an *already-running* conversation. Fresh creation was the v1 `entwurf` verb and remains deferred.
|
|
169
169
|
- **`entwurf_peers`** is a read-only fact surface (liveness / capability / identity / cwd-history). Do not bake verb-routing (`resumable`/`sendable`) into the fact layer; routing is the decider's job.
|
|
170
|
-
- **`entwurf_self`** returns the authoritative identity envelope (pi-session env, or a trusted meta-session sender marker) and is identity-required.
|
|
171
|
-
-
|
|
170
|
+
- **`entwurf_self`** returns the authoritative identity envelope (pi-session env, or a trusted meta-session sender marker) and is identity-required. Its socketPath/mailboxPath lines are the CALLER's own transport diagnostics, not an identity surface — that is why they survive #50 C4 while `entwurf_peers` forbids every socket-shaped key/path (the peers listing points at OTHER citizens, where a socket path is an address claim).
|
|
171
|
+
- The target registry (`pi/entwurf-targets.json` + `setup:links`) is **gone** (#50 C3): v2 never spawns from a model tuple — `entwurf_v2` resumes an already-identified record-backed citizen, and dormant-resume authorization is record existence + the transcript-header ↔ `record.nativeSessionId` integrity check (the old `requireEntwurf` name-tag and resume-marker env are deleted). Bridge-extension routing survives as `getRegistryRouting` (caller-supplied tuple, ← resolve-acp-bridge). Identity Preservation Rule: no model override on resume.
|
|
172
172
|
- `PI_SHELL_ACP_V2_ONLY=1` was the v1-refusal flag; with v1 removed on this branch its guard (`entwurf-v2-only.ts`) is gone too. `runEntwurfV2` was always flag-clean.
|
|
173
173
|
|
|
174
174
|
> **Source-agnostic does not mean harness-agnostic.** 어디서 던지든 — GLG / sibling / external MCP host — entwurf 의 *target* 은 garden citizen 이다. spawn-bg resume 의 spawn surface 는 pi 자식 프로세스만 띄운다 (`pi --entwurf-control` keep-alive resident). 외부 MCP host 가 닿을 때도 target 은 이미 식별된 citizen 이어야 한다. *Model* 은 free axis (어느 형제 학교 모델이든), *spawn target* 은 harness 정합 axis.
|
|
175
175
|
|
|
176
176
|
> **Naming pair.** *Entwurf* (기투, projection-of-self) — a resident agent throws siblings forward (resume / messaging). The resident-side counterpart is *Mitsein* (공존, being-with), defined in the resident's own knowledge base (cwd-scoped, not a global persona). This repo owns the entwurf substrate; resident-side conventions live where the resident wakes.
|
|
177
177
|
|
|
178
|
-
###
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
- **
|
|
186
|
-
|
|
178
|
+
### Resident identity — the record is the address (#50 C2)
|
|
179
|
+
|
|
180
|
+
A `--entwurf-control` session is a garden citizen because it has a **meta-record**, not
|
|
181
|
+
because its session id has a particular shape. pi mints its own id (a uuidv7 is normal);
|
|
182
|
+
`birthPiCitizen` upserts `(backend:"pi", nativeSessionId)` at `session_start`, the record
|
|
183
|
+
mints the `gardenId`, and everything addressable hangs off that one string.
|
|
184
|
+
|
|
185
|
+
- **Launch:** `pi --entwurf-control …`. No `--session-id` injection — that was the old
|
|
186
|
+
launcher's job and it is gone, together with `run.sh new-session-id`'s role in launching
|
|
187
|
+
(the generator itself stays; the record uses it to mint garden ids).
|
|
188
|
+
- **In-process new/resume:** pi's own. `/new`, `/fork`, `/clone` and RPC session replacement
|
|
189
|
+
all just fire `session_start`, which attaches the new session as its own citizen and
|
|
190
|
+
rebinds the socket to its address. The `/gnew` command, the pre-switch cancels and the
|
|
191
|
+
garden-format hard exit are deleted — there is no id to police (LOCKED PROTOCOL 2).
|
|
192
|
+
- **Socket:** `~/.pi/entwurf-control/<gardenId>.sock`, keyed on the RECORD's id. A socket
|
|
193
|
+
carrying pi's session id is the pre-cut address and a gate failure.
|
|
194
|
+
- **`PI_SESSION_ID`** carries the gardenId, so every child MCP process reads back a
|
|
195
|
+
routable address (`entwurf_self`), never pi's internal id.
|
|
196
|
+
- **Failure is loud, not cosmetic:** if the record cannot be written (unreadable store,
|
|
197
|
+
duplicate native id, an unreadable store naming the fresh-cut verb) the control server is
|
|
198
|
+
refused, `PI_SESSION_ID` stays unset, and the reason is on stderr. An unaddressable
|
|
199
|
+
resident must not survive quietly — that is the guard's surviving purpose.
|
|
200
|
+
- **Status label = 🪛 (the forged screwdriver, the North Star), NOT the word "entwurf".**
|
|
201
|
+
`🪛 ready` before the first assistant turn (session file not on disk → model changeable),
|
|
202
|
+
`🪛 <gardenId>` after (file written → model locked).
|
|
203
|
+
- **The resident session NAME is pi's.** The `control`-tagged garden name mirror, its
|
|
204
|
+
`entwurf`-tag refusal and the sessionId-bound resume-marker exemption are gone with the id
|
|
205
|
+
they mirrored. Dormant-resume authorization is record existence (LOCKED PROTOCOL 6) plus
|
|
206
|
+
the transcript-header ↔ `record.nativeSessionId` integrity check (#50 C3).
|
|
207
|
+
- Gates: `smoke-pi-attach` (deterministic, in `pnpm check`: record birth · record-keyed
|
|
208
|
+
socket · attach-on-reopen · artifact delivers to the socket) + `smoke-resident-garden-guard`
|
|
209
|
+
(LIVE, the same contract driven through a real `pi` process).
|
|
187
210
|
|
|
188
211
|
### Send-is-throw
|
|
189
212
|
|
|
@@ -199,18 +222,18 @@ Messages are thrown, not awaited.
|
|
|
199
222
|
|------|---------|
|
|
200
223
|
| `pi-extensions/acp-provider.ts` | ACP plugin entry: registers the package provider `entwurf` + curated Claude model surface; wires `streamSimple` to the real ACP backend |
|
|
201
224
|
| `pi-extensions/lib/acp/*.ts` | ACP plugin internals: curated Claude surface + no-auth sentinel (`models.ts`), Claude config overlay (`overlay.ts`), tool surface + exclude-tools preflight (`tool-surface.ts`), ACP→pi event mapper (`event-mapper.ts`), pi Context→ACP prompt (`context.ts`), spawn-per-turn `streamSimple` backend (`backend.ts`) |
|
|
202
|
-
| `pi-extensions/entwurf-control.ts` | control plane: `--entwurf-control` socket, RPC, `entwurf_v2` / `entwurf_peers` tools
|
|
225
|
+
| `pi-extensions/entwurf-control.ts` | control plane: record attach at session_start, `--entwurf-control` socket (keyed on the record gardenId), RPC, `entwurf_v2` / `entwurf_peers` tools |
|
|
226
|
+
| `pi-extensions/lib/pi-citizen-birth.ts` | the #50 C2 attach seam: pi session → meta-record upsert → control-socket address |
|
|
203
227
|
| `pi-extensions/model-lock.ts` | package-provider model lock (pi.extension) |
|
|
204
228
|
| `pi-extensions/meta-bridge-hook.ts` | Claude Code `SessionStart` hook: register a mailbox-backed garden meta-session |
|
|
205
|
-
| `pi-extensions/lib/entwurf-v2-*.ts` | v2 substrate: contract / lock / decider / matrix / release / send / mailbox / native-push / runner / production / surface / spawn(+production)
|
|
229
|
+
| `pi-extensions/lib/entwurf-v2-*.ts` | v2 substrate: contract / lock / decider / matrix / release / send / mailbox / native-push / runner / production / surface / spawn(+production) |
|
|
206
230
|
| `pi-extensions/lib/native-push/` | Antigravity adapter probe/route, direct-inject hand, explicit native registration core |
|
|
207
|
-
| `pi-extensions/lib/meta-*.ts` | meta-record authority, mailbox state,
|
|
231
|
+
| `pi-extensions/lib/meta-*.ts` | V3-only meta-record authority (`meta-session.ts`), mailbox state, receiver/sender identity — one live schema, no legacy readers |
|
|
208
232
|
| `scripts/agy-{bridge,statusline-bridge,hooks-bridge}.*` | three state-backed agy install/doctor/inverse surfaces |
|
|
209
233
|
| `scripts/agy-imprint.ts` | agy `PreInvocation` automatic birth + record-backed sender marker |
|
|
210
234
|
| `pi-extensions/lib/entwurf-core.ts` | shared core (session-file lookup, identity read, explicit-extension args); some v1 exports now dead pending routing cleanup |
|
|
211
235
|
| `protocol.js` | dependency-free shared wire constants (`<project-context` marker); single source for tsc emit + strip-types MCP paths |
|
|
212
236
|
| `run.sh` | install (incl. `install-meta-bridge`), check-*/smoke-* gates, release-gate |
|
|
213
|
-
| `pi/entwurf-targets.json` | spawn-bg resume target allowlist |
|
|
214
237
|
| `mcp/entwurf-bridge/` | MCP server exposing `entwurf_v2`, `entwurf_self`, `entwurf_peers`, `entwurf_inbox_read` |
|
|
215
238
|
|
|
216
239
|
## Typecheck Boundary
|
|
@@ -234,14 +257,19 @@ Code-level invariants pinned at the same time:
|
|
|
234
257
|
|
|
235
258
|
## Runtime Dependencies
|
|
236
259
|
|
|
237
|
-
- `@modelcontextprotocol/sdk` and `zod` are the substrate runtime deps. With the Claude-first ACP plugin shipped, the Claude/ACP backend deps are pinned alongside them: `@agentclientprotocol/claude-agent-acp` (`0.
|
|
238
|
-
- `pi` (`@earendil-works/pi-ai`) on PATH at the pinned range (`>= 0.
|
|
260
|
+
- `@modelcontextprotocol/sdk` and `zod` are the substrate runtime deps. With the Claude-first ACP plugin shipped, the Claude/ACP backend deps are pinned alongside them: `@agentclientprotocol/claude-agent-acp` (`0.61.0`), `@agentclientprotocol/sdk` (`1.3.0`), `@anthropic-ai/sdk` (`0.100.1` — kept: `claude-agent-sdk@0.3.217`'s peer floor is `>=0.93.0`, so 0.100.1 satisfies it and a mechanical rise to the newest SDK is NOT taken). Codex/Gemini ACP packages stay out of scope; Codex is native/probe, agy is the shipped native-push Google lane, and Gemini ACP remains compatibility history rather than a current target.
|
|
261
|
+
- `pi` (`@earendil-works/pi-ai`) on PATH at the pinned range (`>= 0.82.1 < 0.83` — devDep exact `0.82.1` + next-minor ceiling). Mismatches are caught by `check-dep-versions` / `check-pi-runtime-version`. 0.80 moved the standalone root `getModels()` to the deprecated `@earendil-works/pi-ai/compat` entrypoint; the curated Claude surface (`pi-extensions/lib/acp/models.ts`) imports `getModels` from `/compat` — the single subpath allowlisted in `check-pi-import-surface`. NOT a provider-factory subpath such as `providers/anthropic`: although it typechecks, pi's extension loader (jiti alias map in pi-coding-agent `core/extensions/loader.ts`) resolves only FOUR pi-ai specifiers for extensions — the bare root, `/compat`, `/oauth`, and (added in 0.81) `/providers/all` — so any other `providers/*` import resolves to the unresolvable `dist/compat.js/providers/…` and crashes extension load (caught live by `smoke-resident-garden-guard`, not by static typecheck). This `/compat` use is an **extension-loader compatibility shim** chosen by loader constraint, not a preference for a deprecated API — the `<0.83` ceiling guards it.
|
|
262
|
+
- **The minor-boundary re-evaluation was done 2026-07-24 against pi `v0.80.7..v0.82.0`.** The shim held: root / `/compat` / `/oauth` stayed in the alias map, `getModels` remained a `/compat` re-export of `getBuiltinModels`, and 0.81 added `/providers/all` without forcing migration. **The 2026-07-26 `v0.82.0..v0.82.1` patch was source-diffed and installed again:** loader aliases and `/compat` are unchanged; the builtin Anthropic catalog grows 14→15 only by adding `claude-opus-5`; `claude-sonnet-5` retains identical cost/context/max-token/reasoning metadata. The explicit model cut replaces the curated Opus 4.8 row with Opus 5 (1M context, 128K max output, reasoning enabled) rather than widening the two-model surface. Re-evaluate again at the `<0.83` ceiling.
|
|
239
263
|
|
|
240
264
|
## Working Style
|
|
241
265
|
|
|
242
266
|
- Surgical changes. One thing at a time.
|
|
243
267
|
- Ask: does this belong in pi? In the resident's own repo? Or here?
|
|
244
268
|
- Removal on this branch is gate-verified: subtract source AND its gate/case/script together (the 결합 규칙) so `pnpm check` stays green and never goes silently red.
|
|
269
|
+
- **Every repair/removal commit hunts the sentences it invalidated** — adding the new fact without deleting the old claim has now shipped **eight** times (dead registry link → stale NEXT diagnosis → A1/launcher prose surviving C4 → `docs/setup-clean-host.md` teaching the deleted `--session-id` launcher *and a hard-exit guard that no longer exists* → the `shouldListAsLive` removal leaving its own policy sentences behind → the store-doctor claiming dual-read three cuts after V3-only · a gate header claiming v2 writes → **the schema module itself: `MetaIdentity`/serializer/minter/`decideUpsert` doc comments calling the live v3 shape "v2", one of them defaulting a field #50 deleted, while the same function's body comment was already correct**). **Stop extending the directory list — that is what failed three rounds running (`docs/`, then `scripts/`, then the lib the cut actually rewrote).** The unit is the REPO, and the sweep is a method, two axes:
|
|
270
|
+
1. **Retired vocabulary → repo-wide grep.** Before committing, write down what the cut retired: deleted symbol names, the schema/authority words it demoted (`dual-read`, `v2 identity`, `socketOnly`), the command form it replaced. `grep -rn` each across the whole tree (not only touched files — a schema cut invalidates prose in consumers it never edits), then judge every hit: a *tombstone* ("`X` is GONE since #50") is the goal, a *live claim* ("`X` reads v1 AND v2") is the defect.
|
|
271
|
+
2. **Landed plans → future-tense grep.** A cut that LANDS invalidates its own plan sentences: `yet` · `not here` · `Today …` · `does NOT yet` · `lands in step N` · `will land`. Staged-build headers are written in future tense and nobody returns to them when the step ships.
|
|
272
|
+
Surfaces to cover at minimum: README · AGENTS · DELIVERY · VERIFY · ROADMAP · `docs/**` (an install walkthrough is a new host's first surface, so a stale command there costs more than a stale README line) · run.sh usage lines AND dispatch/function comments · `scripts/**` operator & gate scripts · **the module the cut rewrote, all of it — being the file you edited is not evidence its other 40 comments were read**. A deleted symbol's *prose* is not deleted by the compiler or by biome — only by this sweep.
|
|
245
273
|
- Keep docs calibrated: strong language is fine; unbacked language is not.
|
|
246
274
|
- Resist the urge to make the substrate more magical than necessary.
|
|
247
275
|
|
package/BASELINE.md
CHANGED
|
@@ -24,8 +24,8 @@ host into a certified one.
|
|
|
24
24
|
| Node 24 Linux package consumer | Required `artifact-consumer` CI: read-only candidate `.tgz`, checkout-invisible, non-root global install, PATH shims, frozen package root, path+sha256 regular-file fence, strict doctor fixture | None required for the package layout itself | Package-consumer shape verified. The planted Claude cache/owner/bridge are synthetic and prove no real Claude lifecycle. |
|
|
25
25
|
| Claude Code 2.1.217 exec form | `check-hook-launch-topology` + `check-claude-floor-coherence`; doctor oracle healthy fixture + 21 defect mutations | B2 actual Claude session on NixOS: args per element, literal `${HOME}`, direct parent, FileChanged exit 2 → idle wake | Runtime behavior verified at 2.1.217 on one host; this is the supported floor. |
|
|
26
26
|
| Claude Code 2.1.138 negative | Launcher empty-argv refusal + installer/doctor floor checks | B actual Claude session on NixOS: args discarded while runtime reported success | Unsupported; no shell-form fallback. |
|
|
27
|
-
| Maintainer NixOS installed package | Gates and B/B2 are green
|
|
28
|
-
| Secondary Ubuntu Linux installed package | Linux artifact-consumer gate models the package shape, not this machine |
|
|
27
|
+
| Maintainer NixOS installed package | Gates and B/B2 are green; the published `0.12.8-repair.1` artifact was installed from the registry for acceptance, then the V3 development wiring was restored | 2026-07-25: registry install → installed `install-meta-bridge` → NEW Claude session with a live MCP child → installed doctor **exit 0** (HISTORY) | Host-certified for the published repair artifact, including physical `entwurf_v2` delivery and the live owner join. The doctor first went RED on a managed dev-bin shadowing the registry bridge. This host now runs dev wiring again; stable `0.12.8` earns its own host proof. |
|
|
28
|
+
| Secondary Ubuntu Linux installed package | Linux artifact-consumer gate models the package shape, not this machine | 2026-07-25: same registry artifact, isolated clean `PI_CODING_AGENT_DIR`, NEW Claude session with a live MCP child → installed doctor **exit 0** (HISTORY) | Recovery closed for `0.12.8-repair.1`. Hand-patched hooks and validate output remain non-acceptance; a stable artifact is a separate proof. |
|
|
29
29
|
| macOS Claude meta-bridge | No artifact-consumer job and no `/proc` live join | None | **Not yet verified/certified for this repair cut.** Installer refuses Darwin and doctor remains nonzero; uninstall permits Darwin to remove older managed state. This is not permanent—future native validation may reopen it, and package-level `os` stays unrestricted. |
|
|
30
30
|
| WSL2 / Windows | None | None | Unverified / outside this repair cut. |
|
|
31
31
|
|
|
@@ -274,6 +274,89 @@ prompt, and if so quote the visible text exactly:
|
|
|
274
274
|
|
|
275
275
|
# HISTORY (pointer)
|
|
276
276
|
|
|
277
|
+
2026-07-25 repair.1 installed-native host acceptance (stable-promotion prerequisite):
|
|
278
|
+
the published registry artifact `@junghanacs/entwurf@0.12.8-repair.1` was installed
|
|
279
|
+
fresh on two Linux hosts (maintainer + secondary) through the package's stable bins.
|
|
280
|
+
Each host ran installed `entwurf install-meta-bridge`, opened a NEW real Claude Code
|
|
281
|
+
session with a live MCP child, and ran the installed `entwurf doctor-meta-bridge`
|
|
282
|
+
against an isolated clean `PI_CODING_AGENT_DIR`; both doctors reached **PASS**, including
|
|
283
|
+
the live MCP owner join and a physical `entwurf_v2` delivery. The maintainer host first
|
|
284
|
+
proved the oracle's value by failing when its managed dev-bin shadowed the registry
|
|
285
|
+
`entwurf-bridge`: the installed v2 hook wrote a v2 record while the checkout's v3 bridge
|
|
286
|
+
refused it. Removing the managed dev bin made PATH resolve the registry bridge, after
|
|
287
|
+
which the same native proof passed. The test-created v2 record from that failed mixed-path
|
|
288
|
+
attempt was preserved under `meta-sessions.proof-failed-20260725T165227/`; the maintainer's
|
|
289
|
+
V3 development wiring was restored after acceptance. This closes VERIFY's two-host
|
|
290
|
+
repair.1 prerequisite for a separately authorized stable `0.12.8`; it is host
|
|
291
|
+
corroboration of the published repair artifact, not evidence for the future stable
|
|
292
|
+
candidate, which still earns exact-SHA CI, LIVE, and preserved-artifact acceptance.
|
|
293
|
+
Exact pre-version closure checkpoint `28a52fe2d6e9ca29b657a33e5c80ff4debda2f0f`
|
|
294
|
+
passed GitHub Actions run [30149759311](https://github.com/junghan0611/entwurf/actions/runs/30149759311):
|
|
295
|
+
`check`, `install-surface`, and `artifact-consumer` all success. The host proof then found
|
|
296
|
+
a one-line `remove-dev-bin` dispatch defect, so the eventual stable landing HEAD must earn
|
|
297
|
+
a fresh exact-SHA run; this checkpoint is not reused as that acceptance.
|
|
298
|
+
|
|
299
|
+
2026-07-24 (night) upgrade-harness + review acceptance at exact HEAD
|
|
300
|
+
`cbda097` (branch `repair/v2-core-debt`, merged to main the same night — the
|
|
301
|
+
hard-cut branch chronicle lives in issue #50): the three-cell harness gained
|
|
302
|
+
the UPGRADE axis — `setup` / `install` / `install-meta-bridge` refuse a
|
|
303
|
+
pre-cut (v1/v2) meta-record store BEFORE their first write, prescribe on
|
|
304
|
+
three axes (pre-cut → migrate; problems → repair first; both → repair FIRST,
|
|
305
|
+
then migrate), and the proof seeds every host state from frozen fixture bytes
|
|
306
|
+
(`fixtures/meta-store`, sha256-manifested, excluded from the tarball).
|
|
307
|
+
Deterministic cells at this HEAD: `pnpm check` EXIT=0 (source cell
|
|
308
|
+
`check-upgrade-gate` 57/0), `check-pack-install` EXIT=0,
|
|
309
|
+
`ENTWURF_REQUIRE_DOCKER=1 check-install-container` EXIT=0 — candidate
|
|
310
|
+
`junghanacs-entwurf-0.12.8-repair.1.tgz` **sha256
|
|
311
|
+
`db17165f962c938d71ef97cb7a86252549dc91b00d5ec67f63ec65b41039e6dc`**,
|
|
312
|
+
11413738 bytes, image `sha256:f1158c7f34cf35a047bf0513c38282bb2fa253529e5ae404b32c6d93697410be`.
|
|
313
|
+
Live at this HEAD: `LIVE=1 release-gate` **MUST 16/1/0 + BEHAVIOR 1/0,
|
|
314
|
+
EXIT=1** — the single FAIL is `smoke-acp-bundled-mcp-live`, the known
|
|
315
|
+
bundled-MCP readiness race (ROADMAP 「🔴 OPEN」, GLG: observe, don't fix;
|
|
316
|
+
sample recorded with transcript; isolated re-run PASS 4/4). Every other MUST
|
|
317
|
+
passed at this HEAD, including `smoke-acp-v2-send-live` (send identity /
|
|
318
|
+
replyability) and the matrix honest-reject. **A release cut stays blocked on
|
|
319
|
+
that red by the gate's own words; the merge to main was GLG's explicit call
|
|
320
|
+
with the race documented as an open observation item.**
|
|
321
|
+
|
|
322
|
+
2026-07-24 dependency-uplift acceptance at exact HEAD
|
|
323
|
+
`7cbeb29b6afcfbaf4fc28da3b7929037c339113d` (branch `repair/v2-core-debt`): pi
|
|
324
|
+
runtime **0.80.7 → 0.82.0** and Claude ACP **claude-agent-acp 0.54.1 → 0.61.0 /
|
|
325
|
+
ACP SDK 1.1.0 → 1.3.0** as two separate cuts, with `@anthropic-ai/sdk` held at
|
|
326
|
+
**0.100.1** (measured through the real module graph: claude-agent-sdk 0.3.217's
|
|
327
|
+
`>=0.93.0` peer resolves to 0.100.1 there; dropping the direct pin under this
|
|
328
|
+
repo's `autoInstallPeers:false` leaves only 0.91.1 and the peer goes unmet).
|
|
329
|
+
Deterministic 3 cells all EXIT=0 on Node 24 Linux — checkout (`pnpm
|
|
330
|
+
build-bridge && pnpm check`), installed tree (`check-pack-install`: resolved
|
|
331
|
+
tree holds only `@earendil-works@0.82.0`, loader drove the pinned pi, installed
|
|
332
|
+
bin delivered a `.msg`), clean consumer (`ENTWURF_REQUIRE_DOCKER=1
|
|
333
|
+
check-install-container`, candidate `junghanacs-entwurf-0.12.8-repair.1.tgz`
|
|
334
|
+
**sha256 `ab5dee07585c8d7a4f8f174cedea0051489ae1a26766ff1baf8edd7377d5bac7`**,
|
|
335
|
+
11391060 bytes, image `sha256:f1158c7f34cf35a047bf0513c38282bb2fa253529e5ae404b32c6d93697410be`).
|
|
336
|
+
Live: `LIVE=1 ./run.sh release-gate` measured **MUST 17/0/0 + BEHAVIOR 1/0,
|
|
337
|
+
EXIT=0** at this HEAD — the first aggregate to include
|
|
338
|
+
`smoke-acp-v2-send-live`, which closes the SEND half of ACP citizenship (an ACP
|
|
339
|
+
model calls `entwurf_v2` and the `.msg` lands carrying the resident's own garden
|
|
340
|
+
id, `entwurf/<model>`, replyable — a gid never present in the prompt). Two
|
|
341
|
+
stale claims were retired against measurement rather than argument: the
|
|
342
|
+
extension-loader `/compat` shim survives 0.82.0 (root / `/compat` / `/oauth`
|
|
343
|
+
untouched; `/providers/all` is an addition, and the curated Claude anchors are
|
|
344
|
+
byte-identical across the bump), and the "one-shot bundled-MCP teardown hang"
|
|
345
|
+
that a gate comment used as its rationale does not reproduce on this
|
|
346
|
+
combination. What a plain `pi -p` genuinely lacks is garden identity, and only
|
|
347
|
+
without `--entwurf-control` — now documented as a provider/citizen boundary
|
|
348
|
+
instead of read as a defect.
|
|
349
|
+
|
|
350
|
+
2026-07-24 record-era aggregate floor: `LIVE=1 ./run.sh release-gate` measured
|
|
351
|
+
**MUST 16/0/0 + BEHAVIOR 1/0, EXIT=0** on the `repair/v2-core-debt` branch after
|
|
352
|
+
the #50 C1–C3 cuts and the observability repair — the first aggregate run since
|
|
353
|
+
2026-06-27 (every individual smoke had been green, but the two-tier summary and
|
|
354
|
+
exit code of the aggregate command itself had gone unverified for the whole
|
|
355
|
+
hard-cut window; three MUST live smokes were found dead on the pre-C2 address
|
|
356
|
+
contract and re-authored in the same pass). The step count moved 17→16 with the
|
|
357
|
+
v2-cutover smoke retirements. Evidence log: `/tmp/pi-tmux-release-gate.log`
|
|
358
|
+
(scratch `/tmp/entwurf-rg-scratch-20260724`).
|
|
359
|
+
|
|
277
360
|
2026-07-22 repair evidence: Linux artifact-consumer C is committed locally as
|
|
278
361
|
`328c66e` (not yet pushed at the time of this baseline update); B/B2 direct-native
|
|
279
362
|
observations and the exec-only production cut are documented in issue #51 and
|
|
@@ -303,4 +386,4 @@ baselines — live in **CHANGELOG.md and git history**, including the gate names
|
|
|
303
386
|
their era (several of which, e.g. `smoke-all` / `smoke-async-resume` /
|
|
304
387
|
`smoke-compaction-policy` / `sentinel` / `xt-tool-surface`, were retired in the
|
|
305
388
|
v2 cutover). The live calibration reference is the current release floor in
|
|
306
|
-
[VERIFY.md](./VERIFY.md) §0A — most recent: **2026-
|
|
389
|
+
[VERIFY.md](./VERIFY.md) §0A — most recent: **2026-07-24 MUST 16/0/0 + BEHAVIOR 1/0**.
|
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,53 @@ All notable changes to this project will be documented here. Format follows [Kee
|
|
|
4
4
|
|
|
5
5
|
## Unreleased
|
|
6
6
|
|
|
7
|
+
## 0.12.9 — 2026-07-26
|
|
8
|
+
|
|
9
|
+
### Changed
|
|
10
|
+
|
|
11
|
+
- **The curated ACP surface adopts Claude Opus 5 on pi 0.82.1.** The deliberately narrow two-model surface keeps Sonnet 5 and replaces the Opus 4.8 anchor with Opus 5 (1M context, 128K max output, reasoning enabled). The pi runtime pin, closed peer range, lockfile, install gates, and current-version docs move together; source review of pi 0.82.1 confirmed the extension-loader aliases and `/compat` catalog seam are unchanged.
|
|
12
|
+
- **`meta-bridge-fresh-cut` now reports the transition that actually occurred.** Exit 0 means the cut completed, 1 means nothing moved, 2 is usage, 3 means the cut transition is incomplete, and 4 means the generation was archived and the fresh v3 store opened but residue cleanup is incomplete. The command help, `run.sh` usage, operator docs, and deterministic decision/source-fence cells carry the same contract; exit 4 may proceed to `setup`, while rerunning after a new citizen is born would archive the new generation too.
|
|
13
|
+
|
|
14
|
+
### Fixed
|
|
15
|
+
|
|
16
|
+
- **A marker that cannot plausibly own a session no longer blocks the only repair verb or grants identity indefinitely.** The Claude hook, agy imprint, marker write boundary, all sender/receiver readers, fresh-cut inspection, and sender-candidate filtering share one `isPlausibleOwnerPid` policy. On the currently certified Linux desktop/workstation axis, pid 1 is refuted by construction and reported separately from a proven-dead owner; the cut clears that residue instead of waiting forever on init. A container running the harness as pid 1 remains unsupported and fails closed rather than quietly widening the evidence boundary.
|
|
17
|
+
- **`setup` preserves the repository's tracked pi settings across the full install path.** Both writers of `.pi/settings.json` now share one serializer, recognize the portable relative package entry as the same checkout, and leave already-satisfied bytes untouched. The end-to-end gate plants the candidate-index settings in a stand-in checkout, drives the real `run.sh install`, and requires byte and mtime identity, covering both writers and user-scope side effects rather than only a helper.
|
|
18
|
+
- **Duplicate `nativeSessionId` claims are quarantined on discovery and refused wherever a record becomes an address.** `entwurf_peers` lists neither rival while preserving unrelated citizens and naming diagnostics; canonical `entwurf_v2` dispatch checks the store before choosing any transport, and dormant pi resume uses the same addressable read. A regular unreadable rival fails loud because it might be the duplicate, while symlinked, drifted, or unparseable neighbours remain certification/listing defects without being promoted into addressable rivals. The deliberately narrower raw mailbox and marker paths retain the per-entry half of the contract; that boundary and its promotion rule remain tracked in #55.
|
|
19
|
+
- **Record bytes now come from the same opened file description that proves their kind.** `readStoreRecordFile` opens with `O_NOFOLLOW` so a final-component regular-to-symlink swap fails before a byte is read, uses `fstat` on that fd, reads through the fd, and closes in a `finally`. `O_NONBLOCK` prevents the fd-classification repair from introducing a FIFO hang. The preceding `lstat` classification remains a separate policy layer so settled sockets, devices, and mode-000 directories receive the certification contract's non-regular verdict instead of leaking `ENXIO`/`EACCES` as a second vocabulary.
|
|
20
|
+
|
|
21
|
+
### Verification
|
|
22
|
+
|
|
23
|
+
- Pre-version landing HEAD `aaab00fbd293300d25c294580bb19bd3a88ad757` passed exact-SHA GitHub Actions run [30186472796](https://github.com/junghan0611/entwurf/actions/runs/30186472796): `check`, `install-surface`, and `artifact-consumer` all success.
|
|
24
|
+
- The prepared tree passed an independent `pnpm check`, then `LIVE=1 ./run.sh release-gate /tmp/entwurf-release-gate-0.12.9.8NSzz7` completed all green: **MUST PASS=17 FAIL=0 SKIP=0** and **BEHAVIOR PASS=1 FAIL=0**, EXIT=0. Full log: `/tmp/entwurf-release-gate-0.12.9.8NSzz7/release-gate.log`; per-step artifact paths are preserved inside it. Prepared-HEAD exact-SHA CI and preserved-candidate acceptance remain deliberately deferred to `make`.
|
|
25
|
+
|
|
26
|
+
## 0.12.8 — 2026-07-25
|
|
27
|
+
|
|
28
|
+
### Changed
|
|
29
|
+
|
|
30
|
+
- **ACTION REQUIRED — hosts carrying a pre-v3 meta-record store refuse install and every identity write until an explicit generation cut.** The active citizen store is v3-only and carries no cross-generation address or resume continuity: sessions flow; memory lives in native transcripts and the embedding axes, never in the bridge. `install` / `setup` / citizen birth / `entwurf_register_native` refuse before writing when the store cannot certify and name the one repair verb: quiesce sessions, run `entwurf meta-bridge-fresh-cut` (dev clone: `./run.sh meta-bridge-fresh-cut`), then retry. The cut archives `meta-sessions/` + `meta-mailbox/` as forensic siblings and opens an empty v3 generation; no runtime reads the archive and no restore verb exists.
|
|
31
|
+
- **#50 hard cut: the meta-record is the only address authority.** V3 drops `parentGardenId` + `isEntwurf`, removes the v1 `entwurf` / `entwurf_resume` / `entwurf_send` tools and `/entwurf*` commands, deletes `pi/entwurf-targets.json` + `setup:links`, and authorizes dormant resume through record existence plus transcript-header ↔ `record.nativeSessionId` integrity. A call is not parentage and there is no species boolean.
|
|
32
|
+
- **The migration lane is deleted, not deprecated.** `meta-migration.ts`, the M1 backup/migrate/restore command, three gates (`check-meta-migrate-v3`, `check-meta-migration-readers`, `check-upgrade-gate`), and the frozen byte fixtures — 2,404 lines of deleted files, for continuity the substrate does not promise — are replaced by one generation verb (`meta-bridge-fresh-cut`) and one writer/doctor contract (`certifyActiveStore`). The whole upgrade story is quiesce → fresh-cut → go.
|
|
33
|
+
- **The runtime pins move together.** Pi rises 0.80.7 → 0.82.0 under the closed peer range and doc gates; Claude ACP rises to `@agentclientprotocol/claude-agent-acp 0.61.0` + `@agentclientprotocol/sdk 1.3.0`, with `@anthropic-ai/sdk 0.100.1` retained. The ACP send gate proves a provider model can send as its host socket-citizen.
|
|
34
|
+
|
|
35
|
+
### Fixed
|
|
36
|
+
|
|
37
|
+
- **One active-store contract is shared by the doctor and every identity writer.** `certifyActiveStore` requires each `.meta.json` to be a regular file, readable by the live schema, named by its own body, and the unique holder of its `nativeSessionId`; it runs store-wide before every identity write. Targeted reads enforce the per-entry half and never follow a symlink. Duplicate uniqueness on read/discovery remains tracked separately in #52.
|
|
38
|
+
- **Unknown is never silently converted to absent or dead on the fresh-cut path.** ENOENT alone means absence across record, store, directory and socket-entry inspection; EACCES/ENOTDIR/ELOOP and symlink/non-directory surfaces refuse as UNCERTAIN. The quiesce gate also probes marker-less native-push citizens through the same adapter dispatch uses, and `pgrep` exit 1 alone means no host while scan failures stay indeterminate. Five directory inputs across four code paths and the socket-entry layer are covered by F12–F18.
|
|
39
|
+
- **The archive plan refuses common half-cut causes before moving and reports every partial move honestly.** Store and mailbox may have different parents, so each planned rename preflights parent writability and every destination is inspected with ENOENT-only absence before the first move. No permission probe can promise a rename (sticky bit, immutable attributes, read-only mounts and LSMs remain possible); if a rename fails, the loop prints each `archived so far:` path, calls the generation HALF-CUT, and gives the exact retry/manual-inspection prescription.
|
|
40
|
+
- **Only a doctor verdict earns a destructive prescription.** Both store-doctor callers map exit 1 to certification defects → fresh-cut and exit 3 to access repair; usage, crash and unknown exits are doctor/runtime failures and prescribe no cut. `run.sh` also guards the actual doctor entry selected by its mode (source `.ts` vs installed compiled `.js`), so a missing artifact cannot collide with the doctor's defect exit. I7–I9 drive both callers and the installed-artifact seam.
|
|
41
|
+
- **The installed-host acceptance closed two operator/test seams.** `./run.sh remove-dev-bin` now shifts its own command name before invoking the honest inverse. Stable-bin smokes remove every pre-existing provider/statusline bin directory from their sandbox PATH, so a maintainer carrying both dev links and registry shims cannot mask a dangling-command negative.
|
|
42
|
+
|
|
43
|
+
### Carried from the repair line
|
|
44
|
+
|
|
45
|
+
- Exec-form Claude hooks + the enforced Claude Code `>=2.1.217` floor (repair.0), and the capability registry beside the emitted MCP bridge with live-command physical delivery in `doctor-meta-bridge` (repair.1), are promoted to `latest`. After publication the required registry shape is `latest=0.12.8`, `repair=0.12.8-repair.1`.
|
|
46
|
+
|
|
47
|
+
### Verification
|
|
48
|
+
|
|
49
|
+
- Pre-version landing HEAD `1345688001ed6629bd0f58996a36134e7b7874bc` passed exact-SHA GitHub Actions run [30150824225](https://github.com/junghan0611/entwurf/actions/runs/30150824225): `check`, `install-surface`, and `artifact-consumer` all success.
|
|
50
|
+
- Published `0.12.8-repair.1` passed installed `doctor-meta-bridge` on maintainer + secondary Linux hosts after a new real Claude session opened with a live MCP child; both runs included physical `entwurf_v2` delivery and live owner join (BASELINE HISTORY).
|
|
51
|
+
- On the stable prepared tree, `LIVE=1 ./run.sh release-gate` is all green — **MUST PASS=17 FAIL=0 SKIP=0** (its first step is the full `pnpm check`; the run includes `smoke-acp-bundled-mcp-live` and `smoke-acp-v2-send-live`) and **BEHAVIOR PASS=1 FAIL=0**, EXIT=0 — at scratch `/tmp/entwurf-release-gate-0.12.8.u9y9IX`, complete log `/tmp/entwurf-release-gate-0.12.8.u9y9IX/release-gate.log`, per-step artifact paths printed inside it. The static gate judges the **candidate index**, so the release-prep bytes were staged before the run, not merely present in the working tree.
|
|
52
|
+
- Prepared HEAD `e31c28f` passed exact-SHA GitHub Actions run [30152323861](https://github.com/junghan0611/entwurf/actions/runs/30152323861) with `check`, `install-surface`, and `artifact-consumer` all successful. The preserved candidate `junghanacs-entwurf-0.12.8.tgz` (sha256 `7c7e8985823391ec6dfae918e08c4aed1fafd06b7415806b2d591b0cb95891f3`) passed the checkout-invisible container consumer, was tagged as `v0.12.8`, released on GitHub, and published as `latest=0.12.8` while `repair=0.12.8-repair.1` remained unchanged.
|
|
53
|
+
|
|
7
54
|
## 0.12.8-repair.1 — 2026-07-22
|
|
8
55
|
|
|
9
56
|
### Fixed
|
package/DELIVERY.md
CHANGED
|
@@ -86,7 +86,7 @@ D2 receiver_armed: pass
|
|
|
86
86
|
D3 addressed_enqueue: pass
|
|
87
87
|
D4 idle_active_wake: pass
|
|
88
88
|
D5 context_injection: pass token=AGY-PARITY-3399
|
|
89
|
-
D6 continuity: pass session_id=<native-id> model=claude-opus-
|
|
89
|
+
D6 continuity: pass session_id=<native-id> model=claude-opus-5
|
|
90
90
|
D7 completion_reply: partial reason="no garden outbox yet"
|
|
91
91
|
D8 robustness: partial reason="loop guard present; crash recovery not tested"
|
|
92
92
|
```
|
|
@@ -109,8 +109,8 @@ the `D0–D8` capability level:
|
|
|
109
109
|
|
|
110
110
|
| Harness / surface | Status | Highest current level | Transport | Notes |
|
|
111
111
|
|---|---|---:|---|---|
|
|
112
|
-
| **pi native Entwurf** | shipped | D7+ | Unix control socket + pi followUp/custom messages | Replyable pi session. This is the resident baseline, not an external meta-session.
|
|
113
|
-
| **Claude Code interactive >=2.1.217** | shipped *(Linux is the only certified axis
|
|
112
|
+
| **pi native Entwurf** | shipped | D7+ | Unix control socket + pi followUp/custom messages | Replyable pi session. This is the resident baseline, not an external meta-session. The meta-record is the sole address authority (#50 C4): a record-less control socket — live or not — is refused as `record-less-socket` (diagnostic state), never dispatched. |
|
|
113
|
+
| **Claude Code interactive >=2.1.217** | shipped *(Linux is the only certified axis)* | D6, D7 partial, D8 partial | Exec-form global plugin: `SessionStart` arms `watchPaths`; external write triggers exec-form `FileChanged`; `asyncRewake` wakes idle session | B2 direct-native at 2.1.217 on one NixOS host proved per-element argv, no shell expansion, parent join, and exit-2 idle wake. B at 2.1.138 proved the negative: `args` discarded while Claude reported success, so installer/doctor enforce 2.1.217 and there is no shell fallback. The launcher provenance token keeps an old cached command fail-closed. Active idle wake is D6; D7/D8 remain partial as before. The Linux container's planted cache/owner/bridge are fixtures, not a second native-host proof. |
|
|
114
114
|
| **Antigravity / agy** | shipped | D6, D7 partial | Native LS gRPC `agentapi send-message` (native-push) | `PreInvocation` automatically births/attaches by native `conversationId` and writes the record-backed pid/start-key sender marker; `entwurf_v2` fire-and-forget probes and direct-injects through the antigravity adapter with a one-shot re-probe retry. Three managed adapters own MCP+one exact permission, statusline, and hook separately. `entwurf_register_native` remains an explicit/manual fallback, not the normal birth path. Live sender→sibling→same-gid reply passed on 2026-07-13, re-verified at **agy 1.1.0** on 2026-07-14 (13/13 LIVE checks); D7 stays partial because there is no canonical transcript/content receipt owned by the smoke. |
|
|
115
115
|
| **Codex app-server-backed TUI 0.136.0** | verified-probe | D6, D7 (status) | WebSocket-over-UDS `turn/start` into the live `threadId` | **Demonstrated, no managed standalone, no cloud.** `codex app-server --listen unix://<owned 0700 dir>` + plain `codex` auto-attach (or `--remote unix://`). Full message injection (agy-like, not a doorbell); `thread/status/changed` gives completion observation. D8 robustness (dedupe / crash recovery / ordering policy) is not tested. `turn/steer` is active-turn steering, not idle wake. |
|
|
116
116
|
| **Codex embedded TUI 0.136.0** | deferred | D0 partial | Native state DB / rollout transcript only | Standalone Embedded TUI binds no socket; no `FileChanged`/`asyncRewake` in Codex hooks; not retrofittable. Identify-only via state DB / rollout. |
|