@cleocode/core 2026.10.10-canary.1 → 2026.10.10-canary.2

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 (52) hide show
  1. package/dist/build-provenance.json +2 -2
  2. package/dist/decide/sites/registry.d.ts +26 -0
  3. package/dist/decide/sites/registry.d.ts.map +1 -1
  4. package/dist/decide/sites/registry.js +25 -0
  5. package/dist/decide/sites/registry.js.map +1 -1
  6. package/dist/docs/doctor.d.ts +15 -5
  7. package/dist/docs/doctor.d.ts.map +1 -1
  8. package/dist/docs/doctor.js +182 -83
  9. package/dist/docs/doctor.js.map +1 -1
  10. package/dist/docs/triage.d.ts +211 -0
  11. package/dist/docs/triage.d.ts.map +1 -0
  12. package/dist/docs/triage.js +473 -0
  13. package/dist/docs/triage.js.map +1 -0
  14. package/dist/store/blob-keep.d.ts +15 -0
  15. package/dist/store/blob-keep.d.ts.map +1 -1
  16. package/dist/store/blob-keep.js +20 -0
  17. package/dist/store/blob-keep.js.map +1 -1
  18. package/dist/store/conduit-doc-history.d.ts +265 -0
  19. package/dist/store/conduit-doc-history.d.ts.map +1 -0
  20. package/dist/store/conduit-doc-history.js +468 -0
  21. package/dist/store/conduit-doc-history.js.map +1 -0
  22. package/dist/store/row-identity-registry.d.ts +6 -4
  23. package/dist/store/row-identity-registry.d.ts.map +1 -1
  24. package/dist/store/row-identity-registry.js +59 -10
  25. package/dist/store/row-identity-registry.js.map +1 -1
  26. package/dist/store/schema/cleo-project/conduit.d.ts +554 -7
  27. package/dist/store/schema/cleo-project/conduit.d.ts.map +1 -1
  28. package/dist/store/schema/cleo-project/conduit.js +223 -30
  29. package/dist/store/schema/cleo-project/conduit.js.map +1 -1
  30. package/dist/store/schema/conduit-schema.d.ts +211 -3
  31. package/dist/store/schema/conduit-schema.d.ts.map +1 -1
  32. package/dist/store/schema/conduit-schema.js +53 -14
  33. package/dist/store/schema/conduit-schema.js.map +1 -1
  34. package/dist/store/sync/apply/parent-delete.d.ts.map +1 -1
  35. package/dist/store/sync/apply/parent-delete.js +6 -0
  36. package/dist/store/sync/apply/parent-delete.js.map +1 -1
  37. package/dist/store/sync/timestamp-canon.d.ts.map +1 -1
  38. package/dist/store/sync/timestamp-canon.js +7 -0
  39. package/dist/store/sync/timestamp-canon.js.map +1 -1
  40. package/dist/store/table-classification.d.ts.map +1 -1
  41. package/dist/store/table-classification.js +31 -13
  42. package/dist/store/table-classification.js.map +1 -1
  43. package/dist/tasks/test-run-binding.d.ts +4 -1
  44. package/dist/tasks/test-run-binding.d.ts.map +1 -1
  45. package/dist/tasks/test-run-binding.js +38 -2
  46. package/dist/tasks/test-run-binding.js.map +1 -1
  47. package/migrations/drizzle-cleo-project/20261011000000_t13354-conduit-history-rekey/migration.sql +274 -0
  48. package/package.json +13 -13
  49. package/schemas/project-info.schema.json +2 -2
  50. package/templates/git-hooks/commit-msg +2 -0
  51. package/templates/git-hooks/legacy-hashes.json +1 -0
  52. package/templates/git-hooks/pre-push +3 -0
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "schema": 1,
3
- "gitHead": "e90d32b6df31275bb6f53f661d3161742d94177b",
4
- "builtAt": "2026-10-12T04:29:01.057Z",
3
+ "gitHead": "007ff2ef022d32aa632532fd8447c6703ccb0777",
4
+ "builtAt": "2026-10-12T09:30:27.030Z",
5
5
  "linkedWorktree": null
6
6
  }
@@ -137,6 +137,32 @@ export declare const DECIDE_BENCH_DECISION_SITE: {
137
137
  readonly task: "T12495";
138
138
  readonly note: "Benchmark verb: replays the duplicate, observation-type and contradiction questions; answers are scored, never acted on.";
139
139
  };
140
+ /**
141
+ * `docs.triage` — batch keep/update/supersede/archive verdicts over draft docs
142
+ * (T13446). Proposals only: the site never mutates a doc; `--record` persists
143
+ * each verdict as a `proposed` D#### decision for owner review.
144
+ */
145
+ export declare const DOC_TRIAGE_DECISION_SITE: {
146
+ readonly id: "docs.triage";
147
+ readonly title: "CleoDocs draft triage (keep/update/supersede/archive)";
148
+ readonly files: readonly ["packages/core/src/docs/triage.ts"];
149
+ readonly questionType: "choice";
150
+ readonly primaryRung: "system-one";
151
+ readonly ladder: readonly ["generative"];
152
+ readonly fallback: "rule";
153
+ readonly floors: {
154
+ readonly '*': 0.6;
155
+ };
156
+ readonly ownerEscalation: "below-floor";
157
+ readonly modeKey: "decide.sites.docTriage";
158
+ readonly generativeKey: "decide.generativeFallback.docTriage";
159
+ readonly defaultMode: "shadow";
160
+ readonly llmSystemKey: "consolidation";
161
+ readonly writePath: false;
162
+ readonly sends: readonly ["memory-text"];
163
+ readonly task: "T13446";
164
+ readonly note: "Batch job over `cleo docs triage`; rule fallback is age/topics/link heuristics. Shadow until go-live evidence exists.";
165
+ };
140
166
  /**
141
167
  * Every registered decision site. The System One sites come first, then the
142
168
  * generative and agent-rung sites.
@@ -1 +1 @@
1
- {"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../../../src/decide/sites/registry.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,qBAAqB,CAAC;AAElE,uFAAuF;AACvF,eAAO,MAAM,wBAAwB;;;;;;;;;;;;;;;;;;;;CAkBM,CAAC;AAE5C,8FAA8F;AAC9F,eAAO,MAAM,oCAAoC;;;;;;;;;;;;;;;;;;;CAoBN,CAAC;AAE5C,yEAAyE;AACzE,eAAO,MAAM,8BAA8B;;;;;;;;;;;;;;;;;;CAgBA,CAAC;AAE5C,uFAAuF;AACvF,eAAO,MAAM,4BAA4B;;;;;;;;;;;;;;;;;;CAmBE,CAAC;AAE5C,wEAAwE;AACxE,eAAO,MAAM,wBAAwB;;;;;;;;;;;;;;CAcM,CAAC;AAE5C;;;;;;GAMG;AACH,eAAO,MAAM,0BAA0B;;;;;;;;;;;;;;CAcI,CAAC;AAkP5C;;;GAGG;AACH,eAAO,MAAM,cAAc,EAAE,SAAS,sBAAsB,EAQ3D,CAAC;AAEF;;;;;GAKG;AACH,wBAAgB,eAAe,CAAC,EAAE,EAAE,MAAM,GAAG,sBAAsB,GAAG,SAAS,CAE9E"}
1
+ {"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../../../src/decide/sites/registry.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,qBAAqB,CAAC;AAElE,uFAAuF;AACvF,eAAO,MAAM,wBAAwB;;;;;;;;;;;;;;;;;;;;CAkBM,CAAC;AAE5C,8FAA8F;AAC9F,eAAO,MAAM,oCAAoC;;;;;;;;;;;;;;;;;;;CAoBN,CAAC;AAE5C,yEAAyE;AACzE,eAAO,MAAM,8BAA8B;;;;;;;;;;;;;;;;;;CAgBA,CAAC;AAE5C,uFAAuF;AACvF,eAAO,MAAM,4BAA4B;;;;;;;;;;;;;;;;;;CAmBE,CAAC;AAE5C,wEAAwE;AACxE,eAAO,MAAM,wBAAwB;;;;;;;;;;;;;;CAcM,CAAC;AAE5C;;;;;;GAMG;AACH,eAAO,MAAM,0BAA0B;;;;;;;;;;;;;;CAcI,CAAC;AAE5C;;;;GAIG;AACH,eAAO,MAAM,wBAAwB;;;;;;;;;;;;;;;;;;;;CAkBM,CAAC;AAkP5C;;;GAGG;AACH,eAAO,MAAM,cAAc,EAAE,SAAS,sBAAsB,EAS3D,CAAC;AAEF;;;;;GAKG;AACH,wBAAgB,eAAe,CAAC,EAAE,EAAE,MAAM,GAAG,sBAAsB,GAAG,SAAS,CAE9E"}
@@ -134,6 +134,30 @@ export const DECIDE_BENCH_DECISION_SITE = {
134
134
  task: 'T12495',
135
135
  note: 'Benchmark verb: replays the duplicate, observation-type and contradiction questions; answers are scored, never acted on.',
136
136
  };
137
+ /**
138
+ * `docs.triage` — batch keep/update/supersede/archive verdicts over draft docs
139
+ * (T13446). Proposals only: the site never mutates a doc; `--record` persists
140
+ * each verdict as a `proposed` D#### decision for owner review.
141
+ */
142
+ export const DOC_TRIAGE_DECISION_SITE = {
143
+ id: 'docs.triage',
144
+ title: 'CleoDocs draft triage (keep/update/supersede/archive)',
145
+ files: ['packages/core/src/docs/triage.ts'],
146
+ questionType: 'choice',
147
+ primaryRung: 'system-one',
148
+ ladder: ['generative'],
149
+ fallback: 'rule',
150
+ floors: { '*': 0.6 },
151
+ ownerEscalation: 'below-floor',
152
+ modeKey: 'decide.sites.docTriage',
153
+ generativeKey: 'decide.generativeFallback.docTriage',
154
+ defaultMode: 'shadow',
155
+ llmSystemKey: 'consolidation',
156
+ writePath: false,
157
+ sends: ['memory-text'],
158
+ task: 'T13446',
159
+ note: 'Batch job over `cleo docs triage`; rule fallback is age/topics/link heuristics. Shadow until go-live evidence exists.',
160
+ };
137
161
  /**
138
162
  * Generative and agent-rung sites that predate the ladder: registered so every
139
163
  * model call site is listed (spec §3.3). All `on`; none uses System One.
@@ -384,6 +408,7 @@ export const DECISION_SITES = [
384
408
  OWNER_DECISION_DECISION_SITE,
385
409
  DECIDE_ASK_DECISION_SITE,
386
410
  DECIDE_BENCH_DECISION_SITE,
411
+ DOC_TRIAGE_DECISION_SITE,
387
412
  ...GENERATIVE_SITES,
388
413
  ];
389
414
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"registry.js","sourceRoot":"","sources":["../../../src/decide/sites/registry.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"registry.js","sourceRoot":"","sources":["../../../src/decide/sites/registry.ts"],"names":[],"mappings":"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"}
@@ -6,11 +6,18 @@
6
6
  * invoked with `apply: true`, performs the repairs that are safe to run
7
7
  * in-place:
8
8
  *
9
- * - `dangling-pointers` — `local-file` rows whose path is gone from disk
10
- * or lives inside a worktree/tmp directory. Repair
11
- * archives the row (`lifecycle_status = 'archived'`)
12
- * when the file is gone; existing files are left
13
- * alone (content capture is T13360's scope).
9
+ * - `dangling-pointers` — rows whose recorded local `path` is gone from
10
+ * disk or lives inside a worktree/tmp directory.
11
+ * Rows already `lifecycle_status = 'archived'`
12
+ * are excluded (T13562). Repair for a missing
13
+ * `local-file` target archives the row; a
14
+ * `blob`-kind payload carrying a stale legacy
15
+ * `path` whose content still resolves in the
16
+ * content-addressed blob store is re-pointed
17
+ * instead — the stale `path` field is cleared
18
+ * (`clear-stale-path`, T13562) since the bytes
19
+ * are alive. Existing files are left alone
20
+ * (content capture is T13360's scope).
14
21
  * - `doc-version-skew` — slugged rows whose `docVersion` trails the
15
22
  * revision count in `.cleo/audit/docs-versioning.jsonl`
16
23
  * (the T13351 bug left historical rows at 1). Repair
@@ -173,6 +180,9 @@ export type RunDocsDoctorResult = {
173
180
  * Apply: the backup gate runs first, then repairs execute in dependency
174
181
  * order (doc-version-skew, empty-provenance, dangling-pointers, and finally
175
182
  * the wikilinks rebuild, which re-derives from the freshly repaired columns).
183
+ * On apply the report's diagnostics are re-scanned AFTER the repairs so the
184
+ * envelope reflects POST-repair state and the summary counts match it
185
+ * (T13560); a dry run reports the pre-repair state unchanged.
176
186
  *
177
187
  * @param projectRoot - Absolute path to the CLEO project root.
178
188
  * @param opts - Apply flag, stale-draft threshold, backup receipt.
@@ -1 +1 @@
1
- {"version":3,"file":"doctor.d.ts","sourceRoot":"","sources":["../../src/docs/doctor.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2CG;AAeH;;;;;;;GAOG;AACH,eAAO,MAAM,6BAA6B,QAAiB,CAAC;AAE5D;;;;GAIG;AACH,eAAO,MAAM,mCAAmC,KAAK,CAAC;AAEtD;;;;;GAKG;AACH,eAAO,MAAM,4BAA4B,KAAK,CAAC;AAE/C;;;;GAIG;AACH,MAAM,MAAM,wBAAwB,GAChC,mBAAmB,GACnB,kBAAkB,GAClB,kBAAkB,GAClB,iBAAiB,GACjB,sBAAsB,GACtB,cAAc,CAAC;AAEnB;;;;;GAKG;AACH,MAAM,WAAW,oBAAoB;IACnC,uCAAuC;IACvC,QAAQ,CAAC,IAAI,EAAE,wBAAwB,CAAC;IACxC,2EAA2E;IAC3E,QAAQ,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC;IAC7C,yDAAyD;IACzD,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,yEAAyE;IACzE,QAAQ,CAAC,KAAK,EAAE,aAAa,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;IACvD,iDAAiD;IACjD,QAAQ,CAAC,SAAS,EAAE,OAAO,CAAC;CAC7B;AAED;;;;GAIG;AACH,MAAM,WAAW,sBAAsB;IACrC,8CAA8C;IAC9C,QAAQ,CAAC,IAAI,EAAE,wBAAwB,CAAC;IACxC,6DAA6D;IAC7D,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,8DAA8D;IAC9D,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;IAC1B,oDAAoD;IACpD,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IACvB,yDAAyD;IACzD,QAAQ,CAAC,YAAY,CAAC,EAAE,MAAM,CAAC;IAC/B,iEAAiE;IACjE,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;CACzB;AAED;;;;GAIG;AACH,MAAM,WAAW,gBAAgB;IAC/B,8DAA8D;IAC9D,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;IAC1B,uDAAuD;IACvD,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;IAC/B,kEAAkE;IAClE,QAAQ,CAAC,iBAAiB,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1C,iDAAiD;IACjD,QAAQ,CAAC,WAAW,EAAE,SAAS,oBAAoB,EAAE,CAAC;IACtD,yDAAyD;IACzD,QAAQ,CAAC,OAAO,EAAE,SAAS,sBAAsB,EAAE,CAAC;IACpD,8BAA8B;IAC9B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;CAC1B;AAED;;;;GAIG;AACH,MAAM,WAAW,iBAAiB;IAChC;;;OAGG;IACH,QAAQ,CAAC,KAAK,CAAC,EAAE,OAAO,CAAC;IACzB,0EAA0E;IAC1E,QAAQ,CAAC,aAAa,CAAC,EAAE,MAAM,CAAC;IAChC;;;;OAIG;IACH,QAAQ,CAAC,iBAAiB,CAAC,EAAE,MAAM,CAAC;CACrC;AAED;;;;;;;;GAQG;AACH,MAAM,MAAM,mBAAmB,GAC3B;IAAE,QAAQ,CAAC,EAAE,EAAE,IAAI,CAAC;IAAC,QAAQ,CAAC,MAAM,EAAE,gBAAgB,CAAA;CAAE,GACxD;IAAE,QAAQ,CAAC,EAAE,EAAE,KAAK,CAAC;IAAC,QAAQ,CAAC,KAAK,EAAE;QAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAA;CAAE,CAAC;AAsMhG;;;;;;;;;;;;;GAaG;AAEH,wBAAsB,aAAa,CACjC,WAAW,EAAE,MAAM,EACnB,IAAI,GAAE,iBAAsB,GAC3B,OAAO,CAAC,mBAAmB,CAAC,CA+R9B"}
1
+ {"version":3,"file":"doctor.d.ts","sourceRoot":"","sources":["../../src/docs/doctor.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkDG;AAsBH;;;;;;;GAOG;AACH,eAAO,MAAM,6BAA6B,QAAiB,CAAC;AAE5D;;;;GAIG;AACH,eAAO,MAAM,mCAAmC,KAAK,CAAC;AAEtD;;;;;GAKG;AACH,eAAO,MAAM,4BAA4B,KAAK,CAAC;AAE/C;;;;GAIG;AACH,MAAM,MAAM,wBAAwB,GAChC,mBAAmB,GACnB,kBAAkB,GAClB,kBAAkB,GAClB,iBAAiB,GACjB,sBAAsB,GACtB,cAAc,CAAC;AAEnB;;;;;GAKG;AACH,MAAM,WAAW,oBAAoB;IACnC,uCAAuC;IACvC,QAAQ,CAAC,IAAI,EAAE,wBAAwB,CAAC;IACxC,2EAA2E;IAC3E,QAAQ,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC;IAC7C,yDAAyD;IACzD,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,yEAAyE;IACzE,QAAQ,CAAC,KAAK,EAAE,aAAa,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;IACvD,iDAAiD;IACjD,QAAQ,CAAC,SAAS,EAAE,OAAO,CAAC;CAC7B;AAED;;;;GAIG;AACH,MAAM,WAAW,sBAAsB;IACrC,8CAA8C;IAC9C,QAAQ,CAAC,IAAI,EAAE,wBAAwB,CAAC;IACxC,6DAA6D;IAC7D,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,8DAA8D;IAC9D,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;IAC1B,oDAAoD;IACpD,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IACvB,yDAAyD;IACzD,QAAQ,CAAC,YAAY,CAAC,EAAE,MAAM,CAAC;IAC/B,iEAAiE;IACjE,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;CACzB;AAED;;;;GAIG;AACH,MAAM,WAAW,gBAAgB;IAC/B,8DAA8D;IAC9D,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;IAC1B,uDAAuD;IACvD,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;IAC/B,kEAAkE;IAClE,QAAQ,CAAC,iBAAiB,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1C,iDAAiD;IACjD,QAAQ,CAAC,WAAW,EAAE,SAAS,oBAAoB,EAAE,CAAC;IACtD,yDAAyD;IACzD,QAAQ,CAAC,OAAO,EAAE,SAAS,sBAAsB,EAAE,CAAC;IACpD,8BAA8B;IAC9B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;CAC1B;AAED;;;;GAIG;AACH,MAAM,WAAW,iBAAiB;IAChC;;;OAGG;IACH,QAAQ,CAAC,KAAK,CAAC,EAAE,OAAO,CAAC;IACzB,0EAA0E;IAC1E,QAAQ,CAAC,aAAa,CAAC,EAAE,MAAM,CAAC;IAChC;;;;OAIG;IACH,QAAQ,CAAC,iBAAiB,CAAC,EAAE,MAAM,CAAC;CACrC;AAED;;;;;;;;GAQG;AACH,MAAM,MAAM,mBAAmB,GAC3B;IAAE,QAAQ,CAAC,EAAE,EAAE,IAAI,CAAC;IAAC,QAAQ,CAAC,MAAM,EAAE,gBAAgB,CAAA;CAAE,GACxD;IAAE,QAAQ,CAAC,EAAE,EAAE,KAAK,CAAC;IAAC,QAAQ,CAAC,KAAK,EAAE;QAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAA;CAAE,CAAC;AAofhG;;;;;;;;;;;;;;;;GAgBG;AAEH,wBAAsB,aAAa,CACjC,WAAW,EAAE,MAAM,EACnB,IAAI,GAAE,iBAAsB,GAC3B,OAAO,CAAC,mBAAmB,CAAC,CAoI9B"}
@@ -6,11 +6,18 @@
6
6
  * invoked with `apply: true`, performs the repairs that are safe to run
7
7
  * in-place:
8
8
  *
9
- * - `dangling-pointers` — `local-file` rows whose path is gone from disk
10
- * or lives inside a worktree/tmp directory. Repair
11
- * archives the row (`lifecycle_status = 'archived'`)
12
- * when the file is gone; existing files are left
13
- * alone (content capture is T13360's scope).
9
+ * - `dangling-pointers` — rows whose recorded local `path` is gone from
10
+ * disk or lives inside a worktree/tmp directory.
11
+ * Rows already `lifecycle_status = 'archived'`
12
+ * are excluded (T13562). Repair for a missing
13
+ * `local-file` target archives the row; a
14
+ * `blob`-kind payload carrying a stale legacy
15
+ * `path` whose content still resolves in the
16
+ * content-addressed blob store is re-pointed
17
+ * instead — the stale `path` field is cleared
18
+ * (`clear-stale-path`, T13562) since the bytes
19
+ * are alive. Existing files are left alone
20
+ * (content capture is T13360's scope).
14
21
  * - `doc-version-skew` — slugged rows whose `docVersion` trails the
15
22
  * revision count in `.cleo/audit/docs-versioning.jsonl`
16
23
  * (the T13351 bug left historical rows at 1). Repair
@@ -47,11 +54,13 @@ import { tmpdir } from 'node:os';
47
54
  import { isAbsolute, join, resolve, sep } from 'node:path';
48
55
  import { getCleoWorktreesRoot } from '@cleocode/paths';
49
56
  import { eq } from 'drizzle-orm';
57
+ import { resolveCleoDir } from '../paths.js';
50
58
  import { createAttachmentStore } from '../store/attachment-store.js';
59
+ import { blobContentExists } from '../store/blob-keep.js';
51
60
  import { docsWikilinks } from '../store/schema/attachments.js';
52
61
  import { getDb } from '../store/sqlite.js';
53
62
  import { docsAttachments } from '../store/tasks-schema.js';
54
- import { deriveDocLinks, isScannableTextMime, linksJsonOrNull } from './derive-links.js';
63
+ import { deriveDocLinks, isScannableTextMime, linksJsonOrNull, } from './derive-links.js';
55
64
  import { DOCS_VERSIONING_AUDIT_FILE } from './docs-update.js';
56
65
  import { deriveWikilinkEdges, rebuildDocsWikilinks } from './wikilinks.js';
57
66
  /**
@@ -112,6 +121,30 @@ function asLocalFile(payload) {
112
121
  : {}),
113
122
  };
114
123
  }
124
+ /**
125
+ * Narrow a parsed payload to the legacy `blob`-with-`path` shape. The current
126
+ * contract never writes `path` on a blob payload, so any hit is legacy data.
127
+ * @internal
128
+ */
129
+ function asBlobWithPath(payload) {
130
+ if (payload['kind'] !== 'blob')
131
+ return null;
132
+ const path = payload['path'];
133
+ if (typeof path !== 'string' || path.length === 0)
134
+ return null;
135
+ return { kind: 'blob', path };
136
+ }
137
+ /**
138
+ * True when the row's content is retrievable from the content-addressed blob
139
+ * store right now (primary file or a live keep-link). Read-only — safe in a
140
+ * dry-run planning pass.
141
+ * @internal
142
+ */
143
+ function blobRowContentAlive(row, payload, projectRoot) {
144
+ const mimeRaw = payload['mime'];
145
+ const mime = typeof mimeRaw === 'string' ? mimeRaw : 'application/octet-stream';
146
+ return blobContentExists(resolveCleoDir(projectRoot), row.sha256, mime);
147
+ }
115
148
  /**
116
149
  * True when `absPath` points inside a worktree or temp directory:
117
150
  * the canonical CLEO worktrees root, a `.claude/worktrees/` agent spawn, or
@@ -244,54 +277,53 @@ async function fetchRowContent(row, payload, projectRoot) {
244
277
  }
245
278
  }
246
279
  /**
247
- * Run the docs store health check.
280
+ * Scan the store and compute diagnostics + repair inputs in one pass.
248
281
  *
249
- * Dry run (default): every diagnostic is reported and every repair is
250
- * listed as a plan item with `applied: false` — nothing is written.
251
- * Apply: the backup gate runs first, then repairs execute in dependency
252
- * order (doc-version-skew, empty-provenance, dangling-pointers, and finally
253
- * the wikilinks rebuild, which re-derives from the freshly repaired columns).
282
+ * The function is pure with respect to the database — it is called twice on
283
+ * an apply run (before repairs, to build the plan; after repairs, so the
284
+ * report's diagnostics reflect POST-repair state, T13560).
254
285
  *
255
- * @param projectRoot - Absolute path to the CLEO project root.
256
- * @param opts - Apply flag, stale-draft threshold, backup receipt.
257
- * @returns The structured report, or a backup-gate refusal.
258
- * @task T13447
286
+ * @internal
259
287
  */
260
- // @sync-invariant docs.lifecycle.transitions the only lifecycle write is draft→archived for dangling rows, a legal matrix transition
261
- export async function runDocsDoctor(projectRoot, opts = {}) {
262
- const apply = opts.apply === true;
263
- const olderThanDays = opts.olderThanDays ?? DOCS_DOCTOR_DEFAULT_OLDER_THAN_DAYS;
264
- if (apply) {
265
- const refusal = checkBackupReceipt(opts.backupReceiptPath);
266
- if (refusal)
267
- return { ok: false, error: refusal };
268
- }
269
- const db = await getDb(projectRoot);
288
+ async function scanStore(projectRoot, db, olderThanDays) {
270
289
  const rows = await db.select().from(docsAttachments).all();
271
290
  const payloadById = new Map();
272
291
  for (const row of rows)
273
292
  payloadById.set(row.id, parseAttachmentJson(row.attachmentJson));
274
- const repairs = [];
275
293
  // ── dangling-pointers ──────────────────────────────────────────────────────
276
294
  const danglingItems = [];
277
295
  let danglingCount = 0;
278
296
  const archivable = [];
297
+ const clearable = [];
279
298
  for (const row of rows) {
299
+ // Archived rows already had their repair — counting them again would make
300
+ // the post-apply count unchanged (T13562a).
301
+ if (row.lifecycleStatus === 'archived')
302
+ continue;
280
303
  const payload = payloadById.get(row.id) ?? null;
281
304
  const localFile = payload === null ? null : asLocalFile(payload);
282
- if (!localFile)
305
+ const blobWithPath = payload === null ? null : asBlobWithPath(payload);
306
+ const pointer = localFile ?? blobWithPath;
307
+ if (!pointer)
283
308
  continue;
284
- const absPath = isAbsolute(localFile.path)
285
- ? localFile.path
286
- : resolve(projectRoot, localFile.path);
309
+ const absPath = isAbsolute(pointer.path) ? pointer.path : resolve(projectRoot, pointer.path);
287
310
  const exists = existsSync(absPath);
288
311
  const ephemeral = isWorktreeOrTmpPath(absPath);
289
312
  if (exists && ephemeral === null)
290
313
  continue;
291
314
  danglingCount += 1;
292
315
  const reason = !exists ? 'missing' : (ephemeral ?? 'missing');
293
- if (!exists)
316
+ if (localFile && !exists) {
294
317
  archivable.push({ row, path: absPath });
318
+ }
319
+ else if (blobWithPath &&
320
+ !exists &&
321
+ payload !== null &&
322
+ blobRowContentAlive(row, payload, projectRoot)) {
323
+ // The blob bytes are retrievable by sha256 — re-point the metadata at
324
+ // the content-addressed store by clearing the stale path (T13562b).
325
+ clearable.push({ row, path: absPath, payload });
326
+ }
295
327
  if (danglingItems.length < DOCS_DOCTOR_MAX_DETAIL_ITEMS) {
296
328
  danglingItems.push({
297
329
  attachmentId: row.id,
@@ -299,19 +331,10 @@ export async function runDocsDoctor(projectRoot, opts = {}) {
299
331
  path: absPath,
300
332
  exists,
301
333
  reason,
334
+ ...(blobWithPath ? { kind: 'blob' } : {}),
302
335
  });
303
336
  }
304
337
  }
305
- for (const { row, path } of archivable) {
306
- repairs.push({
307
- kind: 'dangling-pointers',
308
- action: 'archive-dangling',
309
- applied: apply,
310
- attachmentId: row.id,
311
- ...(row.slug !== null ? { slug: row.slug } : {}),
312
- detail: `marked-dangling: local-file target missing (${path}) → lifecycle_status = 'archived'`,
313
- });
314
- }
315
338
  // ── doc-version-skew ───────────────────────────────────────────────────────
316
339
  const revisionCounts = readAuditRevisionCounts(projectRoot);
317
340
  const skewItems = [];
@@ -334,16 +357,6 @@ export async function runDocsDoctor(projectRoot, opts = {}) {
334
357
  });
335
358
  }
336
359
  }
337
- for (const { row, expected } of skewed) {
338
- repairs.push({
339
- kind: 'doc-version-skew',
340
- action: 'set-doc-version',
341
- applied: apply,
342
- attachmentId: row.id,
343
- ...(row.slug !== null ? { slug: row.slug } : {}),
344
- detail: `audit-note: docVersion ${row.docVersion} → ${expected} (audit log revisions + 1)`,
345
- });
346
- }
347
360
  // ── empty-provenance ───────────────────────────────────────────────────────
348
361
  const provItems = [];
349
362
  let provCount = 0;
@@ -362,25 +375,11 @@ export async function runDocsDoctor(projectRoot, opts = {}) {
362
375
  ? labelsRaw.filter((l) => typeof l === 'string')
363
376
  : undefined;
364
377
  provCount += 1;
365
- backfillable.push({ row, content, labels });
378
+ backfillable.push({ row, content, labels, derived: deriveDocLinks(content, labels) });
366
379
  if (provItems.length < DOCS_DOCTOR_MAX_DETAIL_ITEMS) {
367
380
  provItems.push({ attachmentId: row.id, slug: row.slug });
368
381
  }
369
382
  }
370
- for (const { row, content, labels } of backfillable) {
371
- const derived = deriveDocLinks(content, labels);
372
- const derivedCount = derived.topics.length + derived.relatedTasks.length;
373
- repairs.push({
374
- kind: 'empty-provenance',
375
- action: 'backfill-provenance',
376
- applied: apply && derivedCount > 0,
377
- attachmentId: row.id,
378
- ...(row.slug !== null ? { slug: row.slug } : {}),
379
- detail: derivedCount > 0
380
- ? `derived topics=[${derived.topics.join(',')}] related_tasks=[${derived.relatedTasks.join(',')}]`
381
- : 'no derivable topics or task mentions — columns stay NULL',
382
- });
383
- }
384
383
  // ── wikilinks-drift ────────────────────────────────────────────────────────
385
384
  const slugById = new Map();
386
385
  for (const row of rows) {
@@ -409,14 +408,10 @@ export async function runDocsDoctor(projectRoot, opts = {}) {
409
408
  const driftItems = missingEdges
410
409
  .slice(0, DOCS_DOCTOR_MAX_DETAIL_ITEMS)
411
410
  .map((e) => ({ fromSlug: e.fromSlug, toSlug: e.toSlug, relation: e.relation }));
412
- if (missingEdges.length > 0) {
413
- repairs.push({
414
- kind: 'wikilinks-drift',
415
- action: 'rebuild-wikilinks',
416
- applied: apply,
417
- detail: `${missingEdges.length} expected edge(s) absent from docs_wikilinks → full re-derivation`,
418
- });
419
- }
411
+ // A backfill changes the topics/related_tasks columns, so the derived edge
412
+ // set changes even when the pre-repair drift is zero — the rebuild must be
413
+ // planned whenever a backfill will actually write columns (T13561).
414
+ const backfillChangesLinks = backfillable.some((b) => b.derived.topics.length + b.derived.relatedTasks.length > 0);
420
415
  // ── legacy-store-present ───────────────────────────────────────────────────
421
416
  const legacyCandidates = [
422
417
  {
@@ -485,17 +480,108 @@ export async function runDocsDoctor(projectRoot, opts = {}) {
485
480
  truncated: staleRows.length > staleItems.length,
486
481
  },
487
482
  ];
483
+ return {
484
+ diagnostics,
485
+ dangling: { archivable, clearable },
486
+ skewed,
487
+ backfillable,
488
+ missingEdges,
489
+ needsWikilinksRebuild: missingEdges.length > 0 || backfillChangesLinks,
490
+ };
491
+ }
492
+ /**
493
+ * Run the docs store health check.
494
+ *
495
+ * Dry run (default): every diagnostic is reported and every repair is
496
+ * listed as a plan item with `applied: false` — nothing is written.
497
+ * Apply: the backup gate runs first, then repairs execute in dependency
498
+ * order (doc-version-skew, empty-provenance, dangling-pointers, and finally
499
+ * the wikilinks rebuild, which re-derives from the freshly repaired columns).
500
+ * On apply the report's diagnostics are re-scanned AFTER the repairs so the
501
+ * envelope reflects POST-repair state and the summary counts match it
502
+ * (T13560); a dry run reports the pre-repair state unchanged.
503
+ *
504
+ * @param projectRoot - Absolute path to the CLEO project root.
505
+ * @param opts - Apply flag, stale-draft threshold, backup receipt.
506
+ * @returns The structured report, or a backup-gate refusal.
507
+ * @task T13447
508
+ */
509
+ // @sync-invariant docs.lifecycle.transitions the only lifecycle write is draft→archived for dangling rows, a legal matrix transition
510
+ export async function runDocsDoctor(projectRoot, opts = {}) {
511
+ const apply = opts.apply === true;
512
+ const olderThanDays = opts.olderThanDays ?? DOCS_DOCTOR_DEFAULT_OLDER_THAN_DAYS;
513
+ if (apply) {
514
+ const refusal = checkBackupReceipt(opts.backupReceiptPath);
515
+ if (refusal)
516
+ return { ok: false, error: refusal };
517
+ }
518
+ const db = await getDb(projectRoot);
519
+ const pre = await scanStore(projectRoot, db, olderThanDays);
520
+ const repairs = [];
521
+ for (const { row, path } of pre.dangling.archivable) {
522
+ repairs.push({
523
+ kind: 'dangling-pointers',
524
+ action: 'archive-dangling',
525
+ applied: apply,
526
+ attachmentId: row.id,
527
+ ...(row.slug !== null ? { slug: row.slug } : {}),
528
+ detail: `marked-dangling: local-file target missing (${path}) → lifecycle_status = 'archived'`,
529
+ });
530
+ }
531
+ for (const { row, path } of pre.dangling.clearable) {
532
+ repairs.push({
533
+ kind: 'dangling-pointers',
534
+ action: 'clear-stale-path',
535
+ applied: apply,
536
+ attachmentId: row.id,
537
+ ...(row.slug !== null ? { slug: row.slug } : {}),
538
+ detail: `cleared stale legacy path (${path}) — content alive in the blob store ` +
539
+ `(sha256 ${row.sha256.slice(0, 12)}…)`,
540
+ });
541
+ }
542
+ for (const { row, expected } of pre.skewed) {
543
+ repairs.push({
544
+ kind: 'doc-version-skew',
545
+ action: 'set-doc-version',
546
+ applied: apply,
547
+ attachmentId: row.id,
548
+ ...(row.slug !== null ? { slug: row.slug } : {}),
549
+ detail: `audit-note: docVersion ${row.docVersion} → ${expected} (audit log revisions + 1)`,
550
+ });
551
+ }
552
+ for (const { row, derived } of pre.backfillable) {
553
+ const derivedCount = derived.topics.length + derived.relatedTasks.length;
554
+ repairs.push({
555
+ kind: 'empty-provenance',
556
+ action: 'backfill-provenance',
557
+ applied: apply && derivedCount > 0,
558
+ attachmentId: row.id,
559
+ ...(row.slug !== null ? { slug: row.slug } : {}),
560
+ detail: derivedCount > 0
561
+ ? `derived topics=[${derived.topics.join(',')}] related_tasks=[${derived.relatedTasks.join(',')}]`
562
+ : 'no derivable topics or task mentions — columns stay NULL',
563
+ });
564
+ }
565
+ if (pre.needsWikilinksRebuild) {
566
+ repairs.push({
567
+ kind: 'wikilinks-drift',
568
+ action: 'rebuild-wikilinks',
569
+ applied: apply,
570
+ detail: pre.missingEdges.length > 0
571
+ ? `${pre.missingEdges.length} expected edge(s) absent from docs_wikilinks → full re-derivation`
572
+ : 'provenance backfill changes derived edges → full re-derivation',
573
+ });
574
+ }
488
575
  // ── Apply repairs (backup gate already passed) ─────────────────────────────
489
576
  if (apply) {
490
- for (const { row, expected } of skewed) {
577
+ for (const { row, expected } of pre.skewed) {
491
578
  await db
492
579
  .update(docsAttachments)
493
580
  .set({ docVersion: expected })
494
581
  .where(eq(docsAttachments.id, row.id))
495
582
  .run();
496
583
  }
497
- for (const { row, content, labels } of backfillable) {
498
- const derived = deriveDocLinks(content, labels);
584
+ for (const { row, derived } of pre.backfillable) {
499
585
  if (derived.topics.length + derived.relatedTasks.length === 0)
500
586
  continue;
501
587
  await db
@@ -507,20 +593,33 @@ export async function runDocsDoctor(projectRoot, opts = {}) {
507
593
  .where(eq(docsAttachments.id, row.id))
508
594
  .run();
509
595
  }
510
- for (const { row } of archivable) {
596
+ for (const { row } of pre.dangling.archivable) {
511
597
  await db
512
598
  .update(docsAttachments)
513
599
  .set({ lifecycleStatus: 'archived' })
514
600
  .where(eq(docsAttachments.id, row.id))
515
601
  .run();
516
602
  }
517
- if (missingEdges.length > 0) {
603
+ for (const { row, payload } of pre.dangling.clearable) {
604
+ const cleaned = { ...payload };
605
+ delete cleaned['path'];
606
+ await db
607
+ .update(docsAttachments)
608
+ .set({ attachmentJson: JSON.stringify(cleaned) })
609
+ .where(eq(docsAttachments.id, row.id))
610
+ .run();
611
+ }
612
+ if (pre.needsWikilinksRebuild) {
518
613
  await rebuildDocsWikilinks({ projectRoot });
519
614
  }
520
615
  }
521
- const findings = diagnostics.reduce((sum, d) => sum + d.count, 0);
616
+ // T13560: on apply, re-scan so the envelope's diagnostics (and the summary
617
+ // computed from them) describe POST-repair state, consistent with a
618
+ // follow-up dry run. Dry runs keep the pre-repair scan.
619
+ const post = apply ? await scanStore(projectRoot, db, olderThanDays) : pre;
620
+ const findings = post.diagnostics.reduce((sum, d) => sum + d.count, 0);
522
621
  const summary = apply
523
- ? `docs doctor applied ${repairs.filter((r) => r.applied).length} repair(s) across ${findings} finding(s)`
622
+ ? `docs doctor applied ${repairs.filter((r) => r.applied).length} repair(s); ${findings} finding(s) remain post-repair`
524
623
  : `docs doctor found ${findings} finding(s); ${repairs.length} repair(s) planned (dry-run — pass --apply to execute)`;
525
624
  return {
526
625
  ok: true,
@@ -528,7 +627,7 @@ export async function runDocsDoctor(projectRoot, opts = {}) {
528
627
  applied: apply,
529
628
  olderThanDays,
530
629
  backupReceiptPath: apply ? (opts.backupReceiptPath ?? null) : null,
531
- diagnostics,
630
+ diagnostics: post.diagnostics,
532
631
  repairs,
533
632
  summary,
534
633
  },