@miller-tech/uap 2.16.7 → 2.19.5

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 (103) hide show
  1. package/config/capacity-policy.json +33 -0
  2. package/config/model-profiles/qwen38.json +32 -33
  3. package/dist/.tsbuildinfo +1 -1
  4. package/dist/bin/cli.js +57 -0
  5. package/dist/bin/cli.js.map +1 -1
  6. package/dist/capacity/policy.d.ts +32 -1
  7. package/dist/capacity/policy.d.ts.map +1 -1
  8. package/dist/capacity/policy.js +123 -4
  9. package/dist/capacity/policy.js.map +1 -1
  10. package/dist/capacity/probe.d.ts +26 -0
  11. package/dist/capacity/probe.d.ts.map +1 -1
  12. package/dist/capacity/probe.js +84 -3
  13. package/dist/capacity/probe.js.map +1 -1
  14. package/dist/cli/inference.d.ts +4 -0
  15. package/dist/cli/inference.d.ts.map +1 -1
  16. package/dist/cli/inference.js +74 -8
  17. package/dist/cli/inference.js.map +1 -1
  18. package/dist/cli/merge-gate.d.ts +59 -0
  19. package/dist/cli/merge-gate.d.ts.map +1 -0
  20. package/dist/cli/merge-gate.js +238 -0
  21. package/dist/cli/merge-gate.js.map +1 -0
  22. package/dist/cli/merge-queue.d.ts +13 -0
  23. package/dist/cli/merge-queue.d.ts.map +1 -1
  24. package/dist/cli/merge-queue.js +48 -2
  25. package/dist/cli/merge-queue.js.map +1 -1
  26. package/dist/cli/mission.d.ts +25 -0
  27. package/dist/cli/mission.d.ts.map +1 -0
  28. package/dist/cli/mission.js +225 -0
  29. package/dist/cli/mission.js.map +1 -0
  30. package/dist/cli/orch.d.ts +27 -0
  31. package/dist/cli/orch.d.ts.map +1 -0
  32. package/dist/cli/orch.js +70 -0
  33. package/dist/cli/orch.js.map +1 -0
  34. package/dist/cli/systemd-services.d.ts.map +1 -1
  35. package/dist/cli/systemd-services.js +44 -0
  36. package/dist/cli/systemd-services.js.map +1 -1
  37. package/dist/delivery/merge-gate.d.ts +168 -0
  38. package/dist/delivery/merge-gate.d.ts.map +1 -0
  39. package/dist/delivery/merge-gate.js +309 -0
  40. package/dist/delivery/merge-gate.js.map +1 -0
  41. package/dist/inference/analysis.d.ts +69 -3
  42. package/dist/inference/analysis.d.ts.map +1 -1
  43. package/dist/inference/analysis.js +123 -7
  44. package/dist/inference/analysis.js.map +1 -1
  45. package/dist/inference/probe.d.ts +38 -1
  46. package/dist/inference/probe.d.ts.map +1 -1
  47. package/dist/inference/probe.js +303 -30
  48. package/dist/inference/probe.js.map +1 -1
  49. package/dist/inference/strata.d.ts +95 -0
  50. package/dist/inference/strata.d.ts.map +1 -0
  51. package/dist/inference/strata.js +167 -0
  52. package/dist/inference/strata.js.map +1 -0
  53. package/dist/mission/database.d.ts +29 -0
  54. package/dist/mission/database.d.ts.map +1 -0
  55. package/dist/mission/database.js +131 -0
  56. package/dist/mission/database.js.map +1 -0
  57. package/dist/mission/ledger.d.ts +109 -0
  58. package/dist/mission/ledger.d.ts.map +1 -0
  59. package/dist/mission/ledger.js +294 -0
  60. package/dist/mission/ledger.js.map +1 -0
  61. package/dist/mission/poll-cycle.d.ts +73 -0
  62. package/dist/mission/poll-cycle.d.ts.map +1 -0
  63. package/dist/mission/poll-cycle.js +100 -0
  64. package/dist/mission/poll-cycle.js.map +1 -0
  65. package/dist/mission/poll-executor.d.ts +91 -0
  66. package/dist/mission/poll-executor.d.ts.map +1 -0
  67. package/dist/mission/poll-executor.js +328 -0
  68. package/dist/mission/poll-executor.js.map +1 -0
  69. package/dist/models/types.d.ts.map +1 -1
  70. package/dist/models/types.js +33 -27
  71. package/dist/models/types.js.map +1 -1
  72. package/dist/self-tuning/profiles/qwen38.d.ts +13 -14
  73. package/dist/self-tuning/profiles/qwen38.d.ts.map +1 -1
  74. package/dist/self-tuning/profiles/qwen38.js +17 -18
  75. package/dist/self-tuning/profiles/qwen38.js.map +1 -1
  76. package/dist/types/mission.d.ts +80 -0
  77. package/dist/types/mission.d.ts.map +1 -0
  78. package/dist/types/mission.js +12 -0
  79. package/dist/types/mission.js.map +1 -0
  80. package/docs/architecture/adr/0003-mission-orchestrator.md +99 -0
  81. package/docs/architecture/adr/0004-deterministic-merge-gate.md +127 -0
  82. package/docs/guides/CAPACITY_POLICY.md +49 -0
  83. package/docs/guides/INFERENCE_HEALTH.md +65 -8
  84. package/docs/guides/MISSIONS.md +170 -0
  85. package/docs/guides/PROXY.md +2 -0
  86. package/docs/reports/2026-10-02-plane-admin-fail-closed.md +70 -0
  87. package/docs/reports/2026-10-02-plane-admin-protect-session.md +116 -0
  88. package/docs/visual/merge-gate.html +404 -0
  89. package/docs/visual/mission-orchestrator.html +472 -0
  90. package/package.json +2 -2
  91. package/src/policies/enforcers/__pycache__/_common.cpython-312.pyc +0 -0
  92. package/src/policies/enforcers/__pycache__/expert_review_required.cpython-312.pyc +0 -0
  93. package/src/policies/enforcers/__pycache__/quality_metrics_gate.cpython-312.pyc +0 -0
  94. package/src/policies/enforcers/plane_admin_protect.py +133 -0
  95. package/src/policies/schemas/policies/plane-admin-protect.md +55 -0
  96. package/templates/hooks/__pycache__/deliver_autoroute.cpython-312.pyc +0 -0
  97. package/templates/hooks/uap-policy-gate.sh +33 -0
  98. package/tools/agents/scripts/__pycache__/toolcall_path_normalizer.cpython-312.pyc +0 -0
  99. package/tools/agents/scripts/anthropic_proxy.py +493 -40
  100. package/tools/agents/tests/test_anthropic_proxy_streaming.py +171 -0
  101. package/tools/agents/tests/test_gate_failclosed_plane_admin.py +248 -0
  102. package/tools/agents/tests/test_plane_admin_protect.py +124 -0
  103. package/tools/agents/tests/test_stream_heartbeat.py +77 -0
@@ -0,0 +1,95 @@
1
+ /**
2
+ * Strata backend collectors for `uap inference health`.
3
+ *
4
+ * The local Qwen3.8 backend moved (2026-10-04) from the buun llama.cpp fork
5
+ * behind uap-gsq-rco-server.service to the Strata serve layer
6
+ * (`strata serve/server.py`, engine build 0.1.37, flash-next IQ3_XXS pack)
7
+ * on :8080. Strata deliberately mimics the llama.cpp HTTP surface (/v1,
8
+ * /slots, /props) but its /metrics is a JSON document, not Prometheus text —
9
+ * the llamacpp: counter names the existing probe scrapes do not exist there.
10
+ *
11
+ * Two sources, both parsed purely here:
12
+ *
13
+ * - `/metrics` (JSON): `engine` (pool size, KV kind, VRAM free), `live`
14
+ * (in-flight request), and `requests` — a bounded ring of COMPLETED
15
+ * requests with per-request prompt/decode timing and cache reuse. The
16
+ * ring is small (observed: 12), so it gives recent detail but cannot
17
+ * carry a life-of-process trend on its own.
18
+ * - the serve log (text): one `strata serve: prompt ...` summary line per
19
+ * completed request, appended for the process's whole life (observed:
20
+ * 4400+ lines over ~23h). These lines carry NO timestamps, so the
21
+ * parser assigns each sample a monotonically increasing index as its
22
+ * `at` clock — `analyzeTrend` only requires a monotonic clock, and
23
+ * early-vs-recent split by log position is exactly the process-lifetime
24
+ * comparison it wants. The price: strata log trends cannot be windowed
25
+ * with --since/--until; windowed analysis uses the /metrics ring, which
26
+ * does carry epoch timestamps, and honestly reports "not enough samples"
27
+ * when the ring is short.
28
+ */
29
+ import type { PrefillSample, ReuseSample, TrendSample } from './analysis.js';
30
+ export interface DraftSample {
31
+ accepted: number;
32
+ offered: number;
33
+ }
34
+ /** Everything the health analysis consumes, from either source. */
35
+ export interface StrataSamples {
36
+ /** Prefill throughput per request (tokens read, not reused). */
37
+ prefill: PrefillSample[];
38
+ /** Decode throughput per request. `tokens` carries the prompt DEPTH —
39
+ * decode speed depends on context depth, so depth is what the trend
40
+ * buckets must compare like-for-like. */
41
+ decode: TrendSample[];
42
+ reuse: ReuseSample[];
43
+ drafts: DraftSample[];
44
+ }
45
+ /** Parsed `engine` block of /metrics. */
46
+ export interface StrataEngine {
47
+ model?: string;
48
+ maxContext?: number;
49
+ /** KV kind as strata spells it, e.g. 'int8'. */
50
+ kv?: string;
51
+ /** Strata's own reserve-aware view of free VRAM (MiB). */
52
+ vramFreeMiB?: number;
53
+ version?: string;
54
+ spec?: number;
55
+ kvResident?: number;
56
+ }
57
+ export interface StrataLive {
58
+ state?: string;
59
+ phase?: string;
60
+ promptTokens?: number;
61
+ }
62
+ /** Parse a strata serve log (or any slice of one) into samples. `at` values
63
+ * are line indices — monotonic, comparable, and deliberately NOT wall time
64
+ * (the log has no timestamps). */
65
+ export declare function parseStrataLog(text: string): StrataSamples;
66
+ /** Structural guard for the /metrics document: it must have an `engine`
67
+ * object with a `model` string. Anything else (Prometheus text from a
68
+ * llama.cpp server, an HTML error page) is "not strata", not a parse error. */
69
+ export declare function looksLikeStrataMetrics(parsed: unknown): parsed is {
70
+ engine: Record<string, unknown>;
71
+ } & {
72
+ live?: Record<string, unknown>;
73
+ requests?: unknown[];
74
+ };
75
+ /** Parse the /metrics `engine` + `live` blocks into typed facts. */
76
+ export declare function parseStrataEngine(doc: {
77
+ engine: Record<string, unknown>;
78
+ live?: Record<string, unknown>;
79
+ }): {
80
+ engine: StrataEngine;
81
+ live: StrataLive;
82
+ };
83
+ /** Parse the /metrics `requests` ring into samples. Ring entries carry real
84
+ * epoch seconds in `time`, so these samples CAN be windowed — unlike
85
+ * log-derived samples. An entry without a finite `time` is DROPPED, not
86
+ * given a fallback index clock: mixing a small line-index with epoch-ms
87
+ * inside one array would scramble analyzeTrend's era split, and the repo
88
+ * doctrine is UNKNOWN over a guess. */
89
+ export declare function parseStrataRequests(requests: unknown[] | undefined): StrataSamples;
90
+ /** Strata's KV kind string → bits per value, for the pool-quality signal.
91
+ * Unknown kinds yield undefined (UNKNOWN, never a guess). */
92
+ export declare function strataKvBitsPerValue(kv: string | undefined): number | undefined;
93
+ /** Mean draft-acceptance rate over the samples, when any exist. */
94
+ export declare function draftAcceptanceRate(drafts: DraftSample[]): number | undefined;
95
+ //# sourceMappingURL=strata.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"strata.d.ts","sourceRoot":"","sources":["../../src/inference/strata.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAE7E,MAAM,WAAW,WAAW;IAC1B,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,mEAAmE;AACnE,MAAM,WAAW,aAAa;IAC5B,gEAAgE;IAChE,OAAO,EAAE,aAAa,EAAE,CAAC;IACzB;;6CAEyC;IACzC,MAAM,EAAE,WAAW,EAAE,CAAC;IACtB,KAAK,EAAE,WAAW,EAAE,CAAC;IACrB,MAAM,EAAE,WAAW,EAAE,CAAC;CACvB;AAED,yCAAyC;AACzC,MAAM,WAAW,YAAY;IAC3B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,gDAAgD;IAChD,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,0DAA0D;IAC1D,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,UAAU;IACzB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAiBD;;kCAEkC;AAClC,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,aAAa,CA0B1D;AAED;;+EAE+E;AAC/E,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,OAAO,GAAG,MAAM,IAAI;IAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;CAAE,GAAG;IACvG,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC/B,QAAQ,CAAC,EAAE,OAAO,EAAE,CAAC;CACtB,CAQA;AAKD,oEAAoE;AACpE,wBAAgB,iBAAiB,CAAC,GAAG,EAAE;IACrC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAChC,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAChC,GAAG;IAAE,MAAM,EAAE,YAAY,CAAC;IAAC,IAAI,EAAE,UAAU,CAAA;CAAE,CAkB7C;AAED;;;;;uCAKuC;AACvC,wBAAgB,mBAAmB,CAAC,QAAQ,EAAE,OAAO,EAAE,GAAG,SAAS,GAAG,aAAa,CA4BlF;AAED;6DAC6D;AAC7D,wBAAgB,oBAAoB,CAAC,EAAE,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,GAAG,SAAS,CAW/E;AAED,mEAAmE;AACnE,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,WAAW,EAAE,GAAG,MAAM,GAAG,SAAS,CAI7E"}
@@ -0,0 +1,167 @@
1
+ /**
2
+ * Strata backend collectors for `uap inference health`.
3
+ *
4
+ * The local Qwen3.8 backend moved (2026-10-04) from the buun llama.cpp fork
5
+ * behind uap-gsq-rco-server.service to the Strata serve layer
6
+ * (`strata serve/server.py`, engine build 0.1.37, flash-next IQ3_XXS pack)
7
+ * on :8080. Strata deliberately mimics the llama.cpp HTTP surface (/v1,
8
+ * /slots, /props) but its /metrics is a JSON document, not Prometheus text —
9
+ * the llamacpp: counter names the existing probe scrapes do not exist there.
10
+ *
11
+ * Two sources, both parsed purely here:
12
+ *
13
+ * - `/metrics` (JSON): `engine` (pool size, KV kind, VRAM free), `live`
14
+ * (in-flight request), and `requests` — a bounded ring of COMPLETED
15
+ * requests with per-request prompt/decode timing and cache reuse. The
16
+ * ring is small (observed: 12), so it gives recent detail but cannot
17
+ * carry a life-of-process trend on its own.
18
+ * - the serve log (text): one `strata serve: prompt ...` summary line per
19
+ * completed request, appended for the process's whole life (observed:
20
+ * 4400+ lines over ~23h). These lines carry NO timestamps, so the
21
+ * parser assigns each sample a monotonically increasing index as its
22
+ * `at` clock — `analyzeTrend` only requires a monotonic clock, and
23
+ * early-vs-recent split by log position is exactly the process-lifetime
24
+ * comparison it wants. The price: strata log trends cannot be windowed
25
+ * with --since/--until; windowed analysis uses the /metrics ring, which
26
+ * does carry epoch timestamps, and honestly reports "not enough samples"
27
+ * when the ring is short.
28
+ */
29
+ /**
30
+ * One completed-request summary line from the strata serve log:
31
+ *
32
+ * strata serve: prompt 19307 tokens = 15536 reused + 3771 read in 4189 ms
33
+ * (900.2 tok/s), 117 generated in 2471 ms (47.4 tok/s), drafts accepted
34
+ * 80 of 93, 2 checkpoints
35
+ *
36
+ * The trailing segments (drafts, checkpoints) are optional so a strata
37
+ * release that drops one keeps the rest of the sample intact; the core
38
+ * segment order is fixed.
39
+ */
40
+ const REQUEST_LINE_RE = /prompt (\d+) tokens = (\d+) reused \+ (\d+) read in (\d+(?:\.\d+)?) ms \((\d+(?:\.\d+)?) tok\/s\), (\d+) generated in (\d+(?:\.\d+)?) ms \((\d+(?:\.\d+)?) tok\/s\)/;
41
+ const DRAFTS_RE = /drafts accepted (\d+) of (\d+)/;
42
+ /** Parse a strata serve log (or any slice of one) into samples. `at` values
43
+ * are line indices — monotonic, comparable, and deliberately NOT wall time
44
+ * (the log has no timestamps). */
45
+ export function parseStrataLog(text) {
46
+ const out = { prefill: [], decode: [], reuse: [], drafts: [] };
47
+ let at = 0;
48
+ for (const line of text.split('\n')) {
49
+ at += 1;
50
+ const m = REQUEST_LINE_RE.exec(line);
51
+ if (!m)
52
+ continue;
53
+ const promptTokens = Number(m[1]);
54
+ const reused = Number(m[2]);
55
+ const read = Number(m[3]);
56
+ const prefillTps = Number(m[5]);
57
+ const generated = Number(m[6]);
58
+ const decodeTps = Number(m[8]);
59
+ if (![promptTokens, reused, read, prefillTps, generated, decodeTps].every(Number.isFinite))
60
+ continue;
61
+ if (prefillTps < 0 || decodeTps < 0)
62
+ continue; // parse artefact, not a measurement
63
+ out.prefill.push({ at, tokens: read, tokensPerSecond: prefillTps });
64
+ out.decode.push({ at, tokens: promptTokens, tokensPerSecond: decodeTps });
65
+ out.reuse.push({ at, incoming: promptTokens, reused });
66
+ const d = DRAFTS_RE.exec(line);
67
+ if (d) {
68
+ const accepted = Number(d[1]);
69
+ const offered = Number(d[2]);
70
+ if (Number.isFinite(accepted) && Number.isFinite(offered))
71
+ out.drafts.push({ accepted, offered });
72
+ }
73
+ }
74
+ return out;
75
+ }
76
+ /** Structural guard for the /metrics document: it must have an `engine`
77
+ * object with a `model` string. Anything else (Prometheus text from a
78
+ * llama.cpp server, an HTML error page) is "not strata", not a parse error. */
79
+ export function looksLikeStrataMetrics(parsed) {
80
+ return (typeof parsed === 'object' &&
81
+ parsed !== null &&
82
+ typeof parsed.engine === 'object' &&
83
+ parsed.engine !== null &&
84
+ typeof parsed.engine.model === 'string');
85
+ }
86
+ const finiteNumber = (v) => typeof v === 'number' && Number.isFinite(v) ? v : undefined;
87
+ /** Parse the /metrics `engine` + `live` blocks into typed facts. */
88
+ export function parseStrataEngine(doc) {
89
+ const e = doc.engine;
90
+ return {
91
+ engine: {
92
+ model: typeof e.model === 'string' ? e.model : undefined,
93
+ maxContext: finiteNumber(e.max_context) ?? finiteNumber(e.context),
94
+ kv: typeof e.kv === 'string' ? e.kv : undefined,
95
+ vramFreeMiB: finiteNumber(e.vram_free_mib),
96
+ version: typeof e.version === 'string' ? e.version : undefined,
97
+ spec: finiteNumber(e.spec),
98
+ kvResident: finiteNumber(e.kv_resident),
99
+ },
100
+ live: {
101
+ state: typeof doc.live?.state === 'string' ? doc.live.state : undefined,
102
+ phase: typeof doc.live?.phase === 'string' ? doc.live.phase : undefined,
103
+ promptTokens: finiteNumber(doc.live?.prompt_tokens),
104
+ },
105
+ };
106
+ }
107
+ /** Parse the /metrics `requests` ring into samples. Ring entries carry real
108
+ * epoch seconds in `time`, so these samples CAN be windowed — unlike
109
+ * log-derived samples. An entry without a finite `time` is DROPPED, not
110
+ * given a fallback index clock: mixing a small line-index with epoch-ms
111
+ * inside one array would scramble analyzeTrend's era split, and the repo
112
+ * doctrine is UNKNOWN over a guess. */
113
+ export function parseStrataRequests(requests) {
114
+ const out = { prefill: [], decode: [], reuse: [], drafts: [] };
115
+ for (const r of requests ?? []) {
116
+ if (typeof r !== 'object' || r === null)
117
+ continue;
118
+ const req = r;
119
+ const time = finiteNumber(req.time);
120
+ if (time === undefined)
121
+ continue; // no clock, no sample — never a guess
122
+ const at = time * 1000;
123
+ if (!Number.isFinite(at))
124
+ continue; // overflow guard, same doctrine
125
+ const read = finiteNumber(req.prompt_read);
126
+ const promptMs = finiteNumber(req.prompt_ms);
127
+ const promptTokens = finiteNumber(req.prompt_tokens);
128
+ const decodeTps = finiteNumber(req.decode_tok_s);
129
+ if (read !== undefined && promptMs !== undefined && promptMs > 0) {
130
+ out.prefill.push({ at, tokens: read, tokensPerSecond: read / (promptMs / 1000) });
131
+ }
132
+ if (decodeTps !== undefined && promptTokens !== undefined) {
133
+ out.decode.push({ at, tokens: promptTokens, tokensPerSecond: decodeTps });
134
+ }
135
+ const reused = finiteNumber(req.reused);
136
+ if (promptTokens !== undefined && reused !== undefined) {
137
+ out.reuse.push({ at, incoming: promptTokens, reused });
138
+ }
139
+ const accepted = finiteNumber(req.drafts_accepted);
140
+ const offered = finiteNumber(req.drafts_offered);
141
+ if (accepted !== undefined && offered !== undefined)
142
+ out.drafts.push({ accepted, offered });
143
+ }
144
+ return out;
145
+ }
146
+ /** Strata's KV kind string → bits per value, for the pool-quality signal.
147
+ * Unknown kinds yield undefined (UNKNOWN, never a guess). */
148
+ export function strataKvBitsPerValue(kv) {
149
+ switch (kv) {
150
+ case 'int8':
151
+ return 8;
152
+ case 'int4':
153
+ return 4;
154
+ case 'fp16':
155
+ return 16;
156
+ default:
157
+ return undefined;
158
+ }
159
+ }
160
+ /** Mean draft-acceptance rate over the samples, when any exist. */
161
+ export function draftAcceptanceRate(drafts) {
162
+ const offered = drafts.reduce((a, d) => a + d.offered, 0);
163
+ if (offered <= 0)
164
+ return undefined;
165
+ return drafts.reduce((a, d) => a + d.accepted, 0) / offered;
166
+ }
167
+ //# sourceMappingURL=strata.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"strata.js","sourceRoot":"","sources":["../../src/inference/strata.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,29 @@
1
+ import Database from 'better-sqlite3';
2
+ /**
3
+ * Singleton SQLite store for the mission ledger, mirroring the coordination
4
+ * database's concurrency posture (WAL + busy timeout) since the orchestrator
5
+ * daemon and CLI invocations read and write it concurrently.
6
+ */
7
+ export declare class MissionDatabase {
8
+ private db;
9
+ private static instance;
10
+ private constructor();
11
+ static getInstance(dbPath: string): MissionDatabase;
12
+ static resetInstance(): void;
13
+ getDatabase(): Database.Database;
14
+ close(): void;
15
+ private initSchema;
16
+ /** Ledger schema version. Bump + add a case in `migrate` when it changes. */
17
+ private static readonly SCHEMA_VERSION;
18
+ /**
19
+ * Stamp `PRAGMA user_version` and run any pending migrations. Without the
20
+ * stamp, the first post-release schema change becomes a breaking migration
21
+ * (architect review P2-3).
22
+ */
23
+ private stampSchemaVersion;
24
+ /** Placeholder for future versioned migrations (v1 is the baseline). */
25
+ private migrate;
26
+ }
27
+ /** Default ledger location: `<projectRoot>/.uap/missions.db`. */
28
+ export declare function getMissionDbPath(projectRoot: string): string;
29
+ //# sourceMappingURL=database.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"database.d.ts","sourceRoot":"","sources":["../../src/mission/database.ts"],"names":[],"mappings":"AAAA,OAAO,QAAQ,MAAM,gBAAgB,CAAC;AAItC;;;;GAIG;AACH,qBAAa,eAAe;IAC1B,OAAO,CAAC,EAAE,CAAoB;IAC9B,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAgC;IAEvD,OAAO;IAeP,MAAM,CAAC,WAAW,CAAC,MAAM,EAAE,MAAM,GAAG,eAAe;IAOnD,MAAM,CAAC,aAAa,IAAI,IAAI;IAO5B,WAAW,IAAI,QAAQ,CAAC,QAAQ;IAIhC,KAAK,IAAI,IAAI;IAIb,OAAO,CAAC,UAAU;IA+DlB,6EAA6E;IAC7E,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,cAAc,CAAK;IAE3C;;;;OAIG;IACH,OAAO,CAAC,kBAAkB;IAS1B,wEAAwE;IACxE,OAAO,CAAC,OAAO;CAGhB;AAED,iEAAiE;AACjE,wBAAgB,gBAAgB,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM,CAE5D"}
@@ -0,0 +1,131 @@
1
+ import Database from 'better-sqlite3';
2
+ import { existsSync, mkdirSync } from 'fs';
3
+ import { dirname, join } from 'path';
4
+ /**
5
+ * Singleton SQLite store for the mission ledger, mirroring the coordination
6
+ * database's concurrency posture (WAL + busy timeout) since the orchestrator
7
+ * daemon and CLI invocations read and write it concurrently.
8
+ */
9
+ export class MissionDatabase {
10
+ db;
11
+ static instance = null;
12
+ constructor(dbPath) {
13
+ const dir = dirname(dbPath);
14
+ if (!existsSync(dir)) {
15
+ mkdirSync(dir, { recursive: true });
16
+ }
17
+ this.db = new Database(dbPath);
18
+ this.db.pragma('journal_mode = WAL');
19
+ this.db.pragma('synchronous = NORMAL');
20
+ this.db.pragma('busy_timeout = 10000');
21
+ // The REFERENCES clauses below are real: SQLite defaults foreign_keys OFF,
22
+ // which would leave them decorative (code review P3).
23
+ this.db.pragma('foreign_keys = ON');
24
+ this.initSchema();
25
+ }
26
+ static getInstance(dbPath) {
27
+ if (!MissionDatabase.instance) {
28
+ MissionDatabase.instance = new MissionDatabase(dbPath);
29
+ }
30
+ return MissionDatabase.instance;
31
+ }
32
+ static resetInstance() {
33
+ if (MissionDatabase.instance) {
34
+ MissionDatabase.instance.close();
35
+ MissionDatabase.instance = null;
36
+ }
37
+ }
38
+ getDatabase() {
39
+ return this.db;
40
+ }
41
+ close() {
42
+ this.db.close();
43
+ }
44
+ initSchema() {
45
+ this.db.exec(`
46
+ -- Missions: durable goals above deliver runs.
47
+ CREATE TABLE IF NOT EXISTS missions (
48
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
49
+ goal TEXT NOT NULL,
50
+ acceptance TEXT NOT NULL,
51
+ acceptance_hash TEXT NOT NULL,
52
+ status TEXT NOT NULL CHECK(status IN ('active', 'paused', 'delivered', 'failed')),
53
+ preset_id TEXT,
54
+ latest_run_id TEXT,
55
+ launch_count INTEGER NOT NULL DEFAULT 0,
56
+ relaunch_count INTEGER NOT NULL DEFAULT 0,
57
+ last_launch_at TEXT,
58
+ launch_pid INTEGER,
59
+ created_at TEXT NOT NULL,
60
+ updated_at TEXT NOT NULL
61
+ );
62
+ CREATE INDEX IF NOT EXISTS idx_missions_status ON missions(status);
63
+
64
+ -- Attempt history: one row per launch/outcome. The failed rows are the
65
+ -- struggle metric — repeated failures per task ref trigger escalation.
66
+ CREATE TABLE IF NOT EXISTS mission_attempts (
67
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
68
+ mission_id INTEGER NOT NULL REFERENCES missions(id),
69
+ run_id TEXT,
70
+ task_ref TEXT,
71
+ outcome TEXT NOT NULL CHECK(outcome IN ('launched', 'delivered', 'failed', 'interrupted')),
72
+ summary TEXT,
73
+ observed_at TEXT,
74
+ created_at TEXT NOT NULL
75
+ );
76
+ CREATE INDEX IF NOT EXISTS idx_attempts_mission ON mission_attempts(mission_id);
77
+ CREATE INDEX IF NOT EXISTS idx_attempts_run ON mission_attempts(run_id);
78
+
79
+ -- Approval-gated salvage proposals seeded from failed attempts.
80
+ CREATE TABLE IF NOT EXISTS salvage_proposals (
81
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
82
+ mission_id INTEGER NOT NULL REFERENCES missions(id),
83
+ from_attempt_id INTEGER,
84
+ task_ref TEXT,
85
+ proposal TEXT NOT NULL,
86
+ status TEXT NOT NULL CHECK(status IN ('proposed', 'approved', 'rejected')),
87
+ created_at TEXT NOT NULL,
88
+ decided_at TEXT
89
+ );
90
+ CREATE INDEX IF NOT EXISTS idx_salvage_mission ON salvage_proposals(mission_id);
91
+ CREATE INDEX IF NOT EXISTS idx_salvage_status ON salvage_proposals(status);
92
+
93
+ -- Explicit supersede history for frozen acceptance criteria.
94
+ CREATE TABLE IF NOT EXISTS acceptance_revisions (
95
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
96
+ mission_id INTEGER NOT NULL REFERENCES missions(id),
97
+ prior_acceptance TEXT NOT NULL,
98
+ prior_hash TEXT NOT NULL,
99
+ reason TEXT NOT NULL,
100
+ created_at TEXT NOT NULL
101
+ );
102
+ CREATE INDEX IF NOT EXISTS idx_acceptance_revisions_mission ON acceptance_revisions(mission_id);
103
+ `);
104
+ this.stampSchemaVersion();
105
+ }
106
+ /** Ledger schema version. Bump + add a case in `migrate` when it changes. */
107
+ static SCHEMA_VERSION = 1;
108
+ /**
109
+ * Stamp `PRAGMA user_version` and run any pending migrations. Without the
110
+ * stamp, the first post-release schema change becomes a breaking migration
111
+ * (architect review P2-3).
112
+ */
113
+ stampSchemaVersion() {
114
+ const current = this.db.pragma('user_version', { simple: true });
115
+ if (current === MissionDatabase.SCHEMA_VERSION)
116
+ return;
117
+ if (current > 0 && current < MissionDatabase.SCHEMA_VERSION) {
118
+ this.migrate(current);
119
+ }
120
+ this.db.pragma(`user_version = ${MissionDatabase.SCHEMA_VERSION}`);
121
+ }
122
+ /** Placeholder for future versioned migrations (v1 is the baseline). */
123
+ migrate(_fromVersion) {
124
+ /* no migrations yet — schema v1 is the first released shape */
125
+ }
126
+ }
127
+ /** Default ledger location: `<projectRoot>/.uap/missions.db`. */
128
+ export function getMissionDbPath(projectRoot) {
129
+ return join(projectRoot, '.uap', 'missions.db');
130
+ }
131
+ //# sourceMappingURL=database.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"database.js","sourceRoot":"","sources":["../../src/mission/database.ts"],"names":[],"mappings":"AAAA,OAAO,QAAQ,MAAM,gBAAgB,CAAC;AACtC,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,IAAI,CAAC;AAC3C,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAErC;;;;GAIG;AACH,MAAM,OAAO,eAAe;IAClB,EAAE,CAAoB;IACtB,MAAM,CAAC,QAAQ,GAA2B,IAAI,CAAC;IAEvD,YAAoB,MAAc;QAChC,MAAM,GAAG,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;QAC5B,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;YACrB,SAAS,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QACtC,CAAC;QACD,IAAI,CAAC,EAAE,GAAG,IAAI,QAAQ,CAAC,MAAM,CAAC,CAAC;QAC/B,IAAI,CAAC,EAAE,CAAC,MAAM,CAAC,oBAAoB,CAAC,CAAC;QACrC,IAAI,CAAC,EAAE,CAAC,MAAM,CAAC,sBAAsB,CAAC,CAAC;QACvC,IAAI,CAAC,EAAE,CAAC,MAAM,CAAC,sBAAsB,CAAC,CAAC;QACvC,2EAA2E;QAC3E,sDAAsD;QACtD,IAAI,CAAC,EAAE,CAAC,MAAM,CAAC,mBAAmB,CAAC,CAAC;QACpC,IAAI,CAAC,UAAU,EAAE,CAAC;IACpB,CAAC;IAED,MAAM,CAAC,WAAW,CAAC,MAAc;QAC/B,IAAI,CAAC,eAAe,CAAC,QAAQ,EAAE,CAAC;YAC9B,eAAe,CAAC,QAAQ,GAAG,IAAI,eAAe,CAAC,MAAM,CAAC,CAAC;QACzD,CAAC;QACD,OAAO,eAAe,CAAC,QAAQ,CAAC;IAClC,CAAC;IAED,MAAM,CAAC,aAAa;QAClB,IAAI,eAAe,CAAC,QAAQ,EAAE,CAAC;YAC7B,eAAe,CAAC,QAAQ,CAAC,KAAK,EAAE,CAAC;YACjC,eAAe,CAAC,QAAQ,GAAG,IAAI,CAAC;QAClC,CAAC;IACH,CAAC;IAED,WAAW;QACT,OAAO,IAAI,CAAC,EAAE,CAAC;IACjB,CAAC;IAED,KAAK;QACH,IAAI,CAAC,EAAE,CAAC,KAAK,EAAE,CAAC;IAClB,CAAC;IAEO,UAAU;QAChB,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;KA0DZ,CAAC,CAAC;QACH,IAAI,CAAC,kBAAkB,EAAE,CAAC;IAC5B,CAAC;IAED,6EAA6E;IACrE,MAAM,CAAU,cAAc,GAAG,CAAC,CAAC;IAE3C;;;;OAIG;IACK,kBAAkB;QACxB,MAAM,OAAO,GAAG,IAAI,CAAC,EAAE,CAAC,MAAM,CAAC,cAAc,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,CAAW,CAAC;QAC3E,IAAI,OAAO,KAAK,eAAe,CAAC,cAAc;YAAE,OAAO;QACvD,IAAI,OAAO,GAAG,CAAC,IAAI,OAAO,GAAG,eAAe,CAAC,cAAc,EAAE,CAAC;YAC5D,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;QACxB,CAAC;QACD,IAAI,CAAC,EAAE,CAAC,MAAM,CAAC,kBAAkB,eAAe,CAAC,cAAc,EAAE,CAAC,CAAC;IACrE,CAAC;IAED,wEAAwE;IAChE,OAAO,CAAC,YAAoB;QAClC,+DAA+D;IACjE,CAAC;;AAGH,iEAAiE;AACjE,MAAM,UAAU,gBAAgB,CAAC,WAAmB;IAClD,OAAO,IAAI,CAAC,WAAW,EAAE,MAAM,EAAE,aAAa,CAAC,CAAC;AAClD,CAAC"}
@@ -0,0 +1,109 @@
1
+ /**
2
+ * Mission ledger service — typed operations over the mission database.
3
+ *
4
+ * The ledger is the durable goal layer: a mission's acceptance criteria are
5
+ * FROZEN at creation (sha256) and only change through an explicit, recorded
6
+ * replan. Attempt history feeds the struggle metric; failed attempts seed
7
+ * approval-gated salvage proposals.
8
+ */
9
+ import type Database from 'better-sqlite3';
10
+ import type { Mission, MissionAttempt, MissionAttemptOutcome, MissionStatus, SalvageProposal, SalvageStatus, AcceptanceRevision } from '../types/mission.js';
11
+ /** sha256 of the trimmed acceptance text — the freeze-time hash. */
12
+ export declare function hashAcceptance(acceptance: string): string;
13
+ /**
14
+ * Exponential relaunch backoff (minutes): 15, 30, 60, ... capped at one day.
15
+ * A crash-looping mission must not burn cycles every poll — the same lesson
16
+ * as the systemd start-rate limiter: back off, don't hammer.
17
+ */
18
+ export declare function relaunchBackoffMinutes(relaunchCount: number): number;
19
+ /** Open (or reuse) the mission database for a project root. PURE-ish: no writes. */
20
+ export declare function openMissionDb(projectRoot: string): Database.Database;
21
+ /** Test seam: reset the singleton so a new path is honored. */
22
+ export declare function resetMissionDb(): void;
23
+ /** Create a mission with frozen acceptance criteria. */
24
+ export declare function createMission(db: Database.Database, input: {
25
+ goal: string;
26
+ acceptance: string;
27
+ presetId?: string;
28
+ }): Mission;
29
+ export declare function getMission(db: Database.Database, id: number): Mission;
30
+ export declare function listMissions(db: Database.Database, opts?: {
31
+ status?: MissionStatus;
32
+ limit?: number;
33
+ }): Mission[];
34
+ export declare function setMissionStatus(db: Database.Database, id: number, status: MissionStatus): boolean;
35
+ /**
36
+ * Explicit replan: supersede the frozen acceptance criteria. The prior text
37
+ * and hash move to the revisions history — never a silent change. The run
38
+ * link and backoff counters RESET: the prior run embeds the OLD criteria, so
39
+ * resuming it could deliver against superseded acceptance. The next poll
40
+ * launches a fresh run under the new criteria (new marker, new pid).
41
+ */
42
+ export declare function replanAcceptance(db: Database.Database, id: number, newAcceptance: string, reason: string): Mission;
43
+ /** Does `acceptance` match the mission's frozen criteria? (merge-gate hook). */
44
+ export declare function verifyAcceptanceHash(db: Database.Database, id: number, acceptance: string): boolean;
45
+ export declare function listAcceptanceRevisions(db: Database.Database, missionId: number): AcceptanceRevision[];
46
+ /**
47
+ * How recent a claim blocks another: two concurrent cycles (daemon poll +
48
+ * `uap mission create --launch`) must not both spawn. The conditional UPDATE
49
+ * below makes the claim atomic; this window (not the 10-min decision grace)
50
+ * is the anti-race guard.
51
+ */
52
+ export declare const LAUNCH_CLAIM_MS = 60000;
53
+ /**
54
+ * Atomically claim the right to launch/resume. Returns the launch stamp when
55
+ * this cycle WON the claim, null when another cycle launched within the
56
+ * window (the caller must NOT spawn). Single-statement conditional update —
57
+ * no read-then-write race. `nowMs` is the poll cycle's clock (injected for
58
+ * tests; decisions and claims must share one timeline).
59
+ */
60
+ export declare function claimLaunch(db: Database.Database, id: number, kind: 'fresh' | 'resume', nowMs?: number): string | null;
61
+ /**
62
+ * Record the pid of the launch we spawned, guarded by OUR claim stamp so a
63
+ * concurrent winner's stamp is never overwritten.
64
+ */
65
+ export declare function setLaunchPid(db: Database.Database, id: number, stamp: string, pid: number): void;
66
+ /**
67
+ * Link a discovered deliver run to the mission WITHOUT counting a launch:
68
+ * the poll cycle finds the run the mission's own launch created (by its
69
+ * embedded `mission:#<id>` marker) and records the linkage.
70
+ */
71
+ export declare function linkRun(db: Database.Database, id: number, runId: string): boolean;
72
+ /**
73
+ * Record an attempt outcome.
74
+ *
75
+ * Rows tied to a RUN dedupe on (mission, run, outcome, taskRef, observedAt):
76
+ * a poll cycle that re-observes the SAME terminal run state (same
77
+ * updatedAt/exit time) cannot double-count it, while a genuinely NEW event
78
+ * for the same run (a resumed run failing again, a later exit) accumulates
79
+ * into the struggle metric. Without observedAt in the key, a crash-looping
80
+ * run could contribute at most one 'failed' row ever and never reach the
81
+ * struggle threshold (code review P1). Whole-mission notes (no runId) are
82
+ * never deduped: each occurrence is a distinct event.
83
+ */
84
+ export declare function recordAttempt(db: Database.Database, input: {
85
+ missionId: number;
86
+ runId?: string;
87
+ taskRef?: string;
88
+ outcome: MissionAttemptOutcome;
89
+ summary?: string;
90
+ /** What this observation saw (run.updatedAt / exit.at). */
91
+ observedAt?: string;
92
+ }): void;
93
+ export declare function listAttempts(db: Database.Database, missionId: number): MissionAttempt[];
94
+ /** Struggle metric: failed attempts, whole-mission (no taskRef) or per ref. */
95
+ export declare function failedAttemptCount(db: Database.Database, missionId: number, taskRef?: string): number;
96
+ export declare function proposeSalvage(db: Database.Database, input: {
97
+ missionId: number;
98
+ fromAttemptId?: number;
99
+ taskRef?: string;
100
+ proposal: string;
101
+ }): SalvageProposal;
102
+ /** True when an OPEN proposal already cites the same attempt (dedupe). */
103
+ export declare function hasOpenSalvageForAttempt(db: Database.Database, missionId: number, attemptId?: number): boolean;
104
+ export declare function decideSalvage(db: Database.Database, id: number, status: 'approved' | 'rejected'): SalvageProposal;
105
+ export declare function listSalvage(db: Database.Database, opts?: {
106
+ missionId?: number;
107
+ status?: SalvageStatus;
108
+ }): SalvageProposal[];
109
+ //# sourceMappingURL=ledger.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ledger.d.ts","sourceRoot":"","sources":["../../src/mission/ledger.ts"],"names":[],"mappings":"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"}