@cleocode/contracts 2026.10.17 → 2026.10.18

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 (46) hide show
  1. package/dist/__tests__/goal-contract.test.d.ts +9 -0
  2. package/dist/__tests__/goal-contract.test.d.ts.map +1 -0
  3. package/dist/__tests__/goal-contract.test.js +107 -0
  4. package/dist/__tests__/goal-contract.test.js.map +1 -0
  5. package/dist/acceptance-gate-schema.d.ts +19 -0
  6. package/dist/acceptance-gate-schema.d.ts.map +1 -1
  7. package/dist/acceptance-gate-schema.js +28 -0
  8. package/dist/acceptance-gate-schema.js.map +1 -1
  9. package/dist/cloud/api.d.ts +6 -0
  10. package/dist/cloud/api.d.ts.map +1 -1
  11. package/dist/cloud/api.js +16 -0
  12. package/dist/cloud/api.js.map +1 -1
  13. package/dist/done-plan.d.ts +4 -2
  14. package/dist/done-plan.d.ts.map +1 -1
  15. package/dist/goal-contract.d.ts +404 -0
  16. package/dist/goal-contract.d.ts.map +1 -0
  17. package/dist/goal-contract.js +37 -0
  18. package/dist/goal-contract.js.map +1 -0
  19. package/dist/index.d.ts +5 -3
  20. package/dist/index.d.ts.map +1 -1
  21. package/dist/index.js +3 -2
  22. package/dist/index.js.map +1 -1
  23. package/dist/invariants/sync-write-invariants.js +1 -1
  24. package/dist/invariants/sync-write-invariants.js.map +1 -1
  25. package/dist/lean.d.ts +28 -0
  26. package/dist/lean.d.ts.map +1 -1
  27. package/dist/nexus-cloud.d.ts +6 -0
  28. package/dist/nexus-cloud.d.ts.map +1 -1
  29. package/dist/nexus-cloud.js +6 -0
  30. package/dist/nexus-cloud.js.map +1 -1
  31. package/dist/row-identity.d.ts +16 -0
  32. package/dist/row-identity.d.ts.map +1 -1
  33. package/dist/task.d.ts +19 -0
  34. package/dist/task.d.ts.map +1 -1
  35. package/package.json +2 -2
  36. package/src/__tests__/goal-contract.test.ts +112 -0
  37. package/src/acceptance-gate-schema.ts +31 -0
  38. package/src/cloud/api.ts +16 -0
  39. package/src/done-plan.ts +4 -2
  40. package/src/goal-contract.ts +438 -0
  41. package/src/index.ts +39 -0
  42. package/src/invariants/sync-write-invariants.ts +1 -1
  43. package/src/lean.ts +30 -0
  44. package/src/nexus-cloud.ts +7 -0
  45. package/src/row-identity.ts +16 -0
  46. package/src/task.ts +16 -0
@@ -0,0 +1,438 @@
1
+ /**
2
+ * goal/v1 — the contract a goal runtime executes against, and what CLEO reads
3
+ * back from a run.
4
+ *
5
+ * CLEO owns the goal protocol; OpenCode-Goal (OCG) is the goal runtime (owner
6
+ * decision 2026-10-16, epic T13791). The two stay separate packages and talk
7
+ * only through the `cleo` CLI and LAFS envelopes:
8
+ *
9
+ * 1. `cleo goal draft` writes a {@link GoalContract} (`goal.yaml`) from a
10
+ * task's acceptance criteria.
11
+ * 2. The runtime locks the contract by the sha256 of its bytes, runs it, and
12
+ * writes a {@link GoalOutcome}.
13
+ * 3. `cleo goal close` reads the outcome and records evidence for each passing
14
+ * criterion on the gate it demonstrates, via {@link GoalCriterion.proves}.
15
+ *
16
+ * The shapes mirror OCG's `src/contract/types.ts` field for field, in OCG's
17
+ * snake_case YAML spelling, so one file means the same thing on both sides.
18
+ * The only addition is the optional per-criterion `proves` list.
19
+ *
20
+ * Relation to `GoalRecord` (`goal.ts`): a GoalRecord is CLEO's own
21
+ * per-agent, turn-budgeted loop state, whose criteria are free text. A goal/v1
22
+ * contract is the portable, hash-locked agreement a runtime executes; its
23
+ * criteria carry checks. They share no fields.
24
+ *
25
+ * Types only (gate 10): parsing and validation live in core.
26
+ *
27
+ * @packageDocumentation
28
+ * @module @cleocode/contracts/goal-contract
29
+ *
30
+ * @epic T13791
31
+ * @task T13792
32
+ */
33
+
34
+ /** The schema tag every goal/v1 contract carries. */
35
+ export const GOAL_CONTRACT_SCHEMA = 'goal/v1' as const;
36
+
37
+ /** Expected result of a {@link GoalCommandCheck}. Absent fields are not checked; no field at all means `exit: 0`. */
38
+ export interface GoalCheckExpect {
39
+ /** Required exit code. */
40
+ exit?: number;
41
+ /** Text stdout must contain. */
42
+ stdout_contains?: string;
43
+ /** Regular expression stdout must match. */
44
+ stdout_regex?: string;
45
+ }
46
+
47
+ /** The host runs a shell command and checks its result. */
48
+ export interface GoalCommandCheck {
49
+ /** Discriminant. */
50
+ kind: 'command';
51
+ /** Shell command, run from the goal workspace. */
52
+ run: string;
53
+ /** Expected result. */
54
+ expect?: GoalCheckExpect;
55
+ /** Timeout in seconds (runtime default 300). */
56
+ timeout?: number;
57
+ /** Repeat count, 1 to 10; every run must pass. */
58
+ runs?: number;
59
+ /** The command reaches a live service. */
60
+ live?: boolean;
61
+ }
62
+
63
+ /** The host checks that a path exists (or, with `exists: false`, that it does not). */
64
+ export interface GoalFileCheck {
65
+ /** Discriminant. */
66
+ kind: 'file';
67
+ /** Workspace-relative path. */
68
+ path: string;
69
+ /** Expected existence (default true). */
70
+ exists?: boolean;
71
+ }
72
+
73
+ /** The host checks that a file contains text or matches a regex. */
74
+ export interface GoalContainsCheck {
75
+ /** Discriminant. */
76
+ kind: 'contains';
77
+ /** Workspace-relative path. */
78
+ path: string;
79
+ /** Literal text to find. */
80
+ text?: string;
81
+ /** Regular expression to match. */
82
+ regex?: string;
83
+ }
84
+
85
+ /** The host checks that a pattern occurs nowhere (optionally within `paths`). */
86
+ export interface GoalAbsentCheck {
87
+ /** Discriminant. */
88
+ kind: 'absent';
89
+ /** Pattern that must not occur. */
90
+ pattern: string;
91
+ /** Paths to search; absent means the workspace. */
92
+ paths?: string[];
93
+ }
94
+
95
+ /** The host checks that the given paths are unchanged since the run's base commit (a protected oracle). */
96
+ export interface GoalDiffCheck {
97
+ /** Discriminant. */
98
+ kind: 'diff';
99
+ /** Paths (or globs) that must not change. */
100
+ paths: string[];
101
+ }
102
+
103
+ /** An independent verifier agent answers the question, citing quotes the host re-reads. */
104
+ export interface GoalVerifierCheck {
105
+ /** Discriminant. */
106
+ kind: 'verifier';
107
+ /** Question the verifier must answer. */
108
+ ask: string;
109
+ }
110
+
111
+ /** The owner signs the criterion off. */
112
+ export interface GoalHumanCheck {
113
+ /** Discriminant. */
114
+ kind: 'human';
115
+ /** Question the owner answers. */
116
+ ask: string;
117
+ }
118
+
119
+ /** How a criterion is proven. */
120
+ export type GoalCheck =
121
+ | GoalCommandCheck
122
+ | GoalFileCheck
123
+ | GoalContainsCheck
124
+ | GoalAbsentCheck
125
+ | GoalDiffCheck
126
+ | GoalVerifierCheck
127
+ | GoalHumanCheck;
128
+
129
+ /** Discriminant of {@link GoalCheck}. */
130
+ export type GoalCheckKind = GoalCheck['kind'];
131
+
132
+ /** Check kinds the host itself runs; invariants may use only these. */
133
+ export const GOAL_HOST_CHECK_KINDS = ['command', 'file', 'contains', 'absent', 'diff'] as const;
134
+
135
+ /**
136
+ * A CLEO acceptance-criterion reference: exactly the three target forms of a
137
+ * `satisfies:` evidence atom (`evidence-atom-schema.ts`, ADR-079-r2 §2.1).
138
+ *
139
+ * - positional `T1234#AC2` — drifts when the task's ACs are renumbered;
140
+ * - canonical `T1234#<lowercase uuid>` — the criterion's stable id, preferred
141
+ * in a hash-locked contract;
142
+ * - pinned `T1234#AC2@20260524223045` — an alias pinned to a 14-digit
143
+ * `YYYYMMDDhhmmss` version.
144
+ *
145
+ * The template types only shape the value (`${bigint}` still admits `-2`, and
146
+ * the uuid part is any dashed string). Core validates every reference with the
147
+ * real regexes: `SATISFIES_TASK_ID_REGEX` (`^T[0-9]{1,7}$`), `AC_ALIAS_REGEX`
148
+ * (`^AC[0-9]{1,4}$`), `AC_UUID_REGEX` and `SATISFIES_VERSION_PIN_REGEX`
149
+ * (`^[0-9]{14}$`).
150
+ */
151
+ export type GoalAcRef =
152
+ | `T${bigint}#AC${bigint}`
153
+ | `T${bigint}#${string}-${string}-${string}-${string}-${string}`
154
+ | `T${bigint}#AC${bigint}@${bigint}`;
155
+
156
+ /**
157
+ * One criterion (`C<n>`) or invariant (`I<n>`) of a goal.
158
+ *
159
+ * Invariants are always essential and always host-checked.
160
+ */
161
+ export interface GoalCriterion {
162
+ /** `C1`, `C2`, … for criteria; `I1`, `I2`, … for invariants. */
163
+ id: string;
164
+ /** End state that is true when the criterion holds. */
165
+ statement: string;
166
+ /** The goal is not done until every essential criterion passes. */
167
+ essential: boolean;
168
+ /** How the criterion is proven. */
169
+ check: GoalCheck;
170
+ /**
171
+ * CLEO acceptance criteria this criterion's evidence demonstrates. When the
172
+ * criterion passes, `cleo goal close` links its evidence to each one with
173
+ * `satisfies:`. Absent means the criterion proves no CLEO AC.
174
+ */
175
+ proves?: GoalAcRef[];
176
+ }
177
+
178
+ /** A decision the agent made without the owner, open to veto. */
179
+ export interface GoalAssumption {
180
+ /** `A1`, `A2`, … */
181
+ id: string;
182
+ /** What was assumed. */
183
+ text: string;
184
+ /** Why. */
185
+ rationale?: string;
186
+ /** Whether it can be undone cheaply. */
187
+ reversible?: boolean;
188
+ /** Owner disposition. */
189
+ status: 'assumed' | 'confirmed' | 'vetoed';
190
+ }
191
+
192
+ /** One plan step. */
193
+ export interface GoalStep {
194
+ /** `S1`, `S2`, … */
195
+ id: string;
196
+ /** What the step does. */
197
+ title: string;
198
+ /** Criterion ids the step proves. */
199
+ proves: string[];
200
+ /** Step ids that must finish first. */
201
+ depends_on: string[];
202
+ }
203
+
204
+ /** Optional goal priority; absent sorts last. */
205
+ export type GoalPriority = 'low' | 'medium' | 'high';
206
+
207
+ /**
208
+ * Run budget. In YAML, `wall` is a duration (`"90m"`) and `tokens` a count
209
+ * (`400k`); the parsed form holds milliseconds and integers.
210
+ */
211
+ export interface GoalBudget {
212
+ /** Agent turns. */
213
+ turns?: number;
214
+ /** Active wall-clock time, milliseconds (YAML `wall`). */
215
+ wallMs?: number;
216
+ /** Input + output + reasoning tokens. */
217
+ tokens?: number;
218
+ /** Spend ceiling in US dollars. */
219
+ cost_usd?: number;
220
+ }
221
+
222
+ /** Contract changes the owner lets the agent apply to its own contract. */
223
+ export type GoalAmendClass = 'timeout' | 'budget' | 'plan' | 'recover';
224
+
225
+ /** Owner-set autonomy policy. */
226
+ export interface GoalAutonomy {
227
+ /** Whether the agent may ask the owner questions mid-run (`defer` queues them). */
228
+ questions: 'defer' | 'allow';
229
+ /** What an owner message does to a running goal. */
230
+ on_user_message: 'steer' | 'pause';
231
+ /** What an interrupt does. */
232
+ on_interrupt: 'pause' | 'resume-on-message';
233
+ /** Amendment classes the agent may apply itself (default none). */
234
+ amend: GoalAmendClass[];
235
+ /** What the stall detector does. */
236
+ on_stall: 'pause' | 'continue';
237
+ }
238
+
239
+ /** How completion is decided. */
240
+ export type GoalVerificationMode = 'host' | 'host+verifier' | 'strict';
241
+
242
+ /** The CLEO evidence gates a goal can declare evidence for. */
243
+ export type GoalCleoGate = 'implemented' | 'testsPassed' | 'qaPassed';
244
+
245
+ /**
246
+ * A CLEO task the goal serves (OCG `CleoTaskLink`).
247
+ *
248
+ * The bare id links the task for reporting. `acs` is OCG's older per-gate
249
+ * claim of which AC aliases a gate's evidence proves; per-criterion
250
+ * {@link GoalCriterion.proves} is the precise form and what `cleo goal draft`
251
+ * writes. An AC neither form claims stays open.
252
+ */
253
+ export interface GoalTaskLink {
254
+ /** Task id (`T123`). */
255
+ id: string;
256
+ /** Per-gate AC aliases (`AC1`, …) the gate's evidence proves. */
257
+ acs?: Partial<Record<GoalCleoGate, string[]>>;
258
+ }
259
+
260
+ /** A goal/v1 contract: written by the owner (or `cleo goal draft`), locked by hash when a run starts. */
261
+ export interface GoalContract {
262
+ /** Always {@link GOAL_CONTRACT_SCHEMA}. */
263
+ schema: typeof GOAL_CONTRACT_SCHEMA;
264
+ /** Kebab-case slug; equals the goal's directory name. */
265
+ id: string;
266
+ /** Short title (under 80 characters). */
267
+ title: string;
268
+ /** Optional priority. */
269
+ priority?: GoalPriority;
270
+ /** `"<slug>@<lock-prefix>"` of the goal this one replaces. */
271
+ supersedes?: string;
272
+ /** The owner's own words, kept verbatim as the authoritative source. */
273
+ intent: { verbatim: string };
274
+ /** The one end state that is true when the goal is done. */
275
+ outcome: string;
276
+ /** Why the goal matters. */
277
+ why?: string;
278
+ /** What is in and out of scope. */
279
+ scope: { in: string[]; out: string[] };
280
+ /** At least one non-goal. */
281
+ non_goals: string[];
282
+ /** Constraints the run must respect. */
283
+ constraints: string[];
284
+ /** At least one criterion, at least one essential. */
285
+ criteria: GoalCriterion[];
286
+ /** Host-checked conditions that must hold throughout. */
287
+ invariants: GoalCriterion[];
288
+ /** Root-relative execution workspace (default: project root). */
289
+ workspace?: string;
290
+ /** The CLEO tasks this goal serves. Absent means no CLEO behaviour. */
291
+ cleo?: { tasks: GoalTaskLink[] };
292
+ /** Paths the agent must not modify. */
293
+ protect: string[];
294
+ /** Decisions made without the owner. */
295
+ assumptions: GoalAssumption[];
296
+ /** Ordered plan. */
297
+ plan: GoalStep[];
298
+ /** Run budget. */
299
+ budget: GoalBudget;
300
+ /** Stop conditions. */
301
+ stop: { when?: string; escalate_when: string[] };
302
+ /** Autonomy policy. */
303
+ autonomy: GoalAutonomy;
304
+ /** Verification policy. */
305
+ verification: {
306
+ /** How completion is decided (default `host+verifier`). */
307
+ mode: GoalVerificationMode;
308
+ /** Verifier rejections before the run escalates, 1 to 10 (default 3). */
309
+ max_rejections: number;
310
+ /** Folders the verifier may read. */
311
+ read: string[];
312
+ /** Verifier model, `providerID/modelID[#variant]`. */
313
+ model?: string;
314
+ /** Verifier effort. */
315
+ effort?: string;
316
+ };
317
+ /** Execution settings. */
318
+ execution: { agent?: string };
319
+ /** Free-form metadata: any YAML value, opaque to CLEO. */
320
+ meta: Record<string, unknown>;
321
+ }
322
+
323
+ /** Who produced a criterion's verdict. */
324
+ export type GoalVerdictSource = 'host' | 'verifier' | 'verifier-fallback' | 'human';
325
+
326
+ /** A quote the verifier cited, which the host re-read from the file. */
327
+ export interface GoalVerifierQuote {
328
+ /** Workspace-relative path. */
329
+ path: string;
330
+ /** Exact text quoted. */
331
+ quote: string;
332
+ }
333
+
334
+ /** Evidence of a passing or failing `command` check. */
335
+ export interface GoalCommandEvidence {
336
+ /** Discriminant. */
337
+ kind: 'command';
338
+ /** The command as run. */
339
+ command: string;
340
+ /** Exit code of the last run. */
341
+ exitCode: number;
342
+ /**
343
+ * Path of a vitest-shaped JSON report the command wrote, when it ran tests.
344
+ * `cleo goal close` records it as a `test-run:` atom.
345
+ */
346
+ reportPath?: string;
347
+ /**
348
+ * sha256 (hex) of the report bytes the run produced. `cleo goal close`
349
+ * refuses a `test-run:` whose file does not hash to it, or that has none.
350
+ */
351
+ reportSha256?: string;
352
+ /** Test files the report covers. */
353
+ testFiles?: string[];
354
+ }
355
+
356
+ /**
357
+ * Evidence of a `file`, `contains`, `absent` or `diff` check.
358
+ *
359
+ * A passing `diff` proves the paths did NOT change (a protected oracle held),
360
+ * so it must never become `implemented` / `files:` evidence.
361
+ */
362
+ export interface GoalPathEvidence {
363
+ /** Discriminant: the check kind that ran. */
364
+ kind: 'file' | 'contains' | 'absent' | 'diff';
365
+ /** Repo-relative paths the check examined. */
366
+ paths: string[];
367
+ }
368
+
369
+ /** Evidence of a verifier check. */
370
+ export interface GoalVerifierEvidence {
371
+ /** Discriminant. */
372
+ kind: 'verifier';
373
+ /** The verifier's verdict. */
374
+ verdict: 'proven' | 'not_proven' | 'contradicted';
375
+ /** Quotes the verifier cited. */
376
+ quotes: GoalVerifierQuote[];
377
+ /** The verifier's reason. */
378
+ reason?: string;
379
+ }
380
+
381
+ /**
382
+ * Evidence of a human sign-off, as the runtime reports it. It is not CLEO
383
+ * evidence on its own: it counts only when CLEO's own owner or HITL record
384
+ * backs it.
385
+ */
386
+ export interface GoalHumanEvidence {
387
+ /** Discriminant. */
388
+ kind: 'human';
389
+ /** Who signed off. */
390
+ by?: string;
391
+ /** The owner's note. */
392
+ note?: string;
393
+ }
394
+
395
+ /** What a criterion's check produced. */
396
+ export type GoalCheckEvidence =
397
+ | GoalCommandEvidence
398
+ | GoalPathEvidence
399
+ | GoalVerifierEvidence
400
+ | GoalHumanEvidence;
401
+
402
+ /** The verdict on one criterion or invariant. */
403
+ export interface GoalCriterionOutcome {
404
+ /** Criterion or invariant id (`C1`, `I1`). */
405
+ id: string;
406
+ /** Whether it passed. */
407
+ pass: boolean;
408
+ /** Who decided. */
409
+ by: GoalVerdictSource;
410
+ /** Human-readable detail. */
411
+ detail?: string;
412
+ /** What the check produced. */
413
+ evidence: GoalCheckEvidence;
414
+ }
415
+
416
+ /**
417
+ * What a goal run produced, written by the runtime and read by
418
+ * `cleo goal close`.
419
+ *
420
+ * `lock` ties the outcome to the exact contract bytes; `headCommit` is the
421
+ * tree the checks ran on.
422
+ */
423
+ export interface GoalOutcome {
424
+ /** Always `goal-outcome/v1`. */
425
+ schema: 'goal-outcome/v1';
426
+ /** Goal slug ({@link GoalContract.id}). */
427
+ goal: string;
428
+ /** Runtime run id. */
429
+ runId?: string;
430
+ /** sha256 (hex) of the `goal.yaml` bytes the run locked. */
431
+ lock: string;
432
+ /** Commit the run started from (the diff base), or null when none. */
433
+ baseCommit: string | null;
434
+ /** Commit the checks ran on. */
435
+ headCommit: string;
436
+ /** Per-criterion and per-invariant verdicts. */
437
+ results: GoalCriterionOutcome[];
438
+ }
package/src/index.ts CHANGED
@@ -44,6 +44,7 @@ export {
44
44
  lintGateSchema,
45
45
  manualGateSchema,
46
46
  testCountReportSchema,
47
+ testCountSummarySchema,
47
48
  testGateSchema,
48
49
  } from './acceptance-gate-schema.js';
49
50
  // === Provider Adapter Contracts ===
@@ -748,6 +749,41 @@ export {
748
749
  isTerminalGoalStatus,
749
750
  isValidGoalTargetTaskId,
750
751
  } from './goal.js';
752
+ // === goal/v1 protocol: contract, task link, outcome (T13792 · Epic T13791) ===
753
+ export type {
754
+ GoalAbsentCheck,
755
+ GoalAcRef,
756
+ GoalAmendClass,
757
+ GoalAssumption,
758
+ GoalAutonomy,
759
+ GoalBudget,
760
+ GoalCheck,
761
+ GoalCheckEvidence,
762
+ GoalCheckExpect,
763
+ GoalCheckKind,
764
+ GoalCleoGate,
765
+ GoalCommandCheck,
766
+ GoalCommandEvidence,
767
+ GoalContainsCheck,
768
+ GoalContract,
769
+ GoalCriterion,
770
+ GoalCriterionOutcome,
771
+ GoalDiffCheck,
772
+ GoalFileCheck,
773
+ GoalHumanCheck,
774
+ GoalHumanEvidence,
775
+ GoalOutcome,
776
+ GoalPathEvidence,
777
+ GoalPriority,
778
+ GoalStep,
779
+ GoalTaskLink,
780
+ GoalVerdictSource,
781
+ GoalVerificationMode,
782
+ GoalVerifierCheck,
783
+ GoalVerifierEvidence,
784
+ GoalVerifierQuote,
785
+ } from './goal-contract.js';
786
+ export { GOAL_CONTRACT_SCHEMA, GOAL_HOST_CHECK_KINDS } from './goal-contract.js';
751
787
  // === Graph Intelligence Types (T512, T529, T1862, T9145) ===
752
788
  export type {
753
789
  AmbiguousProvenance,
@@ -902,6 +938,8 @@ export type {
902
938
  LeanConfig,
903
939
  LeanDebtItem,
904
940
  LeanDebtReport,
941
+ LeanGainMetric,
942
+ LeanGainReport,
905
943
  LeanLevel,
906
944
  LeanLevelSource,
907
945
  } from './lean.js';
@@ -3133,6 +3171,7 @@ export {
3133
3171
  NEXUS_DEVICE_LIST_STATES,
3134
3172
  NEXUS_DEVICE_STATE_UNKNOWN,
3135
3173
  NEXUS_DEVICE_STATES,
3174
+ NEXUS_FEATURE_MANIFEST_SNAPSHOT_AUTHORITATIVE,
3136
3175
  NEXUS_FEATURE_PROJECT_INITIAL_KEY,
3137
3176
  NEXUS_FORBIDDEN_ERRORS,
3138
3177
  NEXUS_FORBIDDEN_REASONS,
@@ -245,7 +245,7 @@ export const SYNC_WRITE_INVARIANTS: readonly SyncWriteInvariant[] = Object.freez
245
245
  ['tasks_session_handoff_entries'],
246
246
  ['trg_tasks_session_handoff_no_update'],
247
247
  ['H2'],
248
- 'handoff entries are never updated',
248
+ 'handoff entries are never updated, and one session has one (the natural uid over the session merges a peer’s; T13777)',
249
249
  ),
250
250
  trigger(
251
251
  'task.claim.lease-iso',
package/src/lean.ts CHANGED
@@ -69,3 +69,33 @@ export interface LeanDebtReport {
69
69
  /** Keys that already had a `lean-debt` task, so none was filed. */
70
70
  readonly alreadyFiled: readonly string[];
71
71
  }
72
+
73
+ /** One measured metric on the `cleo lean gain` scoreboard (T13669). */
74
+ export interface LeanGainMetric {
75
+ /** What was measured, e.g. `Source lines of code`. */
76
+ readonly name: string;
77
+ /** ct-lean as a share of the no-skill baseline (0.35 = 35%). */
78
+ readonly ctLeanShare: number;
79
+ /** Ponytail 5.1.0 as a share of the same baseline, for comparison. */
80
+ readonly ponytailShare: number;
81
+ }
82
+
83
+ /** The measured scoreboard `cleo lean gain` prints: benchmark numbers, never per-repo ones. */
84
+ export interface LeanGainReport {
85
+ /** Scoreboard heading naming the run the numbers come from. */
86
+ readonly heading: string;
87
+ /** Canonical research doc the numbers come from (`cleo docs fetch <slug>`). */
88
+ readonly source: string;
89
+ /** How the numbers were measured, in one line. */
90
+ readonly method: string;
91
+ /** Size, cost and time metrics. */
92
+ readonly metrics: readonly LeanGainMetric[];
93
+ /** Hidden checks passed per arm, e.g. `{ baseline: '23/24', ponytail: '24/24', ctLean: '24/24' }`. */
94
+ readonly hiddenChecks: {
95
+ readonly baseline: string;
96
+ readonly ponytail: string;
97
+ readonly ctLean: string;
98
+ };
99
+ /** The honesty boundary, always present. */
100
+ readonly note: string;
101
+ }
@@ -274,6 +274,13 @@ export const nexusCloudStatusCheckSchema = z.object({
274
274
  */
275
275
  export const NEXUS_FEATURE_PROJECT_INITIAL_KEY = 'project.initial-key';
276
276
 
277
+ /**
278
+ * The E3 `features` entry of a server whose checkpoint/v3 rule skips the tables a manifest lists as
279
+ * `snapshotAuthoritative` (cleo-nexus #45, cleocode T13777). A journal checkpoint sends the list only to
280
+ * such a server.
281
+ */
282
+ export const NEXUS_FEATURE_MANIFEST_SNAPSHOT_AUTHORITATIVE = 'manifest.snapshot-authoritative';
283
+
277
284
  /** `NexusStatus` (E3 `GET /v1/status`). */
278
285
  export const nexusCloudStatusSchema = z.object({
279
286
  serverTime: isoTime.optional(),
@@ -114,6 +114,22 @@ export interface RowIdentitySpec {
114
114
  readonly birthFacts?: readonly string[];
115
115
  /** `natural` relation tables: the symmetric relation types. */
116
116
  readonly symmetric?: SymmetricEdge;
117
+ /**
118
+ * `natural`: nullable key columns. A row whose value in one of them is NULL
119
+ * gets no uid and stays on its device: it is never captured, never filled
120
+ * and never pending (T12914). SQLite admits several NULLs in a composite
121
+ * primary key, so such rows would otherwise fold into one uid and diverge.
122
+ */
123
+ readonly localWhenNull?: readonly string[];
124
+ /**
125
+ * `natural`: the order columns that pick, among rows sharing one natural
126
+ * key, the FIRST (T13777). Only that row gets the uid; a later row with the
127
+ * same key gets none and stays on its device: it is never captured, never
128
+ * filled and never pending. For a key the schema does not make unique (a
129
+ * write-once table whose legacy DDL lacks the UNIQUE), so a duplicate never
130
+ * wedges the fill.
131
+ */
132
+ readonly localUnlessFirst?: readonly string[];
117
133
  /**
118
134
  * `minted`: every uid is random, never derived from content, including for
119
135
  * existing rows. Required for `portable-secret` tables.
package/src/task.ts CHANGED
@@ -303,6 +303,13 @@ export type EvidenceAtom =
303
303
  * longer matches, unless `ci:<pr>` or a full tool run carries the gate.
304
304
  */
305
305
  treeHash?: string;
306
+ /**
307
+ * HEAD as of the run, when it differs from `headSha` because commits
308
+ * landed on origin's default branch after the run (T13784). Those
309
+ * commits stand only while they touch none of the change's files, the
310
+ * test files the report ran, or the shared test configs.
311
+ */
312
+ runHeadSha?: string;
306
313
  /** Test files the report covered, relative to the bound checkout (capped, T12965). */
307
314
  testFiles?: string[];
308
315
  /** Total test files the report covered; exceeds `testFiles.length` when capped. */
@@ -400,6 +407,8 @@ export type EvidenceAtom =
400
407
  affectedPackages?: string[];
401
408
  /** The test projects the affected run actually selected (incl. non-package projects). */
402
409
  affectedProjects?: string[];
410
+ /** Test files outside every package the affected run named (T13754). */
411
+ affectedTestFiles?: string[];
403
412
  /** Affected DEPENDENT packages with no test project (a changed one refuses the scope). */
404
413
  untestedPackages?: string[];
405
414
  /**
@@ -602,6 +611,13 @@ export type EvidenceAtom =
602
611
  baseSha: string;
603
612
  baseRunId: number;
604
613
  }>;
614
+ /**
615
+ * The merge commit's own run FAILED, but only on the flaky-quarantine
616
+ * budget: every failing job's tests all passed (T13809). `descendantSha`
617
+ * is the later green main run standing in. Each job records its failing
618
+ * merge-commit run.
619
+ */
620
+ nonTestFailures?: Array<{ name: string; mergeRunId: number }>;
605
621
  /**
606
622
  * The PR edited a pinned workflow, so only default-branch `push` runs
607
623
  * attested it; its own `pull_request` runs (which ran the edited