@junghanacs/entwurf 0.34.1 → 0.35.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +217 -0
- package/CONTRIBUTING.md +1 -1
- package/README.md +11 -7
- package/VERIFY.md +11 -1
- package/demo/README.md +109 -175
- package/demo/demo-baseline.sh +5 -1
- package/demo/demo.sh +6 -2
- package/demo/herdr-pi-cc-20261011.provenance.json +64 -0
- package/docs/assets/entwurf-demo.gif +0 -0
- package/docs/setup-clean-host.md +2 -2
- package/package.json +4 -2
- package/run.sh +39 -0
- package/scripts/check-gate-qualification.ts +3 -2
- package/scripts/check-herdr-activation.ts +80 -0
- package/scripts/check-meta-doctor-oracle.sh +86 -1
- package/scripts/check-release-gate-outcomes.ts +159 -1
- package/scripts/ci-qualify-decide.sh +114 -17
- package/scripts/herdr-activation.mjs +50 -1
- package/scripts/herdr-doctor-mode.mjs +26 -0
- package/scripts/meta-bridge-doctor.sh +79 -20
- package/scripts/mutants/demo-reproducibility.json +155 -0
- package/scripts/mutants/herdr-activation.json +71 -0
- package/scripts/mutants/release-gate.json +28 -2
- package/scripts/tsconfig.json +1 -0
|
@@ -17,6 +17,18 @@ MKT_NAME="meta-bridge-local"
|
|
|
17
17
|
PLUGIN="entwurf-meta-receive"
|
|
18
18
|
CLAUDE_CFG="${CLAUDE_CONFIG_DIR:-$HOME/.claude}"
|
|
19
19
|
REPO="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
|
20
|
+
# #136: the one argument. A Herdr plugin activation wires Claude with ABSOLUTE commands under the
|
|
21
|
+
# stable runtime; the mode is normally derived from the activation ledger (see [expectation mode]),
|
|
22
|
+
# and this override exists so a checkout's doctor can name that root. It must agree with the ledger.
|
|
23
|
+
PLUGIN_RUNTIME_OVERRIDE=""
|
|
24
|
+
while [ $# -gt 0 ]; do
|
|
25
|
+
case "$1" in
|
|
26
|
+
--plugin-runtime)
|
|
27
|
+
[ -n "${2:-}" ] || { echo "meta-bridge-doctor: --plugin-runtime requires a value" >&2; exit 2; }
|
|
28
|
+
PLUGIN_RUNTIME_OVERRIDE="$2"; shift 2 ;;
|
|
29
|
+
*) echo "usage: meta-bridge-doctor.sh [--plugin-runtime <stable active runtime root>]" >&2; exit 2 ;;
|
|
30
|
+
esac
|
|
31
|
+
done
|
|
20
32
|
# The live artifact lives under the XDG data dir (dev clone and installed package
|
|
21
33
|
# alike — never the checkout). Prefer the path RECORDED in install-state so a doctor
|
|
22
34
|
# run under a different XDG_DATA_HOME than install still hashes the REAL assembled
|
|
@@ -110,6 +122,44 @@ if command -v node >/dev/null; then
|
|
|
110
122
|
if [ "${MJ:-0}" -ge 24 ]; then ok "node $NV (>= 24, supported axis)"; else bad "node $NV too old (need >= 24; there is no Node 22 lane)"; fi
|
|
111
123
|
else bad "node not on PATH"; fi
|
|
112
124
|
|
|
125
|
+
echo "[expectation mode]"
|
|
126
|
+
# #136: which expectations the three desired-state calls below compute. The judgement is the
|
|
127
|
+
# activation owner's (`resolveDoctorPluginRuntime`, herdr-activation.mjs) reached through one narrow
|
|
128
|
+
# call, so no second reader of the ledger exists. A refusal is NOT a fallback to bare expectations:
|
|
129
|
+
# each call site then reports UNKNOWN, and every other section still runs (Hard Rule 13).
|
|
130
|
+
PLUGIN_ARGS=()
|
|
131
|
+
MODE_ERR=""
|
|
132
|
+
if ! command -v node >/dev/null; then
|
|
133
|
+
MODE_ERR="node not on PATH, so the activation ledger could not be read"
|
|
134
|
+
bad "expectation mode is UNKNOWN: $MODE_ERR"
|
|
135
|
+
else
|
|
136
|
+
MODE_STDERR="$(mktemp -t entwurf-doctor-mode.XXXXXX)"
|
|
137
|
+
set +e
|
|
138
|
+
if [ -n "$PLUGIN_RUNTIME_OVERRIDE" ]; then
|
|
139
|
+
MODE_ROOT="$(node "$REPO/scripts/herdr-doctor-mode.mjs" "$REPO" "$PLUGIN_RUNTIME_OVERRIDE" 2>"$MODE_STDERR")"
|
|
140
|
+
else
|
|
141
|
+
MODE_ROOT="$(node "$REPO/scripts/herdr-doctor-mode.mjs" "$REPO" 2>"$MODE_STDERR")"
|
|
142
|
+
fi
|
|
143
|
+
MODE_RC=$?
|
|
144
|
+
set -e
|
|
145
|
+
MODE_DETAIL="$(tr '\n' ' ' < "$MODE_STDERR" | cut -c1-400)"
|
|
146
|
+
rm -f "$MODE_STDERR"
|
|
147
|
+
if [ "$MODE_RC" -eq 3 ]; then
|
|
148
|
+
MODE_ERR="$MODE_DETAIL"
|
|
149
|
+
bad "expectation mode refused: $MODE_ERR"
|
|
150
|
+
elif [ "$MODE_RC" -ne 0 ]; then
|
|
151
|
+
MODE_ERR="herdr-doctor-mode.mjs exited $MODE_RC: $MODE_DETAIL"
|
|
152
|
+
bad "expectation mode is UNKNOWN: $MODE_ERR"
|
|
153
|
+
elif [ -n "$MODE_ROOT" ]; then
|
|
154
|
+
PLUGIN_ARGS=(--plugin-runtime "$MODE_ROOT")
|
|
155
|
+
ok "mode: plugin-runtime $MODE_ROOT (activation ledger)"
|
|
156
|
+
elif [ "$LIB_EXT" = "js" ]; then
|
|
157
|
+
ok "mode: installed (no activation ledger, or this package is not the plugin runtime)"
|
|
158
|
+
else
|
|
159
|
+
ok "mode: clone (this checkout is not the plugin runtime)"
|
|
160
|
+
fi
|
|
161
|
+
fi
|
|
162
|
+
|
|
113
163
|
echo "[managed config state]"
|
|
114
164
|
if command -v python3 >/dev/null; then
|
|
115
165
|
# state.py check is the effect-based keyset-survival guard: it asserts every
|
|
@@ -123,7 +173,9 @@ if command -v python3 >/dev/null; then
|
|
|
123
173
|
# which key drifted — silent instead of fail-loud. As an `if` condition the
|
|
124
174
|
# substitution's nonzero status is consumed (set -e suspended), so we always
|
|
125
175
|
# reach the detail. stderr (drift detail) is captured via `2>&1 >/dev/null`.
|
|
126
|
-
if
|
|
176
|
+
if [ -n "$MODE_ERR" ]; then
|
|
177
|
+
bad "managed settings/MCP keyset is UNKNOWN: the expectation mode was not established ($MODE_ERR)"
|
|
178
|
+
elif CHECK_ERR="$(python3 "$REPO/scripts/meta-bridge-state.py" check --repo "$REPO" --asm "$ASM" ${PLUGIN_ARGS[@]+"${PLUGIN_ARGS[@]}"} 2>&1 >/dev/null)"; then
|
|
127
179
|
ok "state file present and managed settings/MCP keyset survives intact"
|
|
128
180
|
else
|
|
129
181
|
bad "managed settings/MCP keyset missing or overwritten — another consumer may have clobbered a pi-owned key. Re-run ./run.sh install-meta-bridge. Drift detail:"
|
|
@@ -565,25 +617,29 @@ except Exception:
|
|
|
565
617
|
print('')
|
|
566
618
|
PY
|
|
567
619
|
)"
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
if [[ "$EXPECTED_STATUSLINE" == */* ]]; then
|
|
571
|
-
if [ -x "$EXPECTED_STATUSLINE" ]; then ok "statusline executable"; else bad "statusline script not executable: $EXPECTED_STATUSLINE"; fi
|
|
572
|
-
elif command -v "$EXPECTED_STATUSLINE" >/dev/null 2>&1; then
|
|
573
|
-
ok "statusline bin resolves on PATH: $(command -v "$EXPECTED_STATUSLINE")"
|
|
620
|
+
if [ -n "$MODE_ERR" ]; then
|
|
621
|
+
bad "statusLine expectation is UNKNOWN: the expectation mode was not established ($MODE_ERR)"
|
|
574
622
|
else
|
|
575
|
-
|
|
623
|
+
EXPECTED_STATUSLINE="$(python3 "$REPO/scripts/meta-bridge-state.py" desired-statusline --repo "$REPO" ${PLUGIN_ARGS[@]+"${PLUGIN_ARGS[@]}"} | python3 -c 'import json,sys; print(json.load(sys.stdin).get("command", ""))')"
|
|
624
|
+
if [ "$STATUSLINE_CMD" = "$EXPECTED_STATUSLINE" ]; then ok "statusLine.command matches expected (dev: checkout path; installed: entwurf-statusline bin shim): $STATUSLINE_CMD"; else bad "statusLine.command drifted (got '$STATUSLINE_CMD', expected '$EXPECTED_STATUSLINE')"; fi
|
|
625
|
+
if [[ "$EXPECTED_STATUSLINE" == */* ]]; then
|
|
626
|
+
if [ -x "$EXPECTED_STATUSLINE" ]; then ok "statusline executable"; else bad "statusline script not executable: $EXPECTED_STATUSLINE"; fi
|
|
627
|
+
elif command -v "$EXPECTED_STATUSLINE" >/dev/null 2>&1; then
|
|
628
|
+
ok "statusline bin resolves on PATH: $(command -v "$EXPECTED_STATUSLINE")"
|
|
629
|
+
else
|
|
630
|
+
bad "statusline bin not on PATH: $EXPECTED_STATUSLINE"
|
|
631
|
+
fi
|
|
632
|
+
SAMPLE_STATUSLINE_OUT="$(printf '%s' '{"session_id":"doctor-no-record","workspace":{"current_dir":"/tmp"},"model":{"id":"claude-sonnet-5"},"context_window":{"context_window_size":200000,"used_percentage":1,"current_usage":{"input_tokens":1}}}' | "$EXPECTED_STATUSLINE" 2>/dev/null || true)"
|
|
633
|
+
# The identity row may carry the #98 B unread badge between `cc` and the model letter:
|
|
634
|
+
# ` ✉N` when mail is waiting, nothing when the mailbox is empty, ` ✉?` when the count
|
|
635
|
+
# could not be taken. All three are healthy renders, so the shape test admits any of them.
|
|
636
|
+
if [ "$(printf '%s\n' "$SAMPLE_STATUSLINE_OUT" | wc -l | tr -d ' ')" = "2" ] && printf '%s\n' "$SAMPLE_STATUSLINE_OUT" | sed -n '1p' | grep -q 'tmp' && printf '%s\n' "$SAMPLE_STATUSLINE_OUT" | sed -n '2p' | grep -q '🪛' && printf '%s\n' "$SAMPLE_STATUSLINE_OUT" | sed -n '2p' | grep -qE ' cc( ✉([0-9]+|\?))? \| s'; then ok "statusline synthetic execution emits two rows (work context + identity)"; else bad "statusline synthetic execution failed or omitted two-row work/identity marker"; fi
|
|
637
|
+
# The synthetic feeds a session_id with no meta-record, so the garden id does not
|
|
638
|
+
# resolve and there is no mailbox to count. `✉?` is the required answer: a statusline
|
|
639
|
+
# that drew nothing there would be claiming "no mail" about a mailbox it never opened —
|
|
640
|
+
# the exact silence #98 was opened to remove.
|
|
641
|
+
if printf '%s\n' "$SAMPLE_STATUSLINE_OUT" | sed -n '2p' | grep -q '✉?'; then ok "statusline badge distinguishes 'could not count' (✉?) from zero on the no-record synthetic"; else bad "statusline badge omitted ✉? for the no-record synthetic (a false zero would be indistinguishable from an empty mailbox)"; fi
|
|
576
642
|
fi
|
|
577
|
-
SAMPLE_STATUSLINE_OUT="$(printf '%s' '{"session_id":"doctor-no-record","workspace":{"current_dir":"/tmp"},"model":{"id":"claude-sonnet-5"},"context_window":{"context_window_size":200000,"used_percentage":1,"current_usage":{"input_tokens":1}}}' | "$EXPECTED_STATUSLINE" 2>/dev/null || true)"
|
|
578
|
-
# The identity row may carry the #98 B unread badge between `cc` and the model letter:
|
|
579
|
-
# ` ✉N` when mail is waiting, nothing when the mailbox is empty, ` ✉?` when the count
|
|
580
|
-
# could not be taken. All three are healthy renders, so the shape test admits any of them.
|
|
581
|
-
if [ "$(printf '%s\n' "$SAMPLE_STATUSLINE_OUT" | wc -l | tr -d ' ')" = "2" ] && printf '%s\n' "$SAMPLE_STATUSLINE_OUT" | sed -n '1p' | grep -q 'tmp' && printf '%s\n' "$SAMPLE_STATUSLINE_OUT" | sed -n '2p' | grep -q '🪛' && printf '%s\n' "$SAMPLE_STATUSLINE_OUT" | sed -n '2p' | grep -qE ' cc( ✉([0-9]+|\?))? \| s'; then ok "statusline synthetic execution emits two rows (work context + identity)"; else bad "statusline synthetic execution failed or omitted two-row work/identity marker"; fi
|
|
582
|
-
# The synthetic feeds a session_id with no meta-record, so the garden id does not
|
|
583
|
-
# resolve and there is no mailbox to count. `✉?` is the required answer: a statusline
|
|
584
|
-
# that drew nothing there would be claiming "no mail" about a mailbox it never opened —
|
|
585
|
-
# the exact silence #98 was opened to remove.
|
|
586
|
-
if printf '%s\n' "$SAMPLE_STATUSLINE_OUT" | sed -n '2p' | grep -q '✉?'; then ok "statusline badge distinguishes 'could not count' (✉?) from zero on the no-record synthetic"; else bad "statusline badge omitted ✉? for the no-record synthetic (a false zero would be indistinguishable from an empty mailbox)"; fi
|
|
587
643
|
else
|
|
588
644
|
bad "cannot validate statusline without python3"
|
|
589
645
|
fi
|
|
@@ -669,9 +725,12 @@ PY
|
|
|
669
725
|
[ -n "$LIVE_MCP_DESC" ] || LIVE_MCP_DESC="(unprintable live command)"
|
|
670
726
|
# Ownership axis. `|| true` on the pipeline only: a state.py failure must read as
|
|
671
727
|
# UNKNOWN-and-loud below, never abort the doctor before the delivery drive.
|
|
672
|
-
DESIRED_MCP="
|
|
728
|
+
DESIRED_MCP=""
|
|
729
|
+
[ -n "$MODE_ERR" ] || DESIRED_MCP="$( { python3 "$REPO/scripts/meta-bridge-state.py" desired-mcp --repo "$REPO" ${PLUGIN_ARGS[@]+"${PLUGIN_ARGS[@]}"} \
|
|
673
730
|
| python3 -c 'import json,sys; print(json.dumps(json.load(sys.stdin), sort_keys=True))'; } 2>/dev/null || true)"
|
|
674
|
-
if [ -
|
|
731
|
+
if [ -n "$MODE_ERR" ]; then
|
|
732
|
+
bad "live-vs-desired MCP ownership is UNKNOWN: the expectation mode was not established ($MODE_ERR)"
|
|
733
|
+
elif [ -z "$DESIRED_MCP" ]; then
|
|
675
734
|
bad "could not compute the desired MCP entry (meta-bridge-state.py desired-mcp failed) — live-vs-desired ownership is UNKNOWN"
|
|
676
735
|
elif [ "$LIVE_MCP" = "$DESIRED_MCP" ]; then
|
|
677
736
|
ok "live mcpServers.entwurf-bridge equals desired_mcp() for this mode (installed: bin shim; clone: this checkout's start.sh)"
|
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
{
|
|
2
|
+
"schemaVersion": 1,
|
|
3
|
+
"lane": "demo-reproducibility",
|
|
4
|
+
"mutants": [
|
|
5
|
+
{
|
|
6
|
+
"claim": "DEMO-BASELINE-ARCHIVED",
|
|
7
|
+
"title": "the archived baseline resumes launching the retired scene and can overwrite the approved GIF",
|
|
8
|
+
"subject": "demo/demo-baseline.sh",
|
|
9
|
+
"find": ["exit 2"],
|
|
10
|
+
"replace": [":"],
|
|
11
|
+
"gate": ["bash", "run.sh", "check-demo-reproducibility"],
|
|
12
|
+
"timeoutSeconds": 120,
|
|
13
|
+
"signature": "[QK:DEMO-BASELINE-ARCHIVED]",
|
|
14
|
+
"signatureSource": "demo/maintenance-guards.test.ts"
|
|
15
|
+
},
|
|
16
|
+
{
|
|
17
|
+
"claim": "DEMO-PEER-ARCHIVED",
|
|
18
|
+
"title": "the archived peer scene becomes a second runnable v1 route again",
|
|
19
|
+
"subject": "demo/demo.sh",
|
|
20
|
+
"find": ["exit 2"],
|
|
21
|
+
"replace": [":"],
|
|
22
|
+
"gate": ["bash", "run.sh", "check-demo-reproducibility"],
|
|
23
|
+
"timeoutSeconds": 120,
|
|
24
|
+
"signature": "[QK:DEMO-PEER-ARCHIVED]",
|
|
25
|
+
"signatureSource": "demo/maintenance-guards.test.ts"
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
"claim": "DEMO-LIVE-OPT-IN",
|
|
29
|
+
"title": "the Herdr scene reaches preflight without the explicit LIVE grant",
|
|
30
|
+
"subject": "demo/take-herdr-pi-cc.ts",
|
|
31
|
+
"find": ["if (process.env.LIVE !== \"1\")"],
|
|
32
|
+
"replace": ["if (false)"],
|
|
33
|
+
"gate": ["bash", "run.sh", "check-demo-reproducibility"],
|
|
34
|
+
"timeoutSeconds": 120,
|
|
35
|
+
"signature": "[QK:DEMO-LIVE-OPT-IN]",
|
|
36
|
+
"signatureSource": "demo/maintenance-guards.test.ts"
|
|
37
|
+
},
|
|
38
|
+
{
|
|
39
|
+
"claim": "DEMO-PUBLISHED-PROVENANCE",
|
|
40
|
+
"title": "the tracked provenance names another GIF digest while the approved pixels stay unchanged",
|
|
41
|
+
"subject": "demo/herdr-pi-cc-20261011.provenance.json",
|
|
42
|
+
"find": ["\t\t\"sha256\": \"b686739b5c68fa458dd47c844711aea0f6ab5819eb3eb5d2850449922fa084c0\","],
|
|
43
|
+
"replace": ["\t\t\"sha256\": \"0000000000000000000000000000000000000000000000000000000000000000\","],
|
|
44
|
+
"gate": ["bash", "run.sh", "check-demo-reproducibility"],
|
|
45
|
+
"timeoutSeconds": 120,
|
|
46
|
+
"signature": "[QK:DEMO-PUBLISHED-PROVENANCE]",
|
|
47
|
+
"signatureSource": "demo/maintenance-guards.test.ts"
|
|
48
|
+
},
|
|
49
|
+
{
|
|
50
|
+
"claim": "DEMO-PACK-SOURCE-ONLY",
|
|
51
|
+
"title": "a directory allowlist ships maintainer TypeScript as if it were an installed entrypoint",
|
|
52
|
+
"subject": "package.json",
|
|
53
|
+
"find": [
|
|
54
|
+
"\t\t\"demo/README.md\",",
|
|
55
|
+
"\t\t\"demo/herdr-pi-cc-20261011.provenance.json\",",
|
|
56
|
+
"\t\t\"!demo/**/*.ts\","
|
|
57
|
+
],
|
|
58
|
+
"replace": ["\t\t\"demo/\","],
|
|
59
|
+
"gate": ["bash", "run.sh", "check-demo-reproducibility"],
|
|
60
|
+
"timeoutSeconds": 120,
|
|
61
|
+
"signature": "[QK:DEMO-PACK-SOURCE-ONLY]",
|
|
62
|
+
"signatureSource": "demo/maintenance-guards.test.ts"
|
|
63
|
+
},
|
|
64
|
+
{
|
|
65
|
+
"claim": "DEMO-PUBLICATION-DESTINATION",
|
|
66
|
+
"title": "a live-pass renderer can overwrite publication assets through a direct or aliased destination",
|
|
67
|
+
"subject": "demo/render-take.ts",
|
|
68
|
+
"find": ["\tif (isPublicationOutput(out))"],
|
|
69
|
+
"replace": ["\tif (false)"],
|
|
70
|
+
"gate": ["bash", "run.sh", "check-demo-reproducibility"],
|
|
71
|
+
"timeoutSeconds": 120,
|
|
72
|
+
"signature": "[QK:DEMO-PUBLICATION-DESTINATION]",
|
|
73
|
+
"signatureSource": "demo/maintenance-guards.test.ts"
|
|
74
|
+
},
|
|
75
|
+
{
|
|
76
|
+
"claim": "DEMO-TMUX-SUBJECT-TAIL",
|
|
77
|
+
"title": "the tmux tail trimmer drops real subject text merged with the terminal teardown",
|
|
78
|
+
"subject": "demo/render-take.ts",
|
|
79
|
+
"find": ["\t\tisOnlyCsi(teardown[2])"],
|
|
80
|
+
"replace": ["\t\ttrue"],
|
|
81
|
+
"gate": ["bash", "run.sh", "check-demo-reproducibility"],
|
|
82
|
+
"timeoutSeconds": 120,
|
|
83
|
+
"signature": "[QK:DEMO-TMUX-SUBJECT-TAIL]",
|
|
84
|
+
"signatureSource": "demo/render-take.test.ts"
|
|
85
|
+
},
|
|
86
|
+
{
|
|
87
|
+
"claim": "DEMO-RECORDING-REQUIRED",
|
|
88
|
+
"title": "no recorder means no assertion, so an empty capture again certifies live-pass",
|
|
89
|
+
"subject": "demo/lib/take-recorder.ts",
|
|
90
|
+
"find": [
|
|
91
|
+
"\t\tthis.step(",
|
|
92
|
+
"\t\t\t\"the recording ran until the take ended and the recorder stopped cleanly (no cut, no signal, exit 0)\","
|
|
93
|
+
],
|
|
94
|
+
"replace": [
|
|
95
|
+
"\t\tif (recorder) this.step(",
|
|
96
|
+
"\t\t\t\"the recording ran until the take ended and the recorder stopped cleanly (no cut, no signal, exit 0)\","
|
|
97
|
+
],
|
|
98
|
+
"gate": ["bash", "run.sh", "check-demo-reproducibility"],
|
|
99
|
+
"timeoutSeconds": 120,
|
|
100
|
+
"signature": "[QK:DEMO-RECORDING-REQUIRED]",
|
|
101
|
+
"signatureSource": "demo/lib/take-recorder.test.ts"
|
|
102
|
+
},
|
|
103
|
+
{
|
|
104
|
+
"claim": "DEMO-TEST-DISCOVERY",
|
|
105
|
+
"title": "a dead discovery glob produces no tests but the demo floor is still invoked",
|
|
106
|
+
"subject": "run.sh",
|
|
107
|
+
"find": [
|
|
108
|
+
" while IFS= read -r f; do [ -n \"$f\" ] && tests+=(\"$f\"); done < <(cd \"$REPO_DIR\" && find demo -type f -name '*.test.ts' -print | LC_ALL=C sort)"
|
|
109
|
+
],
|
|
110
|
+
"replace": [
|
|
111
|
+
" while IFS= read -r f; do [ -n \"$f\" ] && tests+=(\"$f\"); done < <(cd \"$REPO_DIR\" && find demo -type f -name '*.test.NO-MATCH' -print | LC_ALL=C sort)"
|
|
112
|
+
],
|
|
113
|
+
"gate": ["bash", "run.sh", "check-demo-reproducibility"],
|
|
114
|
+
"timeoutSeconds": 120,
|
|
115
|
+
"signature": "[QK:DEMO-TEST-DISCOVERY]",
|
|
116
|
+
"signatureSource": "run.sh"
|
|
117
|
+
},
|
|
118
|
+
{
|
|
119
|
+
"claim": "DEMO-NO-EARLY-RESOURCES",
|
|
120
|
+
"title": "a Take allocated before missing-LIVE refusal writes resources without calling any fake tool",
|
|
121
|
+
"subject": "demo/take-pi-cc.ts",
|
|
122
|
+
"find": ["if (process.env.LIVE !== \"1\") {"],
|
|
123
|
+
"replace": [
|
|
124
|
+
"if (process.env.LIVE !== \"1\") {",
|
|
125
|
+
"\tnew Take({ label: LABEL, repo: REPO, cols: 132, rows: 38 });"
|
|
126
|
+
],
|
|
127
|
+
"gate": ["bash", "run.sh", "check-demo-reproducibility"],
|
|
128
|
+
"timeoutSeconds": 120,
|
|
129
|
+
"signature": "[QK:DEMO-NO-EARLY-RESOURCES]",
|
|
130
|
+
"signatureSource": "demo/maintenance-guards.test.ts"
|
|
131
|
+
},
|
|
132
|
+
{
|
|
133
|
+
"claim": "DEMO-ORIGINAL-RENDER-INPUT",
|
|
134
|
+
"title": "rerendering replaces the original approved GIF's exact agg input inside the take directory",
|
|
135
|
+
"subject": "demo/render-take.ts",
|
|
136
|
+
"find": ["\tconst renderCast = path.join(path.dirname(out), `.${path.basename(out)}.${tag}.render.cast`);"],
|
|
137
|
+
"replace": ["\tconst renderCast = path.join(takeDir, \"take.render.cast\");"],
|
|
138
|
+
"gate": ["bash", "run.sh", "check-demo-reproducibility"],
|
|
139
|
+
"timeoutSeconds": 120,
|
|
140
|
+
"signature": "[QK:DEMO-ORIGINAL-RENDER-INPUT]",
|
|
141
|
+
"signatureSource": "demo/render-take.test.ts"
|
|
142
|
+
},
|
|
143
|
+
{
|
|
144
|
+
"claim": "DEMO-RAIL-POLICY",
|
|
145
|
+
"title": "the pi-durable scene stops refusing an OpenRouter base-URL redirect, so LIVE=1 could spend a sibling turn through OpenRouter",
|
|
146
|
+
"subject": "demo/take-pi-durable.ts",
|
|
147
|
+
"find": ["const routedVia = openRouterOverride(process.env);"],
|
|
148
|
+
"replace": ["const routedVia = null;"],
|
|
149
|
+
"gate": ["bash", "run.sh", "check-demo-reproducibility"],
|
|
150
|
+
"timeoutSeconds": 120,
|
|
151
|
+
"signature": "[QK:DEMO-RAIL-POLICY]",
|
|
152
|
+
"signatureSource": "demo/maintenance-guards.test.ts"
|
|
153
|
+
}
|
|
154
|
+
]
|
|
155
|
+
}
|
|
@@ -351,6 +351,77 @@
|
|
|
351
351
|
"timeoutSeconds": 300,
|
|
352
352
|
"signature": "[QK:HAC-LEDGER-PATH-KIND]",
|
|
353
353
|
"signatureSource": "scripts/check-herdr-activation.ts"
|
|
354
|
+
},
|
|
355
|
+
{
|
|
356
|
+
"claim": "DOCTOR-MODE-DERIVED",
|
|
357
|
+
"title": "a resolver that never answers plugin mode leaves the doctor computing bare-bin expectations on a plugin-activated host, so the activation's correct absolute wiring is reported as drift and the supported route can never be certified (#136)",
|
|
358
|
+
"subject": "scripts/herdr-activation.mjs",
|
|
359
|
+
"find": ["\treturn activeDir;\n}"],
|
|
360
|
+
"replace": ["\treturn null;\n}"],
|
|
361
|
+
"gate": ["bash", "run.sh", "check-herdr-activation"],
|
|
362
|
+
"timeoutSeconds": 300,
|
|
363
|
+
"signature": "[QK:DOCTOR-MODE-DERIVED]",
|
|
364
|
+
"signatureSource": "scripts/check-herdr-activation.ts"
|
|
365
|
+
},
|
|
366
|
+
{
|
|
367
|
+
"claim": "DOCTOR-MODE-CHECKOUT-NEVER-DERIVES",
|
|
368
|
+
"title": "dropping the runtime-package precondition lets a checkout's doctor read the plugin ledger and adopt its absolute wiring as its own expectations, so the checkout certifies a runtime it does not own (#136)",
|
|
369
|
+
"subject": "scripts/herdr-activation.mjs",
|
|
370
|
+
"find": ["\t\tif (!same) return null;"],
|
|
371
|
+
"replace": ["\t\tvoid same;"],
|
|
372
|
+
"gate": ["bash", "run.sh", "check-herdr-activation"],
|
|
373
|
+
"timeoutSeconds": 300,
|
|
374
|
+
"signature": "[QK:DOCTOR-MODE-CHECKOUT-NEVER-DERIVES]",
|
|
375
|
+
"signatureSource": "scripts/check-herdr-activation.ts"
|
|
376
|
+
},
|
|
377
|
+
{
|
|
378
|
+
"claim": "DOCTOR-MODE-UNCERTIFIED-DIES",
|
|
379
|
+
"title": "swallowing the reader's refusal turns an uncertified ledger into 'not plugin mode', so a doctor silently falls back to bare expectations over a record nobody can vouch for (#136)",
|
|
380
|
+
"subject": "scripts/herdr-activation.mjs",
|
|
381
|
+
"find": [
|
|
382
|
+
"\tconst ledger = readCertifiedLedger(resolveActivationLayout(env));\n\tif (ledger === null) {\n\t\tif (override === undefined) return null;"
|
|
383
|
+
],
|
|
384
|
+
"replace": [
|
|
385
|
+
"\tlet ledger = null;\n\ttry {\n\t\tledger = readCertifiedLedger(resolveActivationLayout(env));\n\t} catch {\n\t\tledger = null;\n\t}\n\tif (ledger === null) {\n\t\tif (override === undefined || override !== undefined) return null;"
|
|
386
|
+
],
|
|
387
|
+
"gate": ["bash", "run.sh", "check-herdr-activation"],
|
|
388
|
+
"timeoutSeconds": 300,
|
|
389
|
+
"signature": "[QK:DOCTOR-MODE-UNCERTIFIED-DIES]",
|
|
390
|
+
"signatureSource": "scripts/check-herdr-activation.ts"
|
|
391
|
+
},
|
|
392
|
+
{
|
|
393
|
+
"claim": "DOCTOR-MODE-OVERRIDE-AGREES",
|
|
394
|
+
"title": "an override that need not agree with the ledger lets any caller-named root become the doctor's expectation, so the doctor would certify absolute commands pointing anywhere (#136)",
|
|
395
|
+
"subject": "scripts/herdr-activation.mjs",
|
|
396
|
+
"find": ["\tif (override !== undefined && override !== activeDir) {"],
|
|
397
|
+
"replace": ["\tif (false) {"],
|
|
398
|
+
"gate": ["bash", "run.sh", "check-herdr-activation"],
|
|
399
|
+
"timeoutSeconds": 300,
|
|
400
|
+
"signature": "[QK:DOCTOR-MODE-OVERRIDE-AGREES]",
|
|
401
|
+
"signatureSource": "scripts/check-herdr-activation.ts"
|
|
402
|
+
},
|
|
403
|
+
{
|
|
404
|
+
"claim": "DOCTOR-PLUGIN-MODE-GREEN",
|
|
405
|
+
"title": "a doctor that resolves plugin mode but never passes it to its desired-state calls still expects bare bins, so the plugin activation's absolute wiring stays falsely red (#136). One mutant for the shared wire on purpose: omitting the mode at any single one of the three call sites also turns P1 red, but no per-site mutant proves that",
|
|
406
|
+
"subject": "scripts/meta-bridge-doctor.sh",
|
|
407
|
+
"find": [" PLUGIN_ARGS=(--plugin-runtime \"$MODE_ROOT\")"],
|
|
408
|
+
"replace": [" : \"$MODE_ROOT\""],
|
|
409
|
+
"gate": ["bash", "run.sh", "check-meta-doctor-oracle"],
|
|
410
|
+
"timeoutSeconds": 600,
|
|
411
|
+
"signature": "[QK:DOCTOR-PLUGIN-MODE-GREEN]",
|
|
412
|
+
"signatureSource": "scripts/check-meta-doctor-oracle.sh",
|
|
413
|
+
"build": { "argv": ["bash", "scripts/build-bridge.sh"], "output": "mcp/entwurf-bridge/dist" }
|
|
414
|
+
},
|
|
415
|
+
{
|
|
416
|
+
"claim": "DOCTOR-MODE-ADMISSION-CLAUSES",
|
|
417
|
+
"title": "dropping the phase clause lets a ledger caught mid-activation or mid-teardown admit plugin mode, so the doctor certifies absolute wiring the activation has not finished writing or is already removing (#136)",
|
|
418
|
+
"subject": "scripts/herdr-activation.mjs",
|
|
419
|
+
"find": ["\tif (ledger.phase !== \"active\") refuse(`activation ledger phase is ${ledger.phase}, not active`);"],
|
|
420
|
+
"replace": ["\tvoid refuse;"],
|
|
421
|
+
"gate": ["bash", "run.sh", "check-herdr-activation"],
|
|
422
|
+
"timeoutSeconds": 300,
|
|
423
|
+
"signature": "[QK:DOCTOR-MODE-ADMISSION-CLAUSES]",
|
|
424
|
+
"signatureSource": "scripts/check-herdr-activation.ts"
|
|
354
425
|
}
|
|
355
426
|
]
|
|
356
427
|
}
|
|
@@ -151,8 +151,12 @@
|
|
|
151
151
|
"claim": "QUALIFY-FILTER-READS-PUSH-RANGE",
|
|
152
152
|
"title": "the filter reads the tip commit instead of the two-dot push range - the exact misreading that once concluded four of the five historical qualification reds would have been skipped",
|
|
153
153
|
"subject": "scripts/ci-qualify-decide.sh",
|
|
154
|
-
"find": [
|
|
155
|
-
|
|
154
|
+
"find": [
|
|
155
|
+
"CHANGED=\"$(git -C \"$REPO_DIR\" diff --no-renames --no-ext-diff --no-textconv --name-only \"$BEFORE\"..\"$HEAD_SHA\" 2>/dev/null)\""
|
|
156
|
+
],
|
|
157
|
+
"replace": [
|
|
158
|
+
"CHANGED=\"$(git -C \"$REPO_DIR\" diff --no-renames --no-ext-diff --no-textconv --name-only \"$HEAD_SHA~1\"..\"$HEAD_SHA\" 2>/dev/null)\""
|
|
159
|
+
],
|
|
156
160
|
"gate": ["bash", "run.sh", "check-release-gate-outcomes"],
|
|
157
161
|
"timeoutSeconds": 180,
|
|
158
162
|
"signature": "[QK:QUALIFY-FILTER-READS-PUSH-RANGE]",
|
|
@@ -169,6 +173,28 @@
|
|
|
169
173
|
"signature": "[QK:QUALIFY-FILTER-REPLAYS-PAST-CATCHES]",
|
|
170
174
|
"signatureSource": "scripts/check-release-gate-outcomes.ts"
|
|
171
175
|
},
|
|
176
|
+
{
|
|
177
|
+
"claim": "QUALIFY-FILTER-SUBJECT-HUNKS",
|
|
178
|
+
"title": "data-subject hunk refinement collapses back to file identity, so a version-only pin repeats the unchanged mutant body",
|
|
179
|
+
"subject": "scripts/ci-qualify-decide.sh",
|
|
180
|
+
"find": ["\t\t\t\tif subject_find_untouched \"$file\"; then"],
|
|
181
|
+
"replace": ["\t\t\t\tif false; then"],
|
|
182
|
+
"gate": ["bash", "run.sh", "check-release-gate-outcomes"],
|
|
183
|
+
"timeoutSeconds": 180,
|
|
184
|
+
"signature": "[QK:QUALIFY-FILTER-SUBJECT-HUNKS]",
|
|
185
|
+
"signatureSource": "scripts/check-release-gate-outcomes.ts"
|
|
186
|
+
},
|
|
187
|
+
{
|
|
188
|
+
"claim": "QUALIFY-FILTER-TOML-ONLY-REFINEMENT",
|
|
189
|
+
"title": "Markdown/JSON data re-enter hunk refinement, so an out-of-find presence restatement or later duplicate JSON key skips a body whose mutant now survives",
|
|
190
|
+
"subject": "scripts/ci-qualify-decide.sh",
|
|
191
|
+
"find": ["\t\t\t\t\t*.toml) ;;"],
|
|
192
|
+
"replace": ["\t\t\t\t\t*.toml|*.json|*.md) ;;"],
|
|
193
|
+
"gate": ["bash", "run.sh", "check-release-gate-outcomes"],
|
|
194
|
+
"timeoutSeconds": 180,
|
|
195
|
+
"signature": "[QK:QUALIFY-FILTER-TOML-ONLY-REFINEMENT]",
|
|
196
|
+
"signatureSource": "scripts/check-release-gate-outcomes.ts"
|
|
197
|
+
},
|
|
172
198
|
{
|
|
173
199
|
"claim": "MUX-LIFECYCLE-IS-RELEASE-MUST",
|
|
174
200
|
"title": "the integrated mux lifecycle stays listed but bypasses run_live_step, so a missing prerequisite returns SKIP into a branch that never classifies it and the cut reads green",
|
package/scripts/tsconfig.json
CHANGED
|
@@ -27,6 +27,7 @@
|
|
|
27
27
|
"include": [
|
|
28
28
|
"./**/*.ts",
|
|
29
29
|
"../test/**/*.ts",
|
|
30
|
+
"../demo/**/*.ts",
|
|
30
31
|
"../pi-extensions/lib/**/*.ts",
|
|
31
32
|
// The behavior-adjacent tests the root config just excluded (#119 V2). Listed at
|
|
32
33
|
// pi-extensions/** rather than pi-extensions/lib/** so a test beside an extension
|