@junghanacs/entwurf 0.41.1 → 0.41.2
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 +1 -1
- package/BASELINE.md +7 -5
- package/CHANGELOG.md +185 -0
- package/DELIVERY.md +37 -20
- package/README.md +70 -65
- package/VERIFY.md +9 -9
- package/docs/external-mcp-host.md +1 -1
- package/docs/setup-clean-host.md +59 -33
- package/mcp/entwurf-bridge/dist/mcp/entwurf-bridge/src/index.js +14 -11
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/entwurf-self-address.js +10 -0
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/entwurf-v2-contract.js +23 -2
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/entwurf-v2-decider.js +7 -1
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/entwurf-v2-surface.js +3 -0
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/fresh-call-composition.js +21 -10
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/herdr-fresh-call.js +4 -2
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/meta-sender-identity.js +5 -0
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/mux-fresh-call.js +6 -4
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/native-push/register.js +13 -2
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/omp-fresh-preflight.js +2 -2
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/pi-durable-fresh-preflight.js +1 -1
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/remote-pair-receive.js +25 -17
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/remote-pair-send.js +94 -28
- package/mcp/entwurf-bridge/dist/pi-extensions/meta-bridge-omp.js +57 -7
- package/mcp/entwurf-bridge/dist/pi-extensions/meta-bridge-pi-durable.js +2 -2
- package/mcp/entwurf-bridge/dist/scripts/remote-pair-receive.js +12 -12
- package/mcp/entwurf-bridge/src/index.ts +14 -11
- package/native/win32-x64/entwurf_win.node +0 -0
- package/native/win32-x64/manifest.json +2 -2
- package/package.json +4 -4
- package/pi-extensions/lib/entwurf-self-address.ts +13 -0
- package/pi-extensions/lib/entwurf-v2-contract.ts +25 -2
- package/pi-extensions/lib/entwurf-v2-decider.ts +7 -0
- package/pi-extensions/lib/entwurf-v2-surface.ts +3 -0
- package/pi-extensions/lib/fresh-call-composition.ts +21 -10
- package/pi-extensions/lib/herdr-fresh-call.ts +4 -2
- package/pi-extensions/lib/meta-sender-identity.ts +4 -0
- package/pi-extensions/lib/mux-fresh-call.ts +6 -4
- package/pi-extensions/lib/native-push/register.ts +17 -2
- package/pi-extensions/lib/omp-fresh-preflight.ts +2 -2
- package/pi-extensions/lib/pi-durable-fresh-preflight.ts +1 -1
- package/pi-extensions/lib/remote-pair-receive.ts +27 -19
- package/pi-extensions/lib/remote-pair-send.ts +117 -30
- package/pi-extensions/meta-bridge-omp.ts +69 -7
- package/pi-extensions/meta-bridge-pi-durable.ts +2 -2
- package/run.sh +173 -22
- package/scripts/check-agy-sender-identity.ts +6 -4
- package/scripts/check-entwurf-self-address.ts +34 -3
- package/scripts/check-entwurf-v2-contract.ts +24 -2
- package/scripts/check-entwurf-v2-production.ts +45 -31
- package/scripts/check-gate-qualification.ts +10 -8
- package/scripts/check-native-push-adapter.ts +4 -0
- package/scripts/check-native-push-register.ts +32 -82
- package/scripts/check-remote-pair-installed.ts +2 -2
- package/scripts/dev-bin.sh +112 -1
- package/scripts/lib/chain-terminus-publication.ts +58 -0
- package/scripts/lib/codex-fresh-live-protocol.ts +30 -0
- package/scripts/lib/codex-fresh-source-receipts.ts +112 -3
- package/scripts/lib/pi-durable-fresh-live-receipts.ts +29 -1
- package/scripts/mutants/chain-terminus-publication.json +17 -0
- package/scripts/mutants/codex-native.json +98 -0
- package/scripts/mutants/control-send-receipt.json +2 -2
- package/scripts/mutants/mux-fresh-call.json +16 -1
- package/scripts/mutants/native-push-paused.json +17 -0
- package/scripts/mutants/omp-fresh.json +13 -2
- package/scripts/mutants/pack-install.json +46 -0
- package/scripts/mutants/remote-pair-display.json +3 -3
- package/scripts/mutants/remote-pair-receive.json +41 -11
- package/scripts/mutants/remote-pair-roundtrip.json +67 -7
- package/scripts/mutants/remote-pair-send.json +156 -17
- package/scripts/mutants/remote-pair-transport.json +4 -4
- package/scripts/mutants/source-install.json +66 -0
- package/scripts/remote-pair-receive.ts +12 -12
- package/scripts/smoke-agy-install-state.sh +121 -0
- package/scripts/smoke-agy-native-push-live.ts +13 -0
- package/scripts/smoke-codex-fresh-live.ts +50 -27
- package/scripts/smoke-entwurf-chain-live.ts +7 -9
- package/scripts/smoke-herdr-fresh-call-live.ts +4 -4
- package/scripts/smoke-herdr-plugin-build-live.ts +179 -50
- package/scripts/smoke-mux-lifecycle-live.ts +140 -8
- package/scripts/smoke-omp-fresh-live.ts +5 -4
- package/scripts/smoke-pi-durable-fresh-live.ts +29 -7
- package/scripts/smoke-setup-verdict.sh +27 -2
|
@@ -461,6 +461,126 @@ export ENTWURF_AGY_STATUSLINE_TARGET="$SB/fake-status.sh"
|
|
|
461
461
|
export ENTWURF_AGY_IMPRINT_TARGET="$SB/fake-aux.sh"
|
|
462
462
|
export ENTWURF_COPILOT_STATUSLINE_TARGET="$SB/fake-aux.sh"
|
|
463
463
|
|
|
464
|
+
# Hermetic PATH for every dev-bin cell: the host's own entwurf entrypoints (e.g. a real
|
|
465
|
+
# ~/.local/bin/entwurf into some checkout) and its real pnpm/npm global bin dirs must not leak into
|
|
466
|
+
# the exclusivity verdict. Drop every host PATH dir that carries a package bin name, and put fixture
|
|
467
|
+
# package managers first; FAKE_PM_MODE picks their answer. Restored after the dev-bin cells.
|
|
468
|
+
DEVBIN_ORIG_PATH="$PATH"
|
|
469
|
+
PACKAGE_BINS="$(python3 -c 'import json,sys; print(" ".join(json.load(open(sys.argv[1]))["bin"]))' "$REPO_DIR/package.json")"
|
|
470
|
+
HERMETIC_PATH=""
|
|
471
|
+
IFS=':' read -r -a _dirs <<<"$PATH"
|
|
472
|
+
for _d in "${_dirs[@]}"; do
|
|
473
|
+
[ -n "$_d" ] || continue
|
|
474
|
+
for _b in $PACKAGE_BINS; do { [ -e "$_d/$_b" ] || [ -L "$_d/$_b" ]; } && continue 2; done
|
|
475
|
+
HERMETIC_PATH="${HERMETIC_PATH:+$HERMETIC_PATH:}$_d"
|
|
476
|
+
done
|
|
477
|
+
unset _dirs _d _b
|
|
478
|
+
FAKE_PM="$SB/fake-pm"; PM_ROOT="$SB/pm"; mkdir -p "$FAKE_PM"
|
|
479
|
+
for _pm in pnpm npm; do
|
|
480
|
+
case "$_pm" in pnpm) _q="bin -g"; _a="$PM_ROOT/pnpm-bin" ;; npm) _q="prefix -g"; _a="$PM_ROOT/npm-prefix" ;; esac
|
|
481
|
+
cat > "$FAKE_PM/$_pm" <<SH
|
|
482
|
+
#!/usr/bin/env bash
|
|
483
|
+
[ "\$*" = "$_q" ] || { echo "fixture $_pm answers only: $_q" >&2; exit 64; }
|
|
484
|
+
case "\${FAKE_PM_MODE:-ok}" in
|
|
485
|
+
ok) [ "$_pm" = npm ] || case ":\$PATH:" in *":$_a:"*) ;; *) echo "[ERROR] The configured global bin directory \"$_a\" is not in PATH" >&2; exit 1 ;; esac
|
|
486
|
+
echo "$_a" ;;
|
|
487
|
+
fail) echo "ERR_FIXTURE_$_pm boom" >&2; exit 1 ;;
|
|
488
|
+
hang) exec sleep 30 ;;
|
|
489
|
+
esac
|
|
490
|
+
SH
|
|
491
|
+
chmod +x "$FAKE_PM/$_pm"
|
|
492
|
+
done
|
|
493
|
+
unset _pm _q _a
|
|
494
|
+
mkdir -p "$PM_ROOT/pnpm-bin" # an existing, empty pnpm global bin dir
|
|
495
|
+
export PATH="$FAKE_PM:$HERMETIC_PATH:$PM_ROOT/pnpm-bin" # pnpm 11 answers `bin -g` only when that dir is on PATH
|
|
496
|
+
want "dev-bin hermetic PATH: no package bin name resolves, and pnpm/npm are the fixtures" \
|
|
497
|
+
"! command -v entwurf >/dev/null && [ \"\$(command -v pnpm)\" = '$FAKE_PM/pnpm' ] && [ \"\$(command -v npm)\" = '$FAKE_PM/npm' ]"
|
|
498
|
+
|
|
499
|
+
# J-X: developer-install exclusivity (dev-bin.sh exclusive). A certified PATH winner alone let an
|
|
500
|
+
# old global shim LATER in PATH stay selectable by a shell with another PATH order (non-interactive
|
|
501
|
+
# SSH picked it). Every cell links by NAME so an operator-set mutant elsewhere cannot reach here.
|
|
502
|
+
bash "$DEVBIN" expose entwurf >/dev/null 2>&1
|
|
503
|
+
bash "$DEVBIN" expose entwurf-bridge >/dev/null 2>&1
|
|
504
|
+
SAME_DIR="$SB/same-root"; mkdir -p "$SAME_DIR"
|
|
505
|
+
ln -s "$SB/fake-entwurf.sh" "$SAME_DIR/entwurf" # a second link, same target
|
|
506
|
+
ln -s "$DLINK" "$SAME_DIR/entwurf-bridge" # a chain through our link, same target
|
|
507
|
+
set +e; OUT="$(PATH="$DBIN_DIR:$DBIN_DIR:$SAME_DIR:$PATH" bash "$DEVBIN" exclusive 2>&1)"; RC=$?; set -e
|
|
508
|
+
want "dev-bin exclusive: duplicate PATH entries and links resolving to our target are the same install [QK:SOURCE-SAME-TARGET-PASSES]" \
|
|
509
|
+
"[ '$RC' -eq 0 ] && printf '%s' \"\$OUT\" | grep -q 'no other root under the 6 package bin names'"
|
|
510
|
+
want "dev-bin exclusive: an existing-but-empty package-manager global bin is checked and clean, and the PASS names its limit" \
|
|
511
|
+
"printf '%s' \"\$OUT\" | grep -q 'pnpm global bin $PM_ROOT/pnpm-bin' && printf '%s' \"\$OUT\" | grep -q 'another shell.s PATH or another package manager is not covered'"
|
|
512
|
+
TOOLS_ONLY="$SB/tools-only"; mkdir -p "$TOOLS_ONLY"
|
|
513
|
+
for _t in bash python3 dirname env; do ln -s "$(command -v "$_t")" "$TOOLS_ONLY/$_t"; done; unset _t
|
|
514
|
+
set +e; OUT="$(PATH="$TOOLS_ONLY:$DBIN_DIR" bash "$DEVBIN" exclusive 2>&1)"; RC=$?; set -e
|
|
515
|
+
want "dev-bin exclusive: an absent package manager is a named not-checked line, not a failure" \
|
|
516
|
+
"[ '$RC' -eq 0 ] && printf '%s' \"\$OUT\" | grep -q 'not checked: pnpm not on PATH' && printf '%s' \"\$OUT\" | grep -q 'not checked: npm not on PATH'"
|
|
517
|
+
rm -rf "$SAME_DIR"
|
|
518
|
+
|
|
519
|
+
OTHER_DIR="$SB/old-global/bin"; mkdir -p "$OTHER_DIR"
|
|
520
|
+
printf '#!/bin/sh\nexec /old/global/entwurf "$@"\n' > "$OTHER_DIR/entwurf"; chmod +x "$OTHER_DIR/entwurf"
|
|
521
|
+
want "dev-bin control: with an old shim LATER in PATH the winner is still ours, so verify alone passes" \
|
|
522
|
+
"PATH='$DBIN_DIR:$OTHER_DIR':\"\$PATH\" bash '$DEVBIN' verify entwurf >/dev/null 2>&1"
|
|
523
|
+
set +e; OUT="$(PATH="$DBIN_DIR:$OTHER_DIR:$PATH" bash "$DEVBIN" exclusive 2>&1)"; RC=$?; set -e
|
|
524
|
+
want "dev-bin exclusive: an old root LATER in PATH is named and refused, not hidden behind our winner [QK:SOURCE-LATER-ROOT-FAILS]" \
|
|
525
|
+
"[ '$RC' -eq 5 ] && printf '%s' \"\$OUT\" | grep -qF 'another entwurf root is still selectable: $OTHER_DIR/entwurf'"
|
|
526
|
+
want "dev-bin exclusive: the refusal removes nothing and says so" \
|
|
527
|
+
"[ \"\$(sed -n 2p '$OTHER_DIR/entwurf')\" = 'exec /old/global/entwurf \"\$@\"' ] && [ -L '$OLINK' ] && printf '%s' \"\$OUT\" | grep -q 'nothing was removed'"
|
|
528
|
+
mkdir -p "$SB/other-checkout/mcp/entwurf-bridge"; printf '#!/bin/sh\n' > "$SB/other-checkout/mcp/entwurf-bridge/start.sh"
|
|
529
|
+
rm -f "$OTHER_DIR/entwurf"; ln -s "$SB/other-checkout/mcp/entwurf-bridge/start.sh" "$OTHER_DIR/entwurf-bridge"
|
|
530
|
+
set +e; OUT="$(PATH="$DBIN_DIR:$OTHER_DIR:$PATH" bash "$DEVBIN" exclusive 2>&1)"; RC=$?; set -e
|
|
531
|
+
want "dev-bin exclusive: a helper name from another checkout is refused like the operator" \
|
|
532
|
+
"[ '$RC' -eq 5 ] && printf '%s' \"\$OUT\" | grep -qF '$OTHER_DIR/entwurf-bridge -> $SB/other-checkout/mcp/entwurf-bridge/start.sh'"
|
|
533
|
+
rm -rf "$SB/old-global"
|
|
534
|
+
|
|
535
|
+
mkdir -p "$PM_ROOT/npm-prefix/bin"; printf '#!/bin/sh\n' > "$SB/other-checkout/run.sh"
|
|
536
|
+
ln -s "$SB/other-checkout/run.sh" "$PM_ROOT/npm-prefix/bin/entwurf" # npm's <prefix>/bin, OFF this PATH
|
|
537
|
+
set +e; OUT="$(PATH="$DBIN_DIR:$PATH" bash "$DEVBIN" exclusive 2>&1)"; RC=$?; set -e
|
|
538
|
+
want "dev-bin exclusive: another root in npm's global bin dir is refused although that dir is not on this PATH [QK:SOURCE-GLOBAL-BIN-OTHER-ROOT]" \
|
|
539
|
+
"[ '$RC' -eq 5 ] && printf '%s' \"\$OUT\" | grep -qF '$PM_ROOT/npm-prefix/bin/entwurf -> $SB/other-checkout/run.sh' && printf '%s' \"\$OUT\" | grep -qx ' seen via: npm global bin'"
|
|
540
|
+
want "dev-bin exclusive: the removal hint is conditional on the package manager, never asserted" \
|
|
541
|
+
"printf '%s' \"\$OUT\" | grep -qF 'if a global @junghanacs/entwurf installed it: npm uninstall -g @junghanacs/entwurf' && printf '%s' \"\$OUT\" | grep -q 'otherwise remove it through whoever owns it'"
|
|
542
|
+
rm -rf "$PM_ROOT/npm-prefix"
|
|
543
|
+
|
|
544
|
+
set +e; OUT="$(FAKE_PM_MODE=fail PATH="$DBIN_DIR:$PATH" bash "$DEVBIN" exclusive 2>&1)"; RC=$?; set -e
|
|
545
|
+
want "dev-bin exclusive: a package manager that cannot answer is refused, not read as clean [QK:SOURCE-GLOBAL-QUERY-REFUSED]" \
|
|
546
|
+
"[ '$RC' -eq 6 ] && printf '%s' \"\$OUT\" | grep -qF 'could not inspect a package manager — \`pnpm bin -g\` exited 1: ERR_FIXTURE_pnpm boom'"
|
|
547
|
+
set +e; OUT="$(FAKE_PM_MODE=hang ENTWURF_DEV_BIN_PM_TIMEOUT=1 PATH="$DBIN_DIR:$PATH" bash "$DEVBIN" exclusive 2>&1)"; RC=$?; set -e
|
|
548
|
+
want "dev-bin exclusive: a package manager that hangs is bounded and refused" \
|
|
549
|
+
"[ '$RC' -eq 6 ] && printf '%s' \"\$OUT\" | grep -q 'did not answer within 1s'"
|
|
550
|
+
set +e; OUT="$(PATH="$DBIN_DIR:$FAKE_PM:$HERMETIC_PATH" bash "$DEVBIN" exclusive 2>&1)"; RC=$?; set -e
|
|
551
|
+
want "dev-bin exclusive: pnpm refusing because its global bin dir is off PATH is an inspect failure, not a clean dir" \
|
|
552
|
+
"[ '$RC' -eq 6 ] && printf '%s' \"\$OUT\" | grep -qF 'is not in PATH'"
|
|
553
|
+
|
|
554
|
+
# The package manifest is read by the verdict step itself: an unreadable or wrong-shaped one is an
|
|
555
|
+
# inspect failure, never "0 names, no other root". Driven on a copy of THIS dev-bin.sh beside a
|
|
556
|
+
# sandbox package.json, so the repo's own manifest is never touched.
|
|
557
|
+
MANI="$SB/manifest-copy"; mkdir -p "$MANI/scripts"; cp "$DEVBIN" "$MANI/scripts/dev-bin.sh"
|
|
558
|
+
cp "$REPO_DIR/package.json" "$MANI/package.json"
|
|
559
|
+
set +e; OUT="$(PATH="$DBIN_DIR:$PATH" bash "$MANI/scripts/dev-bin.sh" exclusive 2>&1)"; RC=$?; set -e
|
|
560
|
+
want "dev-bin exclusive control: the copied script with the real manifest checks all 6 names and passes" \
|
|
561
|
+
"[ '$RC' -eq 0 ] && printf '%s' \"\$OUT\" | grep -q 'no other root under the 6 package bin names'"
|
|
562
|
+
printf 'not json{' > "$MANI/package.json"
|
|
563
|
+
set +e; OUT="$(PATH="$DBIN_DIR:$PATH" bash "$MANI/scripts/dev-bin.sh" exclusive 2>&1)"; RC=$?; set -e
|
|
564
|
+
want "dev-bin exclusive: an unreadable package manifest is refused, never read as zero names [QK:SOURCE-MANIFEST-UNREADABLE-REFUSED]" \
|
|
565
|
+
"[ '$RC' -eq 6 ] && printf '%s' \"\$OUT\" | grep -qF 'could not inspect the package manifest $MANI/package.json' && ! printf '%s' \"\$OUT\" | grep -q '0 package bin names'"
|
|
566
|
+
for _shape in '{"name":"x"}' '{"bin":"./run.sh"}' '{"bin":{}}' '{"bin":{"entwurf-bridge":"./x"}}'; do
|
|
567
|
+
printf '%s' "$_shape" > "$MANI/package.json"
|
|
568
|
+
set +e; OUT="$(PATH="$DBIN_DIR:$PATH" bash "$MANI/scripts/dev-bin.sh" exclusive 2>&1)"; RC=$?; set -e
|
|
569
|
+
want "dev-bin exclusive: manifest $_shape is refused as uninspectable" \
|
|
570
|
+
"[ '$RC' -eq 6 ] && printf '%s' \"\$OUT\" | grep -qF 'could not inspect the package manifest'"
|
|
571
|
+
done
|
|
572
|
+
unset _shape; rm -rf "$MANI"
|
|
573
|
+
|
|
574
|
+
OTHER_DIR="$SB/old-global/bin"; mkdir -p "$OTHER_DIR"
|
|
575
|
+
printf '#!/bin/sh\nexec /old/global/entwurf "$@"\n' > "$OTHER_DIR/entwurf"; chmod +x "$OTHER_DIR/entwurf"
|
|
576
|
+
set +e; OUT="$(PATH="$DBIN_DIR:$OTHER_DIR:$PATH" bash "$REPO_DIR/run.sh" expose-dev-bin 2>&1)"; RC=$?; set -e
|
|
577
|
+
want "source setup's bins step fails when another root is still selectable [QK:SOURCE-EXCLUSIVE-WIRED]" \
|
|
578
|
+
"[ '$RC' -eq 5 ] && printf '%s' \"\$OUT\" | grep -qF 'another entwurf root is still selectable: $OTHER_DIR/entwurf'"
|
|
579
|
+
rm -rf "$SB/old-global" "$SB/other-checkout" "$TOOLS_ONLY"
|
|
580
|
+
bash "$DEVBIN" remove >/dev/null 2>&1 # the helper links expose-dev-bin just made
|
|
581
|
+
bash "$DEVBIN" remove entwurf >/dev/null 2>&1 # by NAME, like the expose above: the
|
|
582
|
+
bash "$DEVBIN" remove entwurf-bridge >/dev/null 2>&1 # managed list itself may be under test
|
|
583
|
+
|
|
464
584
|
# J-0: the setup wrapper calls no-arg expose. This is the cross-contract cell the #82 regression
|
|
465
585
|
# lacked: an npm consumer gets `entwurf` from package bin linking, and source setup must expose the
|
|
466
586
|
# same operator command without a second global package install.
|
|
@@ -578,6 +698,7 @@ ok "dev-bin migrate: foreign legacy refused (linkPath basename != entwurf-bridge
|
|
|
578
698
|
rm -f "$LEGACY" "$DLINK" "$DSTATE"
|
|
579
699
|
bash "$DEVBIN" remove >/dev/null 2>&1
|
|
580
700
|
unset ENTWURF_DEV_BIN_DIR ENTWURF_OPERATOR_TARGET ENTWURF_BRIDGE_TARGET ENTWURF_AGY_STATUSLINE_TARGET
|
|
701
|
+
export PATH="$DEVBIN_ORIG_PATH"
|
|
581
702
|
unset ENTWURF_AGY_IMPRINT_TARGET ENTWURF_COPILOT_STATUSLINE_TARGET
|
|
582
703
|
|
|
583
704
|
# ── K: permission grant — the OTHER half of a usable bridge ───────────────────
|
|
@@ -48,6 +48,7 @@ import * as os from "node:os";
|
|
|
48
48
|
import * as path from "node:path";
|
|
49
49
|
import { fileURLToPath } from "node:url";
|
|
50
50
|
import type { SenderEnvelope } from "../pi-extensions/lib/entwurf-control-rpc.ts";
|
|
51
|
+
import { nativePushPaused } from "../pi-extensions/lib/entwurf-v2-contract.ts";
|
|
51
52
|
import { makeProductionEntwurfV2Deps } from "../pi-extensions/lib/entwurf-v2-production.ts";
|
|
52
53
|
import type { EntwurfV2RunResult } from "../pi-extensions/lib/entwurf-v2-runner.ts";
|
|
53
54
|
import { runEntwurfV2 } from "../pi-extensions/lib/entwurf-v2-runner.ts";
|
|
@@ -79,6 +80,18 @@ function smokeSender(gardenId: string, cwd: string): SenderEnvelope {
|
|
|
79
80
|
}
|
|
80
81
|
|
|
81
82
|
async function main(): Promise<void> {
|
|
83
|
+
// #152: agy native-push is PAUSED by product policy, so this positive LIVE acceptance cannot
|
|
84
|
+
// run — every cell below would drive the paused rail. It exits NON-ZERO by name (neither a PASS
|
|
85
|
+
// nor the protocol SKIP), and touches no agy process, port or conversation. The pause itself is
|
|
86
|
+
// proven deterministically beside the behavior (pi-extensions/lib/native-push/paused.test.ts).
|
|
87
|
+
if (nativePushPaused("antigravity")) {
|
|
88
|
+
console.error(
|
|
89
|
+
"[entwurf:paused] smoke-agy-native-push-live — agy native-push is paused (#152: its language " +
|
|
90
|
+
"server refused entwurf's measured external calls for a missing CSRF token). This LIVE acceptance does not run while " +
|
|
91
|
+
"the pause holds; it is not a PASS.",
|
|
92
|
+
);
|
|
93
|
+
process.exit(2);
|
|
94
|
+
}
|
|
82
95
|
if (process.env.LIVE !== "1") {
|
|
83
96
|
skipLive(
|
|
84
97
|
"smoke-agy-native-push-live",
|
|
@@ -75,12 +75,14 @@ import {
|
|
|
75
75
|
} from "../pi-extensions/lib/native-push/codex-ws-client.ts";
|
|
76
76
|
import {
|
|
77
77
|
buildCodexInstruction,
|
|
78
|
+
buildInitialPiBootstrapTask,
|
|
78
79
|
buildInitialPiPhaseOne,
|
|
79
80
|
buildInitialPiRelay,
|
|
80
81
|
runCleanupStages,
|
|
81
82
|
selectReport,
|
|
82
83
|
} from "./lib/codex-fresh-live-protocol.ts";
|
|
83
84
|
import {
|
|
85
|
+
assertBootstrapOrder,
|
|
84
86
|
assertExactSourceToolCalls,
|
|
85
87
|
assertSourceCallScopes,
|
|
86
88
|
codexCallbackSenders,
|
|
@@ -978,11 +980,7 @@ async function run(): Promise<void> {
|
|
|
978
980
|
backend: "pi",
|
|
979
981
|
model: piModel,
|
|
980
982
|
cwd: scratch,
|
|
981
|
-
task:
|
|
982
|
-
"Session-info already supplies device and time. Do not recheck time, cwd, or identity with shell or other tools. " +
|
|
983
|
-
"Your FIRST tool call must be mcp__entwurf_bridge__entwurf_callback with no arguments, and nothing before it. " +
|
|
984
|
-
`After your required callback receipt, end the turn and wait passively for one addressed message containing ${initialPiWaitToken}. ` +
|
|
985
|
-
"That message is the only authority to open the Codex sibling. Do not call shell, sleep, terminal, or any tool to wait.",
|
|
983
|
+
task: buildInitialPiBootstrapTask(initialPiWaitToken),
|
|
986
984
|
});
|
|
987
985
|
receipts["2-initial-pi-launch"] = initialPiLaunch.text;
|
|
988
986
|
ok(
|
|
@@ -1440,25 +1438,33 @@ async function run(): Promise<void> {
|
|
|
1440
1438
|
const observed = await readCodexThread(codexSocketPath, codexThreadId, true);
|
|
1441
1439
|
return codexThreadIsTerminal(observed) ? observed : null;
|
|
1442
1440
|
});
|
|
1441
|
+
// THE BOOTSTRAP ORDER, THEN THE ROLES — two leaves, composed. `[GLG 직접, 2026-10-24]` a fresh
|
|
1442
|
+
// sibling may check its caller with the read-only listing the framing offers, then calls back,
|
|
1443
|
+
// then works. `assertBootstrapOrder` admits only that prefix (successful exact `entwurf_peers`
|
|
1444
|
+
// checks), requires the exact callback once and successfully, and hands the rest to the
|
|
1445
|
+
// unchanged exact-once role audit — so `bash true` before the callback (the r3 RED) is still
|
|
1446
|
+
// refused, by the order leaf now rather than by a count. On Pi the receipts carry transcript
|
|
1447
|
+
// ordinals, so this also proves every peers RESULT was recorded before the callback was called,
|
|
1448
|
+
// and the callback RESULT before every task call.
|
|
1449
|
+
//
|
|
1450
|
+
// The callback is the ZERO-ARGUMENT eighth verb and `{}` is compared byte-exactly: a target, a
|
|
1451
|
+
// message or a `wants_reply` typed here is a parameter the verb does not have. Nothing is
|
|
1452
|
+
// weakened by the nonce not being in THIS expectation: the correlation is proven earlier and from
|
|
1453
|
+
// the delivered body — `the initial Pi callback carries the exact launch nonce` reads the
|
|
1454
|
+
// fixture's own mailbox, requires exactly one exact match and refuses duplicates, and the two
|
|
1455
|
+
// cells beside it bind that callback's sender envelope to a real pi V3 citizen.
|
|
1456
|
+
const initialPiSources = piSourceToolReceipts(readInitialPiEntries());
|
|
1457
|
+
const initialPiTaskCalls = assertBootstrapOrder(
|
|
1458
|
+
initialPiSources,
|
|
1459
|
+
// The guided task asked this Pi to take the offered check, so a zero-check PASS is not positive evidence.
|
|
1460
|
+
{ peersArguments: {}, callback: { toolName: "entwurf_callback", arguments: {} }, minPeersPrefix: 1 },
|
|
1461
|
+
"initial Pi bootstrap order",
|
|
1462
|
+
);
|
|
1463
|
+
// The verified prefix count: the order leaf admitted exactly these many leading peers checks.
|
|
1464
|
+
const piPeersPrefix = initialPiSources.length - initialPiTaskCalls.length - 1;
|
|
1443
1465
|
assertExactSourceToolCalls(
|
|
1444
|
-
|
|
1466
|
+
initialPiTaskCalls,
|
|
1445
1467
|
[
|
|
1446
|
-
// 0.24.0 moved a pi sibling's first action to the ZERO-ARGUMENT eighth verb, and this
|
|
1447
|
-
// smoke's own launch receipt says so in the same run: "its first action is the
|
|
1448
|
-
// zero-argument callback verb (codex is the one arm that still sends the nonce as
|
|
1449
|
-
// arguments)". The Codex audit below therefore keeps its `entwurf_v2` shape, and only
|
|
1450
|
-
// this one moves. `{}` is matched by deep-strict equality, so it pins the verb's actual
|
|
1451
|
-
// contract — a target or message typed here would be a second address axis and the verb
|
|
1452
|
-
// refuses it by name.
|
|
1453
|
-
//
|
|
1454
|
-
// Nothing is weakened by dropping the nonce from THIS expectation: the correlation is
|
|
1455
|
-
// proven earlier and from the delivered body, which is where a nonce can actually be
|
|
1456
|
-
// corrupted — `the initial Pi callback carries the exact launch nonce` (:970-973) reads
|
|
1457
|
-
// the fixture's own mailbox, requires exactly one exact match and refuses duplicates,
|
|
1458
|
-
// and the two cells beside it bind that callback's sender envelope to a real pi V3
|
|
1459
|
-
// citizen. This audit's job is the different one its name says: exactly these calls,
|
|
1460
|
-
// once each, and nothing else.
|
|
1461
|
-
{ toolName: "entwurf_callback", arguments: {} },
|
|
1462
1468
|
{
|
|
1463
1469
|
toolName: "entwurf_fresh_call",
|
|
1464
1470
|
arguments: {
|
|
@@ -1480,10 +1486,18 @@ async function run(): Promise<void> {
|
|
|
1480
1486
|
],
|
|
1481
1487
|
"initial Pi final exact-once audit",
|
|
1482
1488
|
);
|
|
1483
|
-
|
|
1484
|
-
|
|
1485
|
-
|
|
1486
|
-
|
|
1489
|
+
// Codex: the same composition over the Entwurf MCP calls `thread/read` reports (this smoke's
|
|
1490
|
+
// Codex scope — no vendor-native action taxonomy). Its callback is `entwurf_v2` to the initial Pi
|
|
1491
|
+
// with the nonce, so `wants_reply` keeps its schema default there. `thread/read` gives item order
|
|
1492
|
+
// and a status at audit time only: on Codex this proves CALL ORDER and completion-at-audit; that a
|
|
1493
|
+
// peers result preceded the callback call, and that the callback result preceded the next call,
|
|
1494
|
+
// are both UNVERIFIED.
|
|
1495
|
+
const codexFinalSources = codexSourceToolReceipts(codexThread);
|
|
1496
|
+
const codexTaskCalls = assertBootstrapOrder(
|
|
1497
|
+
codexFinalSources,
|
|
1498
|
+
{
|
|
1499
|
+
peersArguments: {},
|
|
1500
|
+
callback: {
|
|
1487
1501
|
toolName: "entwurf_v2",
|
|
1488
1502
|
arguments: {
|
|
1489
1503
|
target: initialPiGid,
|
|
@@ -1492,6 +1506,13 @@ async function run(): Promise<void> {
|
|
|
1492
1506
|
message: codexNonce,
|
|
1493
1507
|
},
|
|
1494
1508
|
},
|
|
1509
|
+
},
|
|
1510
|
+
"Codex bootstrap order",
|
|
1511
|
+
);
|
|
1512
|
+
const codexPeersPrefix = codexFinalSources.length - codexTaskCalls.length - 1;
|
|
1513
|
+
assertExactSourceToolCalls(
|
|
1514
|
+
codexTaskCalls,
|
|
1515
|
+
[
|
|
1495
1516
|
{
|
|
1496
1517
|
toolName: "entwurf_fresh_call",
|
|
1497
1518
|
arguments: { backend: "pi", model: piModel, task: outboundPiTask },
|
|
@@ -1508,7 +1529,9 @@ async function run(): Promise<void> {
|
|
|
1508
1529
|
],
|
|
1509
1530
|
"Codex final exact-once audit",
|
|
1510
1531
|
);
|
|
1511
|
-
receipts["16-source-final-audit"] =
|
|
1532
|
+
receipts["16-source-final-audit"] =
|
|
1533
|
+
`initial-pi=bootstrap order (peers prefix=${piPeersPrefix} → callback, results-before-next-call by transcript ordinal) + 2/2 task roles exact\n` +
|
|
1534
|
+
`codex=bootstrap order (peers prefix=${codexPeersPrefix} → callback, call order only) + 2/2 task roles exact`;
|
|
1512
1535
|
}
|
|
1513
1536
|
|
|
1514
1537
|
let failure: unknown = null;
|
|
@@ -64,6 +64,7 @@ import {
|
|
|
64
64
|
writeMetaSenderMarker,
|
|
65
65
|
} from "../pi-extensions/lib/meta-session.ts";
|
|
66
66
|
import { terminateChild } from "./lib/acp-child-cleanup.ts";
|
|
67
|
+
import { awaitTerminusPublication } from "./lib/chain-terminus-publication.ts";
|
|
67
68
|
import { skipLive } from "./lib/live-skip.ts";
|
|
68
69
|
|
|
69
70
|
const REPO_ROOT = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "..");
|
|
@@ -390,14 +391,11 @@ async function main(): Promise<void> {
|
|
|
390
391
|
|
|
391
392
|
// ── the chain runs on its own from here; wait for the terminus ───────────
|
|
392
393
|
const boxDir = path.join(mailboxDir, gidD);
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
);
|
|
399
|
-
if (msgs.length > 0) break;
|
|
400
|
-
await sleep(POLL_MS);
|
|
394
|
+
// Body AND doorbell, inside the same deadline: enqueue publishes `.msg` first and
|
|
395
|
+
// `inbox.signal` last, so a body alone is a publication still in flight (P5 2026-10-24).
|
|
396
|
+
const { msgs, signalled } = await awaitTerminusPublication(boxDir, Date.now() + CHAIN_TIMEOUT_MS, POLL_MS);
|
|
397
|
+
if (msgs.length > 0 && !signalled) {
|
|
398
|
+
console.error(`[smoke-entwurf-chain-live] terminus at timeout: ${msgs.length} body file(s) but no inbox.signal`);
|
|
401
399
|
}
|
|
402
400
|
if (msgs.length === 0) {
|
|
403
401
|
let ownerAlive = false;
|
|
@@ -423,7 +421,7 @@ async function main(): Promise<void> {
|
|
|
423
421
|
console.error(`[smoke-entwurf-chain-live] C stream tail:\n${streamC.slice(-2000)}`);
|
|
424
422
|
}
|
|
425
423
|
ok(`the chain reached the mailbox terminus (${msgs.length} .msg)`, msgs.length === 1);
|
|
426
|
-
ok("the terminus doorbell was poked",
|
|
424
|
+
ok("the terminus doorbell was poked", signalled);
|
|
427
425
|
|
|
428
426
|
const body = await fsp.readFile(path.join(boxDir, msgs[0] as string), "utf8");
|
|
429
427
|
|
|
@@ -45,7 +45,7 @@
|
|
|
45
45
|
* fenced `XDG_CACHE_HOME`, joined to a session by its EXACT `sessionId` — plus
|
|
46
46
|
* entwurf's own mailbox artifact and hook journal. It proves the public call, the
|
|
47
47
|
* identity join, the delivered callback, the caller's continuation, the child's
|
|
48
|
-
*
|
|
48
|
+
* callback before any work (a read-only check may precede it), and the codex named reject. It does NOT prove the receipt text or
|
|
49
49
|
* the final answer content: those have no source artifact on this axis and are
|
|
50
50
|
* left to GLG's manual validation rather than substituted with a screen read.
|
|
51
51
|
*
|
|
@@ -853,7 +853,7 @@ async function main(): Promise<void> {
|
|
|
853
853
|
);
|
|
854
854
|
}
|
|
855
855
|
|
|
856
|
-
// ── the child
|
|
856
|
+
// ── the child called back before its work ───────────────────────────────────
|
|
857
857
|
const childNative = String(joined?.nativeSessionId ?? childRow?.sessionValue ?? "");
|
|
858
858
|
if (cell.childKind === "pi") {
|
|
859
859
|
const childRecords = transcriptRecords(String(childRow?.sessionValue ?? ""));
|
|
@@ -901,8 +901,8 @@ async function main(): Promise<void> {
|
|
|
901
901
|
// BOTH. `[측정 2026-09-17, oracle, LIVE]` this cell used to require `order[0] ===
|
|
902
902
|
// "entwurf_v2"`, and a Sonnet 5 child failed it by calling `entwurf_peers` first and
|
|
903
903
|
// the callback second. That is not a violation: the framing this rail now sends
|
|
904
|
-
// OFFERS exactly that corroboration ("you
|
|
905
|
-
//
|
|
904
|
+
// OFFERS exactly that corroboration ("you may corroborate the caller before that
|
|
905
|
+
// call"), so the old oracle contradicted our own prompt and would have forbidden
|
|
906
906
|
// the behaviour we asked for. What still must hold is everything the claim was
|
|
907
907
|
// actually about — the callback lands before any work, it completes, and neither the
|
|
908
908
|
// callback verb nor the delivery verb failed or timed out anywhere in the log.
|