@cleocode/contracts 2026.10.27 → 2026.11.1-canary.3

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 (106) hide show
  1. package/README.md +2 -0
  2. package/dist/.source-stamp.json +4 -0
  3. package/dist/__tests__/acceptance-gate.test.js +15 -3
  4. package/dist/__tests__/acceptance-gate.test.js.map +1 -1
  5. package/dist/__tests__/evidence-atom-schema.test.js +3 -1
  6. package/dist/__tests__/evidence-atom-schema.test.js.map +1 -1
  7. package/dist/__tests__/memory-wire-shapes.test.js.map +1 -1
  8. package/dist/acceptance-gate-schema.d.ts +25 -0
  9. package/dist/acceptance-gate-schema.d.ts.map +1 -1
  10. package/dist/acceptance-gate-schema.js +5 -0
  11. package/dist/acceptance-gate-schema.js.map +1 -1
  12. package/dist/acceptance-gate.d.ts +8 -0
  13. package/dist/acceptance-gate.d.ts.map +1 -1
  14. package/dist/data-accessor.d.ts +7 -0
  15. package/dist/data-accessor.d.ts.map +1 -1
  16. package/dist/data-accessor.js.map +1 -1
  17. package/dist/dependency.d.ts +2 -0
  18. package/dist/dependency.d.ts.map +1 -1
  19. package/dist/dispatch/operations-registry.d.ts.map +1 -1
  20. package/dist/dispatch/operations-registry.js +216 -0
  21. package/dist/dispatch/operations-registry.js.map +1 -1
  22. package/dist/docs/modernize.d.ts +435 -0
  23. package/dist/docs/modernize.d.ts.map +1 -0
  24. package/dist/docs/modernize.js +137 -0
  25. package/dist/docs/modernize.js.map +1 -0
  26. package/dist/docs-taxonomy.d.ts +6 -0
  27. package/dist/docs-taxonomy.d.ts.map +1 -1
  28. package/dist/docs-taxonomy.js +38 -1
  29. package/dist/docs-taxonomy.js.map +1 -1
  30. package/dist/done-plan.d.ts +27 -2
  31. package/dist/done-plan.d.ts.map +1 -1
  32. package/dist/evidence-atom-schema.d.ts +78 -4
  33. package/dist/evidence-atom-schema.d.ts.map +1 -1
  34. package/dist/evidence-atom-schema.js +136 -11
  35. package/dist/evidence-atom-schema.js.map +1 -1
  36. package/dist/exit-codes.d.ts +41 -0
  37. package/dist/exit-codes.d.ts.map +1 -1
  38. package/dist/exit-codes.js +41 -0
  39. package/dist/exit-codes.js.map +1 -1
  40. package/dist/index.d.ts +9 -5
  41. package/dist/index.d.ts.map +1 -1
  42. package/dist/index.js +2 -1
  43. package/dist/index.js.map +1 -1
  44. package/dist/invariants/sync-write-invariants.d.ts.map +1 -1
  45. package/dist/invariants/sync-write-invariants.js +15 -0
  46. package/dist/invariants/sync-write-invariants.js.map +1 -1
  47. package/dist/memory/search.d.ts +13 -0
  48. package/dist/memory/search.d.ts.map +1 -1
  49. package/dist/merge-close.d.ts +167 -0
  50. package/dist/merge-close.d.ts.map +1 -0
  51. package/dist/merge-close.js +16 -0
  52. package/dist/merge-close.js.map +1 -0
  53. package/dist/operations/admin.d.ts +6 -0
  54. package/dist/operations/admin.d.ts.map +1 -1
  55. package/dist/operations/docs.d.ts +192 -3
  56. package/dist/operations/docs.d.ts.map +1 -1
  57. package/dist/operations/docs.js.map +1 -1
  58. package/dist/operations/worktree.d.ts +63 -0
  59. package/dist/operations/worktree.d.ts.map +1 -1
  60. package/dist/project-context.d.ts +31 -0
  61. package/dist/project-context.d.ts.map +1 -1
  62. package/dist/release/authorization.d.ts +46 -0
  63. package/dist/release/authorization.d.ts.map +1 -0
  64. package/dist/release/authorization.js +10 -0
  65. package/dist/release/authorization.js.map +1 -0
  66. package/dist/review-verdict.d.ts +125 -0
  67. package/dist/review-verdict.d.ts.map +1 -0
  68. package/dist/review-verdict.js +14 -0
  69. package/dist/review-verdict.js.map +1 -0
  70. package/dist/session-journal.d.ts.map +1 -1
  71. package/dist/session-journal.js +7 -1
  72. package/dist/session-journal.js.map +1 -1
  73. package/dist/task-record.d.ts +6 -1
  74. package/dist/task-record.d.ts.map +1 -1
  75. package/dist/task.d.ts +130 -3
  76. package/dist/task.d.ts.map +1 -1
  77. package/package.json +2 -2
  78. package/schemas/acceptance-gate.schema.json +24 -0
  79. package/schemas/task.schema.json +24 -0
  80. package/src/__tests__/__snapshots__/operations-registry.test.ts.snap +1 -1
  81. package/src/__tests__/acceptance-gate.test.ts +16 -3
  82. package/src/__tests__/evidence-atom-schema.test.ts +3 -1
  83. package/src/__tests__/memory-wire-shapes.test.ts +2 -0
  84. package/src/acceptance-gate-schema.ts +5 -0
  85. package/src/acceptance-gate.ts +9 -0
  86. package/src/data-accessor.ts +8 -0
  87. package/src/dependency.ts +2 -0
  88. package/src/dispatch/operations-registry.ts +228 -0
  89. package/src/docs/modernize.ts +407 -0
  90. package/src/docs-taxonomy.ts +44 -1
  91. package/src/done-plan.ts +27 -2
  92. package/src/evidence-atom-schema.ts +167 -14
  93. package/src/exit-codes.ts +41 -0
  94. package/src/index.ts +55 -0
  95. package/src/invariants/sync-write-invariants.ts +16 -0
  96. package/src/memory/search.ts +10 -0
  97. package/src/merge-close.ts +168 -0
  98. package/src/operations/admin.ts +6 -0
  99. package/src/operations/docs.ts +199 -4
  100. package/src/operations/worktree.ts +66 -0
  101. package/src/project-context.ts +33 -0
  102. package/src/release/authorization.ts +48 -0
  103. package/src/review-verdict.ts +122 -0
  104. package/src/session-journal.ts +7 -1
  105. package/src/task-record.ts +6 -1
  106. package/src/task.ts +124 -3
@@ -193,12 +193,14 @@ describe('CommandGate schema', () => {
193
193
  it('round-trips a minimal command gate', () => {
194
194
  const input = {
195
195
  kind: 'command' as const,
196
- cmd: 'cleo doctor',
196
+ cmd: 'cleo',
197
+ args: ['doctor'],
197
198
  description: 'cleo doctor must exit 0',
198
199
  };
199
200
  const result = commandGateSchema.parse(input);
200
201
  expect(result.kind).toBe('command');
201
- expect(result.cmd).toBe('cleo doctor');
202
+ expect(result.cmd).toBe('cleo');
203
+ expect(result.args).toEqual(['doctor']);
202
204
  // exitCode defaults to undefined (not set in schema default)
203
205
  expect(result.exitCode).toBeUndefined();
204
206
  });
@@ -370,12 +372,23 @@ describe('acceptanceGateSchema (discriminated union)', () => {
370
372
  it('routes command gate by kind', () => {
371
373
  const result = acceptanceGateSchema.parse({
372
374
  kind: 'command',
373
- cmd: 'pnpm doctor',
375
+ cmd: 'pnpm',
376
+ args: ['doctor'],
374
377
  description: 'doctor must succeed',
375
378
  });
376
379
  expect(result.kind).toBe('command');
377
380
  });
378
381
 
382
+ it('parse still accepts a legacy stored command gate whose cmd carries arguments (T14155)', () => {
383
+ // Writes refuse this shape (cleo req add / replace); reading a stored one never does.
384
+ const result = acceptanceGateSchema.parse({
385
+ kind: 'command',
386
+ cmd: 'pnpm doctor',
387
+ description: 'doctor must succeed',
388
+ });
389
+ expect(result.kind === 'command' && result.cmd).toBe('pnpm doctor');
390
+ });
391
+
379
392
  it('routes lint gate by kind', () => {
380
393
  const result = acceptanceGateSchema.parse({
381
394
  kind: 'lint',
@@ -32,7 +32,7 @@ describe('EvidenceAtomSchema (T10337)', () => {
32
32
  // Verify the shared constant is in sync with the zod discriminated union.
33
33
  // The discriminated union keys are 'commit','files','test-run','qa-run',
34
34
  // 'tool','url','note','decision','pr','ci','loc-drop','callsite-coverage',
35
- // 'satisfies' ('qa-run': T13427).
35
+ // 'satisfies' ('qa-run': T13427), 'deploy' (T14083), 'ci-run' (T14149).
36
36
  const expected = [
37
37
  'commit',
38
38
  'files',
@@ -44,6 +44,8 @@ describe('EvidenceAtomSchema (T10337)', () => {
44
44
  'decision',
45
45
  'pr',
46
46
  'ci',
47
+ 'ci-run',
48
+ 'deploy',
47
49
  'loc-drop',
48
50
  'callsite-coverage',
49
51
  'satisfies',
@@ -68,6 +68,7 @@ type _BrainCompactHitShape = {
68
68
  bm25Score?: number;
69
69
  _next?: Record<string, string>;
70
70
  scope?: 'project' | 'global';
71
+ docs?: string[];
71
72
  };
72
73
 
73
74
  type _AssertBrainCompactHitPinned = AssertEquals1<Equals<BrainCompactHit, _BrainCompactHitShape>>;
@@ -99,6 +100,7 @@ type _SearchBrainCompactResultShape = {
99
100
  results: BrainCompactHit[];
100
101
  total: number;
101
102
  tokensEstimated: number;
103
+ taskDocs?: Array<{ taskId: string; docs: string[] }>;
102
104
  };
103
105
 
104
106
  type _AssertSearchResultPinned = AssertEquals1<
@@ -34,6 +34,11 @@ export const gateBaseSchema = z.object({
34
34
  advisory: z.boolean().optional(),
35
35
  /** Per-gate timeout override in milliseconds. */
36
36
  timeoutMs: z.number().int().positive().optional(),
37
+ /** Declared evidence repository the gate runs in (T14078). */
38
+ repo: z
39
+ .string()
40
+ .regex(/^[A-Za-z0-9][A-Za-z0-9._-]*$/)
41
+ .optional(),
37
42
  });
38
43
 
39
44
  // ─── File assertion schemas ───────────────────────────────────────────────────
@@ -122,6 +122,15 @@ export interface GateBase {
122
122
  * covers only the surrounding bookkeeping, never a gate (T12621).
123
123
  */
124
124
  timeoutMs?: number;
125
+
126
+ /**
127
+ * Name of an evidence repository the project declares in
128
+ * `.cleo/project-context.json` (`evidence.repositories`, T14078): the gate
129
+ * runs in that checkout, its inputs are captured there and it is
130
+ * revalidated there. A name the project does not declare is refused.
131
+ * Absent, the gate runs in the task's evidence tree.
132
+ */
133
+ repo?: string;
125
134
  }
126
135
 
127
136
  // ─── Variants ────────────────────────────────────────────────────────────────
@@ -743,6 +743,14 @@ export interface DataAccessor {
743
743
  */
744
744
  getAcRows(taskId: string): Promise<AcRow[]>;
745
745
 
746
+ /**
747
+ * Read the AC rows of many tasks in bulk (ordered by task, then ordinal),
748
+ * for whole-store scans such as `cleo doctor --coherence` (T12883). Optional:
749
+ * callers fall back to {@link getAcRows} per task when it is absent.
750
+ * @task T12883
751
+ */
752
+ getAcRowsForTasks?(taskIds: readonly string[]): Promise<AcRow[]>;
753
+
746
754
  /**
747
755
  * Read `evidence_ac_bindings` rows whose `ac_id` ∈ the given set.
748
756
  * Powers the AC-coverage gate (T10509). Returns the empty array when
package/src/dependency.ts CHANGED
@@ -71,6 +71,8 @@ export interface DependencyCheckResult {
71
71
  error?: string;
72
72
  /** Actionable fix suggestion to show the user when `healthy` is `false`. */
73
73
  suggestedFix?: string;
74
+ /** A caveat on a healthy result, e.g. a version that could not be checked (T14166). */
75
+ note?: string;
74
76
  }
75
77
 
76
78
  /**
@@ -8727,6 +8727,13 @@ export const OPERATIONS: OperationDef[] = [
8727
8727
  required: false,
8728
8728
  description: 'Age threshold in days for the stale-drafts check (default 30)',
8729
8729
  },
8730
+ {
8731
+ name: 'only',
8732
+ type: 'string' as const,
8733
+ required: false,
8734
+ description:
8735
+ 'Comma-separated repair classes to scope the plan (and apply) to, e.g. publication-ledger-drift (T14174)',
8736
+ },
8730
8737
  ],
8731
8738
  },
8732
8739
  // ── docs.triage (T13446 — Epic T13340 / Saga T13339) ──────────────────────
@@ -8780,6 +8787,29 @@ export const OPERATIONS: OperationDef[] = [
8780
8787
  requiredParams: [],
8781
8788
  params: [],
8782
8789
  },
8790
+ // ── docs.rot (T14111 — Epic T14106) ──────────────────────────────────────
8791
+ {
8792
+ gateway: 'query',
8793
+ domain: 'docs',
8794
+ operation: 'rot',
8795
+ description:
8796
+ 'docs.rot (query) — docs-rot report from git alone: docs whose covers: code changed ' +
8797
+ 'after them (stale), duplicate docs, and orphaned docs (dead covers globs, ' +
8798
+ 'unreferenced docs/ files). changed:<base>..<head> also lists the docs that merged ' +
8799
+ 'change left stale. Read-only.',
8800
+ tier: 1,
8801
+ idempotent: true,
8802
+ sessionRequired: false,
8803
+ requiredParams: [],
8804
+ params: [
8805
+ {
8806
+ name: 'changed',
8807
+ type: 'string' as const,
8808
+ required: false,
8809
+ description: 'Git range <base>..<head> of a merged change to flag docs for',
8810
+ },
8811
+ ],
8812
+ },
8783
8813
  {
8784
8814
  gateway: 'mutate',
8785
8815
  domain: 'docs',
@@ -8816,6 +8846,13 @@ export const OPERATIONS: OperationDef[] = [
8816
8846
  required: false,
8817
8847
  description: 'Age threshold in days for the stale-drafts check (default 30)',
8818
8848
  },
8849
+ {
8850
+ name: 'only',
8851
+ type: 'string' as const,
8852
+ required: false,
8853
+ description:
8854
+ 'Comma-separated repair classes to scope the plan (and apply) to, e.g. publication-ledger-drift (T14174)',
8855
+ },
8819
8856
  ],
8820
8857
  },
8821
8858
  // ── docs.migrate (T13360 — Epic T13340 / Saga T13339) ─────────────────────
@@ -8836,6 +8873,97 @@ export const OPERATIONS: OperationDef[] = [
8836
8873
  requiredParams: [],
8837
8874
  params: [],
8838
8875
  },
8876
+ // ── docs.modernize (T14113 — Epic T14106) ─────────────────────────────────
8877
+ {
8878
+ gateway: 'mutate',
8879
+ domain: 'docs',
8880
+ operation: 'modernize',
8881
+ description:
8882
+ 'docs.modernize (mutate) — turn a messy docs folder into clean, linked CleoDocs. Dry run ' +
8883
+ 'by default: proposes per file a kind, a stable slug (no task, session or date tokens) ' +
8884
+ 'and keep/rename/merge-into/delete with reasons and any System One judgment. --apply ' +
8885
+ 'stores, merges, supersedes, moves files and writes wikilink edges with a receipt; ' +
8886
+ '--rollback <runId> reverses a run.',
8887
+ tier: 1,
8888
+ idempotent: false,
8889
+ sessionRequired: false,
8890
+ requiredParams: [],
8891
+ params: [
8892
+ {
8893
+ name: 'path',
8894
+ type: 'string' as const,
8895
+ required: false,
8896
+ description: 'Folder to modernize (required unless --rollback)',
8897
+ },
8898
+ {
8899
+ name: 'apply',
8900
+ type: 'boolean' as const,
8901
+ required: false,
8902
+ description: 'Execute the plan (default: dry run, nothing written)',
8903
+ },
8904
+ {
8905
+ name: 'planFile',
8906
+ type: 'string' as const,
8907
+ required: false,
8908
+ description: 'Apply this saved plan JSON verbatim',
8909
+ },
8910
+ {
8911
+ name: 'out',
8912
+ type: 'string' as const,
8913
+ required: false,
8914
+ description: 'Save the plan JSON to this path',
8915
+ },
8916
+ {
8917
+ name: 'rollback',
8918
+ type: 'string' as const,
8919
+ required: false,
8920
+ description: 'Roll back the apply run with this id',
8921
+ },
8922
+ {
8923
+ name: 'exclude',
8924
+ type: 'string' as const,
8925
+ required: false,
8926
+ description: 'Extra folder names to skip, comma-separated',
8927
+ },
8928
+ {
8929
+ name: 'overrides',
8930
+ type: 'string' as const,
8931
+ required: false,
8932
+ description: 'Reviewer decisions JSON keyed by path (DocsModernizeOverrides)',
8933
+ },
8934
+ {
8935
+ name: 'kind',
8936
+ type: 'string' as const,
8937
+ required: false,
8938
+ description: 'Use this kind for every file instead of classifying',
8939
+ },
8940
+ {
8941
+ name: 'storeOnly',
8942
+ type: 'boolean' as const,
8943
+ required: false,
8944
+ description: 'Ingest every file into the store and leave the folder untouched',
8945
+ },
8946
+ {
8947
+ name: 'allowDirty',
8948
+ type: 'boolean' as const,
8949
+ required: false,
8950
+ description: 'Apply even when the root is not a clean git checkout',
8951
+ },
8952
+ {
8953
+ name: 'wikilinks',
8954
+ type: 'boolean' as const,
8955
+ required: false,
8956
+ description:
8957
+ 'Rewrite relative links to planned docs as [[slug]] wikilinks (default: keep markdown links, re-pointed at the new paths)',
8958
+ },
8959
+ {
8960
+ name: 'store',
8961
+ type: 'boolean' as const,
8962
+ required: false,
8963
+ description: 'Modernize the docs already in the store instead of a folder',
8964
+ },
8965
+ ],
8966
+ },
8839
8967
  // ── docs.generate (T798) ─────────────────────────────────────────────────
8840
8968
  {
8841
8969
  gateway: 'query',
@@ -9782,6 +9910,106 @@ export const OPERATIONS: OperationDef[] = [
9782
9910
  ] satisfies ParamDef[],
9783
9911
  },
9784
9912
 
9913
+ // release mutate: cut (T14102 — one-command release from the newest green
9914
+ // default-branch commit; replaces plan → open → bump-PR → hand tag).
9915
+ {
9916
+ gateway: 'mutate',
9917
+ domain: 'release',
9918
+ operation: 'cut',
9919
+ description:
9920
+ 'release.cut (mutate) — tag the newest default-branch commit with green CI as v<version> once confirmed with --yes (D11211/D11212); release.yml writes the CHANGELOG from changesets and publishes. Without --yes it reports the commit, notes, packages and task status and prints the confirm command (T14102).',
9921
+ tier: 1,
9922
+ idempotent: false,
9923
+ sessionRequired: false,
9924
+ requiredParams: ['version'],
9925
+ params: [
9926
+ {
9927
+ name: 'version',
9928
+ type: 'string',
9929
+ required: true,
9930
+ description: 'Release version (accepts v2026.10.28 or 2026.10.28)',
9931
+ cli: { positional: true },
9932
+ },
9933
+ {
9934
+ name: 'sha',
9935
+ type: 'string',
9936
+ required: false,
9937
+ description: 'Pin the commit instead of the newest green one; it must itself be green',
9938
+ },
9939
+ {
9940
+ name: 'lead',
9941
+ type: 'string',
9942
+ required: false,
9943
+ description: 'Markdown file that leads the notes (Update now + Highlights)',
9944
+ },
9945
+ {
9946
+ name: 'dryRun',
9947
+ type: 'boolean',
9948
+ required: false,
9949
+ description: 'Report the commit, notes, packages and tasks without creating the tag',
9950
+ },
9951
+ {
9952
+ name: 'yes',
9953
+ type: 'boolean',
9954
+ required: false,
9955
+ description:
9956
+ 'Create the tag (D11212): the version typed on the controlling terminal (/dev/tty), or a standing release authorization (T14141), allows it. Without it the cut only reports and prints the confirm command',
9957
+ },
9958
+ ] satisfies ParamDef[],
9959
+ },
9960
+
9961
+ // release mutate: write-changelog (T14102 — CHANGELOG section from the
9962
+ // changesets since the previous tag; run by release.yml on the tagged checkout).
9963
+ {
9964
+ gateway: 'mutate',
9965
+ domain: 'release',
9966
+ operation: 'write-changelog',
9967
+ description:
9968
+ 'release.write-changelog (mutate) — write the ## [VERSION] CHANGELOG.md section from the changesets added since the previous release tag, led by the tag annotation; leaves an existing section untouched (T14102).',
9969
+ tier: 1,
9970
+ idempotent: true,
9971
+ sessionRequired: false,
9972
+ requiredParams: ['version'],
9973
+ params: [
9974
+ {
9975
+ name: 'version',
9976
+ type: 'string',
9977
+ required: true,
9978
+ description: 'Release version (accepts v2026.10.28 or 2026.10.28)',
9979
+ cli: { positional: true },
9980
+ },
9981
+ {
9982
+ name: 'ref',
9983
+ type: 'string',
9984
+ required: false,
9985
+ description: 'Commit the release was cut from (default: tag v<version>, else HEAD)',
9986
+ },
9987
+ ] satisfies ParamDef[],
9988
+ },
9989
+
9990
+ // release query: verify-tag (T14102 — release.yml refuses to publish a tag
9991
+ // that is not a green first-parent commit of the default branch).
9992
+ {
9993
+ gateway: 'query',
9994
+ domain: 'release',
9995
+ operation: 'verify-tag',
9996
+ description:
9997
+ 'release.verify-tag (query) — refuse a release tag whose commit is not a first-parent commit of origin/main with every required check (release.prRequiredWorkflows, app-pinned) green on its push run. Run by release.yml before publishing (T14102).',
9998
+ tier: 1,
9999
+ idempotent: true,
10000
+ sessionRequired: false,
10001
+ requiredParams: ['version'],
10002
+ params: [
10003
+ {
10004
+ name: 'version',
10005
+ type: 'string',
10006
+ required: true,
10007
+ description: 'Release version whose tag is checked (accepts v2026.10.28 or 2026.10.28)',
10008
+ cli: { positional: true },
10009
+ },
10010
+ ] satisfies ParamDef[],
10011
+ },
10012
+
9785
10013
  // release query: validate-changelog (T9937 / Saga T9862 — canonical CHANGELOG
9786
10014
  // header validator that replaces the brittle inline grep step in
9787
10015
  // .github/workflows/release.yml). Read-only — exposed only under the query