@telora/daemon 0.22.189 → 0.22.208

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 (189) hide show
  1. package/build-info.json +6 -3
  2. package/dist/backends/index.d.ts.map +1 -1
  3. package/dist/backends/index.js +2 -0
  4. package/dist/backends/index.js.map +1 -1
  5. package/dist/completion/completion-fact-readers.d.ts +35 -0
  6. package/dist/completion/completion-fact-readers.d.ts.map +1 -0
  7. package/dist/completion/completion-fact-readers.js +70 -0
  8. package/dist/completion/completion-fact-readers.js.map +1 -0
  9. package/dist/completion/event-dep-defaults.d.ts +27 -0
  10. package/dist/completion/event-dep-defaults.d.ts.map +1 -0
  11. package/dist/completion/event-dep-defaults.js +30 -0
  12. package/dist/completion/event-dep-defaults.js.map +1 -0
  13. package/dist/completion/event-phases.d.ts.map +1 -1
  14. package/dist/completion/event-phases.js +5 -13
  15. package/dist/completion/event-phases.js.map +1 -1
  16. package/dist/completion/event.d.ts +32 -0
  17. package/dist/completion/event.d.ts.map +1 -1
  18. package/dist/completion/event.js +31 -25
  19. package/dist/completion/event.js.map +1 -1
  20. package/dist/completion/session-hold.d.ts +13 -1
  21. package/dist/completion/session-hold.d.ts.map +1 -1
  22. package/dist/completion/session-hold.js +18 -0
  23. package/dist/completion/session-hold.js.map +1 -1
  24. package/dist/completion/team-phase.d.ts.map +1 -1
  25. package/dist/completion/team-phase.js +1 -0
  26. package/dist/completion/team-phase.js.map +1 -1
  27. package/dist/completion/unclaimed-migration-notice-phase.d.ts +97 -0
  28. package/dist/completion/unclaimed-migration-notice-phase.d.ts.map +1 -0
  29. package/dist/completion/unclaimed-migration-notice-phase.js +270 -0
  30. package/dist/completion/unclaimed-migration-notice-phase.js.map +1 -0
  31. package/dist/directive/directive-executor.d.ts.map +1 -1
  32. package/dist/directive/directive-executor.js +1 -20
  33. package/dist/directive/directive-executor.js.map +1 -1
  34. package/dist/focus/focus-executor.d.ts +1 -0
  35. package/dist/focus/focus-executor.d.ts.map +1 -1
  36. package/dist/focus/focus-executor.js +18 -17
  37. package/dist/focus/focus-executor.js.map +1 -1
  38. package/dist/focus/focus-team-state.js +1 -1
  39. package/dist/focus/listener-spawn.d.ts.map +1 -1
  40. package/dist/focus/listener-spawn.js +5 -20
  41. package/dist/focus/listener-spawn.js.map +1 -1
  42. package/dist/focus/listener-state.d.ts.map +1 -1
  43. package/dist/focus/listener-state.js +1 -0
  44. package/dist/focus/listener-state.js.map +1 -1
  45. package/dist/focus/listener.d.ts +1 -0
  46. package/dist/focus/listener.d.ts.map +1 -1
  47. package/dist/focus/listener.js +9 -0
  48. package/dist/focus/listener.js.map +1 -1
  49. package/dist/focus/migration-claim-pass.d.ts +50 -0
  50. package/dist/focus/migration-claim-pass.d.ts.map +1 -0
  51. package/dist/focus/migration-claim-pass.js +234 -0
  52. package/dist/focus/migration-claim-pass.js.map +1 -0
  53. package/dist/focus/pending-spawn-pass-deps.d.ts.map +1 -1
  54. package/dist/focus/pending-spawn-pass-deps.js +2 -1
  55. package/dist/focus/pending-spawn-pass-deps.js.map +1 -1
  56. package/dist/focus/team-actionable-work.d.ts +21 -0
  57. package/dist/focus/team-actionable-work.d.ts.map +1 -1
  58. package/dist/focus/team-actionable-work.js +3 -0
  59. package/dist/focus/team-actionable-work.js.map +1 -1
  60. package/dist/git/types.d.ts.map +1 -1
  61. package/dist/git/types.js +2 -1
  62. package/dist/git/types.js.map +1 -1
  63. package/dist/loops/llm-client.d.ts.map +1 -1
  64. package/dist/loops/llm-client.js +11 -1
  65. package/dist/loops/llm-client.js.map +1 -1
  66. package/dist/migrations/migration-claim-lifecycle.d.ts +166 -0
  67. package/dist/migrations/migration-claim-lifecycle.d.ts.map +1 -0
  68. package/dist/migrations/migration-claim-lifecycle.js +198 -0
  69. package/dist/migrations/migration-claim-lifecycle.js.map +1 -0
  70. package/dist/migrations/migration-held-set.d.ts +171 -0
  71. package/dist/migrations/migration-held-set.d.ts.map +1 -0
  72. package/dist/migrations/migration-held-set.js +295 -0
  73. package/dist/migrations/migration-held-set.js.map +1 -0
  74. package/dist/migrations/migration-inventory.d.ts +187 -0
  75. package/dist/migrations/migration-inventory.d.ts.map +1 -0
  76. package/dist/migrations/migration-inventory.js +253 -0
  77. package/dist/migrations/migration-inventory.js.map +1 -0
  78. package/dist/migrations/migration-manifest.d.ts +114 -0
  79. package/dist/migrations/migration-manifest.d.ts.map +1 -0
  80. package/dist/migrations/migration-manifest.js +295 -0
  81. package/dist/migrations/migration-manifest.js.map +1 -0
  82. package/dist/prompt/team-prompt-base.js +1 -1
  83. package/dist/prompt-sections/migration-numbering-section.d.ts +58 -0
  84. package/dist/prompt-sections/migration-numbering-section.d.ts.map +1 -0
  85. package/dist/prompt-sections/migration-numbering-section.js +70 -0
  86. package/dist/prompt-sections/migration-numbering-section.js.map +1 -0
  87. package/dist/prompt-sections/migration-numbering-state.d.ts +30 -0
  88. package/dist/prompt-sections/migration-numbering-state.d.ts.map +1 -0
  89. package/dist/prompt-sections/migration-numbering-state.js +24 -0
  90. package/dist/prompt-sections/migration-numbering-state.js.map +1 -0
  91. package/dist/prompt-sections/unclaimed-migration-section.d.ts +38 -0
  92. package/dist/prompt-sections/unclaimed-migration-section.d.ts.map +1 -0
  93. package/dist/prompt-sections/unclaimed-migration-section.js +57 -0
  94. package/dist/prompt-sections/unclaimed-migration-section.js.map +1 -0
  95. package/dist/queries/claim-pass-focuses.d.ts +19 -0
  96. package/dist/queries/claim-pass-focuses.d.ts.map +1 -0
  97. package/dist/queries/claim-pass-focuses.js +72 -0
  98. package/dist/queries/claim-pass-focuses.js.map +1 -0
  99. package/dist/queries/daemon-connection.d.ts.map +1 -1
  100. package/dist/queries/daemon-connection.js +1 -0
  101. package/dist/queries/daemon-connection.js.map +1 -1
  102. package/dist/queries/focus-discovery.d.ts +25 -2
  103. package/dist/queries/focus-discovery.d.ts.map +1 -1
  104. package/dist/queries/focus-discovery.js +16 -9
  105. package/dist/queries/focus-discovery.js.map +1 -1
  106. package/dist/queries/focus-unclaimed-migration.d.ts +146 -0
  107. package/dist/queries/focus-unclaimed-migration.d.ts.map +1 -0
  108. package/dist/queries/focus-unclaimed-migration.js +266 -0
  109. package/dist/queries/focus-unclaimed-migration.js.map +1 -0
  110. package/dist/queries/live-focus-branches.d.ts +32 -0
  111. package/dist/queries/live-focus-branches.d.ts.map +1 -0
  112. package/dist/queries/live-focus-branches.js +66 -0
  113. package/dist/queries/live-focus-branches.js.map +1 -0
  114. package/dist/queries/migration-claims.d.ts +25 -0
  115. package/dist/queries/migration-claims.d.ts.map +1 -0
  116. package/dist/queries/migration-claims.js +79 -0
  117. package/dist/queries/migration-claims.js.map +1 -0
  118. package/dist/queries/schemas.d.ts +2 -0
  119. package/dist/queries/schemas.d.ts.map +1 -1
  120. package/dist/queries/schemas.js +6 -0
  121. package/dist/queries/schemas.js.map +1 -1
  122. package/dist/queries/shared.js +1 -1
  123. package/dist/session/session-lineage.d.ts.map +1 -1
  124. package/dist/session/session-lineage.js +3 -0
  125. package/dist/session/session-lineage.js.map +1 -1
  126. package/dist/shell/heartbeat-metadata.d.ts +48 -2
  127. package/dist/shell/heartbeat-metadata.d.ts.map +1 -1
  128. package/dist/shell/heartbeat-metadata.js +80 -3
  129. package/dist/shell/heartbeat-metadata.js.map +1 -1
  130. package/dist/shell/heartbeat.d.ts +13 -0
  131. package/dist/shell/heartbeat.d.ts.map +1 -1
  132. package/dist/shell/heartbeat.js +31 -10
  133. package/dist/shell/heartbeat.js.map +1 -1
  134. package/dist/shell/mcp-resolution.js +1 -1
  135. package/dist/shell/mcp-resolution.js.map +1 -1
  136. package/dist/shell/migration-held-set-publish.d.ts +170 -0
  137. package/dist/shell/migration-held-set-publish.d.ts.map +1 -0
  138. package/dist/shell/migration-held-set-publish.js +172 -0
  139. package/dist/shell/migration-held-set-publish.js.map +1 -0
  140. package/dist/shell/worker-pidfile.d.ts.map +1 -1
  141. package/dist/shell/worker-pidfile.js +1 -0
  142. package/dist/shell/worker-pidfile.js.map +1 -1
  143. package/dist/spawn/helpers.d.ts.map +1 -1
  144. package/dist/spawn/helpers.js +1 -0
  145. package/dist/spawn/helpers.js.map +1 -1
  146. package/dist/spawn/lead-launch.d.ts.map +1 -1
  147. package/dist/spawn/lead-launch.js +1 -0
  148. package/dist/spawn/lead-launch.js.map +1 -1
  149. package/dist/spawn/lead-process-ownership.d.ts.map +1 -1
  150. package/dist/spawn/lead-process-ownership.js +1 -0
  151. package/dist/spawn/lead-process-ownership.js.map +1 -1
  152. package/dist/spawn/process-group-kill.d.ts.map +1 -1
  153. package/dist/spawn/process-group-kill.js +1 -0
  154. package/dist/spawn/process-group-kill.js.map +1 -1
  155. package/dist/spawn/process-spawn.d.ts +18 -1
  156. package/dist/spawn/process-spawn.d.ts.map +1 -1
  157. package/dist/spawn/process-spawn.js +11 -6
  158. package/dist/spawn/process-spawn.js.map +1 -1
  159. package/dist/spawn/prompt-assembly.d.ts +115 -18
  160. package/dist/spawn/prompt-assembly.d.ts.map +1 -1
  161. package/dist/spawn/prompt-assembly.js +121 -2
  162. package/dist/spawn/prompt-assembly.js.map +1 -1
  163. package/dist/spawn/spawn-and-acknowledge.d.ts +61 -0
  164. package/dist/spawn/spawn-and-acknowledge.d.ts.map +1 -0
  165. package/dist/spawn/spawn-and-acknowledge.js +117 -0
  166. package/dist/spawn/spawn-and-acknowledge.js.map +1 -0
  167. package/dist/spawn/spawn-cooldown.js +1 -1
  168. package/dist/spawn/spawn-decision.d.ts +10 -10
  169. package/dist/spawn/spawn-decision.d.ts.map +1 -1
  170. package/dist/spawn/spawn-decision.js +33 -5
  171. package/dist/spawn/spawn-decision.js.map +1 -1
  172. package/dist/templates/claude-md.d.ts +1 -1
  173. package/dist/templates/claude-md.d.ts.map +1 -1
  174. package/dist/templates/claude-md.js +24 -0
  175. package/dist/templates/claude-md.js.map +1 -1
  176. package/dist/testing/fixtures/index.js +1 -1
  177. package/dist/testing/fixtures/migration-namespace-repo.d.ts +63 -0
  178. package/dist/testing/fixtures/migration-namespace-repo.d.ts.map +1 -0
  179. package/dist/testing/fixtures/migration-namespace-repo.js +164 -0
  180. package/dist/testing/fixtures/migration-namespace-repo.js.map +1 -0
  181. package/dist/testing/fixtures/stubborn-lead-process.d.ts.map +1 -1
  182. package/dist/testing/fixtures/stubborn-lead-process.js +1 -0
  183. package/dist/testing/fixtures/stubborn-lead-process.js.map +1 -1
  184. package/dist/types/index.js +1 -1
  185. package/dist/verify/no-own-delta-verdict.d.ts +16 -2
  186. package/dist/verify/no-own-delta-verdict.d.ts.map +1 -1
  187. package/dist/verify/no-own-delta-verdict.js +18 -2
  188. package/dist/verify/no-own-delta-verdict.js.map +1 -1
  189. package/package.json +2 -2
@@ -0,0 +1,295 @@
1
+ // PINNED-BY-BEGIN (generated by gen:pinned-by -- do not hand-edit; checked by lint:pinned-by)
2
+ // Pinned by: packages/daemon/src/migrations/concurrent-claim-regression.test.ts,
3
+ // packages/daemon/src/migrations/held-set-grant-effect.test.ts,
4
+ // packages/daemon/src/migrations/migration-held-set.test.ts,
5
+ // packages/daemon/src/migrations/migration-inventory.test.ts,
6
+ // packages/daemon/src/migrations/migration-manifest-parity.test.ts,
7
+ // packages/daemon/src/migrations/migration-manifest.test.ts,
8
+ // packages/daemon/src/spawn/migration-numbering-wiring.test.ts,
9
+ // packages/daemon/src/spawn/spawn-and-acknowledge.test.ts
10
+ // PINNED-BY-END
11
+ /**
12
+ * A repo's declaration of its migration numbering (`telora.migrations.json` at
13
+ * the repo root).
14
+ *
15
+ * WHAT THIS IS FOR
16
+ * ----------------
17
+ * A migration number must be claimed ONCE across a product, before the file
18
+ * exists, or two concurrently-armed focuses compute the same "next free" number
19
+ * from the same stale base and both take it. The allocator that grants a number
20
+ * cannot do that without knowing two things it has no way to infer: where a
21
+ * product keeps its migrations, and how a number is read out of a filename.
22
+ * This module is the first half of that perception -- the repo SAYS.
23
+ *
24
+ * WHY A DECLARATION rather than a hard-coded convention
25
+ * -----------------------------------------------------
26
+ * Two live products number their migrations differently, and neither layout can
27
+ * be inferred from the other:
28
+ *
29
+ * - Telora: `supabase/migrations/20260614172757_name.sql`. The ordinal is a
30
+ * 14-digit timestamp prefix, so the scheme is `timestamp`. No journal.
31
+ * - Tinker Tailor: `lib/db/migrations/0352_a_cloth_names_its_supplier.sql`.
32
+ * The ordinal is a 4-digit prefix and the scheme is `sequential`;
33
+ * `lib/db/migrations/meta/_journal.json` registers each migration with an
34
+ * `idx` and a `tag`. `db:generate` is unusable there, so the migrations AND
35
+ * the journal entries are both written BY HAND.
36
+ *
37
+ * A mechanism that assumed a generator would serve only the first. So the repo
38
+ * declares, and the daemon reads the declaration -- the same shape
39
+ * `telora.verify.json` uses to declare the repo's gate command
40
+ * (`verify/verification-manifest.ts`), for the same reason: the declaration
41
+ * travels with the code it describes.
42
+ *
43
+ * WHY `scheme` IS REQUIRED
44
+ * ------------------------
45
+ * It is the one field the filename pattern does not already imply, and the
46
+ * allocator's behaviour turns on it entirely: under `sequential` the next free
47
+ * number is the highest held plus one, and under `timestamp` it is the current
48
+ * time. Guessing from the ordinal's width would read a 14-digit sequential
49
+ * scheme as a timestamp -- and the failure would be silent, because both
50
+ * guesses produce a plausible number. A product that ships this file must say
51
+ * which it is.
52
+ *
53
+ * WHY MALFORMED FAILS LOUDLY (missing does not)
54
+ * ---------------------------------------------
55
+ * The asymmetry is `verification-manifest.ts`'s, applied here, and downstream it
56
+ * is load-bearing rather than stylistic:
57
+ *
58
+ * - MISSING file => `undefined`. A repo that ships no declaration has said
59
+ * nothing: it opts out, and the daemon manages plenty of repos with no
60
+ * migrations at all. Its teams keep numbering the way they do today.
61
+ * - MALFORMED file => THROW, naming the path and the problem. A repo that
62
+ * ships a declaration HAS said something and we could not read it. The
63
+ * consumer is an allocator answering "which number is free?", and an
64
+ * unreadable declaration degraded to "no declaration" would leave that
65
+ * question to be answered from a worktree -- reinstating, on a typo, the
66
+ * exact cause this mechanism exists to remove. A broken declaration is
67
+ * louder than no declaration.
68
+ *
69
+ * That distinction is why {@link readMigrationManifest} has three outcomes and
70
+ * not two: undeclared, unreadable, and declared. A consumer holds on the second
71
+ * while ignoring the first.
72
+ *
73
+ * ORDINALS ARE STRINGS
74
+ * --------------------
75
+ * Both live schemes are zero-padded fixed width (`0352`, `20260614172757`), so
76
+ * string ordering IS numeric ordering within one repo. Nothing here parses an
77
+ * ordinal to a number; introducing a parse would only add a way to mis-read one.
78
+ *
79
+ * KNOWN SEAM, deliberately not closed here: the padding WIDTH a sequential
80
+ * allocator must emit is not declared. It is recoverable from the ordinals a
81
+ * ref holds (they are fixed width by construction), which covers every product
82
+ * that already has a migration. A sequential product with NO migrations yet has
83
+ * no width to recover, and choosing what to do there belongs to the allocator
84
+ * that grants the number, not to the file that describes the layout.
85
+ *
86
+ * @module migration-manifest
87
+ */
88
+ import { existsSync, readFileSync } from 'node:fs';
89
+ import { resolve } from 'node:path';
90
+ /**
91
+ * Filename of the repo-committed migration declaration, at the REPO ROOT.
92
+ *
93
+ * Repo-root for the same reason `telora.verify.json` is: `.gitignore` excludes
94
+ * `.telora/` wholesale and git cannot re-include a file whose parent directory
95
+ * is excluded, so a declaration nested there could never be tracked.
96
+ */
97
+ export const MIGRATION_MANIFEST_FILENAME = 'telora.migrations.json';
98
+ /** Every scheme this reader accepts, in the order an error message lists them. */
99
+ export const MIGRATION_SCHEMES = ['sequential', 'timestamp'];
100
+ /** Real-fs default for {@link MigrationManifestFs}. */
101
+ export const defaultMigrationManifestFs = {
102
+ exists: (path) => existsSync(path),
103
+ readText: (path) => readFileSync(path, 'utf-8'),
104
+ };
105
+ /** Absolute path of the migration declaration for a repo. */
106
+ export function resolveMigrationManifestPath(repoPath) {
107
+ return resolve(repoPath, MIGRATION_MANIFEST_FILENAME);
108
+ }
109
+ /**
110
+ * Thrown when a declaration EXISTS and cannot be read.
111
+ *
112
+ * A distinct class, not a bare Error, because the difference between "this
113
+ * product declared nothing" and "this product's declaration is broken" has to
114
+ * survive all the way to the team that asked for a number: the first is a
115
+ * product that opted out, the second is a bug someone must fix. A consumer that
116
+ * cannot tell them apart can only collapse both into a guess.
117
+ */
118
+ export class MigrationManifestError extends Error {
119
+ /** Absolute path of the declaration that could not be read. */
120
+ manifestPath;
121
+ constructor(manifestPath, problem) {
122
+ super(`Invalid Telora migration declaration at ${manifestPath}: ${problem}. `
123
+ + `A malformed declaration is never degraded to "this repo declares no migration `
124
+ + `numbering" -- that would send the team back to numbering from its own worktree, `
125
+ + `which is the whole failure this declaration exists to remove. Fix the file, or `
126
+ + `delete it to opt this repo out of claiming migration numbers through Telora.`);
127
+ this.name = 'MigrationManifestError';
128
+ this.manifestPath = manifestPath;
129
+ }
130
+ }
131
+ /** Throw a declaration error that always names the offending file. */
132
+ function manifestError(path, problem) {
133
+ throw new MigrationManifestError(path, problem);
134
+ }
135
+ /** A repo-relative path that is safe to hand to git as a pathspec. */
136
+ function requireRepoRelativePath(raw, key, path) {
137
+ if (typeof raw !== 'string') {
138
+ manifestError(path, raw === undefined
139
+ ? `missing required "${key}" string (check for a typo in the key)`
140
+ : `"${key}" must be a string (got ${typeof raw})`);
141
+ }
142
+ const value = raw.trim();
143
+ if (value === '')
144
+ manifestError(path, `"${key}" must not be empty`);
145
+ if (value.startsWith('/')) {
146
+ manifestError(path, `"${key}" must be repo-relative, not absolute (got ${JSON.stringify(value)})`);
147
+ }
148
+ if (value.split('/').includes('..')) {
149
+ manifestError(path, `"${key}" must not escape the repo with ".." (got ${JSON.stringify(value)})`);
150
+ }
151
+ return value.replace(/\/+$/, '');
152
+ }
153
+ /**
154
+ * The file pattern must compile AND capture both `ordinal` and `tag`.
155
+ *
156
+ * A pattern missing a group is malformed rather than partially usable: a claim
157
+ * records the tag alongside the number, and the confirm pass matches the file
158
+ * that lands against the claim by both.
159
+ */
160
+ function requireFilePattern(raw, path) {
161
+ if (typeof raw !== 'string') {
162
+ manifestError(path, raw === undefined
163
+ ? `missing required "filePattern" string (check for a typo in the key)`
164
+ : `"filePattern" must be a string (got ${typeof raw})`);
165
+ }
166
+ if (raw.trim() === '')
167
+ manifestError(path, `"filePattern" must not be empty`);
168
+ let compiled;
169
+ try {
170
+ compiled = new RegExp(raw);
171
+ }
172
+ catch (err) {
173
+ manifestError(path, `"filePattern" is not a valid regular expression (${String(err?.message ?? err)})`);
174
+ }
175
+ for (const group of ['ordinal', 'tag']) {
176
+ if (!compiled.source.includes(`(?<${group}>`)) {
177
+ manifestError(path, `"filePattern" must carry a named capture group (?<${group}>...) -- `
178
+ + `a claim is recorded by ${group === 'ordinal' ? 'number' : 'number AND tag'}`);
179
+ }
180
+ }
181
+ return raw;
182
+ }
183
+ /**
184
+ * The scheme. Required, and an unrecognised value is malformed rather than
185
+ * defaulted: see the module header on why guessing it fails silently.
186
+ */
187
+ function requireScheme(raw, path) {
188
+ if (typeof raw !== 'string') {
189
+ manifestError(path, raw === undefined
190
+ ? `missing required "scheme" string -- one of ${MIGRATION_SCHEMES.join(' | ')} `
191
+ + `(the allocator grants the next ordinal under sequential and the current time `
192
+ + `under timestamp, so it cannot be inferred)`
193
+ : `"scheme" must be a string (got ${typeof raw})`);
194
+ }
195
+ const value = raw.trim();
196
+ const match = MIGRATION_SCHEMES.find((scheme) => scheme === value);
197
+ if (match === undefined) {
198
+ manifestError(path, `"scheme" must be one of ${MIGRATION_SCHEMES.join(' | ')} `
199
+ + `(got ${JSON.stringify(raw)})`);
200
+ }
201
+ return match;
202
+ }
203
+ /** The optional journal declaration. Present-but-wrong is malformed, like every other field. */
204
+ function optionalJournal(raw, path) {
205
+ const value = raw.journal;
206
+ if (value === undefined)
207
+ return undefined;
208
+ if (typeof value !== 'object' || value === null || Array.isArray(value)) {
209
+ manifestError(path, `"journal" must be an object with a "path" `
210
+ + `(got ${Array.isArray(value) ? 'an array' : typeof value})`);
211
+ }
212
+ const journalPath = requireRepoRelativePath(value.path, 'journal.path', path);
213
+ return { path: journalPath };
214
+ }
215
+ /**
216
+ * Read the repo's migration declaration.
217
+ *
218
+ * @param repoPath Product repo root (`configForProduct` sets this per product).
219
+ * Undefined => no repo to read => `undefined`.
220
+ * @param fs Injectable fs seam; defaults to real fs.
221
+ * @returns The parsed declaration, or `undefined` when the repo declares no
222
+ * migration numbering at all.
223
+ * @throws {@link MigrationManifestError} naming the file path when the
224
+ * declaration exists but is unreadable / not JSON / not an object /
225
+ * missing `dir`, `scheme` or a `filePattern` carrying both named
226
+ * groups / carrying a malformed `journal`.
227
+ */
228
+ export function readMigrationManifest(repoPath, fs = defaultMigrationManifestFs) {
229
+ if (!repoPath)
230
+ return undefined;
231
+ const path = resolveMigrationManifestPath(repoPath);
232
+ if (!fs.exists(path))
233
+ return undefined;
234
+ let text;
235
+ try {
236
+ text = fs.readText(path);
237
+ }
238
+ catch (err) {
239
+ manifestError(path, `file could not be read (${String(err?.message ?? err)})`);
240
+ }
241
+ let parsed;
242
+ try {
243
+ parsed = JSON.parse(text);
244
+ }
245
+ catch (err) {
246
+ manifestError(path, `not valid JSON (${String(err?.message ?? err)})`);
247
+ }
248
+ if (typeof parsed !== 'object' || parsed === null || Array.isArray(parsed)) {
249
+ manifestError(path, `expected a JSON object, got ${Array.isArray(parsed) ? 'an array' : typeof parsed}`);
250
+ }
251
+ const raw = parsed;
252
+ const journal = optionalJournal(raw, path);
253
+ return {
254
+ dir: requireRepoRelativePath(raw.dir, 'dir', path),
255
+ filePattern: requireFilePattern(raw.filePattern, path),
256
+ scheme: requireScheme(raw.scheme, path),
257
+ ...(journal !== undefined ? { journal } : {}),
258
+ };
259
+ }
260
+ /**
261
+ * The ordinal width the DECLARATION fixes, or null when it fixes none.
262
+ *
263
+ * WHY THE DECLARATION IS ASKED THIS AT ALL. A journal registers `idx` as a bare
264
+ * number (351) while the filename carries it padded (`0351`), so unioning the
265
+ * two needs a width to normalise to. The filenames were the only source of one
266
+ * -- and a ref whose only surviving evidence is a journal entry (files removed,
267
+ * a journal written ahead of them) has no filenames. The raw `351` then went
268
+ * into the held set, the candidate rule read the width of what it was given,
269
+ * derived 3, and proposed `352` on a product whose migrations must match
270
+ * `^\d{4}`. A number that cannot be the name of a migration on this product is
271
+ * worse than a refusal: it is granted, written, and discovered by whoever runs
272
+ * the migrations.
273
+ *
274
+ * The declaration knew the width the whole time. `^(?<ordinal>\d{4})_` says
275
+ * four digits, and it says it authoritatively: a filename of any other width
276
+ * does not match the pattern, so no inventoried file can disagree with it.
277
+ *
278
+ * Null when the pattern does not FIX a width (`\d+`, a character class, an
279
+ * alternation). Then the filenames are the authority, as they were -- this adds
280
+ * a source, it does not replace one.
281
+ */
282
+ export function declaredOrdinalWidth(filePattern) {
283
+ // The `ordinal` group's body, for a body containing no nested parens (every
284
+ // width-fixing pattern is of that shape; anything else answers null anyway).
285
+ const group = /\(\?<ordinal>((?:\\.|[^()\\])*)\)/.exec(filePattern);
286
+ const body = group?.[1];
287
+ if (body === undefined)
288
+ return null;
289
+ const fixed = /^(?:\\d|\[0-9\])\{(\d+)\}$/.exec(body);
290
+ if (fixed === null)
291
+ return null;
292
+ const width = Number(fixed[1]);
293
+ return Number.isInteger(width) && width > 0 ? width : null;
294
+ }
295
+ //# sourceMappingURL=migration-manifest.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"migration-manifest.js","sourceRoot":"","sources":["../../src/migrations/migration-manifest.ts"],"names":[],"mappings":"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"}
@@ -1,5 +1,5 @@
1
1
  // PINNED-BY-BEGIN (generated by gen:pinned-by -- do not hand-edit; checked by lint:pinned-by)
2
- // Pinned by: 24 tests -- run: npm run gen:pinned-by -- --list packages/daemon/src/prompt/team-prompt-base.ts
2
+ // Pinned by: 27 tests -- run: npm run gen:pinned-by -- --list packages/daemon/src/prompt/team-prompt-base.ts
3
3
  // PINNED-BY-END
4
4
  // Role-framework sections.
5
5
  export { buildRoleSection, buildDomainBoundariesSection, buildTeamLeadRoleSection, buildReadOnlyAuditSection, } from '../prompt-sections/role-sections.js';
@@ -0,0 +1,58 @@
1
+ /**
2
+ * The numbering rule: what a coding team is told about claiming a migration
3
+ * number before it names the file.
4
+ *
5
+ * WHY A PROMPT SECTION AND NOT JUST A TOOL
6
+ * ----------------------------------------
7
+ * The allocator exists, but a team that does not know to call it numbers from
8
+ * its worktree exactly as before -- and that is the entire failure. The MCP
9
+ * tool is the mechanism; this is how the team comes to use it. Telora is in the
10
+ * loop at the moment the file is named because the team's tooling IS Telora's
11
+ * MCP and the daemon composes the prompt, so the rule arrives with the work
12
+ * rather than living in a wiki page someone might read.
13
+ *
14
+ * WHY EVERY MESSAGE SHAPE
15
+ * -----------------------
16
+ * A team writes a migration on whichever turn the work lands on. A rule carried
17
+ * only by the fresh prompt is absent from the resume delta -- which is most
18
+ * turns of a long focus -- so the section is composed into the fresh prompt,
19
+ * the resume delta and the forced-fresh scoping turn alike, through the same
20
+ * seam `integration-reconcile-section.ts` uses, and is therefore byte-identical
21
+ * across both engine backends (they encode the same text).
22
+ *
23
+ * WHEN IT RENDERS NOTHING
24
+ * -----------------------
25
+ * - A product that declares no migration numbering. Its teams keep numbering
26
+ * as they do today; telling them to call a tool that will refuse would be
27
+ * worse than silence.
28
+ * - A REVIEW pass. A reviewer writes no migrations.
29
+ *
30
+ * It DOES render on a product whose declaration is BROKEN, with different text:
31
+ * that team's claims will refuse, and being told why beats discovering it at
32
+ * the moment it needs a number.
33
+ *
34
+ * @module migration-numbering-section
35
+ */
36
+ import type { MigrationManifest } from '../migrations/migration-manifest.js';
37
+ /** The section's heading -- the anchor callers and tests name it by. */
38
+ export declare const MIGRATION_NUMBERING_HEADING = "# CLAIM YOUR MIGRATION NUMBER BEFORE YOU NAME THE FILE";
39
+ /** What the spawn knows about this product's migration numbering. */
40
+ export type MigrationNumberingState =
41
+ /** The product declares numbering, and it reads. */
42
+ {
43
+ kind: 'declared';
44
+ manifest: MigrationManifest;
45
+ }
46
+ /** A declaration exists and is broken; claims will refuse until it is fixed. */
47
+ | {
48
+ kind: 'declarationUnreadable';
49
+ reason: string;
50
+ };
51
+ /**
52
+ * The numbering rule, as a block to append to a CODING message.
53
+ *
54
+ * Returns [] when `state` is null (the product declares no numbering) or when
55
+ * the pass is a review, so those messages compose exactly as they do today.
56
+ */
57
+ export declare function buildMigrationNumberingSection(state: MigrationNumberingState | null, isReviewPass: boolean): string[];
58
+ //# sourceMappingURL=migration-numbering-section.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"migration-numbering-section.d.ts","sourceRoot":"","sources":["../../src/prompt-sections/migration-numbering-section.ts"],"names":[],"mappings":"AAOA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCG;AAEH,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,qCAAqC,CAAC;AAE7E,wEAAwE;AACxE,eAAO,MAAM,2BAA2B,2DAA2D,CAAC;AAEpG,qEAAqE;AACrE,MAAM,MAAM,uBAAuB;AACjC,oDAAoD;AAClD;IAAE,IAAI,EAAE,UAAU,CAAC;IAAC,QAAQ,EAAE,iBAAiB,CAAA;CAAE;AACnD,gFAAgF;GAC9E;IAAE,IAAI,EAAE,uBAAuB,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC;AAEtD;;;;;GAKG;AACH,wBAAgB,8BAA8B,CAC5C,KAAK,EAAE,uBAAuB,GAAG,IAAI,EACrC,YAAY,EAAE,OAAO,GACpB,MAAM,EAAE,CAwDV"}
@@ -0,0 +1,70 @@
1
+ // PINNED-BY-BEGIN (generated by gen:pinned-by -- do not hand-edit; checked by lint:pinned-by)
2
+ // Pinned by: packages/daemon/src/migrations/claim-production-wiring.test.ts,
3
+ // packages/daemon/src/spawn/migration-numbering-spawn.test.ts,
4
+ // packages/daemon/src/spawn/migration-numbering-wiring.test.ts,
5
+ // packages/daemon/src/spawn/spawn-and-acknowledge.test.ts
6
+ // PINNED-BY-END
7
+ /** The section's heading -- the anchor callers and tests name it by. */
8
+ export const MIGRATION_NUMBERING_HEADING = '# CLAIM YOUR MIGRATION NUMBER BEFORE YOU NAME THE FILE';
9
+ /**
10
+ * The numbering rule, as a block to append to a CODING message.
11
+ *
12
+ * Returns [] when `state` is null (the product declares no numbering) or when
13
+ * the pass is a review, so those messages compose exactly as they do today.
14
+ */
15
+ export function buildMigrationNumberingSection(state, isReviewPass) {
16
+ if (isReviewPass || state === null)
17
+ return [];
18
+ if (state.kind === 'declarationUnreadable') {
19
+ return [
20
+ MIGRATION_NUMBERING_HEADING,
21
+ '',
22
+ "This product's `telora.migrations.json` cannot be read, so Telora cannot grant",
23
+ 'migration numbers for it:',
24
+ '',
25
+ ` ${state.reason}`,
26
+ '',
27
+ 'If your work needs a migration, FIX THE DECLARATION FIRST -- a claim against a',
28
+ 'broken declaration is refused, deliberately, rather than answered with a guessed',
29
+ 'number. Do not fall back to reading the highest number in this worktree: that is',
30
+ 'the exact thing the declaration exists to stop.',
31
+ ];
32
+ }
33
+ const { dir, scheme } = state.manifest;
34
+ const schemeLine = scheme === 'sequential'
35
+ ? 'the next number after the highest any of them holds'
36
+ : 'a timestamp no other claim holds';
37
+ return [
38
+ MIGRATION_NUMBERING_HEADING,
39
+ '',
40
+ 'Do NOT pick a migration number by looking at this worktree. Claim it through',
41
+ 'Telora first:',
42
+ '',
43
+ ' telora_product_migration { action: "claim", productId, focusId, tag: "<name>" }',
44
+ '',
45
+ `You get back the ordinal to use and the filename stem to write under \`${dir}\`.`,
46
+ '',
47
+ 'WHY. Two focuses armed at once on this product work in separate worktrees cut',
48
+ 'from the same base. "The next free number" computed locally is the same number',
49
+ 'your sibling just computed locally -- and git sees no conflict, because the two',
50
+ 'files have different names. The merge admits both, and it surfaces only when the',
51
+ 'migrations are applied in order. On 2026-09-22 that cost a renumber of four',
52
+ 'migrations, three renamed sensor tests, a rebuilt journal tail and ~40 corrected',
53
+ 'references across 79 files, with a finished delivery stranded at verify.',
54
+ '',
55
+ `The claim is granted from what integration holds, what every live focus branch`,
56
+ `holds, and every outstanding claim -- ${schemeLine}. None of that is visible from`,
57
+ 'here. The grant is atomic, so two teams claiming in the same instant never',
58
+ 'receive one number.',
59
+ '',
60
+ 'Pass the `tag` you intend to use. If the file ends up named differently that is',
61
+ 'fine -- the daemon confirms your claim with the tag the file actually carries.',
62
+ '',
63
+ 'IF THE CLAIM IS REFUSED, do not work around it. `migration_numbering_unavailable`',
64
+ 'means the declaration is missing or broken; `migration_held_set_unavailable` means',
65
+ 'no daemon has reported what the branches hold, or a branch could not be read, so',
66
+ 'granting would be guessing. Both are refusals on purpose. Fix the cause or raise',
67
+ 'it -- numbering by hand is what they exist to prevent.',
68
+ ];
69
+ }
70
+ //# sourceMappingURL=migration-numbering-section.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"migration-numbering-section.js","sourceRoot":"","sources":["../../src/prompt-sections/migration-numbering-section.ts"],"names":[],"mappings":"AAAA,8FAA8F;AAC9F,6EAA6E;AAC7E,iEAAiE;AACjE,kEAAkE;AAClE,4DAA4D;AAC5D,gBAAgB;AAwChB,wEAAwE;AACxE,MAAM,CAAC,MAAM,2BAA2B,GAAG,wDAAwD,CAAC;AASpG;;;;;GAKG;AACH,MAAM,UAAU,8BAA8B,CAC5C,KAAqC,EACrC,YAAqB;IAErB,IAAI,YAAY,IAAI,KAAK,KAAK,IAAI;QAAE,OAAO,EAAE,CAAC;IAE9C,IAAI,KAAK,CAAC,IAAI,KAAK,uBAAuB,EAAE,CAAC;QAC3C,OAAO;YACL,2BAA2B;YAC3B,EAAE;YACF,gFAAgF;YAChF,2BAA2B;YAC3B,EAAE;YACF,OAAO,KAAK,CAAC,MAAM,EAAE;YACrB,EAAE;YACF,gFAAgF;YAChF,kFAAkF;YAClF,kFAAkF;YAClF,iDAAiD;SAClD,CAAC;IACJ,CAAC;IAED,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,KAAK,CAAC,QAAQ,CAAC;IACvC,MAAM,UAAU,GAAG,MAAM,KAAK,YAAY;QACxC,CAAC,CAAC,qDAAqD;QACvD,CAAC,CAAC,kCAAkC,CAAC;IAEvC,OAAO;QACL,2BAA2B;QAC3B,EAAE;QACF,8EAA8E;QAC9E,eAAe;QACf,EAAE;QACF,qFAAqF;QACrF,EAAE;QACF,0EAA0E,GAAG,KAAK;QAClF,EAAE;QACF,+EAA+E;QAC/E,gFAAgF;QAChF,iFAAiF;QACjF,kFAAkF;QAClF,6EAA6E;QAC7E,kFAAkF;QAClF,0EAA0E;QAC1E,EAAE;QACF,gFAAgF;QAChF,yCAAyC,UAAU,gCAAgC;QACnF,4EAA4E;QAC5E,qBAAqB;QACrB,EAAE;QACF,iFAAiF;QACjF,gFAAgF;QAChF,EAAE;QACF,mFAAmF;QACnF,oFAAoF;QACpF,kFAAkF;QAClF,kFAAkF;QAClF,wDAAwD;KACzD,CAAC;AACJ,CAAC"}
@@ -0,0 +1,30 @@
1
+ /**
2
+ * Reading a product's migration numbering for the spawn prompt.
3
+ *
4
+ * A thin adapter between the declaration reader and the prompt section: the
5
+ * reader THROWS on a broken declaration (deliberately -- see
6
+ * `migration-manifest.ts`), and the prompt must not. A spawn that failed
7
+ * because a product's JSON had a trailing comma would be a far worse failure
8
+ * than the one the declaration guards against.
9
+ *
10
+ * So the throw is turned into a state the section can render: a team whose
11
+ * product has a broken declaration is TOLD, because its claims will refuse and
12
+ * being told why beats discovering it at the moment it needs a number.
13
+ *
14
+ * Lives in `prompt-sections/` rather than `migrations/`: it exists for the
15
+ * PROMPT, and the migrations area is a rank-0 leaf that must not reach up into
16
+ * a section's types.
17
+ *
18
+ * @module migration-numbering-state
19
+ */
20
+ import type { MigrationNumberingState } from './migration-numbering-section.js';
21
+ import { type MigrationManifestFs } from '../migrations/migration-manifest.js';
22
+ /**
23
+ * What the spawn should tell this product's coding teams about numbering.
24
+ *
25
+ * @returns `null` when the product declares no numbering (render nothing), a
26
+ * `declared` state when it reads, or `declarationUnreadable` when it
27
+ * exists and is broken.
28
+ */
29
+ export declare function resolveMigrationNumberingState(repoPath: string | undefined, fs?: MigrationManifestFs): MigrationNumberingState | null;
30
+ //# sourceMappingURL=migration-numbering-state.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"migration-numbering-state.d.ts","sourceRoot":"","sources":["../../src/prompt-sections/migration-numbering-state.ts"],"names":[],"mappings":"AAIA;;;;;;;;;;;;;;;;;;GAkBG;AAEH,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,kCAAkC,CAAC;AAChF,OAAO,EAAyB,KAAK,mBAAmB,EAAE,MAAM,qCAAqC,CAAC;AAEtG;;;;;;GAMG;AACH,wBAAgB,8BAA8B,CAC5C,QAAQ,EAAE,MAAM,GAAG,SAAS,EAC5B,EAAE,CAAC,EAAE,mBAAmB,GACvB,uBAAuB,GAAG,IAAI,CAUhC"}
@@ -0,0 +1,24 @@
1
+ // PINNED-BY-BEGIN (generated by gen:pinned-by -- do not hand-edit; checked by lint:pinned-by)
2
+ // Pinned by: packages/daemon/src/spawn/migration-numbering-spawn.test.ts
3
+ // PINNED-BY-END
4
+ import { readMigrationManifest } from '../migrations/migration-manifest.js';
5
+ /**
6
+ * What the spawn should tell this product's coding teams about numbering.
7
+ *
8
+ * @returns `null` when the product declares no numbering (render nothing), a
9
+ * `declared` state when it reads, or `declarationUnreadable` when it
10
+ * exists and is broken.
11
+ */
12
+ export function resolveMigrationNumberingState(repoPath, fs) {
13
+ try {
14
+ const manifest = readMigrationManifest(repoPath, fs);
15
+ return manifest === undefined ? null : { kind: 'declared', manifest };
16
+ }
17
+ catch (err) {
18
+ return {
19
+ kind: 'declarationUnreadable',
20
+ reason: String(err?.message ?? err),
21
+ };
22
+ }
23
+ }
24
+ //# sourceMappingURL=migration-numbering-state.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"migration-numbering-state.js","sourceRoot":"","sources":["../../src/prompt-sections/migration-numbering-state.ts"],"names":[],"mappings":"AAAA,8FAA8F;AAC9F,yEAAyE;AACzE,gBAAgB;AAuBhB,OAAO,EAAE,qBAAqB,EAA4B,MAAM,qCAAqC,CAAC;AAEtG;;;;;;GAMG;AACH,MAAM,UAAU,8BAA8B,CAC5C,QAA4B,EAC5B,EAAwB;IAExB,IAAI,CAAC;QACH,MAAM,QAAQ,GAAG,qBAAqB,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC;QACrD,OAAO,QAAQ,KAAK,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,UAAU,EAAE,QAAQ,EAAE,CAAC;IACxE,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,OAAO;YACL,IAAI,EAAE,uBAAuB;YAC7B,MAAM,EAAE,MAAM,CAAE,GAAa,EAAE,OAAO,IAAI,GAAG,CAAC;SAC/C,CAAC;IACJ,CAAC;AACH,CAAC"}
@@ -0,0 +1,38 @@
1
+ /**
2
+ * What a team is told when its own branch holds a migration it never claimed.
3
+ *
4
+ * THIS IS A GUARD ON THE RULE, NOT DETECTION AIMED AT A MERGE. It names ONE
5
+ * team's OWN file to THAT team. It does not compare that file against a sibling
6
+ * branch, does not judge a merge, and does not tell two teams to renumber --
7
+ * the contest-notice shape was abandoned by direction (reverted on integration
8
+ * in 0c634616d) precisely because two teams recomputing "next free" from the
9
+ * same union at the same moment collide again.
10
+ *
11
+ * WHY THE TEAM AND NOT A HUMAN. The file was written by this team, and claiming
12
+ * the number or removing the file is something only this team can sensibly do.
13
+ * An escalation would be a row in a human queue that can only wait for the same
14
+ * team to act. So the fact is recorded as focus state and delivered here, at the
15
+ * next spawn, where the party who can act is already reading.
16
+ *
17
+ * WHY IT IS WORTH TELLING AT ALL. An allocator a team can bypass in silence is
18
+ * not an allocator. A file written without a claim is a number nobody knows is
19
+ * taken -- the next team to claim can be granted it, and then two migrations
20
+ * exist at one number with no claim record to explain either.
21
+ *
22
+ * Renders nothing when there is no record, and never on a review pass (a
23
+ * reviewer wrote no migrations).
24
+ *
25
+ * @module unclaimed-migration-section
26
+ */
27
+ /** The section's heading -- the anchor callers and tests name it by. */
28
+ export declare const UNCLAIMED_MIGRATION_HEADING = "# A MIGRATION ON THIS BRANCH HAS NO CLAIM BEHIND IT";
29
+ /**
30
+ * The unclaimed-file notice, as a block to append to a CODING message.
31
+ *
32
+ * @param record The stored focus_debug_artifacts content, or null when the
33
+ * focus has no such record. The stored prose is carried verbatim
34
+ * rather than re-rendered, so the team and a human reading the
35
+ * Debug tab see the identical account.
36
+ */
37
+ export declare function buildUnclaimedMigrationSection(record: string | null, isReviewPass: boolean): string[];
38
+ //# sourceMappingURL=unclaimed-migration-section.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"unclaimed-migration-section.d.ts","sourceRoot":"","sources":["../../src/prompt-sections/unclaimed-migration-section.ts"],"names":[],"mappings":"AAMA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AAEH,wEAAwE;AACxE,eAAO,MAAM,2BAA2B,wDAAwD,CAAC;AAEjG;;;;;;;GAOG;AACH,wBAAgB,8BAA8B,CAC5C,MAAM,EAAE,MAAM,GAAG,IAAI,EACrB,YAAY,EAAE,OAAO,GACpB,MAAM,EAAE,CAaV"}
@@ -0,0 +1,57 @@
1
+ // PINNED-BY-BEGIN (generated by gen:pinned-by -- do not hand-edit; checked by lint:pinned-by)
2
+ // Pinned by: packages/daemon/src/completion/unclaimed-migration-notice-phase.test.ts,
3
+ // packages/daemon/src/spawn/migration-numbering-spawn.test.ts,
4
+ // packages/daemon/src/spawn/migration-numbering-wiring.test.ts
5
+ // PINNED-BY-END
6
+ /**
7
+ * What a team is told when its own branch holds a migration it never claimed.
8
+ *
9
+ * THIS IS A GUARD ON THE RULE, NOT DETECTION AIMED AT A MERGE. It names ONE
10
+ * team's OWN file to THAT team. It does not compare that file against a sibling
11
+ * branch, does not judge a merge, and does not tell two teams to renumber --
12
+ * the contest-notice shape was abandoned by direction (reverted on integration
13
+ * in 0c634616d) precisely because two teams recomputing "next free" from the
14
+ * same union at the same moment collide again.
15
+ *
16
+ * WHY THE TEAM AND NOT A HUMAN. The file was written by this team, and claiming
17
+ * the number or removing the file is something only this team can sensibly do.
18
+ * An escalation would be a row in a human queue that can only wait for the same
19
+ * team to act. So the fact is recorded as focus state and delivered here, at the
20
+ * next spawn, where the party who can act is already reading.
21
+ *
22
+ * WHY IT IS WORTH TELLING AT ALL. An allocator a team can bypass in silence is
23
+ * not an allocator. A file written without a claim is a number nobody knows is
24
+ * taken -- the next team to claim can be granted it, and then two migrations
25
+ * exist at one number with no claim record to explain either.
26
+ *
27
+ * Renders nothing when there is no record, and never on a review pass (a
28
+ * reviewer wrote no migrations).
29
+ *
30
+ * @module unclaimed-migration-section
31
+ */
32
+ /** The section's heading -- the anchor callers and tests name it by. */
33
+ export const UNCLAIMED_MIGRATION_HEADING = '# A MIGRATION ON THIS BRANCH HAS NO CLAIM BEHIND IT';
34
+ /**
35
+ * The unclaimed-file notice, as a block to append to a CODING message.
36
+ *
37
+ * @param record The stored focus_debug_artifacts content, or null when the
38
+ * focus has no such record. The stored prose is carried verbatim
39
+ * rather than re-rendered, so the team and a human reading the
40
+ * Debug tab see the identical account.
41
+ */
42
+ export function buildUnclaimedMigrationSection(record, isReviewPass) {
43
+ if (isReviewPass || !record || !record.trim())
44
+ return [];
45
+ return [
46
+ UNCLAIMED_MIGRATION_HEADING,
47
+ '',
48
+ record.trim(),
49
+ '',
50
+ 'Resolve it before this branch merges: claim the number',
51
+ '(`telora_product_migration { action: "claim", productId, focusId, tag }`) and rename',
52
+ 'the file to the number you are granted, or delete the file if it is not needed.',
53
+ 'Renaming to a number you picked yourself is not a resolution -- it is the same',
54
+ 'unclaimed number under a different digit.',
55
+ ];
56
+ }
57
+ //# sourceMappingURL=unclaimed-migration-section.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"unclaimed-migration-section.js","sourceRoot":"","sources":["../../src/prompt-sections/unclaimed-migration-section.ts"],"names":[],"mappings":"AAAA,8FAA8F;AAC9F,sFAAsF;AACtF,iEAAiE;AACjE,iEAAiE;AACjE,gBAAgB;AAEhB;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AAEH,wEAAwE;AACxE,MAAM,CAAC,MAAM,2BAA2B,GAAG,qDAAqD,CAAC;AAEjG;;;;;;;GAOG;AACH,MAAM,UAAU,8BAA8B,CAC5C,MAAqB,EACrB,YAAqB;IAErB,IAAI,YAAY,IAAI,CAAC,MAAM,IAAI,CAAC,MAAM,CAAC,IAAI,EAAE;QAAE,OAAO,EAAE,CAAC;IACzD,OAAO;QACL,2BAA2B;QAC3B,EAAE;QACF,MAAM,CAAC,IAAI,EAAE;QACb,EAAE;QACF,wDAAwD;QACxD,sFAAsF;QACtF,iFAAiF;QACjF,gFAAgF;QAChF,2CAA2C;KAC5C,CAAC;AACJ,CAAC"}
@@ -0,0 +1,19 @@
1
+ import type { callApi } from './shared.js';
2
+ import type { ClaimPassFocus } from '../focus/migration-claim-pass.js';
3
+ import type { ReleaseReason } from '../migrations/migration-claim-lifecycle.js';
4
+ /** Why this focus's claims should be released, or null while it is live. */
5
+ export declare function endedBecause(row: {
6
+ status?: string;
7
+ assignedAgentRoleId?: string | null;
8
+ }): ReleaseReason | null;
9
+ /**
10
+ * Every focus on the product, with its branch and its ended-reason.
11
+ *
12
+ * Focuses with no branch name are included and skipped by the pass: a focus
13
+ * that never got a branch holds no files, and a claim under it -- if any -- is
14
+ * released by its ended-reason like any other.
15
+ */
16
+ export declare function listClaimPassFocuses(productId: string, deps?: {
17
+ callApi?: typeof callApi;
18
+ }): Promise<ClaimPassFocus[]>;
19
+ //# sourceMappingURL=claim-pass-focuses.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"claim-pass-focuses.d.ts","sourceRoot":"","sources":["../../src/queries/claim-pass-focuses.ts"],"names":[],"mappings":"AAmCA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AAC3C,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,kCAAkC,CAAC;AACvE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,4CAA4C,CAAC;AAYhF,4EAA4E;AAC5E,wBAAgB,YAAY,CAAC,GAAG,EAAE;IAChC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,mBAAmB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CACrC,GAAG,aAAa,GAAG,IAAI,CAMvB;AAED;;;;;;GAMG;AACH,wBAAsB,oBAAoB,CACxC,SAAS,EAAE,MAAM,EACjB,IAAI,GAAE;IAAE,OAAO,CAAC,EAAE,OAAO,OAAO,CAAA;CAAO,GACtC,OAAO,CAAC,cAAc,EAAE,CAAC,CAmB3B"}