@miller-tech/uap 2.11.0 → 2.16.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.
Files changed (166) hide show
  1. package/README.md +7 -6
  2. package/config/capacity-policy.json +15 -3
  3. package/config/model-profiles/qwen38.json +42 -34
  4. package/dist/.tsbuildinfo +1 -1
  5. package/dist/bin/cli.js +39 -0
  6. package/dist/bin/cli.js.map +1 -1
  7. package/dist/capacity/policy.d.ts +15 -0
  8. package/dist/capacity/policy.d.ts.map +1 -1
  9. package/dist/capacity/policy.js +23 -0
  10. package/dist/capacity/policy.js.map +1 -1
  11. package/dist/capacity/probe.d.ts.map +1 -1
  12. package/dist/capacity/probe.js +6 -1
  13. package/dist/capacity/probe.js.map +1 -1
  14. package/dist/cli/deliver.d.ts.map +1 -1
  15. package/dist/cli/deliver.js +148 -2
  16. package/dist/cli/deliver.js.map +1 -1
  17. package/dist/cli/inference.d.ts +13 -0
  18. package/dist/cli/inference.d.ts.map +1 -0
  19. package/dist/cli/inference.js +132 -0
  20. package/dist/cli/inference.js.map +1 -0
  21. package/dist/cli/loops.d.ts +39 -0
  22. package/dist/cli/loops.d.ts.map +1 -0
  23. package/dist/cli/loops.js +154 -0
  24. package/dist/cli/loops.js.map +1 -0
  25. package/dist/cli/wizard-config.d.ts.map +1 -1
  26. package/dist/cli/wizard-config.js +5 -1
  27. package/dist/cli/wizard-config.js.map +1 -1
  28. package/dist/cli/worktree.d.ts.map +1 -1
  29. package/dist/cli/worktree.js +8 -4
  30. package/dist/cli/worktree.js.map +1 -1
  31. package/dist/delivery/adversarial-attack.d.ts +99 -0
  32. package/dist/delivery/adversarial-attack.d.ts.map +1 -0
  33. package/dist/delivery/adversarial-attack.js +326 -0
  34. package/dist/delivery/adversarial-attack.js.map +1 -0
  35. package/dist/delivery/adversarial-gate.d.ts +120 -0
  36. package/dist/delivery/adversarial-gate.d.ts.map +1 -0
  37. package/dist/delivery/adversarial-gate.js +259 -0
  38. package/dist/delivery/adversarial-gate.js.map +1 -0
  39. package/dist/delivery/adversarial-sanction.d.ts +52 -0
  40. package/dist/delivery/adversarial-sanction.d.ts.map +1 -0
  41. package/dist/delivery/adversarial-sanction.js +134 -0
  42. package/dist/delivery/adversarial-sanction.js.map +1 -0
  43. package/dist/delivery/agentic-executor.d.ts +69 -22
  44. package/dist/delivery/agentic-executor.d.ts.map +1 -1
  45. package/dist/delivery/agentic-executor.js +152 -8
  46. package/dist/delivery/agentic-executor.js.map +1 -1
  47. package/dist/delivery/applier.d.ts +8 -0
  48. package/dist/delivery/applier.d.ts.map +1 -1
  49. package/dist/delivery/applier.js +3 -1
  50. package/dist/delivery/applier.js.map +1 -1
  51. package/dist/delivery/convergence-loop.d.ts +15 -0
  52. package/dist/delivery/convergence-loop.d.ts.map +1 -1
  53. package/dist/delivery/convergence-loop.js.map +1 -1
  54. package/dist/delivery/criteria-lint.d.ts +74 -0
  55. package/dist/delivery/criteria-lint.d.ts.map +1 -0
  56. package/dist/delivery/criteria-lint.js +134 -0
  57. package/dist/delivery/criteria-lint.js.map +1 -0
  58. package/dist/delivery/deliver-toggle.d.ts +21 -0
  59. package/dist/delivery/deliver-toggle.d.ts.map +1 -0
  60. package/dist/delivery/deliver-toggle.js +40 -0
  61. package/dist/delivery/deliver-toggle.js.map +1 -0
  62. package/dist/delivery/delivery-evidence.d.ts +109 -0
  63. package/dist/delivery/delivery-evidence.d.ts.map +1 -0
  64. package/dist/delivery/delivery-evidence.js +139 -0
  65. package/dist/delivery/delivery-evidence.js.map +1 -0
  66. package/dist/delivery/epic-mission.d.ts +5 -1
  67. package/dist/delivery/epic-mission.d.ts.map +1 -1
  68. package/dist/delivery/epic-mission.js +34 -6
  69. package/dist/delivery/epic-mission.js.map +1 -1
  70. package/dist/delivery/execution-gate.d.ts.map +1 -1
  71. package/dist/delivery/execution-gate.js +90 -7
  72. package/dist/delivery/execution-gate.js.map +1 -1
  73. package/dist/delivery/index.d.ts +9 -1
  74. package/dist/delivery/index.d.ts.map +1 -1
  75. package/dist/delivery/index.js +9 -1
  76. package/dist/delivery/index.js.map +1 -1
  77. package/dist/delivery/journey-depth.d.ts +61 -0
  78. package/dist/delivery/journey-depth.d.ts.map +1 -0
  79. package/dist/delivery/journey-depth.js +91 -0
  80. package/dist/delivery/journey-depth.js.map +1 -0
  81. package/dist/delivery/master-pipeline.d.ts +50 -0
  82. package/dist/delivery/master-pipeline.d.ts.map +1 -0
  83. package/dist/delivery/master-pipeline.js +52 -0
  84. package/dist/delivery/master-pipeline.js.map +1 -0
  85. package/dist/delivery/mission-acceptance.d.ts.map +1 -1
  86. package/dist/delivery/mission-acceptance.js +54 -2
  87. package/dist/delivery/mission-acceptance.js.map +1 -1
  88. package/dist/delivery/orchestrated-mission.d.ts +4 -1
  89. package/dist/delivery/orchestrated-mission.d.ts.map +1 -1
  90. package/dist/delivery/orchestrated-mission.js +18 -9
  91. package/dist/delivery/orchestrated-mission.js.map +1 -1
  92. package/dist/delivery/plan-check.d.ts +1 -0
  93. package/dist/delivery/plan-check.d.ts.map +1 -1
  94. package/dist/delivery/plan-check.js +48 -0
  95. package/dist/delivery/plan-check.js.map +1 -1
  96. package/dist/delivery/task-orchestrator.d.ts +16 -9
  97. package/dist/delivery/task-orchestrator.d.ts.map +1 -1
  98. package/dist/delivery/task-orchestrator.js +4 -2
  99. package/dist/delivery/task-orchestrator.js.map +1 -1
  100. package/dist/delivery/task-workspace.d.ts +35 -5
  101. package/dist/delivery/task-workspace.d.ts.map +1 -1
  102. package/dist/delivery/task-workspace.js +53 -7
  103. package/dist/delivery/task-workspace.js.map +1 -1
  104. package/dist/delivery/test-oracle-additive.d.ts +26 -6
  105. package/dist/delivery/test-oracle-additive.d.ts.map +1 -1
  106. package/dist/delivery/test-oracle-additive.js +40 -15
  107. package/dist/delivery/test-oracle-additive.js.map +1 -1
  108. package/dist/delivery/user-validation.d.ts +14 -0
  109. package/dist/delivery/user-validation.d.ts.map +1 -1
  110. package/dist/delivery/user-validation.js +103 -9
  111. package/dist/delivery/user-validation.js.map +1 -1
  112. package/dist/delivery/verifier-ladder.d.ts.map +1 -1
  113. package/dist/delivery/verifier-ladder.js +24 -6
  114. package/dist/delivery/verifier-ladder.js.map +1 -1
  115. package/dist/inference/analysis.d.ts +138 -0
  116. package/dist/inference/analysis.d.ts.map +1 -0
  117. package/dist/inference/analysis.js +243 -0
  118. package/dist/inference/analysis.js.map +1 -0
  119. package/dist/inference/probe.d.ts +85 -0
  120. package/dist/inference/probe.d.ts.map +1 -0
  121. package/dist/inference/probe.js +403 -0
  122. package/dist/inference/probe.js.map +1 -0
  123. package/dist/models/types.d.ts.map +1 -1
  124. package/dist/models/types.js +45 -18
  125. package/dist/models/types.js.map +1 -1
  126. package/dist/self-tuning/profiles/qwen38.d.ts +17 -8
  127. package/dist/self-tuning/profiles/qwen38.d.ts.map +1 -1
  128. package/dist/self-tuning/profiles/qwen38.js +21 -11
  129. package/dist/self-tuning/profiles/qwen38.js.map +1 -1
  130. package/dist/utils/model-slots.d.ts +11 -5
  131. package/dist/utils/model-slots.d.ts.map +1 -1
  132. package/dist/utils/model-slots.js +11 -5
  133. package/dist/utils/model-slots.js.map +1 -1
  134. package/docs/INDEX.md +7 -1
  135. package/docs/guides/CAPACITY_POLICY.md +29 -4
  136. package/docs/guides/INFERENCE_HEALTH.md +184 -0
  137. package/docs/guides/PROXY.md +1 -0
  138. package/docs/guides/QWEN38_EXL3.md +268 -0
  139. package/docs/plans/hlg-master-architecture-uplift-2026-09-24.md +67 -0
  140. package/docs/plans/system1-uplift-2026-09-18.md +1 -2
  141. package/docs/reference/CONFIGURATION.md +10 -1
  142. package/docs/reference/CONFIGURATION_REFERENCE.md +14 -0
  143. package/docs/reference/automode-risk.md +1 -1
  144. package/docs/reference/evidence-bound-ship.md +3 -2
  145. package/docs/reference/semantic-supervisor.md +3 -3
  146. package/docs/reference/system1-classifier.md +4 -4
  147. package/package.json +2 -2
  148. package/scripts/lib/llama-upstream.sh +7 -1
  149. package/src/policies/enforcers/__pycache__/_common.cpython-312.pyc +0 -0
  150. package/src/policies/enforcers/__pycache__/expert_review_required.cpython-312.pyc +0 -0
  151. package/src/policies/enforcers/__pycache__/quality_metrics_gate.cpython-312.pyc +0 -0
  152. package/src/policies/enforcers/expert_review_required.py +1 -4
  153. package/templates/hooks/__pycache__/deliver_autoroute.cpython-312.pyc +0 -0
  154. package/tools/agents/scripts/__pycache__/toolcall_path_normalizer.cpython-312.pyc +0 -0
  155. package/tools/agents/scripts/anthropic_proxy.py +374 -16
  156. package/tools/agents/scripts/confidence_escalation.py +4 -2
  157. package/tools/agents/scripts/project_telemetry.py +1 -0
  158. package/tools/agents/scripts/tool_risk.py +1 -0
  159. package/tools/agents/scripts/tool_risk_calibrate.py +1 -0
  160. package/tools/agents/scripts/toolcall_path_normalizer.py +1 -0
  161. package/tools/agents/tests/test_anthropic_proxy_streaming.py +52 -1
  162. package/tools/agents/tests/test_confidence_escalation.py +3 -2
  163. package/tools/agents/tests/test_count_tokens_scale_per_session.py +126 -0
  164. package/tools/agents/tests/test_expert_review_pr_scope.py +10 -11
  165. package/tools/agents/tests/test_lockstep_escalation.py +324 -0
  166. package/tools/agents/tests/test_thinking_template_kwargs.py +10 -4
@@ -0,0 +1,120 @@
1
+ /**
2
+ * Adversarial Red-Team Gate — HLG master architecture, stage 5
3
+ * (docs/plans/hlg-master-architecture-uplift-2026-09-24.md).
4
+ *
5
+ * When a deliver run has converged (all gates green) and BEFORE the verdict
6
+ * is accepted, a skeptical verifier attacks the patch: it writes edge-case
7
+ * tests designed to BREAK the change. If any fail, the run routes back into
8
+ * the convergence loop with that failure as ordinary gate evidence; only a
9
+ * patch that survives proceeds to acceptance (and gate evidence).
10
+ *
11
+ * This module is the STAGE DRIVER: settings resolution, the bounded round
12
+ * loop, breach → re-convergence orchestration, and the repair/rollback
13
+ * rails. The single-round machinery (attack authoring, sanctioning, suite
14
+ * execution, verdicts) lives in adversarial-attack.ts — the split keeps
15
+ * both files under the 500-LOC quality-gate threshold, along the seam the
16
+ * architecture review suggested. This module RE-EXPORTS the attack module's
17
+ * public surface so existing imports from './adversarial-gate.js' keep
18
+ * working.
19
+ *
20
+ * - BOUNDED: at most `maxRounds` attacks per run (default 2). A breach
21
+ * consumes a round and re-enters the convergence loop; the breaching
22
+ * tests REMAIN in the tree, so the repaired state has already survived
23
+ * that attack — the next round, if budget remains, attacks with FRESH
24
+ * tests rather than re-running the old ones forever.
25
+ *
26
+ * ACCEPTED RESIDUAL (C-stage review, 2026-09-24): authored tests execute
27
+ * with HOST FILESYSTEM privileges — sanitized-env strips environment
28
+ * variables but does NOT stop file-based credential reads (~/.aws, ~/.ssh,
29
+ * /etc) from inside a running test; and the repo content quoted into the
30
+ * attack prompt is an INDIRECT PROMPT-INJECTION channel into the authoring
31
+ * model. The additive oracle channel plus lexical+symlink path containment
32
+ * bound what an attack may WRITE and never weaken; what it can READ at
33
+ * runtime is everything the host user can read. This stage therefore runs
34
+ * only on the operator's own deliver run, never on untrusted input.
35
+ */
36
+ import type { DeliveryResult, LoopExecutor } from './convergence-loop.js';
37
+ import type { GateRung } from './verifier-ladder.js';
38
+ import { type AdversarialRoundResult, type AdversarialStatus, type SuiteRunner } from './adversarial-attack.js';
39
+ export { attackSurface, breachReconvergencePrompt, buildAttackPrompt, pickTestRung, runAdversarialRound, type AdversarialAttackFile, type AdversarialRoundOptions, type AdversarialRoundResult, type AdversarialStatus, type SuiteRun, type SuiteRunner, } from './adversarial-attack.js';
40
+ export { sanctionAttackBlocks, type SanctionedWrite } from './adversarial-sanction.js';
41
+ /** Default attacks per converged run; each breach re-enters the loop once. */
42
+ export declare const DEFAULT_ADVERSARIAL_ROUNDS = 2;
43
+ /** Hard ceiling — the stage must never become the loop it exists to bound. */
44
+ export declare const MAX_ADVERSARIAL_ROUNDS = 4;
45
+ /** Resolved on/off + round budget for the stage. */
46
+ export interface AdversarialGateSettings {
47
+ enabled: boolean;
48
+ maxRounds: number;
49
+ }
50
+ /**
51
+ * Resolve the adversarial gate's effective settings.
52
+ *
53
+ * Precedence mirrors `resolveParallelTasks` (task-workspace.ts): the
54
+ * `UAP_DELIVER_ADVERSARIAL_GATE` env var > `.uap.json` `deliver.adversarialGate`
55
+ * > the default. The stage is DEFAULT ON; `0`/`off`/`false` at either layer
56
+ * disables it. A positive integer at either layer retunes the round budget
57
+ * (clamped to [1, MAX_ADVERSARIAL_ROUNDS]); any other truthy value keeps the
58
+ * default budget — a typo must never silently disable a safety gate, and the
59
+ * documented off switch is unambiguous.
60
+ */
61
+ export declare function resolveAdversarialGate(raw: unknown, env?: NodeJS.ProcessEnv): AdversarialGateSettings;
62
+ /** Options for the whole stage (bounded rounds + re-convergence). */
63
+ export interface AdversarialGateOptions {
64
+ instruction: string;
65
+ projectRoot: string;
66
+ rungs: GateRung[];
67
+ executor: LoopExecutor;
68
+ settings: AdversarialGateSettings;
69
+ /** The converged result under attack. */
70
+ initial: DeliveryResult;
71
+ /**
72
+ * Re-enter the convergence loop with the breach as feedback. The breaching
73
+ * tests are already in the tree, so a successful re-convergence has made
74
+ * THEM pass too — the attack persists as ordinary gate evidence.
75
+ */
76
+ reconverge: (prompt: string) => Promise<DeliveryResult>;
77
+ runSuite?: SuiteRunner;
78
+ timeoutMs?: number;
79
+ /** Operator-facing progress lines. */
80
+ note?: (line: string) => void;
81
+ /**
82
+ * Re-derive the rung set AT GATE TIME. deliver.ts wires this to
83
+ * `mergeRedetectedRungs(rungs, detectRungs(projectRoot), …)` — the same
84
+ * policy the loop's mid-mission redetection uses — because the rungs this
85
+ * stage receives were detected at t0, and a mission that CREATED its own
86
+ * test gate (greenfield) would otherwise no-surface forever. A throwing
87
+ * detector falls back to `opts.rungs`.
88
+ */
89
+ redetectRungs?: () => GateRung[];
90
+ /**
91
+ * Called with each breaching round BEFORE reconvergence, so the caller can
92
+ * extend the repair executor's protected set with the breaching test files
93
+ * (the t0 protection snapshot predates them). The post-repair verification
94
+ * below enforces the rule regardless; this is defense in depth.
95
+ */
96
+ onBreach?: (breach: AdversarialRoundResult) => void;
97
+ }
98
+ /** The stage's outcome, including the (possibly re-converged) final result. */
99
+ export interface AdversarialGateReport {
100
+ status: AdversarialStatus | 'disabled';
101
+ rounds: AdversarialRoundResult[];
102
+ authored: number;
103
+ ran: number;
104
+ failed: number;
105
+ /** The state to accept (survived/no-surface) or reject (breached). */
106
+ result: DeliveryResult;
107
+ /** One-line outcome for telemetry / the gate-evidence artifact. */
108
+ summary: string;
109
+ }
110
+ /**
111
+ * The stage: attack the converged state up to `settings.maxRounds` times,
112
+ * routing breaches back into the convergence loop as ordinary gate evidence.
113
+ *
114
+ * Round-budget semantics: a breach CONSUMES a round and re-enters the loop.
115
+ * Because the breaching tests stay in the tree, the repaired state has already
116
+ * survived that attack — so exhausting the budget on a successful repair is an
117
+ * accept, not an open question. Only an UNREPAIRED breach rejects the run.
118
+ */
119
+ export declare function runAdversarialGate(opts: AdversarialGateOptions): Promise<AdversarialGateReport>;
120
+ //# sourceMappingURL=adversarial-gate.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"adversarial-gate.d.ts","sourceRoot":"","sources":["../../src/delivery/adversarial-gate.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCG;AAIH,OAAO,KAAK,EAAE,cAAc,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAC;AAE1E,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AAErD,OAAO,EAGL,KAAK,sBAAsB,EAC3B,KAAK,iBAAiB,EACtB,KAAK,WAAW,EACjB,MAAM,yBAAyB,CAAC;AAIjC,OAAO,EACL,aAAa,EACb,yBAAyB,EACzB,iBAAiB,EACjB,YAAY,EACZ,mBAAmB,EACnB,KAAK,qBAAqB,EAC1B,KAAK,uBAAuB,EAC5B,KAAK,sBAAsB,EAC3B,KAAK,iBAAiB,EACtB,KAAK,QAAQ,EACb,KAAK,WAAW,GACjB,MAAM,yBAAyB,CAAC;AAEjC,OAAO,EAAE,oBAAoB,EAAE,KAAK,eAAe,EAAE,MAAM,2BAA2B,CAAC;AAEvF,8EAA8E;AAC9E,eAAO,MAAM,0BAA0B,IAAI,CAAC;AAC5C,8EAA8E;AAC9E,eAAO,MAAM,sBAAsB,IAAI,CAAC;AAExC,oDAAoD;AACpD,MAAM,WAAW,uBAAuB;IACtC,OAAO,EAAE,OAAO,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,sBAAsB,CACpC,GAAG,EAAE,OAAO,EACZ,GAAG,GAAE,MAAM,CAAC,UAAwB,GACnC,uBAAuB,CAwBzB;AAED,qEAAqE;AACrE,MAAM,WAAW,sBAAsB;IACrC,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;IACpB,KAAK,EAAE,QAAQ,EAAE,CAAC;IAClB,QAAQ,EAAE,YAAY,CAAC;IACvB,QAAQ,EAAE,uBAAuB,CAAC;IAClC,yCAAyC;IACzC,OAAO,EAAE,cAAc,CAAC;IACxB;;;;OAIG;IACH,UAAU,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,OAAO,CAAC,cAAc,CAAC,CAAC;IACxD,QAAQ,CAAC,EAAE,WAAW,CAAC;IACvB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,sCAAsC;IACtC,IAAI,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IAC9B;;;;;;;OAOG;IACH,aAAa,CAAC,EAAE,MAAM,QAAQ,EAAE,CAAC;IACjC;;;;;OAKG;IACH,QAAQ,CAAC,EAAE,CAAC,MAAM,EAAE,sBAAsB,KAAK,IAAI,CAAC;CACrD;AAED,+EAA+E;AAC/E,MAAM,WAAW,qBAAqB;IACpC,MAAM,EAAE,iBAAiB,GAAG,UAAU,CAAC;IACvC,MAAM,EAAE,sBAAsB,EAAE,CAAC;IACjC,QAAQ,EAAE,MAAM,CAAC;IACjB,GAAG,EAAE,MAAM,CAAC;IACZ,MAAM,EAAE,MAAM,CAAC;IACf,sEAAsE;IACtE,MAAM,EAAE,cAAc,CAAC;IACvB,mEAAmE;IACnE,OAAO,EAAE,MAAM,CAAC;CACjB;AA+ED;;;;;;;;GAQG;AACH,wBAAsB,kBAAkB,CAAC,IAAI,EAAE,sBAAsB,GAAG,OAAO,CAAC,qBAAqB,CAAC,CA+FrG"}
@@ -0,0 +1,259 @@
1
+ /**
2
+ * Adversarial Red-Team Gate — HLG master architecture, stage 5
3
+ * (docs/plans/hlg-master-architecture-uplift-2026-09-24.md).
4
+ *
5
+ * When a deliver run has converged (all gates green) and BEFORE the verdict
6
+ * is accepted, a skeptical verifier attacks the patch: it writes edge-case
7
+ * tests designed to BREAK the change. If any fail, the run routes back into
8
+ * the convergence loop with that failure as ordinary gate evidence; only a
9
+ * patch that survives proceeds to acceptance (and gate evidence).
10
+ *
11
+ * This module is the STAGE DRIVER: settings resolution, the bounded round
12
+ * loop, breach → re-convergence orchestration, and the repair/rollback
13
+ * rails. The single-round machinery (attack authoring, sanctioning, suite
14
+ * execution, verdicts) lives in adversarial-attack.ts — the split keeps
15
+ * both files under the 500-LOC quality-gate threshold, along the seam the
16
+ * architecture review suggested. This module RE-EXPORTS the attack module's
17
+ * public surface so existing imports from './adversarial-gate.js' keep
18
+ * working.
19
+ *
20
+ * - BOUNDED: at most `maxRounds` attacks per run (default 2). A breach
21
+ * consumes a round and re-enters the convergence loop; the breaching
22
+ * tests REMAIN in the tree, so the repaired state has already survived
23
+ * that attack — the next round, if budget remains, attacks with FRESH
24
+ * tests rather than re-running the old ones forever.
25
+ *
26
+ * ACCEPTED RESIDUAL (C-stage review, 2026-09-24): authored tests execute
27
+ * with HOST FILESYSTEM privileges — sanitized-env strips environment
28
+ * variables but does NOT stop file-based credential reads (~/.aws, ~/.ssh,
29
+ * /etc) from inside a running test; and the repo content quoted into the
30
+ * attack prompt is an INDIRECT PROMPT-INJECTION channel into the authoring
31
+ * model. The additive oracle channel plus lexical+symlink path containment
32
+ * bound what an attack may WRITE and never weaken; what it can READ at
33
+ * runtime is everything the host user can read. This stage therefore runs
34
+ * only on the operator's own deliver run, never on untrusted input.
35
+ */
36
+ import { existsSync, readFileSync, rmSync, writeFileSync } from 'fs';
37
+ import { join } from 'path';
38
+ import { foldDeliveryResult } from './delivery-result.js';
39
+ import { extractTestTitles } from './test-oracle-additive.js';
40
+ import { breachReconvergencePrompt, runAdversarialRound, } from './adversarial-attack.js';
41
+ // The attack + sanction modules' public surface, re-exported so consumers
42
+ // (index.ts, tests) keep a single import site for the whole stage.
43
+ export { attackSurface, breachReconvergencePrompt, buildAttackPrompt, pickTestRung, runAdversarialRound, } from './adversarial-attack.js';
44
+ export { sanctionAttackBlocks } from './adversarial-sanction.js';
45
+ /** Default attacks per converged run; each breach re-enters the loop once. */
46
+ export const DEFAULT_ADVERSARIAL_ROUNDS = 2;
47
+ /** Hard ceiling — the stage must never become the loop it exists to bound. */
48
+ export const MAX_ADVERSARIAL_ROUNDS = 4;
49
+ /**
50
+ * Resolve the adversarial gate's effective settings.
51
+ *
52
+ * Precedence mirrors `resolveParallelTasks` (task-workspace.ts): the
53
+ * `UAP_DELIVER_ADVERSARIAL_GATE` env var > `.uap.json` `deliver.adversarialGate`
54
+ * > the default. The stage is DEFAULT ON; `0`/`off`/`false` at either layer
55
+ * disables it. A positive integer at either layer retunes the round budget
56
+ * (clamped to [1, MAX_ADVERSARIAL_ROUNDS]); any other truthy value keeps the
57
+ * default budget — a typo must never silently disable a safety gate, and the
58
+ * documented off switch is unambiguous.
59
+ */
60
+ export function resolveAdversarialGate(raw, env = process.env) {
61
+ const off = (v) => v === false || v === 0 || v === '0' || v === 'off';
62
+ const budget = (v) => {
63
+ // Boolean `true` means "on" (the flag form), not a round count —
64
+ // Number(true) === 1 would silently collapse the budget to one round
65
+ // while env 'true' keeps the default. Guard the TYPE, not the value.
66
+ if (typeof v === 'boolean')
67
+ return DEFAULT_ADVERSARIAL_ROUNDS;
68
+ const n = Number(v);
69
+ return Number.isFinite(n) && n > 0
70
+ ? Math.min(Math.floor(n), MAX_ADVERSARIAL_ROUNDS)
71
+ : DEFAULT_ADVERSARIAL_ROUNDS;
72
+ };
73
+ const fromEnv = env.UAP_DELIVER_ADVERSARIAL_GATE;
74
+ if (fromEnv !== undefined && fromEnv.trim() !== '') {
75
+ return off(fromEnv)
76
+ ? { enabled: false, maxRounds: 0 }
77
+ : { enabled: true, maxRounds: budget(fromEnv) };
78
+ }
79
+ if (raw === undefined || raw === null) {
80
+ return { enabled: true, maxRounds: DEFAULT_ADVERSARIAL_ROUNDS };
81
+ }
82
+ return off(raw)
83
+ ? { enabled: false, maxRounds: 0 }
84
+ : { enabled: true, maxRounds: budget(raw) };
85
+ }
86
+ /**
87
+ * Post-repair verification (C-stage review: vacuous breach repair). The
88
+ * reconvergence prompt's "never delete, skip, or weaken" rule is PROSE, and
89
+ * the repair executor's protected-files set was snapshotted at t0 — before
90
+ * the adversarial tests existed — so nothing structural stops a repair from
91
+ * deleting or gutting the very tests that pinned the breach. After a repair
92
+ * reports success, every breaching test file must still EXIST and still
93
+ * contain its authored titles; anything else is a failed repair, whatever
94
+ * the loop's gates say (a repair that removed the test trivially turns them
95
+ * green). Returns the per-file violations; empty means the attack survived
96
+ * the repair intact.
97
+ */
98
+ function breachingTestsGutted(projectRoot, breach) {
99
+ const gutted = [];
100
+ for (const f of breach.attackFiles ?? []) {
101
+ const abs = join(projectRoot, f.rel);
102
+ let content = null;
103
+ try {
104
+ content = existsSync(abs) ? readFileSync(abs, 'utf-8') : null;
105
+ }
106
+ catch {
107
+ content = null;
108
+ }
109
+ if (content === null) {
110
+ gutted.push(`${f.rel}: breaching test file was deleted during repair`);
111
+ continue;
112
+ }
113
+ const present = new Set(extractTestTitles(content));
114
+ const missing = f.titles.filter((t) => !present.has(t));
115
+ if (missing.length > 0) {
116
+ gutted.push(`${f.rel}: ${missing.length} authored adversarial test(s) removed or renamed during repair (${missing
117
+ .slice(0, 2)
118
+ .join('; ')})`);
119
+ }
120
+ }
121
+ return gutted;
122
+ }
123
+ /**
124
+ * Terminal-breach rollback: a REJECTED run must not leave the user's suite
125
+ * red, so the breaching round's authored files come back OUT — created files
126
+ * removed, appended-to files restored to their pre-attack bytes. (The
127
+ * keep-best rollback rail settled BEFORE this stage runs, so this is the
128
+ * only rail left.) Survived and repaired rounds keep their tests: those
129
+ * pass, and are regression tests now. Best-effort, like rollbackWrites.
130
+ */
131
+ function rollbackAttackFiles(projectRoot, round) {
132
+ const rolledBack = [];
133
+ for (const f of round.attackFiles ?? []) {
134
+ try {
135
+ if (f.prior === null)
136
+ rmSync(join(projectRoot, f.rel), { force: true });
137
+ else
138
+ writeFileSync(join(projectRoot, f.rel), f.prior, 'utf-8');
139
+ rolledBack.push(f.rel);
140
+ }
141
+ catch {
142
+ /* rollback is best-effort; the round notes carry the residue */
143
+ }
144
+ }
145
+ return rolledBack;
146
+ }
147
+ function summarize(status, rounds, totals) {
148
+ const counts = `${totals.authored} authored / ${totals.ran} ran / ${totals.failed} failed`;
149
+ if (status === 'disabled')
150
+ return 'adversarial gate: disabled';
151
+ if (status === 'survived') {
152
+ return `adversarial gate: patch survived ${rounds.length} round(s) (${counts})`;
153
+ }
154
+ if (status === 'no-surface') {
155
+ return `adversarial gate: no attack surface found after ${rounds.length} round(s) (${counts})`;
156
+ }
157
+ return `adversarial gate: patch BREACHED (${counts}) — re-convergence could not repair it`;
158
+ }
159
+ /**
160
+ * The stage: attack the converged state up to `settings.maxRounds` times,
161
+ * routing breaches back into the convergence loop as ordinary gate evidence.
162
+ *
163
+ * Round-budget semantics: a breach CONSUMES a round and re-enters the loop.
164
+ * Because the breaching tests stay in the tree, the repaired state has already
165
+ * survived that attack — so exhausting the budget on a successful repair is an
166
+ * accept, not an open question. Only an UNREPAIRED breach rejects the run.
167
+ */
168
+ export async function runAdversarialGate(opts) {
169
+ const totals = { authored: 0, ran: 0, failed: 0 };
170
+ const base = (status, rounds, result) => ({
171
+ status,
172
+ rounds,
173
+ ...totals,
174
+ result,
175
+ summary: summarize(status, rounds, totals),
176
+ });
177
+ if (!opts.settings.enabled) {
178
+ return base('disabled', [], opts.initial);
179
+ }
180
+ const rounds = [];
181
+ let result = opts.initial;
182
+ for (let round = 1; round <= opts.settings.maxRounds; round++) {
183
+ // Gate-time redetection (C-stage review: stale t0 rungs): the rungs this
184
+ // stage was handed were detected at mission start, so a greenfield
185
+ // mission that CREATED its test gate would no-surface forever. Re-merge
186
+ // the fresh detection the way the loop's mid-mission redetection does.
187
+ let roundRungs = opts.rungs;
188
+ if (opts.redetectRungs) {
189
+ try {
190
+ roundRungs = opts.redetectRungs();
191
+ }
192
+ catch {
193
+ roundRungs = opts.rungs;
194
+ }
195
+ }
196
+ const filesApplied = [...new Set(result.history.flatMap((h) => h.filesApplied))];
197
+ const r = await runAdversarialRound({
198
+ instruction: opts.instruction,
199
+ projectRoot: opts.projectRoot,
200
+ filesApplied,
201
+ rungs: roundRungs,
202
+ executor: opts.executor,
203
+ round,
204
+ ...(opts.runSuite ? { runSuite: opts.runSuite } : {}),
205
+ ...(opts.timeoutMs !== undefined ? { timeoutMs: opts.timeoutMs } : {}),
206
+ });
207
+ rounds.push(r);
208
+ totals.authored += r.authored;
209
+ totals.ran += r.ran;
210
+ totals.failed += r.failed;
211
+ opts.note?.(r.status === 'breached'
212
+ ? `🛡 adversarial round ${r.round}: BREACH — ${r.failed} adversarial test(s) failed; re-entering the loop`
213
+ : r.status === 'survived'
214
+ ? `🛡 adversarial round ${r.round}: survived — ${r.ran}/${r.authored} authored test(s) ran and passed`
215
+ : `🛡 adversarial round ${r.round}: no attack surface found (${r.feedback})`);
216
+ if (r.status !== 'breached') {
217
+ return base(r.status, rounds, result);
218
+ }
219
+ // Breach: let the caller extend the repair's protected set with the
220
+ // breaching test files (its t0 protection snapshot predates them), then
221
+ // feed the failure back into the convergence loop as ordinary evidence.
222
+ opts.onBreach?.(r);
223
+ const repaired = await opts.reconverge(breachReconvergencePrompt(opts.instruction, r));
224
+ const merged = { ...result, history: [...result.history] };
225
+ foldDeliveryResult(merged, repaired);
226
+ merged.success = repaired.success;
227
+ merged.changedTree = Boolean(result.changedTree || repaired.changedTree);
228
+ if (!repaired.success) {
229
+ // TERMINAL breach: the run is rejected, and a rejected run must not
230
+ // leave the user's suite red — roll the round's authored files back.
231
+ const rolledBack = rollbackAttackFiles(opts.projectRoot, r);
232
+ r.notes.push(`terminal breach — authored adversarial test file(s) rolled back: ${rolledBack.join(', ') || 'none recorded'}`);
233
+ merged.finalFeedback =
234
+ `⛔ adversarial gate: the red team broke the patch and the repair loop did not converge.\n\n${repaired.finalFeedback}`;
235
+ return base('breached', rounds, merged);
236
+ }
237
+ // Vacuous-repair check: a "successful" repair that deleted or gutted the
238
+ // breaching tests did not fix anything — it removed the evidence. That
239
+ // is a failed repair, and the (terminal) breach rolls back as above.
240
+ const gutted = breachingTestsGutted(opts.projectRoot, r);
241
+ if (gutted.length > 0) {
242
+ const rolledBack = rollbackAttackFiles(opts.projectRoot, r);
243
+ r.notes.push(`repair gutted the breaching test(s) — repair REJECTED: ${gutted.join('; ')}`);
244
+ if (rolledBack.length > 0) {
245
+ r.notes.push(`terminal breach — authored adversarial test file(s) rolled back: ${rolledBack.join(', ')}`);
246
+ }
247
+ merged.success = false;
248
+ merged.finalFeedback =
249
+ '⛔ adversarial gate: the repair deleted or weakened the breaching adversarial tests instead of fixing the code.\n\n' +
250
+ gutted.map((g) => ` ${g}`).join('\n');
251
+ return base('breached', rounds, merged);
252
+ }
253
+ result = merged;
254
+ }
255
+ // Budget exhausted on a repaired state: the breaching tests remained in the
256
+ // tree, so every repair already had to make them green — accept.
257
+ return base('survived', rounds, result);
258
+ }
259
+ //# sourceMappingURL=adversarial-gate.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"adversarial-gate.js","sourceRoot":"","sources":["../../src/delivery/adversarial-gate.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,52 @@
1
+ /**
2
+ * Adversarial attack SANCTIONING — the containment boundary every
3
+ * model-authored red-team test crosses before it touches disk. Split from
4
+ * adversarial-attack.ts to keep each module of the adversarial stage under
5
+ * the 500-LOC quality-gate threshold; the round orchestration that calls
6
+ * these functions lives in adversarial-attack.ts, and the stage driver
7
+ * (adversarial-gate.ts) re-exports the public surface.
8
+ *
9
+ * The rule set (composition over invention — nothing here is new machinery,
10
+ * it is the existing additive oracle channel applied to attack writes):
11
+ *
12
+ * - The red team may only ADD tests: NEW test files pass the delta rule
13
+ * (no suppressors, no process.exit, no assert reassignment); appends to
14
+ * existing test files pass the full additive rule (existing content
15
+ * survives verbatim as a prefix).
16
+ * - Paths are contained to the project root lexically AND through
17
+ * symlinks (realParentEscapes — the same check the applier enforces on
18
+ * every other write), capped in count and in BYTES (not UTF-16 units).
19
+ * - Every refusal and every dropped surplus block is recorded in the
20
+ * notes — the audit trail must distinguish "the model tried X and was
21
+ * refused" from "the model never tried".
22
+ */
23
+ import { type FileBlock } from './applier.js';
24
+ /** At most this many model-authored test files per round. Exported: the
25
+ * attack prompt states the cap to the authoring model. */
26
+ export declare const MAX_ATTACK_FILES = 3;
27
+ export interface SanctionedWrite {
28
+ /** Repo-relative, '/'-separated. */
29
+ rel: string;
30
+ abs: string;
31
+ /** Pre-existing content (append case); null for a new file. */
32
+ prior: string | null;
33
+ /** Test-case titles this write adds. */
34
+ titles: string[];
35
+ }
36
+ /**
37
+ * Sanction model-authored blocks through the additive oracle channel. The red
38
+ * team may only ADD tests: new test files (suppressor/exit/assert-patch
39
+ * checks), or verbatim-prefix appends to existing ones (full additive rule).
40
+ */
41
+ export declare function sanctionAttackBlocks(blocks: FileBlock[], projectRoot: string): {
42
+ writes: SanctionedWrite[];
43
+ notes: string[];
44
+ };
45
+ /** Materialize sanctioned writes; returns nothing (rollback via the writes). */
46
+ export declare function applyWrites(writes: SanctionedWrite[], blocks: FileBlock[]): void;
47
+ /**
48
+ * Undo this round's writes: remove files the round CREATED, restore files it
49
+ * appended to. Only ever touches paths sanctionAttackBlocks sanctioned.
50
+ */
51
+ export declare function rollbackWrites(writes: SanctionedWrite[]): void;
52
+ //# sourceMappingURL=adversarial-sanction.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"adversarial-sanction.d.ts","sourceRoot":"","sources":["../../src/delivery/adversarial-sanction.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAIH,OAAO,EAAqC,KAAK,SAAS,EAAE,MAAM,cAAc,CAAC;AAOjF;0DAC0D;AAC1D,eAAO,MAAM,gBAAgB,IAAI,CAAC;AAIlC,MAAM,WAAW,eAAe;IAC9B,oCAAoC;IACpC,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,EAAE,MAAM,CAAC;IACZ,+DAA+D;IAC/D,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,wCAAwC;IACxC,MAAM,EAAE,MAAM,EAAE,CAAC;CAClB;AAED;;;;GAIG;AACH,wBAAgB,oBAAoB,CAClC,MAAM,EAAE,SAAS,EAAE,EACnB,WAAW,EAAE,MAAM,GAClB;IAAE,MAAM,EAAE,eAAe,EAAE,CAAC;IAAC,KAAK,EAAE,MAAM,EAAE,CAAA;CAAE,CAuEhD;AAED,gFAAgF;AAChF,wBAAgB,WAAW,CAAC,MAAM,EAAE,eAAe,EAAE,EAAE,MAAM,EAAE,SAAS,EAAE,GAAG,IAAI,CAMhF;AAED;;;GAGG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,eAAe,EAAE,GAAG,IAAI,CAS9D"}
@@ -0,0 +1,134 @@
1
+ /**
2
+ * Adversarial attack SANCTIONING — the containment boundary every
3
+ * model-authored red-team test crosses before it touches disk. Split from
4
+ * adversarial-attack.ts to keep each module of the adversarial stage under
5
+ * the 500-LOC quality-gate threshold; the round orchestration that calls
6
+ * these functions lives in adversarial-attack.ts, and the stage driver
7
+ * (adversarial-gate.ts) re-exports the public surface.
8
+ *
9
+ * The rule set (composition over invention — nothing here is new machinery,
10
+ * it is the existing additive oracle channel applied to attack writes):
11
+ *
12
+ * - The red team may only ADD tests: NEW test files pass the delta rule
13
+ * (no suppressors, no process.exit, no assert reassignment); appends to
14
+ * existing test files pass the full additive rule (existing content
15
+ * survives verbatim as a prefix).
16
+ * - Paths are contained to the project root lexically AND through
17
+ * symlinks (realParentEscapes — the same check the applier enforces on
18
+ * every other write), capped in count and in BYTES (not UTF-16 units).
19
+ * - Every refusal and every dropped surplus block is recorded in the
20
+ * notes — the audit trail must distinguish "the model tried X and was
21
+ * refused" from "the model never tried".
22
+ */
23
+ import { existsSync, mkdirSync, readFileSync, realpathSync, rmSync, writeFileSync } from 'fs';
24
+ import { dirname, isAbsolute, resolve, sep } from 'path';
25
+ import { isTestFilePath, realParentEscapes } from './applier.js';
26
+ import { additiveTestDeltaRefusal, additiveTestEditRefusal, extractTestTitles, } from './test-oracle-additive.js';
27
+ /** At most this many model-authored test files per round. Exported: the
28
+ * attack prompt states the cap to the authoring model. */
29
+ export const MAX_ATTACK_FILES = 3;
30
+ /** Per-file content cap for authored tests (guards runaway generations). */
31
+ const MAX_ATTACK_BYTES = 100_000;
32
+ /**
33
+ * Sanction model-authored blocks through the additive oracle channel. The red
34
+ * team may only ADD tests: new test files (suppressor/exit/assert-patch
35
+ * checks), or verbatim-prefix appends to existing ones (full additive rule).
36
+ */
37
+ export function sanctionAttackBlocks(blocks, projectRoot) {
38
+ const writes = [];
39
+ const notes = [];
40
+ const rootAbs = resolve(projectRoot);
41
+ // Symlink-followed root for the containment check — the lexical resolve
42
+ // alone lets a pre-existing symlink inside the repo redirect an attack-file
43
+ // write outside it (same rule the applier enforces on every other write).
44
+ let realRoot = rootAbs;
45
+ try {
46
+ realRoot = realpathSync(rootAbs);
47
+ }
48
+ catch {
49
+ /* root unreadable — fall back to the lexical root */
50
+ }
51
+ if (blocks.length > MAX_ATTACK_FILES) {
52
+ const dropped = blocks.slice(MAX_ATTACK_FILES).map((b) => b.path);
53
+ // Surplus blocks are REFUSED, not silently lost — the audit trail records
54
+ // exactly what the model tried to add beyond the cap.
55
+ notes.push(`dropped ${dropped.length} surplus attack block(s) beyond the ${MAX_ATTACK_FILES}-file cap: ${dropped.join(', ')}`);
56
+ }
57
+ for (const block of blocks.slice(0, MAX_ATTACK_FILES)) {
58
+ const rel = block.path.replace(/\\/g, '/').replace(/^\/+/, '');
59
+ const abs = resolve(rootAbs, rel);
60
+ if (isAbsolute(block.path) || (abs !== rootAbs && !abs.startsWith(rootAbs + sep))) {
61
+ notes.push(`refused ${block.path}: path escapes the project root`);
62
+ continue;
63
+ }
64
+ if (realParentEscapes(abs, realRoot)) {
65
+ notes.push(`refused ${rel}: a symlink in its parent path escapes the project root`);
66
+ continue;
67
+ }
68
+ if (!isTestFilePath(rel)) {
69
+ notes.push(`refused ${rel}: not a test file — the red team may only add tests`);
70
+ continue;
71
+ }
72
+ // Byte-accurate cap: a runaway generation of multibyte text must count
73
+ // the BYTES it would write, not UTF-16 code units.
74
+ if (Buffer.byteLength(block.content, 'utf-8') > MAX_ATTACK_BYTES) {
75
+ notes.push(`refused ${rel}: content exceeds ${MAX_ATTACK_BYTES} bytes`);
76
+ continue;
77
+ }
78
+ if (existsSync(abs)) {
79
+ const prior = readFileSync(abs, 'utf-8');
80
+ const refusal = additiveTestEditRefusal(prior, block.content);
81
+ if (refusal) {
82
+ notes.push(`refused ${rel}: append to an existing test file is not additive — ${refusal}`);
83
+ continue;
84
+ }
85
+ const priorTitles = new Set(extractTestTitles(prior));
86
+ const titles = extractTestTitles(block.content).filter((t) => !priorTitles.has(t));
87
+ if (titles.length === 0) {
88
+ notes.push(`refused ${rel}: the append adds no recognizable test cases`);
89
+ continue;
90
+ }
91
+ writes.push({ rel, abs, prior, titles });
92
+ }
93
+ else {
94
+ const refusal = additiveTestDeltaRefusal(block.content);
95
+ if (refusal) {
96
+ notes.push(`refused ${rel}: ${refusal}`);
97
+ continue;
98
+ }
99
+ const titles = extractTestTitles(block.content);
100
+ if (titles.length === 0) {
101
+ notes.push(`refused ${rel}: no recognizable test cases — nothing runnable to add`);
102
+ continue;
103
+ }
104
+ writes.push({ rel, abs, prior: null, titles });
105
+ }
106
+ }
107
+ return { writes, notes };
108
+ }
109
+ /** Materialize sanctioned writes; returns nothing (rollback via the writes). */
110
+ export function applyWrites(writes, blocks) {
111
+ const contentByRel = new Map(blocks.map((b) => [b.path.replace(/\\/g, '/').replace(/^\/+/, ''), b.content]));
112
+ for (const w of writes) {
113
+ mkdirSync(dirname(w.abs), { recursive: true });
114
+ writeFileSync(w.abs, contentByRel.get(w.rel) ?? '', 'utf-8');
115
+ }
116
+ }
117
+ /**
118
+ * Undo this round's writes: remove files the round CREATED, restore files it
119
+ * appended to. Only ever touches paths sanctionAttackBlocks sanctioned.
120
+ */
121
+ export function rollbackWrites(writes) {
122
+ for (const w of writes) {
123
+ try {
124
+ if (w.prior === null)
125
+ rmSync(w.abs, { force: true });
126
+ else
127
+ writeFileSync(w.abs, w.prior, 'utf-8');
128
+ }
129
+ catch {
130
+ /* rollback is best-effort; the notes carry the residue */
131
+ }
132
+ }
133
+ }
134
+ //# sourceMappingURL=adversarial-sanction.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"adversarial-sanction.js","sourceRoot":"","sources":["../../src/delivery/adversarial-sanction.ts"],"names":[],"mappings":"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"}