Skip to content

v0.12.7

Latest

Choose a tag to compare

@junghan0611 junghan0611 released this 14 Jul 05:15

Fixed

  • Three operator commands were dead in every installed package, and the class is now fenced in one place. entwurf doctor-pi-provider, entwurf new-session-id, and entwurf meta-bridge-prune dispatch through run.sh, whose REPO_DIR sits under node_modules once installed — so each one executed a raw .ts and died on ERR_UNSUPPORTED_NODE_MODULES_TYPE_STRIPPING. new-session-id is the alias docs/setup-clean-host.md tells operators to run, and doctor-pi-provider is the pi-ownership verdict, so both shipped broken while every dev clone stayed green. This is the same fence start.sh (0.12.1), the store-doctor (0.12.4), the plugin hook (0.12.5), and the agy imprint hook already crossed by hand — the fourth recurrence, and the reason it is no longer hand-written. All 75 .ts entrypoints in run.sh now route through a single run_ts helper that dispatches to the prepack-emitted JS when installed and keeps transparent source execution in a dev clone; a dev-only gate, which has no compiled twin by design, is REFUSED with a legible message rather than falling back to raw .ts or exiting 0 as a silent no-op.
  • The install surface is now verified, not assumed. check-pack-install packed a real tarball but drove only bins — never a subcommand — which is precisely why the three commands passed every gate while being dead on arrival. It now executes them from the installed bin under node_modules and asserts MEANING, not the absence of a crash: the session id must match SESSION_ID_RE, the doctor must reach its own verdict body, and prune must walk the 0-record store it was handed. A new static check-install-surface closes the other half: run_ts is the only fence crossing (S1), every operator subcommand has a compiled twin whether it calls run_ts directly or through a helper — the house style (S2), no npm bin points at a raw .ts and every .sh bin that execs one branches on node_modules (S3), and dev-only gates stay out of the tarball (S4). Each S is mutation-checked against the bug it names; review found three bypasses in the first cut (a raw-.ts bin, an operator command hidden behind a helper, and a smoke that aliased the live path into a variable), and all three now fail the gate.
  • The agy bridge doctor no longer reports a working host as broken. It demanded the literal string mcp(entwurf-bridge/entwurf_v2) in permissions.allow, so a host whose operator had granted a broad mcp(*) was told the bridge was "registered and unusable — agy prompts on EVERY entwurf_v2 call". That was false: agy matches mcp(*) and mcp(<server>) against our tool, which the doctor already knew — it read exactly that coverage in the deny/ask direction to detect shadowing, and then refused to read it in the allow direction. Coverage is now read both ways. The installer still writes only the narrowest rule it needs; the doctor distinguishes a grant we own (allow → …) from one the operator's broader rule is carrying (a NOTE that names the covering rule and warns that narrowing it takes the grant away) from a genuinely missing one (DRIFT). Deny/ask precedence is unchanged and still fails loud, including when the same broad rule sits in both lists. Ownership beats coverage in the other direction too (review follow-up): when the permission-state records that WE added the exact rule and it has since vanished, an operator wildcard keeping calls alive does not make the doctor green — it reports both axes (our grant gone, their rule covering) and stays red; a whole-file settings relink (agent-config ensure_link) produces exactly this shape, and only the statusline doctor caught it before.
  • agy doctors now bind install-state to the live file this host actually reads. A hard-verification sweep moved HOME to /tmp but inherited the operator's real XDG_DATA_HOME, writing seven sandbox-target state records into ~/.local/share/entwurf; all three doctors inspected those foreign files and reported green. Bridge, permission, statusline, and hook state now fail FOREIGN TARGET when their normalized managed path differs from the live target, and fail CORRUPT when the state body is unreadable or lacks its required path. Permission state is checked independently even if bridge state is absent. Runtime and ownership evidence remain separate: a resolvable live command is still reported as present while foreign/corrupt provenance keeps the final verdict red. A relative managed path is CORRUPT too (review follow-up): install only ever records absolute paths, and normalizing a relative one against the doctor's own cwd could bless whatever directory it happens to run from. Regressions cover foreign targets, corrupt/relative state, the independent permission-state rail, and wildcard-masked owned drift (agy install/statusline/hooks: 140/69/44).

Fixed (post-review, 2026-07-14 PM)

  • The offline floor no longer removes the operator's live pi-provider wiring while reporting green. smoke-user-scope-citizen redirected PI_CODING_AGENT_DIR to fake settings but left XDG_DATA_HOME real. Its run.sh remove-user-scope drive therefore consumed the operator's real ownership state, followed that state's recorded managedSettingsPath, removed entwurfProvider.mcpServers.entwurf-bridge from the real ~/.pi/agent/settings.json, and deleted the real state. This made the final bundled-MCP LIVE gate fail with Connected MCP servers: (none registered) after pnpm check had passed. Both inverse calls now pair the fake agent dir with fake XDG state, and the gate sandboxes HOME and the whole XDG trio up front, so the next root run.sh reaches for is already fenced. A before/after byte comparison proves the smoke leaves the live settings, the real $XDG_DATA_HOME/entwurf tree, and the real imprint log unchanged. Review then found the first S5c too narrow to hold the class it was written for: it fired only on the inline-env form, so hoisting the same override into an export one line up walked the identical leak past a green gate (mutation-proven), and its command list blessed install/setup drives that sandbox PI_CODING_AGENT_DIR — which those commands ignore, since ensure_agent_dir_symlinks hard-codes $HOME/.pi/agent and would still relink the operator's real agent dir. S5c now matches the drive (in any env form, and never in prose or an assertion string) and then demands the isolation that command actually needs at each root it writes. Cross-review closed one more ordering hole in that rewrite: a sandbox export XDG_DATA_HOME counts as isolation only for drives that come after it, so a trailing export can no longer retroactively bless a mutation that already ran against the live state (mutation-checked).
  • check-pack-install no longer leaks into the operator's real XDG roots — and proves it on every return path. The gate swapped HOME per drive but inherited the operator's exported XDG roots, so its run.sh install drive wrote a foreign pi-provider install-state into the real ~/.local/share/entwurf and the agy-imprint drive appended fake birth lines to the real ~/.local/state/entwurf/agy-imprint.log — the same class as the 2026-07-13 hard-verify pollution, one layer deeper: inside run.sh itself, where S5/S5b (which scan only scripts/*.sh) cannot see. Every sandbox drive now exports XDG_DATA_HOME/XDG_STATE_HOME/XDG_CACHE_HOME alongside HOME. Review found the first self-fence was itself too narrow: it ran only on the success tail and fenced DATA while the known leak also touched STATE. The final outer self-fence runs after every success or early-failure path, requires the operator's real install-state tree to stay byte-identical, and requires the gate-specific fake agy marker count in the real imprint log not to increase. Dropping a drive's XDG swap is mutation-checked. A separate live audit also disproved the initial “all wiring intact” claim: Claude's XDG marketplace artifact was absent, producing cache-miss, no SessionStart records after 08:46, and an honest 🪛 ? cc; this was a real meta-bridge disconnect, not agy's documented pre-first-turn ?. Reinstalling the live meta-bridge restored source=assembled=installed parity and a fresh Claude probe automatically birthed garden id 20260714T121134-5effc4 (record count 116→117).

Changed

  • Backend drift pins moved, each with an explicit verdict. agy 1.0 → 1.1 after live re-verification on the new minor (2026-07-14, agy 1.1.0: entwurf_self without a permission prompt, bidirectional native-push reply on the same gid, LIVE=1 smoke-agy-native-push-live 13/13 — evidence in DELIVERY.md §Antigravity). codex 0.136 → 0.144 as an observed bump, not a re-verification: codex is not a shipped native-citizen lane in 0.12.x, so the probe evidence stays dated at 0.136.0 and DELIVERY.md §Codex now carries the explicit non-reverification verdict; re-run the raw probes before building any codex adapter.

  • CI now runs the install surface, not just the source tree. pnpm check is a dev-clone floor by construction: every fence bug this repo has shipped was green on it. check-pack-install was release-gate-only, so the installed axis had never been in CI at all. It is now its own job (~1 minute), which is what turns "we fixed it" into "it cannot come back".

  • Verification may not rewire the operator's own installation. check-install-surface S5 flags an offline smoke that writes a live ~/.claude / ~/.gemini / ~/.pi path before swapping the process HOME to a sandbox — or without swapping at all — including one hop of variable aliasing. The current tree is clean (the install smokes all export HOME to a sandbox first, and smoke-resident-garden-guard's rm -rf targets a mktemp -d), so this pins the existing contract rather than fixing a live break. It is a static tripwire, not a sandbox proof: it reads shell source, so a path assembled across several variables or built inside an embedded heredoc would slip past it. The real guarantee — running the whole offline floor under a swapped HOME — is recorded in NEXT.md as open, not claimed here. S5b (review follow-up) pins the axis the 2026-07-14 pollution actually used: any offline smoke that swaps HOME into a sandbox must swap XDG_DATA_HOME with it, because HOME alone still writes real install-state below the inherited XDG root.

  • Install/package hygiene guards now seal three post-0.12.6 edges. Package tarballs exclude Python bytecode residue even though scripts/ ships as a whole, pack gates serialize the full npm pack dist-read window and use per-run tarball destinations, and the user-scope pi package inverse is exposed as explicit remove-user-scope with a read-only --remove --dry-run preview.