@miller-tech/uap 1.59.0 → 1.61.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (85) hide show
  1. package/dist/.tsbuildinfo +1 -1
  2. package/dist/benchmarks/paired/adapter.d.ts.map +1 -1
  3. package/dist/benchmarks/paired/adapter.js +14 -1
  4. package/dist/benchmarks/paired/adapter.js.map +1 -1
  5. package/dist/benchmarks/paired/scaffold.d.ts.map +1 -1
  6. package/dist/benchmarks/paired/scaffold.js +6 -1
  7. package/dist/benchmarks/paired/scaffold.js.map +1 -1
  8. package/dist/bin/cli.js +58 -0
  9. package/dist/bin/cli.js.map +1 -1
  10. package/dist/cli/deliver.d.ts +33 -0
  11. package/dist/cli/deliver.d.ts.map +1 -1
  12. package/dist/cli/deliver.js +90 -7
  13. package/dist/cli/deliver.js.map +1 -1
  14. package/dist/cli/self-harness.d.ts +36 -0
  15. package/dist/cli/self-harness.d.ts.map +1 -0
  16. package/dist/cli/self-harness.js +213 -0
  17. package/dist/cli/self-harness.js.map +1 -0
  18. package/dist/mcp-router/executor/client.d.ts.map +1 -1
  19. package/dist/mcp-router/executor/client.js +16 -2
  20. package/dist/mcp-router/executor/client.js.map +1 -1
  21. package/dist/mcp-router/output-compressor.d.ts.map +1 -1
  22. package/dist/mcp-router/output-compressor.js +51 -0
  23. package/dist/mcp-router/output-compressor.js.map +1 -1
  24. package/dist/self-harness/decide.d.ts +41 -0
  25. package/dist/self-harness/decide.d.ts.map +1 -0
  26. package/dist/self-harness/decide.js +69 -0
  27. package/dist/self-harness/decide.js.map +1 -0
  28. package/dist/self-harness/index.d.ts +23 -0
  29. package/dist/self-harness/index.d.ts.map +1 -0
  30. package/dist/self-harness/index.js +23 -0
  31. package/dist/self-harness/index.js.map +1 -0
  32. package/dist/self-harness/middleware/path-normalizer.d.ts +53 -0
  33. package/dist/self-harness/middleware/path-normalizer.d.ts.map +1 -0
  34. package/dist/self-harness/middleware/path-normalizer.js +116 -0
  35. package/dist/self-harness/middleware/path-normalizer.js.map +1 -0
  36. package/dist/self-harness/mine.d.ts +25 -0
  37. package/dist/self-harness/mine.d.ts.map +1 -0
  38. package/dist/self-harness/mine.js +78 -0
  39. package/dist/self-harness/mine.js.map +1 -0
  40. package/dist/self-harness/mods.d.ts +136 -0
  41. package/dist/self-harness/mods.d.ts.map +1 -0
  42. package/dist/self-harness/mods.js +152 -0
  43. package/dist/self-harness/mods.js.map +1 -0
  44. package/dist/self-harness/orchestrator.d.ts +61 -0
  45. package/dist/self-harness/orchestrator.d.ts.map +1 -0
  46. package/dist/self-harness/orchestrator.js +110 -0
  47. package/dist/self-harness/orchestrator.js.map +1 -0
  48. package/dist/self-harness/pending.d.ts +57 -0
  49. package/dist/self-harness/pending.d.ts.map +1 -0
  50. package/dist/self-harness/pending.js +86 -0
  51. package/dist/self-harness/pending.js.map +1 -0
  52. package/dist/self-harness/profile.d.ts +38 -0
  53. package/dist/self-harness/profile.d.ts.map +1 -0
  54. package/dist/self-harness/profile.js +80 -0
  55. package/dist/self-harness/profile.js.map +1 -0
  56. package/dist/self-harness/propose.d.ts +25 -0
  57. package/dist/self-harness/propose.d.ts.map +1 -0
  58. package/dist/self-harness/propose.js +86 -0
  59. package/dist/self-harness/propose.js.map +1 -0
  60. package/dist/self-harness/trace-mine.d.ts +39 -0
  61. package/dist/self-harness/trace-mine.d.ts.map +1 -0
  62. package/dist/self-harness/trace-mine.js +109 -0
  63. package/dist/self-harness/trace-mine.js.map +1 -0
  64. package/dist/self-harness/transfer.d.ts +99 -0
  65. package/dist/self-harness/transfer.d.ts.map +1 -0
  66. package/dist/self-harness/transfer.js +140 -0
  67. package/dist/self-harness/transfer.js.map +1 -0
  68. package/dist/self-harness/weakness.d.ts +56 -0
  69. package/dist/self-harness/weakness.d.ts.map +1 -0
  70. package/dist/self-harness/weakness.js +0 -0
  71. package/dist/self-harness/weakness.js.map +1 -0
  72. package/dist/tasks/coordination.d.ts.map +1 -1
  73. package/dist/tasks/coordination.js +9 -7
  74. package/dist/tasks/coordination.js.map +1 -1
  75. package/dist/tasks/service.d.ts +10 -0
  76. package/dist/tasks/service.d.ts.map +1 -1
  77. package/dist/tasks/service.js +41 -5
  78. package/dist/tasks/service.js.map +1 -1
  79. package/docs/INDEX.md +1 -0
  80. package/docs/design/SELF_HARNESS.md +206 -0
  81. package/package.json +1 -1
  82. package/src/policies/enforcers/__pycache__/_common.cpython-312.pyc +0 -0
  83. package/tools/agents/scripts/anthropic_proxy.py +160 -18
  84. package/tools/agents/scripts/toolcall_path_normalizer.py +140 -0
  85. package/tools/agents/tests/test_anthropic_proxy_streaming.py +93 -2
@@ -0,0 +1,86 @@
1
+ /**
2
+ * Self-Harness — gated promotion queue (P3).
3
+ *
4
+ * Proposals mined from PRODUCTION traces are never auto-applied: they are
5
+ * enqueued here as `PendingProposal`s awaiting validation + a human gate. The
6
+ * promotion policy decides what may auto-promote after validation (low-risk env
7
+ * knobs) vs what always needs human review (scaffold/middleware). docs/design/
8
+ * SELF_HARNESS.md §9, §10.
9
+ */
10
+ import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'fs';
11
+ import { dirname } from 'path';
12
+ /**
13
+ * Promotion policy: env-knob Mods are low-risk and may auto-promote after they
14
+ * pass validation; scaffold + middleware Mods change behavior more broadly and
15
+ * always require a human gate. This is the safety boundary for online learning.
16
+ */
17
+ export function promotionGate(mod) {
18
+ return mod.kind === 'env' ? 'auto-after-validation' : 'human';
19
+ }
20
+ export class PendingQueue {
21
+ path;
22
+ items = [];
23
+ constructor(path) {
24
+ this.path = path;
25
+ if (existsSync(path)) {
26
+ try {
27
+ this.items = JSON.parse(readFileSync(path, 'utf-8'));
28
+ }
29
+ catch {
30
+ this.items = [];
31
+ }
32
+ }
33
+ }
34
+ persist() {
35
+ mkdirSync(dirname(this.path), { recursive: true });
36
+ writeFileSync(this.path, JSON.stringify(this.items, null, 2), 'utf-8');
37
+ }
38
+ /** Enqueue a proposal, de-duped by (model, signature, mod-shape) while pending. */
39
+ enqueue(p) {
40
+ const full = { ...p, gate: promotionGate(p.mod), status: 'pending' };
41
+ const exists = this.items.some((x) => x.status === 'pending' &&
42
+ x.model === full.model &&
43
+ x.signature === full.signature &&
44
+ JSON.stringify(x.mod) === JSON.stringify(full.mod));
45
+ if (!exists) {
46
+ this.items.push(full);
47
+ this.persist();
48
+ }
49
+ return full;
50
+ }
51
+ list(status) {
52
+ return status ? this.items.filter((x) => x.status === status) : [...this.items];
53
+ }
54
+ update(id, patch) {
55
+ const it = this.items.find((x) => x.id === id);
56
+ if (it) {
57
+ Object.assign(it, patch);
58
+ this.persist();
59
+ }
60
+ }
61
+ /**
62
+ * Drop terminal (promoted/rejected) entries older than `maxAgeDays`, and stale
63
+ * still-pending entries older than `maxPendingDays` (never validated → likely
64
+ * obsolete). Returns the removed items.
65
+ */
66
+ prune(opts = {}) {
67
+ const maxAge = (opts.maxAgeDays ?? 30) * 86_400_000;
68
+ const maxPending = (opts.maxPendingDays ?? 14) * 86_400_000;
69
+ const now = opts.now ?? Date.now();
70
+ const removed = [];
71
+ this.items = this.items.filter((it) => {
72
+ const age = now - (Date.parse(it.createdAt) || 0);
73
+ const terminalStale = (it.status === 'promoted' || it.status === 'rejected') && age > maxAge;
74
+ const pendingStale = it.status === 'pending' && age > maxPending;
75
+ if (terminalStale || pendingStale) {
76
+ removed.push(it);
77
+ return false;
78
+ }
79
+ return true;
80
+ });
81
+ if (removed.length)
82
+ this.persist();
83
+ return removed;
84
+ }
85
+ }
86
+ //# sourceMappingURL=pending.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pending.js","sourceRoot":"","sources":["../../src/self-harness/pending.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,38 @@
1
+ /**
2
+ * Self-Harness — the versioned harness profile + env-file apply/revert.
3
+ *
4
+ * A `HarnessProfile` is the source of truth for the current harness state the
5
+ * proposer reads and the orchestrator commits. P1 physically applies `env` Mods
6
+ * to a KEY=value env file (e.g. ~/.config/uap/llama-server.env) and captures the
7
+ * prior value for one-step revert; scaffold/middleware Mods are recorded in the
8
+ * profile (their physical wiring is P1+/P2). All edits are reversible.
9
+ */
10
+ import type { UapComponent } from '../benchmarks/paired/types.js';
11
+ import { KnownKnob, EnvMod } from './mods.js';
12
+ export interface HarnessProfile {
13
+ /** Allow-listed env knob values currently in effect (string form). */
14
+ env: Partial<Record<KnownKnob, string>>;
15
+ /** Accepted scaffold component overrides (component -> full text). */
16
+ scaffold: Partial<Record<UapComponent, string>>;
17
+ /** Accepted middleware configs (id -> params). */
18
+ middleware: Record<string, Record<string, string | number | boolean>>;
19
+ }
20
+ export declare function emptyProfile(): HarnessProfile;
21
+ /** Parse a KEY=value env file into a flat map (ignores comments/blank lines). */
22
+ export declare function parseEnvFile(path: string): Record<string, string>;
23
+ /** Build a profile from an env file, keeping only allow-listed knobs. */
24
+ export declare function profileFromEnvFile(path: string): HarnessProfile;
25
+ /**
26
+ * Apply an `EnvMod` to a KEY=value env file in place (replacing the line if the
27
+ * key exists, else appending). Returns the prior value (or null if absent) so
28
+ * the caller can record a precise revert. Verifies the Mod's `from` matches the
29
+ * file's current value when present (guards against a stale proposal).
30
+ */
31
+ export declare function applyEnvModToFile(path: string, mod: EnvMod): {
32
+ priorValue: string | null;
33
+ };
34
+ /** Apply an accepted Mod's effect to the in-memory profile (after acceptance). */
35
+ export declare function recordModInProfile(profile: HarnessProfile, mod: EnvMod): HarnessProfile;
36
+ /** Default values for allow-listed knobs (used to seed a profile if a knob is unset). */
37
+ export declare function knobDefault(key: KnownKnob): string | null;
38
+ //# sourceMappingURL=profile.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"profile.d.ts","sourceRoot":"","sources":["../../src/self-harness/profile.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAGH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,+BAA+B,CAAC;AAClE,OAAO,EAAkB,SAAS,EAAE,MAAM,EAAe,MAAM,WAAW,CAAC;AAE3E,MAAM,WAAW,cAAc;IAC7B,sEAAsE;IACtE,GAAG,EAAE,OAAO,CAAC,MAAM,CAAC,SAAS,EAAE,MAAM,CAAC,CAAC,CAAC;IACxC,sEAAsE;IACtE,QAAQ,EAAE,OAAO,CAAC,MAAM,CAAC,YAAY,EAAE,MAAM,CAAC,CAAC,CAAC;IAChD,kDAAkD;IAClD,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC,CAAC,CAAC;CACvE;AAED,wBAAgB,YAAY,IAAI,cAAc,CAE7C;AAED,iFAAiF;AACjF,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAWjE;AAED,yEAAyE;AACzE,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,GAAG,cAAc,CAO/D;AAED;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG;IAAE,UAAU,EAAE,MAAM,GAAG,IAAI,CAAA;CAAE,CAkB1F;AAED,kFAAkF;AAClF,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,cAAc,EAAE,GAAG,EAAE,MAAM,GAAG,cAAc,CAEvF;AAED,yFAAyF;AACzF,wBAAgB,WAAW,CAAC,GAAG,EAAE,SAAS,GAAG,MAAM,GAAG,IAAI,CAMzD"}
@@ -0,0 +1,80 @@
1
+ /**
2
+ * Self-Harness — the versioned harness profile + env-file apply/revert.
3
+ *
4
+ * A `HarnessProfile` is the source of truth for the current harness state the
5
+ * proposer reads and the orchestrator commits. P1 physically applies `env` Mods
6
+ * to a KEY=value env file (e.g. ~/.config/uap/llama-server.env) and captures the
7
+ * prior value for one-step revert; scaffold/middleware Mods are recorded in the
8
+ * profile (their physical wiring is P1+/P2). All edits are reversible.
9
+ */
10
+ import { readFileSync, writeFileSync, existsSync } from 'fs';
11
+ import { KNOB_ALLOWLIST, isKnownKnob } from './mods.js';
12
+ export function emptyProfile() {
13
+ return { env: {}, scaffold: {}, middleware: {} };
14
+ }
15
+ /** Parse a KEY=value env file into a flat map (ignores comments/blank lines). */
16
+ export function parseEnvFile(path) {
17
+ if (!existsSync(path))
18
+ return {};
19
+ const out = {};
20
+ for (const line of readFileSync(path, 'utf-8').split('\n')) {
21
+ const t = line.trim();
22
+ if (!t || t.startsWith('#'))
23
+ continue;
24
+ const eq = t.indexOf('=');
25
+ if (eq <= 0)
26
+ continue;
27
+ out[t.slice(0, eq).trim()] = t.slice(eq + 1).trim();
28
+ }
29
+ return out;
30
+ }
31
+ /** Build a profile from an env file, keeping only allow-listed knobs. */
32
+ export function profileFromEnvFile(path) {
33
+ const all = parseEnvFile(path);
34
+ const p = emptyProfile();
35
+ for (const [k, v] of Object.entries(all)) {
36
+ if (isKnownKnob(k))
37
+ p.env[k] = v;
38
+ }
39
+ return p;
40
+ }
41
+ /**
42
+ * Apply an `EnvMod` to a KEY=value env file in place (replacing the line if the
43
+ * key exists, else appending). Returns the prior value (or null if absent) so
44
+ * the caller can record a precise revert. Verifies the Mod's `from` matches the
45
+ * file's current value when present (guards against a stale proposal).
46
+ */
47
+ export function applyEnvModToFile(path, mod) {
48
+ const lines = existsSync(path) ? readFileSync(path, 'utf-8').split('\n') : [];
49
+ let prior = null;
50
+ let replaced = false;
51
+ const key = mod.key;
52
+ for (let i = 0; i < lines.length; i++) {
53
+ const t = lines[i].trim();
54
+ if (t.startsWith('#') || !t.includes('='))
55
+ continue;
56
+ if (t.slice(0, t.indexOf('=')).trim() === key) {
57
+ prior = t.slice(t.indexOf('=') + 1).trim();
58
+ lines[i] = `${key}=${mod.to}`;
59
+ replaced = true;
60
+ break;
61
+ }
62
+ }
63
+ if (!replaced)
64
+ lines.push(`${key}=${mod.to}`);
65
+ writeFileSync(path, lines.join('\n'), 'utf-8');
66
+ return { priorValue: prior };
67
+ }
68
+ /** Apply an accepted Mod's effect to the in-memory profile (after acceptance). */
69
+ export function recordModInProfile(profile, mod) {
70
+ return { ...profile, env: { ...profile.env, [mod.key]: mod.to } };
71
+ }
72
+ /** Default values for allow-listed knobs (used to seed a profile if a knob is unset). */
73
+ export function knobDefault(key) {
74
+ // The allow-list declares ranges, not defaults; defaults live in the proxy/
75
+ // launch script. We return null and let the proposer skip knobs with no
76
+ // observed current value rather than guess.
77
+ void KNOB_ALLOWLIST[key];
78
+ return null;
79
+ }
80
+ //# sourceMappingURL=profile.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"profile.js","sourceRoot":"","sources":["../../src/self-harness/profile.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,25 @@
1
+ /**
2
+ * Self-Harness — Stage 2 harness-proposal.
3
+ *
4
+ * A `Proposer` turns a ranked `WeaknessReport[]` + the current harness profile
5
+ * into candidate `Mod`s (all DSL-validated). P1 ships a deterministic
6
+ * `heuristicProposer` (a known-failure -> candidate-Mod mapping) so the whole
7
+ * loop runs and is testable without an LLM; the `Proposer` interface is the seam
8
+ * an LLM proposer (P1+) drops into. Proposals are biased toward MINIMAL edits
9
+ * (single knob / single block), per the paper.
10
+ */
11
+ import { Mod, KNOB_ALLOWLIST } from './mods.js';
12
+ import { WeaknessReport } from './weakness.js';
13
+ import type { HarnessProfile } from './profile.js';
14
+ export interface Proposer {
15
+ readonly id: string;
16
+ propose(weaknesses: WeaknessReport[], profile: HarnessProfile): Mod[];
17
+ }
18
+ /**
19
+ * Deterministic heuristic proposer: maps each weakness kind to a minimal,
20
+ * known-good candidate Mod. This intentionally encodes the fixes that worked in
21
+ * the manual campaign (e.g. halving LLAMA_N_PREDICT for runaway generation).
22
+ */
23
+ export declare const heuristicProposer: Proposer;
24
+ export { KNOB_ALLOWLIST };
25
+ //# sourceMappingURL=propose.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"propose.d.ts","sourceRoot":"","sources":["../../src/self-harness/propose.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,EAAE,GAAG,EAAqB,cAAc,EAAyB,MAAM,WAAW,CAAC;AAC1F,OAAO,EAAE,cAAc,EAAe,MAAM,eAAe,CAAC;AAC5D,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAEnD,MAAM,WAAW,QAAQ;IACvB,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,OAAO,CAAC,UAAU,EAAE,cAAc,EAAE,EAAE,OAAO,EAAE,cAAc,GAAG,GAAG,EAAE,CAAC;CACvE;AA+BD;;;;GAIG;AACH,eAAO,MAAM,iBAAiB,EAAE,QAU/B,CAAC;AA8BF,OAAO,EAAE,cAAc,EAAE,CAAC"}
@@ -0,0 +1,86 @@
1
+ /**
2
+ * Self-Harness — Stage 2 harness-proposal.
3
+ *
4
+ * A `Proposer` turns a ranked `WeaknessReport[]` + the current harness profile
5
+ * into candidate `Mod`s (all DSL-validated). P1 ships a deterministic
6
+ * `heuristicProposer` (a known-failure -> candidate-Mod mapping) so the whole
7
+ * loop runs and is testable without an LLM; the `Proposer` interface is the seam
8
+ * an LLM proposer (P1+) drops into. Proposals are biased toward MINIMAL edits
9
+ * (single knob / single block), per the paper.
10
+ */
11
+ import { KNOB_ALLOWLIST, validateMod, knobSpec } from './mods.js';
12
+ /** Clamp a numeric knob value to its declared safe range. */
13
+ function clampKnob(key, value) {
14
+ const spec = knobSpec(key);
15
+ if (spec.type !== 'number')
16
+ return value;
17
+ const v = Math.max(spec.min, Math.min(spec.max, value));
18
+ return spec.integer ? Math.round(v) : v;
19
+ }
20
+ /** Read the current value of a knob from the profile (or its declared default). */
21
+ function currentKnob(profile, key) {
22
+ const raw = profile.env[key];
23
+ if (raw == null)
24
+ return null;
25
+ const n = Number(raw);
26
+ return Number.isFinite(n) ? n : null;
27
+ }
28
+ /**
29
+ * Build a numeric env Mod that moves `key` toward `factor`×current (clamped),
30
+ * or null if the current value is unknown or the move is a no-op / out of range.
31
+ */
32
+ function scaleKnob(profile, key, factor) {
33
+ const cur = currentKnob(profile, key);
34
+ if (cur == null)
35
+ return null;
36
+ const next = clampKnob(key, cur * factor);
37
+ if (next === cur)
38
+ return null;
39
+ const mod = { kind: 'env', key, from: String(cur), to: String(next) };
40
+ return validateMod(mod).ok ? mod : null;
41
+ }
42
+ /**
43
+ * Deterministic heuristic proposer: maps each weakness kind to a minimal,
44
+ * known-good candidate Mod. This intentionally encodes the fixes that worked in
45
+ * the manual campaign (e.g. halving LLAMA_N_PREDICT for runaway generation).
46
+ */
47
+ export const heuristicProposer = {
48
+ id: 'heuristic',
49
+ propose(weaknesses, profile) {
50
+ const out = [];
51
+ for (const w of weaknesses) {
52
+ const cand = HEURISTICS[w.kind]?.(profile);
53
+ if (cand && validateMod(cand).ok)
54
+ out.push(cand);
55
+ }
56
+ return out;
57
+ },
58
+ };
59
+ const HEURISTICS = {
60
+ // Runaway generation eating the wall-clock -> halve the per-turn cap.
61
+ 'gen.runaway.npredict': (p) => scaleKnob(p, 'LLAMA_N_PREDICT', 0.5),
62
+ // Non-termination loops -> tighten the hard finalize ceiling.
63
+ 'loop.nonterminate': (p) => scaleKnob(p, 'PROXY_HARD_FINALIZE_TURNS', 0.75),
64
+ // Wall-clock timeouts are usually runaway-driven on this stack -> cap n-predict.
65
+ 'agent.timeout': (p) => scaleKnob(p, 'LLAMA_N_PREDICT', 0.5),
66
+ // Wrong answers -> append a "verify before done" directive to the gates block.
67
+ 'verify.fail': () => ({
68
+ kind: 'scaffold',
69
+ component: 'gates',
70
+ op: 'append',
71
+ text: 'After writing, run the verify/test command and confirm exit 0 before declaring done. ' +
72
+ 'If it fails, fix in place at the same path and re-run.',
73
+ }),
74
+ // Path garbling -> enable the mechanical path-normalizer middleware (P2). This
75
+ // snaps a garbled tool-call path to a path the model already used correctly,
76
+ // fixing the failure the instruction-level attempts couldn't (the small quant
77
+ // can't reliably follow "use the exact path").
78
+ 'toolcall.path.garbled': () => ({
79
+ kind: 'middleware',
80
+ id: 'toolcall-path-normalizer',
81
+ params: { enabled: true },
82
+ }),
83
+ };
84
+ // Re-export so callers don't need the allow-list import path.
85
+ export { KNOB_ALLOWLIST };
86
+ //# sourceMappingURL=propose.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"propose.js","sourceRoot":"","sources":["../../src/self-harness/propose.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,39 @@
1
+ /**
2
+ * Self-Harness — online weakness mining from PRODUCTION traces (P3).
3
+ *
4
+ * The records-miner (mine.ts) needs a paired bench. Online mining works on real
5
+ * traffic from two sources:
6
+ * - HALO spans (.uap/halo/traces.jsonl) — the `uap deliver` pipeline.
7
+ * - Proxy log signals (journald) — the claude-local proxy path, where
8
+ * toolcall.path.garbled actually surfaces (records can't distinguish it from a
9
+ * logic error; the proxy's TOOLCALL PATH NORMALIZER line proves it occurred).
10
+ *
11
+ * Both produce the same ranked WeaknessReport[] keyed by stable signature.
12
+ * Mining is READ-ONLY; prod-mined proposals are enqueued for gated validation,
13
+ * never auto-applied (see pending.ts). docs/design/SELF_HARNESS.md §9.
14
+ */
15
+ import { FailureKind, WeaknessReport } from './weakness.js';
16
+ /** Minimal shape of a HALO span we classify (subset of HaloSpan). */
17
+ export interface HaloSpanLike {
18
+ name?: string;
19
+ status?: {
20
+ code?: string;
21
+ };
22
+ attributes?: Record<string, unknown>;
23
+ }
24
+ /** Classify one HALO span into a FailureKind, or null if it's not a failure. */
25
+ export declare function classifyHaloSpan(span: HaloSpanLike): FailureKind | null;
26
+ /**
27
+ * Classify one proxy journal line. The proxy already logs the structured signals
28
+ * we care about; this turns them into FailureKinds for online mining.
29
+ */
30
+ export declare function classifyProxyLogLine(line: string): FailureKind | null;
31
+ export interface OnlineMineOptions {
32
+ model: string;
33
+ minFrequency?: number;
34
+ }
35
+ /** Mine weaknesses from HALO spans (the deliver pipeline). */
36
+ export declare function mineFromHaloSpans(spans: HaloSpanLike[], opts: OnlineMineOptions): WeaknessReport[];
37
+ /** Mine weaknesses from proxy journal lines (the claude-local proxy path). */
38
+ export declare function mineFromProxyLogLines(lines: string[], opts: OnlineMineOptions): WeaknessReport[];
39
+ //# sourceMappingURL=trace-mine.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"trace-mine.d.ts","sourceRoot":"","sources":["../../src/self-harness/trace-mine.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,EACL,WAAW,EACX,cAAc,EAGf,MAAM,eAAe,CAAC;AAEvB,qEAAqE;AACrE,MAAM,WAAW,YAAY;IAC3B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE;QAAE,IAAI,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IAC3B,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACtC;AAED,gFAAgF;AAChF,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,YAAY,GAAG,WAAW,GAAG,IAAI,CAmBvE;AAED;;;GAGG;AACH,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,MAAM,GAAG,WAAW,GAAG,IAAI,CAOrE;AAwCD,MAAM,WAAW,iBAAiB;IAChC,KAAK,EAAE,MAAM,CAAC;IACd,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,8DAA8D;AAC9D,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,YAAY,EAAE,EAAE,IAAI,EAAE,iBAAiB,GAAG,cAAc,EAAE,CASlG;AAED,8EAA8E;AAC9E,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE,IAAI,EAAE,iBAAiB,GAAG,cAAc,EAAE,CAUhG"}
@@ -0,0 +1,109 @@
1
+ /**
2
+ * Self-Harness — online weakness mining from PRODUCTION traces (P3).
3
+ *
4
+ * The records-miner (mine.ts) needs a paired bench. Online mining works on real
5
+ * traffic from two sources:
6
+ * - HALO spans (.uap/halo/traces.jsonl) — the `uap deliver` pipeline.
7
+ * - Proxy log signals (journald) — the claude-local proxy path, where
8
+ * toolcall.path.garbled actually surfaces (records can't distinguish it from a
9
+ * logic error; the proxy's TOOLCALL PATH NORMALIZER line proves it occurred).
10
+ *
11
+ * Both produce the same ranked WeaknessReport[] keyed by stable signature.
12
+ * Mining is READ-ONLY; prod-mined proposals are enqueued for gated validation,
13
+ * never auto-applied (see pending.ts). docs/design/SELF_HARNESS.md §9.
14
+ */
15
+ import { signatureHash, rankWeaknesses, } from './weakness.js';
16
+ /** Classify one HALO span into a FailureKind, or null if it's not a failure. */
17
+ export function classifyHaloSpan(span) {
18
+ const attrs = span.attributes ?? {};
19
+ const isError = (span.status?.code ?? '').toUpperCase().includes('ERROR');
20
+ const execErr = String(attrs['delivery.executor_error'] ?? '').toLowerCase();
21
+ const applyErr = String(attrs['delivery.apply_error'] ?? '').toLowerCase();
22
+ const err = `${execErr} ${applyErr}`.trim();
23
+ if (err.includes('timed out') || err.includes('timeout'))
24
+ return 'agent.timeout';
25
+ // An apply error mentioning a path/file that could not be located → garbled path.
26
+ if (applyErr && /(no such file|not found|does not exist|invalid path|outside)/.test(applyErr)) {
27
+ return 'toolcall.path.garbled';
28
+ }
29
+ if (err.includes('exit') || err.includes('spawn') || err.includes('killed'))
30
+ return 'agent.error';
31
+ // Gates failed but the turn produced output → a wrong/insufficient deliverable.
32
+ const gatesFailed = attrs['delivery.gates_failed'];
33
+ if (isError || (typeof gatesFailed === 'string' && gatesFailed) || (Array.isArray(gatesFailed) && gatesFailed.length)) {
34
+ return 'verify.fail';
35
+ }
36
+ return null;
37
+ }
38
+ /**
39
+ * Classify one proxy journal line. The proxy already logs the structured signals
40
+ * we care about; this turns them into FailureKinds for online mining.
41
+ */
42
+ export function classifyProxyLogLine(line) {
43
+ if (line.includes('TOOLCALL PATH NORMALIZER'))
44
+ return 'toolcall.path.garbled';
45
+ if (line.includes('TURN-COUNT FINALIZE BREAKER'))
46
+ return 'loop.nonterminate';
47
+ if (line.includes('RECON CONVERGENCE') && line.includes('hard-escalated'))
48
+ return 'guardrail.poison.recon';
49
+ if (line.includes('exceeds the available context size'))
50
+ return 'gen.runaway.npredict';
51
+ if (line.includes('should_stop condition'))
52
+ return 'agent.timeout';
53
+ return null;
54
+ }
55
+ function aggregate(kinds, model, minFrequency) {
56
+ const byKind = new Map();
57
+ for (const { kind, task, evidence } of kinds) {
58
+ let a = byKind.get(kind);
59
+ if (!a) {
60
+ a = { count: 0, tasks: new Set(), evidence: [] };
61
+ byKind.set(kind, a);
62
+ }
63
+ a.count += 1;
64
+ a.tasks.add(task);
65
+ if (a.evidence.length < 5)
66
+ a.evidence.push(evidence);
67
+ }
68
+ const reports = [];
69
+ for (const [kind, a] of byKind) {
70
+ if (a.count < minFrequency)
71
+ continue;
72
+ reports.push({
73
+ signature: signatureHash({ kind, model }),
74
+ kind,
75
+ model,
76
+ frequency: a.count,
77
+ affectedTasks: [...a.tasks],
78
+ hypothesis: `Observed in production traces (${a.count}×).`,
79
+ evidence: a.evidence,
80
+ });
81
+ }
82
+ return rankWeaknesses(reports);
83
+ }
84
+ /** Mine weaknesses from HALO spans (the deliver pipeline). */
85
+ export function mineFromHaloSpans(spans, opts) {
86
+ const hits = [];
87
+ for (const span of spans) {
88
+ const kind = classifyHaloSpan(span);
89
+ if (!kind)
90
+ continue;
91
+ const task = String(span.attributes?.['inference.project_id'] ?? span.name ?? 'unknown');
92
+ hits.push({ kind, task, evidence: `${span.name}: ${kind}` });
93
+ }
94
+ return aggregate(hits, opts.model, opts.minFrequency ?? 1);
95
+ }
96
+ /** Mine weaknesses from proxy journal lines (the claude-local proxy path). */
97
+ export function mineFromProxyLogLines(lines, opts) {
98
+ const hits = [];
99
+ for (const line of lines) {
100
+ const kind = classifyProxyLogLine(line);
101
+ if (!kind)
102
+ continue;
103
+ // Sessions aren't tasks; use the proxy session fingerprint if present.
104
+ const m = /fp:[0-9a-f]+/.exec(line);
105
+ hits.push({ kind, task: m ? m[0] : 'proxy', evidence: line.slice(0, 160) });
106
+ }
107
+ return aggregate(hits, opts.model, opts.minFrequency ?? 1);
108
+ }
109
+ //# sourceMappingURL=trace-mine.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"trace-mine.js","sourceRoot":"","sources":["../../src/self-harness/trace-mine.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,99 @@
1
+ /**
2
+ * Self-Harness — cross-model transfer store (P3).
3
+ *
4
+ * Addresses the paper's stated limitation (fixes stay model-specific). Every
5
+ * accepted Mod is recorded keyed by (model family, failure kind, signature) with
6
+ * its measured delta + provenance. When a NEW model hits the same failure KIND,
7
+ * the proposer seeds from Mods that already worked for that kind on OTHER models
8
+ * — those still go through full validation (transfer is a prior, not a shortcut),
9
+ * and negative results are recorded so known-bad Mods are not re-proposed.
10
+ *
11
+ * See docs/design/SELF_HARNESS.md §8, §11 (P3).
12
+ */
13
+ import { Mod } from './mods.js';
14
+ import { FailureKind } from './weakness.js';
15
+ import type { Proposer } from './propose.js';
16
+ export interface TransferEntry {
17
+ /** Full (model-specific) signature the Mod was mined against. */
18
+ signature: string;
19
+ kind: FailureKind;
20
+ /** Normalized model family the Mod was validated on. */
21
+ model: string;
22
+ mod: Mod;
23
+ /** Measured validation correctness delta when accepted (or rejected: <=0). */
24
+ delta: number;
25
+ /** Whether this entry was an acceptance (true) or a recorded rejection (false). */
26
+ accepted: boolean;
27
+ /** ISO timestamp; provenance string (suite, n, stats). */
28
+ validatedAt: string;
29
+ provenance: string;
30
+ }
31
+ /** Structural identity of a Mod, for de-duplication across sources. */
32
+ export declare function modKey(mod: Mod): string;
33
+ export declare function dedupeMods(mods: Mod[]): Mod[];
34
+ export interface TransferQueryOptions {
35
+ /** Exclude entries already validated on this (normalized) model family. */
36
+ excludeModel?: string;
37
+ /** Only entries that were ACCEPTED (positive). Default true. */
38
+ acceptedOnly?: boolean;
39
+ }
40
+ export interface PruneOptions {
41
+ /** Drop ACCEPTED entries whose measured delta is <= this (no longer worth
42
+ * transferring — the ablation idea: stop carrying a Mod that stopped paying
43
+ * off). Default 0 (keep only strictly-positive accepted). */
44
+ minDelta?: number;
45
+ /** Drop ANY entry older than this many days. Default 90. */
46
+ maxAgeDays?: number;
47
+ /** Override "now" (ms epoch) for deterministic tests. */
48
+ now?: number;
49
+ }
50
+ export interface PruneResult {
51
+ removed: TransferEntry[];
52
+ kept: number;
53
+ }
54
+ export interface TransferStore {
55
+ record(entry: TransferEntry): void;
56
+ /** Cross-model lookup by failure kind, ranked by measured delta (desc). */
57
+ query(kind: FailureKind, opts?: TransferQueryOptions): TransferEntry[];
58
+ all(): TransferEntry[];
59
+ /** Ablation-prune: drop stale / no-longer-paying-off entries. */
60
+ prune(opts?: PruneOptions): PruneResult;
61
+ }
62
+ /** In-memory store (tests, ephemeral runs). */
63
+ export declare class MemoryTransferStore implements TransferStore {
64
+ protected entries: TransferEntry[];
65
+ record(entry: TransferEntry): void;
66
+ query(kind: FailureKind, opts?: TransferQueryOptions): TransferEntry[];
67
+ all(): TransferEntry[];
68
+ prune(opts?: PruneOptions): PruneResult;
69
+ }
70
+ /** JSON-file-backed store (persisted across runs; default under .uap/self-harness). */
71
+ export declare class JsonTransferStore extends MemoryTransferStore {
72
+ private readonly path;
73
+ constructor(path: string);
74
+ record(entry: TransferEntry): void;
75
+ prune(opts?: PruneOptions): PruneResult;
76
+ private persist;
77
+ }
78
+ /** Build a TransferEntry from an accepted/rejected Mod + measured delta. */
79
+ export declare function makeEntry(args: {
80
+ signature: string;
81
+ kind: FailureKind;
82
+ model: string;
83
+ mod: Mod;
84
+ delta: number;
85
+ accepted: boolean;
86
+ validatedAt: string;
87
+ provenance: string;
88
+ }): TransferEntry;
89
+ /** One-line description of a transfer entry, for `uap self-harness transfer` output. */
90
+ export declare function describeEntry(e: TransferEntry): string;
91
+ /**
92
+ * Wrap a base proposer so it SEEDS candidates from the transfer store: for each
93
+ * weakness, Mods that worked for the same failure kind on OTHER model families
94
+ * are proposed first (as priors that still get fully validated), then the base
95
+ * proposer's candidates. De-duped so a transferred Mod the base would also emit
96
+ * isn't validated twice.
97
+ */
98
+ export declare function makeTransferProposer(store: TransferStore, base: Proposer): Proposer;
99
+ //# sourceMappingURL=transfer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"transfer.d.ts","sourceRoot":"","sources":["../../src/self-harness/transfer.ts"],"names":[],"mappings":"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"}