@cleocode/contracts 2026.9.20 → 2026.9.22
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 +1 -1
- package/dist/__tests__/decide.test.d.ts +7 -0
- package/dist/__tests__/decide.test.d.ts.map +1 -0
- package/dist/__tests__/decide.test.js +91 -0
- package/dist/__tests__/decide.test.js.map +1 -0
- package/dist/__tests__/evidence-atom-schema.test.js +19 -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 +5 -0
- package/dist/acceptance-gate-schema.d.ts.map +1 -1
- package/dist/acceptance-gate-schema.js +26 -0
- package/dist/acceptance-gate-schema.js.map +1 -1
- package/dist/acceptance-gate.d.ts +70 -3
- package/dist/acceptance-gate.d.ts.map +1 -1
- package/dist/backup-manifest.d.ts +13 -2
- package/dist/backup-manifest.d.ts.map +1 -1
- package/dist/branch-lock.d.ts +11 -0
- package/dist/branch-lock.d.ts.map +1 -1
- package/dist/branch-lock.js +31 -4
- package/dist/branch-lock.js.map +1 -1
- package/dist/cloud/api.d.ts +607 -0
- package/dist/cloud/api.d.ts.map +1 -0
- package/dist/cloud/api.js +417 -0
- package/dist/cloud/api.js.map +1 -0
- package/dist/cloud/envelope.d.ts +84 -0
- package/dist/cloud/envelope.d.ts.map +1 -0
- package/dist/cloud/envelope.js +54 -0
- package/dist/cloud/envelope.js.map +1 -0
- package/dist/cloud/ids.d.ts +30 -0
- package/dist/cloud/ids.d.ts.map +1 -0
- package/dist/cloud/ids.js +32 -0
- package/dist/cloud/ids.js.map +1 -0
- package/dist/cloud/index.d.ts +17 -0
- package/dist/cloud/index.d.ts.map +1 -0
- package/dist/cloud/index.js +17 -0
- package/dist/cloud/index.js.map +1 -0
- package/dist/data-accessor.d.ts +23 -3
- package/dist/data-accessor.d.ts.map +1 -1
- package/dist/data-accessor.js.map +1 -1
- package/dist/decide.d.ts +333 -0
- package/dist/decide.d.ts.map +1 -0
- package/dist/decide.js +184 -0
- package/dist/decide.js.map +1 -0
- package/dist/dispatch/operations-registry.d.ts.map +1 -1
- package/dist/dispatch/operations-registry.js +56 -0
- package/dist/dispatch/operations-registry.js.map +1 -1
- package/dist/done-plan.d.ts +330 -0
- package/dist/done-plan.d.ts.map +1 -0
- package/dist/done-plan.js +17 -0
- package/dist/done-plan.js.map +1 -0
- package/dist/evidence-atom-schema.d.ts +29 -44
- package/dist/evidence-atom-schema.d.ts.map +1 -1
- package/dist/evidence-atom-schema.js +48 -8
- package/dist/evidence-atom-schema.js.map +1 -1
- package/dist/exit-codes.d.ts +40 -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/graph.d.ts +40 -0
- package/dist/graph.d.ts.map +1 -1
- package/dist/index.d.ts +13 -6
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -0
- package/dist/index.js.map +1 -1
- package/dist/memory/observe.d.ts +16 -0
- package/dist/memory/observe.d.ts.map +1 -1
- package/dist/operations/__tests__/release-shared-surface.test.d.ts +10 -0
- package/dist/operations/__tests__/release-shared-surface.test.d.ts.map +1 -0
- package/dist/operations/__tests__/release-shared-surface.test.js +84 -0
- package/dist/operations/__tests__/release-shared-surface.test.js.map +1 -0
- package/dist/operations/dialectic.d.ts +16 -0
- package/dist/operations/dialectic.d.ts.map +1 -1
- package/dist/operations/docs.d.ts +5 -2
- package/dist/operations/docs.d.ts.map +1 -1
- package/dist/operations/docs.js.map +1 -1
- package/dist/operations/memory.d.ts +48 -0
- package/dist/operations/memory.d.ts.map +1 -1
- package/dist/operations/nexus-scope-map.d.ts +8 -0
- package/dist/operations/nexus-scope-map.d.ts.map +1 -1
- package/dist/operations/nexus-scope-map.js +8 -0
- package/dist/operations/nexus-scope-map.js.map +1 -1
- package/dist/operations/nexus-user-profile.d.ts +27 -1
- package/dist/operations/nexus-user-profile.d.ts.map +1 -1
- package/dist/operations/nexus-user-profile.js +11 -1
- package/dist/operations/nexus-user-profile.js.map +1 -1
- package/dist/operations/nexus.d.ts +394 -3
- package/dist/operations/nexus.d.ts.map +1 -1
- package/dist/operations/release.d.ts +259 -0
- package/dist/operations/release.d.ts.map +1 -1
- package/dist/operations/release.js +130 -1
- package/dist/operations/release.js.map +1 -1
- package/dist/operations/session.d.ts +6 -4
- package/dist/operations/session.d.ts.map +1 -1
- package/dist/operations/tasks.d.ts +6 -0
- package/dist/operations/tasks.d.ts.map +1 -1
- package/dist/operations/tasks.js +1 -0
- package/dist/operations/tasks.js.map +1 -1
- package/dist/operations/validate.d.ts +5 -0
- package/dist/operations/validate.d.ts.map +1 -1
- package/dist/operations/worktree.d.ts +125 -1
- package/dist/operations/worktree.d.ts.map +1 -1
- package/dist/process-probe.d.ts +17 -0
- package/dist/process-probe.d.ts.map +1 -0
- package/dist/process-probe.js +21 -0
- package/dist/process-probe.js.map +1 -0
- package/dist/project-context.d.ts +44 -2
- package/dist/project-context.d.ts.map +1 -1
- package/dist/project-lifecycle.d.ts +143 -0
- package/dist/project-lifecycle.d.ts.map +1 -0
- package/dist/project-lifecycle.js +21 -0
- package/dist/project-lifecycle.js.map +1 -0
- package/dist/release/plan.d.ts +6 -2
- package/dist/release/plan.d.ts.map +1 -1
- package/dist/release/plan.js +8 -2
- package/dist/release/plan.js.map +1 -1
- package/dist/release/plan.test.js +6 -1
- package/dist/release/plan.test.js.map +1 -1
- package/dist/table-classification.d.ts +208 -0
- package/dist/table-classification.d.ts.map +1 -0
- package/dist/table-classification.js +23 -0
- package/dist/table-classification.js.map +1 -0
- package/dist/task.d.ts +97 -1
- package/dist/task.d.ts.map +1 -1
- package/package.json +6 -2
- package/schemas/gate-result.schema.json +43 -0
- package/src/__tests__/__snapshots__/operations-registry.test.ts.snap +1 -1
- package/src/__tests__/decide.test.ts +139 -0
- package/src/__tests__/evidence-atom-schema.test.ts +24 -1
- package/src/__tests__/memory-wire-shapes.test.ts +3 -0
- package/src/acceptance-gate-schema.ts +29 -0
- package/src/acceptance-gate.ts +68 -3
- package/src/backup-manifest.ts +13 -2
- package/src/branch-lock.ts +36 -4
- package/src/cloud/api.ts +512 -0
- package/src/cloud/envelope.ts +63 -0
- package/src/cloud/ids.ts +51 -0
- package/src/cloud/index.ts +16 -0
- package/src/data-accessor.ts +24 -3
- package/src/decide.ts +355 -0
- package/src/dispatch/operations-registry.ts +59 -0
- package/src/done-plan.ts +370 -0
- package/src/evidence-atom-schema.ts +51 -9
- package/src/exit-codes.ts +42 -0
- package/src/graph.ts +44 -0
- package/src/index.ts +118 -0
- package/src/memory/observe.ts +16 -0
- package/src/operations/__tests__/release-shared-surface.test.ts +112 -0
- package/src/operations/dialectic.ts +17 -0
- package/src/operations/docs.ts +5 -2
- package/src/operations/memory.ts +48 -0
- package/src/operations/nexus-scope-map.ts +9 -0
- package/src/operations/nexus-user-profile.ts +29 -1
- package/src/operations/nexus.ts +416 -3
- package/src/operations/release.ts +197 -0
- package/src/operations/session.ts +6 -4
- package/src/operations/tasks.ts +7 -0
- package/src/operations/validate.ts +5 -0
- package/src/operations/worktree.ts +133 -1
- package/src/process-probe.ts +21 -0
- package/src/project-context.ts +42 -2
- package/src/project-lifecycle.ts +149 -0
- package/src/release/plan.test.ts +6 -1
- package/src/release/plan.ts +8 -2
- package/src/table-classification.ts +232 -0
- package/src/task.ts +102 -2
package/src/done-plan.ts
ADDED
|
@@ -0,0 +1,370 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Contracts for the read-only `cleo done --plan` evidence planner.
|
|
3
|
+
*
|
|
4
|
+
* The planner derives, without executing a tool or writing a row, the
|
|
5
|
+
* evidence `cleo done` would record for each required verification gate:
|
|
6
|
+
* the implemented change set and where it came from, the tool runs and
|
|
7
|
+
* whether each already has a fresh cached result, which acceptance criteria
|
|
8
|
+
* map to evidence deterministically, and the blockers in the order an agent
|
|
9
|
+
* must clear them.
|
|
10
|
+
*
|
|
11
|
+
* Spec: `verify-streamlined-design` §3.2 and §7 step 1-2.
|
|
12
|
+
*
|
|
13
|
+
* @task T12623
|
|
14
|
+
* @task T12624
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
import type { VerificationGate } from './task.js';
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Where a task's implemented change set was found, first match wins.
|
|
21
|
+
*
|
|
22
|
+
* - `pr` — a merged PR that cites the task; files read from its merge commit.
|
|
23
|
+
* - `branch` — the unmerged task branch diffed against its merge-base with
|
|
24
|
+
* origin's default branch.
|
|
25
|
+
* - `docs` — attached documents and linked decisions of a research, spike or
|
|
26
|
+
* documentation task.
|
|
27
|
+
* - `none` — nothing references the task yet.
|
|
28
|
+
*/
|
|
29
|
+
export type ChangeSetSource = 'pr' | 'branch' | 'docs' | 'none';
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* How the repository the change set was read from was chosen.
|
|
33
|
+
*
|
|
34
|
+
* - `declared` — `CLEO_EVIDENCE_GIT_ROOT`, `GIT_WORK_TREE` or
|
|
35
|
+
* `evidence.gitRoot`; outranks every inference.
|
|
36
|
+
* - `invocation-worktree` — the caller's own worktree of this project.
|
|
37
|
+
* - `task-worktree` — the task's registered worktree, used when invoked from
|
|
38
|
+
* the main checkout.
|
|
39
|
+
* - `store` — the CLEO store root or its single child checkout.
|
|
40
|
+
*/
|
|
41
|
+
export type ChangeSetRootSource = 'declared' | 'invocation-worktree' | 'task-worktree' | 'store';
|
|
42
|
+
|
|
43
|
+
/** One concrete, runnable next step. */
|
|
44
|
+
export interface DoneNextStep {
|
|
45
|
+
/** Shell command the agent runs next. */
|
|
46
|
+
command: string;
|
|
47
|
+
/** Why this step clears the blocker. */
|
|
48
|
+
why: string;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Blocker vocabulary, in the order the planner reports them.
|
|
53
|
+
*
|
|
54
|
+
* @see DONE_PLAN_BLOCKER_ORDER in core for the ranking.
|
|
55
|
+
*/
|
|
56
|
+
export type DonePlanBlockerCode =
|
|
57
|
+
| 'git-root'
|
|
58
|
+
| 'dirty-tree'
|
|
59
|
+
| 'no-change-set'
|
|
60
|
+
| 'pr-ambiguous'
|
|
61
|
+
| 'pr-unverified'
|
|
62
|
+
| 'pr-stacked'
|
|
63
|
+
| 'pr-reverted'
|
|
64
|
+
| 'merge-commit-missing'
|
|
65
|
+
| 'decision-missing'
|
|
66
|
+
| 'tool-unresolved'
|
|
67
|
+
| 'tool-failed'
|
|
68
|
+
| 'typed-gate-failed'
|
|
69
|
+
| 'ac-mapping-needed'
|
|
70
|
+
| 'manual-gate'
|
|
71
|
+
| 'epic-rollup'
|
|
72
|
+
| 'run-from-worktree'
|
|
73
|
+
| 'checkout-required'
|
|
74
|
+
| 'evidence-refused'
|
|
75
|
+
| 'completion-refused';
|
|
76
|
+
|
|
77
|
+
/** A reason `cleo done` would stop, with exactly one next step. */
|
|
78
|
+
export interface DonePlanBlocker {
|
|
79
|
+
/** Stable machine code. */
|
|
80
|
+
code: DonePlanBlockerCode;
|
|
81
|
+
/** Human-readable statement of what is missing. */
|
|
82
|
+
message: string;
|
|
83
|
+
/** The one next step that clears it. */
|
|
84
|
+
next: DoneNextStep;
|
|
85
|
+
/** Original evidence error code when the blocker wraps a validator refusal. */
|
|
86
|
+
cause?: string;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/** A merged PR that cites the task. */
|
|
90
|
+
export interface ChangeSetPrCandidate {
|
|
91
|
+
/** PR number. */
|
|
92
|
+
prNumber: number;
|
|
93
|
+
/** PR title. */
|
|
94
|
+
title: string;
|
|
95
|
+
/** Head branch the PR merged from. */
|
|
96
|
+
headRefName: string;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/** A document attached to a research, spike or documentation task. */
|
|
100
|
+
export interface ChangeSetDoc {
|
|
101
|
+
/** Attachment or blob identifier. */
|
|
102
|
+
id: string;
|
|
103
|
+
/** Stable slug, when the doc has one. */
|
|
104
|
+
slug: string | null;
|
|
105
|
+
/** Store-relative path of the bytes the `files:` atom will hash. */
|
|
106
|
+
path: string;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* The implemented change set derived for one task.
|
|
111
|
+
*
|
|
112
|
+
* `implementedEvidence` is the atom string the existing ADR-051 validators
|
|
113
|
+
* receive unchanged; there is no second validation path.
|
|
114
|
+
*/
|
|
115
|
+
export interface TaskChangeSet {
|
|
116
|
+
/** Where the change set came from. */
|
|
117
|
+
source: ChangeSetSource;
|
|
118
|
+
/** Absolute path of the repository every git and gh call ran in. */
|
|
119
|
+
executionRoot: string;
|
|
120
|
+
/** Why {@link executionRoot} was chosen. */
|
|
121
|
+
rootSource: ChangeSetRootSource;
|
|
122
|
+
/**
|
|
123
|
+
* Component PR whose change the (integration) `prNumber` landed on the
|
|
124
|
+
* default branch (T12671). Evidence is then `pr:<component>@<prNumber>`.
|
|
125
|
+
*/
|
|
126
|
+
componentPrNumber?: number;
|
|
127
|
+
/** Merged PR number (`source === 'pr'`). */
|
|
128
|
+
prNumber?: number;
|
|
129
|
+
/**
|
|
130
|
+
* Verified merge commit the files were read from (`source === 'pr'`). For a
|
|
131
|
+
* stacked PR this is the BASE PR's merge into the default branch.
|
|
132
|
+
*/
|
|
133
|
+
mergeCommitSha?: string;
|
|
134
|
+
/**
|
|
135
|
+
* Set when the task's PR merged into another branch (a stacked PR) and the
|
|
136
|
+
* task is attributed to that branch's own PR once it reached the default
|
|
137
|
+
* branch.
|
|
138
|
+
*/
|
|
139
|
+
stackedOn?: { baseRef: string; basePrNumber?: number };
|
|
140
|
+
/** Branch tip commit (`source === 'branch'`). */
|
|
141
|
+
commitSha?: string;
|
|
142
|
+
/** Ref that was diffed (`HEAD` or `task/<id>`), for `source === 'branch'`. */
|
|
143
|
+
headRef?: string;
|
|
144
|
+
/** Origin default branch the merge-base was taken against. */
|
|
145
|
+
baseRef?: string;
|
|
146
|
+
/** Merge-base commit between {@link baseRef} and {@link headRef}. */
|
|
147
|
+
mergeBase?: string;
|
|
148
|
+
/** Repo-relative paths that still exist in the change set (the `files:` atom). */
|
|
149
|
+
files: string[];
|
|
150
|
+
/** Repo-relative paths the change set deleted; listed in the receipt, never in `files:`. */
|
|
151
|
+
deletedFiles: string[];
|
|
152
|
+
/** Attached docs (`source === 'docs'`). */
|
|
153
|
+
docs: ChangeSetDoc[];
|
|
154
|
+
/** Decision IDs linked to the task (`source === 'docs'`). */
|
|
155
|
+
decisions: string[];
|
|
156
|
+
/** Every merged PR that cited the task, before disambiguation. */
|
|
157
|
+
candidates: ChangeSetPrCandidate[];
|
|
158
|
+
/**
|
|
159
|
+
* D11151: the task's OTHER own-branch PRs when it shipped across several,
|
|
160
|
+
* oldest first. Each is recorded as its own `implemented` attempt before the
|
|
161
|
+
* primary (latest) PR, which is what the stored gate evidence ends up citing.
|
|
162
|
+
*/
|
|
163
|
+
additionalPrs?: Array<{
|
|
164
|
+
prNumber: number;
|
|
165
|
+
mergeCommitSha?: string;
|
|
166
|
+
files: string[];
|
|
167
|
+
deletedFiles: string[];
|
|
168
|
+
implementedEvidence: string | null;
|
|
169
|
+
}>;
|
|
170
|
+
/** Planned `implemented` atoms (without `satisfies:`), or null when none derive. */
|
|
171
|
+
implementedEvidence: string | null;
|
|
172
|
+
/** Blockers found while deriving the change set. */
|
|
173
|
+
blockers: DonePlanBlocker[];
|
|
174
|
+
/** Non-blocking observations, e.g. PR discovery that could not reach `gh`. */
|
|
175
|
+
warnings: string[];
|
|
176
|
+
/**
|
|
177
|
+
* The merged-PR lookup failed (e.g. `gh` unavailable), so a non-PR change set
|
|
178
|
+
* does not prove the change is unmerged (T12656).
|
|
179
|
+
*/
|
|
180
|
+
prDiscoveryFailed?: boolean;
|
|
181
|
+
/**
|
|
182
|
+
* Whether the task's PR has merged to the default branch, as the PR lookup
|
|
183
|
+
* found it — independent of `source` (T12656 review): a merged PR whose
|
|
184
|
+
* `pr:` check was refused still falls back to the task branch, and the
|
|
185
|
+
* branch outlives a squash merge. Absent when no PR was examined.
|
|
186
|
+
*/
|
|
187
|
+
mergeState?: ChangeSetMergeState;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
/** Whether a task's change has merged to the default branch. */
|
|
191
|
+
export type ChangeSetMergeState = 'merged' | 'unmerged' | 'unknown';
|
|
192
|
+
|
|
193
|
+
/** Planned state of one verification gate. */
|
|
194
|
+
export interface DonePlanGate {
|
|
195
|
+
/** Gate name. */
|
|
196
|
+
gate: VerificationGate;
|
|
197
|
+
/** Whether the project's verification policy requires it. */
|
|
198
|
+
required: boolean;
|
|
199
|
+
/** Whether the task already has the gate recorded as passed. */
|
|
200
|
+
passed: boolean;
|
|
201
|
+
/** Planned `--evidence` string (with `satisfies:`), or null when nothing is planned. */
|
|
202
|
+
evidence: string | null;
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
/**
|
|
206
|
+
* Cache state of a tool run the plan needs.
|
|
207
|
+
*
|
|
208
|
+
* - `fresh-pass` / `fresh-fail` — an ADR-061 cache entry exists for the
|
|
209
|
+
* current HEAD, dirty fingerprint and execution root.
|
|
210
|
+
* - `miss` — `cleo done` would run the tool.
|
|
211
|
+
* - `not-applicable` — the resolver says the tool does not apply here.
|
|
212
|
+
* - `unresolved` — no command resolves for the tool.
|
|
213
|
+
*/
|
|
214
|
+
export type DonePlanToolCacheState =
|
|
215
|
+
| 'fresh-pass'
|
|
216
|
+
| 'fresh-fail'
|
|
217
|
+
| 'miss'
|
|
218
|
+
| 'not-applicable'
|
|
219
|
+
| 'unresolved';
|
|
220
|
+
|
|
221
|
+
/** One tool run a gate needs. The planner never executes it. */
|
|
222
|
+
export interface DonePlanToolRun {
|
|
223
|
+
/** Canonical tool name used in the `tool:` atom. */
|
|
224
|
+
tool: string;
|
|
225
|
+
/** Gate the result satisfies. */
|
|
226
|
+
gate: VerificationGate;
|
|
227
|
+
/** Resolved command line, or null when unresolved. */
|
|
228
|
+
command: string | null;
|
|
229
|
+
/** Resolver source (`project-context`, `language-default`, …). */
|
|
230
|
+
source: string | null;
|
|
231
|
+
/** Cache state for the current tree. */
|
|
232
|
+
cache: DonePlanToolCacheState;
|
|
233
|
+
/** Cached exit code, when an entry exists. */
|
|
234
|
+
exitCode?: number;
|
|
235
|
+
/** When the cached result was captured. */
|
|
236
|
+
capturedAt?: string;
|
|
237
|
+
/** Resolver refusal reason, when unresolved or not applicable. */
|
|
238
|
+
reason?: string;
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
/** Stored result of a typed acceptance gate. The planner never runs it. */
|
|
242
|
+
export interface DonePlanTypedGate {
|
|
243
|
+
/** Criterion alias (`AC<n>`). */
|
|
244
|
+
alias: string;
|
|
245
|
+
/** Typed gate kind. */
|
|
246
|
+
kind: string;
|
|
247
|
+
/** Requirement id, when the gate declares one. */
|
|
248
|
+
req?: string;
|
|
249
|
+
/** Latest stored result; `not-run` when none is stored. */
|
|
250
|
+
status: 'pass' | 'fail' | 'not-run';
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
/**
|
|
254
|
+
* Why an acceptance criterion is (or is not) linked automatically.
|
|
255
|
+
*
|
|
256
|
+
* - `typed-gate` — the criterion is a typed gate with a stored passing result.
|
|
257
|
+
* - `files-in-diff` — every repo path the criterion names is in the change set.
|
|
258
|
+
* - `agent` — the agent named it with `--satisfies`.
|
|
259
|
+
* - `recorded` — already linked by gate evidence the task has recorded.
|
|
260
|
+
* - `none` — no deterministic coverage; the agent must answer.
|
|
261
|
+
*/
|
|
262
|
+
export type DonePlanAcBasis = 'typed-gate' | 'files-in-diff' | 'agent' | 'recorded' | 'none';
|
|
263
|
+
|
|
264
|
+
/** Mapping of one acceptance criterion to gate evidence. */
|
|
265
|
+
export interface DonePlanAcMapping {
|
|
266
|
+
/** Criterion alias (`AC<n>`). */
|
|
267
|
+
alias: string;
|
|
268
|
+
/** Canonical criterion UUID. */
|
|
269
|
+
id: string;
|
|
270
|
+
/** Criterion text. */
|
|
271
|
+
text: string;
|
|
272
|
+
/** Whether the criterion is linked, by any {@link DonePlanAcBasis} other than `none`. */
|
|
273
|
+
mapped: boolean;
|
|
274
|
+
/** Gates whose planned evidence carries `satisfies:` for this criterion. */
|
|
275
|
+
gates: VerificationGate[];
|
|
276
|
+
/** Why it is or is not linked. */
|
|
277
|
+
basis: DonePlanAcBasis;
|
|
278
|
+
/** Repo paths the criterion names (for `files-in-diff` and its misses). */
|
|
279
|
+
files?: string[];
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
/**
|
|
283
|
+
* Result of `deriveTaskEvidence` / `cleo done <id> --plan`.
|
|
284
|
+
*
|
|
285
|
+
* Read-only by construction: the planner records nothing and executes no tool
|
|
286
|
+
* or typed gate. `commands` are the calls `cleo done` would issue, spelled as
|
|
287
|
+
* the existing verbs so every one is runnable today.
|
|
288
|
+
*/
|
|
289
|
+
export interface DonePlan {
|
|
290
|
+
/** Task the plan is for. */
|
|
291
|
+
taskId: string;
|
|
292
|
+
/** Directory the commands must run from (the change set's execution root). */
|
|
293
|
+
runFrom: string;
|
|
294
|
+
/** The derived change set. */
|
|
295
|
+
changeSet: TaskChangeSet;
|
|
296
|
+
/** Every evidence gate the plan covers, required or already passed. */
|
|
297
|
+
gates: DonePlanGate[];
|
|
298
|
+
/** Tool runs the required gates need. */
|
|
299
|
+
toolRuns: DonePlanToolRun[];
|
|
300
|
+
/** Typed acceptance gates and their stored results. */
|
|
301
|
+
typedGates: DonePlanTypedGate[];
|
|
302
|
+
/** Per-criterion mapping. */
|
|
303
|
+
acMapping: DonePlanAcMapping[];
|
|
304
|
+
/** Aliases of criteria that need `--satisfies` from the agent. */
|
|
305
|
+
needsSatisfies: string[];
|
|
306
|
+
/** Blockers, ordered: the first is the one to clear first. */
|
|
307
|
+
blockers: DonePlanBlocker[];
|
|
308
|
+
/**
|
|
309
|
+
* D11151: `implemented` evidence (with its criterion links) for each of the
|
|
310
|
+
* task's earlier own-branch PRs, recorded as separate attempts before the
|
|
311
|
+
* primary gate write.
|
|
312
|
+
*/
|
|
313
|
+
additionalImplemented?: string[];
|
|
314
|
+
/** Runnable commands, in order, that record the gates and complete the task. */
|
|
315
|
+
commands: string[];
|
|
316
|
+
/** True when no blocker remains and `commands` would succeed as planned. */
|
|
317
|
+
ready: boolean;
|
|
318
|
+
/** The single next step: the first blocker's, or the first command. */
|
|
319
|
+
next: DoneNextStep | null;
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
/** One tool `cleo done` ran (or reused from the ADR-061 cache) before recording. */
|
|
323
|
+
export interface DoneToolResult {
|
|
324
|
+
/** Canonical tool name. */
|
|
325
|
+
tool: string;
|
|
326
|
+
/** Gate the result satisfies. */
|
|
327
|
+
gate: VerificationGate;
|
|
328
|
+
/** Exit code of the run. */
|
|
329
|
+
exitCode: number | null;
|
|
330
|
+
/** Whether the result came from the ADR-061 cache. */
|
|
331
|
+
cacheHit: boolean;
|
|
332
|
+
/** Wall-clock duration of the run (0 for a cache hit). */
|
|
333
|
+
durationMs: number;
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
/**
|
|
337
|
+
* Successful `cleo done` / `cleo verify --auto` write: every required gate the
|
|
338
|
+
* task lacked, recorded in one transaction through the existing validators.
|
|
339
|
+
* Completion (for `cleo done`) is reported by the caller alongside it.
|
|
340
|
+
*/
|
|
341
|
+
export interface DoneRecordResult {
|
|
342
|
+
/** Task the gates were recorded for. */
|
|
343
|
+
taskId: string;
|
|
344
|
+
/** Gates this call recorded, in gate order. */
|
|
345
|
+
recordedGates: VerificationGate[];
|
|
346
|
+
/** Required gates that were already passed and left untouched. */
|
|
347
|
+
alreadyPassed: VerificationGate[];
|
|
348
|
+
/** Tool runs performed or reused before the write. */
|
|
349
|
+
toolResults: DoneToolResult[];
|
|
350
|
+
/** Typed acceptance gates executed before the write (0 when the task has none). */
|
|
351
|
+
typedGateCount: number;
|
|
352
|
+
/** Whether all required gates are now passed. */
|
|
353
|
+
verificationPassed: boolean;
|
|
354
|
+
/** The plan the write was derived from. */
|
|
355
|
+
plan: DonePlan;
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
/** Details of an `E_DONE_BLOCKED` failure: one blocker, one next step. */
|
|
359
|
+
export interface DoneBlockedDetails {
|
|
360
|
+
/** The blocker that stopped `cleo done`. */
|
|
361
|
+
blocker: DonePlanBlockerCode;
|
|
362
|
+
/** Original error code (e.g. `E_EVIDENCE_TOOL_FAILED`), when one exists. */
|
|
363
|
+
cause?: string;
|
|
364
|
+
/** The one next step. */
|
|
365
|
+
next: DoneNextStep;
|
|
366
|
+
/** Gates already recorded before a completion refusal (empty otherwise). */
|
|
367
|
+
recordedGates: VerificationGate[];
|
|
368
|
+
/** The plan, for tooling. */
|
|
369
|
+
plan: DonePlan;
|
|
370
|
+
}
|
|
@@ -62,6 +62,7 @@ export const EVIDENCE_ATOM_KINDS = [
|
|
|
62
62
|
'note',
|
|
63
63
|
'decision',
|
|
64
64
|
'pr',
|
|
65
|
+
'ci',
|
|
65
66
|
'loc-drop',
|
|
66
67
|
'callsite-coverage',
|
|
67
68
|
'satisfies',
|
|
@@ -197,7 +198,11 @@ export const decisionAtomSchema = z.object({
|
|
|
197
198
|
* checks task relationship and changed artifacts. Implementation also needs
|
|
198
199
|
* inspected file evidence; testing and review require actual result atoms.
|
|
199
200
|
*
|
|
200
|
-
* Format: `pr:<positive integer>` (e.g. `pr:357`)
|
|
201
|
+
* Format: `pr:<positive integer>` (e.g. `pr:357`), or
|
|
202
|
+
* `pr:<component>@<integration>` (e.g. `pr:356@357`, T12671): component PR
|
|
203
|
+
* #356 merged into an integration branch that PR #357 landed on the default
|
|
204
|
+
* branch. The integration PR supplies the merge commit; the component PR
|
|
205
|
+
* supplies the task linkage and the changed files.
|
|
201
206
|
*
|
|
202
207
|
* @task T9764
|
|
203
208
|
* @task T9838
|
|
@@ -205,6 +210,25 @@ export const decisionAtomSchema = z.object({
|
|
|
205
210
|
export const prAtomSchema = z.object({
|
|
206
211
|
kind: z.literal('pr'),
|
|
207
212
|
prNumber: z.number().int().positive('pr atom requires a positive integer PR number'),
|
|
213
|
+
componentPrNumber: z.number().int().positive().optional(),
|
|
214
|
+
});
|
|
215
|
+
|
|
216
|
+
/**
|
|
217
|
+
* `ci:<number>` atom — the required CI checks of a merged PR, judged on the
|
|
218
|
+
* PR's actual MERGE COMMIT (never its head). Satisfies `testsPassed` and
|
|
219
|
+
* `qaPassed` only when the project opts in with `evidence.ciSatisfies`
|
|
220
|
+
* (owner decision D11149).
|
|
221
|
+
*
|
|
222
|
+
* Format: `ci:<positive integer>` (e.g. `ci:357`), or
|
|
223
|
+
* `ci:<component>@<integration>` (e.g. `ci:356@357`, T12671): the integration
|
|
224
|
+
* PR's merge-commit CI, for a task linked through its component PR.
|
|
225
|
+
*
|
|
226
|
+
* @task T12634
|
|
227
|
+
*/
|
|
228
|
+
export const ciAtomSchema = z.object({
|
|
229
|
+
kind: z.literal('ci'),
|
|
230
|
+
prNumber: z.number().int().positive('ci atom requires a positive integer PR number'),
|
|
231
|
+
componentPrNumber: z.number().int().positive().optional(),
|
|
208
232
|
});
|
|
209
233
|
|
|
210
234
|
/**
|
|
@@ -389,6 +413,7 @@ export const EvidenceAtomSchema = z.discriminatedUnion('kind', [
|
|
|
389
413
|
noteAtomSchema,
|
|
390
414
|
decisionAtomSchema,
|
|
391
415
|
prAtomSchema,
|
|
416
|
+
ciAtomSchema,
|
|
392
417
|
locDropAtomSchema,
|
|
393
418
|
callsiteCoverageAtomSchema,
|
|
394
419
|
satisfiesAtomSchema,
|
|
@@ -477,8 +502,8 @@ export const GATE_EVIDENCE_REQUIREMENTS: Readonly<
|
|
|
477
502
|
['pr', 'files'],
|
|
478
503
|
],
|
|
479
504
|
},
|
|
480
|
-
testsPassed: { oneOf: [['test-run'], ['tool']] },
|
|
481
|
-
qaPassed: { oneOf: [['tool']] },
|
|
505
|
+
testsPassed: { oneOf: [['test-run'], ['tool'], ['ci']] },
|
|
506
|
+
qaPassed: { oneOf: [['tool'], ['ci']] },
|
|
482
507
|
documented: { oneOf: [['files'], ['url']] },
|
|
483
508
|
securityPassed: { oneOf: [['tool'], ['note']] },
|
|
484
509
|
cleanupDone: { oneOf: [['note']] },
|
|
@@ -542,6 +567,7 @@ const ATOM_EXAMPLES: Readonly<Record<EvidenceAtomKind, string>> = Object.freeze(
|
|
|
542
567
|
note: 'note:<short description>',
|
|
543
568
|
decision: 'decision:D-arch-001',
|
|
544
569
|
pr: 'pr:357',
|
|
570
|
+
ci: 'ci:357',
|
|
545
571
|
'loc-drop': 'loc-drop:<fromLines>:<toLines>',
|
|
546
572
|
'callsite-coverage': 'callsite-coverage:<symbolName>:<relativeSourcePath>',
|
|
547
573
|
satisfies: 'satisfies:T1234#AC2',
|
|
@@ -753,6 +779,21 @@ export class EvidenceParseError extends Error {
|
|
|
753
779
|
* @task T10337
|
|
754
780
|
* @adr ADR-051
|
|
755
781
|
*/
|
|
782
|
+
/**
|
|
783
|
+
* `<n>` or `<component>@<integration>` (T12671), each a positive integer.
|
|
784
|
+
* The integration PR is the atom's `prNumber`.
|
|
785
|
+
*/
|
|
786
|
+
function parsePrReference(
|
|
787
|
+
payload: string,
|
|
788
|
+
): { prNumber: number; componentPrNumber?: number } | null {
|
|
789
|
+
const match = /^(\d+)(?:@(\d+))?$/.exec(payload);
|
|
790
|
+
if (!match) return null;
|
|
791
|
+
const first = Number(match[1]);
|
|
792
|
+
const second = match[2] === undefined ? null : Number(match[2]);
|
|
793
|
+
if (first <= 0 || (second !== null && (second <= 0 || second === first))) return null;
|
|
794
|
+
return second === null ? { prNumber: first } : { prNumber: second, componentPrNumber: first };
|
|
795
|
+
}
|
|
796
|
+
|
|
756
797
|
export function parseEvidenceString(raw: string): EvidenceAtom[] {
|
|
757
798
|
if (!raw || typeof raw !== 'string') {
|
|
758
799
|
throw new EvidenceParseError(
|
|
@@ -822,15 +863,16 @@ export function parseEvidenceString(raw: string): EvidenceAtom[] {
|
|
|
822
863
|
atoms.push({ kind: 'decision', decisionId: payload });
|
|
823
864
|
break;
|
|
824
865
|
}
|
|
825
|
-
case 'pr':
|
|
826
|
-
|
|
827
|
-
|
|
866
|
+
case 'pr':
|
|
867
|
+
case 'ci': {
|
|
868
|
+
const ref = parsePrReference(payload);
|
|
869
|
+
if (!ref) {
|
|
828
870
|
throw new EvidenceParseError(
|
|
829
|
-
|
|
830
|
-
|
|
871
|
+
`${kind} atom requires a positive integer PR number, got "${payload}" in "${chunk}"`,
|
|
872
|
+
`Use format: ${kind}:<number> e.g. ${kind}:357, or ${kind}:<component>@<integration> e.g. ${kind}:356@357`,
|
|
831
873
|
);
|
|
832
874
|
}
|
|
833
|
-
atoms.push({ kind: 'pr',
|
|
875
|
+
atoms.push(kind === 'pr' ? { kind: 'pr', ...ref } : { kind: 'ci', ...ref });
|
|
834
876
|
break;
|
|
835
877
|
}
|
|
836
878
|
case 'loc-drop': {
|
package/src/exit-codes.ts
CHANGED
|
@@ -21,6 +21,13 @@ export enum ExitCode {
|
|
|
21
21
|
VALIDATION_ERROR = 6,
|
|
22
22
|
LOCK_TIMEOUT = 7,
|
|
23
23
|
CONFIG_ERROR = 8,
|
|
24
|
+
/**
|
|
25
|
+
* The project this directory resolves to was relocated by
|
|
26
|
+
* `cleo project reroot`; a valid `.cleo-moved.json` tombstone names its new
|
|
27
|
+
* root. Refused instead of silently creating an empty store at the old root.
|
|
28
|
+
* LAFS code `E_PROJECT_MOVED`; details carry `movedTo`. @task T12558
|
|
29
|
+
*/
|
|
30
|
+
PROJECT_MOVED = 9,
|
|
24
31
|
|
|
25
32
|
// === HIERARCHY ERRORS (10-19) ===
|
|
26
33
|
PARENT_NOT_FOUND = 10,
|
|
@@ -38,6 +45,29 @@ export enum ExitCode {
|
|
|
38
45
|
CHECKSUM_MISMATCH = 20,
|
|
39
46
|
CONCURRENT_MODIFICATION = 21,
|
|
40
47
|
ID_COLLISION = 22,
|
|
48
|
+
/**
|
|
49
|
+
* Optimistic-concurrency version mismatch: the caller's expected task
|
|
50
|
+
* version (`updatedAt`) no longer matches the stored row. LAFS code
|
|
51
|
+
* `E_CONFLICT`; the error details carry the current version. @task T12503
|
|
52
|
+
*/
|
|
53
|
+
VERSION_CONFLICT = 23,
|
|
54
|
+
/**
|
|
55
|
+
* A session MUTATION (end, decision, suspend-on-switch) was asked to act on
|
|
56
|
+
* "the caller's session" but the caller has no bound identity: no connection
|
|
57
|
+
* handle, no `CLEO_SESSION_ID` naming a real row, and no terminal binding
|
|
58
|
+
* from `cleo session start` / `cleo session resume`. Guessing the newest
|
|
59
|
+
* active row would act on ANOTHER agent's session, so the operation refuses.
|
|
60
|
+
* LAFS code `E_SESSION_UNBOUND`. @task T12500
|
|
61
|
+
*/
|
|
62
|
+
SESSION_UNBOUND = 24,
|
|
63
|
+
/**
|
|
64
|
+
* A second spawn asked for a task worktree whose per-task lock is held by a
|
|
65
|
+
* live holder (session, agent, pid + process start, device, heartbeat).
|
|
66
|
+
* Re-provisioning would force-remove the holder's live worktree, so the
|
|
67
|
+
* spawn refuses. LAFS code `E_WORKTREE_LOCKED`; the error details name the
|
|
68
|
+
* holder. @task T12506
|
|
69
|
+
*/
|
|
70
|
+
WORKTREE_LOCKED = 25,
|
|
41
71
|
|
|
42
72
|
// === SESSION ERRORS (30-39) ===
|
|
43
73
|
SESSION_EXISTS = 30,
|
|
@@ -97,6 +127,18 @@ export enum ExitCode {
|
|
|
97
127
|
CONTEXT_EMERGENCY = 53,
|
|
98
128
|
CONTEXT_STALE = 54,
|
|
99
129
|
|
|
130
|
+
// === STORE MIGRATION (55-59) ===
|
|
131
|
+
/**
|
|
132
|
+
* A twin collapse (a bare legacy table folded into its prefixed twin in the
|
|
133
|
+
* project `cleo.db`) could not complete: the pre-migration snapshot could
|
|
134
|
+
* not be written (backup directory unusable, not enough free space) or the
|
|
135
|
+
* merge failed and was rolled back. Both tables are unchanged. LAFS code
|
|
136
|
+
* `E_TWIN_COLLAPSE_FAILED`; details carry the table, the cause, the
|
|
137
|
+
* snapshot path and the free space needed. `cleo doctor twin-collapse`
|
|
138
|
+
* reports it and `--retry` re-runs it. @task T12535
|
|
139
|
+
*/
|
|
140
|
+
TWIN_COLLAPSE_FAILED = 55,
|
|
141
|
+
|
|
100
142
|
// === ORCHESTRATOR ERRORS (60-68) ===
|
|
101
143
|
PROTOCOL_MISSING = 60,
|
|
102
144
|
INVALID_RETURN_MESSAGE = 61,
|
package/src/graph.ts
CHANGED
|
@@ -683,6 +683,50 @@ export interface GraphIndexAssessment {
|
|
|
683
683
|
files: GraphIndexFileReport[];
|
|
684
684
|
}
|
|
685
685
|
|
|
686
|
+
/** Processing outcome of one assessed file. */
|
|
687
|
+
export type GraphIndexFileStatus = GraphIndexFileReport['status'];
|
|
688
|
+
|
|
689
|
+
/** Per-status file counts of an assessment; every status is present, zero included. */
|
|
690
|
+
export type GraphIndexFileStatusCounts = Record<GraphIndexFileStatus, number>;
|
|
691
|
+
|
|
692
|
+
/** One page of an assessment's per-file report, in stored order (T12560). */
|
|
693
|
+
export interface GraphIndexFilePage {
|
|
694
|
+
/** Rows skipped before this page. */
|
|
695
|
+
offset: number;
|
|
696
|
+
/** Requested page size; null when every remaining row was requested. */
|
|
697
|
+
limit: number | null;
|
|
698
|
+
/** Only rows with this status were paged; absent when unfiltered. */
|
|
699
|
+
status?: GraphIndexFileStatus;
|
|
700
|
+
/** Rows matching the filter, before paging. */
|
|
701
|
+
total: number;
|
|
702
|
+
/** Rows in this page. */
|
|
703
|
+
returned: number;
|
|
704
|
+
/** Offset of the next page; null when this page reaches the end. */
|
|
705
|
+
nextOffset: number | null;
|
|
706
|
+
/** The page itself. */
|
|
707
|
+
rows: GraphIndexFileReport[];
|
|
708
|
+
}
|
|
709
|
+
|
|
710
|
+
/**
|
|
711
|
+
* Bounded status projection of a {@link GraphIndexAssessment} (T12560).
|
|
712
|
+
*
|
|
713
|
+
* The per-file list grows with the repository (~635 B per file), so status
|
|
714
|
+
* reports its counts and one page. `files` is present only when every row was
|
|
715
|
+
* requested; otherwise `_withheld.files` carries the full list's UTF-8 JSON size.
|
|
716
|
+
*/
|
|
717
|
+
export interface GraphIndexAssessmentProjection extends Omit<GraphIndexAssessment, 'files'> {
|
|
718
|
+
/** Omitted source fields and their UTF-8 serialized sizes; absent when complete. */
|
|
719
|
+
_withheld?: Record<string, number>;
|
|
720
|
+
/** Every file row; present only when the complete list was requested. */
|
|
721
|
+
files?: GraphIndexFileReport[];
|
|
722
|
+
/** Number of assessed files, including excluded ones. */
|
|
723
|
+
fileCount: number;
|
|
724
|
+
/** Assessed files per processing outcome. */
|
|
725
|
+
filesByStatus: GraphIndexFileStatusCounts;
|
|
726
|
+
/** The requested page of file rows; absent when `files` is complete. */
|
|
727
|
+
filesPage?: GraphIndexFilePage;
|
|
728
|
+
}
|
|
729
|
+
|
|
686
730
|
/** Validated rows staged before an atomic graph publication. */
|
|
687
731
|
export interface GraphPublicationRows {
|
|
688
732
|
/** Immutable publication identity shared by anonymous symbols, rows and assessment. */
|