@isaacriehm/cairn-core 0.26.0 → 0.31.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.
- package/dist/.tsbuildinfo +1 -1
- package/dist/gc/config-drift.d.ts +60 -0
- package/dist/gc/config-drift.js +262 -0
- package/dist/gc/config-drift.js.map +1 -0
- package/dist/gc/index.d.ts +2 -0
- package/dist/gc/index.js +1 -0
- package/dist/gc/index.js.map +1 -1
- package/dist/gc/sweep.js +11 -0
- package/dist/gc/sweep.js.map +1 -1
- package/dist/gc/types.d.ts +2 -2
- package/dist/hooks/post-tool-use/sot-align.d.ts +4 -0
- package/dist/hooks/post-tool-use/sot-align.js +26 -3
- package/dist/hooks/post-tool-use/sot-align.js.map +1 -1
- package/dist/hooks/sot-align-common.d.ts +10 -0
- package/dist/hooks/sot-align-common.js +32 -0
- package/dist/hooks/sot-align-common.js.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/init/brand-setup.js +8 -3
- package/dist/init/brand-setup.js.map +1 -1
- package/dist/init/curator/emit.d.ts +10 -0
- package/dist/init/curator/emit.js +29 -17
- package/dist/init/curator/emit.js.map +1 -1
- package/dist/init/curator/index.d.ts +2 -0
- package/dist/init/curator/index.js +2 -0
- package/dist/init/curator/index.js.map +1 -1
- package/dist/init/curator/walker.d.ts +7 -0
- package/dist/init/curator/walker.js +17 -4
- package/dist/init/curator/walker.js.map +1 -1
- package/dist/init/index.d.ts +1 -1
- package/dist/init/index.js +1 -1
- package/dist/init/index.js.map +1 -1
- package/dist/init/phases/4-seed.js +7 -2
- package/dist/init/phases/4-seed.js.map +1 -1
- package/dist/init/seed.d.ts +7 -0
- package/dist/init/seed.js +24 -16
- package/dist/init/seed.js.map +1 -1
- package/dist/init/topic-index/index.d.ts +8 -0
- package/dist/init/topic-index/index.js +17 -8
- package/dist/init/topic-index/index.js.map +1 -1
- package/dist/invariants/prune.d.ts +6 -4
- package/dist/invariants/prune.js +40 -7
- package/dist/invariants/prune.js.map +1 -1
- package/dist/mcp/schemas.d.ts +26 -0
- package/dist/mcp/schemas.js +23 -0
- package/dist/mcp/schemas.js.map +1 -1
- package/dist/mcp/tools/in-scope.js +7 -1
- package/dist/mcp/tools/in-scope.js.map +1 -1
- package/dist/mcp/tools/index.js +3 -0
- package/dist/mcp/tools/index.js.map +1 -1
- package/dist/mcp/tools/invariant-get.js +37 -28
- package/dist/mcp/tools/invariant-get.js.map +1 -1
- package/dist/mcp/tools/resolve-attention.d.ts +1 -1
- package/dist/mcp/tools/resolve-attention.js +92 -0
- package/dist/mcp/tools/resolve-attention.js.map +1 -1
- package/dist/mcp/tools/resync.d.ts +19 -0
- package/dist/mcp/tools/resync.js +109 -0
- package/dist/mcp/tools/resync.js.map +1 -0
- package/dist/migrate/migrations/0005-demote-autofilled-brand.d.ts +11 -3
- package/dist/migrate/migrations/0005-demote-autofilled-brand.js +67 -21
- package/dist/migrate/migrations/0005-demote-autofilled-brand.js.map +1 -1
- package/dist/migrate/migrations/0006-prune-sot-align-invariants.d.ts +17 -15
- package/dist/migrate/migrations/0006-prune-sot-align-invariants.js +23 -17
- package/dist/migrate/migrations/0006-prune-sot-align-invariants.js.map +1 -1
- package/dist/migrate/migrations/0008-clean-adoption-scaffolding.d.ts +39 -0
- package/dist/migrate/migrations/0008-clean-adoption-scaffolding.js +206 -0
- package/dist/migrate/migrations/0008-clean-adoption-scaffolding.js.map +1 -0
- package/dist/migrate/registry.js +2 -0
- package/dist/migrate/registry.js.map +1 -1
- package/dist/resync/archive.d.ts +12 -0
- package/dist/resync/archive.js +29 -0
- package/dist/resync/archive.js.map +1 -0
- package/dist/resync/index.d.ts +73 -0
- package/dist/resync/index.js +389 -0
- package/dist/resync/index.js.map +1 -0
- package/dist/resync/recluster.d.ts +59 -0
- package/dist/resync/recluster.js +66 -0
- package/dist/resync/recluster.js.map +1 -0
- package/dist/session-start/build.js +47 -30
- package/dist/session-start/build.js.map +1 -1
- package/dist/session-start/templates.js +4 -4
- package/dist/session-start/templates.js.map +1 -1
- package/package.json +2 -2
- package/templates/.cairn/config/sensors.yaml +1 -1
- package/templates/.cairn/config/workflow.md +5 -12
- package/templates/.cairn/git-hooks/commit-msg +0 -2
- package/templates/.cairn/git-hooks/post-commit +0 -2
- package/templates/.cairn/ground/brand/overview.md +2 -2
- package/templates/.cairn/ground/brand/voice.md +2 -2
- package/templates/.cairn/ground/product/positioning.md +2 -2
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `cairn_resync` — operator-initiated re-discovery that resolves config drift.
|
|
3
|
+
*
|
|
4
|
+
* The config-drift sensor (24h GC) surfaces the gap between declared config and
|
|
5
|
+
* the grown tree as `baseline_finding` nudges; this tool is the verb that turns
|
|
6
|
+
* them into concrete `config.yaml` edits. It writes COMMITTED config, so it is
|
|
7
|
+
* review-class: preview first (default), summarize the proposed edits, get the
|
|
8
|
+
* operator's OK, then call again with `apply: true`. Apply archives the
|
|
9
|
+
* pre-resync config to `.cairn/ground/.archive/` and is idempotent.
|
|
10
|
+
*/
|
|
11
|
+
import { cairnDir } from "@isaacriehm/cairn-state";
|
|
12
|
+
import { runResync, runResyncRecluster } from "../../resync/index.js";
|
|
13
|
+
import { runCuratorEmit, runCuratorWalker } from "../../init/index.js";
|
|
14
|
+
import { requireBootstrap } from "../bootstrap-guard.js";
|
|
15
|
+
import { resyncInput } from "../schemas.js";
|
|
16
|
+
const RECURATE_CAPTURE_SOURCE = "resync-curator";
|
|
17
|
+
export const resyncTool = {
|
|
18
|
+
name: "cairn_resync",
|
|
19
|
+
description: "Resolve surfaced config drift (the config-drift baseline findings) by proposing concrete .cairn/config.yaml edits: add a grown dir to componentDirs, add a new file type to extensions, add an ignored path to off_limits, or drop a dead componentDir. Default previews the edits (mutates nothing) — summarize them and get the operator's OK, then call with apply:true. Apply archives the pre-resync config to .cairn/ground/.archive/ and is idempotent. Pass `area` to scope to one subtree. Pass recluster:true to instead run the LLM re-cluster pass (re-walk prose, Haiku-judge new semantic collisions, rebuild topic-index + anchor-map) — opt-in, spends Haiku on new prose only; preview first, then apply:true to overwrite the (archived) maps. Pass recurate:'walk' (with `area`) to build the curator corpus for re-curation, then — after the cairn-resync skill dispatches curator-map/reduce subagents — recurate:'emit' to write the resulting DEC/INV drafts to _inbox/ (drained via cairn-attention). recurate is skill-driven; don't call it directly.",
|
|
20
|
+
inputSchema: resyncInput,
|
|
21
|
+
handler: async (ctx, input) => {
|
|
22
|
+
const block = requireBootstrap(ctx.repoRoot);
|
|
23
|
+
if (block !== null)
|
|
24
|
+
return block;
|
|
25
|
+
const apply = input.apply === true;
|
|
26
|
+
if (input.recurate === "walk") {
|
|
27
|
+
const w = await runCuratorWalker({
|
|
28
|
+
repoRoot: ctx.repoRoot,
|
|
29
|
+
...(input.area !== undefined ? { area: input.area } : {}),
|
|
30
|
+
});
|
|
31
|
+
return {
|
|
32
|
+
ok: true,
|
|
33
|
+
mode: "recurate-walk",
|
|
34
|
+
area: input.area ?? null,
|
|
35
|
+
curator_dir: cairnDir(ctx.repoRoot, "init", "curator"),
|
|
36
|
+
shards_path: w.shards_path,
|
|
37
|
+
corpus_path: w.corpus_path,
|
|
38
|
+
records_total: w.records_total,
|
|
39
|
+
records_by_kind: w.records_by_kind,
|
|
40
|
+
shards: w.shards,
|
|
41
|
+
note: w.shards === 0
|
|
42
|
+
? "no curatable prose in this area — nothing to dispatch; skip emit"
|
|
43
|
+
: "dispatch curator-map (rounds of 4) + curator-reduce over the shard plan, then call again with recurate:'emit'",
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
if (input.recurate === "emit") {
|
|
47
|
+
const e = await runCuratorEmit({
|
|
48
|
+
repoRoot: ctx.repoRoot,
|
|
49
|
+
draft: true,
|
|
50
|
+
captureSource: RECURATE_CAPTURE_SOURCE,
|
|
51
|
+
});
|
|
52
|
+
return {
|
|
53
|
+
ok: true,
|
|
54
|
+
mode: "recurate-emit",
|
|
55
|
+
dec_drafts: e.decsWritten.map((d) => ({ id: d.id, path: d.path, title: d.title })),
|
|
56
|
+
inv_drafts: e.invsWritten.map((d) => ({ id: d.id, path: d.path, title: d.title })),
|
|
57
|
+
dropped: e.dropped,
|
|
58
|
+
drop_reasons: e.dropReasons,
|
|
59
|
+
note: "DEC/INV drafts written to _inbox/ — drain via cairn-attention (accept graduates; reject archives)",
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
if (input.recluster === true) {
|
|
63
|
+
const r = await runResyncRecluster({ repoRoot: ctx.repoRoot, dryRun: !apply });
|
|
64
|
+
return {
|
|
65
|
+
ok: true,
|
|
66
|
+
mode: "recluster",
|
|
67
|
+
dry_run: r.dryRun,
|
|
68
|
+
applied: r.applied,
|
|
69
|
+
topics_before: r.topicsBefore,
|
|
70
|
+
topics_after: r.topicsAfter,
|
|
71
|
+
block_count: r.blockCount,
|
|
72
|
+
judge_calls: r.judgeCalls,
|
|
73
|
+
judge_calls_fresh: r.judgeFresh,
|
|
74
|
+
judge_calls_cached: r.judgeCached,
|
|
75
|
+
judge_calls_errors: r.judgeErrors,
|
|
76
|
+
archived_maps: r.archivedMaps,
|
|
77
|
+
note: r.dryRun
|
|
78
|
+
? "preview only — re-walked + judged but wrote no map; call again with apply:true (and recluster:true) to overwrite the archived maps"
|
|
79
|
+
: undefined,
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
const result = runResync({
|
|
83
|
+
repoRoot: ctx.repoRoot,
|
|
84
|
+
dryRun: !apply,
|
|
85
|
+
...(input.area !== undefined ? { area: input.area } : {}),
|
|
86
|
+
});
|
|
87
|
+
return {
|
|
88
|
+
ok: true,
|
|
89
|
+
dry_run: result.dryRun,
|
|
90
|
+
applied: result.applied,
|
|
91
|
+
proposals: result.proposals.map((p) => ({
|
|
92
|
+
kind: p.kind,
|
|
93
|
+
workspace: p.workspace,
|
|
94
|
+
value: p.value,
|
|
95
|
+
from: p.from,
|
|
96
|
+
detail: p.detail,
|
|
97
|
+
})),
|
|
98
|
+
skipped: result.skipped,
|
|
99
|
+
archived_config: result.archivedConfig,
|
|
100
|
+
archived_entities: result.archivedEntities,
|
|
101
|
+
note: result.proposals.length === 0
|
|
102
|
+
? "no config drift to resolve — config is in sync with the tree"
|
|
103
|
+
: result.dryRun
|
|
104
|
+
? "preview only — call again with apply:true to write these edits"
|
|
105
|
+
: undefined,
|
|
106
|
+
};
|
|
107
|
+
},
|
|
108
|
+
};
|
|
109
|
+
//# sourceMappingURL=resync.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resync.js","sourceRoot":"","sources":["../../../src/mcp/tools/resync.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,EAAE,QAAQ,EAAE,MAAM,yBAAyB,CAAC;AACnD,OAAO,EAAE,SAAS,EAAE,kBAAkB,EAAE,MAAM,uBAAuB,CAAC;AACtE,OAAO,EAAE,cAAc,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AAEvE,OAAO,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AACzD,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAG5C,MAAM,uBAAuB,GAAG,gBAAgB,CAAC;AASjD,MAAM,CAAC,MAAM,UAAU,GAAmB;IACxC,IAAI,EAAE,cAAc;IACpB,WAAW,EACT,khCAAkhC;IACphC,WAAW,EAAE,WAAW;IACxB,OAAO,EAAE,KAAK,EAAE,GAAe,EAAE,KAAY,EAAoB,EAAE;QACjE,MAAM,KAAK,GAAG,gBAAgB,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;QAC7C,IAAI,KAAK,KAAK,IAAI;YAAE,OAAO,KAAK,CAAC;QACjC,MAAM,KAAK,GAAG,KAAK,CAAC,KAAK,KAAK,IAAI,CAAC;QAEnC,IAAI,KAAK,CAAC,QAAQ,KAAK,MAAM,EAAE,CAAC;YAC9B,MAAM,CAAC,GAAG,MAAM,gBAAgB,CAAC;gBAC/B,QAAQ,EAAE,GAAG,CAAC,QAAQ;gBACtB,GAAG,CAAC,KAAK,CAAC,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;aAC1D,CAAC,CAAC;YACH,OAAO;gBACL,EAAE,EAAE,IAAI;gBACR,IAAI,EAAE,eAAe;gBACrB,IAAI,EAAE,KAAK,CAAC,IAAI,IAAI,IAAI;gBACxB,WAAW,EAAE,QAAQ,CAAC,GAAG,CAAC,QAAQ,EAAE,MAAM,EAAE,SAAS,CAAC;gBACtD,WAAW,EAAE,CAAC,CAAC,WAAW;gBAC1B,WAAW,EAAE,CAAC,CAAC,WAAW;gBAC1B,aAAa,EAAE,CAAC,CAAC,aAAa;gBAC9B,eAAe,EAAE,CAAC,CAAC,eAAe;gBAClC,MAAM,EAAE,CAAC,CAAC,MAAM;gBAChB,IAAI,EACF,CAAC,CAAC,MAAM,KAAK,CAAC;oBACZ,CAAC,CAAC,kEAAkE;oBACpE,CAAC,CAAC,+GAA+G;aACtH,CAAC;QACJ,CAAC;QAED,IAAI,KAAK,CAAC,QAAQ,KAAK,MAAM,EAAE,CAAC;YAC9B,MAAM,CAAC,GAAG,MAAM,cAAc,CAAC;gBAC7B,QAAQ,EAAE,GAAG,CAAC,QAAQ;gBACtB,KAAK,EAAE,IAAI;gBACX,aAAa,EAAE,uBAAuB;aACvC,CAAC,CAAC;YACH,OAAO;gBACL,EAAE,EAAE,IAAI;gBACR,IAAI,EAAE,eAAe;gBACrB,UAAU,EAAE,CAAC,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC,KAAK,EAAE,CAAC,CAAC;gBAClF,UAAU,EAAE,CAAC,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC,KAAK,EAAE,CAAC,CAAC;gBAClF,OAAO,EAAE,CAAC,CAAC,OAAO;gBAClB,YAAY,EAAE,CAAC,CAAC,WAAW;gBAC3B,IAAI,EAAE,mGAAmG;aAC1G,CAAC;QACJ,CAAC;QAED,IAAI,KAAK,CAAC,SAAS,KAAK,IAAI,EAAE,CAAC;YAC7B,MAAM,CAAC,GAAG,MAAM,kBAAkB,CAAC,EAAE,QAAQ,EAAE,GAAG,CAAC,QAAQ,EAAE,MAAM,EAAE,CAAC,KAAK,EAAE,CAAC,CAAC;YAC/E,OAAO;gBACL,EAAE,EAAE,IAAI;gBACR,IAAI,EAAE,WAAW;gBACjB,OAAO,EAAE,CAAC,CAAC,MAAM;gBACjB,OAAO,EAAE,CAAC,CAAC,OAAO;gBAClB,aAAa,EAAE,CAAC,CAAC,YAAY;gBAC7B,YAAY,EAAE,CAAC,CAAC,WAAW;gBAC3B,WAAW,EAAE,CAAC,CAAC,UAAU;gBACzB,WAAW,EAAE,CAAC,CAAC,UAAU;gBACzB,iBAAiB,EAAE,CAAC,CAAC,UAAU;gBAC/B,kBAAkB,EAAE,CAAC,CAAC,WAAW;gBACjC,kBAAkB,EAAE,CAAC,CAAC,WAAW;gBACjC,aAAa,EAAE,CAAC,CAAC,YAAY;gBAC7B,IAAI,EAAE,CAAC,CAAC,MAAM;oBACZ,CAAC,CAAC,oIAAoI;oBACtI,CAAC,CAAC,SAAS;aACd,CAAC;QACJ,CAAC;QAED,MAAM,MAAM,GAAG,SAAS,CAAC;YACvB,QAAQ,EAAE,GAAG,CAAC,QAAQ;YACtB,MAAM,EAAE,CAAC,KAAK;YACd,GAAG,CAAC,KAAK,CAAC,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;SAC1D,CAAC,CAAC;QACH,OAAO;YACL,EAAE,EAAE,IAAI;YACR,OAAO,EAAE,MAAM,CAAC,MAAM;YACtB,OAAO,EAAE,MAAM,CAAC,OAAO;YACvB,SAAS,EAAE,MAAM,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;gBACtC,IAAI,EAAE,CAAC,CAAC,IAAI;gBACZ,SAAS,EAAE,CAAC,CAAC,SAAS;gBACtB,KAAK,EAAE,CAAC,CAAC,KAAK;gBACd,IAAI,EAAE,CAAC,CAAC,IAAI;gBACZ,MAAM,EAAE,CAAC,CAAC,MAAM;aACjB,CAAC,CAAC;YACH,OAAO,EAAE,MAAM,CAAC,OAAO;YACvB,eAAe,EAAE,MAAM,CAAC,cAAc;YACtC,iBAAiB,EAAE,MAAM,CAAC,gBAAgB;YAC1C,IAAI,EACF,MAAM,CAAC,SAAS,CAAC,MAAM,KAAK,CAAC;gBAC3B,CAAC,CAAC,8DAA8D;gBAChE,CAAC,CAAC,MAAM,CAAC,MAAM;oBACb,CAAC,CAAC,gEAAgE;oBAClE,CAAC,CAAC,SAAS;SAClB,CAAC;IACJ,CAAC;CACF,CAAC"}
|
|
@@ -15,12 +15,20 @@
|
|
|
15
15
|
* injected. Operator-written brand is left alone; a demoted file is one
|
|
16
16
|
* frontmatter edit (or a re-run of brand setup) away from `current` again.
|
|
17
17
|
*
|
|
18
|
+
* The 0.26.0 detection only caught the mechanical fallback (fixed marker
|
|
19
|
+
* strings) and the byte-identical overview/positioning pair — it missed
|
|
20
|
+
* Haiku-derived auto-fill (voice.md / personas.yaml), which is worded
|
|
21
|
+
* freshly each run. 0.27.0 adds a co-generation cohort channel: once the
|
|
22
|
+
* overview≡positioning identity proves the pass auto-filled brand, every
|
|
23
|
+
* confirmed doc stamped with the same `generated` timestamp is demoted too.
|
|
24
|
+
*
|
|
18
25
|
* `review`-class: it rewrites committed ground state, so it surfaces for
|
|
19
26
|
* the operator and applies via `cairn migrate` — never silently.
|
|
20
27
|
*
|
|
21
|
-
*
|
|
22
|
-
*
|
|
23
|
-
*
|
|
28
|
+
* The cohort channel ships in 0.27.0, so `introducedIn` advances to 0.27.0:
|
|
29
|
+
* a repo that already ran the 0.26.0 pass (demoting only the pair) must
|
|
30
|
+
* re-evaluate to catch the co-generated siblings. `detect()` carries
|
|
31
|
+
* correctness.
|
|
24
32
|
*/
|
|
25
33
|
import type { Migration } from "../types.js";
|
|
26
34
|
export declare const demoteAutofilledBrand: Migration;
|
|
@@ -15,12 +15,20 @@
|
|
|
15
15
|
* injected. Operator-written brand is left alone; a demoted file is one
|
|
16
16
|
* frontmatter edit (or a re-run of brand setup) away from `current` again.
|
|
17
17
|
*
|
|
18
|
+
* The 0.26.0 detection only caught the mechanical fallback (fixed marker
|
|
19
|
+
* strings) and the byte-identical overview/positioning pair — it missed
|
|
20
|
+
* Haiku-derived auto-fill (voice.md / personas.yaml), which is worded
|
|
21
|
+
* freshly each run. 0.27.0 adds a co-generation cohort channel: once the
|
|
22
|
+
* overview≡positioning identity proves the pass auto-filled brand, every
|
|
23
|
+
* confirmed doc stamped with the same `generated` timestamp is demoted too.
|
|
24
|
+
*
|
|
18
25
|
* `review`-class: it rewrites committed ground state, so it surfaces for
|
|
19
26
|
* the operator and applies via `cairn migrate` — never silently.
|
|
20
27
|
*
|
|
21
|
-
*
|
|
22
|
-
*
|
|
23
|
-
*
|
|
28
|
+
* The cohort channel ships in 0.27.0, so `introducedIn` advances to 0.27.0:
|
|
29
|
+
* a repo that already ran the 0.26.0 pass (demoting only the pair) must
|
|
30
|
+
* re-evaluate to catch the co-generated siblings. `detect()` carries
|
|
31
|
+
* correctness.
|
|
24
32
|
*/
|
|
25
33
|
import { existsSync, readFileSync, writeFileSync } from "node:fs";
|
|
26
34
|
import { cairnDir, parseFrontmatter } from "@isaacriehm/cairn-state";
|
|
@@ -56,7 +64,12 @@ function readDoc(abs) {
|
|
|
56
64
|
const m = raw.match(/^status:\s*(\S+)\s*$/m);
|
|
57
65
|
status = m?.[1] ?? null;
|
|
58
66
|
}
|
|
59
|
-
|
|
67
|
+
let generated = typeof fm["generated"] === "string" ? fm["generated"] : null;
|
|
68
|
+
if (generated === null) {
|
|
69
|
+
const g = raw.match(/^generated:\s*(\S+)\s*$/m);
|
|
70
|
+
generated = g?.[1] ?? null;
|
|
71
|
+
}
|
|
72
|
+
return { status, generated, body: parsed.body, raw };
|
|
60
73
|
}
|
|
61
74
|
const CONFIRMED = new Set(["current", "accepted"]);
|
|
62
75
|
/** Strip headings + collapse whitespace, matching SessionStart's dedup. */
|
|
@@ -68,12 +81,26 @@ function normalize(s) {
|
|
|
68
81
|
}
|
|
69
82
|
/**
|
|
70
83
|
* Repo-relative labels of confirmed brand docs that are provably the
|
|
71
|
-
* pre-0.25.0 auto-fill output:
|
|
72
|
-
*
|
|
73
|
-
* - personas.yaml carrying
|
|
74
|
-
*
|
|
75
|
-
*
|
|
76
|
-
*
|
|
84
|
+
* pre-0.25.0 auto-fill output. Two evidence channels:
|
|
85
|
+
*
|
|
86
|
+
* 1. Per-doc markers — voice.md / personas.yaml carrying a mechanical
|
|
87
|
+
* fallback's distinctive string. Precise but narrow: it ONLY catches
|
|
88
|
+
* the timeout fallback, never the Haiku-derived auto-fill (which is
|
|
89
|
+
* worded freshly each run and so carries no fixed marker).
|
|
90
|
+
*
|
|
91
|
+
* 2. Co-generation cohort — overview.md and positioning.md with
|
|
92
|
+
* byte-identical bodies is near-certain auto-fill proof (a hand-author
|
|
93
|
+
* doesn't write the exact same domain summary into two files). When
|
|
94
|
+
* that fires, every confirmed brand doc stamped with the SAME
|
|
95
|
+
* `generated` timestamp came out of the same automated pass and is
|
|
96
|
+
* demoted too. This is what catches a Haiku-derived voice.md the
|
|
97
|
+
* marker channel misses. The identity check is status-independent —
|
|
98
|
+
* an earlier run may have already demoted the pair to draft, yet its
|
|
99
|
+
* still-confirmed siblings must follow.
|
|
100
|
+
*
|
|
101
|
+
* A demoted file is one frontmatter edit from `current` again, so the
|
|
102
|
+
* asymmetry favors demoting: a false demote costs one keystroke, a false
|
|
103
|
+
* keep burns context every session as machine-written "authoritative" voice.
|
|
77
104
|
*/
|
|
78
105
|
function autofilledConfirmed(repoRoot) {
|
|
79
106
|
const docs = brandDocs(repoRoot);
|
|
@@ -81,10 +108,12 @@ function autofilledConfirmed(repoRoot) {
|
|
|
81
108
|
for (const d of docs)
|
|
82
109
|
byRel.set(d.rel, readDoc(d.abs));
|
|
83
110
|
const hits = new Set();
|
|
111
|
+
const get = (rel) => byRel.get(rel) ?? null;
|
|
84
112
|
const confirmed = (rel) => {
|
|
85
|
-
const p =
|
|
113
|
+
const p = get(rel);
|
|
86
114
|
return p !== null && p.status !== null && CONFIRMED.has(p.status) ? p : null;
|
|
87
115
|
};
|
|
116
|
+
// Channel 1 — per-doc mechanical-fallback markers.
|
|
88
117
|
const voice = confirmed("brand/voice.md");
|
|
89
118
|
if (voice && (voice.body.includes(VOICE_MARKER) || voice.body.includes(AVOID_MARKER))) {
|
|
90
119
|
hits.add("brand/voice.md");
|
|
@@ -93,14 +122,31 @@ function autofilledConfirmed(repoRoot) {
|
|
|
93
122
|
if (personas && personas.raw.includes(PERSONAS_MARKER)) {
|
|
94
123
|
hits.add("product/personas.yaml");
|
|
95
124
|
}
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
125
|
+
// Channel 2 — co-generation cohort, proven by the overview≡positioning
|
|
126
|
+
// identity (checked regardless of either doc's current status).
|
|
127
|
+
const overviewAny = get("brand/overview.md");
|
|
128
|
+
const positioningAny = get("product/positioning.md");
|
|
129
|
+
const pairAutofilled = overviewAny !== null &&
|
|
130
|
+
positioningAny !== null &&
|
|
131
|
+
normalize(overviewAny.body).length > 0 &&
|
|
132
|
+
normalize(overviewAny.body) === normalize(positioningAny.body);
|
|
133
|
+
if (pairAutofilled) {
|
|
134
|
+
// Cohort timestamp — the pass stamps every co-generated doc identically.
|
|
135
|
+
const cohortGen = overviewAny.generated ?? positioningAny.generated;
|
|
136
|
+
// overview/positioning are themselves cohort members; demote if still confirmed.
|
|
137
|
+
if (confirmed("brand/overview.md"))
|
|
138
|
+
hits.add("brand/overview.md");
|
|
139
|
+
if (confirmed("product/positioning.md"))
|
|
140
|
+
hits.add("product/positioning.md");
|
|
141
|
+
// A confirmed voice.md sharing the cohort timestamp is the same pass's
|
|
142
|
+
// output — the timestamp guard spares a voice the operator hand-wrote later.
|
|
143
|
+
if (voice && cohortGen !== null && voice.generated === cohortGen) {
|
|
144
|
+
hits.add("brand/voice.md");
|
|
145
|
+
}
|
|
146
|
+
// personas.yaml carries no `generated`; it's the lowest-value, most
|
|
147
|
+
// placeholder-prone doc, so the pair-proof alone demotes a confirmed one.
|
|
148
|
+
if (personas)
|
|
149
|
+
hits.add("product/personas.yaml");
|
|
104
150
|
}
|
|
105
151
|
return [...hits];
|
|
106
152
|
}
|
|
@@ -126,8 +172,8 @@ function demoteToDraft(abs) {
|
|
|
126
172
|
}
|
|
127
173
|
export const demoteAutofilledBrand = {
|
|
128
174
|
id: "0005-demote-autofilled-brand",
|
|
129
|
-
introducedIn: "0.
|
|
130
|
-
describe: "Demote auto-generated brand
|
|
175
|
+
introducedIn: "0.27.0",
|
|
176
|
+
describe: "Demote auto-generated brand (marked confirmed before 0.25.0) back to status: draft so machine-written voice/positioning/personas stops being injected every session — now catches the full co-generated cohort, not just the mechanical fallback",
|
|
131
177
|
class: "review",
|
|
132
178
|
detect(repoRoot) {
|
|
133
179
|
return autofilledConfirmed(repoRoot).length > 0;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"0005-demote-autofilled-brand.js","sourceRoot":"","sources":["../../../src/migrate/migrations/0005-demote-autofilled-brand.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"0005-demote-autofilled-brand.js","sourceRoot":"","sources":["../../../src/migrate/migrations/0005-demote-autofilled-brand.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,25 +1,27 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* 0006 — prune junk Layer-A (sot-align) invariants from existing repos.
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
4
|
+
* The sot-align hook minted an "invariant" from almost any prose block —
|
|
5
|
+
* banners, separators, class/endpoint descriptions, test notes. The 0.23.0
|
|
6
|
+
* creation gate cut the worst of it, but a modal buried anywhere in a
|
|
7
|
+
* multi-line block still slipped through, so even post-gate repos accreted
|
|
8
|
+
* box-drawing-titled artifacts and test-fixture comments as "active
|
|
9
|
+
* invariants". 0.27.0 sharpens both the gate (skip test files) and this
|
|
10
|
+
* prune (statement-scoped shape + test-source + separator-title rejects).
|
|
11
11
|
*
|
|
12
12
|
* `detect`/`apply` wrap the same `pruneInvariants` surgical core the CLI
|
|
13
|
-
* uses: it touches ONLY `capture_source: layer-a-sot-align` invariants
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
* (recoverable), rebuilding the ledger once at
|
|
17
|
-
* are never touched.
|
|
13
|
+
* uses: it touches ONLY `capture_source: layer-a-sot-align` invariants —
|
|
14
|
+
* archiving those captured from a test/fixture file, titled with a
|
|
15
|
+
* separator, or with no constraint shape in their statement — to
|
|
16
|
+
* `.cairn/ground/.archive/` (recoverable), rebuilding the ledger once at
|
|
17
|
+
* the end. Curated DEC/INV are never touched. For a full reset of the
|
|
18
|
+
* legacy corpus the operator can run `cairn invariants prune --all`.
|
|
18
19
|
*
|
|
19
20
|
* `review`-class: it archives committed ground state, so it surfaces for
|
|
20
|
-
* the operator and applies via `cairn migrate`.
|
|
21
|
-
* `introducedIn`
|
|
22
|
-
* re-evaluate
|
|
21
|
+
* the operator and applies via `cairn migrate`. The sharpened gate ships
|
|
22
|
+
* in 0.27.0, so `introducedIn` advances to 0.27.0 — a repo that already
|
|
23
|
+
* ran the weaker 0.26.0 pass must re-evaluate; `detect()` carries
|
|
24
|
+
* correctness.
|
|
23
25
|
*/
|
|
24
26
|
import type { Migration } from "../types.js";
|
|
25
27
|
export declare const pruneSotAlignInvariants: Migration;
|
|
@@ -1,31 +1,37 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* 0006 — prune junk Layer-A (sot-align) invariants from existing repos.
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
4
|
+
* The sot-align hook minted an "invariant" from almost any prose block —
|
|
5
|
+
* banners, separators, class/endpoint descriptions, test notes. The 0.23.0
|
|
6
|
+
* creation gate cut the worst of it, but a modal buried anywhere in a
|
|
7
|
+
* multi-line block still slipped through, so even post-gate repos accreted
|
|
8
|
+
* box-drawing-titled artifacts and test-fixture comments as "active
|
|
9
|
+
* invariants". 0.27.0 sharpens both the gate (skip test files) and this
|
|
10
|
+
* prune (statement-scoped shape + test-source + separator-title rejects).
|
|
11
11
|
*
|
|
12
12
|
* `detect`/`apply` wrap the same `pruneInvariants` surgical core the CLI
|
|
13
|
-
* uses: it touches ONLY `capture_source: layer-a-sot-align` invariants
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
* (recoverable), rebuilding the ledger once at
|
|
17
|
-
* are never touched.
|
|
13
|
+
* uses: it touches ONLY `capture_source: layer-a-sot-align` invariants —
|
|
14
|
+
* archiving those captured from a test/fixture file, titled with a
|
|
15
|
+
* separator, or with no constraint shape in their statement — to
|
|
16
|
+
* `.cairn/ground/.archive/` (recoverable), rebuilding the ledger once at
|
|
17
|
+
* the end. Curated DEC/INV are never touched. For a full reset of the
|
|
18
|
+
* legacy corpus the operator can run `cairn invariants prune --all`.
|
|
18
19
|
*
|
|
19
20
|
* `review`-class: it archives committed ground state, so it surfaces for
|
|
20
|
-
* the operator and applies via `cairn migrate`.
|
|
21
|
-
* `introducedIn`
|
|
22
|
-
* re-evaluate
|
|
21
|
+
* the operator and applies via `cairn migrate`. The sharpened gate ships
|
|
22
|
+
* in 0.27.0, so `introducedIn` advances to 0.27.0 — a repo that already
|
|
23
|
+
* ran the weaker 0.26.0 pass must re-evaluate; `detect()` carries
|
|
24
|
+
* correctness.
|
|
23
25
|
*/
|
|
24
26
|
import { pruneInvariants } from "../../invariants/prune.js";
|
|
25
27
|
export const pruneSotAlignInvariants = {
|
|
26
28
|
id: "0006-prune-sot-align-invariants",
|
|
27
|
-
|
|
28
|
-
|
|
29
|
+
// 0.27.0: the surgical gate was sharpened (statement-scoped shape +
|
|
30
|
+
// test-source + separator-title rejects). A repo that already ran the
|
|
31
|
+
// weaker 0.26.0 pass must re-evaluate, so `introducedIn` advances to the
|
|
32
|
+
// ship version — `detect()` (a dry-run prune) stays the correctness floor.
|
|
33
|
+
introducedIn: "0.27.0",
|
|
34
|
+
describe: "Archive junk Layer-A (sot-align) invariants the creation gate would reject today — test/fixture captures, separator-titled artifacts, and entries with no rule in their statement; curated DEC/INV untouched",
|
|
29
35
|
class: "review",
|
|
30
36
|
detect(repoRoot) {
|
|
31
37
|
try {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"0006-prune-sot-align-invariants.js","sourceRoot":"","sources":["../../../src/migrate/migrations/0006-prune-sot-align-invariants.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"0006-prune-sot-align-invariants.js","sourceRoot":"","sources":["../../../src/migrate/migrations/0006-prune-sot-align-invariants.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AAEH,OAAO,EAAE,eAAe,EAAE,MAAM,2BAA2B,CAAC;AAG5D,MAAM,CAAC,MAAM,uBAAuB,GAAc;IAChD,EAAE,EAAE,iCAAiC;IACrC,oEAAoE;IACpE,sEAAsE;IACtE,yEAAyE;IACzE,2EAA2E;IAC3E,YAAY,EAAE,QAAQ;IACtB,QAAQ,EACN,8MAA8M;IAChN,KAAK,EAAE,QAAQ;IACf,MAAM,CAAC,QAAgB;QACrB,IAAI,CAAC;YACH,OAAO,eAAe,CAAC,EAAE,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC;QACvE,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,KAAK,CAAC;QACf,CAAC;IACH,CAAC;IACD,KAAK,CAAC,QAAgB;QACpB,MAAM,MAAM,GAAG,eAAe,CAAC,EAAE,QAAQ,EAAE,CAAC,CAAC;QAC7C,MAAM,CAAC,GAAG,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC;QAC/B,OAAO;YACL,OAAO,EAAE,CAAC,GAAG,CAAC;YACd,MAAM,EACJ,CAAC,GAAG,CAAC;gBACH,CAAC,CAAC,YAAY,CAAC,wCAAwC,MAAM,CAAC,aAAa,cAAc,MAAM,CAAC,IAAI,kCAAkC;gBACtI,CAAC,CAAC,oCAAoC;SAC3C,CAAC;IACJ,CAAC;CACF,CAAC"}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 0008 — clean leaked adoption scaffolding from a project's committed `.cairn/`.
|
|
3
|
+
*
|
|
4
|
+
* The shipped templates leaked Cairn-internal strings into every adopter's
|
|
5
|
+
* committed files that the seed never scrubbed:
|
|
6
|
+
* - workflow.md : a "Project-extension placeholder" meta-comment describing
|
|
7
|
+
* the template's OWN substitution (false the moment init
|
|
8
|
+
* ran) + a dangling `docs/SYSTEM_OVERVIEW.md` pointer (a
|
|
9
|
+
* Cairn-internal doc that never ships to adopters).
|
|
10
|
+
* - sensors.yaml : the "honest-agent invariants stack" framing — internal
|
|
11
|
+
* jargon that means nothing in an adopter's repo.
|
|
12
|
+
* - .gitignore : `PLUGIN_ARCHITECTURE §7/§17`, `docs/FILESYSTEM_LAYOUT.md`,
|
|
13
|
+
* `spec §2.2` — references to Cairn-internal docs that
|
|
14
|
+
* dangle in the adopter's tree.
|
|
15
|
+
* - git-hooks : `Spec: PLUGIN_ARCHITECTURE §17 Layer 1` refs in the
|
|
16
|
+
* commit-msg + post-commit hooks.
|
|
17
|
+
* - personas.yaml: a `DOCS_SPEC.md §3.4` shape ref written by an older
|
|
18
|
+
* brand-setup path (the template itself is clean).
|
|
19
|
+
*
|
|
20
|
+
* Plus synthetic, template-author timestamps in workflow.md + the brand /
|
|
21
|
+
* product files (`2026-05-02T…`, `2026-05-04T…`). A fake `verified-at` is one
|
|
22
|
+
* the freshness system can't trust, so we replace each synthetic stamp with
|
|
23
|
+
* the file's real git first-commit author-date — the true adoption time,
|
|
24
|
+
* identical on every clone. If git can't resolve it (untracked / ghost) the
|
|
25
|
+
* stamp is LEFT rather than fabricated (no clock value → no per-clone churn).
|
|
26
|
+
*
|
|
27
|
+
* The templates now ship clean; this converges existing repos to them.
|
|
28
|
+
*
|
|
29
|
+
* `safe` (not `review`): deterministic, zero-semantic cosmetic edits. The
|
|
30
|
+
* comment scrubs carry none of the matched anchor text (idempotent), and the
|
|
31
|
+
* timestamp swap is content-derived — whoever runs it first commits the
|
|
32
|
+
* canonical clean file and every other clone's `detect()` short-circuits, so
|
|
33
|
+
* there is no churn. Auto-applies on session open (cf. 0001/0004).
|
|
34
|
+
*
|
|
35
|
+
* Ships in 0.27.0 → `introducedIn` 0.27.0; every prior adopter re-evaluates on
|
|
36
|
+
* upgrade. `detect()` carries correctness.
|
|
37
|
+
*/
|
|
38
|
+
import type { Migration } from "../types.js";
|
|
39
|
+
export declare const cleanAdoptionScaffolding: Migration;
|