harnery 0.36.0 → 0.37.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 (311) hide show
  1. package/dist/commander.js +4 -0
  2. package/dist/commands/agents.d.ts.map +1 -1
  3. package/dist/commands/agents.js +87 -46
  4. package/dist/commands/artifacts.d.ts.map +1 -1
  5. package/dist/commands/artifacts.js +26 -1
  6. package/dist/commands/browse.d.ts.map +1 -1
  7. package/dist/commands/browse.js +11 -0
  8. package/dist/commands/diagnostics.d.ts +4 -0
  9. package/dist/commands/diagnostics.d.ts.map +1 -0
  10. package/dist/commands/diagnostics.js +229 -0
  11. package/dist/commands/files.d.ts +12 -0
  12. package/dist/commands/files.d.ts.map +1 -1
  13. package/dist/commands/files.js +54 -1
  14. package/dist/commands/governor.d.ts.map +1 -1
  15. package/dist/commands/governor.js +4 -0
  16. package/dist/commands/ledger-v3.d.ts.map +1 -1
  17. package/dist/commands/ledger-v3.js +71 -2
  18. package/dist/commands/qa-run.d.ts +4 -0
  19. package/dist/commands/qa-run.d.ts.map +1 -0
  20. package/dist/commands/qa-run.js +141 -0
  21. package/dist/commands/resources.d.ts +4 -0
  22. package/dist/commands/resources.d.ts.map +1 -0
  23. package/dist/commands/resources.js +29 -0
  24. package/dist/commands/supervisor.d.ts +4 -0
  25. package/dist/commands/supervisor.d.ts.map +1 -0
  26. package/dist/commands/supervisor.js +101 -0
  27. package/dist/commands/web.d.ts.map +1 -1
  28. package/dist/commands/web.js +17 -0
  29. package/dist/commands/workflow.d.ts.map +1 -1
  30. package/dist/commands/workflow.js +4 -0
  31. package/dist/core/agents/cli.js +7 -3
  32. package/dist/core/agents/health.d.ts +17 -0
  33. package/dist/core/agents/health.d.ts.map +1 -0
  34. package/dist/core/agents/health.js +109 -0
  35. package/dist/core/agents/mailbox.d.ts +92 -0
  36. package/dist/core/agents/mailbox.d.ts.map +1 -0
  37. package/dist/core/agents/mailbox.js +325 -0
  38. package/dist/core/agents/reconcile-coordination-v3.d.ts +44 -0
  39. package/dist/core/agents/reconcile-coordination-v3.d.ts.map +1 -0
  40. package/dist/core/agents/reconcile-coordination-v3.js +58 -0
  41. package/dist/core/agents/render/prompt-context.d.ts +5 -0
  42. package/dist/core/agents/render/prompt-context.d.ts.map +1 -1
  43. package/dist/core/agents/render/prompt-context.js +34 -13
  44. package/dist/core/agents/render/session-context.d.ts +8 -0
  45. package/dist/core/agents/render/session-context.d.ts.map +1 -1
  46. package/dist/core/agents/render/session-context.js +34 -3
  47. package/dist/core/agents/rules/commit-conflict.d.ts.map +1 -1
  48. package/dist/core/agents/rules/commit-conflict.js +50 -1
  49. package/dist/core/agents/rules/stop-hook.d.ts.map +1 -1
  50. package/dist/core/agents/rules/stop-hook.js +6 -10
  51. package/dist/core/agents/session-finalizer-v3.js +4 -1
  52. package/dist/core/artifacts/index.d.ts +26 -1
  53. package/dist/core/artifacts/index.d.ts.map +1 -1
  54. package/dist/core/artifacts/index.js +146 -6
  55. package/dist/core/config.d.ts +12 -0
  56. package/dist/core/config.d.ts.map +1 -1
  57. package/dist/core/config.js +43 -0
  58. package/dist/core/diagnostics/advice.d.ts +9 -0
  59. package/dist/core/diagnostics/advice.d.ts.map +1 -0
  60. package/dist/core/diagnostics/advice.js +112 -0
  61. package/dist/core/diagnostics/bundle.d.ts +35 -0
  62. package/dist/core/diagnostics/bundle.d.ts.map +1 -0
  63. package/dist/core/diagnostics/bundle.js +874 -0
  64. package/dist/core/diagnostics/comparison.d.ts +5 -0
  65. package/dist/core/diagnostics/comparison.d.ts.map +1 -0
  66. package/dist/core/diagnostics/comparison.js +444 -0
  67. package/dist/core/diagnostics/contract.d.ts +245 -0
  68. package/dist/core/diagnostics/contract.d.ts.map +1 -0
  69. package/dist/core/diagnostics/contract.js +18 -0
  70. package/dist/core/diagnostics/identity.d.ts +3 -0
  71. package/dist/core/diagnostics/identity.d.ts.map +1 -0
  72. package/dist/core/diagnostics/identity.js +10 -0
  73. package/dist/core/diagnostics/index.d.ts +8 -0
  74. package/dist/core/diagnostics/index.d.ts.map +1 -0
  75. package/dist/core/diagnostics/index.js +7 -0
  76. package/dist/core/diagnostics/replay.d.ts +8 -0
  77. package/dist/core/diagnostics/replay.d.ts.map +1 -0
  78. package/dist/core/diagnostics/replay.js +213 -0
  79. package/dist/core/diagnostics/sanitize.d.ts +9 -0
  80. package/dist/core/diagnostics/sanitize.d.ts.map +1 -0
  81. package/dist/core/diagnostics/sanitize.js +84 -0
  82. package/dist/core/events/legacy-storage/compression.d.ts +13 -0
  83. package/dist/core/events/legacy-storage/compression.d.ts.map +1 -0
  84. package/dist/core/events/legacy-storage/compression.js +107 -0
  85. package/dist/core/events/legacy-storage/index.d.ts +1 -0
  86. package/dist/core/events/legacy-storage/index.d.ts.map +1 -1
  87. package/dist/core/events/legacy-storage/index.js +1 -0
  88. package/dist/core/events/v3/archive-retention.d.ts +33 -0
  89. package/dist/core/events/v3/archive-retention.d.ts.map +1 -0
  90. package/dist/core/events/v3/archive-retention.js +195 -0
  91. package/dist/core/events/v3/capabilities.d.ts +1 -1
  92. package/dist/core/events/v3/capabilities.d.ts.map +1 -1
  93. package/dist/core/events/v3/capabilities.js +1 -0
  94. package/dist/core/events/v3/index.d.ts +1 -0
  95. package/dist/core/events/v3/index.d.ts.map +1 -1
  96. package/dist/core/events/v3/index.js +1 -0
  97. package/dist/core/events/v3/live-routing.d.ts.map +1 -1
  98. package/dist/core/events/v3/live-routing.js +1 -0
  99. package/dist/core/events/v3/producers/hook-base.d.ts +1 -1
  100. package/dist/core/events/v3/producers/hook-base.d.ts.map +1 -1
  101. package/dist/core/events/v3/producers/hook-base.js +13 -2
  102. package/dist/core/events/v3/producers/intake.d.ts.map +1 -1
  103. package/dist/core/events/v3/producers/intake.js +1 -0
  104. package/dist/core/events/v3/producers/recorder.d.ts +16 -0
  105. package/dist/core/events/v3/producers/recorder.d.ts.map +1 -1
  106. package/dist/core/events/v3/producers/recorder.js +88 -1
  107. package/dist/core/hooks/adapter/output.d.ts +8 -0
  108. package/dist/core/hooks/adapter/output.d.ts.map +1 -1
  109. package/dist/core/hooks/adapter/output.js +11 -1
  110. package/dist/core/hooks/cli.js +183 -192
  111. package/dist/core/hooks/health.d.ts +59 -0
  112. package/dist/core/hooks/health.d.ts.map +1 -0
  113. package/dist/core/hooks/health.js +84 -0
  114. package/dist/core/resources/contract.d.ts +90 -0
  115. package/dist/core/resources/contract.d.ts.map +1 -0
  116. package/dist/core/resources/contract.js +2 -0
  117. package/dist/core/resources/index.d.ts +6 -0
  118. package/dist/core/resources/index.d.ts.map +1 -0
  119. package/dist/core/resources/index.js +5 -0
  120. package/dist/core/resources/sampler.d.ts +27 -0
  121. package/dist/core/resources/sampler.d.ts.map +1 -0
  122. package/dist/core/resources/sampler.js +357 -0
  123. package/dist/core/resources/service-status.d.ts +3 -0
  124. package/dist/core/resources/service-status.d.ts.map +1 -0
  125. package/dist/core/resources/service-status.js +48 -0
  126. package/dist/core/resources/service.d.ts +26 -0
  127. package/dist/core/resources/service.d.ts.map +1 -0
  128. package/dist/core/resources/service.js +292 -0
  129. package/dist/core/resources/storage.d.ts +13 -0
  130. package/dist/core/resources/storage.d.ts.map +1 -0
  131. package/dist/core/resources/storage.js +30 -0
  132. package/dist/core/storage/atomic-json.d.ts +3 -0
  133. package/dist/core/storage/atomic-json.d.ts.map +1 -0
  134. package/dist/core/storage/atomic-json.js +15 -0
  135. package/dist/core/storage/builtins.d.ts.map +1 -1
  136. package/dist/core/storage/builtins.js +45 -6
  137. package/dist/core/storage/logger.d.ts +2 -0
  138. package/dist/core/storage/logger.d.ts.map +1 -1
  139. package/dist/core/storage/logger.js +2 -0
  140. package/dist/core/storage/query.d.ts +14 -0
  141. package/dist/core/storage/query.d.ts.map +1 -1
  142. package/dist/core/storage/query.js +51 -0
  143. package/dist/core/supervisor/activity.d.ts +4 -0
  144. package/dist/core/supervisor/activity.d.ts.map +1 -0
  145. package/dist/core/supervisor/activity.js +141 -0
  146. package/dist/core/supervisor/contract.d.ts +268 -0
  147. package/dist/core/supervisor/contract.d.ts.map +1 -0
  148. package/dist/core/supervisor/contract.js +35 -0
  149. package/dist/core/supervisor/explanations.d.ts +4 -0
  150. package/dist/core/supervisor/explanations.d.ts.map +1 -0
  151. package/dist/core/supervisor/explanations.js +71 -0
  152. package/dist/core/supervisor/findings.d.ts +20 -0
  153. package/dist/core/supervisor/findings.d.ts.map +1 -0
  154. package/dist/core/supervisor/findings.js +399 -0
  155. package/dist/core/supervisor/history.d.ts +9 -0
  156. package/dist/core/supervisor/history.d.ts.map +1 -0
  157. package/dist/core/supervisor/history.js +46 -0
  158. package/dist/core/supervisor/hook-health-alerts.d.ts +14 -0
  159. package/dist/core/supervisor/hook-health-alerts.d.ts.map +1 -0
  160. package/dist/core/supervisor/hook-health-alerts.js +70 -0
  161. package/dist/core/supervisor/hook-health-storage.d.ts +5 -0
  162. package/dist/core/supervisor/hook-health-storage.d.ts.map +1 -0
  163. package/dist/core/supervisor/hook-health-storage.js +24 -0
  164. package/dist/core/supervisor/hook-health.d.ts +72 -0
  165. package/dist/core/supervisor/hook-health.d.ts.map +1 -0
  166. package/dist/core/supervisor/hook-health.js +203 -0
  167. package/dist/core/supervisor/hooks.d.ts +10 -0
  168. package/dist/core/supervisor/hooks.d.ts.map +1 -0
  169. package/dist/core/supervisor/hooks.js +28 -0
  170. package/dist/core/supervisor/index.d.ts +15 -0
  171. package/dist/core/supervisor/index.d.ts.map +1 -0
  172. package/dist/core/supervisor/index.js +14 -0
  173. package/dist/core/supervisor/log-feed.d.ts +9 -0
  174. package/dist/core/supervisor/log-feed.d.ts.map +1 -0
  175. package/dist/core/supervisor/log-feed.js +103 -0
  176. package/dist/core/supervisor/service.d.ts +29 -0
  177. package/dist/core/supervisor/service.d.ts.map +1 -0
  178. package/dist/core/supervisor/service.js +450 -0
  179. package/dist/core/supervisor/services.d.ts +11 -0
  180. package/dist/core/supervisor/services.d.ts.map +1 -0
  181. package/dist/core/supervisor/services.js +155 -0
  182. package/dist/core/supervisor/status.d.ts +3 -0
  183. package/dist/core/supervisor/status.d.ts.map +1 -0
  184. package/dist/core/supervisor/status.js +48 -0
  185. package/dist/core/supervisor/storage.d.ts +30 -0
  186. package/dist/core/supervisor/storage.d.ts.map +1 -0
  187. package/dist/core/supervisor/storage.js +73 -0
  188. package/dist/core/supervisor/timeline.d.ts +3 -0
  189. package/dist/core/supervisor/timeline.d.ts.map +1 -0
  190. package/dist/core/supervisor/timeline.js +87 -0
  191. package/dist/core/workflow/admission.d.ts +23 -0
  192. package/dist/core/workflow/admission.d.ts.map +1 -0
  193. package/dist/core/workflow/admission.js +136 -0
  194. package/dist/core/workflow/engine.d.ts.map +1 -1
  195. package/dist/core/workflow/engine.js +77 -2
  196. package/dist/core/workflow/index.d.ts +3 -2
  197. package/dist/core/workflow/index.d.ts.map +1 -1
  198. package/dist/core/workflow/index.js +2 -1
  199. package/dist/core/workflow/proof.d.ts +2 -1
  200. package/dist/core/workflow/proof.d.ts.map +1 -1
  201. package/dist/core/workflow/proof.js +39 -1
  202. package/dist/core/workflow/run-state.d.ts +3 -2
  203. package/dist/core/workflow/run-state.d.ts.map +1 -1
  204. package/dist/core/workflow/run-state.js +8 -1
  205. package/dist/core/workflow/types.d.ts +33 -1
  206. package/dist/core/workflow/types.d.ts.map +1 -1
  207. package/dist/core/workflow/types.js +2 -1
  208. package/dist/lib/browser/client.d.ts +5 -0
  209. package/dist/lib/browser/client.d.ts.map +1 -1
  210. package/dist/lib/browser/client.js +1 -0
  211. package/dist/lib/browser/index.d.ts +2 -0
  212. package/dist/lib/browser/index.d.ts.map +1 -1
  213. package/dist/lib/browser/index.js +2 -0
  214. package/dist/lib/browser/qa-run-contracts.d.ts +173 -0
  215. package/dist/lib/browser/qa-run-contracts.d.ts.map +1 -0
  216. package/dist/lib/browser/qa-run-contracts.js +226 -0
  217. package/dist/lib/browser/qa-run.d.ts +51 -0
  218. package/dist/lib/browser/qa-run.d.ts.map +1 -0
  219. package/dist/lib/browser/qa-run.js +684 -0
  220. package/dist/lib/coord-root-id.d.ts +9 -0
  221. package/dist/lib/coord-root-id.d.ts.map +1 -0
  222. package/dist/lib/coord-root-id.js +17 -0
  223. package/dist/lib/instructions/apply.d.ts +3 -1
  224. package/dist/lib/instructions/apply.d.ts.map +1 -1
  225. package/dist/lib/instructions/apply.js +74 -3
  226. package/dist/lib/instructions/templates.d.ts.map +1 -1
  227. package/dist/lib/instructions/templates.js +6 -0
  228. package/package.json +12 -1
  229. package/src/commander.ts +26 -0
  230. package/src/commands/agents.ts +102 -49
  231. package/src/commands/artifacts.ts +40 -2
  232. package/src/commands/browse.ts +15 -0
  233. package/src/commands/diagnostics.ts +271 -0
  234. package/src/commands/files.ts +102 -2
  235. package/src/commands/governor.ts +8 -0
  236. package/src/commands/ledger-v3.ts +82 -0
  237. package/src/commands/qa-run.ts +184 -0
  238. package/src/commands/resources.ts +38 -0
  239. package/src/commands/supervisor.ts +141 -0
  240. package/src/commands/web.ts +19 -0
  241. package/src/commands/workflow.ts +8 -0
  242. package/src/core/agents/cli.ts +7 -3
  243. package/src/core/agents/health.ts +142 -0
  244. package/src/core/agents/mailbox.ts +373 -0
  245. package/src/core/agents/reconcile-coordination-v3.ts +77 -0
  246. package/src/core/agents/render/prompt-context.ts +42 -12
  247. package/src/core/agents/render/session-context.ts +37 -3
  248. package/src/core/agents/rules/commit-conflict.ts +58 -1
  249. package/src/core/agents/rules/stop-hook.ts +6 -12
  250. package/src/core/agents/session-finalizer-v3.ts +4 -1
  251. package/src/core/artifacts/index.ts +196 -10
  252. package/src/core/config.ts +111 -2
  253. package/src/core/diagnostics/advice.ts +147 -0
  254. package/src/core/diagnostics/bundle.ts +1142 -0
  255. package/src/core/diagnostics/comparison.ts +565 -0
  256. package/src/core/diagnostics/contract.ts +311 -0
  257. package/src/core/diagnostics/identity.ts +11 -0
  258. package/src/core/diagnostics/index.ts +7 -0
  259. package/src/core/diagnostics/replay.ts +314 -0
  260. package/src/core/diagnostics/sanitize.ts +97 -0
  261. package/src/core/events/legacy-storage/compression.ts +130 -0
  262. package/src/core/events/legacy-storage/index.ts +1 -0
  263. package/src/core/events/v3/archive-retention.ts +251 -0
  264. package/src/core/events/v3/capabilities.ts +2 -0
  265. package/src/core/events/v3/index.ts +9 -0
  266. package/src/core/events/v3/live-routing.ts +1 -0
  267. package/src/core/events/v3/producers/hook-base.ts +14 -2
  268. package/src/core/events/v3/producers/intake.ts +1 -0
  269. package/src/core/events/v3/producers/recorder.ts +110 -1
  270. package/src/core/hooks/adapter/output.ts +12 -1
  271. package/src/core/hooks/cli.ts +192 -215
  272. package/src/core/hooks/health.ts +146 -0
  273. package/src/core/resources/contract.ts +98 -0
  274. package/src/core/resources/index.ts +5 -0
  275. package/src/core/resources/sampler.ts +458 -0
  276. package/src/core/resources/service-status.ts +62 -0
  277. package/src/core/resources/service.ts +337 -0
  278. package/src/core/resources/storage.ts +44 -0
  279. package/src/core/storage/atomic-json.ts +15 -0
  280. package/src/core/storage/builtins.ts +62 -6
  281. package/src/core/storage/logger.ts +2 -0
  282. package/src/core/storage/query.ts +58 -0
  283. package/src/core/supervisor/activity.ts +193 -0
  284. package/src/core/supervisor/contract.ts +312 -0
  285. package/src/core/supervisor/explanations.ts +104 -0
  286. package/src/core/supervisor/findings.ts +788 -0
  287. package/src/core/supervisor/history.ts +61 -0
  288. package/src/core/supervisor/hook-health-alerts.ts +108 -0
  289. package/src/core/supervisor/hook-health-storage.ts +25 -0
  290. package/src/core/supervisor/hook-health.ts +301 -0
  291. package/src/core/supervisor/hooks.ts +35 -0
  292. package/src/core/supervisor/index.ts +14 -0
  293. package/src/core/supervisor/log-feed.ts +131 -0
  294. package/src/core/supervisor/service.ts +511 -0
  295. package/src/core/supervisor/services.ts +203 -0
  296. package/src/core/supervisor/status.ts +59 -0
  297. package/src/core/supervisor/storage.ts +126 -0
  298. package/src/core/supervisor/timeline.ts +133 -0
  299. package/src/core/workflow/admission.ts +215 -0
  300. package/src/core/workflow/engine.ts +93 -1
  301. package/src/core/workflow/index.ts +10 -0
  302. package/src/core/workflow/proof.ts +54 -1
  303. package/src/core/workflow/run-state.ts +13 -1
  304. package/src/core/workflow/types.ts +39 -1
  305. package/src/lib/browser/client.ts +6 -0
  306. package/src/lib/browser/index.ts +29 -0
  307. package/src/lib/browser/qa-run-contracts.ts +380 -0
  308. package/src/lib/browser/qa-run.ts +784 -0
  309. package/src/lib/coord-root-id.ts +23 -0
  310. package/src/lib/instructions/apply.ts +81 -2
  311. package/src/lib/instructions/templates.ts +6 -0
@@ -0,0 +1,193 @@
1
+ import { createHash } from "node:crypto";
2
+ import { existsSync, lstatSync, readdirSync, readFileSync } from "node:fs";
3
+ import { join, resolve } from "node:path";
4
+ import {
5
+ SUPERVISOR_ACTIVITY_SCHEMA_VERSION,
6
+ SUPERVISOR_DIAGNOSTIC_LIMITS,
7
+ SUPERVISOR_FINDING_POLICY,
8
+ type SupervisorActivitySnapshot,
9
+ type SupervisorDeclaredActivity,
10
+ type SupervisorSourceReference,
11
+ } from "./contract.ts";
12
+
13
+ interface ActivityCache {
14
+ schema_version?: number;
15
+ instance_id?: string;
16
+ session_id?: string;
17
+ activity?: string;
18
+ task_state?: string;
19
+ last_heartbeat?: string;
20
+ v3_instance_id?: string;
21
+ v3_generation_id?: string;
22
+ }
23
+
24
+ interface CandidateFile {
25
+ name: string;
26
+ path: string;
27
+ bytes: number;
28
+ mtimeMs: number;
29
+ }
30
+
31
+ /** Read a bounded, generation-bound activity projection without loading Event Ledger V3. */
32
+ export function collectSupervisorActivitySnapshot(
33
+ coordRoot: string,
34
+ now = new Date(),
35
+ ): SupervisorActivitySnapshot {
36
+ const observedAt = now.toISOString();
37
+ const directory = join(resolve(coordRoot), ".harnery", "active");
38
+ if (!existsSync(directory)) return unavailable(observedAt, "activity-projection-missing");
39
+
40
+ const candidates: CandidateFile[] = [];
41
+ let rejected = 0;
42
+ try {
43
+ for (const entry of readdirSync(directory)) {
44
+ if (!/^[A-Za-z0-9_-]{1,128}\.json$/.test(entry)) {
45
+ rejected += 1;
46
+ continue;
47
+ }
48
+ const path = join(directory, entry);
49
+ const stat = lstatSync(path);
50
+ if (
51
+ stat.isSymbolicLink() ||
52
+ !stat.isFile() ||
53
+ stat.size < 2 ||
54
+ stat.size > SUPERVISOR_FINDING_POLICY.max_activity_file_bytes
55
+ ) {
56
+ rejected += 1;
57
+ continue;
58
+ }
59
+ candidates.push({ name: entry.slice(0, -5), path, bytes: stat.size, mtimeMs: stat.mtimeMs });
60
+ }
61
+ } catch {
62
+ return unavailable(observedAt, "activity-projection-read-failed", "error");
63
+ }
64
+
65
+ candidates.sort(
66
+ (left, right) => right.mtimeMs - left.mtimeMs || left.name.localeCompare(right.name),
67
+ );
68
+ const entries: SupervisorDeclaredActivity[] = [];
69
+ let totalBytes = 0;
70
+ let stale = 0;
71
+ for (const candidate of candidates) {
72
+ if (
73
+ entries.length >= SUPERVISOR_DIAGNOSTIC_LIMITS.max_activity_entries ||
74
+ totalBytes + candidate.bytes > SUPERVISOR_FINDING_POLICY.max_activity_total_bytes
75
+ ) {
76
+ rejected += 1;
77
+ continue;
78
+ }
79
+ totalBytes += candidate.bytes;
80
+ let cache: ActivityCache;
81
+ try {
82
+ cache = JSON.parse(readFileSync(candidate.path, "utf8")) as ActivityCache;
83
+ } catch {
84
+ rejected += 1;
85
+ continue;
86
+ }
87
+ if (!validCache(cache, candidate.name)) {
88
+ rejected += 1;
89
+ continue;
90
+ }
91
+ const age = now.getTime() - Date.parse(cache.last_heartbeat!);
92
+ if (
93
+ !Number.isFinite(age) ||
94
+ age < -30_000 ||
95
+ age > SUPERVISOR_FINDING_POLICY.activity_freshness_ms
96
+ ) {
97
+ stale += 1;
98
+ continue;
99
+ }
100
+ entries.push(activityEntry(cache as Required<ActivityCache>));
101
+ }
102
+
103
+ const state = rejected > 0 ? "partial" : "supported";
104
+ return {
105
+ schema_version: SUPERVISOR_ACTIVITY_SCHEMA_VERSION,
106
+ observed_at: observedAt,
107
+ max_entries: SUPERVISOR_DIAGNOSTIC_LIMITS.max_activity_entries,
108
+ entries: entries.sort((left, right) => left.scope_id.localeCompare(right.scope_id)),
109
+ omitted_entry_count: rejected + stale,
110
+ capability: {
111
+ source_kind: "coordination.activity-projection",
112
+ state,
113
+ ...(state === "partial" ? { reason_code: "bounded-cache-rejection" } : {}),
114
+ ...(rejected + stale > 0
115
+ ? { detail: `${rejected} invalid or over-budget and ${stale} stale activity rows omitted.` }
116
+ : {}),
117
+ },
118
+ };
119
+ }
120
+
121
+ function validCache(cache: ActivityCache, fileId: string): boolean {
122
+ return (
123
+ cache.schema_version === 2 &&
124
+ cache.instance_id === fileId &&
125
+ typeof cache.session_id === "string" &&
126
+ cache.session_id.length > 0 &&
127
+ isActivity(cache.activity) &&
128
+ isTaskState(cache.task_state) &&
129
+ typeof cache.last_heartbeat === "string" &&
130
+ typeof cache.v3_instance_id === "string" &&
131
+ cache.v3_instance_id.startsWith("inst_") &&
132
+ typeof cache.v3_generation_id === "string" &&
133
+ cache.v3_generation_id.startsWith("gen_")
134
+ );
135
+ }
136
+
137
+ function activityEntry(cache: Required<ActivityCache>): SupervisorDeclaredActivity {
138
+ const source = activitySource(cache);
139
+ return {
140
+ scope_kind: "agent",
141
+ scope_id: cache.instance_id,
142
+ session_id: cache.session_id,
143
+ declared_activity: cache.activity as SupervisorDeclaredActivity["declared_activity"],
144
+ task_state: cache.task_state as SupervisorDeclaredActivity["task_state"],
145
+ observed_at: cache.last_heartbeat,
146
+ source,
147
+ };
148
+ }
149
+
150
+ function activitySource(cache: Required<ActivityCache>): SupervisorSourceReference {
151
+ const sourceId = `${cache.v3_instance_id}:${cache.v3_generation_id}`;
152
+ return {
153
+ id: `src_${digest(`coordination.activity-projection\u0000${sourceId}\u0000${cache.last_heartbeat}`).slice(0, 24)}`,
154
+ source_kind: "coordination.activity-projection",
155
+ source_id: sourceId,
156
+ observed_at: cache.last_heartbeat,
157
+ schema_version: SUPERVISOR_ACTIVITY_SCHEMA_VERSION,
158
+ capability: "supported",
159
+ };
160
+ }
161
+
162
+ function unavailable(
163
+ observedAt: string,
164
+ reasonCode: string,
165
+ state: "unsupported" | "error" = "unsupported",
166
+ ): SupervisorActivitySnapshot {
167
+ return {
168
+ schema_version: SUPERVISOR_ACTIVITY_SCHEMA_VERSION,
169
+ observed_at: observedAt,
170
+ max_entries: SUPERVISOR_DIAGNOSTIC_LIMITS.max_activity_entries,
171
+ entries: [],
172
+ omitted_entry_count: 0,
173
+ capability: {
174
+ source_kind: "coordination.activity-projection",
175
+ state,
176
+ reason_code: reasonCode,
177
+ },
178
+ };
179
+ }
180
+
181
+ function isActivity(
182
+ value: string | undefined,
183
+ ): value is SupervisorDeclaredActivity["declared_activity"] {
184
+ return value === "working" || value === "needs_input" || value === "idle" || value === "unknown";
185
+ }
186
+
187
+ function isTaskState(value: string | undefined): value is SupervisorDeclaredActivity["task_state"] {
188
+ return value === "active" || value === "blocked" || value === "done";
189
+ }
190
+
191
+ function digest(value: string): string {
192
+ return createHash("sha256").update(value).digest("hex");
193
+ }
@@ -0,0 +1,312 @@
1
+ import type { ResourceProcessGroup } from "../resources/contract.ts";
2
+ import type { HarneryLogRecordV1 } from "../storage/jsonl.ts";
3
+
4
+ export const SUPERVISOR_STATUS_SCHEMA_VERSION = 1 as const;
5
+ export const SUPERVISOR_SNAPSHOT_SCHEMA_VERSION = 2 as const;
6
+ export const SUPERVISOR_HISTORY_SCHEMA_VERSION = 1 as const;
7
+ export const SUPERVISOR_FINDING_SCHEMA_VERSION = 2 as const;
8
+ export const SUPERVISOR_ACTIVITY_SCHEMA_VERSION = 1 as const;
9
+ export const SUPERVISOR_TIMELINE_SCHEMA_VERSION = 2 as const;
10
+ export const SUPERVISOR_EXPLANATION_SCHEMA_VERSION = 1 as const;
11
+ export const SUPERVISOR_LOG_FEED_SCHEMA_VERSION = 1 as const;
12
+ export const SUPERVISOR_CONSUMER_SCHEMA_VERSION = 1 as const;
13
+
14
+ export const SUPERVISOR_DIAGNOSTIC_LIMITS = {
15
+ max_findings: 100,
16
+ max_active_findings: 32,
17
+ max_evidence_per_finding: 32,
18
+ max_timeline_entries: 160,
19
+ max_explanation_items: 24,
20
+ max_capabilities: 16,
21
+ max_activity_entries: 64,
22
+ max_bundle_files: 32,
23
+ max_bundle_bytes: 8 * 1_024 * 1_024,
24
+ max_summary_chars: 500,
25
+ max_excerpt_chars: 2_000,
26
+ } as const;
27
+
28
+ export const SUPERVISOR_FINDING_POLICY = {
29
+ episode_gap_ms: 5 * 60_000,
30
+ activity_freshness_ms: 2 * 60_000,
31
+ max_activity_file_bytes: 64 * 1_024,
32
+ max_activity_total_bytes: 512 * 1_024,
33
+ } as const;
34
+
35
+ export const SUPERVISOR_RESOURCE_BUDGET = {
36
+ max_rss_bytes: 128 * 1_024 * 1_024,
37
+ max_cycle_duration_ms: 50,
38
+ max_startup_duration_ms: 2_000,
39
+ max_cache_bytes: 8 * 1_024 * 1_024,
40
+ max_regression_ratio: 1.2,
41
+ } as const;
42
+
43
+ export type SupervisorProcessState = "starting" | "running" | "stopping" | "stopped" | "error";
44
+
45
+ export interface SupervisorServiceStatusRecord {
46
+ schema_version: typeof SUPERVISOR_STATUS_SCHEMA_VERSION;
47
+ pid: number;
48
+ start_token?: string;
49
+ host: string;
50
+ nonce: string;
51
+ state: SupervisorProcessState;
52
+ started_at: string;
53
+ heartbeat_at: string;
54
+ interval_ms: number;
55
+ keep_alive: boolean;
56
+ idle_exit_ms: number;
57
+ cycle_count: number;
58
+ last_cycle_at?: string;
59
+ last_cycle_duration_ms?: number;
60
+ idle_since?: string;
61
+ last_error_code?: string;
62
+ stopped_at?: string;
63
+ }
64
+
65
+ export interface SupervisorStatus {
66
+ running: boolean;
67
+ stale: boolean;
68
+ record?: SupervisorServiceStatusRecord;
69
+ status_path: string;
70
+ snapshot_path: string;
71
+ }
72
+
73
+ export interface SupervisorConsumerRecord {
74
+ schema_version: typeof SUPERVISOR_CONSUMER_SCHEMA_VERSION;
75
+ id: string;
76
+ pid: number;
77
+ start_token?: string;
78
+ registered_at: string;
79
+ }
80
+
81
+ export type ObservedServiceState = "running" | "stopped" | "stale" | "unknown";
82
+
83
+ export interface ObservedServiceHealth {
84
+ id: "supervisor" | "semantic-reader" | "presence-relay" | "governor" | "dashboard";
85
+ state: ObservedServiceState;
86
+ pid?: number;
87
+ started_at?: string;
88
+ heartbeat_at?: string;
89
+ reason?: string;
90
+ }
91
+
92
+ export interface ObservedHookHealth {
93
+ pid: number;
94
+ owner_id: string;
95
+ state: string;
96
+ age_seconds: number;
97
+ cpu_percent: number | null;
98
+ rss_bytes: number;
99
+ command: string;
100
+ long_running: boolean;
101
+ evidence: "validated-owner-and-exact-entrypoint";
102
+ }
103
+
104
+ export interface SupervisorHistoryPoint {
105
+ sampled_at: string;
106
+ machine: {
107
+ cpu_percent: number | null;
108
+ memory_percent: number | null;
109
+ memory_used_bytes: number | null;
110
+ swap_used_bytes: number | null;
111
+ process_count: number;
112
+ };
113
+ groups: readonly ResourceProcessGroup[];
114
+ }
115
+
116
+ export interface SupervisorHistory {
117
+ schema_version: typeof SUPERVISOR_HISTORY_SCHEMA_VERSION;
118
+ interval_ms: number;
119
+ max_points: number;
120
+ points: readonly SupervisorHistoryPoint[];
121
+ }
122
+
123
+ export type SupervisorCapabilityState =
124
+ | "supported"
125
+ | "partial"
126
+ | "unsupported"
127
+ | "error"
128
+ | "expired"
129
+ | "malformed"
130
+ | "redacted";
131
+ export type SupervisorFindingSeverity = "info" | "warning" | "critical";
132
+ export type SupervisorFindingState = "opened" | "resolved";
133
+
134
+ export interface SupervisorCapability {
135
+ source_kind: string;
136
+ state: SupervisorCapabilityState;
137
+ reason_code?: string;
138
+ detail?: string;
139
+ }
140
+
141
+ export interface SupervisorSourceReference {
142
+ id: string;
143
+ source_kind: string;
144
+ source_id: string;
145
+ observed_at: string;
146
+ record_id?: string;
147
+ sequence?: number;
148
+ schema_version?: number;
149
+ capability: SupervisorCapabilityState;
150
+ }
151
+
152
+ export interface SupervisorFindingEvidence {
153
+ id: string;
154
+ source: SupervisorSourceReference;
155
+ summary: string;
156
+ observed_value?: number;
157
+ unit?: "percent" | "bytes" | "milliseconds" | "seconds" | "processes" | "count";
158
+ }
159
+
160
+ export interface SupervisorFindingAttribution {
161
+ state: "attributed" | "unattributed";
162
+ owner_kind?: "agent" | "service";
163
+ owner_id?: string;
164
+ owner_root_pid?: number;
165
+ reason_code?: "no-validated-process-anchor";
166
+ }
167
+
168
+ export interface SupervisorFindingWorkloadContext {
169
+ relationship: "active-work" | "unexpected-idle-growth" | "unknown";
170
+ declared_activity: "working" | "needs_input" | "idle" | "unknown";
171
+ task_state: "active" | "blocked" | "done" | "unknown";
172
+ observed_at: string;
173
+ source: SupervisorSourceReference;
174
+ }
175
+
176
+ export interface SupervisorFinding {
177
+ schema_version: typeof SUPERVISOR_FINDING_SCHEMA_VERSION;
178
+ id: string;
179
+ fingerprint: string;
180
+ source_kind: string;
181
+ finding_kind: string;
182
+ severity: SupervisorFindingSeverity;
183
+ state: SupervisorFindingState;
184
+ scope_kind: string;
185
+ scope_id: string;
186
+ summary: string;
187
+ opened_at: string;
188
+ observed_at: string;
189
+ resolved_at?: string;
190
+ occurrence_count: number;
191
+ peak_observed_value?: number;
192
+ peak_observed_at?: string;
193
+ peak_unit?: SupervisorFindingEvidence["unit"];
194
+ attribution?: SupervisorFindingAttribution;
195
+ workload_context?: SupervisorFindingWorkloadContext;
196
+ primary_source: SupervisorSourceReference;
197
+ evidence: readonly SupervisorFindingEvidence[];
198
+ capabilities: readonly SupervisorCapability[];
199
+ }
200
+
201
+ export interface SupervisorDeclaredActivity {
202
+ scope_kind: "agent";
203
+ scope_id: string;
204
+ session_id: string;
205
+ declared_activity: "working" | "needs_input" | "idle" | "unknown";
206
+ task_state: "active" | "blocked" | "done";
207
+ observed_at: string;
208
+ source: SupervisorSourceReference;
209
+ }
210
+
211
+ export interface SupervisorActivitySnapshot {
212
+ schema_version: typeof SUPERVISOR_ACTIVITY_SCHEMA_VERSION;
213
+ observed_at: string;
214
+ max_entries: number;
215
+ entries: readonly SupervisorDeclaredActivity[];
216
+ omitted_entry_count: number;
217
+ capability: SupervisorCapability;
218
+ }
219
+
220
+ export interface SupervisorFindings {
221
+ schema_version: typeof SUPERVISOR_FINDING_SCHEMA_VERSION;
222
+ max_findings: number;
223
+ active: readonly SupervisorFinding[];
224
+ transitions: readonly SupervisorFinding[];
225
+ }
226
+
227
+ export type SupervisorTimelineRelation =
228
+ | "opened"
229
+ | "observed"
230
+ | "related"
231
+ | "resolved"
232
+ | "capability"
233
+ | "missing";
234
+
235
+ export interface SupervisorTimelineEntry {
236
+ id: string;
237
+ occurred_at: string;
238
+ first_occurred_at: string;
239
+ last_occurred_at: string;
240
+ occurrence_count: number;
241
+ relation: SupervisorTimelineRelation;
242
+ summary: string;
243
+ source: SupervisorSourceReference;
244
+ evidence_id?: string;
245
+ }
246
+
247
+ export interface SupervisorTimeline {
248
+ schema_version: typeof SUPERVISOR_TIMELINE_SCHEMA_VERSION;
249
+ finding_id: string;
250
+ start_at: string;
251
+ end_at: string;
252
+ max_entries: number;
253
+ omitted_entries: number;
254
+ compacted_entries: number;
255
+ entries: readonly SupervisorTimelineEntry[];
256
+ capabilities: readonly SupervisorCapability[];
257
+ }
258
+
259
+ export interface SupervisorExplanationStatement {
260
+ id: string;
261
+ code: string;
262
+ summary: string;
263
+ evidence_ids: readonly string[];
264
+ }
265
+
266
+ export interface SupervisorPossibleExplanation extends SupervisorExplanationStatement {
267
+ confidence: "low" | "medium" | "high";
268
+ evidence_against_ids: readonly string[];
269
+ }
270
+
271
+ export interface SupervisorFindingExplanation {
272
+ schema_version: typeof SUPERVISOR_EXPLANATION_SCHEMA_VERSION;
273
+ finding_id: string;
274
+ generated_at: string;
275
+ observed: readonly SupervisorExplanationStatement[];
276
+ related: readonly SupervisorExplanationStatement[];
277
+ possible: readonly SupervisorPossibleExplanation[];
278
+ missing_capabilities: readonly SupervisorCapability[];
279
+ }
280
+
281
+ export interface SupervisorLogLane {
282
+ family_id: string;
283
+ owner: string;
284
+ storage_class: "operational-log" | "debug-log";
285
+ records: readonly HarneryLogRecordV1[];
286
+ truncated: boolean;
287
+ error?: string;
288
+ }
289
+
290
+ export interface SupervisorLogFeed {
291
+ schema_version: typeof SUPERVISOR_LOG_FEED_SCHEMA_VERSION;
292
+ captured_at: string;
293
+ sequence: number;
294
+ lanes: readonly SupervisorLogLane[];
295
+ total_records: number;
296
+ unavailable_families: number;
297
+ }
298
+
299
+ export interface SupervisorSnapshot {
300
+ schema_version: typeof SUPERVISOR_SNAPSHOT_SCHEMA_VERSION;
301
+ sampled_at: string;
302
+ sequence: number;
303
+ collector_duration_ms: number;
304
+ resource_sample_duration_ms: number;
305
+ services: readonly ObservedServiceHealth[];
306
+ hooks: readonly ObservedHookHealth[];
307
+ active_finding_count: number;
308
+ history_point_count: number;
309
+ log_record_count: number;
310
+ live_consumer_count: number;
311
+ attributed_agent_count: number;
312
+ }
@@ -0,0 +1,104 @@
1
+ import { createHash } from "node:crypto";
2
+ import {
3
+ SUPERVISOR_DIAGNOSTIC_LIMITS,
4
+ SUPERVISOR_EXPLANATION_SCHEMA_VERSION,
5
+ type SupervisorExplanationStatement,
6
+ type SupervisorFinding,
7
+ type SupervisorFindingExplanation,
8
+ type SupervisorPossibleExplanation,
9
+ } from "./contract.ts";
10
+
11
+ /** Build evidence-linked statements without presenting correlation as causation. */
12
+ export function explainSupervisorFinding(finding: SupervisorFinding): SupervisorFindingExplanation {
13
+ const observed = finding.evidence.map((evidence) =>
14
+ statement("observed.source", evidence.summary, [evidence.id]),
15
+ );
16
+ const related = relatedStatements(finding);
17
+ const possible = possibleStatements(finding);
18
+ return {
19
+ schema_version: SUPERVISOR_EXPLANATION_SCHEMA_VERSION,
20
+ finding_id: finding.id,
21
+ generated_at: finding.observed_at,
22
+ observed: observed.slice(0, SUPERVISOR_DIAGNOSTIC_LIMITS.max_explanation_items),
23
+ related: related.slice(0, SUPERVISOR_DIAGNOSTIC_LIMITS.max_explanation_items),
24
+ possible: possible.slice(0, SUPERVISOR_DIAGNOSTIC_LIMITS.max_explanation_items),
25
+ missing_capabilities: finding.capabilities
26
+ .filter((capability) => capability.state !== "supported")
27
+ .slice(0, SUPERVISOR_DIAGNOSTIC_LIMITS.max_capabilities),
28
+ };
29
+ }
30
+
31
+ function relatedStatements(finding: SupervisorFinding): SupervisorExplanationStatement[] {
32
+ const sources = new Set(finding.evidence.map((evidence) => evidence.source.source_kind));
33
+ if (sources.size < 2) return [];
34
+ return [
35
+ statement(
36
+ "related.multi-source",
37
+ `${sources.size} independent source kinds recorded related observations in this finding window.`,
38
+ finding.evidence.map((evidence) => evidence.id),
39
+ ),
40
+ ];
41
+ }
42
+
43
+ function possibleStatements(finding: SupervisorFinding): SupervisorPossibleExplanation[] {
44
+ const evidenceIds = finding.evidence.map((evidence) => evidence.id);
45
+ const possible: SupervisorPossibleExplanation[] = [];
46
+ if (finding.finding_kind.includes("memory")) {
47
+ possible.push({
48
+ ...statement(
49
+ "possible.memory-retention-or-workload",
50
+ "A growing workload, retained objects, or operating-system caching could explain the memory observation; this evidence does not distinguish them.",
51
+ evidenceIds,
52
+ ),
53
+ confidence: "low",
54
+ evidence_against_ids: [],
55
+ });
56
+ } else if (finding.finding_kind.includes("process-pressure")) {
57
+ possible.push({
58
+ ...statement(
59
+ "possible.concurrent-work",
60
+ "Concurrent local work could explain the process count; the finding does not establish which activity caused it.",
61
+ evidenceIds,
62
+ ),
63
+ confidence: "low",
64
+ evidence_against_ids: [],
65
+ });
66
+ } else if (finding.finding_kind === "hook.long-running") {
67
+ possible.push({
68
+ ...statement(
69
+ "possible.hook-stall",
70
+ "The hook may be waiting on I/O or blocked work, but elapsed time alone cannot identify the cause.",
71
+ evidenceIds,
72
+ ),
73
+ confidence: "low",
74
+ evidence_against_ids: [],
75
+ });
76
+ } else if (finding.finding_kind === "coordination.ledger-diagnostic") {
77
+ possible.push({
78
+ ...statement(
79
+ "possible.ledger-write-or-read-boundary",
80
+ "A producer write or reader validation boundary may explain the ledger diagnostic; inspect the referenced V3 record before attributing a cause.",
81
+ evidenceIds,
82
+ ),
83
+ confidence: "low",
84
+ evidence_against_ids: [],
85
+ });
86
+ }
87
+ return possible;
88
+ }
89
+
90
+ function statement(
91
+ code: string,
92
+ summary: string,
93
+ evidenceIds: readonly string[],
94
+ ): SupervisorExplanationStatement {
95
+ return {
96
+ id: `ex_${createHash("sha256")
97
+ .update(`${code}\u0000${summary}\u0000${evidenceIds.join(",")}`)
98
+ .digest("hex")
99
+ .slice(0, 24)}`,
100
+ code,
101
+ summary: summary.slice(0, SUPERVISOR_DIAGNOSTIC_LIMITS.max_summary_chars),
102
+ evidence_ids: [...evidenceIds].slice(0, SUPERVISOR_DIAGNOSTIC_LIMITS.max_evidence_per_finding),
103
+ };
104
+ }