@miller-tech/uap 2.1.7 → 2.11.1

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 (143) hide show
  1. package/README.md +7 -6
  2. package/config/capacity-policy.json +32 -0
  3. package/config/classify-thresholds.json +9 -0
  4. package/config/supervise-policy.json +13 -0
  5. package/dist/.tsbuildinfo +1 -1
  6. package/dist/bin/cli.js +87 -2
  7. package/dist/bin/cli.js.map +1 -1
  8. package/dist/capacity/policy.d.ts +67 -0
  9. package/dist/capacity/policy.d.ts.map +1 -0
  10. package/dist/capacity/policy.js +133 -0
  11. package/dist/capacity/policy.js.map +1 -0
  12. package/dist/capacity/probe.d.ts +23 -0
  13. package/dist/capacity/probe.d.ts.map +1 -0
  14. package/dist/capacity/probe.js +93 -0
  15. package/dist/capacity/probe.js.map +1 -0
  16. package/dist/classify/baseline.d.ts +24 -0
  17. package/dist/classify/baseline.d.ts.map +1 -0
  18. package/dist/classify/baseline.js +140 -0
  19. package/dist/classify/baseline.js.map +1 -0
  20. package/dist/classify/index.d.ts +30 -0
  21. package/dist/classify/index.d.ts.map +1 -0
  22. package/dist/classify/index.js +84 -0
  23. package/dist/classify/index.js.map +1 -0
  24. package/dist/classify/shadow.d.ts +34 -0
  25. package/dist/classify/shadow.d.ts.map +1 -0
  26. package/dist/classify/shadow.js +33 -0
  27. package/dist/classify/shadow.js.map +1 -0
  28. package/dist/classify/types.d.ts +64 -0
  29. package/dist/classify/types.d.ts.map +1 -0
  30. package/dist/classify/types.js +37 -0
  31. package/dist/classify/types.js.map +1 -0
  32. package/dist/cli/classify.d.ts +24 -0
  33. package/dist/cli/classify.d.ts.map +1 -0
  34. package/dist/cli/classify.js +94 -0
  35. package/dist/cli/classify.js.map +1 -0
  36. package/dist/cli/deliver.d.ts.map +1 -1
  37. package/dist/cli/deliver.js +26 -0
  38. package/dist/cli/deliver.js.map +1 -1
  39. package/dist/cli/doctor.d.ts +9 -0
  40. package/dist/cli/doctor.d.ts.map +1 -0
  41. package/dist/cli/doctor.js +49 -0
  42. package/dist/cli/doctor.js.map +1 -0
  43. package/dist/cli/review.d.ts +12 -0
  44. package/dist/cli/review.d.ts.map +1 -0
  45. package/dist/cli/review.js +118 -0
  46. package/dist/cli/review.js.map +1 -0
  47. package/dist/cli/supervise.d.ts +8 -0
  48. package/dist/cli/supervise.d.ts.map +1 -0
  49. package/dist/cli/supervise.js +76 -0
  50. package/dist/cli/supervise.js.map +1 -0
  51. package/dist/delivery/convergence-loop.d.ts +8 -0
  52. package/dist/delivery/convergence-loop.d.ts.map +1 -1
  53. package/dist/delivery/convergence-loop.js +1 -0
  54. package/dist/delivery/convergence-loop.js.map +1 -1
  55. package/dist/delivery/delivery-result.d.ts.map +1 -1
  56. package/dist/delivery/delivery-result.js +5 -0
  57. package/dist/delivery/delivery-result.js.map +1 -1
  58. package/dist/delivery/gate-evidence.d.ts +143 -0
  59. package/dist/delivery/gate-evidence.d.ts.map +1 -0
  60. package/dist/delivery/gate-evidence.js +239 -0
  61. package/dist/delivery/gate-evidence.js.map +1 -0
  62. package/dist/delivery/index.d.ts +1 -0
  63. package/dist/delivery/index.d.ts.map +1 -1
  64. package/dist/delivery/index.js +1 -0
  65. package/dist/delivery/index.js.map +1 -1
  66. package/dist/evals/routing-corpus.d.ts +35 -0
  67. package/dist/evals/routing-corpus.d.ts.map +1 -0
  68. package/dist/evals/routing-corpus.js +142 -0
  69. package/dist/evals/routing-corpus.js.map +1 -0
  70. package/dist/evals/routing-eval.d.ts +104 -0
  71. package/dist/evals/routing-eval.d.ts.map +1 -0
  72. package/dist/evals/routing-eval.js +231 -0
  73. package/dist/evals/routing-eval.js.map +1 -0
  74. package/dist/evals/tfidf.d.ts +35 -0
  75. package/dist/evals/tfidf.d.ts.map +1 -0
  76. package/dist/evals/tfidf.js +132 -0
  77. package/dist/evals/tfidf.js.map +1 -0
  78. package/dist/review/prepass.d.ts +88 -0
  79. package/dist/review/prepass.d.ts.map +1 -0
  80. package/dist/review/prepass.js +428 -0
  81. package/dist/review/prepass.js.map +1 -0
  82. package/dist/review/visual-captures.d.ts +60 -0
  83. package/dist/review/visual-captures.d.ts.map +1 -0
  84. package/dist/review/visual-captures.js +222 -0
  85. package/dist/review/visual-captures.js.map +1 -0
  86. package/dist/supervise/assess.d.ts +73 -0
  87. package/dist/supervise/assess.d.ts.map +1 -0
  88. package/dist/supervise/assess.js +215 -0
  89. package/dist/supervise/assess.js.map +1 -0
  90. package/dist/supervise/config.d.ts +13 -0
  91. package/dist/supervise/config.d.ts.map +1 -0
  92. package/dist/supervise/config.js +81 -0
  93. package/dist/supervise/config.js.map +1 -0
  94. package/dist/supervise/loop.d.ts +78 -0
  95. package/dist/supervise/loop.d.ts.map +1 -0
  96. package/dist/supervise/loop.js +311 -0
  97. package/dist/supervise/loop.js.map +1 -0
  98. package/dist/supervise/observe.d.ts +31 -0
  99. package/dist/supervise/observe.d.ts.map +1 -0
  100. package/dist/supervise/observe.js +172 -0
  101. package/dist/supervise/observe.js.map +1 -0
  102. package/dist/supervise/policy.d.ts +16 -0
  103. package/dist/supervise/policy.d.ts.map +1 -0
  104. package/dist/supervise/policy.js +147 -0
  105. package/dist/supervise/policy.js.map +1 -0
  106. package/dist/supervise/types.d.ts +109 -0
  107. package/dist/supervise/types.d.ts.map +1 -0
  108. package/dist/supervise/types.js +11 -0
  109. package/dist/supervise/types.js.map +1 -0
  110. package/docs/INDEX.md +15 -4
  111. package/docs/architecture/adr/0001-automode-risk-floor.md +75 -0
  112. package/docs/architecture/adr/0002-evidence-bound-ship.md +81 -0
  113. package/docs/guides/CAPACITY_POLICY.md +99 -0
  114. package/docs/performance/automode-risk-calibration.md +72 -0
  115. package/docs/performance/reliability-ladder.md +78 -0
  116. package/docs/plans/system1-uplift-2026-09-18.md +190 -0
  117. package/docs/reference/automode-risk.md +134 -0
  118. package/docs/reference/evidence-bound-ship.md +146 -0
  119. package/docs/reference/review-prepass.md +77 -0
  120. package/docs/reference/routing-evals.md +71 -0
  121. package/docs/reference/semantic-supervisor.md +140 -0
  122. package/docs/reference/system1-classifier.md +103 -0
  123. package/docs/reference/visual-captures.md +113 -0
  124. package/package.json +5 -3
  125. package/src/policies/enforcers/__pycache__/_common.cpython-312.pyc +0 -0
  126. package/src/policies/enforcers/__pycache__/expert_review_required.cpython-312.pyc +0 -0
  127. package/src/policies/enforcers/__pycache__/quality_metrics_gate.cpython-312.pyc +0 -0
  128. package/src/policies/enforcers/enforcement_self_protect.py +25 -2
  129. package/src/policies/enforcers/evidence_bound_ship.py +257 -0
  130. package/src/policies/enforcers/expert_review_required.py +120 -0
  131. package/src/policies/schemas/policies/evidence-bound-ship.md +106 -0
  132. package/src/policies/schemas/policies/visual-verification.md +8 -0
  133. package/templates/hooks/__pycache__/deliver_autoroute.cpython-312.pyc +0 -0
  134. package/tools/agents/scripts/__pycache__/toolcall_path_normalizer.cpython-312.pyc +0 -0
  135. package/tools/agents/scripts/anthropic_proxy.py +782 -19
  136. package/tools/agents/scripts/project_telemetry.py +52 -0
  137. package/tools/agents/scripts/tool_risk.py +789 -0
  138. package/tools/agents/scripts/tool_risk_calibrate.py +255 -0
  139. package/tools/agents/tests/fixtures/tool_risk_cases.json +124 -0
  140. package/tools/agents/tests/test_enforcer_escape_hatches.py +13 -0
  141. package/tools/agents/tests/test_gate_evidence.py +56 -0
  142. package/tools/agents/tests/test_tool_risk.py +521 -0
  143. package/tools/agents/tests/test_verbatim_compact.py +629 -0
@@ -0,0 +1,222 @@
1
+ /**
2
+ * Before/after visual captures bound to a review (uplift 0.3).
3
+ *
4
+ * A diff that touches UI files is not reviewable from code alone — the change
5
+ * is to what the user SEES. This module records capture pairs (produced by
6
+ * the agent via agent-browser for web surfaces, tuistory/pty-capture for
7
+ * terminal surfaces) into a sibling artifact and validates that a UI diff is
8
+ * covered by fresh, complete pairs before the ship gate opens.
9
+ *
10
+ * Artifact: .uap/reviews/<branch-slug>.captures.json — a SIBLING of the
11
+ * review artifact, for the same reason the pre-pass is one (see
12
+ * src/review/prepass.ts): the expert-review enforcer treats the existence of
13
+ * <slug>.json as "a review happened", so nothing advisory may create it.
14
+ * Consolidation embeds the capture paths into the real review artifact.
15
+ *
16
+ * The gate is deterministic pairing/freshness, not judgment: the model (or
17
+ * human) looks at the captures; the policy only proves they exist, form
18
+ * before/after pairs, and postdate the newest UI change on disk.
19
+ */
20
+ import { execFileSync } from 'child_process';
21
+ import { existsSync, mkdirSync, readFileSync, renameSync, statSync, writeFileSync, } from 'fs';
22
+ import { join, relative, resolve } from 'path';
23
+ import { branchSlug } from './prepass.js';
24
+ /** UI surface definition — mirrored (with matching case handling) by
25
+ * UI_EXT/UI_DIR_PREFIXES in src/policies/enforcers/expert_review_required.py
26
+ * and visual_verification.py. Keep all three in sync; the parity test in
27
+ * test/visual-captures.test.ts pins the intended surface. */
28
+ export const UI_EXT = new Set([
29
+ '.css', '.scss', '.sass', '.less',
30
+ '.tsx', '.jsx', '.vue', '.svelte', '.html', '.astro',
31
+ ]);
32
+ export const UI_DIR_PREFIXES = ['web/', 'src/dashboard/', 'public/'];
33
+ function git(projectDir, args) {
34
+ try {
35
+ const out = execFileSync('git', args, {
36
+ cwd: projectDir,
37
+ encoding: 'utf-8',
38
+ stdio: ['pipe', 'pipe', 'pipe'],
39
+ });
40
+ return out.trim();
41
+ }
42
+ catch {
43
+ return null; // fail-soft: non-git/detached/no-base states disable the gate
44
+ }
45
+ }
46
+ export function isUiFile(file) {
47
+ const lower = file.toLowerCase();
48
+ const dot = lower.lastIndexOf('.');
49
+ if (dot >= 0 && UI_EXT.has(lower.slice(dot)))
50
+ return true;
51
+ return UI_DIR_PREFIXES.some((p) => lower.startsWith(p));
52
+ }
53
+ /** Files changed vs the upstream base (origin/master, origin/main, master,
54
+ * main — first that resolves), or null when no base exists (fail-open). */
55
+ export function changedFilesVsBase(projectDir) {
56
+ for (const base of ['origin/master', 'origin/main', 'master', 'main']) {
57
+ const out = git(projectDir, ['diff', '--name-only', `${base}...HEAD`]);
58
+ if (out !== null)
59
+ return out.split('\n').map((l) => l.trim()).filter(Boolean);
60
+ }
61
+ return null;
62
+ }
63
+ export function capturesArtifactPath(projectDir, branch) {
64
+ return join(projectDir, '.uap', 'reviews', `${branchSlug(branch)}.captures.json`);
65
+ }
66
+ function readArtifact(path) {
67
+ try {
68
+ const data = JSON.parse(readFileSync(path, 'utf-8'));
69
+ if (typeof data !== 'object' || data === null)
70
+ return null;
71
+ // Normalize: a hand-edited artifact with a non-array `captures` must not
72
+ // crash validation or corrupt the file on the next `add` (spreading a
73
+ // string yields its chars). Unknown entries are dropped, not trusted.
74
+ const raw = data.captures;
75
+ return {
76
+ ...data,
77
+ captures: Array.isArray(raw)
78
+ ? raw.filter((c) => typeof c === 'object' && c !== null)
79
+ : [],
80
+ };
81
+ }
82
+ catch {
83
+ return null; // missing or malformed — treated as absent by callers
84
+ }
85
+ }
86
+ /** Project-relative normalization: absolute paths under the project are
87
+ * relativized; anything escaping the project is refused by the caller-visible
88
+ * existence check below (we never write paths we cannot verify). */
89
+ function toProjectRelative(projectDir, p) {
90
+ const abs = resolve(projectDir, p);
91
+ return relative(projectDir, abs);
92
+ }
93
+ /**
94
+ * Register one before/after capture pair for the current branch.
95
+ * Returns the artifact path, or an error string when the pair is unusable.
96
+ */
97
+ export function recordCapture(projectDir, entry) {
98
+ const tool = entry.tool.trim();
99
+ if (!tool)
100
+ return { error: 'capture tool is required (agent-browser, tuistory, pty-capture, ...)' };
101
+ const before = toProjectRelative(projectDir, entry.before);
102
+ const after = toProjectRelative(projectDir, entry.after);
103
+ for (const [label, rel] of [['before', before], ['after', after]]) {
104
+ // `..` alone or as a leading segment escapes the project; a leading `..`
105
+ // inside a filename (`..assets/x.png`) is legitimate and stays allowed.
106
+ if (rel === '..' || rel.startsWith('../')) {
107
+ return { error: `${label} capture escapes the project: ${label === 'before' ? entry.before : entry.after}` };
108
+ }
109
+ if (!existsSync(join(projectDir, rel))) {
110
+ return { error: `${label} capture not found: ${rel}` };
111
+ }
112
+ }
113
+ const branch = git(projectDir, ['rev-parse', '--abbrev-ref', 'HEAD']);
114
+ if (!branch || branch === 'HEAD')
115
+ return { error: 'not on a branch (detached/non-git)' };
116
+ const head = git(projectDir, ['rev-parse', 'HEAD']);
117
+ const changed = changedFilesVsBase(projectDir) ?? [];
118
+ const uiFiles = changed.filter(isUiFile);
119
+ const path = capturesArtifactPath(projectDir, branch);
120
+ const existing = readArtifact(path);
121
+ const now = new Date().toISOString();
122
+ const artifact = {
123
+ branch,
124
+ head,
125
+ ui_files: uiFiles,
126
+ captures: [
127
+ ...(existing?.captures ?? []),
128
+ { tool, before, after, ...(entry.note ? { note: entry.note } : {}), at: now },
129
+ ],
130
+ at: now,
131
+ };
132
+ mkdirSync(join(projectDir, '.uap', 'reviews'), { recursive: true });
133
+ // Atomic write: a crash mid-write must not leave a torn artifact that a
134
+ // later validation half-reads.
135
+ const tmp = `${path}.${process.pid}.tmp`;
136
+ writeFileSync(tmp, JSON.stringify(artifact, null, 2));
137
+ renameSync(tmp, path);
138
+ return { path, artifact };
139
+ }
140
+ const STALENESS_GRACE_S = 1; // same 1s grace the commit-time visual enforcer uses
141
+ /**
142
+ * Validate that a UI diff is covered by complete, fresh capture pairs.
143
+ * Fail-open only when no base is resolvable (non-git/detached), matching the
144
+ * expert-review enforcer's posture.
145
+ */
146
+ export function validateCaptures(projectDir) {
147
+ const branch = git(projectDir, ['rev-parse', '--abbrev-ref', 'HEAD']);
148
+ const artifactPath = capturesArtifactPath(projectDir, branch ?? 'HEAD');
149
+ const base = {
150
+ required: false,
151
+ ok: true,
152
+ reasons: [],
153
+ uiFiles: [],
154
+ artifactPath,
155
+ captures: [],
156
+ };
157
+ // Detached HEAD: the enforcer fails open there (no branch → no slug), and
158
+ // the advisory CLI must not claim otherwise.
159
+ if (!branch || branch === 'HEAD') {
160
+ base.reasons.push('detached HEAD — gate inactive (fail-open)');
161
+ return base;
162
+ }
163
+ const changed = changedFilesVsBase(projectDir);
164
+ if (changed === null) {
165
+ base.reasons.push('no upstream base resolvable — gate inactive (fail-open)');
166
+ return base;
167
+ }
168
+ const uiFiles = changed.filter(isUiFile);
169
+ if (uiFiles.length === 0) {
170
+ base.reasons.push('no UI files in the diff');
171
+ return base;
172
+ }
173
+ base.required = true;
174
+ base.uiFiles = uiFiles;
175
+ const artifact = readArtifact(artifactPath);
176
+ if (!artifact) {
177
+ base.ok = false;
178
+ base.reasons.push(`no captures artifact at ${relative(projectDir, artifactPath)} — capture before/after ` +
179
+ 'evidence (agent-browser / tuistory / pty-capture) and register each pair with ' +
180
+ '`uap review captures add --before <img> --after <img> --tool <name>`');
181
+ return base;
182
+ }
183
+ base.captures = artifact.captures ?? [];
184
+ const pairs = base.captures.filter((c) => c.before && c.after);
185
+ if (pairs.length === 0) {
186
+ base.ok = false;
187
+ base.reasons.push('captures artifact has no complete before/after pair');
188
+ return base;
189
+ }
190
+ const missing = pairs.flatMap((c) => [c.before, c.after].filter((p) => !existsSync(join(projectDir, p))));
191
+ if (missing.length > 0) {
192
+ base.ok = false;
193
+ base.reasons.push(`capture file(s) missing on disk: ${missing.join(', ')}`);
194
+ return base;
195
+ }
196
+ // Freshness: captures recorded before the newest UI edit prove nothing
197
+ // about the CURRENT look. Fail CLOSED when `at` is missing/unparseable —
198
+ // the ship enforcer coerces the same failure to epoch 0 (everything stale),
199
+ // so the advisory CLI must not say OK where the gate will refuse.
200
+ const capturedAt = Date.parse(artifact.at) / 1000;
201
+ if (!Number.isFinite(capturedAt)) {
202
+ base.ok = false;
203
+ base.reasons.push('captures artifact has no parseable `at` timestamp — re-register a pair');
204
+ return base;
205
+ }
206
+ const stale = uiFiles.filter((f) => {
207
+ try {
208
+ return statSync(join(projectDir, f)).mtimeMs / 1000 > capturedAt + STALENESS_GRACE_S;
209
+ }
210
+ catch {
211
+ return false; // deleted files cannot be stale
212
+ }
213
+ });
214
+ if (stale.length > 0) {
215
+ base.ok = false;
216
+ base.reasons.push(`UI file(s) changed after the captures were taken: ${stale.join(', ')} — re-capture`);
217
+ return base;
218
+ }
219
+ base.reasons.push(`${pairs.length} before/after pair(s) cover ${uiFiles.length} UI file(s)`);
220
+ return base;
221
+ }
222
+ //# sourceMappingURL=visual-captures.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"visual-captures.js","sourceRoot":"","sources":["../../src/review/visual-captures.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,73 @@
1
+ /**
2
+ * The nine assessment dimensions — each a PURE function over a bounded
3
+ * Observation. Heuristics are the floor: they always answer. An optional
4
+ * classifier (structural contract only — the SYS1 classifier lands
5
+ * separately) may RAISE a flag when confident, but can never clear one the
6
+ * heuristic set, and a throwing/absent classifier changes nothing. That is
7
+ * the fail-closed posture: model failure degrades to reviewed heuristics,
8
+ * never to looser supervision.
9
+ */
10
+ import type { DimensionAssessment, Observation, SupervisorConfig } from './types.js';
11
+ /**
12
+ * Structural match for the SYS1 classifier contract (PR #807 — do NOT import
13
+ * src/classify, it is unmerged). Only the built-in question names below may
14
+ * be sent; the backend throws on custom names, so none exist here. When #807
15
+ * lands, this interface is replaced by the real import and reconciled.
16
+ */
17
+ export interface ClassifierQuestion {
18
+ name: string;
19
+ kind: 'noul' | 'choice' | 'score';
20
+ prompt: string;
21
+ options?: string[];
22
+ }
23
+ export interface ClassifierLike {
24
+ name: string;
25
+ assess(state: string, questions: ClassifierQuestion[]): Record<string, {
26
+ value: unknown;
27
+ probability: number;
28
+ confidence: number;
29
+ }>;
30
+ }
31
+ /** 1. running, but no state update past the stall budget. */
32
+ export declare function progressStalled(obs: Observation, cfg: SupervisorConfig): DimensionAssessment;
33
+ /**
34
+ * 2. diff touches paths with NO overlap with instruction keywords. A simple
35
+ * heuristic by design: absence of evidence (no diff, no keywords) is an
36
+ * abstention (defer), never an accusation.
37
+ */
38
+ export declare function offTrack(obs: Observation): DimensionAssessment;
39
+ /** 3. the mission is asking for something only a human can provide. */
40
+ export declare function humanNeeded(obs: Observation): DimensionAssessment;
41
+ /**
42
+ * 4. stuck-loop: too many recorded failures, or ONE error signature repeated
43
+ * >= 3 times in the tail (same normalized line — the loop is saying the same
44
+ * thing, not making new mistakes).
45
+ */
46
+ export declare function stuckLoop(obs: Observation, cfg: SupervisorConfig): DimensionAssessment;
47
+ /** 5. delivered status, or the mission's own success markers in the tail. */
48
+ export declare function completionSignaled(obs: Observation): DimensionAssessment;
49
+ /** 6. a checkpoint exists but the tail shows no test run to back it. */
50
+ export declare function verificationPending(obs: Observation): DimensionAssessment;
51
+ /** 7. error-line density in the tail, scored 1-5. */
52
+ export declare function errorDensity(obs: Observation): DimensionAssessment;
53
+ /** 8. how much of the turn budget is spent, scored 1-5. */
54
+ export declare function iterationPressure(obs: Observation, cfg: SupervisorConfig): DimensionAssessment;
55
+ /** 9. destructive-token density in the tail, scored 1-5. */
56
+ export declare function risk(obs: Observation): DimensionAssessment;
57
+ export declare const DIMENSIONS: readonly ["progress-stalled", "off-track", "human-needed", "stuck-loop", "completion-signaled", "verification-pending", "error-density", "iteration-pressure", "risk"];
58
+ export declare function heuristicAssessAll(obs: Observation, cfg: SupervisorConfig): DimensionAssessment[];
59
+ /** Bounded, redaction-friendly summary handed to the classifier. */
60
+ export declare function summarizeObservation(obs: Observation): string;
61
+ /**
62
+ * Assess all nine dimensions. With a classifier, ONLY the SYS1 built-in
63
+ * questions are asked (escalation-risk noul, action-class choice); confident
64
+ * answers map onto flag dimensions:
65
+ * escalation-risk=true (probability ≥ classifierTau AND confidence ≥
66
+ * classifierConfidenceMin) → raises off-track
67
+ * action-class 'escalate' → raises stuck-loop
68
+ * action-class 'stop' → raises off-track
69
+ * The classifier may RAISE a flag, never clear one (never looser), and any
70
+ * classifier error leaves the pure heuristics in charge (fail closed).
71
+ */
72
+ export declare function assessAll(obs: Observation, cfg: SupervisorConfig, classifier?: ClassifierLike): DimensionAssessment[];
73
+ //# sourceMappingURL=assess.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"assess.d.ts","sourceRoot":"","sources":["../../src/supervise/assess.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,OAAO,KAAK,EAAE,mBAAmB,EAAE,WAAW,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAErF;;;;;GAKG;AACH,MAAM,WAAW,kBAAkB;IACjC,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,GAAG,QAAQ,GAAG,OAAO,CAAC;IAClC,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;CACpB;AAED,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,CACJ,KAAK,EAAE,MAAM,EACb,SAAS,EAAE,kBAAkB,EAAE,GAC9B,MAAM,CAAC,MAAM,EAAE;QAAE,KAAK,EAAE,OAAO,CAAC;QAAC,WAAW,EAAE,MAAM,CAAC;QAAC,UAAU,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CAChF;AA8CD,6DAA6D;AAC7D,wBAAgB,eAAe,CAAC,GAAG,EAAE,WAAW,EAAE,GAAG,EAAE,gBAAgB,GAAG,mBAAmB,CAG5F;AAED;;;;GAIG;AACH,wBAAgB,QAAQ,CAAC,GAAG,EAAE,WAAW,GAAG,mBAAmB,CAc9D;AAED,uEAAuE;AACvE,wBAAgB,WAAW,CAAC,GAAG,EAAE,WAAW,GAAG,mBAAmB,CAEjE;AAED;;;;GAIG;AACH,wBAAgB,SAAS,CAAC,GAAG,EAAE,WAAW,EAAE,GAAG,EAAE,gBAAgB,GAAG,mBAAmB,CAgBtF;AAED,6EAA6E;AAC7E,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,WAAW,GAAG,mBAAmB,CAGxE;AAED,wEAAwE;AACxE,wBAAgB,mBAAmB,CAAC,GAAG,EAAE,WAAW,GAAG,mBAAmB,CAGzE;AAED,qDAAqD;AACrD,wBAAgB,YAAY,CAAC,GAAG,EAAE,WAAW,GAAG,mBAAmB,CAKlE;AAED,2DAA2D;AAC3D,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,WAAW,EAAE,GAAG,EAAE,gBAAgB,GAAG,mBAAmB,CAG9F;AAED,4DAA4D;AAC5D,wBAAgB,IAAI,CAAC,GAAG,EAAE,WAAW,GAAG,mBAAmB,CAG1D;AAED,eAAO,MAAM,UAAU,wKAUb,CAAC;AAEX,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,WAAW,EAAE,GAAG,EAAE,gBAAgB,GAAG,mBAAmB,EAAE,CAYjG;AAED,oEAAoE;AACpE,wBAAgB,oBAAoB,CAAC,GAAG,EAAE,WAAW,GAAG,MAAM,CAS7D;AA4BD;;;;;;;;;;GAUG;AACH,wBAAgB,SAAS,CACvB,GAAG,EAAE,WAAW,EAChB,GAAG,EAAE,gBAAgB,EACrB,UAAU,CAAC,EAAE,cAAc,GAC1B,mBAAmB,EAAE,CA0BvB"}
@@ -0,0 +1,215 @@
1
+ /** The ONLY questions ever sent — the SYS1 built-ins. */
2
+ const BUILTIN_QUESTIONS = [
3
+ {
4
+ name: 'escalation-risk',
5
+ kind: 'noul',
6
+ prompt: 'Does this mission evidence indicate escalation-level risk (stuck, off-track, or needing a human)?',
7
+ },
8
+ {
9
+ name: 'action-class',
10
+ kind: 'choice',
11
+ prompt: 'Which supervisor action class does this evidence most suggest?',
12
+ },
13
+ ];
14
+ /**
15
+ * Human-need means an INTERROGATIVE the mission cannot answer itself:
16
+ * credential prompts and approve/confirm questions. Declaratives like
17
+ * "Permission denied" or "approved the change" must NOT fire.
18
+ */
19
+ const HUMAN_NEEDED_RE = /\b(enter|type|provide|requires?)\b.{0,24}\b(password|passphrase|credentials?)\b|\b(password|passphrase)\s*[:?]|\b(approve|confirm|allow)\s+(this|the|these)?\s*(action|change|operation)s?\?|\[y(?:es)?\/n(?:o)?\]/i;
20
+ const SUCCESS_RE = /(delivered in \d+ turn|delivery complete|mission complete|✓ delivered)/i;
21
+ const TEST_EVIDENCE_RE = /(npm (run )?test|vitest|pytest|go test|cargo test|tests? (passed|pass)|✓ tests)/i;
22
+ const ERROR_LINE_RE = /(error|fatal|exception|failed)/i;
23
+ /** Healthy summaries like "0 failed" / "0 errors" are not error evidence. */
24
+ const HEALTHY_COUNT_RE = /\b0\s+(failed|failures?|errors?)\b/i;
25
+ const DESTRUCTIVE_RE = /(rm\s+-rf|drop\s+table|force-push|git\s+push\s+--force|delete\s+from|truncate\s+table|mkfs|git\s+reset\s+--hard)/gi;
26
+ /** Error-evidence lines: error-shaped MINUS healthy zero-count summaries. */
27
+ function errorLines(tail) {
28
+ return tail
29
+ .split('\n')
30
+ .filter((l) => ERROR_LINE_RE.test(l) && !HEALTHY_COUNT_RE.test(l));
31
+ }
32
+ function flag(name, value, confidence, defer = false) {
33
+ return { name, value, probability: value ? confidence : 1 - confidence, confidence, defer, source: 'heuristic' };
34
+ }
35
+ function score(name, value, confidence) {
36
+ const v = Math.max(1, Math.min(5, Math.round(value)));
37
+ return { name, value: v, probability: confidence, confidence, defer: false, source: 'heuristic' };
38
+ }
39
+ /** 1. running, but no state update past the stall budget. */
40
+ export function progressStalled(obs, cfg) {
41
+ const stalled = obs.status === 'running' && obs.minutesSinceUpdate > cfg.stallMinutes;
42
+ return flag('progress-stalled', stalled, 0.9);
43
+ }
44
+ /**
45
+ * 2. diff touches paths with NO overlap with instruction keywords. A simple
46
+ * heuristic by design: absence of evidence (no diff, no keywords) is an
47
+ * abstention (defer), never an accusation.
48
+ */
49
+ export function offTrack(obs) {
50
+ const stat = obs.diffStat;
51
+ if (!stat || !stat.trim())
52
+ return flag('off-track', false, 0.2, true);
53
+ const keywords = obs.instruction
54
+ .toLowerCase()
55
+ .split(/[^a-z0-9]+/)
56
+ .filter((w) => w.length >= 4);
57
+ const paths = stat
58
+ .split('\n')
59
+ .map((l) => l.split('|')[0].trim())
60
+ .filter((p) => p.length > 0 && !p.startsWith('...'));
61
+ if (keywords.length === 0 || paths.length === 0)
62
+ return flag('off-track', false, 0.2, true);
63
+ const related = paths.some((p) => keywords.some((k) => p.toLowerCase().includes(k)));
64
+ return flag('off-track', !related, 0.6);
65
+ }
66
+ /** 3. the mission is asking for something only a human can provide. */
67
+ export function humanNeeded(obs) {
68
+ return flag('human-needed', HUMAN_NEEDED_RE.test(obs.recentLogTail), 0.9);
69
+ }
70
+ /**
71
+ * 4. stuck-loop: too many recorded failures, or ONE error signature repeated
72
+ * >= 3 times in the tail (same normalized line — the loop is saying the same
73
+ * thing, not making new mistakes).
74
+ */
75
+ export function stuckLoop(obs, cfg) {
76
+ if (obs.failures >= cfg.maxFailures)
77
+ return flag('stuck-loop', true, 0.9);
78
+ const counts = new Map();
79
+ for (const line of errorLines(obs.recentLogTail)) {
80
+ const sig = line
81
+ .toLowerCase()
82
+ .replace(/\d{4}-\d{2}-\d{2}[t ][\d:.]+z?/g, '')
83
+ .replace(/\d+/g, '#')
84
+ .trim()
85
+ .slice(0, 120);
86
+ if (!sig)
87
+ continue;
88
+ counts.set(sig, (counts.get(sig) ?? 0) + 1);
89
+ }
90
+ let maxRepeat = 0;
91
+ for (const n of counts.values())
92
+ maxRepeat = Math.max(maxRepeat, n);
93
+ return flag('stuck-loop', maxRepeat >= 3, 0.8);
94
+ }
95
+ /** 5. delivered status, or the mission's own success markers in the tail. */
96
+ export function completionSignaled(obs) {
97
+ const done = obs.status === 'delivered' || SUCCESS_RE.test(obs.recentLogTail);
98
+ return flag('completion-signaled', done, 0.9);
99
+ }
100
+ /** 6. a checkpoint exists but the tail shows no test run to back it. */
101
+ export function verificationPending(obs) {
102
+ const pending = obs.hasCheckpoint && !TEST_EVIDENCE_RE.test(obs.recentLogTail);
103
+ return flag('verification-pending', pending, 0.6, !obs.hasCheckpoint);
104
+ }
105
+ /** 7. error-line density in the tail, scored 1-5. */
106
+ export function errorDensity(obs) {
107
+ const lines = obs.recentLogTail.split('\n').filter((l) => l.trim().length > 0);
108
+ if (lines.length === 0)
109
+ return score('error-density', 1, 0.5);
110
+ const errors = errorLines(obs.recentLogTail).length;
111
+ return score('error-density', 1 + Math.min(4, Math.floor((errors / lines.length) * 20)), 0.7);
112
+ }
113
+ /** 8. how much of the turn budget is spent, scored 1-5. */
114
+ export function iterationPressure(obs, cfg) {
115
+ const ratio = obs.turnsCompleted / cfg.maxTurns;
116
+ return score('iteration-pressure', 1 + Math.min(4, Math.round(ratio * 4)), 0.9);
117
+ }
118
+ /** 9. destructive-token density in the tail, scored 1-5. */
119
+ export function risk(obs) {
120
+ const matches = obs.recentLogTail.match(DESTRUCTIVE_RE);
121
+ return score('risk', 1 + Math.min(4, matches ? matches.length : 0), 0.6);
122
+ }
123
+ export const DIMENSIONS = [
124
+ 'progress-stalled',
125
+ 'off-track',
126
+ 'human-needed',
127
+ 'stuck-loop',
128
+ 'completion-signaled',
129
+ 'verification-pending',
130
+ 'error-density',
131
+ 'iteration-pressure',
132
+ 'risk',
133
+ ];
134
+ export function heuristicAssessAll(obs, cfg) {
135
+ return [
136
+ progressStalled(obs, cfg),
137
+ offTrack(obs),
138
+ humanNeeded(obs),
139
+ stuckLoop(obs, cfg),
140
+ completionSignaled(obs),
141
+ verificationPending(obs),
142
+ errorDensity(obs),
143
+ iterationPressure(obs, cfg),
144
+ risk(obs),
145
+ ];
146
+ }
147
+ /** Bounded, redaction-friendly summary handed to the classifier. */
148
+ export function summarizeObservation(obs) {
149
+ return [
150
+ `run=${obs.runId} status=${obs.status}`,
151
+ `elapsed=${obs.elapsedMinutes.toFixed(1)}m sinceUpdate=${obs.minutesSinceUpdate.toFixed(1)}m`,
152
+ `turns=${obs.turnsCompleted} failures=${obs.failures} checkpoint=${obs.hasCheckpoint}`,
153
+ `gitDirty=${obs.gitDirtyFiles ?? 'n/a'}`,
154
+ `diffStat: ${(obs.diffStat ?? 'n/a').slice(0, 500)}`,
155
+ `logTail: ${obs.recentLogTail.slice(-2000)}`,
156
+ ].join('\n');
157
+ }
158
+ function clamp01(n) {
159
+ return typeof n === 'number' && Number.isFinite(n) ? Math.max(0, Math.min(1, n)) : 0;
160
+ }
161
+ /** Raise a flag dimension from a classifier answer — NEVER clears one. */
162
+ function raiseFlag(dims, name, a) {
163
+ return dims.map((d) => d.name === name && d.value !== true
164
+ ? {
165
+ name,
166
+ value: true,
167
+ probability: clamp01(a.probability),
168
+ confidence: clamp01(a.confidence),
169
+ defer: false,
170
+ source: 'classifier',
171
+ }
172
+ : d);
173
+ }
174
+ /**
175
+ * Assess all nine dimensions. With a classifier, ONLY the SYS1 built-in
176
+ * questions are asked (escalation-risk noul, action-class choice); confident
177
+ * answers map onto flag dimensions:
178
+ * escalation-risk=true (probability ≥ classifierTau AND confidence ≥
179
+ * classifierConfidenceMin) → raises off-track
180
+ * action-class 'escalate' → raises stuck-loop
181
+ * action-class 'stop' → raises off-track
182
+ * The classifier may RAISE a flag, never clear one (never looser), and any
183
+ * classifier error leaves the pure heuristics in charge (fail closed).
184
+ */
185
+ export function assessAll(obs, cfg, classifier) {
186
+ const heuristics = heuristicAssessAll(obs, cfg);
187
+ if (!classifier)
188
+ return heuristics;
189
+ let answers;
190
+ try {
191
+ answers = classifier.assess(summarizeObservation(obs), BUILTIN_QUESTIONS);
192
+ }
193
+ catch {
194
+ return heuristics;
195
+ }
196
+ if (!answers || typeof answers !== 'object')
197
+ return heuristics;
198
+ let out = heuristics;
199
+ const er = answers['escalation-risk'];
200
+ if (er &&
201
+ er.value === true &&
202
+ clamp01(er.probability) >= cfg.classifierTau &&
203
+ clamp01(er.confidence) >= cfg.classifierConfidenceMin) {
204
+ out = raiseFlag(out, 'off-track', er);
205
+ }
206
+ const ac = answers['action-class'];
207
+ if (ac && clamp01(ac.confidence) >= cfg.classifierConfidenceMin) {
208
+ if (ac.value === 'escalate')
209
+ out = raiseFlag(out, 'stuck-loop', ac);
210
+ else if (ac.value === 'stop')
211
+ out = raiseFlag(out, 'off-track', ac);
212
+ }
213
+ return out;
214
+ }
215
+ //# sourceMappingURL=assess.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"assess.js","sourceRoot":"","sources":["../../src/supervise/assess.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,13 @@
1
+ import type { SupervisorConfig } from './types.js';
2
+ export declare class SupervisorError extends Error {
3
+ constructor(message: string);
4
+ }
5
+ export declare const POLICY_VERSION = 1;
6
+ /** The policy shipped with the package (dist/supervise → ../../config). */
7
+ export declare function packagedPolicyPath(): string;
8
+ export declare function resolvePolicyPath(): string;
9
+ /** Validate a parsed policy. Throws SupervisorError on ANY deviation. */
10
+ export declare function validatePolicy(raw: unknown, source: string): SupervisorConfig;
11
+ /** Load + validate the policy. NEVER returns defaults — fail closed. */
12
+ export declare function loadSupervisorConfig(path?: string): SupervisorConfig;
13
+ //# sourceMappingURL=config.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/supervise/config.ts"],"names":[],"mappings":"AAaA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAEnD,qBAAa,eAAgB,SAAQ,KAAK;gBAC5B,OAAO,EAAE,MAAM;CAI5B;AAED,eAAO,MAAM,cAAc,IAAI,CAAC;AAgBhC,2EAA2E;AAC3E,wBAAgB,kBAAkB,IAAI,MAAM,CAG3C;AAED,wBAAgB,iBAAiB,IAAI,MAAM,CAE1C;AAED,yEAAyE;AACzE,wBAAgB,cAAc,CAAC,GAAG,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,GAAG,gBAAgB,CA2B7E;AAED,wEAAwE;AACxE,wBAAgB,oBAAoB,CAAC,IAAI,GAAE,MAA4B,GAAG,gBAAgB,CAezF"}
@@ -0,0 +1,81 @@
1
+ /**
2
+ * Supervisor policy config — versioned, range-checked, loud.
3
+ *
4
+ * Thresholds are POLICY, not preference: they ship reviewed in
5
+ * `config/supervise-policy.json` and are validated at load. A missing,
6
+ * corrupt, mis-versioned, or out-of-range file throws SupervisorError rather
7
+ * than falling back to invented defaults — supervising with unreviewed
8
+ * numbers is worse than not supervising. Tests and operators may point
9
+ * `UAP_SUPERVISE_POLICY` at an alternate file.
10
+ */
11
+ import { existsSync, readFileSync } from 'fs';
12
+ import { dirname, join } from 'path';
13
+ import { fileURLToPath } from 'url';
14
+ export class SupervisorError extends Error {
15
+ constructor(message) {
16
+ super(message);
17
+ this.name = 'SupervisorError';
18
+ }
19
+ }
20
+ export const POLICY_VERSION = 1;
21
+ /** [min, max] per numeric threshold — the review envelope. */
22
+ const RANGES = {
23
+ stallMinutes: [1, 1440],
24
+ maxMinutes: [1, 2880],
25
+ maxTurns: [1, 1000],
26
+ maxRetries: [0, 10],
27
+ maxFailures: [1, 25],
28
+ debounceMs: [1000, 60_000],
29
+ intervalMs: [5_000, 3_600_000],
30
+ classifierConfidenceMin: [0, 1],
31
+ classifierTau: [0, 1],
32
+ maxVerify: [1, 25],
33
+ };
34
+ /** The policy shipped with the package (dist/supervise → ../../config). */
35
+ export function packagedPolicyPath() {
36
+ const here = dirname(fileURLToPath(import.meta.url));
37
+ return join(here, '..', '..', 'config', 'supervise-policy.json');
38
+ }
39
+ export function resolvePolicyPath() {
40
+ return process.env.UAP_SUPERVISE_POLICY || packagedPolicyPath();
41
+ }
42
+ /** Validate a parsed policy. Throws SupervisorError on ANY deviation. */
43
+ export function validatePolicy(raw, source) {
44
+ if (typeof raw !== 'object' || raw === null || Array.isArray(raw)) {
45
+ throw new SupervisorError(`supervisor policy ${source}: expected a JSON object`);
46
+ }
47
+ const obj = raw;
48
+ if (obj.version !== POLICY_VERSION) {
49
+ throw new SupervisorError(`supervisor policy ${source}: version must be ${POLICY_VERSION} (got ${JSON.stringify(obj.version)})`);
50
+ }
51
+ const out = {};
52
+ for (const [key, [min, max]] of Object.entries(RANGES)) {
53
+ const v = obj[key];
54
+ if (typeof v !== 'number' || !Number.isFinite(v)) {
55
+ throw new SupervisorError(`supervisor policy ${source}: ${key} must be a finite number`);
56
+ }
57
+ if (v < min || v > max) {
58
+ throw new SupervisorError(`supervisor policy ${source}: ${key}=${v} outside reviewed range [${min}, ${max}]`);
59
+ }
60
+ out[key] = v;
61
+ }
62
+ if (out.intervalMs < out.debounceMs) {
63
+ throw new SupervisorError(`supervisor policy ${source}: intervalMs (${out.intervalMs}) must be >= debounceMs (${out.debounceMs})`);
64
+ }
65
+ return { version: POLICY_VERSION, ...out };
66
+ }
67
+ /** Load + validate the policy. NEVER returns defaults — fail closed. */
68
+ export function loadSupervisorConfig(path = resolvePolicyPath()) {
69
+ if (!existsSync(path)) {
70
+ throw new SupervisorError(`supervisor policy not found: ${path} — thresholds ship as reviewed config; refusing to run with defaults`);
71
+ }
72
+ let parsed;
73
+ try {
74
+ parsed = JSON.parse(readFileSync(path, 'utf-8'));
75
+ }
76
+ catch (err) {
77
+ throw new SupervisorError(`supervisor policy ${path}: unreadable JSON (${err instanceof Error ? err.message : String(err)})`);
78
+ }
79
+ return validatePolicy(parsed, path);
80
+ }
81
+ //# sourceMappingURL=config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/supervise/config.ts"],"names":[],"mappings":"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"}