@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.
Files changed (165) hide show
  1. package/README.md +1 -1
  2. package/dist/__tests__/decide.test.d.ts +7 -0
  3. package/dist/__tests__/decide.test.d.ts.map +1 -0
  4. package/dist/__tests__/decide.test.js +91 -0
  5. package/dist/__tests__/decide.test.js.map +1 -0
  6. package/dist/__tests__/evidence-atom-schema.test.js +19 -1
  7. package/dist/__tests__/evidence-atom-schema.test.js.map +1 -1
  8. package/dist/__tests__/memory-wire-shapes.test.js.map +1 -1
  9. package/dist/acceptance-gate-schema.d.ts +5 -0
  10. package/dist/acceptance-gate-schema.d.ts.map +1 -1
  11. package/dist/acceptance-gate-schema.js +26 -0
  12. package/dist/acceptance-gate-schema.js.map +1 -1
  13. package/dist/acceptance-gate.d.ts +70 -3
  14. package/dist/acceptance-gate.d.ts.map +1 -1
  15. package/dist/backup-manifest.d.ts +13 -2
  16. package/dist/backup-manifest.d.ts.map +1 -1
  17. package/dist/branch-lock.d.ts +11 -0
  18. package/dist/branch-lock.d.ts.map +1 -1
  19. package/dist/branch-lock.js +31 -4
  20. package/dist/branch-lock.js.map +1 -1
  21. package/dist/cloud/api.d.ts +607 -0
  22. package/dist/cloud/api.d.ts.map +1 -0
  23. package/dist/cloud/api.js +417 -0
  24. package/dist/cloud/api.js.map +1 -0
  25. package/dist/cloud/envelope.d.ts +84 -0
  26. package/dist/cloud/envelope.d.ts.map +1 -0
  27. package/dist/cloud/envelope.js +54 -0
  28. package/dist/cloud/envelope.js.map +1 -0
  29. package/dist/cloud/ids.d.ts +30 -0
  30. package/dist/cloud/ids.d.ts.map +1 -0
  31. package/dist/cloud/ids.js +32 -0
  32. package/dist/cloud/ids.js.map +1 -0
  33. package/dist/cloud/index.d.ts +17 -0
  34. package/dist/cloud/index.d.ts.map +1 -0
  35. package/dist/cloud/index.js +17 -0
  36. package/dist/cloud/index.js.map +1 -0
  37. package/dist/data-accessor.d.ts +23 -3
  38. package/dist/data-accessor.d.ts.map +1 -1
  39. package/dist/data-accessor.js.map +1 -1
  40. package/dist/decide.d.ts +333 -0
  41. package/dist/decide.d.ts.map +1 -0
  42. package/dist/decide.js +184 -0
  43. package/dist/decide.js.map +1 -0
  44. package/dist/dispatch/operations-registry.d.ts.map +1 -1
  45. package/dist/dispatch/operations-registry.js +56 -0
  46. package/dist/dispatch/operations-registry.js.map +1 -1
  47. package/dist/done-plan.d.ts +330 -0
  48. package/dist/done-plan.d.ts.map +1 -0
  49. package/dist/done-plan.js +17 -0
  50. package/dist/done-plan.js.map +1 -0
  51. package/dist/evidence-atom-schema.d.ts +29 -44
  52. package/dist/evidence-atom-schema.d.ts.map +1 -1
  53. package/dist/evidence-atom-schema.js +48 -8
  54. package/dist/evidence-atom-schema.js.map +1 -1
  55. package/dist/exit-codes.d.ts +40 -0
  56. package/dist/exit-codes.d.ts.map +1 -1
  57. package/dist/exit-codes.js +41 -0
  58. package/dist/exit-codes.js.map +1 -1
  59. package/dist/graph.d.ts +40 -0
  60. package/dist/graph.d.ts.map +1 -1
  61. package/dist/index.d.ts +13 -6
  62. package/dist/index.d.ts.map +1 -1
  63. package/dist/index.js +4 -0
  64. package/dist/index.js.map +1 -1
  65. package/dist/memory/observe.d.ts +16 -0
  66. package/dist/memory/observe.d.ts.map +1 -1
  67. package/dist/operations/__tests__/release-shared-surface.test.d.ts +10 -0
  68. package/dist/operations/__tests__/release-shared-surface.test.d.ts.map +1 -0
  69. package/dist/operations/__tests__/release-shared-surface.test.js +84 -0
  70. package/dist/operations/__tests__/release-shared-surface.test.js.map +1 -0
  71. package/dist/operations/dialectic.d.ts +16 -0
  72. package/dist/operations/dialectic.d.ts.map +1 -1
  73. package/dist/operations/docs.d.ts +5 -2
  74. package/dist/operations/docs.d.ts.map +1 -1
  75. package/dist/operations/docs.js.map +1 -1
  76. package/dist/operations/memory.d.ts +48 -0
  77. package/dist/operations/memory.d.ts.map +1 -1
  78. package/dist/operations/nexus-scope-map.d.ts +8 -0
  79. package/dist/operations/nexus-scope-map.d.ts.map +1 -1
  80. package/dist/operations/nexus-scope-map.js +8 -0
  81. package/dist/operations/nexus-scope-map.js.map +1 -1
  82. package/dist/operations/nexus-user-profile.d.ts +27 -1
  83. package/dist/operations/nexus-user-profile.d.ts.map +1 -1
  84. package/dist/operations/nexus-user-profile.js +11 -1
  85. package/dist/operations/nexus-user-profile.js.map +1 -1
  86. package/dist/operations/nexus.d.ts +394 -3
  87. package/dist/operations/nexus.d.ts.map +1 -1
  88. package/dist/operations/release.d.ts +259 -0
  89. package/dist/operations/release.d.ts.map +1 -1
  90. package/dist/operations/release.js +130 -1
  91. package/dist/operations/release.js.map +1 -1
  92. package/dist/operations/session.d.ts +6 -4
  93. package/dist/operations/session.d.ts.map +1 -1
  94. package/dist/operations/tasks.d.ts +6 -0
  95. package/dist/operations/tasks.d.ts.map +1 -1
  96. package/dist/operations/tasks.js +1 -0
  97. package/dist/operations/tasks.js.map +1 -1
  98. package/dist/operations/validate.d.ts +5 -0
  99. package/dist/operations/validate.d.ts.map +1 -1
  100. package/dist/operations/worktree.d.ts +125 -1
  101. package/dist/operations/worktree.d.ts.map +1 -1
  102. package/dist/process-probe.d.ts +17 -0
  103. package/dist/process-probe.d.ts.map +1 -0
  104. package/dist/process-probe.js +21 -0
  105. package/dist/process-probe.js.map +1 -0
  106. package/dist/project-context.d.ts +44 -2
  107. package/dist/project-context.d.ts.map +1 -1
  108. package/dist/project-lifecycle.d.ts +143 -0
  109. package/dist/project-lifecycle.d.ts.map +1 -0
  110. package/dist/project-lifecycle.js +21 -0
  111. package/dist/project-lifecycle.js.map +1 -0
  112. package/dist/release/plan.d.ts +6 -2
  113. package/dist/release/plan.d.ts.map +1 -1
  114. package/dist/release/plan.js +8 -2
  115. package/dist/release/plan.js.map +1 -1
  116. package/dist/release/plan.test.js +6 -1
  117. package/dist/release/plan.test.js.map +1 -1
  118. package/dist/table-classification.d.ts +208 -0
  119. package/dist/table-classification.d.ts.map +1 -0
  120. package/dist/table-classification.js +23 -0
  121. package/dist/table-classification.js.map +1 -0
  122. package/dist/task.d.ts +97 -1
  123. package/dist/task.d.ts.map +1 -1
  124. package/package.json +6 -2
  125. package/schemas/gate-result.schema.json +43 -0
  126. package/src/__tests__/__snapshots__/operations-registry.test.ts.snap +1 -1
  127. package/src/__tests__/decide.test.ts +139 -0
  128. package/src/__tests__/evidence-atom-schema.test.ts +24 -1
  129. package/src/__tests__/memory-wire-shapes.test.ts +3 -0
  130. package/src/acceptance-gate-schema.ts +29 -0
  131. package/src/acceptance-gate.ts +68 -3
  132. package/src/backup-manifest.ts +13 -2
  133. package/src/branch-lock.ts +36 -4
  134. package/src/cloud/api.ts +512 -0
  135. package/src/cloud/envelope.ts +63 -0
  136. package/src/cloud/ids.ts +51 -0
  137. package/src/cloud/index.ts +16 -0
  138. package/src/data-accessor.ts +24 -3
  139. package/src/decide.ts +355 -0
  140. package/src/dispatch/operations-registry.ts +59 -0
  141. package/src/done-plan.ts +370 -0
  142. package/src/evidence-atom-schema.ts +51 -9
  143. package/src/exit-codes.ts +42 -0
  144. package/src/graph.ts +44 -0
  145. package/src/index.ts +118 -0
  146. package/src/memory/observe.ts +16 -0
  147. package/src/operations/__tests__/release-shared-surface.test.ts +112 -0
  148. package/src/operations/dialectic.ts +17 -0
  149. package/src/operations/docs.ts +5 -2
  150. package/src/operations/memory.ts +48 -0
  151. package/src/operations/nexus-scope-map.ts +9 -0
  152. package/src/operations/nexus-user-profile.ts +29 -1
  153. package/src/operations/nexus.ts +416 -3
  154. package/src/operations/release.ts +197 -0
  155. package/src/operations/session.ts +6 -4
  156. package/src/operations/tasks.ts +7 -0
  157. package/src/operations/validate.ts +5 -0
  158. package/src/operations/worktree.ts +133 -1
  159. package/src/process-probe.ts +21 -0
  160. package/src/project-context.ts +42 -2
  161. package/src/project-lifecycle.ts +149 -0
  162. package/src/release/plan.test.ts +6 -1
  163. package/src/release/plan.ts +8 -2
  164. package/src/table-classification.ts +232 -0
  165. package/src/task.ts +102 -2
package/src/index.ts CHANGED
@@ -365,6 +365,7 @@ export type {
365
365
  TaskFieldUpdates,
366
366
  TaskPopulation,
367
367
  TaskQueryFilters,
368
+ TaskWriteGuard,
368
369
  TransactionAccessor,
369
370
  } from './data-accessor.js';
370
371
  // === Database Inventory (Saga T10281 / Epic T10282 / Task T10305 — SG-BRAIN-DB-RESILIENCE) ===
@@ -512,6 +513,28 @@ export type {
512
513
  WorktreeAnomaly,
513
514
  WorktreeAnomalyKind,
514
515
  } from './doctor.js';
516
+ // === Done planner: read-only `cleo done --plan` evidence plan (T12623, T12624) ===
517
+ export type {
518
+ ChangeSetDoc,
519
+ ChangeSetMergeState,
520
+ ChangeSetPrCandidate,
521
+ ChangeSetRootSource,
522
+ ChangeSetSource,
523
+ DoneBlockedDetails,
524
+ DoneNextStep,
525
+ DonePlan,
526
+ DonePlanAcBasis,
527
+ DonePlanAcMapping,
528
+ DonePlanBlocker,
529
+ DonePlanBlockerCode,
530
+ DonePlanGate,
531
+ DonePlanToolCacheState,
532
+ DonePlanToolRun,
533
+ DonePlanTypedGate,
534
+ DoneRecordResult,
535
+ DoneToolResult,
536
+ TaskChangeSet,
537
+ } from './done-plan.js';
515
538
  export type {
516
539
  EngineErrorPayload,
517
540
  EngineFailure,
@@ -715,7 +738,11 @@ export type {
715
738
  ExtractedProvenance,
716
739
  GraphEdgeConfidenceLabel,
717
740
  GraphIndexAssessment,
741
+ GraphIndexAssessmentProjection,
742
+ GraphIndexFilePage,
718
743
  GraphIndexFileReport,
744
+ GraphIndexFileStatus,
745
+ GraphIndexFileStatusCounts,
719
746
  GraphIndexFreshness,
720
747
  GraphIndexReferenceReport,
721
748
  GraphIndexRunSummary,
@@ -1274,6 +1301,7 @@ export type {
1274
1301
  ApplyInsightsResult,
1275
1302
  DialecticInsights,
1276
1303
  DialecticTurn,
1304
+ DialecticTurnOrigin,
1277
1305
  EvaluateDialecticParams,
1278
1306
  EvaluateDialecticResult,
1279
1307
  } from './operations/dialectic.js';
@@ -1457,6 +1485,7 @@ export type {
1457
1485
  NexusDepsEntry,
1458
1486
  NexusDepsParams,
1459
1487
  NexusDepsResult,
1488
+ NexusDeviceRecord,
1460
1489
  NexusDiffHealth,
1461
1490
  NexusDiffParams,
1462
1491
  NexusDiffResult,
@@ -1468,6 +1497,7 @@ export type {
1468
1497
  NexusFlowsResult,
1469
1498
  NexusFullContextParams,
1470
1499
  NexusFullContextResult,
1500
+ NexusGitProbeErrorCode,
1471
1501
  NexusGraphEdge,
1472
1502
  NexusGraphNode,
1473
1503
  NexusGraphParams,
@@ -1497,14 +1527,20 @@ export type {
1497
1527
  NexusPermissionLevel,
1498
1528
  NexusPermissionSetParams,
1499
1529
  NexusPermissionSetResult,
1530
+ NexusProjectCandidate,
1500
1531
  NexusProjectCheckout,
1532
+ NexusProjectGitState,
1533
+ NexusProjectLocationState,
1501
1534
  NexusProjectRecord,
1502
1535
  NexusProjectStats,
1536
+ NexusProjectsCleanIdMismatch,
1503
1537
  NexusProjectsCleanParams,
1504
1538
  NexusProjectsCleanReason,
1505
1539
  NexusProjectsCleanReceipt,
1540
+ NexusProjectsCleanRelocated,
1506
1541
  NexusProjectsCleanRemoval,
1507
1542
  NexusProjectsCleanResult,
1543
+ NexusProjectsCleanUnreadable,
1508
1544
  NexusProjectsListParams,
1509
1545
  NexusProjectsListResult,
1510
1546
  NexusProjectsRegisterParams,
@@ -1513,6 +1549,8 @@ export type {
1513
1549
  NexusProjectsRemoveResult,
1514
1550
  NexusProjectsScanParams,
1515
1551
  NexusProjectsScanResult,
1552
+ NexusProjectsStatusParams,
1553
+ NexusProjectsStatusResult,
1516
1554
  NexusQueryCteParams,
1517
1555
  NexusQueryCteResult,
1518
1556
  NexusReconcileParams,
@@ -1521,7 +1559,15 @@ export type {
1521
1559
  NexusRefreshBridgeResult,
1522
1560
  NexusRegisterParams,
1523
1561
  NexusRegisterResult,
1562
+ NexusRegistryAmbiguousAlias,
1524
1563
  NexusRegistryClassification,
1564
+ NexusRegistryFinding,
1565
+ NexusRegistryFindingKind,
1566
+ NexusRegistryIntegrityReport,
1567
+ NexusRegistryRepairAction,
1568
+ NexusRegistryRepairReceipt,
1569
+ NexusRegistryRollbackResult,
1570
+ NexusRegistrySplitPeer,
1525
1571
  NexusResolveParams,
1526
1572
  NexusResolveResult,
1527
1573
  NexusRouteMapParams,
@@ -1610,8 +1656,10 @@ export type {
1610
1656
  NexusProfileUpsertResult,
1611
1657
  NexusProfileViewParams,
1612
1658
  NexusProfileViewResult,
1659
+ UserProfileScope,
1613
1660
  UserProfileTrait,
1614
1661
  } from './operations/nexus-user-profile.js';
1662
+ export { USER_PROFILE_SCOPES } from './operations/nexus-user-profile.js';
1615
1663
  // Commonly used ops types re-exported at top level for convenience
1616
1664
  export type {
1617
1665
  BrainState,
@@ -1932,6 +1980,10 @@ export type {
1932
1980
  WorktreeLifecycleAction,
1933
1981
  WorktreeLifecycleAuditEntry,
1934
1982
  WorktreeListEntry,
1983
+ WorktreeLockAcquisition,
1984
+ WorktreeLockAcquisitionStatus,
1985
+ WorktreeLockHolder,
1986
+ WorktreeLockRecord,
1935
1987
  WorktreeSource,
1936
1988
  WorktreeStatusCategory,
1937
1989
  } from './operations/worktree.js';
@@ -2011,6 +2063,8 @@ export type {
2011
2063
  SyncResult,
2012
2064
  SyncStatus,
2013
2065
  } from './postgres-data-accessor.js';
2066
+ // === Process-table probe constants (T12500 · T12506) ===
2067
+ export { PS_STABLE_ENV } from './process-probe.js';
2014
2068
  // === Project Context (ecosystem detection types) ===
2015
2069
  export type {
2016
2070
  EcosystemHint,
@@ -2020,6 +2074,16 @@ export type {
2020
2074
  ProjectType,
2021
2075
  TestFramework,
2022
2076
  } from './project-context.js';
2077
+ // === Project relocation (move / reroot — T12552 · T12558) ===
2078
+ export type {
2079
+ MoveProjectResult,
2080
+ ProjectMovedTombstone,
2081
+ ProjectRelocationExclusion,
2082
+ ProjectRelocationKind,
2083
+ ProjectRelocationPlan,
2084
+ ProjectRelocationRegistryAction,
2085
+ RerootProjectResult,
2086
+ } from './project-lifecycle.js';
2023
2087
  // === ProjectTools Contracts (scaffold-project, doctor-project, scaffold-global — T10069 / T9835b) ===
2024
2088
  export type {
2025
2089
  DoctorProjectOptions,
@@ -2400,6 +2464,20 @@ export {
2400
2464
  SupervisorIpcResponseEnvelopeSchema,
2401
2465
  SupervisorIpcResponseSchema,
2402
2466
  } from './supervisor-ipc/index.js';
2467
+ // === Table Classification Types (T12332 — Gate A replication classes) ===
2468
+ export type {
2469
+ ColumnClass,
2470
+ ColumnOverride,
2471
+ PendingTableClassification,
2472
+ RowRouting,
2473
+ TableClass,
2474
+ TableClassification,
2475
+ TableClassificationStatus,
2476
+ TablePatternRule,
2477
+ TableRegistryEntry,
2478
+ TableScope,
2479
+ TableScopeRegistry,
2480
+ } from './table-classification.js';
2403
2481
  // === Task Types ===
2404
2482
  export type {
2405
2483
  AcceptanceItem,
@@ -2807,4 +2885,44 @@ export {
2807
2885
  DEFAULT_IDENTITY_FIELD,
2808
2886
  } from './collection-keys.js';
2809
2887
 
2888
+ // === Typed-decision contracts (T12489 · epic T12486) ===
2889
+ export type {
2890
+ ChoiceDecisionAnswer,
2891
+ ChoiceDecisionQuestion,
2892
+ DecisionAnswer,
2893
+ DecisionInstructions,
2894
+ DecisionJsonValue,
2895
+ DecisionOutcome,
2896
+ DecisionOutcomeSource,
2897
+ DecisionProviderConfig,
2898
+ DecisionQuestion,
2899
+ DecisionQuestionType,
2900
+ DecisionRequest,
2901
+ DecisionState,
2902
+ NoulDecisionAnswer,
2903
+ NoulDecisionQuestion,
2904
+ ScoreDecisionAnswer,
2905
+ ScoreDecisionQuestion,
2906
+ } from './decide.js';
2907
+ export {
2908
+ choiceDecisionAnswerSchema,
2909
+ choiceDecisionQuestionSchema,
2910
+ DECISION_OUTCOME_SOURCES,
2911
+ DECISION_QUESTION_TYPES,
2912
+ DECISION_REQUEST_LIMITS,
2913
+ decisionAnswerSchema,
2914
+ decisionInstructionsSchema,
2915
+ decisionOutcomeSchema,
2916
+ decisionOutcomeSourceSchema,
2917
+ decisionProviderConfigSchema,
2918
+ decisionQuestionSchema,
2919
+ decisionQuestionTypeSchema,
2920
+ decisionRequestSchema,
2921
+ decisionStateSchema,
2922
+ noulDecisionAnswerSchema,
2923
+ noulDecisionQuestionSchema,
2924
+ scoreDecisionAnswerSchema,
2925
+ scoreDecisionQuestionSchema,
2926
+ } from './decide.js';
2927
+
2810
2928
  export { isStorableTaskId, isTaskId, TASK_ID_REGEX, type TaskId } from './task-id.js';
@@ -115,6 +115,13 @@ export interface ObserveBrainParams {
115
115
  * Null for directly-observed rows.
116
116
  */
117
117
  provenanceChain?: string[] | null;
118
+ /**
119
+ * T12494: opt in to a System One type choice when `type` is absent.
120
+ * Set ONLY by the interactive `memory.observe` operation (`cleo memory
121
+ * observe`). Background writers leave it unset, so they never send their
122
+ * content to a provider; their type comes from the keyword heuristic.
123
+ */
124
+ askTypeDecision?: boolean;
118
125
  /**
119
126
  * T992: Internal flag — when true, bypasses the verifyAndStore gate.
120
127
  * Set by storeVerifiedCandidate in extraction-gate.ts to avoid recursion,
@@ -148,6 +155,15 @@ export interface ObserveBrainResult {
148
155
  type: string;
149
156
  /** ISO 8601 creation timestamp. */
150
157
  createdAt: string;
158
+ /**
159
+ * T12494: where the stored type came from — `caller` (explicit `type`),
160
+ * `keyword` (whole-word keyword heuristic) or `system-one` (a confident
161
+ * System One `choice` in `on` mode). Absent when not determined on this path
162
+ * (e.g. the extraction gate merged or rejected the write).
163
+ */
164
+ typeSource?: 'caller' | 'keyword' | 'system-one';
165
+ /** T12494: confidence behind a `keyword` (flat 0.5) or `system-one` type. */
166
+ typeConfidence?: number;
151
167
  }
152
168
 
153
169
  // ── DocAttachmentObservationPayload ─────────────────────────────────
@@ -0,0 +1,112 @@
1
+ /**
2
+ * T10483 — release command/template shared-surface contract.
3
+ *
4
+ * These tests pin the taxonomy needed by T10468/T10476: shipped CLEO release
5
+ * commands, cleocode dogfood workflow templates, and the command↔template seams
6
+ * that are shared public surfaces. They also protect deterministic
7
+ * changesets-first release planning and the no-LLM blocking path invariant.
8
+ */
9
+
10
+ import { existsSync, readdirSync } from 'node:fs';
11
+ import { fileURLToPath } from 'node:url';
12
+ import { describe, expect, it } from 'vitest';
13
+ import {
14
+ RELEASE_SHARED_COMMAND_SURFACES,
15
+ RELEASE_SHARED_SURFACE_CONTRACT,
16
+ RELEASE_SHARED_TEMPLATE_SURFACES,
17
+ } from '../release.js';
18
+
19
+ /** Repository root, resolved from this file (`packages/contracts/src/operations/__tests__`). */
20
+ const REPO_ROOT = fileURLToPath(new URL('../../../../../', import.meta.url));
21
+ /** The shipped workflow-template directory the contract claims to cover. */
22
+ const WORKFLOW_TEMPLATE_DIR = fileURLToPath(
23
+ new URL('../../../../core/templates/workflows/', import.meta.url),
24
+ );
25
+
26
+ describe('release shared-surface contract (T10483)', () => {
27
+ it('classifies shipped release surfaces as consumer tooling or shared, never dogfood', () => {
28
+ const audiences = new Set<string>([
29
+ ...RELEASE_SHARED_COMMAND_SURFACES.map((surface) => surface.audience),
30
+ ...RELEASE_SHARED_TEMPLATE_SURFACES.map((surface) => surface.audience),
31
+ ]);
32
+
33
+ // Dogfood-only owner CI lives in the cleocode repo's .github/workflows and
34
+ // is never shipped, so no shipped command or template may carry it.
35
+ expect(audiences).toEqual(new Set(['shipped-consumer-tooling', 'shared-surface']));
36
+ });
37
+
38
+ it('pins every command to its registered dispatch gateway/operation', () => {
39
+ const byCommand = new Map(
40
+ RELEASE_SHARED_COMMAND_SURFACES.map((surface) => [
41
+ surface.command,
42
+ `${surface.gateway}:${surface.operation}`,
43
+ ]),
44
+ );
45
+
46
+ expect(byCommand).toEqual(
47
+ new Map([
48
+ ['cleo release plan', 'mutate:release.plan'],
49
+ ['cleo release open', 'mutate:release.open'],
50
+ ['cleo release reconcile', 'mutate:release.reconcile'],
51
+ ['cleo release rollback', 'mutate:pipeline.release.rollback'],
52
+ ]),
53
+ );
54
+ });
55
+
56
+ it('covers each shipped release workflow template on disk exactly once', () => {
57
+ // Compare against the real template directory, not a restated list, so a
58
+ // template added or removed without updating the contract fails here.
59
+ const onDisk = readdirSync(WORKFLOW_TEMPLATE_DIR)
60
+ .filter((name) => name.endsWith('.yml.tmpl'))
61
+ .map((name) => name.replace(/\.tmpl$/, ''))
62
+ .sort();
63
+ const rendered = RELEASE_SHARED_TEMPLATE_SURFACES.map((surface) => surface.renderedWorkflow);
64
+
65
+ expect(onDisk.length).toBeGreaterThan(0);
66
+ expect([...rendered].sort()).toEqual(onDisk);
67
+ for (const surface of RELEASE_SHARED_TEMPLATE_SURFACES) {
68
+ expect(existsSync(`${REPO_ROOT}${surface.template}`), surface.template).toBe(true);
69
+ expect(surface.template.endsWith(`/${surface.renderedWorkflow}.tmpl`)).toBe(true);
70
+ }
71
+ });
72
+
73
+ it('pins deterministic changesets-first planning as local and network-free', () => {
74
+ const plan = RELEASE_SHARED_COMMAND_SURFACES.find(
75
+ (surface) =>
76
+ surface.command === RELEASE_SHARED_SURFACE_CONTRACT.invariants.deterministicPlanningCommand,
77
+ );
78
+
79
+ expect(plan).toBeDefined();
80
+ expect(plan?.operation).toBe('release.plan');
81
+ expect(plan?.deterministic).toBe(true);
82
+ expect(plan?.mayCallNetwork).toBe(false);
83
+ expect(plan?.changesetRequired).toBe(true);
84
+ });
85
+
86
+ it('forbids LLM-first blocking paths on every release command and workflow template', () => {
87
+ expect(RELEASE_SHARED_SURFACE_CONTRACT.invariants.llmBlockingPathAllowed).toBe(false);
88
+
89
+ for (const surface of RELEASE_SHARED_COMMAND_SURFACES) {
90
+ expect(surface.llmBlockingPath).toBe(false);
91
+ }
92
+ for (const surface of RELEASE_SHARED_TEMPLATE_SURFACES) {
93
+ expect(surface.llmBlockingPath).toBe(false);
94
+ }
95
+ });
96
+
97
+ it('keeps public workflow templates attached to a shipped owner command', () => {
98
+ const commands = new Set(RELEASE_SHARED_COMMAND_SURFACES.map((surface) => surface.command));
99
+
100
+ for (const template of RELEASE_SHARED_TEMPLATE_SURFACES) {
101
+ expect(template.template).toMatch(
102
+ /^packages\/core\/templates\/workflows\/release-.+\.yml\.tmpl$/,
103
+ );
104
+ expect(template.renderSnapshotRequired).toBe(true);
105
+ if (template.stability === 'public-contract') {
106
+ expect(commands.has(template.owningCommand), template.owningCommand).toBe(true);
107
+ expect(template.audience).toBe('shared-surface');
108
+ expect(template.consumesReleasePlan).toBe(true);
109
+ }
110
+ }
111
+ });
112
+ });
@@ -55,8 +55,25 @@ export interface DialecticTurn {
55
55
  activePeerId: string;
56
56
  /** Session ID from the CLEO session store (e.g. `ses_20260422131135_5149eb`). */
57
57
  sessionId: string;
58
+ /**
59
+ * Structural origin of the turn (T12543). Omitted means `'conversation'`.
60
+ *
61
+ * `'operation-envelope'` marks a turn synthesised from a dispatched
62
+ * operation and its result envelope (the CQRS dispatcher hook). Such a turn
63
+ * carries no user utterance, so it can never yield a user trait: the
64
+ * evaluator drops every global trait for it and keeps only peer insights
65
+ * and the narrative delta.
66
+ */
67
+ origin?: DialecticTurnOrigin;
58
68
  }
59
69
 
70
+ /**
71
+ * Structural origin of a {@link DialecticTurn}.
72
+ *
73
+ * @task T12543
74
+ */
75
+ export type DialecticTurnOrigin = 'conversation' | 'operation-envelope';
76
+
60
77
  /**
61
78
  * Structured insights extracted from a single dialectic turn.
62
79
  *
@@ -715,7 +715,9 @@ export type DocsLifecycleStatus = (typeof DOCS_LIFECYCLE_STATUSES)[number];
715
715
  * {@link DocsSupersedeParams}-style flows, NO supersession edge is created
716
716
  * (callers wanting an explicit lineage edge should use `cleo docs supersede`).
717
717
  *
718
- * Exactly one of `file` or `content` MUST be provided.
718
+ * At most one of `file` or `content` may be provided. With neither, `status`
719
+ * is required and the update changes only the lifecycle status, keeping the
720
+ * stored bytes (T12654).
719
721
  *
720
722
  * @task T10161 (Epic T10157 / Saga T9855 — E12.C4)
721
723
  */
@@ -738,7 +740,8 @@ export interface DocsUpdateParams {
738
740
  /**
739
741
  * Override the new lifecycle status. Defaults to `'draft'` on every update
740
742
  * so an explicit `accepted` doc gets back-pressured to draft on edit. Pass
741
- * `--status accepted` (or any other valid status) to override.
743
+ * `--status accepted` (or any other valid status) to override. Passed alone
744
+ * (no `file`/`content`), it changes only the lifecycle status.
742
745
  */
743
746
  status?: DocsLifecycleStatus;
744
747
  /** Validate/preflight only; do not mutate attachment rows, blob storage, or audit logs. */
@@ -1223,6 +1223,17 @@ export interface RetrievalObservation {
1223
1223
  * until the T1147 W7 sweep stamps them as clean.
1224
1224
  */
1225
1225
  provenanceClass?: string;
1226
+ /**
1227
+ * Stored quality score in [0, 1] (`quality_score` column), when the row
1228
+ * carries one. Used to rank entries inside the spawn-prompt PSYCHE-MEMORY
1229
+ * budget (T12519). Absent on legacy schemas.
1230
+ */
1231
+ qualityScore?: number;
1232
+ /**
1233
+ * Number of times this entry has been cited (`citation_count` column).
1234
+ * Secondary ranking signal for the PSYCHE-MEMORY budget (T12519).
1235
+ */
1236
+ citationCount?: number;
1226
1237
  }
1227
1238
 
1228
1239
  /**
@@ -1241,6 +1252,17 @@ export interface RetrievalLearning {
1241
1252
  * until the T1147 W7 sweep stamps them as clean.
1242
1253
  */
1243
1254
  provenanceClass?: string;
1255
+ /**
1256
+ * Stored quality score in [0, 1] (`quality_score` column), when the row
1257
+ * carries one. Used to rank entries inside the spawn-prompt PSYCHE-MEMORY
1258
+ * budget (T12519). Absent on legacy schemas.
1259
+ */
1260
+ qualityScore?: number;
1261
+ /**
1262
+ * Number of times this entry has been cited (`citation_count` column).
1263
+ * Secondary ranking signal for the PSYCHE-MEMORY budget (T12519).
1264
+ */
1265
+ citationCount?: number;
1244
1266
  }
1245
1267
 
1246
1268
  /**
@@ -1259,6 +1281,17 @@ export interface RetrievalPattern {
1259
1281
  * until the T1147 W7 sweep stamps them as clean.
1260
1282
  */
1261
1283
  provenanceClass?: string;
1284
+ /**
1285
+ * Stored quality score in [0, 1] (`quality_score` column), when the row
1286
+ * carries one. Used to rank entries inside the spawn-prompt PSYCHE-MEMORY
1287
+ * budget (T12519). Absent on legacy schemas.
1288
+ */
1289
+ qualityScore?: number;
1290
+ /**
1291
+ * Number of times this entry has been cited (`citation_count` column).
1292
+ * Secondary ranking signal for the PSYCHE-MEMORY budget (T12519).
1293
+ */
1294
+ citationCount?: number;
1262
1295
  }
1263
1296
 
1264
1297
  /**
@@ -1277,6 +1310,21 @@ export interface RetrievalDecision {
1277
1310
  * until the T1147 W7 sweep stamps them as clean.
1278
1311
  */
1279
1312
  provenanceClass?: string;
1313
+ /**
1314
+ * Stored quality score in [0, 1] (`quality_score` column), when the row
1315
+ * carries one. Used to rank entries inside the spawn-prompt PSYCHE-MEMORY
1316
+ * budget (T12519). Absent on legacy schemas.
1317
+ */
1318
+ qualityScore?: number;
1319
+ /**
1320
+ * Number of times this entry has been cited (`citation_count` column).
1321
+ * Secondary ranking signal for the PSYCHE-MEMORY budget (T12519).
1322
+ */
1323
+ citationCount?: number;
1324
+ /** Task the decision was recorded against (`context_task_id`), if any (T12519). */
1325
+ contextTaskId?: string | null;
1326
+ /** Epic the decision was recorded against (`context_epic_id`), if any (T12519). */
1327
+ contextEpicId?: string | null;
1280
1328
  }
1281
1329
 
1282
1330
  /**
@@ -505,6 +505,15 @@ export const NEXUS_SCOPE_MAP = {
505
505
  stores: ['nexus-registry'],
506
506
  requiresProject: false,
507
507
  },
508
+ 'projects.status': {
509
+ op: 'projects.status',
510
+ description:
511
+ 'Probe git state (branch, head, dirty, upstream, ahead/behind) of every location on this device and record it.',
512
+ scope: 'global',
513
+ effect: 'write',
514
+ stores: ['nexus-registry', 'fs'],
515
+ requiresProject: false,
516
+ },
508
517
  'refresh-bridge': {
509
518
  op: 'refresh-bridge',
510
519
  description: 'Refresh the Nexus → BRAIN cross-store bridge.',
@@ -24,6 +24,18 @@
24
24
  // Shared domain types
25
25
  // ============================================================================
26
26
 
27
+ /**
28
+ * Legal visibility scopes for a user-profile trait (T12543).
29
+ *
30
+ * - `project` — visible only to agents working in the project whose portable
31
+ * id is stamped on the trait (`projectId`). The default for every new row.
32
+ * - `user` — explicitly marked user-global: visible in every project.
33
+ */
34
+ export const USER_PROFILE_SCOPES = ['project', 'user'] as const;
35
+
36
+ /** Visibility scope of a user-profile trait. See {@link USER_PROFILE_SCOPES}. */
37
+ export type UserProfileScope = (typeof USER_PROFILE_SCOPES)[number];
38
+
27
39
  /**
28
40
  * A single user-profile trait record.
29
41
  *
@@ -61,6 +73,22 @@ export interface UserProfileTrait {
61
73
  * Set by `supersedeTrait` (T1139 supersession graph prep).
62
74
  */
63
75
  supersededBy: string | null;
76
+ /**
77
+ * Portable project id (`.cleo/project-id`, ADR-094) of the project the trait
78
+ * was derived in. `null` = unknown origin (rows written before T12543).
79
+ * Omitted on input means `null`.
80
+ *
81
+ * @task T12543
82
+ */
83
+ projectId?: string | null;
84
+ /**
85
+ * Visibility scope. Omitted on input means `'project'`. Spawn prompts include
86
+ * only `user` traits plus `project` traits whose `projectId` is the current
87
+ * project; unknown-origin rows are excluded.
88
+ *
89
+ * @task T12543
90
+ */
91
+ scope?: UserProfileScope;
64
92
  }
65
93
 
66
94
  // ============================================================================
@@ -180,7 +208,7 @@ export interface NexusProfileUpsertParams {
180
208
  /** Trait to create or update (required). */
181
209
  trait: Pick<
182
210
  UserProfileTrait,
183
- 'traitKey' | 'traitValue' | 'confidence' | 'source' | 'derivedFromMessageId'
211
+ 'traitKey' | 'traitValue' | 'confidence' | 'source' | 'derivedFromMessageId' | 'scope'
184
212
  >;
185
213
  }
186
214