@miller-tech/uap 1.135.1 → 1.136.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.
@@ -41,7 +41,7 @@ export interface AcceptanceOptions {
41
41
  maxChars?: number;
42
42
  }
43
43
  /** Bounded walk gathering source-file evidence (path-labelled, truncated). */
44
- export declare function gatherEvidence(projectRoot: string, maxFiles?: number, maxChars?: number): string;
44
+ export declare function gatherEvidence(projectRoot: string, maxFiles?: number, maxChars?: number, spec?: string): string;
45
45
  /**
46
46
  * Extract the first PARSEABLE balanced top-level JSON object from model text.
47
47
  * If a balanced object fails to parse (e.g. a stray `{…}` fragment in the
@@ -1 +1 @@
1
- {"version":3,"file":"acceptance-judge.d.ts","sourceRoot":"","sources":["../../src/delivery/acceptance-judge.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAIH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAC;AAE1D,MAAM,WAAW,mBAAmB;IAClC,WAAW,EAAE,MAAM,CAAC;IACpB,GAAG,EAAE,OAAO,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,gBAAgB;IAC/B,MAAM,EAAE,OAAO,CAAC;IAChB,6DAA6D;IAC7D,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,mBAAmB,EAAE,CAAC;IAChC,+EAA+E;IAC/E,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,iBAAiB;IAChC,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,iCAAiC;IACjC,QAAQ,EAAE,YAAY,CAAC;IACvB,kEAAkE;IAClE,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,2EAA2E;IAC3E,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,4DAA4D;IAC5D,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,gDAAgD;IAChD,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AA+BD,8EAA8E;AAC9E,wBAAgB,cAAc,CAAC,WAAW,EAAE,MAAM,EAAE,QAAQ,SAAoB,EAAE,QAAQ,SAAoB,GAAG,MAAM,CAqDtH;AAyBD;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAiC9E;AAED;;;;GAIG;AACH,wBAAsB,iBAAiB,CAAC,IAAI,EAAE,iBAAiB,GAAG,OAAO,CAAC,gBAAgB,CAAC,CAyC1F;AAED,2DAA2D;AAC3D,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,gBAAgB,GAAG,MAAM,CASvE;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,4BAA4B,CAC1C,KAAK,EAAE,MAAM,EACb,iBAAiB,CAAC,EAAE,MAAM,OAAO,GAChC;IACD,KAAK,CACH,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE;QAAE,MAAM,EAAE,OAAO,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE,GAC7D;QAAE,MAAM,EAAE,OAAO,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAC;QAAC,UAAU,CAAC,EAAE,OAAO,CAAA;KAAE,CAAC;CAChF,CAqCA"}
1
+ {"version":3,"file":"acceptance-judge.d.ts","sourceRoot":"","sources":["../../src/delivery/acceptance-judge.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAIH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAC;AAE1D,MAAM,WAAW,mBAAmB;IAClC,WAAW,EAAE,MAAM,CAAC;IACpB,GAAG,EAAE,OAAO,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,gBAAgB;IAC/B,MAAM,EAAE,OAAO,CAAC;IAChB,6DAA6D;IAC7D,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,mBAAmB,EAAE,CAAC;IAChC,+EAA+E;IAC/E,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,iBAAiB;IAChC,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,iCAAiC;IACjC,QAAQ,EAAE,YAAY,CAAC;IACvB,kEAAkE;IAClE,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,2EAA2E;IAC3E,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,4DAA4D;IAC5D,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,gDAAgD;IAChD,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAiDD,8EAA8E;AAC9E,wBAAgB,cAAc,CAC5B,WAAW,EAAE,MAAM,EACnB,QAAQ,SAAoB,EAC5B,QAAQ,SAAoB,EAC5B,IAAI,CAAC,EAAE,MAAM,GACZ,MAAM,CAoIR;AAyBD;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAiC9E;AAED;;;;GAIG;AACH,wBAAsB,iBAAiB,CAAC,IAAI,EAAE,iBAAiB,GAAG,OAAO,CAAC,gBAAgB,CAAC,CAyC1F;AAED,2DAA2D;AAC3D,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,gBAAgB,GAAG,MAAM,CASvE;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,4BAA4B,CAC1C,KAAK,EAAE,MAAM,EACb,iBAAiB,CAAC,EAAE,MAAM,OAAO,GAChC;IACD,KAAK,CACH,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE;QAAE,MAAM,EAAE,OAAO,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE,GAC7D;QAAE,MAAM,EAAE,OAAO,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAC;QAAC,UAAU,CAAC,EAAE,OAAO,CAAA;KAAE,CAAC;CAChF,CAqCA"}
@@ -13,7 +13,7 @@
13
13
  * the logic is fully unit-testable with a mock.
14
14
  */
15
15
  import { lstatSync, readdirSync, readFileSync } from 'fs';
16
- import { join, relative } from 'path';
16
+ import { join, relative, dirname } from 'path';
17
17
  const SKIP_DIRS = new Set(['node_modules', '.git', 'dist', 'build', 'out', 'coverage', '.uap', '.uap-deliver', 'agents', '.worktrees']);
18
18
  const SRC_EXT = /\.(js|mjs|cjs|ts|tsx|jsx|html|css|json|py|go|rs|java|rb|md|txt)$/i;
19
19
  /** Never ship likely-secret files into the LLM prompt (esp. for remote endpoints). */
@@ -45,8 +45,26 @@ function evidencePriority(name) {
45
45
  return 1;
46
46
  return 2; // md, txt, misc data
47
47
  }
48
+ /**
49
+ * Path-like tokens the spec explicitly names (files or directories). These are
50
+ * what the judge is being asked to verify, so they get guaranteed evidence
51
+ * slots: at repo scale the alphabetical candidate walk fills its pool long
52
+ * before late-alphabet directories — observed live 2026-07-11, a mission whose
53
+ * whole deliverable lived under web/dash/ was judged 0/4 with "no such file"
54
+ * while every file sat on disk, because web/ never entered the candidate pool.
55
+ */
56
+ function specReferencedPaths(spec) {
57
+ const out = new Set();
58
+ for (const m of spec.matchAll(/[\w.@-]+(?:\/[\w.@*-]+)+/g)) {
59
+ // Strip trailing punctuation from prose (e.g. "web/dash/styles.css —").
60
+ const p = m[0].replace(/[.,;:)]+$/, '');
61
+ if (!p.includes('//') && !p.startsWith('http'))
62
+ out.add(p);
63
+ }
64
+ return [...out];
65
+ }
48
66
  /** Bounded walk gathering source-file evidence (path-labelled, truncated). */
49
- export function gatherEvidence(projectRoot, maxFiles = DEFAULT_MAX_FILES, maxChars = DEFAULT_MAX_CHARS) {
67
+ export function gatherEvidence(projectRoot, maxFiles = DEFAULT_MAX_FILES, maxChars = DEFAULT_MAX_CHARS, spec) {
50
68
  const root = projectRoot;
51
69
  // Collect a generous candidate pool FIRST, then priority-order and cut to
52
70
  // maxFiles — so neither walk order nor a data-heavy directory can starve
@@ -58,7 +76,9 @@ export function gatherEvidence(projectRoot, maxFiles = DEFAULT_MAX_FILES, maxCha
58
76
  return;
59
77
  let entries;
60
78
  try {
61
- entries = readdirSync(dir);
79
+ // Sorted: readdir returns filesystem hash order, which made evidence
80
+ // content (and therefore judge verdicts) vary between machines/runs.
81
+ entries = readdirSync(dir).sort();
62
82
  }
63
83
  catch {
64
84
  return;
@@ -85,26 +105,114 @@ export function gatherEvidence(projectRoot, maxFiles = DEFAULT_MAX_FILES, maxCha
85
105
  }
86
106
  }
87
107
  };
108
+ // Spec-referenced paths first: exact files at priority -1 (uncuttable),
109
+ // spec-named directories walked before the root walk so their contents make
110
+ // the candidate pool even in huge repos. In BOTH cases the parent directory
111
+ // is walked too: specs routinely reference files in template form
112
+ // ("web/dash/tab-<name>.js") whose literal token never resolves, and the
113
+ // siblings of a named file are usually the rest of the deliverable —
114
+ // observed live 2026-07-11: 8 tab files sat next to the spec-named
115
+ // styles.css yet were judged "not present" (4/7 MET instead of 7/7).
116
+ if (spec) {
117
+ const dirsToWalk = new Set();
118
+ for (const rel of specReferencedPaths(spec)) {
119
+ if (rel.includes('..'))
120
+ continue; // stay inside projectRoot
121
+ const abs = join(root, rel);
122
+ let st;
123
+ try {
124
+ st = lstatSync(abs);
125
+ }
126
+ catch {
127
+ // Token doesn't resolve (template form / not created yet) — its
128
+ // parent directory is still the best evidence lead.
129
+ const parent = dirname(abs);
130
+ if (parent.startsWith(root) && parent !== root)
131
+ dirsToWalk.add(parent);
132
+ continue;
133
+ }
134
+ if (st.isFile() && SRC_EXT.test(abs) && !SECRET_FILE_RE.test(abs) && st.size <= 200_000) {
135
+ files.push({ abs, prio: -1 });
136
+ const parent = dirname(abs);
137
+ if (parent.startsWith(root) && parent !== root)
138
+ dirsToWalk.add(parent);
139
+ }
140
+ else if (st.isDirectory()) {
141
+ dirsToWalk.add(abs);
142
+ }
143
+ }
144
+ for (const d of dirsToWalk) {
145
+ try {
146
+ if (lstatSync(d).isDirectory())
147
+ walk(d, 1);
148
+ }
149
+ catch {
150
+ /* parent doesn't exist either — nothing to walk */
151
+ }
152
+ }
153
+ }
88
154
  walk(root, 0);
89
- files.sort((a, b) => a.prio - b.prio); // stable: walk order preserved within a class
90
- const chosen = files.slice(0, maxFiles);
91
- let out = '';
92
- let used = 0;
155
+ // Dedupe (a spec-referenced file can also be found by a walk) keeping the
156
+ // best (lowest) priority per path.
157
+ const best = new Map();
158
+ for (const f of files) {
159
+ const cur = best.get(f.abs);
160
+ if (!cur || f.prio < cur.prio)
161
+ best.set(f.abs, f);
162
+ }
163
+ const deduped = [...best.values()];
164
+ deduped.sort((a, b) => a.prio - b.prio); // stable: insertion order preserved within a class
165
+ const chosen = deduped.slice(0, maxFiles);
166
+ // Two-pass assembly. The old single pass `break`-ed when the char budget
167
+ // ran out, so a few large early files silently erased every file after
168
+ // them — the judge then reported those files as "not present" (observed
169
+ // live 2026-07-11: four 9-20K spec-named modules exhausted the 60K budget
170
+ // and eight 600-byte sibling stubs vanished from evidence; which files
171
+ // starved even varied with readdir hash order). Pass 1 guarantees EVERY
172
+ // chosen file a head (existence + its opening lines — enough to verify
173
+ // "file X exists and registers Y"); pass 2 spends the remaining budget
174
+ // extending files in priority order.
175
+ const contents = new Map();
93
176
  for (const f of chosen) {
94
- if (used >= maxChars)
95
- break;
96
- let content;
97
177
  try {
98
- content = readFileSync(f.abs, 'utf-8');
178
+ contents.set(f.abs, readFileSync(f.abs, 'utf-8'));
99
179
  }
100
180
  catch {
101
- continue;
181
+ /* unreadable — skip */
102
182
  }
103
- const rel = relative(root, f.abs);
183
+ }
184
+ const HEAD_CHARS = 600;
185
+ const granted = new Map();
186
+ let used = 0;
187
+ for (const f of chosen) {
188
+ const content = contents.get(f.abs);
189
+ if (content === undefined || used >= maxChars)
190
+ continue;
191
+ const head = Math.min(content.length, HEAD_CHARS, maxChars - used);
192
+ granted.set(f.abs, head);
193
+ used += head;
194
+ }
195
+ for (const f of chosen) {
196
+ const content = contents.get(f.abs);
197
+ if (content === undefined || used >= maxChars)
198
+ continue;
104
199
  const perFileCap = f.prio === 2 ? DATA_FILE_CHARS : PER_FILE_CHARS;
105
- const budget = Math.min(content.length, maxChars - used, perFileCap);
106
- out += `\n=== ${rel} ===\n${content.slice(0, budget)}\n`;
107
- used += budget;
200
+ const cur = granted.get(f.abs) ?? 0;
201
+ const extra = Math.min(content.length, perFileCap) - cur;
202
+ if (extra <= 0)
203
+ continue;
204
+ const grant = Math.min(extra, maxChars - used);
205
+ granted.set(f.abs, cur + grant);
206
+ used += grant;
207
+ }
208
+ let out = '';
209
+ for (const f of chosen) {
210
+ const content = contents.get(f.abs);
211
+ const take = granted.get(f.abs) ?? 0;
212
+ if (content === undefined || take <= 0)
213
+ continue;
214
+ const rel = relative(root, f.abs);
215
+ out += `\n=== ${rel} ===\n${content.slice(0, take)}\n`;
108
216
  }
109
217
  return out.trim();
110
218
  }
@@ -182,7 +290,7 @@ export function extractJsonObject(text) {
182
290
  * never wedge delivery on its own nondeterminism.
183
291
  */
184
292
  export async function runAcceptanceGate(opts) {
185
- const evidence = opts.evidence ?? gatherEvidence(opts.projectRoot, opts.maxFiles, opts.maxChars);
293
+ const evidence = opts.evidence ?? gatherEvidence(opts.projectRoot, opts.maxFiles, opts.maxChars, opts.spec);
186
294
  if (!evidence.trim()) {
187
295
  return { passed: true, score: 1, criteria: [], parseError: 'no source evidence found' };
188
296
  }
@@ -1 +1 @@
1
- {"version":3,"file":"acceptance-judge.js","sourceRoot":"","sources":["../../src/delivery/acceptance-judge.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"acceptance-judge.js","sourceRoot":"","sources":["../../src/delivery/acceptance-judge.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@miller-tech/uap",
3
- "version": "1.135.1",
3
+ "version": "1.136.0",
4
4
  "description": "Autonomous AI agent memory system with CLAUDE.md protocol enforcement",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -1349,6 +1349,7 @@ class SessionMonitor:
1349
1349
  stuck_break_fires: int = 0 # monotonic count of forced stuck-breaks
1350
1350
  deferral_streak: int = 0 # consecutive no-tool turns deferring the work (Fix A)
1351
1351
  deferral_break_fires: int = 0 # monotonic count of forced deferral-breaks (Fix A)
1352
+ mandate_deliver_fires: int = 0 # monotonic count of forced deliver-routings (mandate)
1352
1353
  tool_starvation_streak: int = 0 # Consecutive forced turns with no tool_calls produced
1353
1354
  last_request_msg_count: int = 0 # Message count of the previous request (compaction-boundary detection)
1354
1355
  malformed_tool_streak: int = 0 # consecutive malformed pseudo tool payloads
@@ -4601,6 +4602,121 @@ def _maybe_inject_deferral_break(openai_body: dict, monitor: "SessionMonitor") -
4601
4602
  )
4602
4603
 
4603
4604
 
4605
+ # MANDATE-DELIVER guardrail: delivery-enforcement blocks a direct source edit and
4606
+ # tells the model to "call the `deliver` tool", but the enforcer's route:deliver
4607
+ # signal is only honored by harnesses that understand it -- weak local models see
4608
+ # the text and flail (RECON deadlock). This makes the routing BINDING for ANY
4609
+ # model: on detecting the enforcer's block marker in the just-returned turn AND a
4610
+ # deliver-class tool in the request, pin tool_choice to that tool so the next turn
4611
+ # MUST call deliver. PROXY_MANDATE_DELIVER=off disables.
4612
+ PROXY_MANDATE_DELIVER = os.environ.get("PROXY_MANDATE_DELIVER", "on").lower() not in {
4613
+ "0", "off", "false", "no",
4614
+ }
4615
+ # Enforcer-block-SPECIFIC phrases only (src/policies/enforcers/delivery_enforcement.py).
4616
+ # Deliberately NOT matching the reactor's STANDING "route through deliver" guidance
4617
+ # (which is injected every turn) -- only the actual block event must trigger.
4618
+ _DELIVER_BLOCK_RE = re.compile(
4619
+ r"BLOCKED: do not edit|do NOT retry this edit|\"route\"\s*:\s*\"deliver\"",
4620
+ re.IGNORECASE,
4621
+ )
4622
+
4623
+
4624
+ def _deliver_tool_name(tools) -> "str | None":
4625
+ """Name of a deliver-class tool in the request (exact `deliver` or an
4626
+ MCP-namespaced `..._deliver`), or None when the agent has no deliver tool."""
4627
+ if not isinstance(tools, list):
4628
+ return None
4629
+ for t in tools:
4630
+ name = ((t.get("function", {}) or {}).get("name", "") or "")
4631
+ low = name.lower()
4632
+ if low == "deliver" or low.endswith("__deliver") or low.endswith("_deliver") or (
4633
+ "deliver" in low and "delivery" not in low
4634
+ ):
4635
+ return name
4636
+ return None
4637
+
4638
+
4639
+ def _recent_text_has_block(messages) -> bool:
4640
+ """True when a user/tool message in the current turn's tail carries the
4641
+ delivery-enforcement block marker (a direct edit was just gated)."""
4642
+ if not isinstance(messages, list):
4643
+ return False
4644
+ for m in reversed(messages[-4:]):
4645
+ role = m.get("role")
4646
+ if role == "assistant":
4647
+ break # older blocks belong to a prior, already-handled turn
4648
+ if role not in ("user", "tool"):
4649
+ continue
4650
+ content = m.get("content")
4651
+ text = ""
4652
+ if isinstance(content, str):
4653
+ text = content
4654
+ elif isinstance(content, list):
4655
+ parts = []
4656
+ for c in content:
4657
+ if isinstance(c, dict):
4658
+ parts.append(c.get("text") or c.get("content") or "")
4659
+ else:
4660
+ parts.append(str(c))
4661
+ text = " ".join(parts)
4662
+ if text and _DELIVER_BLOCK_RE.search(text):
4663
+ return True
4664
+ return False
4665
+
4666
+
4667
+ def _assistant_already_called_deliver(messages, deliver_name: str) -> bool:
4668
+ """True if the MOST RECENT assistant turn already called the deliver tool --
4669
+ then we must NOT re-force (let the tool result return); prevents a force loop."""
4670
+ if not isinstance(messages, list):
4671
+ return False
4672
+ for m in reversed(messages):
4673
+ if m.get("role") != "assistant":
4674
+ continue
4675
+ for tc in (m.get("tool_calls") or []):
4676
+ if ((tc.get("function", {}) or {}).get("name", "") or "").lower() == deliver_name.lower():
4677
+ return True
4678
+ return False # only inspect the latest assistant turn
4679
+ return False
4680
+
4681
+
4682
+ def _maybe_inject_mandate_deliver(openai_body: dict, monitor: "SessionMonitor") -> None:
4683
+ """MANDATORY deliver-routing: when a direct source edit was just blocked by
4684
+ delivery-enforcement, force the next turn to call the `deliver` tool for ANY
4685
+ model. Pins tool_choice to the deliver tool + injects a terse directive.
4686
+ Runs before the softer guards so the pin stands. PROXY_MANDATE_DELIVER=off."""
4687
+ if not PROXY_MANDATE_DELIVER:
4688
+ return
4689
+ deliver_name = _deliver_tool_name(openai_body.get("tools"))
4690
+ if not deliver_name:
4691
+ return # cannot mandate a tool the agent does not have
4692
+ messages = openai_body.get("messages")
4693
+ if not _recent_text_has_block(messages):
4694
+ return
4695
+ if _assistant_already_called_deliver(messages, deliver_name):
4696
+ return # deliver is already in flight -- don't loop on it
4697
+ openai_body["tool_choice"] = {"type": "function", "function": {"name": deliver_name}}
4698
+ monitor.mandate_deliver_fires += 1
4699
+ directive = (
4700
+ "\n\nMANDATORY: your direct source edit was BLOCKED by delivery-enforcement. "
4701
+ "You MUST call the `" + deliver_name + "` tool now with a one-line description "
4702
+ "of the change. Do NOT retry the edit, do NOT claim the file is written, do "
4703
+ "NOT explain -- call `" + deliver_name + "` this turn. Deliver writes the "
4704
+ "files and verifies them against the gates."
4705
+ )
4706
+ msgs = openai_body.get("messages")
4707
+ if not isinstance(msgs, list):
4708
+ msgs = []
4709
+ if msgs and msgs[0].get("role") == "system":
4710
+ msgs[0]["content"] = (msgs[0].get("content") or "") + directive
4711
+ else:
4712
+ msgs.insert(0, {"role": "system", "content": directive.strip()})
4713
+ openai_body["messages"] = msgs
4714
+ logger.warning(
4715
+ "MANDATE-DELIVER: pinned tool_choice to deliver (tool=%s, fires=%d)",
4716
+ deliver_name, monitor.mandate_deliver_fires,
4717
+ )
4718
+
4719
+
4604
4720
  def _maybe_inject_recon_convergence(
4605
4721
  openai_body: dict,
4606
4722
  monitor: "SessionMonitor",
@@ -5415,6 +5531,11 @@ def build_openai_request(
5415
5531
  # session wandering in exploration without producing a write is nudged
5416
5532
  # toward its deliverable regardless of tool-turn phase. Passed the full
5417
5533
  # pre-narrowing toolset so it can restore a dropped write tool.
5534
+ # MANDATE-DELIVER: a just-blocked direct edit MUST route to the deliver tool
5535
+ # (makes the enforcer's route:deliver signal binding for any model). Runs first
5536
+ # so the forced tool_choice pins before the softer guards.
5537
+ _maybe_inject_mandate_deliver(openai_body, monitor)
5538
+
5418
5539
  _maybe_inject_recon_convergence(openai_body, monitor, full_openai_tools)
5419
5540
 
5420
5541
  _maybe_inject_stuck_break(openai_body, monitor)
@@ -0,0 +1,101 @@
1
+ #!/usr/bin/env python3
2
+ """MANDATE-DELIVER guardrail: when delivery-enforcement blocks a direct source
3
+ edit, the proxy must force the next turn to call the `deliver` tool for ANY model
4
+ (pin tool_choice), so weak models can't ignore the routing and deadlock."""
5
+
6
+ import importlib.util
7
+ import os
8
+ import unittest
9
+ from pathlib import Path
10
+
11
+
12
+ def _load_proxy():
13
+ p = Path(__file__).resolve().parents[1] / "scripts" / "anthropic_proxy.py"
14
+ spec = importlib.util.spec_from_file_location("anthropic_proxy", p)
15
+ assert spec is not None and spec.loader is not None
16
+ m = importlib.util.module_from_spec(spec)
17
+ spec.loader.exec_module(m)
18
+ return m
19
+
20
+
21
+ proxy = _load_proxy()
22
+
23
+ DELIVER_TOOL = {"type": "function", "function": {"name": "deliver", "parameters": {}}}
24
+ READ_TOOL = {"type": "function", "function": {"name": "read", "parameters": {}}}
25
+ BLOCK_MSG = (
26
+ "BLOCKED: do not edit 'src/foo.ts' directly. To create or change code, call "
27
+ "the `deliver` tool (or run: uap deliver \"...\"). Do NOT retry this edit."
28
+ )
29
+
30
+
31
+ def _body(messages, tools=None, tool_choice="auto"):
32
+ return {
33
+ "tools": DELIVER_TOOL if tools is None else tools,
34
+ "messages": messages,
35
+ "tool_choice": tool_choice,
36
+ }
37
+
38
+
39
+ class MandateDeliverTest(unittest.TestCase):
40
+ def setUp(self):
41
+ self.mon = proxy.SessionMonitor()
42
+
43
+ def test_forces_deliver_on_block(self):
44
+ b = _body([
45
+ {"role": "assistant", "content": "editing", "tool_calls": [{"function": {"name": "edit"}}]},
46
+ {"role": "tool", "content": BLOCK_MSG},
47
+ ], tools=[DELIVER_TOOL])
48
+ proxy._maybe_inject_mandate_deliver(b, self.mon)
49
+ self.assertEqual(b["tool_choice"], {"type": "function", "function": {"name": "deliver"}})
50
+ self.assertEqual(self.mon.mandate_deliver_fires, 1)
51
+ self.assertTrue(any("MANDATORY" in (m.get("content") or "") for m in b["messages"]))
52
+
53
+ def test_no_block_no_change(self):
54
+ b = _body([{"role": "user", "content": "hi"}], tools=[DELIVER_TOOL], tool_choice="auto")
55
+ proxy._maybe_inject_mandate_deliver(b, self.mon)
56
+ self.assertEqual(b["tool_choice"], "auto")
57
+ self.assertEqual(self.mon.mandate_deliver_fires, 0)
58
+
59
+ def test_reactor_standing_guidance_does_not_trigger(self):
60
+ # The reactor injects this EVERY turn — it must NOT be treated as a block.
61
+ b = _body([{"role": "user", "content": "Use the `deliver` tool to write code — direct Edit/Write is gated and will be blocked."}], tools=[DELIVER_TOOL])
62
+ proxy._maybe_inject_mandate_deliver(b, self.mon)
63
+ self.assertEqual(self.mon.mandate_deliver_fires, 0)
64
+
65
+ def test_no_deliver_tool_no_change(self):
66
+ b = _body([{"role": "tool", "content": BLOCK_MSG}], tools=[READ_TOOL])
67
+ proxy._maybe_inject_mandate_deliver(b, self.mon)
68
+ self.assertEqual(self.mon.mandate_deliver_fires, 0)
69
+
70
+ def test_already_called_deliver_no_reforce(self):
71
+ b = _body([
72
+ {"role": "assistant", "content": "", "tool_calls": [{"function": {"name": "deliver"}}]},
73
+ {"role": "tool", "content": BLOCK_MSG},
74
+ ], tools=[DELIVER_TOOL])
75
+ proxy._maybe_inject_mandate_deliver(b, self.mon)
76
+ self.assertEqual(self.mon.mandate_deliver_fires, 0)
77
+
78
+ def test_mcp_namespaced_deliver_tool(self):
79
+ mcp_deliver = {"type": "function", "function": {"name": "mcp__uap-router__deliver", "parameters": {}}}
80
+ b = _body([{"role": "tool", "content": BLOCK_MSG}], tools=[mcp_deliver])
81
+ proxy._maybe_inject_mandate_deliver(b, self.mon)
82
+ self.assertEqual(b["tool_choice"], {"type": "function", "function": {"name": "mcp__uap-router__deliver"}})
83
+
84
+ def test_disabled_by_env(self):
85
+ old = os.environ.get("PROXY_MANDATE_DELIVER")
86
+ os.environ["PROXY_MANDATE_DELIVER"] = "off"
87
+ try:
88
+ p2 = _load_proxy()
89
+ mon = p2.SessionMonitor()
90
+ b = _body([{"role": "tool", "content": BLOCK_MSG}], tools=[DELIVER_TOOL])
91
+ p2._maybe_inject_mandate_deliver(b, mon)
92
+ self.assertEqual(mon.mandate_deliver_fires, 0)
93
+ finally:
94
+ if old is None:
95
+ os.environ.pop("PROXY_MANDATE_DELIVER", None)
96
+ else:
97
+ os.environ["PROXY_MANDATE_DELIVER"] = old
98
+
99
+
100
+ if __name__ == "__main__":
101
+ unittest.main()