@junghanacs/entwurf 0.12.9 → 0.12.10

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.
Files changed (69) hide show
  1. package/AGENTS.md +134 -248
  2. package/BASELINE.md +1 -1
  3. package/CHANGELOG.md +19 -0
  4. package/DELIVERY.md +4 -3
  5. package/README.md +26 -13
  6. package/VERIFY.md +3 -2
  7. package/demo/demo.sh +7 -1
  8. package/docs/setup-clean-host.md +10 -4
  9. package/mcp/entwurf-bridge/dist/mcp/entwurf-bridge/src/index.js +159 -66
  10. package/mcp/entwurf-bridge/dist/pi-extensions/lib/acp/overlay.js +5 -3
  11. package/mcp/entwurf-bridge/dist/pi-extensions/lib/entwurf-core.js +26 -9
  12. package/mcp/entwurf-bridge/dist/pi-extensions/lib/entwurf-deliverability.js +10 -6
  13. package/mcp/entwurf-bridge/dist/pi-extensions/lib/entwurf-fact-provider.js +15 -17
  14. package/mcp/entwurf-bridge/dist/pi-extensions/lib/entwurf-facts.js +13 -13
  15. package/mcp/entwurf-bridge/dist/pi-extensions/lib/entwurf-resume-args.js +31 -41
  16. package/mcp/entwurf-bridge/dist/pi-extensions/lib/entwurf-self-address.js +8 -9
  17. package/mcp/entwurf-bridge/dist/pi-extensions/lib/entwurf-v2-contract.js +32 -25
  18. package/mcp/entwurf-bridge/dist/pi-extensions/lib/entwurf-v2-decider.js +4 -4
  19. package/mcp/entwurf-bridge/dist/pi-extensions/lib/entwurf-v2-lock.js +5 -4
  20. package/mcp/entwurf-bridge/dist/pi-extensions/lib/entwurf-v2-production.js +9 -11
  21. package/mcp/entwurf-bridge/dist/pi-extensions/lib/entwurf-v2-spawn-production.js +3 -1
  22. package/mcp/entwurf-bridge/dist/pi-extensions/lib/meta-session.js +17 -20
  23. package/mcp/entwurf-bridge/src/index.ts +190 -82
  24. package/package.json +5 -3
  25. package/pi-extensions/entwurf-control.ts +69 -27
  26. package/pi-extensions/lib/acp/overlay.ts +5 -3
  27. package/pi-extensions/lib/entwurf-core.ts +26 -9
  28. package/pi-extensions/lib/entwurf-deliverability.ts +10 -6
  29. package/pi-extensions/lib/entwurf-fact-provider.ts +15 -17
  30. package/pi-extensions/lib/entwurf-facts.ts +13 -13
  31. package/pi-extensions/lib/entwurf-resume-args.ts +40 -46
  32. package/pi-extensions/lib/entwurf-self-address.ts +8 -9
  33. package/pi-extensions/lib/entwurf-v2-contract-schema.ts +7 -2
  34. package/pi-extensions/lib/entwurf-v2-contract.ts +32 -25
  35. package/pi-extensions/lib/entwurf-v2-decider.ts +8 -8
  36. package/pi-extensions/lib/entwurf-v2-lock.ts +5 -4
  37. package/pi-extensions/lib/entwurf-v2-production.ts +14 -11
  38. package/pi-extensions/lib/entwurf-v2-spawn-production.ts +3 -1
  39. package/pi-extensions/lib/meta-session.ts +17 -20
  40. package/run.sh +48 -41
  41. package/scripts/agy-bridge-config.py +249 -49
  42. package/scripts/agy-bridge.sh +59 -14
  43. package/scripts/check-acp-carrier-augment.ts +34 -2
  44. package/scripts/check-acp-sdk-surface.ts +22 -11
  45. package/scripts/check-agy-permission-matrix.py +655 -0
  46. package/scripts/check-entwurf-deliverability.ts +9 -6
  47. package/scripts/check-entwurf-fact-provider.ts +7 -7
  48. package/scripts/check-entwurf-facts.ts +12 -12
  49. package/scripts/check-entwurf-resume-args.ts +22 -60
  50. package/scripts/check-entwurf-self-address.ts +187 -4
  51. package/scripts/check-entwurf-v2-contract.ts +2 -2
  52. package/scripts/check-entwurf-v2-production.ts +5 -5
  53. package/scripts/check-entwurf-v2-spawn-production.ts +6 -2
  54. package/scripts/check-entwurf-v2-surface.ts +327 -14
  55. package/scripts/check-gate-qualification.ts +785 -0
  56. package/scripts/check-meta-identity-consumers.ts +1 -1
  57. package/scripts/check-shell-quote.ts +2 -1
  58. package/scripts/lib/mutation-qualify.ts +794 -0
  59. package/scripts/mutants/acp-augment.json +30 -0
  60. package/scripts/mutants/agy-permission.json +144 -0
  61. package/scripts/mutants/meta-identity.json +17 -0
  62. package/scripts/mutants/self-address.json +59 -0
  63. package/scripts/mutants/v2-surface.json +87 -0
  64. package/scripts/smoke-acp-raw-turn-live.ts +1 -1
  65. package/scripts/smoke-acp-v2-send-live.ts +33 -18
  66. package/scripts/smoke-agy-install-state.sh +205 -20
  67. package/scripts/smoke-entwurf-v2-matrix-live.ts +3 -2
  68. package/pi-extensions/lib/entwurf-mailbox-guard.ts +0 -100
  69. package/scripts/check-entwurf-mailbox-guard.ts +0 -266
@@ -0,0 +1,30 @@
1
+ {
2
+ "schemaVersion": 1,
3
+ "lane": "acp-augment",
4
+ "mutants": [
5
+ {
6
+ "claim": "AUGMENT-BUDGET-FITS",
7
+ "title": "shrinking the augment cap re-opens the tail-cut that hid AGENTS rules + cwd from ACP siblings",
8
+ "subject": "pi-extensions/lib/acp/augment.ts",
9
+ "find": ["const MAX_AUGMENT_BYTES = 50 * 1024;"],
10
+ "replace": ["const MAX_AUGMENT_BYTES = 20 * 1024;"],
11
+ "gate": ["bash", "run.sh", "check-acp-carrier-augment"],
12
+ "timeoutSeconds": 60,
13
+ "signature": "[QK:AUGMENT-BUDGET-FITS]",
14
+ "signatureSource": "scripts/check-acp-carrier-augment.ts"
15
+ },
16
+ {
17
+ "claim": "AUGMENT-TRUNC-MARKER",
18
+ "title": "silent truncation: dropping the honest marker leaves a cut augment with no trace",
19
+ "subject": "pi-extensions/lib/acp/augment.ts",
20
+ "find": [
21
+ "\tconst marker = `\\n\\n[entwurf: context augment truncated to ${MAX_AUGMENT_BYTES} bytes; read AGENTS.md files directly if more detail is needed.]`;"
22
+ ],
23
+ "replace": ["\tconst marker = \"\";"],
24
+ "gate": ["bash", "run.sh", "check-acp-carrier-augment"],
25
+ "timeoutSeconds": 60,
26
+ "signature": "[QK:AUGMENT-TRUNC-MARKER]",
27
+ "signatureSource": "scripts/check-acp-carrier-augment.ts"
28
+ }
29
+ ]
30
+ }
@@ -0,0 +1,144 @@
1
+ {
2
+ "schemaVersion": 1,
3
+ "lane": "agy-permission",
4
+ "mutants": [
5
+ {
6
+ "claim": "AGY-EXACT-RULE-SET",
7
+ "title": "over-grant: adding entwurf_inbox_read to ALLOW_RULES must die at the independent literal oracle",
8
+ "subject": "scripts/agy-bridge-config.py",
9
+ "find": [
10
+ "ALLOW_RULES = tuple(f\"mcp({SERVER_KEY}/{tool})\" for tool in (\"entwurf_v2\", \"entwurf_peers\", \"entwurf_self\"))"
11
+ ],
12
+ "replace": [
13
+ "ALLOW_RULES = tuple(",
14
+ " f\"mcp({SERVER_KEY}/{tool})\" for tool in (\"entwurf_v2\", \"entwurf_peers\", \"entwurf_self\", \"entwurf_inbox_read\")",
15
+ ")"
16
+ ],
17
+ "gate": ["bash", "run.sh", "smoke-agy-install-state"],
18
+ "timeoutSeconds": 180,
19
+ "signature": "[QK:AGY-EXACT-RULE-SET]",
20
+ "signatureSource": "scripts/smoke-agy-install-state.sh"
21
+ },
22
+ {
23
+ "claim": "AGY-INSTALL-MALFORMED-PRIOR",
24
+ "title": "install reverts to a shallow prior-state check (empty provenance map passes all()) and re-captures",
25
+ "subject": "scripts/agy-bridge-config.py",
26
+ "find": [
27
+ " try:",
28
+ " _prior_rules, prior_existed = _parse_permission_state(prior)",
29
+ " except _PermissionStateError as exc:",
30
+ " _die(4, f\"agy-bridge: prior permission install-state is unusable — {exc}. Refusing to \"",
31
+ " \"overwrite provenance this entwurf cannot read; inspect it by hand.\")",
32
+ " for rule in ALLOW_RULES:",
33
+ " if rule in prior_existed:",
34
+ " rules_existed[rule] = prior_existed[rule]"
35
+ ],
36
+ "replace": [
37
+ " if prior.get(\"schemaVersion\") == 1:",
38
+ " legacy_rule = prior.get(\"rule\")",
39
+ " if isinstance(legacy_rule, str) and isinstance(prior.get(\"ruleExistedBefore\"), bool):",
40
+ " if legacy_rule in ALLOW_RULES:",
41
+ " rules_existed[legacy_rule] = prior[\"ruleExistedBefore\"]",
42
+ " else:",
43
+ " prior_existed = prior.get(\"rulesExistedBefore\")",
44
+ " if isinstance(prior_existed, dict) and all(isinstance(v, bool) for v in prior_existed.values()):",
45
+ " for rule in ALLOW_RULES:",
46
+ " if rule in prior_existed:",
47
+ " rules_existed[rule] = prior_existed[rule]"
48
+ ],
49
+ "gate": ["bash", "run.sh", "smoke-agy-install-state"],
50
+ "timeoutSeconds": 180,
51
+ "signature": "[QK:AGY-INSTALL-MALFORMED-PRIOR]",
52
+ "signatureSource": "scripts/smoke-agy-install-state.sh"
53
+ },
54
+ {
55
+ "claim": "AGY-UNINSTALL-VALIDATE-FIRST",
56
+ "title": "uninstall validates the state only inside the settings-exists branch (refusal after mutation)",
57
+ "subject": "scripts/agy-bridge-config.py",
58
+ "find": [
59
+ " ours = _owned_rules(state)",
60
+ "",
61
+ " if os.path.islink(settings_path):",
62
+ " _die(3, f\"agy-bridge: refusing to uninstall — {settings_path} became a symlink since install \"",
63
+ " f\"(someone else's SSOT now). Resolve by hand.\")",
64
+ "",
65
+ " if os.path.exists(settings_path):",
66
+ " data = _load_config(settings_path)"
67
+ ],
68
+ "replace": [
69
+ " if os.path.islink(settings_path):",
70
+ " _die(3, f\"agy-bridge: refusing to uninstall — {settings_path} became a symlink since install \"",
71
+ " f\"(someone else's SSOT now). Resolve by hand.\")",
72
+ "",
73
+ " ours = []",
74
+ " if os.path.exists(settings_path):",
75
+ " data = _load_config(settings_path)",
76
+ " ours = _owned_rules(state)"
77
+ ],
78
+ "gate": ["bash", "run.sh", "smoke-agy-install-state"],
79
+ "timeoutSeconds": 180,
80
+ "signature": "[QK:AGY-UNINSTALL-VALIDATE-FIRST]",
81
+ "signatureSource": "scripts/smoke-agy-install-state.sh"
82
+ },
83
+ {
84
+ "claim": "AGY-DOCTOR-OWNERSHIP-AXIS",
85
+ "title": "the state-doctor rounds a path-correct but unreadable ownership record up to ok",
86
+ "subject": "scripts/agy-bridge-config.py",
87
+ "find": [
88
+ " try:",
89
+ " rules, _existed = _parse_permission_state(state)",
90
+ " except _PermissionStateError as exc:",
91
+ " sys.stdout.write(f\"corrupt {exc}\\n\")",
92
+ " return",
93
+ " sys.stdout.write(f\"ok {len(rules)}\\n\")"
94
+ ],
95
+ "replace": [" sys.stdout.write(\"ok 0\\n\")"],
96
+ "gate": ["bash", "run.sh", "smoke-agy-install-state"],
97
+ "timeoutSeconds": 180,
98
+ "signature": "[QK:AGY-DOCTOR-OWNERSHIP-AXIS]",
99
+ "signatureSource": "scripts/smoke-agy-install-state.sh"
100
+ },
101
+ {
102
+ "claim": "AGY-CROSS-LIST-BROAD-FIRST",
103
+ "title": "broad-most-covering runs only within each list, so a deny-exact shadows an ask-broad host wrongly",
104
+ "subject": "scripts/agy-bridge-config.py",
105
+ "find": [
106
+ " for rule_set, scope in ((BROAD_RULES, \"broad\"), (ALLOW_RULES, \"exact\")):",
107
+ " for list_name in SHADOWING_LISTS:",
108
+ " rules = perms.get(list_name)",
109
+ " if not isinstance(rules, list):",
110
+ " continue",
111
+ " for rule in rules:",
112
+ " if rule in rule_set:",
113
+ " sys.stdout.write(f\"shadowed-by-{list_name} {scope} {rule}\\n\")",
114
+ " return"
115
+ ],
116
+ "replace": [
117
+ " for list_name in SHADOWING_LISTS:",
118
+ " rules = perms.get(list_name)",
119
+ " if not isinstance(rules, list):",
120
+ " continue",
121
+ " for rule_set, scope in ((BROAD_RULES, \"broad\"), (ALLOW_RULES, \"exact\")):",
122
+ " for rule in rules:",
123
+ " if rule in rule_set:",
124
+ " sys.stdout.write(f\"shadowed-by-{list_name} {scope} {rule}\\n\")",
125
+ " return"
126
+ ],
127
+ "gate": ["bash", "run.sh", "check-agy-permission-matrix"],
128
+ "timeoutSeconds": 60,
129
+ "signature": "[QK:AGY-CROSS-LIST-BROAD-FIRST]",
130
+ "signatureSource": "scripts/check-agy-permission-matrix.py"
131
+ },
132
+ {
133
+ "claim": "AGY-SCHEMA-VERSIONS-APART",
134
+ "title": "re-merging the two state schema constants stamps a lying version onto the MCP install-state",
135
+ "subject": "scripts/agy-bridge-config.py",
136
+ "find": ["STATE_SCHEMA_VERSION = 1 # MCP install-state (server key + preimage); shape unchanged"],
137
+ "replace": ["STATE_SCHEMA_VERSION = 2 # re-merged with the permission version (the schema re-merge defect)"],
138
+ "gate": ["bash", "run.sh", "smoke-agy-install-state"],
139
+ "timeoutSeconds": 180,
140
+ "signature": "[QK:AGY-SCHEMA-VERSIONS-APART]",
141
+ "signatureSource": "scripts/smoke-agy-install-state.sh"
142
+ }
143
+ ]
144
+ }
@@ -0,0 +1,17 @@
1
+ {
2
+ "schemaVersion": 1,
3
+ "lane": "meta-identity",
4
+ "mutants": [
5
+ {
6
+ "claim": "META-FIFO-NONBLOCK",
7
+ "title": "removing O_NONBLOCK makes a fifo-shaped record block the open — the 7/26 mutation evidence, committed",
8
+ "subject": "pi-extensions/lib/meta-session.ts",
9
+ "find": ["\tconst fd = fs.openSync(file, fs.constants.O_RDONLY | O_NOFOLLOW_FLAG | O_NONBLOCK_FLAG);"],
10
+ "replace": ["\tconst fd = fs.openSync(file, fs.constants.O_RDONLY | O_NOFOLLOW_FLAG);"],
11
+ "gate": ["bash", "run.sh", "check-meta-identity-consumers"],
12
+ "timeoutSeconds": 120,
13
+ "signature": "[QK:META-FIFO-NONBLOCK]",
14
+ "signatureSource": "scripts/check-meta-identity-consumers.ts"
15
+ }
16
+ ]
17
+ }
@@ -0,0 +1,59 @@
1
+ {
2
+ "schemaVersion": 1,
3
+ "lane": "self-address",
4
+ "mutants": [
5
+ {
6
+ "claim": "SELFADDR-RAIL-RENDER",
7
+ "title": "entwurf_self reverts to an empty self-fetch guard + unconditional mailbox render (ordering-not-containment)",
8
+ "subject": "mcp/entwurf-bridge/src/index.ts",
9
+ "find": [
10
+ "\t\t\t\tif (rail === \"self-fetch\") {",
11
+ "\t\t\t\t\tconst mailboxPath = path.join(defaultMetaMailboxDir(), sender.sessionId);",
12
+ "\t\t\t\t\textra.mailboxPath = mailboxPath;",
13
+ "\t\t\t\t\tlines.push(`mailboxPath: ${mailboxPath}`);",
14
+ "\t\t\t\t} else if (rail === \"native-push\") {"
15
+ ],
16
+ "replace": [
17
+ "\t\t\t\tif (rail === \"self-fetch\") {",
18
+ "\t\t\t\t}",
19
+ "\t\t\t\tconst mailboxPath = path.join(defaultMetaMailboxDir(), sender.sessionId);",
20
+ "\t\t\t\textra.mailboxPath = mailboxPath;",
21
+ "\t\t\t\tlines.push(`mailboxPath: ${mailboxPath}`);",
22
+ "\t\t\t\tif (rail === \"native-push\") {"
23
+ ],
24
+ "gate": ["bash", "run.sh", "check-entwurf-self-address"],
25
+ "timeoutSeconds": 60,
26
+ "signature": "[QK:SELFADDR-RAIL-RENDER]",
27
+ "signatureSource": "scripts/check-entwurf-self-address.ts"
28
+ },
29
+ {
30
+ "claim": "SELFADDR-NO-HARDCODED-REPLYABLE",
31
+ "title": "buildStrictPiSenderEnvelope hardcodes replyable: true again (env presence read as reachability)",
32
+ "subject": "mcp/entwurf-bridge/src/index.ts",
33
+ "find": ["\t\torigin: \"pi-session\",", "\t\treplyable: self.replyable,", "\t};", "}"],
34
+ "replace": ["\t\torigin: \"pi-session\",", "\t\treplyable: true,", "\t};", "}"],
35
+ "gate": ["bash", "run.sh", "check-entwurf-self-address"],
36
+ "timeoutSeconds": 60,
37
+ "signature": "[QK:SELFADDR-NO-HARDCODED-REPLYABLE]",
38
+ "signatureSource": "scripts/check-entwurf-self-address.ts"
39
+ },
40
+ {
41
+ "claim": "SELFADDR-RAIL-FACT-LEAK",
42
+ "title": "the native-push predicate lets a mailbox fact (watchArmed) buy replyability — behavioral, not text",
43
+ "subject": "pi-extensions/lib/entwurf-self-address.ts",
44
+ "find": [
45
+ "\t\t\t\t\tconst push = nativePushDeliverable({ recordBacked: facts.recordBacked, probeAlive: facts.probeAlive });"
46
+ ],
47
+ "replace": [
48
+ "\t\t\t\t\tconst push = nativePushDeliverable({",
49
+ "\t\t\t\t\t\trecordBacked: facts.recordBacked,",
50
+ "\t\t\t\t\t\tprobeAlive: facts.probeAlive === true || facts.watchArmed === true,",
51
+ "\t\t\t\t\t});"
52
+ ],
53
+ "gate": ["bash", "run.sh", "check-entwurf-self-address"],
54
+ "timeoutSeconds": 60,
55
+ "signature": "[QK:SELFADDR-RAIL-FACT-LEAK]",
56
+ "signatureSource": "scripts/check-entwurf-self-address.ts"
57
+ }
58
+ ]
59
+ }
@@ -0,0 +1,87 @@
1
+ {
2
+ "schemaVersion": 1,
3
+ "lane": "v2-surface",
4
+ "mutants": [
5
+ {
6
+ "claim": "V2SURF-MCP-LOCK-DOMAIN",
7
+ "title": "MCP long description reverts to the false \"socket paths take a per-target lock\" claim",
8
+ "subject": "mcp/entwurf-bridge/src/index.ts",
9
+ "find": [
10
+ "\t\t\"(delivered / rejected / lock-retained / delivered-but-lock-dirty). LOCK POLICY (do not \" +",
11
+ "\t\t\"over-generalize it): the per-target lock is taken for a control-socket-DOMAIN dispatch, which is \" +",
12
+ "\t\t\"both the live send AND the dormant cell's spawn-bg resume — spawn-bg is a separate relaunch \" +",
13
+ "\t\t\"transport yet it still runs under that domain's lock. The mailbox and native-push rails are \" +",
14
+ "\t\t\"lock-free: the mailbox is guarded instead by active-receiver deliverability, and native-push by \" +",
15
+ "\t\t\"its adapter probe. The decider — not the \" +"
16
+ ],
17
+ "replace": [
18
+ "\t\t\"(delivered / rejected / lock-retained / delivered-but-lock-dirty). LOCK POLICY: socket paths \" +",
19
+ "\t\t\"take a per-target lock; the mailbox path does not. The decider — not the \" +"
20
+ ],
21
+ "gate": ["bash", "run.sh", "check-entwurf-v2-surface"],
22
+ "timeoutSeconds": 60,
23
+ "signature": "[QK:V2SURF-MCP-LOCK-DOMAIN]",
24
+ "signatureSource": "scripts/check-entwurf-v2-surface.ts"
25
+ },
26
+ {
27
+ "claim": "V2SURF-PI-MODE-SCOPE",
28
+ "title": "pi-native mode param reverts to \"Delivery mode for a live send\" (false for native-push)",
29
+ "subject": "pi-extensions/entwurf-control.ts",
30
+ "find": [
31
+ "\t\t\t\tdescription:",
32
+ "\t\t\t\t\t\"Injection style for a CONTROL-SOCKET send only: steer (immediate) or follow_up (after task). \" +",
33
+ "\t\t\t\t\t\"The mailbox, native-push, and spawn-bg plans carry no mode, so it has no effect on those rails.\","
34
+ ],
35
+ "replace": [
36
+ "\t\t\t\tdescription:",
37
+ "\t\t\t\t\t\"Delivery mode for a live send: steer (immediate, interrupt the current turn) or follow_up \" +",
38
+ "\t\t\t\t\t\"(queued after the current task finishes running to completion).\","
39
+ ],
40
+ "gate": ["bash", "run.sh", "check-entwurf-v2-surface"],
41
+ "timeoutSeconds": 60,
42
+ "signature": "[QK:V2SURF-PI-MODE-SCOPE]",
43
+ "signatureSource": "scripts/check-entwurf-v2-surface.ts"
44
+ },
45
+ {
46
+ "claim": "V2SURF-INBOX-SCOPE-HONESTY",
47
+ "title": "entwurf_inbox_read reverts to the false \"drains your own inbox\" access claim (SCOPE paragraph gone)",
48
+ "subject": "mcp/entwurf-bridge/src/index.ts",
49
+ "find": [
50
+ "\t\t\"doorbell is only a wake attempt, not a read. An empty inbox mutates nothing. \" +",
51
+ "\t\t\"SCOPE — read this literally: the garden id is CALLER-SUPPLIED and is NOT verified against \" +",
52
+ "\t\t\"your own identity (a host with no garden record of its own can call this too). So passing \" +",
53
+ "\t\t\"another citizen's garden id drains THEIR mail and stamps THEIR receipt, and they will never \" +",
54
+ "\t\t\"see those messages. Pass only the id from your own doorbell notice or your own meta-record; \" +",
55
+ "\t\t\"use entwurf_self if you need to confirm which id that is. \" +"
56
+ ],
57
+ "replace": [
58
+ "\t\t\"doorbell is only a wake attempt, not a read. An empty inbox mutates nothing. \" +",
59
+ "\t\t\"This tool drains your own meta-bridge inbox and stamps the read receipt on your meta-record. \" +"
60
+ ],
61
+ "gate": ["bash", "run.sh", "check-entwurf-v2-surface"],
62
+ "timeoutSeconds": 60,
63
+ "signature": "[QK:V2SURF-INBOX-SCOPE-HONESTY]",
64
+ "signatureSource": "scripts/check-entwurf-v2-surface.ts"
65
+ },
66
+ {
67
+ "claim": "V2SURF-MERGED-REJECT",
68
+ "title": "MCP long description merges the two owned rejects back under backend-liveness-unsupported",
69
+ "subject": "mcp/entwurf-bridge/src/index.ts",
70
+ "find": [
71
+ "\t\t\"owned-outcome is ONLY for waking a DORMANT socket-domain citizen (spawn-bg resume, currently \" +",
72
+ "\t\t\"backend pi); on a live target it is rejected as owned-live-no-autosend. Neither self-fetch nor \" +",
73
+ "\t\t\"native-push has resume authority, but they reject under DIFFERENT reasons — self-fetch as \" +",
74
+ "\t\t\"backend-liveness-unsupported, native-push as native-push-no-resume-authority. \" +"
75
+ ],
76
+ "replace": [
77
+ "\t\t\"owned-outcome is ONLY for waking a DORMANT socket-domain citizen (spawn-bg resume, currently \" +",
78
+ "\t\t\"backend pi); on a live target it is rejected as owned-live-no-autosend, and on self-fetch and \" +",
79
+ "\t\t\"native-push alike it is rejected as backend-liveness-unsupported. \" +"
80
+ ],
81
+ "gate": ["bash", "run.sh", "check-entwurf-v2-surface"],
82
+ "timeoutSeconds": 60,
83
+ "signature": "[QK:V2SURF-MERGED-REJECT]",
84
+ "signatureSource": "scripts/check-entwurf-v2-surface.ts"
85
+ }
86
+ ]
87
+ }
@@ -3,7 +3,7 @@
3
3
  // LIVE=1 ./run.sh smoke-acp-raw-turn-live
4
4
  //
5
5
  // What this proves (and ONLY this): the pinned Claude ACP adapter
6
- // (@agentclientprotocol/claude-agent-acp@0.61.0) spawns, speaks the ACP wire
6
+ // (@agentclientprotocol/claude-agent-acp@0.62.0) spawns, speaks the ACP wire
7
7
  // protocol over stdio NDJSON, and returns one real model turn. It is the
8
8
  // bytes-flow proof that the S2a dep surface is not just installable but
9
9
  // actually drivable — before any provider/overlay/streamSimple code (S2b+).
@@ -32,26 +32,41 @@
32
32
  // The isolated world also keeps the operator's live store and mailbox clean: a
33
33
  // smoke that delivers into the real garden would page a human.
34
34
  //
35
- // KNOWN OPEN DEFECT this gate catches — bundled-MCP readiness (2026-07-24). Two
36
- // independent failures were first read as the model declining an explicit
37
- // instruction, and the transcripts said otherwise: in both, the entwurf tool was
38
- // ABSENT from the session's schema. The two models then behaved differently, which
39
- // is why the shared cause was easy to miss — in this gate's failure (a standalone
40
- // run) the model called anyway and the runtime answered `No such tool available:
41
- // mcp__entwurf-bridge__entwurf_v2`; in the sibling smoke-acp-bundled-mcp-live's
42
- // failure (a separate run, half an hour later, inside a release-gate aggregate) the
43
- // model read its schema first, reported that only Read/Bash/Edit/Write/Skill were
44
- // exposed, and refused to invent a result for a tool it did not have. Two
45
- // independent runs, different behaviour, one defect: the server was not there to be
46
- // called. The window is
47
- // structural: claude-agent-acp 0.61.0's createSession awaits only
35
+ // KNOWN OPEN DEFECT this gate catches — bundled-MCP readiness (2026-07-24).
36
+ // SSOT for the ledger and the claim tiers: ROADMAP 「번들 MCP readiness race」 +
37
+ // docs/acp-backend-rail.md §11. Keep this comment at the strength those carry.
38
+ //
39
+ // OBSERVED (established): in three runs the entwurf tool was ABSENT from the
40
+ // session's schema — the same SYMPTOM each time, reached by two different model
41
+ // behaviours, which is why one shared symptom was easy to miss. In this gate's
42
+ // failure (a standalone run) the model called anyway and the runtime answered
43
+ // `No such tool available: mcp__entwurf-bridge__entwurf_v2`; in the sibling
44
+ // smoke-acp-bundled-mcp-live's failure (a separate run, half an hour later,
45
+ // inside a release-gate aggregate) the model read its schema first, reported that
46
+ // only Read/Bash/Edit/Write/Skill were exposed, and refused to invent a result for
47
+ // a tool it did not have.
48
+ //
49
+ // ESTABLISHED CONTRACT GAP (not the same as a cause): there is no client-side
50
+ // readiness fence on this path. claude-agent-acp's createSession awaits only
48
51
  // `initializationResult()`, and this backend prompts right after
49
52
  // (acp/backend.ts:718-790) — nothing waits for the configured MCP servers to reach
50
- // `connected`, though claude-agent-sdk 0.3.217 exposes exactly that via
51
- // `mcpServerStatus()`. Both observed hits came under heavy concurrent load, which
52
- // is correlation, not established cause. So this gate stays MUST: its failures are
53
- // OURS. Until the readiness wait exists, a FAIL here is a real release blocker and
54
- // must not be re-read as model flakiness.
53
+ // `connected`, though claude-agent-sdk exposes exactly that via
54
+ // `mcpServerStatus()`.
55
+ //
56
+ // OPEN (do NOT write as settled): whether that missing fence is what produced the
57
+ // three observations. No controlled repro exists yet, and the load association is
58
+ // correlation only. Do not restate this as "one defect" or "the cause".
59
+ //
60
+ // Bump note: measured at claude-agent-acp 0.61.0 / claude-agent-sdk 0.3.217;
61
+ // re-checked at the 2026-07-27 bump to 0.62.0 / 0.3.219 — the adapter's `dist/` is
62
+ // byte-identical across 0.61.0→0.62.0 and adds no readiness fence. That is an
63
+ // unchanged ABSENCE of any explicit wait, not an unchanged window: the transitive
64
+ // SDK moved and MCP startup lives inside it, so effective timing may differ.
65
+ //
66
+ // So this gate stays MUST: it TELLS the model which tool to call, so a failure
67
+ // here is OURS, not model preference. While the symptom and the contract gap
68
+ // remain unresolved, a FAIL here is a real release blocker and must not be
69
+ // re-read as model flakiness.
55
70
  //
56
71
  // LIVE-only — kept OUT of `pnpm check`; honest skip when LIVE!=1 (skip = CI safety,
57
72
  // NOT an acceptance PASS). Model override: ENTWURF_ACP_PROVIDER_MODEL (default sonnet).