@cleocode/core 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 (316) hide show
  1. package/dist/build-provenance.json +6 -0
  2. package/dist/decide/audit.d.ts +7 -1
  3. package/dist/decide/audit.d.ts.map +1 -1
  4. package/dist/decide/audit.js.map +1 -1
  5. package/dist/decide/client.d.ts +46 -4
  6. package/dist/decide/client.d.ts.map +1 -1
  7. package/dist/decide/client.js +328 -33
  8. package/dist/decide/client.js.map +1 -1
  9. package/dist/decide/credentials.d.ts +28 -4
  10. package/dist/decide/credentials.d.ts.map +1 -1
  11. package/dist/decide/credentials.js +50 -12
  12. package/dist/decide/credentials.js.map +1 -1
  13. package/dist/decide/index.d.ts +10 -4
  14. package/dist/decide/index.d.ts.map +1 -1
  15. package/dist/decide/index.js +10 -4
  16. package/dist/decide/index.js.map +1 -1
  17. package/dist/decide/jev-wire.d.ts +100 -8
  18. package/dist/decide/jev-wire.d.ts.map +1 -1
  19. package/dist/decide/jev-wire.js +402 -55
  20. package/dist/decide/jev-wire.js.map +1 -1
  21. package/dist/decide/operations.d.ts +97 -20
  22. package/dist/decide/operations.d.ts.map +1 -1
  23. package/dist/decide/operations.js +180 -28
  24. package/dist/decide/operations.js.map +1 -1
  25. package/dist/decide/provider-state.d.ts +89 -0
  26. package/dist/decide/provider-state.d.ts.map +1 -0
  27. package/dist/decide/provider-state.js +134 -0
  28. package/dist/decide/provider-state.js.map +1 -0
  29. package/dist/decide/provider.d.ts +26 -5
  30. package/dist/decide/provider.d.ts.map +1 -1
  31. package/dist/decide/provider.js.map +1 -1
  32. package/dist/decide/providers.d.ts +58 -0
  33. package/dist/decide/providers.d.ts.map +1 -0
  34. package/dist/decide/providers.js +69 -0
  35. package/dist/decide/providers.js.map +1 -0
  36. package/dist/decide/site.d.ts +2 -2
  37. package/dist/decide/site.d.ts.map +1 -1
  38. package/dist/decide/site.js +2 -0
  39. package/dist/decide/site.js.map +1 -1
  40. package/dist/decide/sites/list.d.ts +46 -0
  41. package/dist/decide/sites/list.d.ts.map +1 -0
  42. package/dist/decide/sites/list.js +206 -0
  43. package/dist/decide/sites/list.js.map +1 -0
  44. package/dist/decide/sites/registry.d.ts +130 -0
  45. package/dist/decide/sites/registry.d.ts.map +1 -0
  46. package/dist/decide/sites/registry.js +375 -0
  47. package/dist/decide/sites/registry.js.map +1 -0
  48. package/dist/decide/spend.d.ts +196 -0
  49. package/dist/decide/spend.d.ts.map +1 -0
  50. package/dist/decide/spend.js +387 -0
  51. package/dist/decide/spend.js.map +1 -0
  52. package/dist/decide/wizard.d.ts +53 -0
  53. package/dist/decide/wizard.d.ts.map +1 -0
  54. package/dist/decide/wizard.js +144 -0
  55. package/dist/decide/wizard.js.map +1 -0
  56. package/dist/docs/docs-audit.d.ts.map +1 -1
  57. package/dist/docs/docs-audit.js +1 -2
  58. package/dist/docs/docs-audit.js.map +1 -1
  59. package/dist/docs/export-document.js +775 -415
  60. package/dist/docs/export-document.js.map +3 -3
  61. package/dist/index.d.ts +2 -2
  62. package/dist/index.d.ts.map +1 -1
  63. package/dist/index.js +1 -1
  64. package/dist/index.js.map +1 -1
  65. package/dist/init/scaffold-workflows.d.ts.map +1 -1
  66. package/dist/init/scaffold-workflows.js +6 -3
  67. package/dist/init/scaffold-workflows.js.map +1 -1
  68. package/dist/init/upgrade-workflows.d.ts.map +1 -1
  69. package/dist/init/upgrade-workflows.js +6 -3
  70. package/dist/init/upgrade-workflows.js.map +1 -1
  71. package/dist/internal.d.ts +1 -1
  72. package/dist/internal.d.ts.map +1 -1
  73. package/dist/internal.js +1 -1
  74. package/dist/internal.js.map +1 -1
  75. package/dist/llm/plugin-facade.js +886 -526
  76. package/dist/llm/plugin-facade.js.map +3 -3
  77. package/dist/memory/decision-contradiction.d.ts +3 -3
  78. package/dist/memory/decision-contradiction.d.ts.map +1 -1
  79. package/dist/memory/decision-contradiction.js +4 -3
  80. package/dist/memory/decision-contradiction.js.map +1 -1
  81. package/dist/memory/graph-memory-bridge.d.ts.map +1 -1
  82. package/dist/memory/graph-memory-bridge.js +2 -0
  83. package/dist/memory/graph-memory-bridge.js.map +1 -1
  84. package/dist/memory/observation-type-decision.d.ts +2 -2
  85. package/dist/memory/observation-type-decision.d.ts.map +1 -1
  86. package/dist/memory/observation-type-decision.js +3 -2
  87. package/dist/memory/observation-type-decision.js.map +1 -1
  88. package/dist/memory/pipeline-manifest-sqlite.d.ts +111 -0
  89. package/dist/memory/pipeline-manifest-sqlite.d.ts.map +1 -1
  90. package/dist/memory/pipeline-manifest-sqlite.js +230 -2
  91. package/dist/memory/pipeline-manifest-sqlite.js.map +1 -1
  92. package/dist/nexus/migrations/M-split-graph.d.ts.map +1 -1
  93. package/dist/nexus/migrations/M-split-graph.js +4 -0
  94. package/dist/nexus/migrations/M-split-graph.js.map +1 -1
  95. package/dist/nexus/store.d.ts.map +1 -1
  96. package/dist/nexus/store.js +2 -0
  97. package/dist/nexus/store.js.map +1 -1
  98. package/dist/orchestrate/pivot.d.ts.map +1 -1
  99. package/dist/orchestrate/pivot.js +13 -8
  100. package/dist/orchestrate/pivot.js.map +1 -1
  101. package/dist/orchestrate/plan.d.ts.map +1 -1
  102. package/dist/orchestrate/plan.js +3 -0
  103. package/dist/orchestrate/plan.js.map +1 -1
  104. package/dist/orchestration/lead-rollup.js +14 -2
  105. package/dist/orchestration/lead-rollup.js.map +1 -1
  106. package/dist/orchestration/owner-decision-readiness.d.ts +2 -2
  107. package/dist/orchestration/owner-decision-readiness.d.ts.map +1 -1
  108. package/dist/orchestration/owner-decision-readiness.js +3 -2
  109. package/dist/orchestration/owner-decision-readiness.js.map +1 -1
  110. package/dist/orchestration/validate-spawn.d.ts.map +1 -1
  111. package/dist/orchestration/validate-spawn.js +2 -0
  112. package/dist/orchestration/validate-spawn.js.map +1 -1
  113. package/dist/project-scope.d.ts +16 -0
  114. package/dist/project-scope.d.ts.map +1 -1
  115. package/dist/project-scope.js +38 -2
  116. package/dist/project-scope.js.map +1 -1
  117. package/dist/release/github-pr.d.ts.map +1 -1
  118. package/dist/release/github-pr.js +2 -1
  119. package/dist/release/github-pr.js.map +1 -1
  120. package/dist/routing/capability-matrix.d.ts.map +1 -1
  121. package/dist/routing/capability-matrix.js +7 -0
  122. package/dist/routing/capability-matrix.js.map +1 -1
  123. package/dist/selfimprove/fix-gen.js +895 -535
  124. package/dist/selfimprove/fix-gen.js.map +3 -3
  125. package/dist/sessions/briefing.d.ts.map +1 -1
  126. package/dist/sessions/briefing.js +23 -62
  127. package/dist/sessions/briefing.js.map +1 -1
  128. package/dist/sessions/focus-state-store.d.ts +6 -1
  129. package/dist/sessions/focus-state-store.d.ts.map +1 -1
  130. package/dist/sessions/focus-state-store.js +5 -2
  131. package/dist/sessions/focus-state-store.js.map +1 -1
  132. package/dist/setup/config-json-merge.d.ts +28 -0
  133. package/dist/setup/config-json-merge.d.ts.map +1 -1
  134. package/dist/setup/config-json-merge.js +51 -0
  135. package/dist/setup/config-json-merge.js.map +1 -1
  136. package/dist/setup/index.d.ts +13 -10
  137. package/dist/setup/index.d.ts.map +1 -1
  138. package/dist/setup/index.js +15 -10
  139. package/dist/setup/index.js.map +1 -1
  140. package/dist/setup/sections/llm.js +1 -1
  141. package/dist/setup/sections/llm.js.map +1 -1
  142. package/dist/setup/sections/system-one.d.ts +28 -0
  143. package/dist/setup/sections/system-one.d.ts.map +1 -0
  144. package/dist/setup/sections/system-one.js +53 -0
  145. package/dist/setup/sections/system-one.js.map +1 -0
  146. package/dist/setup/wizard.d.ts +15 -1
  147. package/dist/setup/wizard.d.ts.map +1 -1
  148. package/dist/setup/wizard.js +15 -0
  149. package/dist/setup/wizard.js.map +1 -1
  150. package/dist/skills/prune-bundled.d.ts +40 -1
  151. package/dist/skills/prune-bundled.d.ts.map +1 -1
  152. package/dist/skills/prune-bundled.js +117 -1
  153. package/dist/skills/prune-bundled.js.map +1 -1
  154. package/dist/store/agent-registry-accessor.d.ts.map +1 -1
  155. package/dist/store/agent-registry-accessor.js +2 -0
  156. package/dist/store/agent-registry-accessor.js.map +1 -1
  157. package/dist/store/backup-pack.js +1 -1
  158. package/dist/store/backup-pack.js.map +1 -1
  159. package/dist/store/backup.d.ts +15 -1
  160. package/dist/store/backup.d.ts.map +1 -1
  161. package/dist/store/backup.js +18 -2
  162. package/dist/store/backup.js.map +1 -1
  163. package/dist/store/conduit-sqlite.d.ts.map +1 -1
  164. package/dist/store/conduit-sqlite.js +3 -0
  165. package/dist/store/conduit-sqlite.js.map +1 -1
  166. package/dist/store/credential-transfer.d.ts.map +1 -1
  167. package/dist/store/credential-transfer.js +2 -0
  168. package/dist/store/credential-transfer.js.map +1 -1
  169. package/dist/store/cross-db-cleanup.d.ts.map +1 -1
  170. package/dist/store/cross-db-cleanup.js +2 -0
  171. package/dist/store/cross-db-cleanup.js.map +1 -1
  172. package/dist/store/dual-scope-db.d.ts.map +1 -1
  173. package/dist/store/dual-scope-db.js +13 -2
  174. package/dist/store/dual-scope-db.js.map +1 -1
  175. package/dist/store/migrate-signaldock-to-conduit.d.ts.map +1 -1
  176. package/dist/store/migrate-signaldock-to-conduit.js +3 -0
  177. package/dist/store/migrate-signaldock-to-conduit.js.map +1 -1
  178. package/dist/store/migration-manager.d.ts.map +1 -1
  179. package/dist/store/migration-manager.js +37 -3
  180. package/dist/store/migration-manager.js.map +1 -1
  181. package/dist/store/migration-sqlite.d.ts.map +1 -1
  182. package/dist/store/migration-sqlite.js +2 -0
  183. package/dist/store/migration-sqlite.js.map +1 -1
  184. package/dist/store/nexus-sqlite.d.ts.map +1 -1
  185. package/dist/store/nexus-sqlite.js +3 -0
  186. package/dist/store/nexus-sqlite.js.map +1 -1
  187. package/dist/store/open-cleo-db.d.ts.map +1 -1
  188. package/dist/store/open-cleo-db.js +3 -0
  189. package/dist/store/open-cleo-db.js.map +1 -1
  190. package/dist/store/portable-bundle-import.d.ts.map +1 -1
  191. package/dist/store/portable-bundle-import.js +2 -0
  192. package/dist/store/portable-bundle-import.js.map +1 -1
  193. package/dist/store/portable-bundle-relocate.d.ts.map +1 -1
  194. package/dist/store/portable-bundle-relocate.js +2 -0
  195. package/dist/store/portable-bundle-relocate.js.map +1 -1
  196. package/dist/store/portable-bundle-scan.js +1 -1
  197. package/dist/store/portable-bundle-scan.js.map +1 -1
  198. package/dist/store/ports/domain-binding.d.ts.map +1 -1
  199. package/dist/store/ports/domain-binding.js +5 -0
  200. package/dist/store/ports/domain-binding.js.map +1 -1
  201. package/dist/store/split-brain-import.d.ts.map +1 -1
  202. package/dist/store/split-brain-import.js +2 -0
  203. package/dist/store/split-brain-import.js.map +1 -1
  204. package/dist/store/sqlite-data-accessor.js +7 -0
  205. package/dist/store/sqlite-data-accessor.js.map +1 -1
  206. package/dist/store/sqlite-native.d.ts.map +1 -1
  207. package/dist/store/sqlite-native.js +1 -0
  208. package/dist/store/sqlite-native.js.map +1 -1
  209. package/dist/store/sqlite.d.ts.map +1 -1
  210. package/dist/store/sqlite.js +5 -0
  211. package/dist/store/sqlite.js.map +1 -1
  212. package/dist/store/worktree-build-guard.d.ts +191 -0
  213. package/dist/store/worktree-build-guard.d.ts.map +1 -0
  214. package/dist/store/worktree-build-guard.js +486 -0
  215. package/dist/store/worktree-build-guard.js.map +1 -0
  216. package/dist/store/worktree-isolation-guard.d.ts +27 -0
  217. package/dist/store/worktree-isolation-guard.d.ts.map +1 -1
  218. package/dist/store/worktree-isolation-guard.js +67 -1
  219. package/dist/store/worktree-isolation-guard.js.map +1 -1
  220. package/dist/store/writer-lease.d.ts.map +1 -1
  221. package/dist/store/writer-lease.js +2 -0
  222. package/dist/store/writer-lease.js.map +1 -1
  223. package/dist/system/backup.d.ts +6 -2
  224. package/dist/system/backup.d.ts.map +1 -1
  225. package/dist/system/backup.js +6 -3
  226. package/dist/system/backup.js.map +1 -1
  227. package/dist/task-tools/index.d.ts +4 -2
  228. package/dist/task-tools/index.d.ts.map +1 -1
  229. package/dist/task-tools/index.js +3 -2
  230. package/dist/task-tools/index.js.map +1 -1
  231. package/dist/task-tools/score-task-priority.d.ts +93 -18
  232. package/dist/task-tools/score-task-priority.d.ts.map +1 -1
  233. package/dist/task-tools/score-task-priority.js +193 -81
  234. package/dist/task-tools/score-task-priority.js.map +1 -1
  235. package/dist/tasks/affected-packages.d.ts +5 -1
  236. package/dist/tasks/affected-packages.d.ts.map +1 -1
  237. package/dist/tasks/affected-packages.js +21 -3
  238. package/dist/tasks/affected-packages.js.map +1 -1
  239. package/dist/tasks/analyze.d.ts +29 -1
  240. package/dist/tasks/analyze.d.ts.map +1 -1
  241. package/dist/tasks/analyze.js +45 -34
  242. package/dist/tasks/analyze.js.map +1 -1
  243. package/dist/tasks/backfill-child-projections.d.ts.map +1 -1
  244. package/dist/tasks/backfill-child-projections.js +4 -1
  245. package/dist/tasks/backfill-child-projections.js.map +1 -1
  246. package/dist/tasks/change-set.d.ts.map +1 -1
  247. package/dist/tasks/change-set.js +16 -3
  248. package/dist/tasks/change-set.js.map +1 -1
  249. package/dist/tasks/command-line.d.ts +54 -0
  250. package/dist/tasks/command-line.d.ts.map +1 -0
  251. package/dist/tasks/command-line.js +151 -0
  252. package/dist/tasks/command-line.js.map +1 -0
  253. package/dist/tasks/component-pr.d.ts.map +1 -1
  254. package/dist/tasks/component-pr.js +97 -12
  255. package/dist/tasks/component-pr.js.map +1 -1
  256. package/dist/tasks/delete.d.ts.map +1 -1
  257. package/dist/tasks/delete.js +20 -0
  258. package/dist/tasks/delete.js.map +1 -1
  259. package/dist/tasks/duplicate-detector.d.ts +3 -3
  260. package/dist/tasks/duplicate-detector.d.ts.map +1 -1
  261. package/dist/tasks/duplicate-detector.js +4 -3
  262. package/dist/tasks/duplicate-detector.js.map +1 -1
  263. package/dist/tasks/engine-wrap-ops.d.ts +29 -0
  264. package/dist/tasks/engine-wrap-ops.d.ts.map +1 -1
  265. package/dist/tasks/engine-wrap-ops.js +40 -0
  266. package/dist/tasks/engine-wrap-ops.js.map +1 -1
  267. package/dist/tasks/engine-wrap.d.ts +1 -1
  268. package/dist/tasks/engine-wrap.d.ts.map +1 -1
  269. package/dist/tasks/engine-wrap.js +1 -1
  270. package/dist/tasks/engine-wrap.js.map +1 -1
  271. package/dist/tasks/evidence.d.ts +2 -0
  272. package/dist/tasks/evidence.d.ts.map +1 -1
  273. package/dist/tasks/evidence.js +30 -4
  274. package/dist/tasks/evidence.js.map +1 -1
  275. package/dist/tasks/gate-runner.d.ts.map +1 -1
  276. package/dist/tasks/gate-runner.js +48 -12
  277. package/dist/tasks/gate-runner.js.map +1 -1
  278. package/dist/tasks/index.d.ts +1 -1
  279. package/dist/tasks/index.d.ts.map +1 -1
  280. package/dist/tasks/index.js +1 -1
  281. package/dist/tasks/index.js.map +1 -1
  282. package/dist/tasks/ops.d.ts +1 -0
  283. package/dist/tasks/ops.d.ts.map +1 -1
  284. package/dist/tasks/ranking-audit.d.ts +122 -0
  285. package/dist/tasks/ranking-audit.d.ts.map +1 -0
  286. package/dist/tasks/ranking-audit.js +193 -0
  287. package/dist/tasks/ranking-audit.js.map +1 -0
  288. package/dist/tasks/task-analyze.d.ts.map +1 -1
  289. package/dist/tasks/task-analyze.js +19 -32
  290. package/dist/tasks/task-analyze.js.map +1 -1
  291. package/dist/tasks/task-next.d.ts +44 -2
  292. package/dist/tasks/task-next.d.ts.map +1 -1
  293. package/dist/tasks/task-next.js +80 -102
  294. package/dist/tasks/task-next.js.map +1 -1
  295. package/dist/tasks/task-ops.d.ts +1 -1
  296. package/dist/tasks/task-ops.d.ts.map +1 -1
  297. package/dist/tasks/task-ops.js +1 -1
  298. package/dist/tasks/task-ops.js.map +1 -1
  299. package/dist/tasks/tool-resolver.d.ts +7 -1
  300. package/dist/tasks/tool-resolver.d.ts.map +1 -1
  301. package/dist/tasks/tool-resolver.js +24 -10
  302. package/dist/tasks/tool-resolver.js.map +1 -1
  303. package/dist/tasks/update.d.ts +8 -2
  304. package/dist/tasks/update.d.ts.map +1 -1
  305. package/dist/tasks/update.js +28 -1
  306. package/dist/tasks/update.js.map +1 -1
  307. package/dist/telemetry/sqlite.d.ts.map +1 -1
  308. package/dist/telemetry/sqlite.js +2 -0
  309. package/dist/telemetry/sqlite.js.map +1 -1
  310. package/dist/validation/doctor/checks.d.ts.map +1 -1
  311. package/dist/validation/doctor/checks.js +2 -2
  312. package/dist/validation/doctor/checks.js.map +1 -1
  313. package/package.json +14 -14
  314. package/schemas/config.schema.json +13 -0
  315. package/templates/CLEO-INJECTION.md +1 -1
  316. package/templates/CLEO-REFERENCE.md +5 -1
@@ -0,0 +1,193 @@
1
+ /**
2
+ * Ranking-input audit trail (T12693, owner decision D11161).
3
+ *
4
+ * Agents may write a task's ranking inputs — priority, severity, kind and
5
+ * depends — directly, but every such change records WHO (actor), in WHICH
6
+ * session, WHY (optional reason) and the values before and after, as one
7
+ * `ranking_changed` row in the task audit log, written in the same
8
+ * transaction as the change. `cleo history ranking <id>` lists them and
9
+ * `cleo history revert <entryId>` undoes one.
10
+ *
11
+ * @task T12693
12
+ */
13
+ import { ExitCode } from '@cleocode/contracts';
14
+ import { CleoError } from '../errors.js';
15
+ import { resolveAgentIdFromEnv, resolveSessionIdFromEnv } from '../sessions/session-id.js';
16
+ import { getTaskAccessor } from '../store/data-accessor.js';
17
+ /** The audit action a ranking change is recorded under. */
18
+ export const RANKING_CHANGED_ACTION = 'ranking_changed';
19
+ /** Fields the ranking sort reads (D11161). */
20
+ export const RANKING_FIELDS = ['priority', 'severity', 'kind', 'depends'];
21
+ /**
22
+ * A task's ranking inputs.
23
+ *
24
+ * @param task - The task.
25
+ * @returns The snapshot (depends sorted, so order changes are not changes).
26
+ * @task T12693
27
+ */
28
+ export function rankingSnapshot(task) {
29
+ return {
30
+ priority: task.priority ?? null,
31
+ severity: task.severity ?? null,
32
+ kind: task.kind ?? null,
33
+ depends: [...(task.depends ?? [])].sort(),
34
+ };
35
+ }
36
+ /**
37
+ * The ranking fields that differ between two snapshots.
38
+ *
39
+ * @param before - Snapshot before the change.
40
+ * @param after - Snapshot after it.
41
+ * @returns Changed fields, in {@link RANKING_FIELDS} order.
42
+ * @task T12693
43
+ */
44
+ export function rankingDiff(before, after) {
45
+ return RANKING_FIELDS.filter((field) => field === 'depends'
46
+ ? before.depends.join('\0') !== after.depends.join('\0')
47
+ : before[field] !== after[field]);
48
+ }
49
+ /**
50
+ * The actor and session a change is attributed to: the agent id
51
+ * (`CLEO_AGENT_ID`, else `human`) and the caller's session (env first, then
52
+ * the bound session).
53
+ *
54
+ * @param cwd - Project root.
55
+ * @returns The actor and session.
56
+ * @task T12693
57
+ */
58
+ export async function resolveRankingActor(cwd) {
59
+ let sessionId = resolveSessionIdFromEnv();
60
+ if (!sessionId) {
61
+ try {
62
+ const { resolveBoundSessionId } = await import('../store/session-store.js');
63
+ sessionId = (await resolveBoundSessionId(cwd)) ?? null;
64
+ }
65
+ catch {
66
+ sessionId = null;
67
+ }
68
+ }
69
+ return { actor: resolveAgentIdFromEnv() ?? 'human', sessionId };
70
+ }
71
+ /**
72
+ * The audit-log entry for one ranking change, or null when nothing ranking
73
+ * related changed. Only the changed fields are stored before and after.
74
+ *
75
+ * @param input - Task, snapshots, attribution and why.
76
+ * @returns The `appendLog` entry, or null.
77
+ * @task T12693
78
+ */
79
+ export function rankingAuditEntry(input) {
80
+ const fields = rankingDiff(input.before, input.after);
81
+ if (fields.length === 0)
82
+ return null;
83
+ const pick = (snap) => Object.fromEntries(fields.map((f) => [f, snap[f]]));
84
+ return {
85
+ id: `log-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 8)}`,
86
+ timestamp: new Date().toISOString(),
87
+ action: RANKING_CHANGED_ACTION,
88
+ taskId: input.taskId,
89
+ actor: input.actor.actor,
90
+ sessionId: input.actor.sessionId,
91
+ details: {
92
+ fields,
93
+ reason: input.reason?.trim() ? input.reason.trim() : null,
94
+ source: input.source,
95
+ },
96
+ before: pick(input.before),
97
+ after: pick(input.after),
98
+ };
99
+ }
100
+ function parseRow(row) {
101
+ const json = (text, fallback) => {
102
+ try {
103
+ return text ? JSON.parse(text) : fallback;
104
+ }
105
+ catch {
106
+ return fallback;
107
+ }
108
+ };
109
+ const details = json(row.detailsJson, {});
110
+ return {
111
+ id: row.id,
112
+ taskId: row.taskId,
113
+ timestamp: row.timestamp,
114
+ actor: row.actor,
115
+ sessionId: row.sessionId ?? null,
116
+ reason: details.reason ?? null,
117
+ source: details.source ?? null,
118
+ fields: details.fields ?? [],
119
+ before: json(row.beforeJson, {}),
120
+ after: json(row.afterJson, {}),
121
+ };
122
+ }
123
+ /**
124
+ * Who changed a task's ranking inputs, when, and why — newest first.
125
+ *
126
+ * @param taskId - Task.
127
+ * @param cwd - Project root.
128
+ * @param limit - Maximum rows (default 50).
129
+ * @returns The recorded changes.
130
+ * @task T12693
131
+ */
132
+ export async function listRankingHistory(taskId, cwd, limit = 50) {
133
+ const accessor = await getTaskAccessor(cwd);
134
+ const rows = await accessor.queryAuditLog({
135
+ taskIds: [taskId],
136
+ actions: [RANKING_CHANGED_ACTION],
137
+ limit,
138
+ });
139
+ return rows.map(parseRow);
140
+ }
141
+ /**
142
+ * Undo one recorded ranking change: set each field it changed back to its
143
+ * value before, as a new audited change (source `revert`). Refused when a
144
+ * field has changed again since, so a later decision is never silently lost —
145
+ * unless `force`.
146
+ *
147
+ * @param entryId - The `ranking_changed` audit row id.
148
+ * @param opts - Why (recorded), and `force` to revert over later changes.
149
+ * @param cwd - Project root.
150
+ * @returns The task id, the reverted fields and the new audit row id.
151
+ * @throws {CleoError} When the entry is not a ranking change, or a field
152
+ * changed since and `force` is not set.
153
+ * @task T12693
154
+ */
155
+ export async function revertRankingChange(entryId, opts = {}, cwd) {
156
+ const accessor = await getTaskAccessor(cwd);
157
+ const [row] = await accessor.queryAuditLog({ ids: [entryId], actions: [RANKING_CHANGED_ACTION] });
158
+ if (!row) {
159
+ throw new CleoError(ExitCode.NOT_FOUND, `No ranking change ${entryId}`, {
160
+ fix: 'cleo history ranking <taskId> # lists ranking changes with their ids',
161
+ });
162
+ }
163
+ const change = parseRow(row);
164
+ const task = await accessor.loadSingleTask(change.taskId);
165
+ if (!task) {
166
+ throw new CleoError(ExitCode.NOT_FOUND, `Task ${change.taskId} no longer exists`);
167
+ }
168
+ const current = rankingSnapshot(task);
169
+ const moved = change.fields.filter((field) => {
170
+ const now = current[field];
171
+ const then = change.after[field];
172
+ return field === 'depends'
173
+ ? [...now].sort().join('\0') !==
174
+ [...(then ?? [])].sort().join('\0')
175
+ : now !== (then ?? null);
176
+ });
177
+ if (moved.length > 0 && !opts.force) {
178
+ throw new CleoError(ExitCode.VALIDATION_ERROR, `${change.taskId}'s ${moved.join(', ')} changed again after ${entryId}; reverting would discard that later change`, { fix: `cleo history ranking ${change.taskId} # or re-run with --force` });
179
+ }
180
+ const { updateTask } = await import('./update.js');
181
+ const back = change.before;
182
+ await updateTask({
183
+ taskId: change.taskId,
184
+ ...(change.fields.includes('priority') && back.priority ? { priority: back.priority } : {}),
185
+ ...(change.fields.includes('severity') ? { severity: back.severity ?? null } : {}),
186
+ ...(change.fields.includes('kind') && back.kind ? { kind: back.kind } : {}),
187
+ ...(change.fields.includes('depends') ? { depends: back.depends ?? [] } : {}),
188
+ reason: `revert ${entryId}${opts.reason?.trim() ? `: ${opts.reason.trim()}` : ''}`,
189
+ rankingSource: 'revert',
190
+ }, cwd, accessor);
191
+ return { taskId: change.taskId, fields: change.fields, revertedTo: back };
192
+ }
193
+ //# sourceMappingURL=ranking-audit.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ranking-audit.js","sourceRoot":"","sources":["../../src/tasks/ranking-audit.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"task-analyze.d.ts","sourceRoot":"","sources":["../../src/tasks/task-analyze.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,IAAI,EAAE,kBAAkB,EAAE,MAAM,qBAAqB,CAAC;AAGpE,sDAAsD;AACtD,KAAK,UAAU,GAAG,IAAI,CAAC;AAEvB,gEAAgE;AAChE,MAAM,WAAW,gBAAgB;IAC/B,iEAAiE;IACjE,IAAI,EAAE,MAAM,CAAC;IACb,mDAAmD;IACnD,KAAK,EAAE,MAAM,CAAC;IACd,yEAAyE;IACzE,MAAM,EAAE,MAAM,CAAC;CAChB;AAQD;;;;;;GAMG;AACH,wBAAgB,sBAAsB,CACpC,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,GAAG,CAAC,MAAM,EAAE,UAAU,CAAC,EAChC,OAAO,GAAE,GAAG,CAAC,MAAM,CAAa,GAC/B,MAAM,CAaR;AAED;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,wBAAsB,eAAe,CACnC,WAAW,EAAE,MAAM,EACnB,MAAM,CAAC,EAAE,MAAM,EACf,MAAM,CAAC,EAAE;IAAE,SAAS,CAAC,EAAE,MAAM,CAAA;CAAE,GAC9B,OAAO,CAAC,kBAAkB,GAAG;IAAE,SAAS,EAAE,MAAM,CAAA;CAAE,CAAC,CAqFrD;AAED;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAsB,0BAA0B,CAC9C,WAAW,EAAE,MAAM,EACnB,MAAM,EAAE;IAAE,MAAM,EAAE,MAAM,CAAA;CAAE,GACzB,OAAO,CAAC;IACT,IAAI,EAAE,OAAO,GAAG,QAAQ,GAAG,OAAO,CAAC;IACnC,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,gBAAgB,EAAE,CAAC;IAC5B,eAAe,EAAE,MAAM,CAAC;IACxB,YAAY,EAAE,MAAM,CAAC;IACrB,SAAS,EAAE,MAAM,CAAC;CACnB,CAAC,CA8DD"}
1
+ {"version":3,"file":"task-analyze.d.ts","sourceRoot":"","sources":["../../src/tasks/task-analyze.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,IAAI,EAAE,kBAAkB,EAAE,MAAM,qBAAqB,CAAC;AAKpE,sDAAsD;AACtD,KAAK,UAAU,GAAG,IAAI,CAAC;AAEvB,gEAAgE;AAChE,MAAM,WAAW,gBAAgB;IAC/B,iEAAiE;IACjE,IAAI,EAAE,MAAM,CAAC;IACb,mDAAmD;IACnD,KAAK,EAAE,MAAM,CAAC;IACd,yEAAyE;IACzE,MAAM,EAAE,MAAM,CAAC;CAChB;AAQD;;;;;;GAMG;AACH,wBAAgB,sBAAsB,CACpC,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,GAAG,CAAC,MAAM,EAAE,UAAU,CAAC,EAChC,OAAO,GAAE,GAAG,CAAC,MAAM,CAAa,GAC/B,MAAM,CAaR;AAED;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,wBAAsB,eAAe,CACnC,WAAW,EAAE,MAAM,EACnB,MAAM,CAAC,EAAE,MAAM,EACf,MAAM,CAAC,EAAE;IAAE,SAAS,CAAC,EAAE,MAAM,CAAA;CAAE,GAC9B,OAAO,CAAC,kBAAkB,GAAG;IAAE,SAAS,EAAE,MAAM,CAAA;CAAE,CAAC,CAqErD;AAED;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAsB,0BAA0B,CAC9C,WAAW,EAAE,MAAM,EACnB,MAAM,EAAE;IAAE,MAAM,EAAE,MAAM,CAAA;CAAE,GACzB,OAAO,CAAC;IACT,IAAI,EAAE,OAAO,GAAG,QAAQ,GAAG,OAAO,CAAC;IACnC,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,gBAAgB,EAAE,CAAC;IAC5B,eAAe,EAAE,MAAM,CAAC;IACxB,YAAY,EAAE,MAAM,CAAC;IACrB,SAAS,EAAE,MAAM,CAAC;CACnB,CAAC,CA8DD"}
@@ -4,6 +4,8 @@
4
4
  * @epic T9834
5
5
  */
6
6
  import { getTaskAccessor } from '../store/data-accessor.js';
7
+ import { computeLeverage } from '../task-tools/score-task-priority.js';
8
+ import { rankForAnalysis } from './analyze.js';
7
9
  async function loadAllTasks(projectRoot) {
8
10
  const accessor = await getTaskAccessor(projectRoot);
9
11
  const { tasks } = await accessor.queryTasks({});
@@ -54,44 +56,29 @@ export function measureDependencyDepth(taskId, taskMap, visited = new Set()) {
54
56
  * @task T4790
55
57
  */
56
58
  export async function coreTaskAnalyze(projectRoot, taskId, params) {
57
- const allTasks = await loadAllTasks(projectRoot);
59
+ const accessor = await getTaskAccessor(projectRoot);
60
+ const { tasks: allTasks } = await accessor.queryTasks({});
58
61
  const effectiveTierLimit = params?.tierLimit ?? 10;
59
62
  const tasks = taskId
60
63
  ? allTasks.filter((t) => t.id === taskId || t.parentId === taskId)
61
64
  : allTasks;
62
- const blocksMap = {};
63
- for (const task of tasks) {
64
- if (task.depends) {
65
- for (const dep of task.depends) {
66
- if (!blocksMap[dep])
67
- blocksMap[dep] = [];
68
- blocksMap[dep].push(task.id);
69
- }
70
- }
71
- }
72
- const leverageMap = {};
73
- for (const task of tasks) {
74
- leverageMap[task.id] = (blocksMap[task.id] ?? []).length;
75
- }
76
- const actionable = tasks.filter((t) => t.status === 'pending' || t.status === 'active');
65
+ // Open tasks each task unblocks — the same leverage the shared scorer uses (T12661).
66
+ const openDependents = computeLeverage(tasks);
77
67
  const blocked = tasks.filter((t) => t.status === 'blocked');
78
68
  const bottlenecks = tasks
79
- .filter((t) => (blocksMap[t.id]?.length ?? 0) > 0 && t.status !== 'done')
80
- .map((t) => ({ id: t.id, title: t.title, blocksCount: blocksMap[t.id].length }))
81
- .sort((a, b) => b.blocksCount - a.blocksCount)
69
+ .filter((t) => (openDependents.get(t.id) ?? 0) > 0 && t.status !== 'done')
70
+ .map((t) => ({ id: t.id, title: t.title, blocksCount: openDependents.get(t.id) ?? 0 }))
71
+ .sort((a, b) => b.blocksCount - a.blocksCount || a.id.localeCompare(b.id))
82
72
  .slice(0, 5);
83
- const scored = actionable.map((t) => ({
84
- id: t.id,
85
- title: t.title,
86
- leverage: leverageMap[t.id] ?? 0,
87
- priority: t.priority,
88
- }));
89
- scored.sort((a, b) => {
90
- const priorityWeight = { critical: 100, high: 50, medium: 20, low: 5 };
91
- const aScore = (priorityWeight[a.priority ?? 'medium'] ?? 20) + a.leverage * 10;
92
- const bScore = (priorityWeight[b.priority ?? 'medium'] ?? 20) + b.leverage * 10;
93
- return bScore - aScore;
73
+ // T12661: the same ranking as `cleo next` and the briefing (ready candidates,
74
+ // current phase, BRAIN patterns, shared scorer), scoped to `taskId` when given.
75
+ const { ranked: scored } = await rankForAnalysis(accessor, allTasks, {
76
+ projectRoot,
77
+ ...(taskId ? { scopeTaskIds: new Set(tasks.map((t) => t.id)) } : {}),
94
78
  });
79
+ // The metric keeps its meaning (pending + active); the tiers above rank only
80
+ // the READY subset, exactly as `cleo next` does.
81
+ const actionable = tasks.filter((t) => t.status === 'pending' || t.status === 'active');
95
82
  const critical = scored.filter((t) => t.priority === 'critical');
96
83
  const high = scored.filter((t) => t.priority === 'high');
97
84
  const normal = scored.filter((t) => t.priority !== 'critical' && t.priority !== 'high');
@@ -100,10 +87,10 @@ export async function coreTaskAnalyze(projectRoot, taskId, params) {
100
87
  id: scored[0].id,
101
88
  title: scored[0].title,
102
89
  leverage: scored[0].leverage,
103
- reason: 'Highest combined priority and leverage score',
90
+ reason: 'Top of the shared task ranking — the same order as `cleo next`',
104
91
  }
105
92
  : null;
106
- const totalLeverage = Object.values(leverageMap).reduce((s, v) => s + v, 0);
93
+ const totalLeverage = [...openDependents.values()].reduce((s, v) => s + v, 0);
107
94
  const avgLeverage = tasks.length > 0 ? Math.round((totalLeverage / tasks.length) * 100) / 100 : 0;
108
95
  return {
109
96
  recommended,
@@ -1 +1 @@
1
- {"version":3,"file":"task-analyze.js","sourceRoot":"","sources":["../../src/tasks/task-analyze.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"task-analyze.js","sourceRoot":"","sources":["../../src/tasks/task-analyze.ts"],"names":[],"mappings":"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"}
@@ -3,6 +3,9 @@
3
3
  * @task T10064
4
4
  * @epic T9834
5
5
  */
6
+ import type { Task } from '@cleocode/contracts';
7
+ import type { DataAccessor } from '../store/data-accessor.js';
8
+ import { type RankedTask } from '../task-tools/score-task-priority.js';
6
9
  /**
7
10
  * Suggest next task to work on based on priority, phase, age, and deps.
8
11
  *
@@ -16,8 +19,12 @@
16
19
  * @returns Ranked suggestions with scores and the total number of eligible candidates
17
20
  *
18
21
  * @remarks
19
- * Scoring considers priority weight, current phase alignment, dependency readiness,
20
- * task age, and brain success/failure pattern matches. Results are sorted descending by score.
22
+ * Ranks through the shared {@link scoreTask} (via {@link rankReadyTasks}):
23
+ * the lexicographic D11161 key — priority band, then attested severity (an
24
+ * unset severity is unknown; nothing is imputed from `kind`), then a bounded
25
+ * tiebreak (dependency readiness, phase alignment, leverage, age), then
26
+ * `createdAt`, then id. BRAIN patterns are informational factors only.
27
+ * `explain` returns every factor. The briefing's `nextTasks` uses the same ranking (T12661).
21
28
  * Candidates retain the active query population; a separate canonical lookup
22
29
  * resolves explicit dependencies, including archived records. Missing/cancelled
23
30
  * prerequisites block selection, and required dependency-read failures propagate.
@@ -47,4 +54,39 @@ export declare function coreTaskNext(projectRoot: string, params?: {
47
54
  }>;
48
55
  totalCandidates: number;
49
56
  }>;
57
+ /**
58
+ * The phase that earns the phase-alignment bonus: the caller's session focus
59
+ * phase, else the project's current phase. `cleo next` and the briefing both
60
+ * resolve it here so they rank identically (T12661).
61
+ *
62
+ * @param accessor - Task data accessor.
63
+ * @returns The phase slug, or null.
64
+ * @task T12661
65
+ */
66
+ export declare function resolveRankingPhase(accessor: DataAccessor): Promise<string | null>;
67
+ /**
68
+ * Rank every READY task — pending, not cancelled, all dependencies satisfied
69
+ * under the canonical lookup (archived dependencies included) — through the
70
+ * shared {@link scoreTask}. The single ranking behind `cleo next` and the
71
+ * briefing's `nextTasks` (T12661).
72
+ *
73
+ * @param accessor - Task data accessor (for dependency records outside `allTasks`).
74
+ * @param allTasks - The active task population.
75
+ * @param opts - Current phase, optional id scope, `nowMs`, and `projectRoot`
76
+ * to attach BRAIN success/failure patterns as informational factors
77
+ * (best-effort; they are not part of the order).
78
+ * @returns Ranked candidates, how many there were, and the leverage map used.
79
+ * @task T12661
80
+ */
81
+ export declare function rankReadyTasks(accessor: DataAccessor, allTasks: readonly Task[], opts: {
82
+ currentPhase: string | null;
83
+ scopeTaskIds?: ReadonlySet<string>;
84
+ projectRoot?: string;
85
+ /** Clock for the age tiebreak; one instant for the whole ranking. */
86
+ nowMs?: number;
87
+ }): Promise<{
88
+ ranked: RankedTask<Task>[];
89
+ totalCandidates: number;
90
+ leverage: ReadonlyMap<string, number>;
91
+ }>;
50
92
  //# sourceMappingURL=task-next.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"task-next.d.ts","sourceRoot":"","sources":["../../src/tasks/task-next.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAgCH;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AACH,wBAAsB,YAAY,CAChC,WAAW,EAAE,MAAM,EACnB,MAAM,CAAC,EAAE;IAAE,KAAK,CAAC,EAAE,MAAM,CAAC;IAAC,OAAO,CAAC,EAAE,OAAO,CAAC;IAAC,KAAK,CAAC,EAAE,OAAO,CAAA;CAAE,GAC9D,OAAO,CAAC;IACT,WAAW,EAAE,KAAK,CAAC;QACjB,EAAE,EAAE,MAAM,CAAC;QACX,KAAK,EAAE,MAAM,CAAC;QACd,QAAQ,EAAE,MAAM,CAAC;QACjB,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;QACrB,KAAK,EAAE,MAAM,CAAC;QACd,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;KACpB,CAAC,CAAC;IACH,eAAe,EAAE,MAAM,CAAC;CACzB,CAAC,CAyGD"}
1
+ {"version":3,"file":"task-next.d.ts","sourceRoot":"","sources":["../../src/tasks/task-next.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAiC,IAAI,EAAE,MAAM,qBAAqB,CAAC;AAG/E,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,2BAA2B,CAAC;AAE9D,OAAO,EAGL,KAAK,UAAU,EAEhB,MAAM,sCAAsC,CAAC;AAI9C;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AACH,wBAAsB,YAAY,CAChC,WAAW,EAAE,MAAM,EACnB,MAAM,CAAC,EAAE;IAAE,KAAK,CAAC,EAAE,MAAM,CAAC;IAAC,OAAO,CAAC,EAAE,OAAO,CAAC;IAAC,KAAK,CAAC,EAAE,OAAO,CAAA;CAAE,GAC9D,OAAO,CAAC;IACT,WAAW,EAAE,KAAK,CAAC;QACjB,EAAE,EAAE,MAAM,CAAC;QACX,KAAK,EAAE,MAAM,CAAC;QACd,QAAQ,EAAE,MAAM,CAAC;QACjB,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;QACrB,KAAK,EAAE,MAAM,CAAC;QACd,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;KACpB,CAAC,CAAC;IACH,eAAe,EAAE,MAAM,CAAC;CACzB,CAAC,CAsBD;AAED;;;;;;;;GAQG;AACH,wBAAsB,mBAAmB,CAAC,QAAQ,EAAE,YAAY,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAOxF;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAsB,cAAc,CAClC,QAAQ,EAAE,YAAY,EACtB,QAAQ,EAAE,SAAS,IAAI,EAAE,EACzB,IAAI,EAAE;IACJ,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,YAAY,CAAC,EAAE,WAAW,CAAC,MAAM,CAAC,CAAC;IACnC,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,qEAAqE;IACrE,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB,GACA,OAAO,CAAC;IACT,MAAM,EAAE,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC;IAC3B,eAAe,EAAE,MAAM,CAAC;IACxB,QAAQ,EAAE,WAAW,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CACvC,CAAC,CAkCD"}
@@ -3,32 +3,12 @@
3
3
  * @task T10064
4
4
  * @epic T9834
5
5
  */
6
+ import { readFocusState } from '../sessions/focus-state-store.js';
7
+ import { resolveSessionIdFromEnv } from '../sessions/session-id.js';
6
8
  import { getTaskAccessor } from '../store/data-accessor.js';
9
+ import { computeLeverage, formatScoreFactor, rankTasks, } from '../task-tools/score-task-priority.js';
7
10
  import { loadReadinessDependencyLookup } from './dependency-check.js';
8
11
  import { depsReady } from './deps-ready.js';
9
- const PRIORITY_SCORE = {
10
- critical: 100,
11
- high: 75,
12
- medium: 50,
13
- low: 25,
14
- };
15
- /**
16
- * Severity-axis score bumps (T9905 unified urgency surface).
17
- *
18
- * Severity is orthogonal to priority — a task can have `priority='medium'` and
19
- * `severity='P0'` (e.g. a freshly-filed P0 incident before triage promotes its
20
- * priority). Without a severity boost the P0 work sits below an unrelated
21
- * `priority='high'` task in the `next` ranking, which inverts the operator's
22
- * expectations. The bump is conservative (P0 = +30, P1 = +15) so that
23
- * `priority='critical'` (+100) still wins all ties, but a P0/P1 row decisively
24
- * outranks any `priority='medium'` peer with no severity set.
25
- *
26
- * @task T9905
27
- */
28
- const SEVERITY_SCORE = {
29
- P0: 30,
30
- P1: 15,
31
- };
32
12
  /**
33
13
  * Suggest next task to work on based on priority, phase, age, and deps.
34
14
  *
@@ -42,8 +22,12 @@ const SEVERITY_SCORE = {
42
22
  * @returns Ranked suggestions with scores and the total number of eligible candidates
43
23
  *
44
24
  * @remarks
45
- * Scoring considers priority weight, current phase alignment, dependency readiness,
46
- * task age, and brain success/failure pattern matches. Results are sorted descending by score.
25
+ * Ranks through the shared {@link scoreTask} (via {@link rankReadyTasks}):
26
+ * the lexicographic D11161 key — priority band, then attested severity (an
27
+ * unset severity is unknown; nothing is imputed from `kind`), then a bounded
28
+ * tiebreak (dependency readiness, phase alignment, leverage, age), then
29
+ * `createdAt`, then id. BRAIN patterns are informational factors only.
30
+ * `explain` returns every factor. The briefing's `nextTasks` uses the same ranking (T12661).
47
31
  * Candidates retain the active query population; a separate canonical lookup
48
32
  * resolves explicit dependencies, including archived records. Missing/cancelled
49
33
  * prerequisites block selection, and required dependency-read failures propagate.
@@ -61,90 +45,84 @@ const SEVERITY_SCORE = {
61
45
  export async function coreTaskNext(projectRoot, params) {
62
46
  const accessor = await getTaskAccessor(projectRoot);
63
47
  const { tasks: allTasks } = await accessor.queryTasks({});
64
- const dependencyLookup = await loadReadinessDependencyLookup(allTasks, accessor);
48
+ const { ranked, totalCandidates } = await rankReadyTasks(accessor, allTasks, {
49
+ currentPhase: await resolveRankingPhase(accessor),
50
+ // T12689: a one-line hint (`brain: false`) opens no brain store.
51
+ ...(params?.brain !== false && { projectRoot }),
52
+ });
53
+ const count = Math.min(params?.count || 1, ranked.length);
54
+ const explain = params?.explain ?? false;
55
+ const suggestions = ranked.slice(0, count).map(({ task, score, factors }) => ({
56
+ id: task.id,
57
+ title: task.title,
58
+ priority: task.priority,
59
+ phase: task.phase ?? null,
60
+ score,
61
+ ...(explain && { reasons: factors.map(formatScoreFactor) }),
62
+ }));
63
+ return { suggestions, totalCandidates };
64
+ }
65
+ /**
66
+ * The phase that earns the phase-alignment bonus: the caller's session focus
67
+ * phase, else the project's current phase. `cleo next` and the briefing both
68
+ * resolve it here so they rank identically (T12661).
69
+ *
70
+ * @param accessor - Task data accessor.
71
+ * @returns The phase slug, or null.
72
+ * @task T12661
73
+ */
74
+ export async function resolveRankingPhase(accessor) {
75
+ // Only the focus PHASE is read here, never the task pointer, so the stale-
76
+ // pointer check in readLiveFocus (and its task load) does not apply.
77
+ const focus = await readFocusState(accessor, resolveSessionIdFromEnv());
78
+ if (focus?.currentPhase)
79
+ return focus.currentPhase;
65
80
  const projectMeta = await accessor.getMetaValue('project_meta');
66
- const currentPhase = projectMeta?.currentPhase ?? null;
67
- const candidates = allTasks.filter((t) => t.status === 'pending' && !t.cancelledAt && depsReady(t.depends, dependencyLookup));
68
- if (candidates.length === 0) {
69
- return { suggestions: [], totalCandidates: 0 };
70
- }
71
- const scored = candidates
72
- .map((task) => {
73
- const reasons = [];
74
- let score = 0;
75
- score += PRIORITY_SCORE[task.priority] ?? 50;
76
- reasons.push(`priority: ${task.priority} (+${PRIORITY_SCORE[task.priority] ?? 50})`);
77
- // T9905: severity axis boost — orthogonal to priority.
78
- const severityKey = task.severity ?? '';
79
- const severityBump = SEVERITY_SCORE[severityKey];
80
- if (severityBump !== undefined) {
81
- score += severityBump;
82
- reasons.push(`severity: ${severityKey} (+${severityBump})`);
83
- }
84
- if (currentPhase && task.phase === currentPhase) {
85
- score += 20;
86
- reasons.push(`phase alignment: ${currentPhase} (+20)`);
87
- }
88
- if (depsReady(task.depends, dependencyLookup)) {
89
- score += 10;
90
- reasons.push('all dependencies satisfied (+10)');
91
- }
92
- if (task.createdAt) {
93
- const ageMs = Date.now() - new Date(task.createdAt).getTime();
94
- const ageDays = ageMs / (1000 * 60 * 60 * 24);
95
- if (ageDays > 7) {
96
- const ageBonus = Math.min(15, Math.floor(ageDays / 7));
97
- score += ageBonus;
98
- reasons.push(`age: ${Math.floor(ageDays)} days (+${ageBonus})`);
99
- }
100
- }
101
- return { task, score, reasons };
102
- })
103
- .sort((a, b) => b.score - a.score);
104
- // Brain pattern scoring (best-effort; skipped for a one-line hint)
105
- if (params?.brain !== false)
81
+ return projectMeta?.currentPhase ?? null;
82
+ }
83
+ /**
84
+ * Rank every READY task — pending, not cancelled, all dependencies satisfied
85
+ * under the canonical lookup (archived dependencies included) — through the
86
+ * shared {@link scoreTask}. The single ranking behind `cleo next` and the
87
+ * briefing's `nextTasks` (T12661).
88
+ *
89
+ * @param accessor - Task data accessor (for dependency records outside `allTasks`).
90
+ * @param allTasks - The active task population.
91
+ * @param opts - Current phase, optional id scope, `nowMs`, and `projectRoot`
92
+ * to attach BRAIN success/failure patterns as informational factors
93
+ * (best-effort; they are not part of the order).
94
+ * @returns Ranked candidates, how many there were, and the leverage map used.
95
+ * @task T12661
96
+ */
97
+ export async function rankReadyTasks(accessor, allTasks, opts) {
98
+ const dependencyLookup = await loadReadinessDependencyLookup(allTasks, accessor);
99
+ const candidates = allTasks.filter((t) => t.status === 'pending' &&
100
+ !t.cancelledAt &&
101
+ (!opts.scopeTaskIds || opts.scopeTaskIds.has(t.id)) &&
102
+ depsReady(t.depends, dependencyLookup));
103
+ const leverage = computeLeverage(allTasks);
104
+ if (candidates.length === 0)
105
+ return { ranked: [], totalCandidates: 0, leverage };
106
+ const ctx = {
107
+ currentPhase: opts.currentPhase,
108
+ nowMs: opts.nowMs ?? Date.now(),
109
+ taskStatuses: new Map([...dependencyLookup.values()].map((task) => [task.id, task.status])),
110
+ leverage,
111
+ };
112
+ if (opts.projectRoot) {
106
113
  try {
107
114
  const { searchPatterns } = await import('../memory/patterns.js');
108
- const [successPatterns, failurePatterns] = await Promise.all([
109
- searchPatterns(projectRoot, { type: 'success', limit: 20 }),
110
- searchPatterns(projectRoot, { type: 'failure', limit: 20 }),
115
+ const [success, failure] = await Promise.all([
116
+ searchPatterns(opts.projectRoot, { type: 'success', limit: 20 }),
117
+ searchPatterns(opts.projectRoot, { type: 'failure', limit: 20 }),
111
118
  ]);
112
- if (successPatterns.length > 0 || failurePatterns.length > 0) {
113
- for (const item of scored) {
114
- const titleLower = item.task.title.toLowerCase();
115
- const labels = (item.task.labels ?? []).map((l) => l.toLowerCase());
116
- const matchText = [titleLower, ...labels].join(' ');
117
- for (const sp of successPatterns) {
118
- if (matchText.includes(sp.pattern.toLowerCase())) {
119
- item.score += 10;
120
- item.reasons.push(`brain: success pattern match "${sp.pattern}" (+10)`);
121
- break;
122
- }
123
- }
124
- for (const fp of failurePatterns) {
125
- if (matchText.includes(fp.pattern.toLowerCase())) {
126
- item.score -= 5;
127
- item.reasons.push(`brain: failure pattern match "${fp.pattern}" (-5)`);
128
- break;
129
- }
130
- }
131
- }
132
- scored.sort((a, b) => b.score - a.score);
133
- }
119
+ ctx.successPatterns = success;
120
+ ctx.failurePatterns = failure;
134
121
  }
135
122
  catch {
136
123
  // Brain pattern scoring is best-effort
137
124
  }
138
- const count = Math.min(params?.count || 1, scored.length);
139
- const explain = params?.explain ?? false;
140
- const suggestions = scored.slice(0, count).map(({ task, score, reasons }) => ({
141
- id: task.id,
142
- title: task.title,
143
- priority: task.priority,
144
- phase: task.phase ?? null,
145
- score,
146
- ...(explain && { reasons }),
147
- }));
148
- return { suggestions, totalCandidates: candidates.length };
125
+ }
126
+ return { ranked: rankTasks(candidates, ctx), totalCandidates: candidates.length, leverage };
149
127
  }
150
128
  //# sourceMappingURL=task-next.js.map