@cleocode/contracts 2026.9.23 → 2026.9.25

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 (85) hide show
  1. package/dist/branch-lock.d.ts +51 -0
  2. package/dist/branch-lock.d.ts.map +1 -1
  3. package/dist/branch-lock.js +25 -3
  4. package/dist/branch-lock.js.map +1 -1
  5. package/dist/cloud/api.d.ts +1 -1
  6. package/dist/data-accessor.d.ts +270 -16
  7. package/dist/data-accessor.d.ts.map +1 -1
  8. package/dist/data-accessor.js.map +1 -1
  9. package/dist/decide.d.ts +110 -1
  10. package/dist/decide.d.ts.map +1 -1
  11. package/dist/decide.js +23 -0
  12. package/dist/decide.js.map +1 -1
  13. package/dist/dispatch/operations-registry.d.ts.map +1 -1
  14. package/dist/dispatch/operations-registry.js +137 -6
  15. package/dist/dispatch/operations-registry.js.map +1 -1
  16. package/dist/doctor.d.ts +9 -0
  17. package/dist/doctor.d.ts.map +1 -1
  18. package/dist/exit-codes.d.ts +7 -0
  19. package/dist/exit-codes.d.ts.map +1 -1
  20. package/dist/exit-codes.js +7 -0
  21. package/dist/exit-codes.js.map +1 -1
  22. package/dist/index.d.ts +10 -6
  23. package/dist/index.d.ts.map +1 -1
  24. package/dist/index.js +3 -1
  25. package/dist/index.js.map +1 -1
  26. package/dist/knowledge-health.d.ts +21 -0
  27. package/dist/knowledge-health.d.ts.map +1 -1
  28. package/dist/nexus-account.d.ts +160 -0
  29. package/dist/nexus-account.d.ts.map +1 -0
  30. package/dist/nexus-account.js +68 -0
  31. package/dist/nexus-account.js.map +1 -0
  32. package/dist/operations/focus.d.ts +7 -3
  33. package/dist/operations/focus.d.ts.map +1 -1
  34. package/dist/operations/nexus-scope-map.d.ts +8 -0
  35. package/dist/operations/nexus-scope-map.d.ts.map +1 -1
  36. package/dist/operations/nexus-scope-map.js +8 -0
  37. package/dist/operations/nexus-scope-map.js.map +1 -1
  38. package/dist/operations/nexus.d.ts +265 -0
  39. package/dist/operations/nexus.d.ts.map +1 -1
  40. package/dist/operations/nexus.js +9 -1
  41. package/dist/operations/nexus.js.map +1 -1
  42. package/dist/operations/orchestrate.d.ts +6 -1
  43. package/dist/operations/orchestrate.d.ts.map +1 -1
  44. package/dist/operations/output-contracts-data.d.ts.map +1 -1
  45. package/dist/operations/output-contracts-data.js +115 -1
  46. package/dist/operations/output-contracts-data.js.map +1 -1
  47. package/dist/operations/tasks.d.ts +73 -9
  48. package/dist/operations/tasks.d.ts.map +1 -1
  49. package/dist/operations/tasks.js.map +1 -1
  50. package/dist/project-lifecycle.d.ts +6 -2
  51. package/dist/project-lifecycle.d.ts.map +1 -1
  52. package/dist/row-identity.d.ts +128 -0
  53. package/dist/row-identity.d.ts.map +1 -0
  54. package/dist/row-identity.js +20 -0
  55. package/dist/row-identity.js.map +1 -0
  56. package/dist/session.d.ts +19 -1
  57. package/dist/session.d.ts.map +1 -1
  58. package/dist/session.js +9 -2
  59. package/dist/session.js.map +1 -1
  60. package/dist/task.d.ts +56 -2
  61. package/dist/task.d.ts.map +1 -1
  62. package/dist/tools/score-task-priority.d.ts +1 -1
  63. package/dist/tools/score-task-priority.d.ts.map +1 -1
  64. package/package.json +2 -2
  65. package/src/__tests__/__snapshots__/operations-registry.test.ts.snap +1 -1
  66. package/src/branch-lock.ts +80 -3
  67. package/src/data-accessor.ts +283 -17
  68. package/src/decide.ts +127 -1
  69. package/src/dispatch/operations-registry.ts +144 -6
  70. package/src/doctor.ts +9 -0
  71. package/src/exit-codes.ts +7 -0
  72. package/src/index.ts +56 -0
  73. package/src/knowledge-health.ts +22 -0
  74. package/src/nexus-account.ts +181 -0
  75. package/src/operations/focus.ts +7 -3
  76. package/src/operations/nexus-scope-map.ts +9 -0
  77. package/src/operations/nexus.ts +281 -0
  78. package/src/operations/orchestrate.ts +6 -2
  79. package/src/operations/output-contracts-data.ts +125 -1
  80. package/src/operations/tasks.ts +78 -12
  81. package/src/project-lifecycle.ts +6 -2
  82. package/src/row-identity.ts +132 -0
  83. package/src/session.ts +20 -2
  84. package/src/task.ts +58 -2
  85. package/src/tools/score-task-priority.ts +1 -1
@@ -0,0 +1,132 @@
1
+ /**
2
+ * Row identity contracts — the uid every syncing row carries as its merge key
3
+ * (T12341).
4
+ *
5
+ * A table whose Gate A class syncs (`portable-*`) gets a `uid` column. The
6
+ * local primary key stays the local key and local foreign keys keep pointing
7
+ * at it; the uid is what a merge compares. The registry that declares, per
8
+ * table, how its uid is made lives in core (`store/row-identity.ts`); this
9
+ * module holds only the shapes.
10
+ *
11
+ * Spec: `cleo docs fetch t12341-uid-scheme`.
12
+ *
13
+ * Types only (arch gate 10): no runtime values are exported from here.
14
+ *
15
+ * @task T12341
16
+ * @epic T12323
17
+ * @module row-identity
18
+ */
19
+
20
+ /**
21
+ * How a table's uid is made.
22
+ *
23
+ * - `minted` — the local key was allocated on one device (`T####`, an
24
+ * autoincrement integer, a random id), so equal keys on two devices may be
25
+ * different rows. A new row gets a random UUIDv7; a row without a uid (an
26
+ * existing row, or one an older build wrote) gets a deterministic v7-layout
27
+ * uid over (table, key, birth, owner uids, content).
28
+ * - `natural` — the key is content or a relationship (an edge, a label), so
29
+ * equal keys mean the same row everywhere. The uid is a UUIDv8 over the key
30
+ * with every reference replaced by the referenced row's uid.
31
+ *
32
+ * @task T12341
33
+ */
34
+ export type RowIdentityKind = 'minted' | 'natural';
35
+
36
+ /**
37
+ * A column that holds another row's local key.
38
+ *
39
+ * @task T12341
40
+ */
41
+ export interface RowIdentityRef {
42
+ /** Physical column in this table. */
43
+ readonly column: string;
44
+ /** Physical table the column points into (its single-column local key). */
45
+ readonly table: string;
46
+ }
47
+
48
+ /**
49
+ * A stored copy of a fact about a referenced row, taken when the row is
50
+ * written: its uid (`ac_uid`, kept because an AC id is derived from the AC
51
+ * text and changes on edit), or the hash of its text (`ac_text_hash`, the
52
+ * text the evidence was recorded against).
53
+ *
54
+ * @task T12341
55
+ */
56
+ export interface StoredRefUid {
57
+ /** Physical column holding the copied fact (e.g. `ac_uid`). */
58
+ readonly column: string;
59
+ /** Column holding the referenced local key (e.g. `ac_id`). */
60
+ readonly from: string;
61
+ /** Referenced table. */
62
+ readonly table: string;
63
+ /** What is copied: the referenced row's uid (default) or the hash of its `text`. */
64
+ readonly source?: 'uid' | 'text_hash';
65
+ }
66
+
67
+ /**
68
+ * A relation table whose rows are symmetric for some values of a type column:
69
+ * the endpoint uids are hashed in sorted order, so `A related B` and
70
+ * `B related A` are one edge.
71
+ *
72
+ * @task T12341
73
+ */
74
+ export interface SymmetricEdge {
75
+ /** Column holding the relation type. */
76
+ readonly column: string;
77
+ /** Type values that are symmetric; every other value keeps direction. */
78
+ readonly values: readonly string[];
79
+ }
80
+
81
+ /**
82
+ * How one syncing table carries its uid.
83
+ *
84
+ * @task T12341
85
+ */
86
+ export interface RowIdentitySpec {
87
+ /** Physical table name. */
88
+ readonly table: string;
89
+ /** How the uid is made. */
90
+ readonly kind: RowIdentityKind;
91
+ /** Local key columns, in hash order. */
92
+ readonly key: readonly string[];
93
+ /** `minted`: the column recording when the row was created. */
94
+ readonly birth?: string;
95
+ /** `minted`: references whose target uid is part of the row's identity. */
96
+ readonly owners?: readonly RowIdentityRef[];
97
+ /**
98
+ * `minted`, append-only tables only: columns hashed into the uid. Their
99
+ * rows never change, and their keys collide across devices by construction.
100
+ */
101
+ readonly content?: readonly string[];
102
+ /** `natural`: key columns that reference rows; their target uid is hashed. */
103
+ readonly keyRefs?: readonly RowIdentityRef[];
104
+ /**
105
+ * `minted`: facts of the row's creation hashed into its birth fingerprint
106
+ * (`birth_fp`), besides the canonical birth. Each entry is a column name,
107
+ * `@ownerFp:<column>` (the birth fingerprint of the owner that column
108
+ * references, so the children of two colliding owners fingerprint apart),
109
+ * or `@refFp:<column>` (the fingerprint of the row a stored reference uid
110
+ * column names, e.g. the AC behind `ac_uid`).
111
+ * Read from the row as it is when its identity is first assigned; frozen
112
+ * per recipe version.
113
+ */
114
+ readonly birthFacts?: readonly string[];
115
+ /** `natural` relation tables: the symmetric relation types. */
116
+ readonly symmetric?: SymmetricEdge;
117
+ /**
118
+ * `minted`: every uid is random, never derived from content, including for
119
+ * existing rows. Required for `portable-secret` tables.
120
+ */
121
+ readonly randomOnly?: boolean;
122
+ /** Other references, translated to uids on the wire (not hashed). */
123
+ readonly refs?: readonly RowIdentityRef[];
124
+ /** JSON-array columns of referenced keys, translated element by element. */
125
+ readonly jsonArrayRefs?: readonly RowIdentityRef[];
126
+ /** Stored copies of referenced uids. */
127
+ readonly storedRefUids?: readonly StoredRefUid[];
128
+ /** The key is a user-facing display id that a collision re-mints. */
129
+ readonly displayId?: boolean;
130
+ /** Task that declared the table. */
131
+ readonly task: string;
132
+ }
package/src/session.ts CHANGED
@@ -132,6 +132,17 @@ export interface Session {
132
132
  * @defaultValue undefined
133
133
  */
134
134
  parentSessionId?: string | null;
135
+ /**
136
+ * ID of the orchestrator session that SPAWNED this one, recorded by the
137
+ * spawn itself (T12502). Unlike {@link Session.parentSessionId}, which a
138
+ * process declares for itself at `session start`, only the spawn writes
139
+ * this edge, so the task-claim chokepoint trusts it to let a spawn family
140
+ * pass a live lease between its members. Read-only on the session record:
141
+ * the whole-row session upsert never writes it.
142
+ *
143
+ * @defaultValue undefined
144
+ */
145
+ spawnedBySessionId?: string | null;
135
146
  /** Provider-specific agent identifier string. @defaultValue undefined */
136
147
  agentIdentifier?: string | null;
137
148
  /** ISO 8601 timestamp of when the handoff was consumed. @defaultValue undefined */
@@ -233,9 +244,16 @@ export class SessionView {
233
244
  return this._sessions.length;
234
245
  }
235
246
 
236
- /** Find the currently active session (if any). */
247
+ /**
248
+ * First `active` session in THIS collection — a scan over the rows the
249
+ * caller loaded, NOT the caller's own session (T12500). With several agents
250
+ * active it names an arbitrary one of them.
251
+ *
252
+ * @deprecated For "my session" use `resolveBoundSession` (mutations) or
253
+ * `resolveSessionForRead` (reads, labels an unbound guess).
254
+ */
237
255
  findActive(): Session | undefined {
238
- return this._sessions.find((s) => s.status === 'active');
256
+ return this._sessions.find((s) => s.status === 'active'); // get-active-session-allowed: collection scan over caller-supplied rows, not identity (T12500)
239
257
  }
240
258
 
241
259
  /** Find a session by ID. */
package/src/task.ts CHANGED
@@ -435,8 +435,28 @@ export type EvidenceAtom =
435
435
  /** Event of the judged run (`push`, `pull_request`, …), when known. */
436
436
  event?: string;
437
437
  }>;
438
- /** Tree of the merge commit — the content every recorded check tested. */
438
+ /** Tree of the merge commit — the content every check judged on it (or on a tree-equal PR head) tested. */
439
439
  testedTree?: string;
440
+ /**
441
+ * Later default-branch commit whose green `push` runs stood in for a
442
+ * required check the merge commit's own run only had cancelled or
443
+ * skipped (T12742). Its CI tested the DESCENDANT's tree, not the merge
444
+ * tree: it descends from the merge commit, and no commit in
445
+ * `descendantRange` — merge or not — touched the PR's changed files or a
446
+ * pinned CI workflow. Checks judged there record it as their `sha`.
447
+ */
448
+ descendantSha?: string;
449
+ /**
450
+ * `<mergeCommitSha>..<descendantSha>`: the first-parent range proven to
451
+ * leave the PR's files and the pinned workflows untouched (T12742).
452
+ */
453
+ descendantRange?: string;
454
+ /**
455
+ * Final PR head whose latest `pull_request` runs were green for every
456
+ * check the descendant stood in for (T12742); a descendant never
457
+ * vouches for a PR that was not itself green.
458
+ */
459
+ descendantPrHeadSha?: string;
440
460
  /** Task the PR was verified to be linked to (T12634). */
441
461
  taskId?: string;
442
462
  /** Component PR the task is linked through; its CI ran as this integration PR's (T12671). */
@@ -723,9 +743,22 @@ export interface Task {
723
743
  */
724
744
  pipelineStage?: string | null;
725
745
 
726
- /** Agent ID that has claimed/is assigned to this task. Null when unclaimed. @defaultValue undefined */
746
+ /**
747
+ * First-class human / owner assignee (`cleo assignee`, Studio boards).
748
+ * Separate from the agent work lease in {@link Task.claim}: `cleo start`,
749
+ * `cleo claim` and spawn never write it (T12502). @defaultValue undefined
750
+ */
727
751
  assignee?: string | null;
728
752
 
753
+ /**
754
+ * The agent work lease held on this task, when one is recorded (T12502).
755
+ * Absent when the task is unclaimed. Distinct from the human
756
+ * {@link Task.assignee}. Read-only on the task object: full-row writes
757
+ * never carry it, only the claim chokepoint changes it.
758
+ * @defaultValue undefined
759
+ */
760
+ claim?: TaskClaim;
761
+
729
762
  /**
730
763
  * Abort reason when a worker was stopped due to runaway detection (T1658).
731
764
  *
@@ -1020,3 +1053,26 @@ export interface TaskWorkState {
1020
1053
  /** ID of the primary session managing this work state. @defaultValue undefined */
1021
1054
  primarySession?: string | null;
1022
1055
  }
1056
+
1057
+ /**
1058
+ * A leased agent claim on a task (T12502 · epic T12497).
1059
+ *
1060
+ * Taken by `cleo start`, `cleo claim` and spawn with a compare-and-set in the
1061
+ * same write transaction; renewed by the holder session's activity or
1062
+ * `cleo claim <id> --renew`; released by `cleo stop`, completion,
1063
+ * cancellation, archive and the holder session ending. A claim whose
1064
+ * `leaseExpiresAt` has passed stays recorded until another session takes it
1065
+ * over explicitly (`--take-over`, audited).
1066
+ *
1067
+ * @task T12502
1068
+ */
1069
+ export interface TaskClaim {
1070
+ /** Session holding the lease. */
1071
+ sessionId: string;
1072
+ /** Agent identity of the holder (`CLEO_AGENT_ID` / spawn handle), or `null`. */
1073
+ agentId: string | null;
1074
+ /** ISO-8601 UTC instant the lease was taken. */
1075
+ claimedAt: string;
1076
+ /** ISO-8601 UTC instant the lease lapses unless renewed. */
1077
+ leaseExpiresAt: string;
1078
+ }
@@ -26,7 +26,7 @@ export interface ScoreTaskInput {
26
26
  labels?: string[];
27
27
  /** Severity axis (orthogonal to priority); unset for most tasks. */
28
28
  severity?: TaskSeverity | null;
29
- /** Kind axis; a `bug` with no severity is scored at the default bug severity (T12661). */
29
+ /** Kind axis; not part of the order — an unset severity is unknown, never imputed from `kind` (D11161). */
30
30
  kind?: TaskKind | null;
31
31
  }
32
32