@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.
- package/README.md +2 -0
- package/dist/.source-stamp.json +4 -0
- package/dist/__tests__/acceptance-gate.test.js +15 -3
- package/dist/__tests__/acceptance-gate.test.js.map +1 -1
- package/dist/__tests__/evidence-atom-schema.test.js +3 -1
- package/dist/__tests__/evidence-atom-schema.test.js.map +1 -1
- package/dist/__tests__/memory-wire-shapes.test.js.map +1 -1
- package/dist/acceptance-gate-schema.d.ts +25 -0
- package/dist/acceptance-gate-schema.d.ts.map +1 -1
- package/dist/acceptance-gate-schema.js +5 -0
- package/dist/acceptance-gate-schema.js.map +1 -1
- package/dist/acceptance-gate.d.ts +8 -0
- package/dist/acceptance-gate.d.ts.map +1 -1
- package/dist/data-accessor.d.ts +7 -0
- package/dist/data-accessor.d.ts.map +1 -1
- package/dist/data-accessor.js.map +1 -1
- package/dist/dependency.d.ts +2 -0
- package/dist/dependency.d.ts.map +1 -1
- package/dist/dispatch/operations-registry.d.ts.map +1 -1
- package/dist/dispatch/operations-registry.js +216 -0
- package/dist/dispatch/operations-registry.js.map +1 -1
- package/dist/docs/modernize.d.ts +435 -0
- package/dist/docs/modernize.d.ts.map +1 -0
- package/dist/docs/modernize.js +137 -0
- package/dist/docs/modernize.js.map +1 -0
- package/dist/docs-taxonomy.d.ts +6 -0
- package/dist/docs-taxonomy.d.ts.map +1 -1
- package/dist/docs-taxonomy.js +38 -1
- package/dist/docs-taxonomy.js.map +1 -1
- package/dist/done-plan.d.ts +27 -2
- package/dist/done-plan.d.ts.map +1 -1
- package/dist/evidence-atom-schema.d.ts +78 -4
- package/dist/evidence-atom-schema.d.ts.map +1 -1
- package/dist/evidence-atom-schema.js +136 -11
- package/dist/evidence-atom-schema.js.map +1 -1
- package/dist/exit-codes.d.ts +41 -0
- package/dist/exit-codes.d.ts.map +1 -1
- package/dist/exit-codes.js +41 -0
- package/dist/exit-codes.js.map +1 -1
- package/dist/index.d.ts +9 -5
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -1
- package/dist/index.js.map +1 -1
- package/dist/invariants/sync-write-invariants.d.ts.map +1 -1
- package/dist/invariants/sync-write-invariants.js +15 -0
- package/dist/invariants/sync-write-invariants.js.map +1 -1
- package/dist/memory/search.d.ts +13 -0
- package/dist/memory/search.d.ts.map +1 -1
- package/dist/merge-close.d.ts +167 -0
- package/dist/merge-close.d.ts.map +1 -0
- package/dist/merge-close.js +16 -0
- package/dist/merge-close.js.map +1 -0
- package/dist/operations/admin.d.ts +6 -0
- package/dist/operations/admin.d.ts.map +1 -1
- package/dist/operations/docs.d.ts +192 -3
- package/dist/operations/docs.d.ts.map +1 -1
- package/dist/operations/docs.js.map +1 -1
- package/dist/operations/worktree.d.ts +63 -0
- package/dist/operations/worktree.d.ts.map +1 -1
- package/dist/project-context.d.ts +31 -0
- package/dist/project-context.d.ts.map +1 -1
- package/dist/release/authorization.d.ts +46 -0
- package/dist/release/authorization.d.ts.map +1 -0
- package/dist/release/authorization.js +10 -0
- package/dist/release/authorization.js.map +1 -0
- package/dist/review-verdict.d.ts +125 -0
- package/dist/review-verdict.d.ts.map +1 -0
- package/dist/review-verdict.js +14 -0
- package/dist/review-verdict.js.map +1 -0
- package/dist/session-journal.d.ts.map +1 -1
- package/dist/session-journal.js +7 -1
- package/dist/session-journal.js.map +1 -1
- package/dist/task-record.d.ts +6 -1
- package/dist/task-record.d.ts.map +1 -1
- package/dist/task.d.ts +130 -3
- package/dist/task.d.ts.map +1 -1
- package/package.json +2 -2
- package/schemas/acceptance-gate.schema.json +24 -0
- package/schemas/task.schema.json +24 -0
- package/src/__tests__/__snapshots__/operations-registry.test.ts.snap +1 -1
- package/src/__tests__/acceptance-gate.test.ts +16 -3
- package/src/__tests__/evidence-atom-schema.test.ts +3 -1
- package/src/__tests__/memory-wire-shapes.test.ts +2 -0
- package/src/acceptance-gate-schema.ts +5 -0
- package/src/acceptance-gate.ts +9 -0
- package/src/data-accessor.ts +8 -0
- package/src/dependency.ts +2 -0
- package/src/dispatch/operations-registry.ts +228 -0
- package/src/docs/modernize.ts +407 -0
- package/src/docs-taxonomy.ts +44 -1
- package/src/done-plan.ts +27 -2
- package/src/evidence-atom-schema.ts +167 -14
- package/src/exit-codes.ts +41 -0
- package/src/index.ts +55 -0
- package/src/invariants/sync-write-invariants.ts +16 -0
- package/src/memory/search.ts +10 -0
- package/src/merge-close.ts +168 -0
- package/src/operations/admin.ts +6 -0
- package/src/operations/docs.ts +199 -4
- package/src/operations/worktree.ts +66 -0
- package/src/project-context.ts +33 -0
- package/src/release/authorization.ts +48 -0
- package/src/review-verdict.ts +122 -0
- package/src/session-journal.ts +7 -1
- package/src/task-record.ts +6 -1
- package/src/task.ts +124 -3
package/src/operations/admin.ts
CHANGED
|
@@ -1662,6 +1662,12 @@ export interface AdminBackupMutateParams {
|
|
|
1662
1662
|
confirmOwnerStore?: boolean;
|
|
1663
1663
|
/** Create: also back up the global store (`<CLEO_HOME>/cleo.db`, T13245). */
|
|
1664
1664
|
includeGlobal?: boolean;
|
|
1665
|
+
/**
|
|
1666
|
+
* Create: write the backup into this directory (the global copy under
|
|
1667
|
+
* `<destination>/global`) instead of the rotating backup dirs; it never
|
|
1668
|
+
* rotates or is rotated (T13209).
|
|
1669
|
+
*/
|
|
1670
|
+
destination?: string;
|
|
1665
1671
|
/** Restore by id: `global` restores a backup of the global store (T13245). */
|
|
1666
1672
|
scope?: 'project' | 'global';
|
|
1667
1673
|
}
|
package/src/operations/docs.ts
CHANGED
|
@@ -32,6 +32,8 @@
|
|
|
32
32
|
|
|
33
33
|
import { z } from 'zod';
|
|
34
34
|
import type { AttachmentKind } from '../attachment.js';
|
|
35
|
+
import type { TaskPopulation } from '../data-accessor.js';
|
|
36
|
+
import type { DocsModernizePlan, DocsModernizeReceipt } from '../docs/modernize.js';
|
|
35
37
|
import { BUILTIN_DOC_KIND_VALUES, type BuiltinDocKind } from '../docs-taxonomy.js';
|
|
36
38
|
import type {
|
|
37
39
|
BackgroundJobStatus,
|
|
@@ -316,6 +318,12 @@ export interface DocsListResult {
|
|
|
316
318
|
* @task T9792
|
|
317
319
|
*/
|
|
318
320
|
totalCount?: number;
|
|
321
|
+
/**
|
|
322
|
+
* How many attachments matched, how many this response returns, whether it
|
|
323
|
+
* left any out, and the window applied (`null`: every match, `--limit 0`).
|
|
324
|
+
* The same shape `cleo list` reports (T14115).
|
|
325
|
+
*/
|
|
326
|
+
population: Pick<TaskPopulation, 'matched' | 'returned' | 'truncated' | 'limit'>;
|
|
319
327
|
/**
|
|
320
328
|
* Effective limit applied to this response. Mirrored from the request
|
|
321
329
|
* (or {@link DOCS_LIST_DEFAULT_LIMIT} when the request did not set one)
|
|
@@ -458,6 +466,37 @@ export interface DocsFetchResult {
|
|
|
458
466
|
* ratifies.
|
|
459
467
|
*/
|
|
460
468
|
linkedDecisions?: string[];
|
|
469
|
+
/**
|
|
470
|
+
* Where this doc sits in its supersession chain and what it serves
|
|
471
|
+
* (T14110). Present for slugged docs.
|
|
472
|
+
*/
|
|
473
|
+
lineage?: DocsLineage;
|
|
474
|
+
}
|
|
475
|
+
|
|
476
|
+
/**
|
|
477
|
+
* A doc's supersession chain and the work it serves (T14110). Built from the
|
|
478
|
+
* existing `supersedes`/`superseded_by` pointers, task refs and
|
|
479
|
+
* `related_tasks`; nothing here is stored separately.
|
|
480
|
+
*/
|
|
481
|
+
export interface DocsLineage {
|
|
482
|
+
/** The doc's lifecycle status (`superseded` when replaced). */
|
|
483
|
+
readonly lifecycleStatus: string;
|
|
484
|
+
/** Slug of the doc this one replaced, when any. */
|
|
485
|
+
readonly supersedes: string | null;
|
|
486
|
+
/** Slug of the doc that replaced this one, when any. */
|
|
487
|
+
readonly supersededBy: string | null;
|
|
488
|
+
/**
|
|
489
|
+
* Slug of the current doc at the end of the `superseded_by` chain: this
|
|
490
|
+
* doc's own slug when it is current. Read this one instead.
|
|
491
|
+
*/
|
|
492
|
+
readonly currentSlug: string;
|
|
493
|
+
/** Task ids the doc serves: its task owners and the tasks its body names. */
|
|
494
|
+
readonly servesTasks: readonly string[];
|
|
495
|
+
/**
|
|
496
|
+
* Decisions this doc supersedes: the `supersedes` of each decision it links
|
|
497
|
+
* (`docs link-decision`). Absent when it links none that supersede another.
|
|
498
|
+
*/
|
|
499
|
+
readonly supersedesDecisions?: readonly string[];
|
|
461
500
|
}
|
|
462
501
|
|
|
463
502
|
// --------------------------------------------------------------------------
|
|
@@ -570,6 +609,12 @@ export interface DocsAddParams {
|
|
|
570
609
|
* @saga T9855
|
|
571
610
|
*/
|
|
572
611
|
strict?: boolean;
|
|
612
|
+
/**
|
|
613
|
+
* Why this doc is new although it resembles an existing one (T14109). A
|
|
614
|
+
* likely duplicate is refused unless this states the reason (at least 15
|
|
615
|
+
* characters); the reason is recorded in `.cleo/audit/docs-new-because.jsonl`.
|
|
616
|
+
*/
|
|
617
|
+
newBecause?: string;
|
|
573
618
|
}
|
|
574
619
|
|
|
575
620
|
/** Canonical attachment and owner whose optional projections may be prepared. */
|
|
@@ -1104,6 +1149,12 @@ export interface DocsDoctorParams {
|
|
|
1104
1149
|
repair?: boolean;
|
|
1105
1150
|
/** Age threshold (days) for the `stale-drafts` diagnostic. Default 30. */
|
|
1106
1151
|
olderThanDays?: number;
|
|
1152
|
+
/**
|
|
1153
|
+
* Comma-separated repair classes to scope the run to (T14174), for example
|
|
1154
|
+
* `publication-ledger-drift`. Only their repairs are planned and, with
|
|
1155
|
+
* `apply`, written. Diagnostics still cover every class.
|
|
1156
|
+
*/
|
|
1157
|
+
only?: string;
|
|
1107
1158
|
}
|
|
1108
1159
|
|
|
1109
1160
|
/**
|
|
@@ -1121,7 +1172,8 @@ export interface DocsDoctorDiagnostic {
|
|
|
1121
1172
|
| 'legacy-store-present'
|
|
1122
1173
|
| 'legacy-blob-coverage'
|
|
1123
1174
|
| 'stale-drafts'
|
|
1124
|
-
| 'conduit-history-gaps'
|
|
1175
|
+
| 'conduit-history-gaps'
|
|
1176
|
+
| 'publication-ledger-drift';
|
|
1125
1177
|
/** `error` should be fixed promptly; `info` is observational. */
|
|
1126
1178
|
severity: 'info' | 'warn' | 'error';
|
|
1127
1179
|
/** Total offenders found (may exceed `items.length`). */
|
|
@@ -1164,10 +1216,18 @@ export interface DocsDoctorResult {
|
|
|
1164
1216
|
olderThanDays: number;
|
|
1165
1217
|
/** Backup receipt that authorised this run (null on dry runs). */
|
|
1166
1218
|
backupReceiptPath: string | null;
|
|
1167
|
-
/** All
|
|
1219
|
+
/** All nine diagnostics, in declaration order. */
|
|
1168
1220
|
diagnostics: readonly DocsDoctorDiagnostic[];
|
|
1169
1221
|
/** Repair plan (dry run) or executed repairs (apply). */
|
|
1170
1222
|
repairs: readonly DocsDoctorRepairAction[];
|
|
1223
|
+
/** Repairs per class: planned entries and those written (T14174). */
|
|
1224
|
+
repairCounts: Readonly<
|
|
1225
|
+
Partial<
|
|
1226
|
+
Record<DocsDoctorDiagnostic['kind'], { readonly planned: number; readonly applied: number }>
|
|
1227
|
+
>
|
|
1228
|
+
>;
|
|
1229
|
+
/** The repair classes this run was scoped to, or null for every class (T14174). */
|
|
1230
|
+
only: readonly DocsDoctorDiagnostic['kind'][] | null;
|
|
1171
1231
|
/** One-line human summary. */
|
|
1172
1232
|
summary: string;
|
|
1173
1233
|
}
|
|
@@ -1242,6 +1302,87 @@ export interface DocsStatsResult {
|
|
|
1242
1302
|
readonly summary: string;
|
|
1243
1303
|
}
|
|
1244
1304
|
|
|
1305
|
+
/**
|
|
1306
|
+
* Parameters for `docs.rot` — the docs-rot report (T14111).
|
|
1307
|
+
*
|
|
1308
|
+
* Read-only and git-only: it reads tracked markdown and git history, never
|
|
1309
|
+
* the docs store, so it runs the same in CI and locally.
|
|
1310
|
+
*
|
|
1311
|
+
* @task T14111 (Epic T14106)
|
|
1312
|
+
*/
|
|
1313
|
+
export interface DocsRotParams {
|
|
1314
|
+
/**
|
|
1315
|
+
* Git revision range `<base>..<head>` of a merged change. When set, the
|
|
1316
|
+
* report also lists the docs whose `covers:` globs match a file the range
|
|
1317
|
+
* changed (and that the range did not update itself).
|
|
1318
|
+
*/
|
|
1319
|
+
readonly changed?: string;
|
|
1320
|
+
}
|
|
1321
|
+
|
|
1322
|
+
/**
|
|
1323
|
+
* A doc whose declared `covers:` code changed without the doc changing.
|
|
1324
|
+
*
|
|
1325
|
+
* @task T14111
|
|
1326
|
+
*/
|
|
1327
|
+
export interface DocsRotCoverageHit {
|
|
1328
|
+
/** Repo-relative path of the doc. */
|
|
1329
|
+
readonly doc: string;
|
|
1330
|
+
/** Covered files that changed (sorted, repo-relative). */
|
|
1331
|
+
readonly files: readonly string[];
|
|
1332
|
+
}
|
|
1333
|
+
|
|
1334
|
+
/**
|
|
1335
|
+
* A group of docs that duplicate each other: identical bodies, or titles
|
|
1336
|
+
* close enough that one is a fork of the other.
|
|
1337
|
+
*
|
|
1338
|
+
* @task T14111
|
|
1339
|
+
*/
|
|
1340
|
+
export interface DocsRotDuplicate {
|
|
1341
|
+
/** Why the docs were grouped: `content` (same body) or `title`. */
|
|
1342
|
+
readonly reason: 'content' | 'title';
|
|
1343
|
+
/** Repo-relative paths of the duplicates (sorted). */
|
|
1344
|
+
readonly docs: readonly string[];
|
|
1345
|
+
}
|
|
1346
|
+
|
|
1347
|
+
/**
|
|
1348
|
+
* A doc nothing ties to the repo: a `covers:` glob that matches no tracked
|
|
1349
|
+
* file, or a `docs/` file no other tracked file references.
|
|
1350
|
+
*
|
|
1351
|
+
* @task T14111
|
|
1352
|
+
*/
|
|
1353
|
+
export interface DocsRotOrphan {
|
|
1354
|
+
/** Repo-relative path of the doc. */
|
|
1355
|
+
readonly doc: string;
|
|
1356
|
+
/** `dead-covers` (globs listed in `globs`) or `unreferenced`. */
|
|
1357
|
+
readonly reason: 'dead-covers' | 'unreferenced';
|
|
1358
|
+
/** The covers globs that match nothing (only for `dead-covers`). */
|
|
1359
|
+
readonly globs?: readonly string[];
|
|
1360
|
+
}
|
|
1361
|
+
|
|
1362
|
+
/**
|
|
1363
|
+
* Result of `docs.rot` — stale, duplicate and orphaned docs (T14111).
|
|
1364
|
+
*
|
|
1365
|
+
* @task T14111
|
|
1366
|
+
*/
|
|
1367
|
+
export interface DocsRotResult {
|
|
1368
|
+
/** Tracked markdown docs scanned. */
|
|
1369
|
+
readonly scanned: number;
|
|
1370
|
+
/** Docs that declare `covers:`. */
|
|
1371
|
+
readonly covering: number;
|
|
1372
|
+
/** Docs whose covered code changed after the doc last changed on main. */
|
|
1373
|
+
readonly stale: readonly DocsRotCoverageHit[];
|
|
1374
|
+
/** Duplicate doc groups. */
|
|
1375
|
+
readonly duplicates: readonly DocsRotDuplicate[];
|
|
1376
|
+
/** Orphaned docs. */
|
|
1377
|
+
readonly orphans: readonly DocsRotOrphan[];
|
|
1378
|
+
/** Docs the `changed` range flags for update (empty without `changed`). */
|
|
1379
|
+
readonly flagged: readonly DocsRotCoverageHit[];
|
|
1380
|
+
/** Wall time of the scan in milliseconds. */
|
|
1381
|
+
readonly durationMs: number;
|
|
1382
|
+
/** One-line human summary. */
|
|
1383
|
+
readonly summary: string;
|
|
1384
|
+
}
|
|
1385
|
+
|
|
1245
1386
|
// ============================================================================
|
|
1246
1387
|
// Discriminated Union (DocsOps)
|
|
1247
1388
|
// ============================================================================
|
|
@@ -1269,7 +1410,59 @@ export type DocsOps =
|
|
|
1269
1410
|
| { op: 'docs.unlink-decision'; params: DocsDecisionLinkParams; result: DocsDecisionLinkResult }
|
|
1270
1411
|
| { op: 'docs.doctor'; params: DocsDoctorParams; result: DocsDoctorResult }
|
|
1271
1412
|
| { op: 'docs.migrate'; params: DocsMigrateParams; result: DocsMigrateResult }
|
|
1272
|
-
| { op: 'docs.
|
|
1413
|
+
| { op: 'docs.modernize'; params: DocsModernizeParams; result: DocsModernizeResult }
|
|
1414
|
+
| { op: 'docs.stats'; params: DocsStatsParams; result: DocsStatsResult }
|
|
1415
|
+
| { op: 'docs.rot'; params: DocsRotParams; result: DocsRotResult };
|
|
1416
|
+
|
|
1417
|
+
/**
|
|
1418
|
+
* Parameters for `docs.modernize` (T14113) — dry run by default.
|
|
1419
|
+
*/
|
|
1420
|
+
export interface DocsModernizeParams {
|
|
1421
|
+
/** Folder to modernize, relative to the project root or absolute. Required unless `rollback`. */
|
|
1422
|
+
readonly path?: string;
|
|
1423
|
+
/** Execute the plan; without it the run is a dry run that writes nothing. */
|
|
1424
|
+
readonly apply?: boolean;
|
|
1425
|
+
/** Apply this saved plan JSON verbatim instead of re-planning. */
|
|
1426
|
+
readonly planFile?: string;
|
|
1427
|
+
/** Save the plan JSON here. */
|
|
1428
|
+
readonly out?: string;
|
|
1429
|
+
/** Roll back the apply run with this id. */
|
|
1430
|
+
readonly rollback?: string;
|
|
1431
|
+
/** Extra folder names to skip, comma-separated. */
|
|
1432
|
+
readonly exclude?: string;
|
|
1433
|
+
/** Path of a `DocsModernizeOverrides` JSON file keyed by root-relative path. */
|
|
1434
|
+
readonly overrides?: string;
|
|
1435
|
+
/** Use this kind for every file instead of classifying. */
|
|
1436
|
+
readonly kind?: string;
|
|
1437
|
+
/** Ingest every file into the store (task-owned, slugless) and leave the folder untouched. */
|
|
1438
|
+
readonly storeOnly?: boolean;
|
|
1439
|
+
/** Apply even when the root is not a clean git checkout. */
|
|
1440
|
+
readonly allowDirty?: boolean;
|
|
1441
|
+
/**
|
|
1442
|
+
* Rewrite relative links to planned docs as `[[slug]]` wikilinks (opt-in).
|
|
1443
|
+
* By default links stay markdown, re-pointed at the new paths (T14185).
|
|
1444
|
+
*/
|
|
1445
|
+
readonly wikilinks?: boolean;
|
|
1446
|
+
/** Modernize the docs already in the store (re-kind, re-slug with aliases, ADR numbers). */
|
|
1447
|
+
readonly store?: boolean;
|
|
1448
|
+
}
|
|
1449
|
+
|
|
1450
|
+
/**
|
|
1451
|
+
* Result of `docs.modernize`: the plan (dry run, apply) and the receipt
|
|
1452
|
+
* (apply, rollback).
|
|
1453
|
+
*/
|
|
1454
|
+
export interface DocsModernizeResult {
|
|
1455
|
+
/** What ran. */
|
|
1456
|
+
readonly mode: 'dry-run' | 'apply' | 'rollback';
|
|
1457
|
+
/** The plan, or null for a rollback. */
|
|
1458
|
+
readonly plan: DocsModernizePlan | null;
|
|
1459
|
+
/** Where the plan was saved, when `out` was given. */
|
|
1460
|
+
readonly planPath: string | null;
|
|
1461
|
+
/** The receipt, or null for a dry run. */
|
|
1462
|
+
readonly receipt: DocsModernizeReceipt | null;
|
|
1463
|
+
/** One-line human summary. */
|
|
1464
|
+
readonly summary: string;
|
|
1465
|
+
}
|
|
1273
1466
|
|
|
1274
1467
|
/**
|
|
1275
1468
|
* Parameters for `docs.migrate` — the T13360 legacy docs migration (spec §5).
|
|
@@ -1336,4 +1529,6 @@ export type DocsOp =
|
|
|
1336
1529
|
| 'docs.unlink-decision'
|
|
1337
1530
|
| 'docs.doctor'
|
|
1338
1531
|
| 'docs.migrate'
|
|
1339
|
-
| 'docs.
|
|
1532
|
+
| 'docs.modernize'
|
|
1533
|
+
| 'docs.stats'
|
|
1534
|
+
| 'docs.rot';
|
|
@@ -1098,3 +1098,69 @@ export interface AdoptWorktreeResult {
|
|
|
1098
1098
|
*/
|
|
1099
1099
|
projectInfo: 'seeded' | 'present' | 'skipped';
|
|
1100
1100
|
}
|
|
1101
|
+
|
|
1102
|
+
/**
|
|
1103
|
+
* Options for `cleanupMergedWork` (T14142): remove what merged work left
|
|
1104
|
+
* behind, after proving each item redundant.
|
|
1105
|
+
*
|
|
1106
|
+
* @task T14142
|
|
1107
|
+
*/
|
|
1108
|
+
export interface MergedCleanupOpts {
|
|
1109
|
+
/** Project root (the main checkout; its hash names the canonical worktree root). */
|
|
1110
|
+
projectRoot: string;
|
|
1111
|
+
/**
|
|
1112
|
+
* Tasks whose work merged (the sweep's merged PR, or a release's tasks).
|
|
1113
|
+
* Either way a task is in scope only while stored `done` or `cancelled`:
|
|
1114
|
+
* an open task (more PRs to come) keeps its worktree and branches.
|
|
1115
|
+
*/
|
|
1116
|
+
taskIds?: readonly string[];
|
|
1117
|
+
/** List everything without deleting. Default `true`: deleting is opt-in. */
|
|
1118
|
+
dryRun?: boolean;
|
|
1119
|
+
/** Also delete merged task branches on `origin`. Default `true`. */
|
|
1120
|
+
remote?: boolean;
|
|
1121
|
+
}
|
|
1122
|
+
|
|
1123
|
+
/**
|
|
1124
|
+
* One item the cleanup considered: removed (or, on a dry run, removable), or
|
|
1125
|
+
* kept with the reason.
|
|
1126
|
+
*
|
|
1127
|
+
* @task T14142
|
|
1128
|
+
*/
|
|
1129
|
+
export interface MergedCleanupItem {
|
|
1130
|
+
/** Worktree or nested-copy path, or branch name. */
|
|
1131
|
+
target: string;
|
|
1132
|
+
/** Owning task, when the target names one. */
|
|
1133
|
+
taskId: string | null;
|
|
1134
|
+
/** Branch tip (branches only): what a restore pushes back. */
|
|
1135
|
+
sha?: string;
|
|
1136
|
+
/** True when removed (dry run: when it would be removed). */
|
|
1137
|
+
removed: boolean;
|
|
1138
|
+
/** Why it was kept, or what proved it redundant. */
|
|
1139
|
+
reason: string;
|
|
1140
|
+
/** Bytes on disk (worktrees and nested copies; 0 for branches). */
|
|
1141
|
+
bytes: number;
|
|
1142
|
+
}
|
|
1143
|
+
|
|
1144
|
+
/**
|
|
1145
|
+
* Result of `cleanupMergedWork` (T14142).
|
|
1146
|
+
*
|
|
1147
|
+
* @task T14142
|
|
1148
|
+
*/
|
|
1149
|
+
export interface MergedCleanupResult {
|
|
1150
|
+
/** Whether nothing was deleted. */
|
|
1151
|
+
dryRun: boolean;
|
|
1152
|
+
/** The default branch merges were proven against (`origin/<name>`). */
|
|
1153
|
+
base: string;
|
|
1154
|
+
/** Canonical task worktrees. */
|
|
1155
|
+
worktrees: MergedCleanupItem[];
|
|
1156
|
+
/** Local `task/*` branches. */
|
|
1157
|
+
localBranches: MergedCleanupItem[];
|
|
1158
|
+
/** `origin` `task/*` branches. */
|
|
1159
|
+
remoteBranches: MergedCleanupItem[];
|
|
1160
|
+
/** Repository copies nested inside worktrees. */
|
|
1161
|
+
nestedCopies: MergedCleanupItem[];
|
|
1162
|
+
/** Bytes removed (dry run: that would be removed). */
|
|
1163
|
+
bytesReclaimed: number;
|
|
1164
|
+
/** Why nothing was considered (the fetch failed, no base branch); absent when it ran. */
|
|
1165
|
+
skippedReason?: string;
|
|
1166
|
+
}
|
package/src/project-context.ts
CHANGED
|
@@ -11,6 +11,8 @@
|
|
|
11
11
|
* @adr ADR-013
|
|
12
12
|
*/
|
|
13
13
|
|
|
14
|
+
import type { VerificationGate } from './task.js';
|
|
15
|
+
|
|
14
16
|
/** Detected project ecosystem. Matches the writer in `detectProjectType`. */
|
|
15
17
|
export type ProjectType =
|
|
16
18
|
| 'node'
|
|
@@ -78,6 +80,14 @@ export interface ProjectEvidenceContext {
|
|
|
78
80
|
* @task T12634
|
|
79
81
|
*/
|
|
80
82
|
ciSatisfies?: boolean;
|
|
83
|
+
/**
|
|
84
|
+
* Gates a probed `deploy:` atom satisfies (T14083). No default: unset or
|
|
85
|
+
* empty, a deploy atom satisfies nothing, and never `testsPassed` unless
|
|
86
|
+
* listed here.
|
|
87
|
+
*
|
|
88
|
+
* @task T14083
|
|
89
|
+
*/
|
|
90
|
+
deploySatisfies?: VerificationGate[];
|
|
81
91
|
/**
|
|
82
92
|
* Which required checks attest each gate for `ci:<pr>`. Each list must be a
|
|
83
93
|
* subset of the required-check list; a gate without a list refuses `ci:`.
|
|
@@ -106,6 +116,24 @@ export interface ProjectEvidenceContext {
|
|
|
106
116
|
* refused (E_EVIDENCE_RUNTIME_PATH_PROTECTED). Default: none.
|
|
107
117
|
*/
|
|
108
118
|
runtimePaths?: string[];
|
|
119
|
+
/**
|
|
120
|
+
* Further git repositories this project's evidence may come from (an SDK in
|
|
121
|
+
* a separate repository, T14078). A typed gate names one by `repo`; any
|
|
122
|
+
* repository not declared here is refused.
|
|
123
|
+
*/
|
|
124
|
+
repositories?: EvidenceRepositoryDeclaration[];
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
/**
|
|
128
|
+
* A git repository outside the project that typed gates may run in (T14078).
|
|
129
|
+
*/
|
|
130
|
+
export interface EvidenceRepositoryDeclaration {
|
|
131
|
+
/** Name a typed gate's `repo` field uses. */
|
|
132
|
+
name: string;
|
|
133
|
+
/** The checkout's root, relative to the CLEO store root or absolute. */
|
|
134
|
+
path: string;
|
|
135
|
+
/** Why the project's evidence comes from it. */
|
|
136
|
+
purpose: string;
|
|
109
137
|
}
|
|
110
138
|
|
|
111
139
|
/**
|
|
@@ -163,6 +191,11 @@ export interface ProjectContext {
|
|
|
163
191
|
build?: {
|
|
164
192
|
command?: string;
|
|
165
193
|
outputDir?: string;
|
|
194
|
+
/**
|
|
195
|
+
* Globs, relative to the project root, of scripts that run heavy tools:
|
|
196
|
+
* `cleo run` charges them as heavy whatever their content shows (T14162).
|
|
197
|
+
*/
|
|
198
|
+
heavyScripts?: string[];
|
|
166
199
|
};
|
|
167
200
|
directories?: {
|
|
168
201
|
source?: string;
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Standing release authorization (T14141 · owner decision D11215): a grant the
|
|
3
|
+
* owner signs with the enrolled owner key so a non-interactive
|
|
4
|
+
* `cleo release cut --yes` (an agent) may tag without a typed terminal
|
|
5
|
+
* confirmation.
|
|
6
|
+
*
|
|
7
|
+
* @task T14141
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* What a grant covers: `canary` (`-canary.N` versions), `prerelease` (any
|
|
12
|
+
* `-suffix`), `stable` (no suffix), or one exact `v`-prefixed version.
|
|
13
|
+
*/
|
|
14
|
+
export type ReleaseAuthorizationScope = 'canary' | 'prerelease' | 'stable' | `v${string}`;
|
|
15
|
+
|
|
16
|
+
/** One owner-signed standing release authorization. */
|
|
17
|
+
export interface ReleaseAuthorizationGrant {
|
|
18
|
+
/** Grant id (`ra-<hex>`), named in the cut audit row and the tag message. */
|
|
19
|
+
id: string;
|
|
20
|
+
/** Versions the grant covers. */
|
|
21
|
+
scope: ReleaseAuthorizationScope;
|
|
22
|
+
/** Why the owner granted it. */
|
|
23
|
+
reason: string;
|
|
24
|
+
/** ISO time the grant was issued. */
|
|
25
|
+
issuedAt: string;
|
|
26
|
+
/** ISO time it stops counting (at most 30 days after issue). */
|
|
27
|
+
expiresAt: string;
|
|
28
|
+
/** Optional cap on cuts it may allow; null = no limit (D11215). */
|
|
29
|
+
uses: number | null;
|
|
30
|
+
/** The owner decision recorded for the grant (BRAIN decision id). */
|
|
31
|
+
decisionId: string;
|
|
32
|
+
/** Revocations on record when it was issued; a shorter revocation list later means tampering. */
|
|
33
|
+
revocationsAtIssue: number;
|
|
34
|
+
/** Enrolled owner public key (hex) that signed it. */
|
|
35
|
+
ownerPubkey: string;
|
|
36
|
+
/** Ed25519 signature (hex) over the grant's fields. */
|
|
37
|
+
sig: string;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/** A grant as `cleo release authorize --list` reports it. */
|
|
41
|
+
export interface ReleaseAuthorizationStatus extends ReleaseAuthorizationGrant {
|
|
42
|
+
/** Whether it currently allows a cut, and if not why. */
|
|
43
|
+
state: 'active' | 'expired' | 'used-up' | 'revoked' | 'tampered';
|
|
44
|
+
/** Cuts it has allowed (audit rows and tags naming it). */
|
|
45
|
+
used: number;
|
|
46
|
+
/** Why it is tampered, when it is. */
|
|
47
|
+
why?: string;
|
|
48
|
+
}
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Independent per-AC review of a PR (T14122, council run
|
|
3
|
+
* 20261028T155822Z-293ed9f0, blocking amendment 2 of D11211).
|
|
4
|
+
*
|
|
5
|
+
* A reviewer other than the task's author judges each acceptance criterion
|
|
6
|
+
* from the PR diff and the criterion text alone, and records a verdict under
|
|
7
|
+
* its own CLEO session, bound to the PR head it reviewed. The merge sweep
|
|
8
|
+
* (T14101) records `satisfies:` only from a `met` verdict on the merged head;
|
|
9
|
+
* PR text can neither create nor waive one.
|
|
10
|
+
*
|
|
11
|
+
* @task T14122
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
/** One acceptance criterion as a reviewer sees it: its alias and its text. */
|
|
15
|
+
export interface ReviewPacketCriterion {
|
|
16
|
+
/** `AC1`, `AC2`, … */
|
|
17
|
+
alias: string;
|
|
18
|
+
/** The criterion text. */
|
|
19
|
+
text: string;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* What a reviewer is given for one PR and task: the diff at the PR head and
|
|
24
|
+
* the task's criteria. The PR title, body, comments and commit messages are
|
|
25
|
+
* never included, so the author's `Closes:` / `Refs:` lines and summary cannot
|
|
26
|
+
* reach the reviewer.
|
|
27
|
+
*/
|
|
28
|
+
export interface ReviewPacket {
|
|
29
|
+
/** The PR. */
|
|
30
|
+
prNumber: number;
|
|
31
|
+
/** The PR head the diff was taken at (`headRefOid`). */
|
|
32
|
+
headSha: string;
|
|
33
|
+
/** The task under review. */
|
|
34
|
+
taskId: string;
|
|
35
|
+
/** The task's criteria, in ordinal order. */
|
|
36
|
+
acs: ReviewPacketCriterion[];
|
|
37
|
+
/** The PR diff at `headSha`, without the paths in `withheldPaths`. */
|
|
38
|
+
diff: string;
|
|
39
|
+
/** Changed paths left out of `diff` because they carry the author's own account (changesets). */
|
|
40
|
+
withheldPaths: string[];
|
|
41
|
+
/** sha256 of the head, the criteria and the diff: a verdict names it to prove what was reviewed. */
|
|
42
|
+
packetSha256: string;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/** The identities that authored a task: its claim holders and the session that created it. */
|
|
46
|
+
export interface ReviewAuthors {
|
|
47
|
+
/** CLEO session ids. */
|
|
48
|
+
sessionIds: string[];
|
|
49
|
+
/** Agent ids (`CLEO_AGENT_ID`, spawn handles). */
|
|
50
|
+
agentIds: string[];
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/** One reviewer's verdict on one criterion of one task, for one PR head. */
|
|
54
|
+
export interface ReviewVerdict {
|
|
55
|
+
/** Verdict id (uuid). */
|
|
56
|
+
id: string;
|
|
57
|
+
/** The task. */
|
|
58
|
+
taskId: string;
|
|
59
|
+
/** The criterion alias (`AC2`). */
|
|
60
|
+
ac: string;
|
|
61
|
+
/** The criterion's stable id (`task_acceptance_criteria.id`). */
|
|
62
|
+
acId: string;
|
|
63
|
+
/** The PR. */
|
|
64
|
+
prNumber: number;
|
|
65
|
+
/** The PR head the reviewer judged (`headRefOid`), never the merge sha. */
|
|
66
|
+
headSha: string;
|
|
67
|
+
/** Whether the diff implements the criterion. */
|
|
68
|
+
verdict: 'met' | 'unmet';
|
|
69
|
+
/** Why, in the reviewer's words. */
|
|
70
|
+
reason: string;
|
|
71
|
+
/** Who reviewed: never one of `authors`. */
|
|
72
|
+
reviewer: { sessionId: string; agentId: string | null };
|
|
73
|
+
/** The task's authors when the verdict was recorded, so a reader can re-check independence. */
|
|
74
|
+
authors: ReviewAuthors;
|
|
75
|
+
/** The {@link ReviewPacket.packetSha256} the reviewer was given. */
|
|
76
|
+
packetSha256: string;
|
|
77
|
+
/**
|
|
78
|
+
* The id of an earlier non-author `unmet` verdict on the same head that
|
|
79
|
+
* this `met` answers (T14128). Without it, a later `met` cannot clear that
|
|
80
|
+
* `unmet`, so shopping for a friendlier reviewer stays visible.
|
|
81
|
+
*/
|
|
82
|
+
answers?: string;
|
|
83
|
+
/** ISO-8601 time it was recorded. */
|
|
84
|
+
createdAt: string;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/** Why one criterion has no usable verdict on a head. */
|
|
88
|
+
export interface ReviewGap {
|
|
89
|
+
/** The criterion alias. */
|
|
90
|
+
ac: string;
|
|
91
|
+
/**
|
|
92
|
+
* `missing`: none recorded; `unmet`: the latest says unmet; `stale`: only
|
|
93
|
+
* older heads have one; `author`: the latest on the head came from one of
|
|
94
|
+
* the task's own authors (a re-check of the record-time refusal).
|
|
95
|
+
*/
|
|
96
|
+
kind: 'missing' | 'unmet' | 'stale' | 'author';
|
|
97
|
+
/** A one-line reason, e.g. `AC2: no verdict on head abc1234 (latest is for 9f00e12)`. */
|
|
98
|
+
reason: string;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* An `unmet` verdict a later `met` answered on the same head (T14137), so an
|
|
103
|
+
* owner can see who cleared whose finding.
|
|
104
|
+
*/
|
|
105
|
+
export interface ReviewAnswer {
|
|
106
|
+
/** The criterion. */
|
|
107
|
+
ac: string;
|
|
108
|
+
/** The answered `unmet` verdict and its reviewer. */
|
|
109
|
+
unmet: { id: string; reviewer: ReviewVerdict['reviewer'] };
|
|
110
|
+
/** The `met` verdict that answered it and its reviewer. */
|
|
111
|
+
met: { id: string; reviewer: ReviewVerdict['reviewer'] };
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
/** The criteria a set of verdicts proves met on a head, and the gaps. */
|
|
115
|
+
export interface ReviewJudgement {
|
|
116
|
+
/** The head judged against. */
|
|
117
|
+
headSha: string;
|
|
118
|
+
/** Criteria whose latest verdict on `headSha` is `met`. */
|
|
119
|
+
met: string[];
|
|
120
|
+
/** Criteria without a `met` verdict on `headSha`, each with why. */
|
|
121
|
+
gaps: ReviewGap[];
|
|
122
|
+
}
|
package/src/session-journal.ts
CHANGED
|
@@ -112,7 +112,13 @@ export const sessionJournalEntrySchema = z.object({
|
|
|
112
112
|
tasksCompleted: z.array(z.string()).optional(),
|
|
113
113
|
|
|
114
114
|
// Doctor summary (T1262 absorbed)
|
|
115
|
-
/**
|
|
115
|
+
/**
|
|
116
|
+
* Compact result of `scanBrainNoise` run at session-end.
|
|
117
|
+
*
|
|
118
|
+
* @deprecated T14120: no longer written. Session end stopped running the
|
|
119
|
+
* brain scan (it held `cleo session end` for ~120 s on a large store); kept
|
|
120
|
+
* so older journal entries still parse. Use `cleo memory doctor`.
|
|
121
|
+
*/
|
|
116
122
|
doctorSummary: sessionJournalDoctorSummarySchema.optional(),
|
|
117
123
|
|
|
118
124
|
// Debrief summary
|
package/src/task-record.ts
CHANGED
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
* @epic T4654
|
|
9
9
|
*/
|
|
10
10
|
|
|
11
|
-
import type { AcceptanceItem, TaskVerification } from './task.js';
|
|
11
|
+
import type { AcceptanceItem, TaskClaim, TaskVerification } from './task.js';
|
|
12
12
|
|
|
13
13
|
/** Omitted source fields and their UTF-8 serialized sizes on partial records. */
|
|
14
14
|
export interface RecordProjectionDisclosure {
|
|
@@ -119,6 +119,11 @@ export interface TaskRecord extends RecordProjectionDisclosure {
|
|
|
119
119
|
* @task T944
|
|
120
120
|
*/
|
|
121
121
|
severity?: string | null;
|
|
122
|
+
/**
|
|
123
|
+
* The agent work lease held on this task (T12502); absent when unclaimed.
|
|
124
|
+
* Surfaced so `cleo show` reads back what `cleo claim` wrote (T14165).
|
|
125
|
+
*/
|
|
126
|
+
claim?: TaskClaim;
|
|
122
127
|
}
|
|
123
128
|
|
|
124
129
|
/**
|