@isaacriehm/cairn-core 0.4.3 → 0.6.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 (186) hide show
  1. package/dist/.tsbuildinfo +1 -1
  2. package/dist/align-undo/index.d.ts +6 -0
  3. package/dist/align-undo/index.js +6 -0
  4. package/dist/align-undo/index.js.map +1 -0
  5. package/dist/align-undo/log.d.ts +53 -0
  6. package/dist/align-undo/log.js +162 -0
  7. package/dist/align-undo/log.js.map +1 -0
  8. package/dist/align-undo/undo.d.ts +65 -0
  9. package/dist/align-undo/undo.js +397 -0
  10. package/dist/align-undo/undo.js.map +1 -0
  11. package/dist/attention/bulk-accept.js +9 -22
  12. package/dist/attention/bulk-accept.js.map +1 -1
  13. package/dist/attention/dedup.js +1 -47
  14. package/dist/attention/dedup.js.map +1 -1
  15. package/dist/attention/serve/api.js +3 -17
  16. package/dist/attention/serve/api.js.map +1 -1
  17. package/dist/attention/serve/index.js +3 -3
  18. package/dist/attention/serve/index.js.map +1 -1
  19. package/dist/drain/drain.d.ts +77 -0
  20. package/dist/drain/drain.js +464 -0
  21. package/dist/drain/drain.js.map +1 -0
  22. package/dist/drain/index.d.ts +5 -0
  23. package/dist/drain/index.js +5 -0
  24. package/dist/drain/index.js.map +1 -0
  25. package/dist/fix-align/index.d.ts +7 -0
  26. package/dist/fix-align/index.js +6 -0
  27. package/dist/fix-align/index.js.map +1 -0
  28. package/dist/fix-align/run.d.ts +99 -0
  29. package/dist/fix-align/run.js +258 -0
  30. package/dist/fix-align/run.js.map +1 -0
  31. package/dist/fix-align/sentinel.d.ts +59 -0
  32. package/dist/fix-align/sentinel.js +149 -0
  33. package/dist/fix-align/sentinel.js.map +1 -0
  34. package/dist/fs.d.ts +5 -0
  35. package/dist/fs.js +11 -0
  36. package/dist/fs.js.map +1 -0
  37. package/dist/gc/apply.js +4 -4
  38. package/dist/gc/apply.js.map +1 -1
  39. package/dist/ground/alignment-pending.d.ts +28 -0
  40. package/dist/ground/alignment-pending.js +83 -0
  41. package/dist/ground/alignment-pending.js.map +1 -0
  42. package/dist/ground/anchor-map.d.ts +14 -0
  43. package/dist/ground/anchor-map.js +56 -0
  44. package/dist/ground/anchor-map.js.map +1 -0
  45. package/dist/ground/frontmatter.d.ts +12 -0
  46. package/dist/ground/frontmatter.js +28 -0
  47. package/dist/ground/frontmatter.js.map +1 -1
  48. package/dist/ground/index.d.ts +10 -3
  49. package/dist/ground/index.js +9 -3
  50. package/dist/ground/index.js.map +1 -1
  51. package/dist/ground/paths.d.ts +21 -0
  52. package/dist/ground/paths.js +43 -0
  53. package/dist/ground/paths.js.map +1 -1
  54. package/dist/ground/schemas.d.ts +201 -0
  55. package/dist/ground/schemas.js +135 -10
  56. package/dist/ground/schemas.js.map +1 -1
  57. package/dist/ground/scope-index.js +4 -4
  58. package/dist/ground/scope-index.js.map +1 -1
  59. package/dist/ground/slug.d.ts +60 -0
  60. package/dist/ground/slug.js +103 -0
  61. package/dist/ground/slug.js.map +1 -0
  62. package/dist/ground/sot-bindings.d.ts +14 -0
  63. package/dist/ground/sot-bindings.js +79 -0
  64. package/dist/ground/sot-bindings.js.map +1 -0
  65. package/dist/ground/sot-cache.d.ts +18 -0
  66. package/dist/ground/sot-cache.js +62 -0
  67. package/dist/ground/sot-cache.js.map +1 -0
  68. package/dist/ground/topic-index.d.ts +27 -0
  69. package/dist/ground/topic-index.js +82 -0
  70. package/dist/ground/topic-index.js.map +1 -0
  71. package/dist/hooks/post-tool-use/index.d.ts +2 -0
  72. package/dist/hooks/post-tool-use/index.js +1 -0
  73. package/dist/hooks/post-tool-use/index.js.map +1 -1
  74. package/dist/hooks/post-tool-use/sot-align.d.ts +166 -0
  75. package/dist/hooks/post-tool-use/sot-align.js +1306 -0
  76. package/dist/hooks/post-tool-use/sot-align.js.map +1 -0
  77. package/dist/hooks/pre-commit/index.d.ts +8 -0
  78. package/dist/hooks/pre-commit/index.js +8 -0
  79. package/dist/hooks/pre-commit/index.js.map +1 -0
  80. package/dist/hooks/pre-commit/sot-align-precommit.d.ts +60 -0
  81. package/dist/hooks/pre-commit/sot-align-precommit.js +221 -0
  82. package/dist/hooks/pre-commit/sot-align-precommit.js.map +1 -0
  83. package/dist/hooks/runners/session-start.js +41 -0
  84. package/dist/hooks/runners/session-start.js.map +1 -1
  85. package/dist/hooks/sot-align-common.d.ts +39 -0
  86. package/dist/hooks/sot-align-common.js +152 -0
  87. package/dist/hooks/sot-align-common.js.map +1 -0
  88. package/dist/index.d.ts +5 -0
  89. package/dist/index.js +5 -0
  90. package/dist/index.js.map +1 -1
  91. package/dist/init/index.d.ts +4 -2
  92. package/dist/init/index.js +2 -1
  93. package/dist/init/index.js.map +1 -1
  94. package/dist/init/ingest-docs.d.ts +30 -47
  95. package/dist/init/ingest-docs.js +113 -410
  96. package/dist/init/ingest-docs.js.map +1 -1
  97. package/dist/init/init.d.ts +8 -0
  98. package/dist/init/init.js +58 -29
  99. package/dist/init/init.js.map +1 -1
  100. package/dist/init/mapper.js +6 -6
  101. package/dist/init/mapper.js.map +1 -1
  102. package/dist/init/phases/5-brand.js +1 -1
  103. package/dist/init/phases/5-brand.js.map +1 -1
  104. package/dist/init/phases/5b-topic-index.d.ts +30 -0
  105. package/dist/init/phases/5b-topic-index.js +62 -0
  106. package/dist/init/phases/5b-topic-index.js.map +1 -0
  107. package/dist/init/phases/6-docs-ingest.d.ts +4 -5
  108. package/dist/init/phases/6-docs-ingest.js +5 -6
  109. package/dist/init/phases/6-docs-ingest.js.map +1 -1
  110. package/dist/init/phases/index.d.ts +2 -0
  111. package/dist/init/phases/index.js +1 -0
  112. package/dist/init/phases/index.js.map +1 -1
  113. package/dist/init/phases/parallel-678.d.ts +14 -17
  114. package/dist/init/phases/parallel-678.js +77 -98
  115. package/dist/init/phases/parallel-678.js.map +1 -1
  116. package/dist/init/phases/source-comments-output-io.d.ts +16 -10
  117. package/dist/init/phases/source-comments-output-io.js +7 -10
  118. package/dist/init/phases/source-comments-output-io.js.map +1 -1
  119. package/dist/init/phases/types.d.ts +1 -1
  120. package/dist/init/phases/types.js +1 -0
  121. package/dist/init/phases/types.js.map +1 -1
  122. package/dist/init/rules-merge/discover.d.ts +8 -3
  123. package/dist/init/rules-merge/discover.js +7 -3
  124. package/dist/init/rules-merge/discover.js.map +1 -1
  125. package/dist/init/rules-merge/ingest.d.ts +81 -28
  126. package/dist/init/rules-merge/ingest.js +456 -162
  127. package/dist/init/rules-merge/ingest.js.map +1 -1
  128. package/dist/init/sot-emit.d.ts +84 -0
  129. package/dist/init/sot-emit.js +214 -0
  130. package/dist/init/sot-emit.js.map +1 -0
  131. package/dist/init/source-comments/classify.d.ts +12 -10
  132. package/dist/init/source-comments/classify.js +13 -25
  133. package/dist/init/source-comments/classify.js.map +1 -1
  134. package/dist/init/source-comments/index.d.ts +1 -1
  135. package/dist/init/source-comments/index.js +1 -1
  136. package/dist/init/source-comments/index.js.map +1 -1
  137. package/dist/init/source-comments/ingest.d.ts +91 -67
  138. package/dist/init/source-comments/ingest.js +392 -361
  139. package/dist/init/source-comments/ingest.js.map +1 -1
  140. package/dist/init/topic-index/index.d.ts +36 -0
  141. package/dist/init/topic-index/index.js +46 -0
  142. package/dist/init/topic-index/index.js.map +1 -0
  143. package/dist/init/topic-index/judge.d.ts +20 -0
  144. package/dist/init/topic-index/judge.js +65 -0
  145. package/dist/init/topic-index/judge.js.map +1 -0
  146. package/dist/init/topic-index/resolve.d.ts +50 -0
  147. package/dist/init/topic-index/resolve.js +196 -0
  148. package/dist/init/topic-index/resolve.js.map +1 -0
  149. package/dist/init/topic-index/walk.d.ts +43 -0
  150. package/dist/init/topic-index/walk.js +293 -0
  151. package/dist/init/topic-index/walk.js.map +1 -0
  152. package/dist/mcp/schemas.d.ts +45 -8
  153. package/dist/mcp/schemas.js +43 -7
  154. package/dist/mcp/schemas.js.map +1 -1
  155. package/dist/mcp/tools/align-drain.d.ts +7 -0
  156. package/dist/mcp/tools/align-drain.js +26 -0
  157. package/dist/mcp/tools/align-drain.js.map +1 -0
  158. package/dist/mcp/tools/index.d.ts +1 -1
  159. package/dist/mcp/tools/index.js +3 -0
  160. package/dist/mcp/tools/index.js.map +1 -1
  161. package/dist/mcp/tools/init-phases.js +4 -1
  162. package/dist/mcp/tools/init-phases.js.map +1 -1
  163. package/dist/mcp/tools/record-decision.js +5 -2
  164. package/dist/mcp/tools/record-decision.js.map +1 -1
  165. package/dist/mcp/tools/resolve-attention.d.ts +2 -2
  166. package/dist/mcp/tools/resolve-attention.js +781 -5
  167. package/dist/mcp/tools/resolve-attention.js.map +1 -1
  168. package/dist/status-line/event-queue.d.ts +40 -0
  169. package/dist/status-line/event-queue.js +195 -0
  170. package/dist/status-line/event-queue.js.map +1 -0
  171. package/dist/status-line/format.d.ts +1 -1
  172. package/dist/status-line/format.js +49 -6
  173. package/dist/status-line/format.js.map +1 -1
  174. package/dist/status-line/index.d.ts +41 -0
  175. package/dist/status-line/index.js +14 -0
  176. package/dist/status-line/index.js.map +1 -1
  177. package/dist/status-line/reader.js +23 -18
  178. package/dist/status-line/reader.js.map +1 -1
  179. package/dist/status-line/writer.d.ts +1 -1
  180. package/dist/status-line/writer.js +5 -0
  181. package/dist/status-line/writer.js.map +1 -1
  182. package/dist/text/jaccard.d.ts +19 -0
  183. package/dist/text/jaccard.js +68 -0
  184. package/dist/text/jaccard.js.map +1 -0
  185. package/package.json +1 -1
  186. package/templates/.cairn/git-hooks/pre-commit +16 -3
@@ -0,0 +1,62 @@
1
+ import { existsSync, readFileSync } from "node:fs";
2
+ import { writeFileSafe } from "../fs.js";
3
+ import { parse as parseYaml, stringify as stringifyYaml } from "yaml";
4
+ import { logger } from "../logger.js";
5
+ import { sotCachePath } from "./paths.js";
6
+ import { SotCache } from "./schemas.js";
7
+ const log = logger("ground.sot-cache");
8
+ /**
9
+ * Sot-cache holds pre-tokenized DEC body content for the Layer A Jaccard
10
+ * pre-filter. Rebuilt at SessionStart, incremental on PostToolUse Write
11
+ * events that touch a DEC body or sot-path file. Mtime-keyed so a stale
12
+ * entry is detected without re-tokenizing every body on every Write.
13
+ */
14
+ export function emptySotCache() {
15
+ return { version: 1, generated: new Date().toISOString(), entries: {} };
16
+ }
17
+ export function readSotCache(repoRoot) {
18
+ const path = sotCachePath(repoRoot);
19
+ if (!existsSync(path))
20
+ return emptySotCache();
21
+ try {
22
+ const raw = readFileSync(path, "utf8");
23
+ const parsed = SotCache.safeParse(parseYaml(raw));
24
+ if (!parsed.success) {
25
+ log.warn({ path, error: parsed.error.message }, "sot-cache invalid; treating as empty");
26
+ return emptySotCache();
27
+ }
28
+ return parsed.data;
29
+ }
30
+ catch (err) {
31
+ log.warn({ path, err }, "sot-cache read failed; treating as empty");
32
+ return emptySotCache();
33
+ }
34
+ }
35
+ export function writeSotCache(repoRoot, cache) {
36
+ const path = sotCachePath(repoRoot);
37
+ const next = { ...cache, generated: new Date().toISOString() };
38
+ writeFileSafe(path, stringifyYaml(next));
39
+ log.debug({ path, entries: Object.keys(next.entries).length }, "wrote sot-cache");
40
+ return path;
41
+ }
42
+ export function setEntry(cache, decId, entry) {
43
+ return { ...cache, entries: { ...cache.entries, [decId]: entry } };
44
+ }
45
+ export function getEntry(cache, decId) {
46
+ return cache.entries[decId] ?? null;
47
+ }
48
+ export function deleteEntry(cache, decId) {
49
+ if (cache.entries[decId] === undefined)
50
+ return cache;
51
+ const entries = { ...cache.entries };
52
+ delete entries[decId];
53
+ return { ...cache, entries };
54
+ }
55
+ /**
56
+ * Iterate all entries. Layer A's pre-filter pass calls this on each
57
+ * Write to compute Jaccard against every cached DEC body.
58
+ */
59
+ export function entries(cache) {
60
+ return Object.values(cache.entries);
61
+ }
62
+ //# sourceMappingURL=sot-cache.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sot-cache.js","sourceRoot":"","sources":["../../src/ground/sot-cache.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,27 @@
1
+ import { TopicIndex, type TopicIndexEntry } from "./schemas.js";
2
+ /**
3
+ * Topic-index is the ground-state file that maps content-fingerprint
4
+ * slugs to the DECs they belong to. Phase 5b builds it before any
5
+ * extractor runs so phases 6 / 7b / 7c can dedup-by-topic instead of
6
+ * emitting one DEC per source. Layer A's PostToolUse hook reads it on
7
+ * every Write to know whether a freshly typed prose block is the first
8
+ * sighting of its content or a repeat of an existing topic.
9
+ */
10
+ export declare function emptyTopicIndex(): TopicIndex;
11
+ export declare function readTopicIndex(repoRoot: string): TopicIndex;
12
+ export declare function writeTopicIndex(repoRoot: string, index: TopicIndex): string;
13
+ /**
14
+ * Insert or replace a topic entry. Returns the updated index.
15
+ */
16
+ export declare function setTopic(index: TopicIndex, slug: string, entry: TopicIndexEntry): TopicIndex;
17
+ /**
18
+ * Look up a topic by slug. Returns null if absent.
19
+ */
20
+ export declare function getTopic(index: TopicIndex, slug: string): TopicIndexEntry | null;
21
+ /**
22
+ * Clear `dec_id` from any topic entry that references this DEC. Used
23
+ * by `cairn attention undo` for tier3-creation reversal so the topic
24
+ * stays in the index (next phase 5b walk can re-emit the topic) but
25
+ * no longer points at the now-deleted DEC.
26
+ */
27
+ export declare function clearDecFromTopicIndex(index: TopicIndex, decId: string): TopicIndex;
@@ -0,0 +1,82 @@
1
+ import { existsSync, readFileSync } from "node:fs";
2
+ import { writeFileSafe } from "../fs.js";
3
+ import { parse as parseYaml, stringify as stringifyYaml } from "yaml";
4
+ import { logger } from "../logger.js";
5
+ import { topicIndexPath } from "./paths.js";
6
+ import { TopicIndex } from "./schemas.js";
7
+ const log = logger("ground.topic-index");
8
+ /**
9
+ * Topic-index is the ground-state file that maps content-fingerprint
10
+ * slugs to the DECs they belong to. Phase 5b builds it before any
11
+ * extractor runs so phases 6 / 7b / 7c can dedup-by-topic instead of
12
+ * emitting one DEC per source. Layer A's PostToolUse hook reads it on
13
+ * every Write to know whether a freshly typed prose block is the first
14
+ * sighting of its content or a repeat of an existing topic.
15
+ */
16
+ export function emptyTopicIndex() {
17
+ return { version: 1, generated: new Date().toISOString(), topics: {} };
18
+ }
19
+ export function readTopicIndex(repoRoot) {
20
+ const path = topicIndexPath(repoRoot);
21
+ if (!existsSync(path))
22
+ return emptyTopicIndex();
23
+ try {
24
+ const raw = readFileSync(path, "utf8");
25
+ const parsed = TopicIndex.safeParse(parseYaml(raw));
26
+ if (!parsed.success) {
27
+ log.warn({ path, error: parsed.error.message }, "topic-index invalid; treating as empty");
28
+ return emptyTopicIndex();
29
+ }
30
+ return parsed.data;
31
+ }
32
+ catch (err) {
33
+ log.warn({ path, err }, "topic-index read failed; treating as empty");
34
+ return emptyTopicIndex();
35
+ }
36
+ }
37
+ export function writeTopicIndex(repoRoot, index) {
38
+ const path = topicIndexPath(repoRoot);
39
+ const next = { ...index, generated: new Date().toISOString() };
40
+ writeFileSafe(path, stringifyYaml(next));
41
+ log.debug({ path, topics: Object.keys(next.topics).length }, "wrote topic-index");
42
+ return path;
43
+ }
44
+ /**
45
+ * Insert or replace a topic entry. Returns the updated index.
46
+ */
47
+ export function setTopic(index, slug, entry) {
48
+ return {
49
+ ...index,
50
+ topics: { ...index.topics, [slug]: entry },
51
+ };
52
+ }
53
+ /**
54
+ * Look up a topic by slug. Returns null if absent.
55
+ */
56
+ export function getTopic(index, slug) {
57
+ return index.topics[slug] ?? null;
58
+ }
59
+ /**
60
+ * Clear `dec_id` from any topic entry that references this DEC. Used
61
+ * by `cairn attention undo` for tier3-creation reversal so the topic
62
+ * stays in the index (next phase 5b walk can re-emit the topic) but
63
+ * no longer points at the now-deleted DEC.
64
+ */
65
+ export function clearDecFromTopicIndex(index, decId) {
66
+ let mutated = false;
67
+ const topics = {};
68
+ for (const [slug, entry] of Object.entries(index.topics)) {
69
+ if (entry.dec_id === decId) {
70
+ const { dec_id: _omitted, ...rest } = entry;
71
+ topics[slug] = rest;
72
+ mutated = true;
73
+ }
74
+ else {
75
+ topics[slug] = entry;
76
+ }
77
+ }
78
+ if (!mutated)
79
+ return index;
80
+ return { ...index, topics };
81
+ }
82
+ //# sourceMappingURL=topic-index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"topic-index.js","sourceRoot":"","sources":["../../src/ground/topic-index.ts"],"names":[],"mappings":"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"}
@@ -17,3 +17,5 @@ export { scanForCopyLeakage } from "./copy-scanner.js";
17
17
  export type { CopyIssue } from "./copy-scanner.js";
18
18
  export { readCopySafetyConfig } from "./allowlist-reader.js";
19
19
  export type { CopySafetyConfig } from "./allowlist-reader.js";
20
+ export { alignFile, runSotAlign } from "./sot-align.js";
21
+ export type { AlignFileArgs, AlignFileResult, CreationVerdict, DedupVerdict, } from "./sot-align.js";
@@ -12,4 +12,5 @@ export { buildLegend } from "./legend-builder.js";
12
12
  export { runWriteGuardian } from "./write-guardian.js";
13
13
  export { scanForCopyLeakage } from "./copy-scanner.js";
14
14
  export { readCopySafetyConfig } from "./allowlist-reader.js";
15
+ export { alignFile, runSotAlign } from "./sot-align.js";
15
16
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/hooks/post-tool-use/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AACrD,OAAO,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AAEtD,OAAO,EACL,mBAAmB,EACnB,kBAAkB,EAClB,UAAU,GACX,MAAM,mBAAmB,CAAC;AAM3B,OAAO,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAElD,OAAO,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AACvD,OAAO,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AAEvD,OAAO,EAAE,oBAAoB,EAAE,MAAM,uBAAuB,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/hooks/post-tool-use/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AACrD,OAAO,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AAEtD,OAAO,EACL,mBAAmB,EACnB,kBAAkB,EAClB,UAAU,GACX,MAAM,mBAAmB,CAAC;AAM3B,OAAO,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAElD,OAAO,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AACvD,OAAO,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AAEvD,OAAO,EAAE,oBAAoB,EAAE,MAAM,uBAAuB,CAAC;AAE7D,OAAO,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC"}
@@ -0,0 +1,166 @@
1
+ /**
2
+ * Layer A — live SoT alignment hook (plan §4.1).
3
+ *
4
+ * `cairn hook sot-align` runs as a PostToolUse hook on Claude Code's
5
+ * Write/Edit. For every prose block in the just-written file the
6
+ * pipeline picks one of:
7
+ *
8
+ * - **Tier 1 (deterministic, no Haiku)** — block is a verbatim/
9
+ * near-verbatim duplicate of an existing accepted DEC/INV body
10
+ * (Jaccard ≥ 0.85, 3-shingle ≥ 60%, length ratio 0.5-2.0).
11
+ * Auto-replace with `// §DEC-<hash>` (or `# §DEC-<hash>` per
12
+ * language). Statusline blip `⬡ aligned`.
13
+ *
14
+ * - **Tier 2 — Haiku dedup judge, two-pass.**
15
+ * Pass 1 (cheap, snippet + candidate body) → `same | different |
16
+ * ambiguous`. `same` → cite. `different` → next candidate.
17
+ * `ambiguous` → escalate to Pass 2.
18
+ * Pass 2 (full bodies + ±200-char source context + step-by-step
19
+ * prompt) → `same | different | augments | ambiguous`. `same`
20
+ * cite; `different` next; `augments` triggers two-stage delta:
21
+ * - Stage 1 — Haiku extracts the delta prose ("NO_DELTA" → same).
22
+ * - Stage 2 — Haiku classifies the delta `constraint | rationale`.
23
+ * constraint → fresh INV linked via `derived_from`; rationale
24
+ * → fresh DEC linked via `related`. The augmented source
25
+ * gains a `// §INV-<new>` / `// §DEC-<new>` cite *alongside*
26
+ * the existing one (existing token preserved).
27
+ * `ambiguous` (still!) → write to `.cairn/ground/alignment-
28
+ * pending/<id>.md` and surface via cairn-attention.
29
+ *
30
+ * - **Tier 3 — Haiku creation judge, two-pass.**
31
+ * Pass 1 → `decision | constraint | descriptive | ambiguous`.
32
+ * `descriptive` no-op (false-positive DEC creation pollutes
33
+ * ground state worse than missed capture). `ambiguous` →
34
+ * escalate to Pass 2 (full prose + ±200-char context + step-by-
35
+ * step prompt). Pass-2-still-ambiguous → alignment-pending.
36
+ *
37
+ * Hard rules:
38
+ * - The hook never blocks the Write. Failures degrade to no-op +
39
+ * log; the operator's edit always succeeds.
40
+ * - Per-Write call caps: max HAIKU_PASS1_CAP Pass-1 calls + max
41
+ * HAIKU_PASS2_CAP Pass-2 calls per Write. Excess defers to
42
+ * `.cairn/staleness/layer-a-deferred.jsonl` for Layer C drain.
43
+ * - Verdict cache at `.cairn/cache/haiku/<scope>/<blockHash>-<key>.json`
44
+ * so re-running the same prose hits cache instead of Haiku.
45
+ * - Source files outside Claude's repo (cwd) are skipped. Markdown
46
+ * (`.md`/`.mdx`) skipped entirely — operator-curated narrative is
47
+ * handled by phase 5b's topic-index + the doc-drift sensor.
48
+ */
49
+ export interface AlignFileArgs {
50
+ repoRoot: string;
51
+ /** Repo-relative POSIX path written by Claude Code. */
52
+ filePath: string;
53
+ /** Claude Code session id (for statusline blips). */
54
+ sessionId: string | null;
55
+ /**
56
+ * Mock dedup judge — Pass 1. Default uses Haiku via runClaude.
57
+ */
58
+ mockDedupJudgePass1?: (args: {
59
+ blockBody: string;
60
+ candidate: {
61
+ id: string;
62
+ body: string;
63
+ };
64
+ }) => Promise<DedupVerdictPass1>;
65
+ /**
66
+ * Mock dedup judge — Pass 2 (CoT escalation). Default uses Haiku.
67
+ */
68
+ mockDedupJudgePass2?: (args: {
69
+ blockBody: string;
70
+ blockContext: string;
71
+ candidate: {
72
+ id: string;
73
+ body: string;
74
+ };
75
+ }) => Promise<DedupVerdictPass2>;
76
+ /**
77
+ * Mock delta extractor (Stage 1) — extract the prose delta when
78
+ * Pass 2 returns `augments`. Default uses Haiku.
79
+ */
80
+ mockDeltaExtract?: (args: {
81
+ blockBody: string;
82
+ candidateBody: string;
83
+ }) => Promise<string>;
84
+ /**
85
+ * Mock delta classifier (Stage 2) — `constraint | rationale`.
86
+ * Default uses Haiku.
87
+ */
88
+ mockDeltaClassify?: (args: {
89
+ delta: string;
90
+ }) => Promise<DeltaKind>;
91
+ /**
92
+ * Mock creation judge — Pass 1. Default uses Haiku via runClaude.
93
+ */
94
+ mockCreationJudgePass1?: (args: {
95
+ blockBody: string;
96
+ file: string;
97
+ line: number;
98
+ }) => Promise<CreationVerdict>;
99
+ /**
100
+ * Mock creation judge — Pass 2 (CoT escalation). Default uses Haiku.
101
+ */
102
+ mockCreationJudgePass2?: (args: {
103
+ blockBody: string;
104
+ blockContext: string;
105
+ file: string;
106
+ line: number;
107
+ }) => Promise<CreationVerdict>;
108
+ /**
109
+ * Override the per-call Pass-1 Haiku cap. Default 5 — appropriate
110
+ * for live PostToolUse Writes where the cost has to stay tight.
111
+ * Layer D (`cairn fix align`) sets this much higher (e.g. 200) so a
112
+ * single-file sweep can fully judge every block.
113
+ */
114
+ pass1Cap?: number;
115
+ /** Override the per-call Pass-2 Haiku cap. Default 2. */
116
+ pass2Cap?: number;
117
+ /**
118
+ * When true, suppress the Tier 3 creation pipeline entirely — Tier 1
119
+ * + Tier 2 dedup still run. Layer D's `--no-creation` flag sets this
120
+ * so a sweep only consolidates duplicates without proposing fresh
121
+ * DECs from prose that doesn't match anything in the ledger yet.
122
+ */
123
+ skipCreation?: boolean;
124
+ }
125
+ type DedupVerdictPass1 = "same" | "different" | "ambiguous";
126
+ type DedupVerdictPass2 = "same" | "different" | "augments" | "ambiguous";
127
+ type DeltaKind = "constraint" | "rationale";
128
+ export type CreationVerdict = "decision" | "constraint" | "descriptive" | "ambiguous";
129
+ /** Back-compat alias preserved for external callers. */
130
+ export type DedupVerdict = DedupVerdictPass1;
131
+ export interface AlignFileResult {
132
+ /** Number of prose blocks discovered in the written file. */
133
+ blocksConsidered: number;
134
+ /** Tier 1 deterministic auto-cites. */
135
+ tier1Aligned: number;
136
+ /** Tier 2 Haiku-confirmed cites. */
137
+ tier2Aligned: number;
138
+ /** Tier 3 fresh DECs emitted. */
139
+ decsCreated: number;
140
+ /** Tier 3 fresh INVs emitted. */
141
+ invsCreated: number;
142
+ /** Augments-DEC siblings (Pass 2 delta = rationale). */
143
+ augmentsDecs: number;
144
+ /** Augments-INV siblings (Pass 2 delta = constraint). */
145
+ augmentsInvs: number;
146
+ /** Blocks queued in `.cairn/ground/alignment-pending/`. */
147
+ pending: number;
148
+ /** Blocks deferred to staleness (cap exceeded). */
149
+ deferredToStaleness: number;
150
+ /** Blocks classified as descriptive (no-op). */
151
+ descriptive: number;
152
+ /** Blocks skipped for any reason — already-cited, length floor, etc. */
153
+ skipped: number;
154
+ /** Pass-1 Haiku calls made. */
155
+ haikuPass1Calls: number;
156
+ /** Pass-2 Haiku calls made. */
157
+ haikuPass2Calls: number;
158
+ /** Total Haiku calls (Pass 1 + Pass 2 + augments stages). Back-compat. */
159
+ haikuCalls: number;
160
+ }
161
+ /**
162
+ * Run the Layer A pipeline against one repo-relative file.
163
+ */
164
+ export declare function alignFile(args: AlignFileArgs): Promise<AlignFileResult>;
165
+ export declare function runSotAlign(): Promise<void>;
166
+ export {};