@cleocode/contracts 2026.9.22 → 2026.9.23

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (52) hide show
  1. package/dist/__tests__/evidence-atom-schema.test.js +3 -2
  2. package/dist/__tests__/evidence-atom-schema.test.js.map +1 -1
  3. package/dist/acceptance-gate-schema.d.ts.map +1 -1
  4. package/dist/acceptance-gate-schema.js +4 -1
  5. package/dist/acceptance-gate-schema.js.map +1 -1
  6. package/dist/data-accessor.d.ts +4 -0
  7. package/dist/data-accessor.d.ts.map +1 -1
  8. package/dist/data-accessor.js.map +1 -1
  9. package/dist/decide-sites.d.ts +157 -0
  10. package/dist/decide-sites.d.ts.map +1 -0
  11. package/dist/decide-sites.js +28 -0
  12. package/dist/decide-sites.js.map +1 -0
  13. package/dist/decide.d.ts +105 -0
  14. package/dist/decide.d.ts.map +1 -1
  15. package/dist/decide.js +31 -0
  16. package/dist/decide.js.map +1 -1
  17. package/dist/dispatch/operations-registry.d.ts.map +1 -1
  18. package/dist/dispatch/operations-registry.js +37 -2
  19. package/dist/dispatch/operations-registry.js.map +1 -1
  20. package/dist/evidence-atom-schema.d.ts.map +1 -1
  21. package/dist/evidence-atom-schema.js +3 -0
  22. package/dist/evidence-atom-schema.js.map +1 -1
  23. package/dist/index.d.ts +5 -3
  24. package/dist/index.d.ts.map +1 -1
  25. package/dist/index.js +2 -1
  26. package/dist/index.js.map +1 -1
  27. package/dist/operations/admin.d.ts +5 -0
  28. package/dist/operations/admin.d.ts.map +1 -1
  29. package/dist/operations/tasks.d.ts +24 -0
  30. package/dist/operations/tasks.d.ts.map +1 -1
  31. package/dist/operations/tasks.js.map +1 -1
  32. package/dist/task.d.ts +14 -0
  33. package/dist/task.d.ts.map +1 -1
  34. package/dist/tools/index.d.ts +1 -1
  35. package/dist/tools/index.d.ts.map +1 -1
  36. package/dist/tools/score-task-priority.d.ts +28 -3
  37. package/dist/tools/score-task-priority.d.ts.map +1 -1
  38. package/package.json +2 -2
  39. package/src/__tests__/__snapshots__/operations-registry.test.ts.snap +1 -1
  40. package/src/__tests__/evidence-atom-schema.test.ts +3 -2
  41. package/src/acceptance-gate-schema.ts +4 -1
  42. package/src/data-accessor.ts +4 -0
  43. package/src/decide-sites.ts +179 -0
  44. package/src/decide.ts +109 -0
  45. package/src/dispatch/operations-registry.ts +39 -2
  46. package/src/evidence-atom-schema.ts +3 -0
  47. package/src/index.ts +24 -0
  48. package/src/operations/admin.ts +5 -0
  49. package/src/operations/tasks.ts +26 -0
  50. package/src/task.ts +14 -0
  51. package/src/tools/index.ts +1 -0
  52. package/src/tools/score-task-priority.ts +29 -3
@@ -684,7 +684,8 @@ describe('formatGateRequirement (T10337)', () => {
684
684
  expect(s).toContain('[decision AND note]');
685
685
  expect(s).toContain('[pr AND files]');
686
686
  // Joiner between combinations is ' OR '.
687
- expect(s.split(' OR ').length).toBe(5);
687
+ // T12689: + [pr AND note] for a deletion-only PR.
688
+ expect(s.split(' OR ').length).toBe(6);
688
689
  });
689
690
 
690
691
  it('formats single-element combination without AND', () => {
@@ -759,7 +760,7 @@ describe('validateEvidenceForGate failure surface (T9949)', () => {
759
760
  if (!r.ok) {
760
761
  // Error includes the same artifact requirement as the validator.
761
762
  expect(r.message).toBe(
762
- "Gate 'implemented' requires evidence: [commit AND files] OR [commit AND note] OR [decision AND files] OR [decision AND note] OR [pr AND files]",
763
+ "Gate 'implemented' requires evidence: [commit AND files] OR [commit AND note] OR [decision AND files] OR [decision AND note] OR [pr AND files] OR [pr AND note]",
763
764
  );
764
765
  // New rich hint includes the same content as formatGateRequirementHint.
765
766
  expect(r.hint).toBe(formatGateRequirementHint('implemented'));
@@ -536,7 +536,10 @@ export const acceptanceGateResultSchema = z
536
536
  message: 'Result cannot precede input capture',
537
537
  });
538
538
  const executable = ['test', 'command', 'lint'].includes(result.kind);
539
- if (executable && !binding.invocation)
539
+ // T12718: a command the runner refused to split (shell syntax, open
540
+ // quote) never had an invocation. It is bound as an unmet `error` so the
541
+ // rest of its batch still records; any verdict needs the invocation.
542
+ if (executable && !binding.invocation && result.result !== 'error')
540
543
  context.addIssue({
541
544
  code: 'custom',
542
545
  path: ['binding', 'invocation'],
@@ -255,6 +255,8 @@ export interface AcBindingRow {
255
255
 
256
256
  /** Query options for bounded reads from the append-only task audit log. @task T10594 */
257
257
  export interface TaskAuditLogQuery {
258
+ /** Exact audit row ids (T12693: revert one ranking change). */
259
+ ids?: readonly string[];
258
260
  taskIds?: readonly string[];
259
261
  actions?: readonly string[];
260
262
  since?: string;
@@ -271,6 +273,8 @@ export interface TaskAuditLogRow {
271
273
  detailsJson: string | null;
272
274
  beforeJson: string | null;
273
275
  afterJson: string | null;
276
+ /** Session the mutation ran in, when recorded (T12693). */
277
+ sessionId?: string | null;
274
278
  }
275
279
 
276
280
  /**
@@ -0,0 +1,179 @@
1
+ /**
2
+ * Decision-site registry contracts — the "decision ladder as code" (spec
3
+ * `system-one-integration` §3, owner decisions D11158 and D11159).
4
+ *
5
+ * Every place CLEO makes a judgement is a decision site: it has one primary
6
+ * rung, an ordered ladder of rungs it may escalate to, a fallback, an
7
+ * owner-escalation rule, a mode and (to act on a System One answer) go-live
8
+ * evidence. The registry rows live in `packages/core/src/decide/sites/`;
9
+ * these are their types.
10
+ *
11
+ * Types and const data only (arch gate 10).
12
+ *
13
+ * @task T12662
14
+ * @epic T12486
15
+ */
16
+
17
+ /**
18
+ * The decision rungs, cheapest first. Escalation only moves up this list.
19
+ *
20
+ * - `rule` — the answer follows from data (ids, statuses, thresholds).
21
+ * - `system-one` — a typed judgement over text with a small fixed answer set.
22
+ * - `generative` — the output must be free text or code.
23
+ * - `agent` — multi-step work.
24
+ * - `owner` — authority only the owner can take (the ask tool).
25
+ */
26
+ export const DECISION_RUNGS = ['rule', 'system-one', 'generative', 'agent', 'owner'] as const;
27
+
28
+ /** One rung of the decision ladder. */
29
+ export type DecisionRung = (typeof DECISION_RUNGS)[number];
30
+
31
+ /** Site modes: `off` never asks, `shadow` asks and audits, `on` acts. */
32
+ export const DECISION_SITE_MODES = ['off', 'shadow', 'on'] as const;
33
+
34
+ /** How a site uses its System One rung. */
35
+ export type DecisionSiteModeValue = (typeof DECISION_SITE_MODES)[number];
36
+
37
+ /** The shape of the question a site answers. */
38
+ export type DecisionSiteQuestionType =
39
+ | 'noul'
40
+ | 'choice'
41
+ | 'score'
42
+ | 'text'
43
+ | 'multi-step'
44
+ | 'owner-choice';
45
+
46
+ /**
47
+ * When a site may put a question to the owner.
48
+ *
49
+ * - `never` — the site never asks the owner.
50
+ * - `escalate-only` — it may add an owner question, never clear one.
51
+ * - `below-floor` — it asks the owner when every lower rung is below its floor.
52
+ * - `always` — the owner always decides.
53
+ */
54
+ export type DecisionSiteOwnerEscalation = 'never' | 'escalate-only' | 'below-floor' | 'always';
55
+
56
+ /** Classes of text a site may send off the machine (spec §8). */
57
+ export type DecisionSiteTextClass =
58
+ | 'task-text'
59
+ | 'memory-text'
60
+ | 'diff'
61
+ | 'skill-text'
62
+ | 'external-text';
63
+
64
+ /** Measured evidence that lets a site act on its System One answer (`mode: on`). */
65
+ export interface DecisionSiteGoLive {
66
+ /** Canonical doc slug holding the measurement. */
67
+ readonly evidenceDoc: string;
68
+ /** ISO date of the measurement. */
69
+ readonly measuredAt: string;
70
+ /** Number of labelled decisions measured. */
71
+ readonly n: number;
72
+ /** Metric name, e.g. `precision@acting-class`. */
73
+ readonly metric: string;
74
+ /** Measured value. */
75
+ readonly value: number;
76
+ /** Floor the value had to clear. */
77
+ readonly floor: number;
78
+ }
79
+
80
+ /** One registry row: everything CLEO knows about a decision site. */
81
+ export interface DecisionSiteDefinition {
82
+ /** Site id; the string `decide()` and the audit log use, e.g. `tasks.duplicate-detection`. */
83
+ readonly id: string;
84
+ /** Human title. */
85
+ readonly title: string;
86
+ /** Repo-relative files where the site lives. */
87
+ readonly files: readonly string[];
88
+ /** The shape of the question. */
89
+ readonly questionType: DecisionSiteQuestionType;
90
+ /** The rung that answers first. */
91
+ readonly primaryRung: DecisionRung;
92
+ /** Rungs it may escalate to, in order, all above the primary. */
93
+ readonly ladder: readonly DecisionRung[];
94
+ /** What acts when the primary is unavailable. */
95
+ readonly fallback: DecisionRung | 'none';
96
+ /**
97
+ * Minimum confidence per question before `on` may act on a System One
98
+ * answer. The key `*` applies to every question of the site.
99
+ */
100
+ readonly floors?: Readonly<Record<string, number>>;
101
+ /** When the site may ask the owner. */
102
+ readonly ownerEscalation: DecisionSiteOwnerEscalation;
103
+ /** Config key holding the mode (the existing `decide.sites.*` keys, D11159). */
104
+ readonly modeKey?: string;
105
+ /** Config key opting the site into its generative rung (`decide.generativeFallback.*`). */
106
+ readonly generativeKey?: string;
107
+ /** Mode when the config key is unset. */
108
+ readonly defaultMode: DecisionSiteModeValue;
109
+ /** Generative rung: the role or system key it resolves its model with. */
110
+ readonly llmSystemKey?: string;
111
+ /** True for a site on a write path: 300 ms budget, never blocks the write. */
112
+ readonly writePath: boolean;
113
+ /** Text classes it sends to a provider. */
114
+ readonly sends: readonly DecisionSiteTextClass[];
115
+ /** Go-live evidence, required before a System One site runs `on`. */
116
+ readonly goLive?: DecisionSiteGoLive;
117
+ /** Owning task. */
118
+ readonly task: string;
119
+ /** Free-form note (constraints such as "interactive only"). */
120
+ readonly note?: string;
121
+ }
122
+
123
+ /** Audit counts for one site over the last seven days. */
124
+ export interface DecisionSiteActivity {
125
+ /** Audit lines written for the site. */
126
+ readonly asked: number;
127
+ /** Answered by the provider. */
128
+ readonly provider: number;
129
+ /** Answered from the decision cache. */
130
+ readonly cache: number;
131
+ /** Answered by the fallback. */
132
+ readonly fallback: number;
133
+ /** Escalated to a higher rung (0 until the ladder executor lands, T12665). */
134
+ readonly escalated: number;
135
+ /** Share of compared shadow lines where decision and heuristic agreed, when any were compared. */
136
+ readonly agreement?: number;
137
+ }
138
+
139
+ /** One site as `cleo decide sites` reports it. */
140
+ export interface DecisionSiteSummary {
141
+ /** Site id. */
142
+ readonly id: string;
143
+ /** Human title. */
144
+ readonly title: string;
145
+ /** Question shape. */
146
+ readonly questionType: DecisionSiteQuestionType;
147
+ /** Primary rung. */
148
+ readonly primaryRung: DecisionRung;
149
+ /** Escalation ladder. */
150
+ readonly ladder: readonly DecisionRung[];
151
+ /** Fallback. */
152
+ readonly fallback: DecisionRung | 'none';
153
+ /** Owner-escalation rule. */
154
+ readonly ownerEscalation: DecisionSiteOwnerEscalation;
155
+ /** Registry default mode. */
156
+ readonly mode: DecisionSiteModeValue;
157
+ /** Mode set in config, when the site has a mode key and it is set. */
158
+ readonly configuredMode?: DecisionSiteModeValue;
159
+ /** Mode in force: `off` for a System One site while no provider is configured. */
160
+ readonly effectiveMode: DecisionSiteModeValue;
161
+ /** Config key holding the mode, when the site has one. */
162
+ readonly modeKey?: string;
163
+ /** Go-live evidence, when recorded. */
164
+ readonly goLive?: DecisionSiteGoLive;
165
+ /** Owning task. */
166
+ readonly task: string;
167
+ /** Audit activity over the last seven days. */
168
+ readonly last7d: DecisionSiteActivity;
169
+ }
170
+
171
+ /** Result of `cleo decide sites`. */
172
+ export interface DecisionSitesListResult {
173
+ /** Whether a System One provider is configured (else System One sites are `off`). */
174
+ readonly providerConfigured: boolean;
175
+ /** Registered sites total, before filters. */
176
+ readonly total: number;
177
+ /** Matching sites. */
178
+ readonly sites: readonly DecisionSiteSummary[];
179
+ }
package/src/decide.ts CHANGED
@@ -143,6 +143,17 @@ export interface DecisionRequest {
143
143
  readonly state: DecisionState;
144
144
  /** Question name → question (1–32 entries). Names key the answers in {@link DecisionOutcome}. */
145
145
  readonly questions: Readonly<Record<string, DecisionQuestion>>;
146
+ /**
147
+ * Language hint (e.g. `en`). Sent only to a provider whose capabilities
148
+ * include `langHint`; others never see it (T12664).
149
+ */
150
+ readonly lang?: string;
151
+ /**
152
+ * Provider-side answer cache. `false` asks a provider with `cacheControl`
153
+ * not to answer from its cache (real latency, sensitive text). Ignored by
154
+ * providers without the capability.
155
+ */
156
+ readonly cache?: boolean;
146
157
  }
147
158
 
148
159
  /** Answer to a {@link NoulDecisionQuestion}. */
@@ -196,14 +207,100 @@ export interface DecisionOutcome {
196
207
  readonly latencyMs: number;
197
208
  /** Provider-reported cost in US dollars, when known. */
198
209
  readonly costUsd?: number;
210
+ /** Provider-reported cost in integer micro-dollars, when known (T12664). */
211
+ readonly costMicros?: number;
212
+ /** Account balance in integer micro-dollars reported with this answer, when known. */
213
+ readonly balanceMicros?: number;
214
+ /** Provider model checkpoint that answered, when reported. */
215
+ readonly checkpoint?: string;
199
216
  /** Provider-reported input-token count, when known. */
200
217
  readonly inputTokens?: number;
201
218
  }
202
219
 
220
+ // ─── Provider kinds (T12713) ─────────────────────────────────────────────────
221
+
222
+ /**
223
+ * Every supported decision-provider kind, recommended first.
224
+ *
225
+ * - `layahost` — the hosted provider at {@link LAYAHOST_BASE_URL}; the user
226
+ * supplies only an API key.
227
+ * - `jev` — any other Jev-compatible endpoint; the user supplies the URL.
228
+ */
229
+ export const DECISION_PROVIDER_KINDS = ['layahost', 'jev'] as const;
230
+
231
+ /** A decision-provider kind. See {@link DECISION_PROVIDER_KINDS}. */
232
+ export type DecisionProviderKind = (typeof DECISION_PROVIDER_KINDS)[number];
233
+
234
+ /** Base URL of the layahost API (its OpenAPI `servers[0].url`). */
235
+ export const LAYAHOST_BASE_URL = 'https://layahost.com';
236
+
237
+ /** layahost's routing model, the default for a layahost connection. */
238
+ export const LAYAHOST_DEFAULT_MODEL = 'laya-auto';
239
+
203
240
  /** Connection settings for a decision provider. */
204
241
  export interface DecisionProviderConfig {
205
242
  /** Absolute base URL of the provider's API (no trailing path to the endpoint). */
206
243
  readonly baseUrl: string;
244
+ /** Provider kind; absent means a custom Jev-compatible endpoint (`jev`). */
245
+ readonly provider?: DecisionProviderKind;
246
+ }
247
+
248
+ // ─── Provider capabilities (T12664) ──────────────────────────────────────────
249
+
250
+ /**
251
+ * What a decision provider can do beyond the Jev minimum
252
+ * (`POST /v1/systemone`, 32 questions, 32,000-character state). A caller asks
253
+ * for a capability; the client degrades when it is absent (spec
254
+ * `system-one-integration` §2.2).
255
+ */
256
+ export interface DecisionProviderCapabilities {
257
+ /** Wire protocol the provider speaks. */
258
+ readonly wire: string;
259
+ /** Most questions one request may carry. */
260
+ readonly maxQuestionsPerRequest: number;
261
+ /** Largest state, in characters. */
262
+ readonly maxStateChars: number;
263
+ /** Batch endpoint limits, when the provider has one. */
264
+ readonly batch?: { readonly maxRequests: number; readonly maxQuestions: number };
265
+ /** Built-in template names, when the provider has templates. */
266
+ readonly templates?: readonly string[];
267
+ /** Server-side flows are available. */
268
+ readonly flows?: boolean;
269
+ /** A usage/balance endpoint and cost headers are available. */
270
+ readonly usage?: boolean;
271
+ /** The request's `cache` field is honoured. */
272
+ readonly cacheControl?: boolean;
273
+ /** The request's `lang` field is honoured. */
274
+ readonly langHint?: boolean;
275
+ /** How the provider reports cost. */
276
+ readonly reportsCost?: 'micros' | 'usd' | false;
277
+ }
278
+
279
+ /** The Jev minimum every provider supports; the default when a provider reports nothing. */
280
+ export const JEV_MINIMUM_CAPABILITIES: DecisionProviderCapabilities = {
281
+ wire: 'jev-systemone/1',
282
+ maxQuestionsPerRequest: 32,
283
+ maxStateChars: 32_000,
284
+ reportsCost: 'usd',
285
+ };
286
+
287
+ /** One item of a batch call: its outcome, or why it failed. */
288
+ export type DecisionBatchItem =
289
+ | { readonly ok: true; readonly outcome: DecisionOutcome }
290
+ | { readonly ok: false; readonly status?: number; readonly errorKind: string };
291
+
292
+ /** Account usage and balance as a provider reports it. */
293
+ export interface DecisionProviderUsage {
294
+ /** Balance in integer micro-dollars. */
295
+ readonly balanceMicros?: number;
296
+ /** Decisions the balance still covers. */
297
+ readonly decisionsLeft?: number;
298
+ /** Plan name. */
299
+ readonly plan?: string;
300
+ /** End of the current plan period, ISO-8601. */
301
+ readonly periodEnd?: string;
302
+ /** Decisions and cost over the queried window. */
303
+ readonly totals?: { readonly decisions?: number; readonly costMicros?: number };
207
304
  }
208
305
 
209
306
  // ─── Zod schemas ──────────────────────────────────────────────────────────────
@@ -290,6 +387,11 @@ export const decisionQuestionSchema = z.discriminatedUnion('type', [
290
387
  */
291
388
  export const decisionRequestSchema = z.object({
292
389
  model: z.string().min(1).optional(),
390
+ lang: z
391
+ .string()
392
+ .regex(/^[a-z]{2,3}(-[A-Za-z0-9]{2,8})?$/)
393
+ .optional(),
394
+ cache: z.boolean().optional(),
293
395
  state: decisionStateSchema,
294
396
  questions: z.record(z.string().min(1), decisionQuestionSchema).refine(
295
397
  (questions) => {
@@ -346,10 +448,17 @@ export const decisionOutcomeSchema = z.object({
346
448
  requestId: z.string().min(1).optional(),
347
449
  latencyMs: z.number().nonnegative(),
348
450
  costUsd: z.number().nonnegative().optional(),
451
+ costMicros: z.number().int().nonnegative().optional(),
452
+ balanceMicros: z.number().int().optional(),
453
+ checkpoint: z.string().min(1).optional(),
349
454
  inputTokens: z.number().int().nonnegative().optional(),
350
455
  });
351
456
 
457
+ /** Zod schema for {@link DecisionProviderKind}. */
458
+ export const decisionProviderKindSchema = z.enum(DECISION_PROVIDER_KINDS);
459
+
352
460
  /** Zod schema for {@link DecisionProviderConfig}; `baseUrl` must be an absolute URL. */
353
461
  export const decisionProviderConfigSchema = z.object({
354
462
  baseUrl: z.url(),
463
+ provider: decisionProviderKindSchema.optional(),
355
464
  });
@@ -814,12 +814,22 @@ export const OPERATIONS: OperationDef[] = [
814
814
  gateway: 'query' as const,
815
815
  domain: 'tasks' as const,
816
816
  operation: 'history',
817
- description: 'Show task work history (time tracked per task)',
817
+ description:
818
+ 'Show task work history; with taskId, the task audit trail; with ranking, who changed its priority/severity/kind/depends and why (T12693)',
818
819
  tier: 1,
819
820
  idempotent: true,
820
821
  sessionRequired: false,
821
822
  requiredParams: [],
822
- params: [],
823
+ params: [
824
+ { name: 'taskId', type: 'string', required: false, description: 'Task to show history for' },
825
+ { name: 'limit', type: 'number', required: false, description: 'Maximum entries' },
826
+ {
827
+ name: 'ranking',
828
+ type: 'boolean',
829
+ required: false,
830
+ description: 'Only ranking-input changes (actor, session, reason, before/after)',
831
+ },
832
+ ] satisfies ParamDef[],
823
833
  },
824
834
  {
825
835
  gateway: 'query',
@@ -3364,6 +3374,33 @@ export const OPERATIONS: OperationDef[] = [
3364
3374
  ] satisfies ParamDef[],
3365
3375
  outputSchema: OUTPUT_CONTRACTS['tasks.assignee'],
3366
3376
  },
3377
+ {
3378
+ gateway: 'mutate',
3379
+ domain: 'tasks',
3380
+ operation: 'ranking.revert',
3381
+ description:
3382
+ 'tasks.ranking.revert (mutate) — undo one recorded ranking change (priority/severity/kind/depends) as a new audited change (T12693, D11161)',
3383
+ tier: 1,
3384
+ idempotent: false,
3385
+ sessionRequired: false,
3386
+ requiredParams: ['entryId'],
3387
+ params: [
3388
+ {
3389
+ name: 'entryId',
3390
+ type: 'string',
3391
+ required: true,
3392
+ description: 'ranking_changed audit row id (cleo history ranking <taskId>)',
3393
+ cli: { positional: true },
3394
+ },
3395
+ { name: 'reason', type: 'string', required: false, description: 'Why it is reverted' },
3396
+ {
3397
+ name: 'force',
3398
+ type: 'boolean',
3399
+ required: false,
3400
+ description: 'Revert even though a field changed again since',
3401
+ },
3402
+ ] satisfies ParamDef[],
3403
+ },
3367
3404
  {
3368
3405
  gateway: 'mutate',
3369
3406
  domain: 'tasks',
@@ -500,6 +500,9 @@ export const GATE_EVIDENCE_REQUIREMENTS: Readonly<
500
500
  ['decision', 'files'],
501
501
  ['decision', 'note'],
502
502
  ['pr', 'files'],
503
+ // T12689: a deletion-only PR (no bytes to hash). Contextual validation
504
+ // accepts this only when every change the PR made is a deletion.
505
+ ['pr', 'note'],
503
506
  ],
504
507
  },
505
508
  testsPassed: { oneOf: [['test-run'], ['tool'], ['ci']] },
package/src/index.ts CHANGED
@@ -2703,6 +2703,7 @@ export type {
2703
2703
  ScoreFactor,
2704
2704
  ScoreTaskContext,
2705
2705
  ScoreTaskInput,
2706
+ ScoreTaskKey,
2706
2707
  ScoreTaskResult,
2707
2708
  } from './tools/score-task-priority.js';
2708
2709
  // === Transport (low-level wire protocol) ===
@@ -2890,11 +2891,15 @@ export type {
2890
2891
  ChoiceDecisionAnswer,
2891
2892
  ChoiceDecisionQuestion,
2892
2893
  DecisionAnswer,
2894
+ DecisionBatchItem,
2893
2895
  DecisionInstructions,
2894
2896
  DecisionJsonValue,
2895
2897
  DecisionOutcome,
2896
2898
  DecisionOutcomeSource,
2899
+ DecisionProviderCapabilities,
2897
2900
  DecisionProviderConfig,
2901
+ DecisionProviderKind,
2902
+ DecisionProviderUsage,
2898
2903
  DecisionQuestion,
2899
2904
  DecisionQuestionType,
2900
2905
  DecisionRequest,
@@ -2908,6 +2913,7 @@ export {
2908
2913
  choiceDecisionAnswerSchema,
2909
2914
  choiceDecisionQuestionSchema,
2910
2915
  DECISION_OUTCOME_SOURCES,
2916
+ DECISION_PROVIDER_KINDS,
2911
2917
  DECISION_QUESTION_TYPES,
2912
2918
  DECISION_REQUEST_LIMITS,
2913
2919
  decisionAnswerSchema,
@@ -2915,14 +2921,32 @@ export {
2915
2921
  decisionOutcomeSchema,
2916
2922
  decisionOutcomeSourceSchema,
2917
2923
  decisionProviderConfigSchema,
2924
+ decisionProviderKindSchema,
2918
2925
  decisionQuestionSchema,
2919
2926
  decisionQuestionTypeSchema,
2920
2927
  decisionRequestSchema,
2921
2928
  decisionStateSchema,
2929
+ JEV_MINIMUM_CAPABILITIES,
2930
+ LAYAHOST_BASE_URL,
2931
+ LAYAHOST_DEFAULT_MODEL,
2922
2932
  noulDecisionAnswerSchema,
2923
2933
  noulDecisionQuestionSchema,
2924
2934
  scoreDecisionAnswerSchema,
2925
2935
  scoreDecisionQuestionSchema,
2926
2936
  } from './decide.js';
2937
+ // T12662: decision-site registry (the decision ladder as code).
2938
+ export type {
2939
+ DecisionRung,
2940
+ DecisionSiteActivity,
2941
+ DecisionSiteDefinition,
2942
+ DecisionSiteGoLive,
2943
+ DecisionSiteModeValue,
2944
+ DecisionSiteOwnerEscalation,
2945
+ DecisionSiteQuestionType,
2946
+ DecisionSiteSummary,
2947
+ DecisionSitesListResult,
2948
+ DecisionSiteTextClass,
2949
+ } from './decide-sites.js';
2950
+ export { DECISION_RUNGS, DECISION_SITE_MODES } from './decide-sites.js';
2927
2951
 
2928
2952
  export { isStorableTaskId, isTaskId, TASK_ID_REGEX, type TaskId } from './task-id.js';
@@ -1648,6 +1648,11 @@ export interface AdminBackupMutateParams {
1648
1648
  file?: string;
1649
1649
  /** Preview the restore without writing (restore.file only). */
1650
1650
  dryRun?: boolean;
1651
+ /**
1652
+ * Allow a restore run from inside a git worktree to overwrite the owning
1653
+ * project's live store (T12680). Without it such a restore is refused.
1654
+ */
1655
+ confirmOwnerStore?: boolean;
1651
1656
  }
1652
1657
 
1653
1658
  /** Result of `admin.backup` mutate (create action). */
@@ -921,6 +921,31 @@ export interface TasksComplexityEstimateResult {
921
921
  export interface TasksHistoryParams {
922
922
  taskId?: string;
923
923
  limit?: number;
924
+ /**
925
+ * With `taskId`: only ranking-input changes (priority, severity, kind,
926
+ * depends) — who, which session, why, before/after (T12693, D11161).
927
+ */
928
+ ranking?: boolean;
929
+ }
930
+
931
+ // tasks.ranking.revert
932
+ /** Parameters for `tasks.ranking.revert` (T12693, D11161). */
933
+ export interface TasksRankingRevertParams {
934
+ /** The `ranking_changed` audit row id to undo (from `cleo history ranking`). */
935
+ entryId: string;
936
+ /** Why it is reverted; recorded on the new audit row. */
937
+ reason?: string;
938
+ /** Revert even though a field changed again since. */
939
+ force?: boolean;
940
+ }
941
+ /** Result of `tasks.ranking.revert`. */
942
+ export interface TasksRankingRevertResult {
943
+ /** Task whose ranking inputs were restored. */
944
+ taskId: string;
945
+ /** Fields set back. */
946
+ fields: string[];
947
+ /** The values they were set back to. */
948
+ revertedTo: Record<string, unknown>;
924
949
  }
925
950
  /**
926
951
  * Result of `tasks.history` — audit log entries for a task.
@@ -2277,6 +2302,7 @@ export type TasksOps = {
2277
2302
  readonly 'relates.add': readonly [TasksRelatesAddParams, TasksRelatesAddResult];
2278
2303
  readonly 'relates.add-batch': readonly [TasksRelatesAddBatchParams, TasksRelatesAddBatchResult];
2279
2304
  readonly 'relates.remove': readonly [TasksRelatesRemoveParams, TasksRelatesRemoveResult];
2305
+ readonly 'ranking.revert': readonly [TasksRankingRevertParams, TasksRankingRevertResult];
2280
2306
  readonly start: readonly [TasksStartQueryParams, TasksStartQueryResult];
2281
2307
  readonly stop: readonly [TasksStopQueryParams, TasksStopQueryResult];
2282
2308
  readonly 'sync.reconcile': readonly [TasksSyncReconcileParams, TasksSyncReconcileResult];
package/src/task.ts CHANGED
@@ -187,6 +187,14 @@ export interface CriterionEvidenceLink {
187
187
  artifactPaths: string[];
188
188
  /** Indices of actual validated result atoms in the containing gate's atoms array. */
189
189
  resultAtomIndices: number[];
190
+ /**
191
+ * How the `implemented` link is supported (T12689): `files` when a path the
192
+ * criterion names is among the inspected artifacts; `self-attested` when the
193
+ * criterion names no path in them, so the link rests on the agent's claim.
194
+ * Paths parsed from criterion text are advisory (T12118), so this flags
195
+ * rather than refuses. Absent on other gates and on older receipts.
196
+ */
197
+ basis?: 'files' | 'self-attested';
190
198
  }
191
199
 
192
200
  /** Verification failure log entry. */
@@ -390,6 +398,12 @@ export type EvidenceAtom =
390
398
  * (T12671): the task is linked through it and its files are the change.
391
399
  */
392
400
  componentPrNumber?: number;
401
+ /**
402
+ * Paths the (component) PR deleted that stay deleted in the landing
403
+ * commit (T12689). A deletion has no bytes to hash, so a PR whose every
404
+ * change is a deletion implements with `pr:` + `note:` instead of `files:`.
405
+ */
406
+ deletedPaths?: string[];
393
407
  }
394
408
  | {
395
409
  /**
@@ -63,6 +63,7 @@ export type {
63
63
  ScoreFactor,
64
64
  ScoreTaskContext,
65
65
  ScoreTaskInput,
66
+ ScoreTaskKey,
66
67
  ScoreTaskResult,
67
68
  } from './score-task-priority.js';
68
69
  // === Web + browser agent tools (T1742 / T11456) ===
@@ -6,7 +6,7 @@
6
6
  * @epic T9835
7
7
  */
8
8
 
9
- import type { TaskPriority } from '../task.js';
9
+ import type { TaskKind, TaskPriority, TaskSeverity } from '../task.js';
10
10
 
11
11
  /** Minimal task shape required by scoreTask. */
12
12
  export interface ScoreTaskInput {
@@ -24,6 +24,10 @@ export interface ScoreTaskInput {
24
24
  createdAt?: string;
25
25
  /** Labels for pattern matching. */
26
26
  labels?: string[];
27
+ /** Severity axis (orthogonal to priority); unset for most tasks. */
28
+ severity?: TaskSeverity | null;
29
+ /** Kind axis; a `bug` with no severity is scored at the default bug severity (T12661). */
30
+ kind?: TaskKind | null;
27
31
  }
28
32
 
29
33
  /** Context provided to scoreTask to enable phase-aware and dependency-aware scoring. */
@@ -38,6 +42,8 @@ export interface ScoreTaskContext {
38
42
  successPatterns?: Array<{ pattern: string }>;
39
43
  /** Matched failure patterns from BRAIN (optional penalty scoring). */
40
44
  failurePatterns?: Array<{ pattern: string }>;
45
+ /** Open tasks that depend on each task id — its leverage (bounded bonus, T12661). */
46
+ leverage?: ReadonlyMap<string, number>;
41
47
  }
42
48
 
43
49
  /** A scoring factor contributing to the final score. */
@@ -48,12 +54,32 @@ export interface ScoreFactor {
48
54
  delta: number;
49
55
  /** Human-readable explanation. */
50
56
  detail: string;
57
+ /**
58
+ * Comparator tier the factor belongs to (T12691): 1 priority band, 2 severity,
59
+ * 3 bounded tiebreak; `null` for an informational factor outside the order.
60
+ */
61
+ tier?: 1 | 2 | 3 | null;
62
+ }
63
+
64
+ /** The lexicographic sort key of a scored task (T12691); higher sorts first. */
65
+ export interface ScoreTaskKey {
66
+ /** Owner priority band: critical 4, high 3, medium 2, low 1. */
67
+ band: number;
68
+ /** Attested severity: P0 4, P1 3, P2 2, P3 1, unknown 0. */
69
+ severity: number;
70
+ /** Bounded computed tiebreak (deps, phase, leverage, age). */
71
+ tiebreak: number;
51
72
  }
52
73
 
53
74
  /** Result of scoreTask. */
54
75
  export interface ScoreTaskResult {
55
- /** Final computed score. */
76
+ /**
77
+ * The key as one number that sorts identically (band × 10000 + severity ×
78
+ * 1000 + tiebreak), for display and single-number consumers.
79
+ */
56
80
  score: number;
57
- /** Individual scoring factors. */
81
+ /** Individual scoring factors, each tagged with its comparator tier. */
58
82
  factors: ScoreFactor[];
83
+ /** The lexicographic sort key (T12691). */
84
+ key?: ScoreTaskKey;
59
85
  }