@eir-labs/coltrane 0.4.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 (279) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +85 -0
  3. package/agents/anticipation-mapper.json +34 -0
  4. package/agents/claim-amender.json +34 -0
  5. package/agents/claim-architect.json +34 -0
  6. package/agents/claim-rewriter.json +32 -0
  7. package/agents/delivery-finalizer.json +40 -0
  8. package/agents/diamond-cutter.json +33 -0
  9. package/agents/disclosure-analyst.json +26 -0
  10. package/agents/domain-explorer.json +37 -0
  11. package/agents/e2e-runner.json +34 -0
  12. package/agents/e2e-suite-judge.json +26 -0
  13. package/agents/event-clusterer.json +29 -0
  14. package/agents/novelty-searcher.json +40 -0
  15. package/agents/patent-browser-scout.json +49 -0
  16. package/agents/patent-examiner.json +36 -0
  17. package/agents/phase_agents/claim-rewriter.md +44 -0
  18. package/agents/phase_agents/delivery-finalizer.md +30 -0
  19. package/agents/phase_agents/diamond-cutter.md +47 -0
  20. package/agents/phase_agents/domain-explorer.md +27 -0
  21. package/agents/phase_agents/novelty-searcher.md +50 -0
  22. package/agents/phase_agents/problem-definer.md +32 -0
  23. package/agents/phase_agents/solution-developer.md +26 -0
  24. package/agents/phase_agents/verdict-judger.md +70 -0
  25. package/agents/players/audience-modeler.md +40 -0
  26. package/agents/players/chain-audit-keeper.md +41 -0
  27. package/agents/players/illumination-reviewer.md +42 -0
  28. package/agents/players/methodology-cadence-keeper.md +42 -0
  29. package/agents/players/substrate-edge-keeper.md +45 -0
  30. package/agents/prior-art-scout.json +45 -0
  31. package/agents/problem-definer.json +35 -0
  32. package/agents/seeds/steve_seed_a.json +12 -0
  33. package/agents/seeds/steve_seed_b.json +12 -0
  34. package/agents/seeds/steve_seed_c.json +12 -0
  35. package/agents/seeds/steve_seed_d.json +12 -0
  36. package/agents/sensor.json +22 -0
  37. package/agents/solution-developer.json +35 -0
  38. package/agents/source-walker.json +38 -0
  39. package/agents/spec-drafter.json +31 -0
  40. package/agents/sub_thread_soft_judge.json +26 -0
  41. package/agents/sub_thread_trace_sensor.json +22 -0
  42. package/agents/summarizer.json +25 -0
  43. package/agents/synthesis-writer.json +29 -0
  44. package/agents/triage-judge.json +39 -0
  45. package/agents/user_flow_judge.json +26 -0
  46. package/agents/user_flow_sensor.json +22 -0
  47. package/agents/verdict-judger.json +39 -0
  48. package/core_types/artifact.json +17 -0
  49. package/core_types/interpretation.json +16 -0
  50. package/core_types/judgment.json +16 -0
  51. package/core_types/plan.json +16 -0
  52. package/core_types/signal.json +16 -0
  53. package/core_types/verdict.json +27 -0
  54. package/dist/src/access_grant.d.ts +46 -0
  55. package/dist/src/access_grant.js +76 -0
  56. package/dist/src/access_grant.js.map +1 -0
  57. package/dist/src/acoustics.d.ts +9 -0
  58. package/dist/src/acoustics.js +65 -0
  59. package/dist/src/acoustics.js.map +1 -0
  60. package/dist/src/agent_profile.d.ts +36 -0
  61. package/dist/src/agent_profile.js +57 -0
  62. package/dist/src/agent_profile.js.map +1 -0
  63. package/dist/src/bifrost_invoker.d.ts +33 -0
  64. package/dist/src/bifrost_invoker.js +85 -0
  65. package/dist/src/bifrost_invoker.js.map +1 -0
  66. package/dist/src/canonical_core_types.d.ts +2 -0
  67. package/dist/src/canonical_core_types.js +111 -0
  68. package/dist/src/canonical_core_types.js.map +1 -0
  69. package/dist/src/canonical_form.d.ts +55 -0
  70. package/dist/src/canonical_form.js +93 -0
  71. package/dist/src/canonical_form.js.map +1 -0
  72. package/dist/src/charter.d.ts +37 -0
  73. package/dist/src/charter.js +86 -0
  74. package/dist/src/charter.js.map +1 -0
  75. package/dist/src/circle_of_fifths.d.ts +27 -0
  76. package/dist/src/circle_of_fifths.js +78 -0
  77. package/dist/src/circle_of_fifths.js.map +1 -0
  78. package/dist/src/claude_invoker.d.ts +102 -0
  79. package/dist/src/claude_invoker.js +760 -0
  80. package/dist/src/claude_invoker.js.map +1 -0
  81. package/dist/src/coltrane_profile.d.ts +87 -0
  82. package/dist/src/coltrane_profile.js +132 -0
  83. package/dist/src/coltrane_profile.js.map +1 -0
  84. package/dist/src/composition.d.ts +57 -0
  85. package/dist/src/composition.js +447 -0
  86. package/dist/src/composition.js.map +1 -0
  87. package/dist/src/core_types.d.ts +6 -0
  88. package/dist/src/core_types.js +25 -0
  89. package/dist/src/core_types.js.map +1 -0
  90. package/dist/src/document_factory.d.ts +89 -0
  91. package/dist/src/document_factory.js +176 -0
  92. package/dist/src/document_factory.js.map +1 -0
  93. package/dist/src/genome_schema.d.ts +512 -0
  94. package/dist/src/genome_schema.js +168 -0
  95. package/dist/src/genome_schema.js.map +1 -0
  96. package/dist/src/genome_writer.d.ts +67 -0
  97. package/dist/src/genome_writer.js +179 -0
  98. package/dist/src/genome_writer.js.map +1 -0
  99. package/dist/src/gig_song.d.ts +29 -0
  100. package/dist/src/gig_song.js +56 -0
  101. package/dist/src/gig_song.js.map +1 -0
  102. package/dist/src/gig_tracker.d.ts +54 -0
  103. package/dist/src/gig_tracker.js +109 -0
  104. package/dist/src/gig_tracker.js.map +1 -0
  105. package/dist/src/harmonic_validation.d.ts +11 -0
  106. package/dist/src/harmonic_validation.js +35 -0
  107. package/dist/src/harmonic_validation.js.map +1 -0
  108. package/dist/src/hooks.d.ts +27 -0
  109. package/dist/src/hooks.js +2 -0
  110. package/dist/src/hooks.js.map +1 -0
  111. package/dist/src/index.d.ts +36 -0
  112. package/dist/src/index.js +37 -0
  113. package/dist/src/index.js.map +1 -0
  114. package/dist/src/jsong.d.ts +47 -0
  115. package/dist/src/jsong.js +130 -0
  116. package/dist/src/jsong.js.map +1 -0
  117. package/dist/src/judges/user_flow_judge.d.ts +89 -0
  118. package/dist/src/judges/user_flow_judge.js +200 -0
  119. package/dist/src/judges/user_flow_judge.js.map +1 -0
  120. package/dist/src/learner.d.ts +37 -0
  121. package/dist/src/learner.js +30 -0
  122. package/dist/src/learner.js.map +1 -0
  123. package/dist/src/ledger.d.ts +225 -0
  124. package/dist/src/ledger.js +306 -0
  125. package/dist/src/ledger.js.map +1 -0
  126. package/dist/src/loader.d.ts +87 -0
  127. package/dist/src/loader.js +504 -0
  128. package/dist/src/loader.js.map +1 -0
  129. package/dist/src/mcp.d.ts +23 -0
  130. package/dist/src/mcp.js +125 -0
  131. package/dist/src/mcp.js.map +1 -0
  132. package/dist/src/modulation_path.d.ts +42 -0
  133. package/dist/src/modulation_path.js +60 -0
  134. package/dist/src/modulation_path.js.map +1 -0
  135. package/dist/src/output_validation.d.ts +19 -0
  136. package/dist/src/output_validation.js +51 -0
  137. package/dist/src/output_validation.js.map +1 -0
  138. package/dist/src/outputs.d.ts +125 -0
  139. package/dist/src/outputs.js +452 -0
  140. package/dist/src/outputs.js.map +1 -0
  141. package/dist/src/overtones.d.ts +42 -0
  142. package/dist/src/overtones.js +98 -0
  143. package/dist/src/overtones.js.map +1 -0
  144. package/dist/src/player_to_claude_code.d.ts +17 -0
  145. package/dist/src/player_to_claude_code.js +141 -0
  146. package/dist/src/player_to_claude_code.js.map +1 -0
  147. package/dist/src/playwright_cage.d.ts +28 -0
  148. package/dist/src/playwright_cage.js +47 -0
  149. package/dist/src/playwright_cage.js.map +1 -0
  150. package/dist/src/polyphony.d.ts +46 -0
  151. package/dist/src/polyphony.js +91 -0
  152. package/dist/src/polyphony.js.map +1 -0
  153. package/dist/src/portfolio.d.ts +52 -0
  154. package/dist/src/portfolio.js +186 -0
  155. package/dist/src/portfolio.js.map +1 -0
  156. package/dist/src/pricing.d.ts +23 -0
  157. package/dist/src/pricing.js +16 -0
  158. package/dist/src/pricing.js.map +1 -0
  159. package/dist/src/registry.d.ts +46 -0
  160. package/dist/src/registry.js +199 -0
  161. package/dist/src/registry.js.map +1 -0
  162. package/dist/src/runtime.d.ts +304 -0
  163. package/dist/src/runtime.js +1099 -0
  164. package/dist/src/runtime.js.map +1 -0
  165. package/dist/src/server.d.ts +88 -0
  166. package/dist/src/server.js +1692 -0
  167. package/dist/src/server.js.map +1 -0
  168. package/dist/src/server_entry.d.ts +2 -0
  169. package/dist/src/server_entry.js +40 -0
  170. package/dist/src/server_entry.js.map +1 -0
  171. package/dist/src/server_relay.d.ts +82 -0
  172. package/dist/src/server_relay.js +341 -0
  173. package/dist/src/server_relay.js.map +1 -0
  174. package/dist/src/simulate.d.ts +60 -0
  175. package/dist/src/simulate.js +72 -0
  176. package/dist/src/simulate.js.map +1 -0
  177. package/dist/src/skill_runner.mjs +34 -0
  178. package/dist/src/skill_subprocess.d.ts +65 -0
  179. package/dist/src/skill_subprocess.js +132 -0
  180. package/dist/src/skill_subprocess.js.map +1 -0
  181. package/dist/src/skills.d.ts +85 -0
  182. package/dist/src/skills.js +258 -0
  183. package/dist/src/skills.js.map +1 -0
  184. package/dist/src/subthread_recorder.d.ts +68 -0
  185. package/dist/src/subthread_recorder.js +166 -0
  186. package/dist/src/subthread_recorder.js.map +1 -0
  187. package/dist/src/tensor_read.d.ts +38 -0
  188. package/dist/src/tensor_read.js +60 -0
  189. package/dist/src/tensor_read.js.map +1 -0
  190. package/dist/src/test_honest_broker.d.ts +34 -0
  191. package/dist/src/test_honest_broker.js +155 -0
  192. package/dist/src/test_honest_broker.js.map +1 -0
  193. package/dist/src/test_topology.d.ts +22 -0
  194. package/dist/src/test_topology.js +137 -0
  195. package/dist/src/test_topology.js.map +1 -0
  196. package/dist/src/tones.d.ts +20 -0
  197. package/dist/src/tones.js +81 -0
  198. package/dist/src/tones.js.map +1 -0
  199. package/dist/src/tool_providers.d.ts +45 -0
  200. package/dist/src/tool_providers.js +104 -0
  201. package/dist/src/tool_providers.js.map +1 -0
  202. package/dist/src/type_versioning.d.ts +23 -0
  203. package/dist/src/type_versioning.js +31 -0
  204. package/dist/src/type_versioning.js.map +1 -0
  205. package/dist/src/version.d.ts +28 -0
  206. package/dist/src/version.js +86 -0
  207. package/dist/src/version.js.map +1 -0
  208. package/domain_types/claim-draft.json +34 -0
  209. package/domain_types/coverage-report.json +31 -0
  210. package/domain_types/draft-agent-profile.json +31 -0
  211. package/domain_types/draft-domain-type.json +28 -0
  212. package/domain_types/draft-standard.json +46 -0
  213. package/domain_types/e2e-observation.json +32 -0
  214. package/domain_types/e2e-report.json +30 -0
  215. package/domain_types/e2e-target.json +26 -0
  216. package/domain_types/e2e-verdict.json +26 -0
  217. package/domain_types/examine-round-record.json +40 -0
  218. package/domain_types/examiner-rejection.json +28 -0
  219. package/domain_types/failure-modes.json +31 -0
  220. package/domain_types/invention-analysis.json +34 -0
  221. package/domain_types/invention-spec.json +34 -0
  222. package/domain_types/novelty-analysis.json +28 -0
  223. package/domain_types/novelty-verdict.json +35 -0
  224. package/domain_types/parsed-conversation-trace.json +38 -0
  225. package/domain_types/pattern-extraction.json +62 -0
  226. package/domain_types/prior-art-hit.json +50 -0
  227. package/domain_types/project-charter.json +71 -0
  228. package/domain_types/provisional-draft.json +34 -0
  229. package/domain_types/raw-note.json +19 -0
  230. package/domain_types/repo-survey.json +28 -0
  231. package/domain_types/seeding-verdict.json +70 -0
  232. package/domain_types/soft-verdict.json +55 -0
  233. package/domain_types/summary.json +19 -0
  234. package/domain_types/triage-verdict.json +59 -0
  235. package/domain_types/user-flow-transcript.json +43 -0
  236. package/domain_types/user-flow-verdict.json +60 -0
  237. package/domain_types/verdict-record.json +39 -0
  238. package/package.json +82 -0
  239. package/skills/citation-verify/fixtures/basic.json +14 -0
  240. package/skills/citation-verify/meta.json +10 -0
  241. package/skills/citation-verify/skill.mjs +26 -0
  242. package/skills/claim-element-decompose/fixtures/basic.json +11 -0
  243. package/skills/claim-element-decompose/meta.json +10 -0
  244. package/skills/claim-element-decompose/skill.mjs +14 -0
  245. package/skills/diamond-cutting-discipline/fixtures/basic.json +13 -0
  246. package/skills/diamond-cutting-discipline/meta.json +19 -0
  247. package/skills/diamond-cutting-discipline/skill.md +46 -0
  248. package/skills/element-mapping-matrix/fixtures/basic.json +13 -0
  249. package/skills/element-mapping-matrix/meta.json +10 -0
  250. package/skills/element-mapping-matrix/skill.mjs +20 -0
  251. package/skills/number-adder/fixtures/basic.json +9 -0
  252. package/skills/number-adder/meta.json +10 -0
  253. package/skills/number-adder/skill.mjs +12 -0
  254. package/skills/patent-fetch/fixtures/parse.json +18 -0
  255. package/skills/patent-fetch/meta.json +11 -0
  256. package/skills/patent-fetch/skill.mjs +34 -0
  257. package/skills/query-expand/fixtures/basic.json +14 -0
  258. package/skills/query-expand/meta.json +10 -0
  259. package/skills/query-expand/skill.mjs +29 -0
  260. package/skills/run-vitest-band/fixtures/basic.json +9 -0
  261. package/skills/run-vitest-band/meta.json +18 -0
  262. package/skills/run-vitest-band/skill.mjs +22 -0
  263. package/skills/statutory-checklist/fixtures/basic.json +16 -0
  264. package/skills/statutory-checklist/meta.json +10 -0
  265. package/skills/statutory-checklist/skill.mjs +25 -0
  266. package/skills/summarize-tight/fixtures/basic.json +13 -0
  267. package/skills/summarize-tight/meta.json +20 -0
  268. package/skills/summarize-tight/skill.md +1 -0
  269. package/skills/verdict-gate/fixtures/basic.json +9 -0
  270. package/skills/verdict-gate/meta.json +10 -0
  271. package/skills/verdict-gate/skill.mjs +82 -0
  272. package/standards/e2e-suite-v0.json +44 -0
  273. package/standards/patent-triage-v0.json +98 -0
  274. package/standards/patent-triage-v1.json +84 -0
  275. package/standards/seed-from-local-repos-v0.json +115 -0
  276. package/standards/sub_thread_invocation.json +50 -0
  277. package/standards/summarize.json +40 -0
  278. package/standards/synthesis-walk-v0.json +108 -0
  279. package/standards/user_flow_correctness.json +57 -0
@@ -0,0 +1,34 @@
1
+ export interface DivergenceReport {
2
+ path: string;
3
+ primary: string;
4
+ secondary: string;
5
+ reason: string;
6
+ }
7
+ export interface HonestBrokerComparison<T> {
8
+ primary: T;
9
+ secondary: T;
10
+ agreement: boolean;
11
+ divergence: DivergenceReport | null;
12
+ }
13
+ export type Comparator<T> = (a: T, b: T) => boolean;
14
+ /**
15
+ * Walk two JSON-serialisable values in parallel. Returns null when structurally
16
+ * equal, or a DivergenceReport pinpointing the first mismatch. Arrays are
17
+ * length-checked then compared positionally; objects are key-set-checked then
18
+ * compared by key. Primitives use strict equality (NaN is treated as unequal).
19
+ */
20
+ export declare function findDivergence(a: unknown, b: unknown, path?: string): DivergenceReport | null;
21
+ /**
22
+ * Run two independent code paths that should produce the same result under the
23
+ * same contract; compare structurally. The comparator defaults to deep
24
+ * structural equality on JSON-serialisable objects. When a custom comparator is
25
+ * supplied, the DivergenceReport will still be produced via findDivergence so
26
+ * the failure is locatable.
27
+ */
28
+ export declare function compareHonestBroker<T>(primary: () => Promise<T> | T, secondary: () => Promise<T> | T, comparator?: Comparator<T>): Promise<HonestBrokerComparison<T>>;
29
+ /**
30
+ * Returns a new object with the named keys removed RECURSIVELY at any depth.
31
+ * Used to scrub volatile fields (uuids, timestamps, derived fingerprints)
32
+ * before comparison so two structurally-equivalent runs match.
33
+ */
34
+ export declare function scrubKeys<T>(value: T, keys: readonly string[]): T;
@@ -0,0 +1,155 @@
1
+ // Independent re-measurement layer. For a given contract, run the primary code
2
+ // path and a secondary code path that exercises the SAME contract via a different
3
+ // route, then compare. Agreement = the contract holds across both paths; a
4
+ // divergence is an honest finding — either the public API does work the raw path
5
+ // skips, or the underlying schema is under-specified.
6
+ //
7
+ // Used by tests under tests/honest_broker/. The comparator scrubs known volatile
8
+ // keys (uuids, timestamps, fingerprints derived from uuids) so two structurally
9
+ // equivalent runs match; surviving differences are real.
10
+ const MAX_VALUE_LEN = 200;
11
+ function truncate(v) {
12
+ let s;
13
+ try {
14
+ s = typeof v === "string" ? v : JSON.stringify(v);
15
+ }
16
+ catch {
17
+ s = String(v);
18
+ }
19
+ if (s.length > MAX_VALUE_LEN)
20
+ s = s.slice(0, MAX_VALUE_LEN) + "…";
21
+ return s;
22
+ }
23
+ /**
24
+ * Walk two JSON-serialisable values in parallel. Returns null when structurally
25
+ * equal, or a DivergenceReport pinpointing the first mismatch. Arrays are
26
+ * length-checked then compared positionally; objects are key-set-checked then
27
+ * compared by key. Primitives use strict equality (NaN is treated as unequal).
28
+ */
29
+ export function findDivergence(a, b, path = "$") {
30
+ if (a === b)
31
+ return null;
32
+ // both null/undefined catch-all
33
+ if (a === null || b === null || a === undefined || b === undefined) {
34
+ return {
35
+ path,
36
+ primary: truncate(a),
37
+ secondary: truncate(b),
38
+ reason: `null/undefined on one side`,
39
+ };
40
+ }
41
+ const ta = typeof a;
42
+ const tb = typeof b;
43
+ if (ta !== tb) {
44
+ return {
45
+ path,
46
+ primary: truncate(a),
47
+ secondary: truncate(b),
48
+ reason: `type mismatch: ${ta} vs ${tb}`,
49
+ };
50
+ }
51
+ if (ta !== "object") {
52
+ return {
53
+ path,
54
+ primary: truncate(a),
55
+ secondary: truncate(b),
56
+ reason: `value mismatch (${ta})`,
57
+ };
58
+ }
59
+ const aArr = Array.isArray(a);
60
+ const bArr = Array.isArray(b);
61
+ if (aArr !== bArr) {
62
+ return {
63
+ path,
64
+ primary: truncate(a),
65
+ secondary: truncate(b),
66
+ reason: `one side is array, other is object`,
67
+ };
68
+ }
69
+ if (aArr && bArr) {
70
+ const arrA = a;
71
+ const arrB = b;
72
+ if (arrA.length !== arrB.length) {
73
+ return {
74
+ path,
75
+ primary: `length=${arrA.length}`,
76
+ secondary: `length=${arrB.length}`,
77
+ reason: `array length mismatch`,
78
+ };
79
+ }
80
+ for (let i = 0; i < arrA.length; i++) {
81
+ const d = findDivergence(arrA[i], arrB[i], `${path}[${i}]`);
82
+ if (d)
83
+ return d;
84
+ }
85
+ return null;
86
+ }
87
+ const objA = a;
88
+ const objB = b;
89
+ const keysA = Object.keys(objA).sort();
90
+ const keysB = Object.keys(objB).sort();
91
+ if (keysA.length !== keysB.length || keysA.some((k, i) => k !== keysB[i])) {
92
+ const onlyA = keysA.filter((k) => !keysB.includes(k));
93
+ const onlyB = keysB.filter((k) => !keysA.includes(k));
94
+ return {
95
+ path,
96
+ primary: `keys: ${keysA.join(",")}`,
97
+ secondary: `keys: ${keysB.join(",")}`,
98
+ reason: `key-set mismatch (only-primary: [${onlyA.join(",")}], only-secondary: [${onlyB.join(",")}])`,
99
+ };
100
+ }
101
+ for (const k of keysA) {
102
+ const d = findDivergence(objA[k], objB[k], `${path}.${k}`);
103
+ if (d)
104
+ return d;
105
+ }
106
+ return null;
107
+ }
108
+ /**
109
+ * Run two independent code paths that should produce the same result under the
110
+ * same contract; compare structurally. The comparator defaults to deep
111
+ * structural equality on JSON-serialisable objects. When a custom comparator is
112
+ * supplied, the DivergenceReport will still be produced via findDivergence so
113
+ * the failure is locatable.
114
+ */
115
+ export async function compareHonestBroker(primary, secondary, comparator) {
116
+ const primaryResult = await primary();
117
+ const secondaryResult = await secondary();
118
+ const cmp = comparator ?? (defaultDeepEqual);
119
+ const agreement = cmp(primaryResult, secondaryResult);
120
+ const divergence = agreement
121
+ ? null
122
+ : findDivergence(primaryResult, secondaryResult);
123
+ return {
124
+ primary: primaryResult,
125
+ secondary: secondaryResult,
126
+ agreement,
127
+ divergence,
128
+ };
129
+ }
130
+ function defaultDeepEqual(a, b) {
131
+ return findDivergence(a, b) === null;
132
+ }
133
+ /**
134
+ * Returns a new object with the named keys removed RECURSIVELY at any depth.
135
+ * Used to scrub volatile fields (uuids, timestamps, derived fingerprints)
136
+ * before comparison so two structurally-equivalent runs match.
137
+ */
138
+ export function scrubKeys(value, keys) {
139
+ const skip = new Set(keys);
140
+ function walk(v) {
141
+ if (v === null || typeof v !== "object")
142
+ return v;
143
+ if (Array.isArray(v))
144
+ return v.map(walk);
145
+ const out = {};
146
+ for (const [k, val] of Object.entries(v)) {
147
+ if (skip.has(k))
148
+ continue;
149
+ out[k] = walk(val);
150
+ }
151
+ return out;
152
+ }
153
+ return walk(value);
154
+ }
155
+ //# sourceMappingURL=test_honest_broker.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"test_honest_broker.js","sourceRoot":"","sources":["../../src/test_honest_broker.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,22 @@
1
+ export type ContextSizeClass = "small" | "medium" | "large" | "overflow";
2
+ export type PersonaClass = "backend-eng" | "oss-maintainer" | "security-eng" | "fresh-contributor" | "non-engineer-tash-shape";
3
+ export interface SubThreadState {
4
+ parent_turn: number;
5
+ child_turn: number;
6
+ context_size_class: ContextSizeClass;
7
+ persona_class: PersonaClass;
8
+ }
9
+ export interface Transition {
10
+ from: SubThreadState;
11
+ to: SubThreadState;
12
+ kind: "spawn" | "resume" | "context-overflow" | "persona-switch";
13
+ }
14
+ export declare function buildStateSpace(maxParentTurns: number, maxChildTurns: number): SubThreadState[];
15
+ export declare function equivalenceClasses(states: SubThreadState[]): SubThreadState[][];
16
+ export declare function selectRepresentatives(classes: SubThreadState[][]): SubThreadState[];
17
+ export declare function coverageReport(allClasses: SubThreadState[][], testedStates: SubThreadState[]): {
18
+ covered: number;
19
+ total: number;
20
+ missing: SubThreadState[][];
21
+ };
22
+ export declare function adjacentTransitions(states: SubThreadState[]): Transition[];
@@ -0,0 +1,137 @@
1
+ // Topology-based test-coverage helper for sub-thread state-space tests.
2
+ // Saves compute by collapsing the full (parent_turn x child_turn x context_size x persona)
3
+ // product into equivalence classes, then picking 1-2 representatives per class
4
+ // instead of running every multi-turn flow exhaustively.
5
+ const PERSONA_CLASSES = [
6
+ "backend-eng",
7
+ "oss-maintainer",
8
+ "security-eng",
9
+ "fresh-contributor",
10
+ "non-engineer-tash-shape",
11
+ ];
12
+ // Map child_turn -> context_size_class by accumulation bound.
13
+ // Bands cumulative tokens by integer turn count; overflow at the last threshold.
14
+ function contextSizeForTurn(childTurn) {
15
+ if (childTurn <= 2)
16
+ return "small";
17
+ if (childTurn <= 5)
18
+ return "medium";
19
+ if (childTurn <= 8)
20
+ return "large";
21
+ return "overflow";
22
+ }
23
+ // Enumerate all reachable sub-thread states up to the given bounds.
24
+ // A state is reachable if there is some parent_turn in [0, maxParentTurns]
25
+ // and child_turn in [0, maxChildTurns] paired with a persona; context_size_class
26
+ // follows from child_turn under the accumulation model above.
27
+ export function buildStateSpace(maxParentTurns, maxChildTurns) {
28
+ if (maxParentTurns < 0 || maxChildTurns < 0) {
29
+ throw new Error(`buildStateSpace bounds must be non-negative; got parent=${maxParentTurns}, child=${maxChildTurns}`);
30
+ }
31
+ const states = [];
32
+ for (let p = 0; p <= maxParentTurns; p++) {
33
+ for (let c = 0; c <= maxChildTurns; c++) {
34
+ const ctx = contextSizeForTurn(c);
35
+ for (const persona of PERSONA_CLASSES) {
36
+ states.push({
37
+ parent_turn: p,
38
+ child_turn: c,
39
+ context_size_class: ctx,
40
+ persona_class: persona,
41
+ });
42
+ }
43
+ }
44
+ }
45
+ return states;
46
+ }
47
+ // Two states are equivalent modulo (context_size_class, child_turn % 3, persona_class).
48
+ function classKey(s) {
49
+ return `${s.context_size_class}|${s.child_turn % 3}|${s.persona_class}`;
50
+ }
51
+ export function equivalenceClasses(states) {
52
+ const buckets = new Map();
53
+ for (const s of states) {
54
+ const k = classKey(s);
55
+ const existing = buckets.get(k);
56
+ if (existing) {
57
+ existing.push(s);
58
+ }
59
+ else {
60
+ buckets.set(k, [s]);
61
+ }
62
+ }
63
+ // Stable iteration order by insertion.
64
+ return Array.from(buckets.values());
65
+ }
66
+ // Pick 1-2 representatives per class.
67
+ // Centroid: the median-child_turn member of the class.
68
+ // Boundary: the maximum-parent_turn member.
69
+ // If the class is singleton, return just the centroid.
70
+ export function selectRepresentatives(classes) {
71
+ const reps = [];
72
+ for (const cls of classes) {
73
+ if (cls.length === 0)
74
+ continue;
75
+ const sorted = [...cls].sort((a, b) => a.child_turn - b.child_turn);
76
+ const centroidIdx = Math.floor(sorted.length / 2);
77
+ const centroid = sorted[centroidIdx];
78
+ if (!centroid)
79
+ continue;
80
+ reps.push(centroid);
81
+ if (cls.length > 1) {
82
+ const boundary = [...cls].sort((a, b) => b.parent_turn - a.parent_turn)[0];
83
+ if (boundary && !sameState(boundary, centroid)) {
84
+ reps.push(boundary);
85
+ }
86
+ }
87
+ }
88
+ return reps;
89
+ }
90
+ function sameState(a, b) {
91
+ return (a.parent_turn === b.parent_turn &&
92
+ a.child_turn === b.child_turn &&
93
+ a.context_size_class === b.context_size_class &&
94
+ a.persona_class === b.persona_class);
95
+ }
96
+ // Coverage report: which classes are exercised by `testedStates`, which are missed.
97
+ export function coverageReport(allClasses, testedStates) {
98
+ const testedKeys = new Set();
99
+ for (const s of testedStates)
100
+ testedKeys.add(classKey(s));
101
+ const missing = [];
102
+ let covered = 0;
103
+ for (const cls of allClasses) {
104
+ const first = cls[0];
105
+ if (!first)
106
+ continue;
107
+ if (testedKeys.has(classKey(first))) {
108
+ covered += 1;
109
+ }
110
+ else {
111
+ missing.push(cls);
112
+ }
113
+ }
114
+ return { covered, total: allClasses.length, missing };
115
+ }
116
+ // Optional convenience: enumerate transitions between adjacent states.
117
+ // Not required by the public spec, but cheap to expose for downstream graph use.
118
+ export function adjacentTransitions(states) {
119
+ const ts = [];
120
+ for (let i = 0; i < states.length - 1; i++) {
121
+ const from = states[i];
122
+ const to = states[i + 1];
123
+ if (!from || !to)
124
+ continue;
125
+ let kind = "resume";
126
+ if (from.persona_class !== to.persona_class)
127
+ kind = "persona-switch";
128
+ else if (from.context_size_class !== "overflow" &&
129
+ to.context_size_class === "overflow")
130
+ kind = "context-overflow";
131
+ else if (to.child_turn === 0)
132
+ kind = "spawn";
133
+ ts.push({ from, to, kind });
134
+ }
135
+ return ts;
136
+ }
137
+ //# sourceMappingURL=test_topology.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"test_topology.js","sourceRoot":"","sources":["../../src/test_topology.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,20 @@
1
+ export declare const TONES: readonly ["C", "C#", "D", "D#", "E", "F", "F#", "G", "G#", "A", "A#", "B"];
2
+ export declare const N_TONES = 12;
3
+ export type Tone = number;
4
+ export type Chord = readonly Tone[];
5
+ export declare function toneName(t: Tone): string;
6
+ export declare function intervalClass(a: Tone, b: Tone): number;
7
+ export declare function intervalConsonance(a: Tone, b: Tone): number;
8
+ export type Arity = "silent" | "monotonic" | "bitonic" | "tritonic" | "tetratonic" | "pentatonic" | "polyphonic";
9
+ export declare function classifyArity(toneCount: number): Arity;
10
+ export declare function chordArity(chord: Chord): Arity;
11
+ export declare function chordConsonance(chord: Chord): number;
12
+ export declare function chordTension(chord: Chord): number;
13
+ export interface Resolution {
14
+ resolves: boolean;
15
+ tonic: Tone | null;
16
+ finalConsonance: number;
17
+ tensionProfile: number[];
18
+ tensionDropped: boolean;
19
+ }
20
+ export declare function resolve(progression: readonly Chord[]): Resolution;
@@ -0,0 +1,81 @@
1
+ // Song-substrate CORE — the 12 chromatic tones, additive chords, arity (the
2
+ // monotonic…polyphonic primitives = tone-count), interval consonance, and
3
+ // resolution. This is ONE channel's read (the song). Per the directive: it returns
4
+ // STRUCTURE, never a scalar "truth" — the song is one vantage of three
5
+ // (score · output · song); triangulation across them lives above this module.
6
+ // Nothing here collapses to pass/fail; it emits the song-read's shape for the
7
+ // tensor to couple against the other channels.
8
+ export const TONES = ["C", "C#", "D", "D#", "E", "F", "F#", "G", "G#", "A", "A#", "B"];
9
+ export const N_TONES = 12;
10
+ export function toneName(t) {
11
+ return TONES[((t % N_TONES) + N_TONES) % N_TONES];
12
+ }
13
+ // Interval class (0..6) = the symmetric semitone distance. Consonance is grounded
14
+ // in just-intonation ratios: unison/octave most consonant, tritone least.
15
+ export function intervalClass(a, b) {
16
+ const d = Math.abs(a - b) % N_TONES;
17
+ return Math.min(d, N_TONES - d);
18
+ }
19
+ const IC_CONSONANCE = {
20
+ 0: 1.0, // unison / octave (2:1)
21
+ 5: 0.9, // perfect fifth / fourth (3:2, 4:3)
22
+ 4: 0.7, // major third / minor sixth (5:4)
23
+ 3: 0.6, // minor third / major sixth (6:5)
24
+ 2: 0.35, // major second / minor seventh
25
+ 1: 0.1, // minor second / major seventh
26
+ 6: 0.05, // tritone
27
+ };
28
+ export function intervalConsonance(a, b) {
29
+ return IC_CONSONANCE[intervalClass(a, b)] ?? 0;
30
+ }
31
+ export function classifyArity(toneCount) {
32
+ switch (toneCount) {
33
+ case 0: return "silent";
34
+ case 1: return "monotonic";
35
+ case 2: return "bitonic";
36
+ case 3: return "tritonic";
37
+ case 4: return "tetratonic";
38
+ case 5: return "pentatonic";
39
+ default: return "polyphonic";
40
+ }
41
+ }
42
+ export function chordArity(chord) {
43
+ return classifyArity(new Set(chord.map((t) => ((t % N_TONES) + N_TONES) % N_TONES)).size);
44
+ }
45
+ // Chord consonance = the mean of pairwise interval consonances (additive over
46
+ // pairs). A lone tone is maximally consonant (nothing clashes); silence is null.
47
+ export function chordConsonance(chord) {
48
+ const ts = [...new Set(chord.map((t) => ((t % N_TONES) + N_TONES) % N_TONES))];
49
+ if (ts.length <= 1)
50
+ return 1.0;
51
+ let sum = 0, pairs = 0;
52
+ for (let i = 0; i < ts.length; i++) {
53
+ for (let j = i + 1; j < ts.length; j++) {
54
+ sum += intervalConsonance(ts[i], ts[j]);
55
+ pairs++;
56
+ }
57
+ }
58
+ return sum / pairs;
59
+ }
60
+ // Tension = the complement of consonance. A dissonant chord wants to resolve.
61
+ export function chordTension(chord) {
62
+ return 1 - chordConsonance(chord);
63
+ }
64
+ const RESOLVE_CONSONANCE = 0.6; // a final chord at/above this is "at rest"
65
+ export function resolve(progression) {
66
+ const tensionProfile = progression.map(chordTension);
67
+ if (progression.length === 0) {
68
+ return { resolves: false, tonic: null, finalConsonance: 0, tensionProfile, tensionDropped: false };
69
+ }
70
+ const last = progression[progression.length - 1];
71
+ const finalConsonance = chordConsonance(last);
72
+ const tensionDropped = progression.length >= 2
73
+ ? tensionProfile[tensionProfile.length - 2] > tensionProfile[tensionProfile.length - 1]
74
+ : true; // a lone consonant chord is trivially at rest
75
+ const tonic = last.length ? [...last].sort((a, b) => a - b)[0] : null;
76
+ return {
77
+ resolves: finalConsonance >= RESOLVE_CONSONANCE && tensionDropped,
78
+ tonic, finalConsonance, tensionProfile, tensionDropped,
79
+ };
80
+ }
81
+ //# sourceMappingURL=tones.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tones.js","sourceRoot":"","sources":["../../src/tones.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,45 @@
1
+ /** How a granted tool name resolves to something runnable. */
2
+ export interface ToolProvider {
3
+ tool: string;
4
+ kind: "mcp" | "in_house";
5
+ /** the MCP server slug that hosts this tool (multiple tools may share one server). For kind "mcp"
6
+ * it's the external server; for kind "in_house" it's the engine's own server (#204), through which
7
+ * the tool is bridged and under whose mcp__<server>__ prefix it is advertised. */
8
+ server?: string;
9
+ /** for kind "mcp": the server's --mcp-config entry (command/args/env/url). */
10
+ config?: Record<string, unknown>;
11
+ }
12
+ export type ToolProviderRegistry = ReadonlyMap<string, ToolProvider>;
13
+ /** The engine's own MCP server slug — the key the repo's .mcp.json ships it under, and the prefix
14
+ * its tools are advertised behind (mcp__coltrane__<tool>). In-house engine tools are bridged through
15
+ * this server, so an in-house grant resolves to it (#204). */
16
+ export declare const ENGINE_MCP_SERVER = "coltrane";
17
+ /** A scoped grant like `Bash(npx vitest run:*)` resolves on its base tool name (`Bash`). */
18
+ export declare function toolBaseName(grant: string): string;
19
+ export interface ResolvedGrants {
20
+ /** MCP server slug → its --mcp-config entry, deduped across all grants that share a server. */
21
+ mcpServers: Record<string, unknown>;
22
+ /** in-house runtime tools the spawn should expose. */
23
+ inHouse: string[];
24
+ /** grants with no resolvable provider — dead names. Dispatch must refuse these. */
25
+ unknown: string[];
26
+ /** the grants as the SPAWN will see them, to feed --allowedTools (NOT the raw allowed_tools).
27
+ * Host-builtins and `mcp__<server>__*` grants pass through unchanged; a registry tool that
28
+ * resolves to an MCP server — INCLUDING an in-house engine tool bridged through the engine's own
29
+ * server — is namespaced to `mcp__<server>__<tool>`, because that is the name the server actually
30
+ * advertises. A bare slug (e.g. `output_write`) in --allowedTools matches nothing and the agent
31
+ * can't seal — #204. An in-house tool with no engine-server config keeps its bare name (no regression). */
32
+ effectiveAllowed: string[];
33
+ }
34
+ /** Claude Code MCP tools follow the `mcp__<server>__<tool>` naming convention. Extract the server
35
+ * slug so an MCP grant resolves to its server by convention — no per-tool registration needed. */
36
+ export declare function mcpServerOf(grant: string): string | null;
37
+ /** Resolve an agent's allowed_tools to providers. In order: a host-builtin passes (no server); an
38
+ * explicit registry entry wins; an `mcp__<server>__*` grant resolves by convention to that server's
39
+ * config from `mcpServerConfigs` (deployment-registered; coltrane ships its own); everything else —
40
+ * including an MCP grant for an unconfigured server — is `unknown` (a dead name). */
41
+ export declare function resolveToolGrants(allowed: readonly string[], registry: ToolProviderRegistry, mcpServerConfigs?: Readonly<Record<string, unknown>>): ResolvedGrants;
42
+ /** Fail closed: an agent that grants an unresolvable tool must not be dispatched — a granted tool
43
+ * with no provider is indistinguishable from a real one until the agent tries (and fails) to call
44
+ * it. Raising here at dispatch surfaces it as a clear error instead of a confabulated answer. */
45
+ export declare function assertToolGrantsResolvable(agentSlug: string, allowed: readonly string[], registry: ToolProviderRegistry, mcpServerConfigs?: Readonly<Record<string, unknown>>): ResolvedGrants;
@@ -0,0 +1,104 @@
1
+ // Tool-grant → provider resolution (#185). An agent's `allowed_tools` is a set of grants, each of
2
+ // which resolves to one of three provider classes:
3
+ // - host-builtin (Read/Write/Edit/Bash/Glob/Grep/WebFetch/WebSearch/…): provided by the Claude
4
+ // runtime, governed by --allowedTools + code_tool_access. No MCP server needed.
5
+ // - mcp: provided by an MCP server (e.g. a browser server) that must be wired into the spawn's
6
+ // --mcp-config. The OSS engine ships this RESOLUTION machinery; a deployment registers the
7
+ // actual server config (the server itself is deployment-provided).
8
+ // - in_house: a runtime primitive (e.g. output_write) the engine provides directly.
9
+ // A grant that resolves to NONE of these is a DEAD NAME — the prompt lists a tool the spawn can't
10
+ // provide, so the model confabulates. resolveToolGrants surfaces those as `unknown` so dispatch can
11
+ // fail closed instead of launching a spawn that advertises tools it cannot back.
12
+ // Host-builtin Claude Code tools — provided by the runtime, not an MCP server. Grants are governed
13
+ // by --allowedTools + code_tool_access; they never need a provider entry and are never "unknown".
14
+ const HOST_BUILTINS = new Set([
15
+ "Read", "Write", "Edit", "MultiEdit", "NotebookEdit",
16
+ "Bash", "BashOutput", "KillShell",
17
+ "Glob", "Grep", "LS",
18
+ "WebFetch", "WebSearch",
19
+ "Task", "TodoWrite",
20
+ ]);
21
+ /** The engine's own MCP server slug — the key the repo's .mcp.json ships it under, and the prefix
22
+ * its tools are advertised behind (mcp__coltrane__<tool>). In-house engine tools are bridged through
23
+ * this server, so an in-house grant resolves to it (#204). */
24
+ export const ENGINE_MCP_SERVER = "coltrane";
25
+ /** A scoped grant like `Bash(npx vitest run:*)` resolves on its base tool name (`Bash`). */
26
+ export function toolBaseName(grant) {
27
+ const paren = grant.indexOf("(");
28
+ return (paren >= 0 ? grant.slice(0, paren) : grant).trim();
29
+ }
30
+ /** Claude Code MCP tools follow the `mcp__<server>__<tool>` naming convention. Extract the server
31
+ * slug so an MCP grant resolves to its server by convention — no per-tool registration needed. */
32
+ export function mcpServerOf(grant) {
33
+ const m = toolBaseName(grant).match(/^mcp__(.+?)__/);
34
+ return m ? m[1] : null;
35
+ }
36
+ /** Resolve an agent's allowed_tools to providers. In order: a host-builtin passes (no server); an
37
+ * explicit registry entry wins; an `mcp__<server>__*` grant resolves by convention to that server's
38
+ * config from `mcpServerConfigs` (deployment-registered; coltrane ships its own); everything else —
39
+ * including an MCP grant for an unconfigured server — is `unknown` (a dead name). */
40
+ export function resolveToolGrants(allowed, registry, mcpServerConfigs = {}) {
41
+ const mcpServers = {};
42
+ const inHouse = [];
43
+ const unknown = [];
44
+ const effectiveAllowed = [];
45
+ for (const grant of allowed) {
46
+ const base = toolBaseName(grant);
47
+ if (HOST_BUILTINS.has(base)) {
48
+ effectiveAllowed.push(grant); // builtins pass through with their scoping intact
49
+ continue;
50
+ }
51
+ const prov = registry.get(base);
52
+ if (prov) {
53
+ if (prov.kind === "mcp" && prov.server) {
54
+ if (prov.config !== undefined)
55
+ mcpServers[prov.server] = prov.config;
56
+ effectiveAllowed.push(`mcp__${prov.server}__${base}`); // the name the server advertises
57
+ }
58
+ else if (prov.kind === "in_house") {
59
+ inHouse.push(base);
60
+ // #204 — an in-house engine tool is bridged through the engine's OWN MCP server. Resolving
61
+ // it as a "runtime primitive" left the server out of the spawn's mcp-config AND advertised
62
+ // the bare slug, which the server's namespaced surface never matched — so the agent could
63
+ // never call it (drafts emitted as text, nothing sealed). Wire the engine server in and name
64
+ // the tool the way the server exposes it. No engine-server config → keep the bare name.
65
+ if (prov.server && Object.prototype.hasOwnProperty.call(mcpServerConfigs, prov.server)) {
66
+ mcpServers[prov.server] = mcpServerConfigs[prov.server];
67
+ effectiveAllowed.push(`mcp__${prov.server}__${base}`);
68
+ }
69
+ else {
70
+ effectiveAllowed.push(base);
71
+ }
72
+ }
73
+ else {
74
+ effectiveAllowed.push(grant);
75
+ }
76
+ continue;
77
+ }
78
+ const server = mcpServerOf(base);
79
+ if (server) {
80
+ if (Object.prototype.hasOwnProperty.call(mcpServerConfigs, server)) {
81
+ mcpServers[server] = mcpServerConfigs[server];
82
+ effectiveAllowed.push(grant); // already in mcp__<server>__<tool> form
83
+ }
84
+ else {
85
+ unknown.push(grant); // an MCP tool whose server has no registered config — a dead name
86
+ }
87
+ continue;
88
+ }
89
+ unknown.push(grant);
90
+ }
91
+ return { mcpServers, inHouse, unknown, effectiveAllowed };
92
+ }
93
+ /** Fail closed: an agent that grants an unresolvable tool must not be dispatched — a granted tool
94
+ * with no provider is indistinguishable from a real one until the agent tries (and fails) to call
95
+ * it. Raising here at dispatch surfaces it as a clear error instead of a confabulated answer. */
96
+ export function assertToolGrantsResolvable(agentSlug, allowed, registry, mcpServerConfigs = {}) {
97
+ const resolved = resolveToolGrants(allowed, registry, mcpServerConfigs);
98
+ if (resolved.unknown.length > 0) {
99
+ throw new Error(`agent "${agentSlug}" grants unresolvable tool(s) [${resolved.unknown.join(", ")}] — no provider registered ` +
100
+ `(a granted tool with no provider is a dead name; register a provider or remove the grant)`);
101
+ }
102
+ return resolved;
103
+ }
104
+ //# sourceMappingURL=tool_providers.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tool_providers.js","sourceRoot":"","sources":["../../src/tool_providers.ts"],"names":[],"mappings":"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"}