@miller-tech/uap 2.11.1 → 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.
- package/config/capacity-policy.json +15 -3
- package/config/model-profiles/qwen38.json +42 -34
- package/dist/.tsbuildinfo +1 -1
- package/dist/bin/cli.js +39 -0
- package/dist/bin/cli.js.map +1 -1
- package/dist/capacity/policy.d.ts +15 -0
- package/dist/capacity/policy.d.ts.map +1 -1
- package/dist/capacity/policy.js +23 -0
- package/dist/capacity/policy.js.map +1 -1
- package/dist/capacity/probe.d.ts.map +1 -1
- package/dist/capacity/probe.js +6 -1
- package/dist/capacity/probe.js.map +1 -1
- package/dist/cli/deliver.d.ts.map +1 -1
- package/dist/cli/deliver.js +148 -2
- package/dist/cli/deliver.js.map +1 -1
- package/dist/cli/inference.d.ts +13 -0
- package/dist/cli/inference.d.ts.map +1 -0
- package/dist/cli/inference.js +132 -0
- package/dist/cli/inference.js.map +1 -0
- package/dist/cli/loops.d.ts +39 -0
- package/dist/cli/loops.d.ts.map +1 -0
- package/dist/cli/loops.js +154 -0
- package/dist/cli/loops.js.map +1 -0
- package/dist/cli/wizard-config.d.ts.map +1 -1
- package/dist/cli/wizard-config.js +5 -1
- package/dist/cli/wizard-config.js.map +1 -1
- package/dist/cli/worktree.d.ts.map +1 -1
- package/dist/cli/worktree.js +8 -4
- package/dist/cli/worktree.js.map +1 -1
- package/dist/delivery/adversarial-attack.d.ts +99 -0
- package/dist/delivery/adversarial-attack.d.ts.map +1 -0
- package/dist/delivery/adversarial-attack.js +326 -0
- package/dist/delivery/adversarial-attack.js.map +1 -0
- package/dist/delivery/adversarial-gate.d.ts +120 -0
- package/dist/delivery/adversarial-gate.d.ts.map +1 -0
- package/dist/delivery/adversarial-gate.js +259 -0
- package/dist/delivery/adversarial-gate.js.map +1 -0
- package/dist/delivery/adversarial-sanction.d.ts +52 -0
- package/dist/delivery/adversarial-sanction.d.ts.map +1 -0
- package/dist/delivery/adversarial-sanction.js +134 -0
- package/dist/delivery/adversarial-sanction.js.map +1 -0
- package/dist/delivery/agentic-executor.d.ts +69 -22
- package/dist/delivery/agentic-executor.d.ts.map +1 -1
- package/dist/delivery/agentic-executor.js +152 -8
- package/dist/delivery/agentic-executor.js.map +1 -1
- package/dist/delivery/applier.d.ts +8 -0
- package/dist/delivery/applier.d.ts.map +1 -1
- package/dist/delivery/applier.js +3 -1
- package/dist/delivery/applier.js.map +1 -1
- package/dist/delivery/convergence-loop.d.ts +15 -0
- package/dist/delivery/convergence-loop.d.ts.map +1 -1
- package/dist/delivery/convergence-loop.js.map +1 -1
- package/dist/delivery/criteria-lint.d.ts +74 -0
- package/dist/delivery/criteria-lint.d.ts.map +1 -0
- package/dist/delivery/criteria-lint.js +134 -0
- package/dist/delivery/criteria-lint.js.map +1 -0
- package/dist/delivery/deliver-toggle.d.ts +21 -0
- package/dist/delivery/deliver-toggle.d.ts.map +1 -0
- package/dist/delivery/deliver-toggle.js +40 -0
- package/dist/delivery/deliver-toggle.js.map +1 -0
- package/dist/delivery/delivery-evidence.d.ts +109 -0
- package/dist/delivery/delivery-evidence.d.ts.map +1 -0
- package/dist/delivery/delivery-evidence.js +139 -0
- package/dist/delivery/delivery-evidence.js.map +1 -0
- package/dist/delivery/epic-mission.d.ts +5 -1
- package/dist/delivery/epic-mission.d.ts.map +1 -1
- package/dist/delivery/epic-mission.js +34 -6
- package/dist/delivery/epic-mission.js.map +1 -1
- package/dist/delivery/execution-gate.d.ts.map +1 -1
- package/dist/delivery/execution-gate.js +90 -7
- package/dist/delivery/execution-gate.js.map +1 -1
- package/dist/delivery/index.d.ts +9 -1
- package/dist/delivery/index.d.ts.map +1 -1
- package/dist/delivery/index.js +9 -1
- package/dist/delivery/index.js.map +1 -1
- package/dist/delivery/journey-depth.d.ts +61 -0
- package/dist/delivery/journey-depth.d.ts.map +1 -0
- package/dist/delivery/journey-depth.js +91 -0
- package/dist/delivery/journey-depth.js.map +1 -0
- package/dist/delivery/master-pipeline.d.ts +50 -0
- package/dist/delivery/master-pipeline.d.ts.map +1 -0
- package/dist/delivery/master-pipeline.js +52 -0
- package/dist/delivery/master-pipeline.js.map +1 -0
- package/dist/delivery/mission-acceptance.d.ts.map +1 -1
- package/dist/delivery/mission-acceptance.js +54 -2
- package/dist/delivery/mission-acceptance.js.map +1 -1
- package/dist/delivery/orchestrated-mission.d.ts +4 -1
- package/dist/delivery/orchestrated-mission.d.ts.map +1 -1
- package/dist/delivery/orchestrated-mission.js +18 -9
- package/dist/delivery/orchestrated-mission.js.map +1 -1
- package/dist/delivery/plan-check.d.ts +1 -0
- package/dist/delivery/plan-check.d.ts.map +1 -1
- package/dist/delivery/plan-check.js +48 -0
- package/dist/delivery/plan-check.js.map +1 -1
- package/dist/delivery/task-orchestrator.d.ts +16 -9
- package/dist/delivery/task-orchestrator.d.ts.map +1 -1
- package/dist/delivery/task-orchestrator.js +4 -2
- package/dist/delivery/task-orchestrator.js.map +1 -1
- package/dist/delivery/task-workspace.d.ts +35 -5
- package/dist/delivery/task-workspace.d.ts.map +1 -1
- package/dist/delivery/task-workspace.js +53 -7
- package/dist/delivery/task-workspace.js.map +1 -1
- package/dist/delivery/test-oracle-additive.d.ts +26 -6
- package/dist/delivery/test-oracle-additive.d.ts.map +1 -1
- package/dist/delivery/test-oracle-additive.js +40 -15
- package/dist/delivery/test-oracle-additive.js.map +1 -1
- package/dist/delivery/user-validation.d.ts +14 -0
- package/dist/delivery/user-validation.d.ts.map +1 -1
- package/dist/delivery/user-validation.js +103 -9
- package/dist/delivery/user-validation.js.map +1 -1
- package/dist/delivery/verifier-ladder.d.ts.map +1 -1
- package/dist/delivery/verifier-ladder.js +24 -6
- package/dist/delivery/verifier-ladder.js.map +1 -1
- package/dist/inference/analysis.d.ts +138 -0
- package/dist/inference/analysis.d.ts.map +1 -0
- package/dist/inference/analysis.js +243 -0
- package/dist/inference/analysis.js.map +1 -0
- package/dist/inference/probe.d.ts +85 -0
- package/dist/inference/probe.d.ts.map +1 -0
- package/dist/inference/probe.js +403 -0
- package/dist/inference/probe.js.map +1 -0
- package/dist/models/types.d.ts.map +1 -1
- package/dist/models/types.js +45 -18
- package/dist/models/types.js.map +1 -1
- package/dist/self-tuning/profiles/qwen38.d.ts +17 -8
- package/dist/self-tuning/profiles/qwen38.d.ts.map +1 -1
- package/dist/self-tuning/profiles/qwen38.js +21 -11
- package/dist/self-tuning/profiles/qwen38.js.map +1 -1
- package/dist/utils/model-slots.d.ts +11 -5
- package/dist/utils/model-slots.d.ts.map +1 -1
- package/dist/utils/model-slots.js +11 -5
- package/dist/utils/model-slots.js.map +1 -1
- package/docs/INDEX.md +1 -0
- package/docs/guides/CAPACITY_POLICY.md +24 -0
- package/docs/guides/INFERENCE_HEALTH.md +184 -0
- package/docs/guides/PROXY.md +1 -0
- package/docs/guides/QWEN38_EXL3.md +268 -0
- package/docs/plans/hlg-master-architecture-uplift-2026-09-24.md +67 -0
- package/docs/reference/CONFIGURATION.md +10 -1
- package/docs/reference/CONFIGURATION_REFERENCE.md +14 -0
- package/package.json +2 -2
- package/scripts/lib/llama-upstream.sh +7 -1
- package/src/policies/enforcers/__pycache__/_common.cpython-312.pyc +0 -0
- package/src/policies/enforcers/__pycache__/expert_review_required.cpython-312.pyc +0 -0
- package/src/policies/enforcers/__pycache__/quality_metrics_gate.cpython-312.pyc +0 -0
- package/src/policies/enforcers/expert_review_required.py +1 -4
- package/templates/hooks/__pycache__/deliver_autoroute.cpython-312.pyc +0 -0
- package/tools/agents/scripts/__pycache__/toolcall_path_normalizer.cpython-312.pyc +0 -0
- package/tools/agents/scripts/anthropic_proxy.py +374 -16
- package/tools/agents/scripts/confidence_escalation.py +4 -2
- package/tools/agents/scripts/project_telemetry.py +1 -0
- package/tools/agents/scripts/tool_risk.py +1 -0
- package/tools/agents/scripts/tool_risk_calibrate.py +1 -0
- package/tools/agents/scripts/toolcall_path_normalizer.py +1 -0
- package/tools/agents/tests/test_anthropic_proxy_streaming.py +52 -1
- package/tools/agents/tests/test_confidence_escalation.py +3 -2
- package/tools/agents/tests/test_count_tokens_scale_per_session.py +126 -0
- package/tools/agents/tests/test_expert_review_pr_scope.py +10 -11
- package/tools/agents/tests/test_lockstep_escalation.py +324 -0
- package/tools/agents/tests/test_thinking_template_kwargs.py +10 -4
package/dist/cli/deliver.js
CHANGED
|
@@ -278,6 +278,8 @@ import { createEscalationController, defaultEscalationLadder, DEFAULT_STAGNATION
|
|
|
278
278
|
import { FilePracticeStore, defaultPracticePath, extractKeywords, retrievePracticesSemantic, } from '../delivery/practice.js';
|
|
279
279
|
import { detectRungs, mergeRedetectedRungs, runLadder, runTieredLadder, tierOf, TIER_ORDER, demoteBaselineFailures, baselineRegressions } from '../delivery/verifier-ladder.js';
|
|
280
280
|
import { recordGateEvidence, gateOutcomesFromResult } from '../delivery/gate-evidence.js';
|
|
281
|
+
import { resolveAdversarialGate, runAdversarialGate } from '../delivery/adversarial-gate.js';
|
|
282
|
+
import { resolveMasterPipeline, formatMasterPipelineLine } from '../delivery/master-pipeline.js';
|
|
281
283
|
import { runDeployDevLadder } from '../delivery/deploy-dev-gate.js';
|
|
282
284
|
import { commitPushAndWatch } from '../delivery/ci-watcher.js';
|
|
283
285
|
import { snapshotTree, restoreTreeScoped, disposeSnapshot } from '../delivery/snapshot.js';
|
|
@@ -1495,6 +1497,25 @@ async function runDeliver(instruction, options) {
|
|
|
1495
1497
|
console.log(chalk.cyan('⚖ acceptance judge on (verification rail; UAP_DELIVER_ACCEPTANCE=0 to disable)'));
|
|
1496
1498
|
}
|
|
1497
1499
|
}
|
|
1500
|
+
// Master-pipeline stage readout — the Harness/Loop/Graph composition this
|
|
1501
|
+
// command runs by default: worktree-isolated parallel fan-out → evidence-
|
|
1502
|
+
// gated convergence loops → state-hash read dedup → adversarial red-team
|
|
1503
|
+
// gate. Resolved once via delivery/master-pipeline.ts (which mirrors each
|
|
1504
|
+
// stage's own env > .uap.json > default precedence) and surfaced in the
|
|
1505
|
+
// startup banner and the dry-run plan, so what is printed is what the
|
|
1506
|
+
// run gets.
|
|
1507
|
+
const deliverCfgEarly = (() => {
|
|
1508
|
+
try {
|
|
1509
|
+
return (loadUapConfigRaw(projectRoot) ?? {}).deliver;
|
|
1510
|
+
}
|
|
1511
|
+
catch {
|
|
1512
|
+
return undefined;
|
|
1513
|
+
}
|
|
1514
|
+
})();
|
|
1515
|
+
const masterPipeline = resolveMasterPipeline(deliverCfgEarly);
|
|
1516
|
+
if (!options.dryRun) {
|
|
1517
|
+
console.log(chalk.cyan(`⇒ master pipeline: ${formatMasterPipelineLine(masterPipeline)}`));
|
|
1518
|
+
}
|
|
1498
1519
|
// `--optimize` turns on every convergence aid at once. Deploy queueing is
|
|
1499
1520
|
// deliberately excluded — committing applied files is a side effect the
|
|
1500
1521
|
// user must opt into explicitly.
|
|
@@ -1880,6 +1901,12 @@ async function runDeliver(instruction, options) {
|
|
|
1880
1901
|
branch: watchCi ? currentBranch(projectRoot) : null,
|
|
1881
1902
|
gates: rungs.map((r) => ({ id: r.id, name: r.name, required: r.required, tier: tierOf(r) })),
|
|
1882
1903
|
selfGate: needsSelfGate,
|
|
1904
|
+
masterPipeline: {
|
|
1905
|
+
parallelTasks: masterPipeline.parallelTasks,
|
|
1906
|
+
stateHash: masterPipeline.stateHash,
|
|
1907
|
+
stateHashMinBytes: masterPipeline.stateHashMinBytes,
|
|
1908
|
+
adversarialGate: masterPipeline.adversarial.enabled ? masterPipeline.adversarial.maxRounds : 0,
|
|
1909
|
+
},
|
|
1883
1910
|
};
|
|
1884
1911
|
if (options.json) {
|
|
1885
1912
|
console.log(JSON.stringify(summary, null, 2));
|
|
@@ -1898,6 +1925,7 @@ async function runDeliver(instruction, options) {
|
|
|
1898
1925
|
console.log(` HALO tracing: ${summary.halo ? 'on' : 'off'}`);
|
|
1899
1926
|
console.log(` Coordination: ${summary.coordinate ? 'on' : 'off'}`);
|
|
1900
1927
|
console.log(` Deploy queue on success: ${summary.deploy ? 'on' : 'off'}`);
|
|
1928
|
+
console.log(` Master pipeline: ${formatMasterPipelineLine(masterPipeline)}`);
|
|
1901
1929
|
console.log(` Test protection: ${summary.protectTests ? `on (${summary.protectedTestFiles} pre-existing test/oracle file(s))` : 'off'}`);
|
|
1902
1930
|
console.log(` IaC protection: ${summary.protectIac ? 'on (Dockerfile/compose/terraform writes blocked)' : 'off (permissive — IaC writes allowed)'}`);
|
|
1903
1931
|
console.log(` Guidance file: ${summary.guidanceFile ?? 'none (mission runs unattended)'}`);
|
|
@@ -2139,6 +2167,12 @@ async function runDeliver(instruction, options) {
|
|
|
2139
2167
|
// sweep record real written paths here; the applier below drains them into
|
|
2140
2168
|
// ApplyResult.filesWritten so history[].filesApplied is truthful again.
|
|
2141
2169
|
const agenticWriteLedger = new Set();
|
|
2170
|
+
// Hoisted shared protection set (HLG stage 5 hardening): the adversarial
|
|
2171
|
+
// gate's breaching tests are written AFTER this t0 snapshot, so a repair
|
|
2172
|
+
// could delete them unless the set grows. Both executors hold THIS
|
|
2173
|
+
// reference and check membership per write, so the stage's onBreach hook
|
|
2174
|
+
// can extend it before reconvergence runs.
|
|
2175
|
+
const sharedProtectedFiles = options.protectTests !== false ? snapshotProtection(projectRoot).protectedFiles : new Set();
|
|
2142
2176
|
const executor = agentic
|
|
2143
2177
|
? createAgenticExecutor(model, {
|
|
2144
2178
|
projectRoot,
|
|
@@ -2149,7 +2183,7 @@ async function runDeliver(instruction, options) {
|
|
|
2149
2183
|
contractFiles: contractLock,
|
|
2150
2184
|
writeLedger: agenticWriteLedger,
|
|
2151
2185
|
// Block oracle tampering: protected test files are read-only to the agent.
|
|
2152
|
-
protectedFiles:
|
|
2186
|
+
protectedFiles: sharedProtectedFiles,
|
|
2153
2187
|
// Block gate-config / IaC rigging in the agentic path too (it bypasses
|
|
2154
2188
|
// the file-block applier where this protection otherwise lives).
|
|
2155
2189
|
protectGateConfigs: options.protectTests !== false,
|
|
@@ -2171,7 +2205,7 @@ async function runDeliver(instruction, options) {
|
|
|
2171
2205
|
contextTokenBudget: sessionBudget,
|
|
2172
2206
|
contractFiles: contractLock,
|
|
2173
2207
|
writeLedger: agenticWriteLedger,
|
|
2174
|
-
protectedFiles:
|
|
2208
|
+
protectedFiles: sharedProtectedFiles,
|
|
2175
2209
|
protectGateConfigs: options.protectTests !== false,
|
|
2176
2210
|
allowBash: options.allowBash === true || process.env.UAP_DELIVER_ALLOW_BASH === '1',
|
|
2177
2211
|
onEvent: (e) => console.log(chalk.dim(` [repair r${e.round} ${e.kind}${e.tool ? `:${e.tool}` : ''}] ${e.detail ?? ''}`)),
|
|
@@ -3847,6 +3881,81 @@ async function runDeliver(instruction, options) {
|
|
|
3847
3881
|
disposeSnapshot(regressSnapshot);
|
|
3848
3882
|
}
|
|
3849
3883
|
}
|
|
3884
|
+
// Adversarial red-team gate (HLG stage 5): before the verdict is accepted,
|
|
3885
|
+
// a skeptical verifier attacks the converged patch with edge-case tests
|
|
3886
|
+
// designed to break it. A breach routes back into the convergence loop as
|
|
3887
|
+
// ordinary gate evidence (bounded rounds); only a surviving patch proceeds
|
|
3888
|
+
// to the outcome/evidence bookkeeping below. Placed AFTER keep-best so the
|
|
3889
|
+
// attack targets the same tree the rollback rail settled on, and BEFORE
|
|
3890
|
+
// evidence recording so the artifact reflects the post-attack state.
|
|
3891
|
+
// Skipped on alreadyDelivered (no patch to attack) and on --dry-run.
|
|
3892
|
+
// Default ON; escape hatch: UAP_DELIVER_ADVERSARIAL_GATE=0 or
|
|
3893
|
+
// `.uap.json` deliver.adversarialGate=false — same path deliver.parallelTasks
|
|
3894
|
+
// resolves through.
|
|
3895
|
+
const adversarialSettings = resolveAdversarialGate(cfgRaw.deliver?.adversarialGate);
|
|
3896
|
+
if (result.success && !result.alreadyDelivered && adversarialSettings.enabled && !options.dryRun) {
|
|
3897
|
+
const adversarial = await runAdversarialGate({
|
|
3898
|
+
instruction,
|
|
3899
|
+
projectRoot,
|
|
3900
|
+
rungs,
|
|
3901
|
+
// Gate-time redetection: `rungs` was detected at t0, so a mission that
|
|
3902
|
+
// CREATED its test gate (greenfield) would no-surface forever. Merge
|
|
3903
|
+
// the fresh detection with the same policy the loop's mid-mission
|
|
3904
|
+
// redetection and the combined-tree verification use.
|
|
3905
|
+
redetectRungs: () => {
|
|
3906
|
+
try {
|
|
3907
|
+
return mergeRedetectedRungs(rungs, detectRungs(projectRoot), loopConfig.redetectFilter);
|
|
3908
|
+
}
|
|
3909
|
+
catch {
|
|
3910
|
+
return rungs; // detection unavailable — attack with the t0 rungs
|
|
3911
|
+
}
|
|
3912
|
+
},
|
|
3913
|
+
// Defense in depth for the repair: the executors' protected set was
|
|
3914
|
+
// snapshotted before the breaching tests existed — add them so the
|
|
3915
|
+
// repair agent structurally CANNOT delete/skip/weaken them (the gate's
|
|
3916
|
+
// own post-repair verification remains the enforcing floor).
|
|
3917
|
+
onBreach: (breach) => {
|
|
3918
|
+
for (const rel of breach.testFiles)
|
|
3919
|
+
sharedProtectedFiles.add(rel.toLowerCase());
|
|
3920
|
+
},
|
|
3921
|
+
// Authoring judges text; keep it on the blind executor even when the
|
|
3922
|
+
// loop's executor is agentic (same rule as the critic/judge).
|
|
3923
|
+
executor: jsonBlindExecutor,
|
|
3924
|
+
settings: adversarialSettings,
|
|
3925
|
+
initial: result,
|
|
3926
|
+
reconverge: (prompt) => new ConvergenceLoop({ ...loopConfig, baselineCheck: false, resumeFrom: undefined, onCheckpoint: undefined }, executor, seams).deliver(prompt),
|
|
3927
|
+
note: (line) => console.log(chalk.dim(` ${line}`)),
|
|
3928
|
+
});
|
|
3929
|
+
result = adversarial.result;
|
|
3930
|
+
result.adversarial = {
|
|
3931
|
+
status: adversarial.status,
|
|
3932
|
+
rounds: adversarial.rounds.length,
|
|
3933
|
+
authored: adversarial.authored,
|
|
3934
|
+
ran: adversarial.ran,
|
|
3935
|
+
failed: adversarial.failed,
|
|
3936
|
+
summary: adversarial.summary,
|
|
3937
|
+
};
|
|
3938
|
+
if (!options.json) {
|
|
3939
|
+
const color = adversarial.status === 'breached'
|
|
3940
|
+
? chalk.red
|
|
3941
|
+
: adversarial.status === 'survived'
|
|
3942
|
+
? chalk.green
|
|
3943
|
+
: chalk.dim;
|
|
3944
|
+
console.log(color(` 🛡 ${adversarial.summary}`));
|
|
3945
|
+
}
|
|
3946
|
+
}
|
|
3947
|
+
else if (result.success && !result.alreadyDelivered && !adversarialSettings.enabled) {
|
|
3948
|
+
// Record the hatch on the result so the JSON outcome and evidence say the
|
|
3949
|
+
// stage was deliberately off, not silently absent.
|
|
3950
|
+
result.adversarial = {
|
|
3951
|
+
status: 'disabled',
|
|
3952
|
+
rounds: 0,
|
|
3953
|
+
authored: 0,
|
|
3954
|
+
ran: 0,
|
|
3955
|
+
failed: 0,
|
|
3956
|
+
summary: 'adversarial gate: disabled (UAP_DELIVER_ADVERSARIAL_GATE=0 or deliver.adversarialGate=false)',
|
|
3957
|
+
};
|
|
3958
|
+
}
|
|
3850
3959
|
// Surface the observed stop on the result itself: the JSON output (and the
|
|
3851
3960
|
// MCP deliver tool reading it) is what the NEXT agent decides from, and a
|
|
3852
3961
|
// stopped run that prints as a plain failure gets relaunched instead of
|
|
@@ -3891,6 +4000,20 @@ async function runDeliver(instruction, options) {
|
|
|
3891
4000
|
if (result.success) {
|
|
3892
4001
|
try {
|
|
3893
4002
|
const gates = gateOutcomesFromResult(result, rungs);
|
|
4003
|
+
// HLG stage 5 telemetry: bind the adversarial attack outcome into the
|
|
4004
|
+
// same artifact as the run's other gate evidence, so evidence consumers
|
|
4005
|
+
// see what the red team did (tests authored / ran / failed / survived).
|
|
4006
|
+
// 'disabled' is recorded too — an absent entry must never be ambiguous
|
|
4007
|
+
// with a skipped one.
|
|
4008
|
+
if (result.adversarial) {
|
|
4009
|
+
gates.push({
|
|
4010
|
+
name: 'adversarial-gate',
|
|
4011
|
+
command: 'uap deliver adversarial red-team gate',
|
|
4012
|
+
exitCode: 0,
|
|
4013
|
+
outputTail: result.adversarial.summary,
|
|
4014
|
+
at: new Date().toISOString(),
|
|
4015
|
+
});
|
|
4016
|
+
}
|
|
3894
4017
|
const evidencePath = recordGateEvidence(projectRoot, gates, { runId });
|
|
3895
4018
|
if (!options.json)
|
|
3896
4019
|
console.log(chalk.dim(` gate evidence: ${evidencePath}`));
|
|
@@ -3899,6 +4022,29 @@ async function runDeliver(instruction, options) {
|
|
|
3899
4022
|
console.warn(chalk.yellow(` ⚠ gate evidence not recorded: ${e.message}`));
|
|
3900
4023
|
}
|
|
3901
4024
|
}
|
|
4025
|
+
else if (result.adversarial) {
|
|
4026
|
+
// Breached runs record their adversarial evidence TOO (C-stage review):
|
|
4027
|
+
// the stage ran and REJECTED the patch, so an absent entry would be
|
|
4028
|
+
// ambiguous with "stage skipped". Nonzero exitCode — the enforcer only
|
|
4029
|
+
// accepts 0, so this artifact can never masquerade as a pass. Fail-soft,
|
|
4030
|
+
// same as the success path (a dirty post-breach tree simply warns).
|
|
4031
|
+
try {
|
|
4032
|
+
const evidencePath = recordGateEvidence(projectRoot, [
|
|
4033
|
+
{
|
|
4034
|
+
name: 'adversarial-gate',
|
|
4035
|
+
command: 'uap deliver adversarial red-team gate',
|
|
4036
|
+
exitCode: 1,
|
|
4037
|
+
outputTail: result.adversarial.summary,
|
|
4038
|
+
at: new Date().toISOString(),
|
|
4039
|
+
},
|
|
4040
|
+
], { runId });
|
|
4041
|
+
if (!options.json)
|
|
4042
|
+
console.log(chalk.dim(` gate evidence: ${evidencePath}`));
|
|
4043
|
+
}
|
|
4044
|
+
catch (e) {
|
|
4045
|
+
console.warn(chalk.yellow(` ⚠ gate evidence not recorded: ${e.message}`));
|
|
4046
|
+
}
|
|
4047
|
+
}
|
|
3902
4048
|
// Close the HALO observe→learn loop: mine the trace tail for recurring
|
|
3903
4049
|
// failure patterns after every run — no operator step required.
|
|
3904
4050
|
if (isHaloTracingEnabled()) {
|