@tiphys/kernel 0.0.0 → 0.2.0

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 (207) hide show
  1. package/AGENTS.md +663 -0
  2. package/LICENSE +202 -0
  3. package/assurance-modes.yaml +299 -0
  4. package/checklists/clean-room.yaml +325 -0
  5. package/checklists/env-failure-diagnosis.yaml +68 -0
  6. package/checklists/flake-playbook.yaml +68 -0
  7. package/checklists/hazard-review.yaml +144 -0
  8. package/checklists/plan-review.yaml +103 -0
  9. package/dist/bin/tiphys.d.ts +2 -0
  10. package/dist/bin/tiphys.js +92 -0
  11. package/dist/src/adapters/load.d.ts +202 -0
  12. package/dist/src/adapters/load.js +440 -0
  13. package/dist/src/brief.d.ts +32 -0
  14. package/dist/src/brief.js +66 -0
  15. package/dist/src/checklists.d.ts +169 -0
  16. package/dist/src/checklists.js +310 -0
  17. package/dist/src/checks.d.ts +1539 -0
  18. package/dist/src/checks.js +5025 -0
  19. package/dist/src/cli.d.ts +9 -0
  20. package/dist/src/cli.js +68 -0
  21. package/dist/src/commands/brief.d.ts +92 -0
  22. package/dist/src/commands/brief.js +343 -0
  23. package/dist/src/commands/checklist.d.ts +42 -0
  24. package/dist/src/commands/checklist.js +168 -0
  25. package/dist/src/commands/cutover.d.ts +35 -0
  26. package/dist/src/commands/cutover.js +448 -0
  27. package/dist/src/commands/doctor.d.ts +264 -0
  28. package/dist/src/commands/doctor.js +1546 -0
  29. package/dist/src/commands/gates.d.ts +9 -0
  30. package/dist/src/commands/gates.js +360 -0
  31. package/dist/src/commands/init.d.ts +30 -0
  32. package/dist/src/commands/init.js +177 -0
  33. package/dist/src/commands/lock.d.ts +34 -0
  34. package/dist/src/commands/lock.js +340 -0
  35. package/dist/src/commands/mode.d.ts +40 -0
  36. package/dist/src/commands/mode.js +134 -0
  37. package/dist/src/commands/next.d.ts +130 -0
  38. package/dist/src/commands/next.js +597 -0
  39. package/dist/src/commands/plan.d.ts +20 -0
  40. package/dist/src/commands/plan.js +105 -0
  41. package/dist/src/commands/pool.d.ts +1 -0
  42. package/dist/src/commands/pool.js +139 -0
  43. package/dist/src/commands/resume.d.ts +1 -0
  44. package/dist/src/commands/resume.js +88 -0
  45. package/dist/src/commands/spawn.d.ts +1 -0
  46. package/dist/src/commands/spawn.js +195 -0
  47. package/dist/src/commands/status.d.ts +21 -0
  48. package/dist/src/commands/status.js +122 -0
  49. package/dist/src/commands/sync.d.ts +47 -0
  50. package/dist/src/commands/sync.js +341 -0
  51. package/dist/src/commands/teardown.d.ts +1 -0
  52. package/dist/src/commands/teardown.js +87 -0
  53. package/dist/src/commands/tuition.d.ts +21 -0
  54. package/dist/src/commands/tuition.js +218 -0
  55. package/dist/src/commands/validate.d.ts +78 -0
  56. package/dist/src/commands/validate.js +430 -0
  57. package/dist/src/commands/watch.d.ts +1 -0
  58. package/dist/src/commands/watch.js +172 -0
  59. package/dist/src/cutover.d.ts +584 -0
  60. package/dist/src/cutover.js +1444 -0
  61. package/dist/src/exclusion.d.ts +389 -0
  62. package/dist/src/exclusion.js +843 -0
  63. package/dist/src/exec/env.d.ts +278 -0
  64. package/dist/src/exec/env.js +334 -0
  65. package/dist/src/fleet.d.ts +223 -0
  66. package/dist/src/fleet.js +298 -0
  67. package/dist/src/gates/adapters/http-json.d.ts +5 -0
  68. package/dist/src/gates/adapters/http-json.js +283 -0
  69. package/dist/src/gates/adapters/migrations-command.d.ts +1 -0
  70. package/dist/src/gates/adapters/migrations-command.js +373 -0
  71. package/dist/src/gates/citations.d.ts +408 -0
  72. package/dist/src/gates/citations.js +1169 -0
  73. package/dist/src/gates/coverage.d.ts +375 -0
  74. package/dist/src/gates/coverage.js +836 -0
  75. package/dist/src/gates/credentials.d.ts +233 -0
  76. package/dist/src/gates/credentials.js +752 -0
  77. package/dist/src/gates/deploy.d.ts +1 -0
  78. package/dist/src/gates/deploy.js +33 -0
  79. package/dist/src/gates/gate-classes.d.ts +56 -0
  80. package/dist/src/gates/gate-classes.js +633 -0
  81. package/dist/src/gates/manifest.d.ts +99 -0
  82. package/dist/src/gates/manifest.js +208 -0
  83. package/dist/src/gates/merge-preconditions.d.ts +319 -0
  84. package/dist/src/gates/merge-preconditions.js +932 -0
  85. package/dist/src/gates/migrations.d.ts +1 -0
  86. package/dist/src/gates/migrations.js +36 -0
  87. package/dist/src/gates/pin.d.ts +114 -0
  88. package/dist/src/gates/pin.js +154 -0
  89. package/dist/src/gates/red-witness.d.ts +22 -0
  90. package/dist/src/gates/red-witness.js +482 -0
  91. package/dist/src/gates/release.d.ts +283 -0
  92. package/dist/src/gates/release.js +820 -0
  93. package/dist/src/gates/result.d.ts +116 -0
  94. package/dist/src/gates/result.js +91 -0
  95. package/dist/src/gates/run.d.ts +614 -0
  96. package/dist/src/gates/run.js +1614 -0
  97. package/dist/src/gates/schemas/citation-config.schema.json +59 -0
  98. package/dist/src/gates/schemas/coverage-config.schema.json +77 -0
  99. package/dist/src/gates/schemas/gate-manifest.schema.json +125 -0
  100. package/dist/src/gates/schemas/gate-result.schema.json +160 -0
  101. package/dist/src/gates/schemas/phase-declaration.schema.json +87 -0
  102. package/dist/src/gates/schemas/release-record.schema.json +119 -0
  103. package/dist/src/gates/schemas/verifier-config.schema.json +101 -0
  104. package/dist/src/gates/schemas/witness-spec.schema.json +110 -0
  105. package/dist/src/gates/scope.d.ts +131 -0
  106. package/dist/src/gates/scope.js +1018 -0
  107. package/dist/src/gates/suite.d.ts +217 -0
  108. package/dist/src/gates/suite.js +968 -0
  109. package/dist/src/gates/validate.d.ts +121 -0
  110. package/dist/src/gates/validate.js +414 -0
  111. package/dist/src/hooks.d.ts +84 -0
  112. package/dist/src/hooks.js +125 -0
  113. package/dist/src/index.d.ts +31 -0
  114. package/dist/src/index.js +30 -0
  115. package/dist/src/liveness.d.ts +321 -0
  116. package/dist/src/liveness.js +396 -0
  117. package/dist/src/lock.d.ts +256 -0
  118. package/dist/src/lock.js +792 -0
  119. package/dist/src/model-resolution.d.ts +159 -0
  120. package/dist/src/model-resolution.js +307 -0
  121. package/dist/src/modes.d.ts +149 -0
  122. package/dist/src/modes.js +258 -0
  123. package/dist/src/path-identity.d.ts +34 -0
  124. package/dist/src/path-identity.js +48 -0
  125. package/dist/src/plan.d.ts +73 -0
  126. package/dist/src/plan.js +153 -0
  127. package/dist/src/pool.d.ts +326 -0
  128. package/dist/src/pool.js +988 -0
  129. package/dist/src/roles.d.ts +461 -0
  130. package/dist/src/roles.js +776 -0
  131. package/dist/src/spawn.d.ts +482 -0
  132. package/dist/src/spawn.js +1003 -0
  133. package/dist/src/status.d.ts +116 -0
  134. package/dist/src/status.js +148 -0
  135. package/dist/src/task.d.ts +504 -0
  136. package/dist/src/task.js +307 -0
  137. package/dist/src/teardown.d.ts +39 -0
  138. package/dist/src/teardown.js +422 -0
  139. package/dist/src/tuition.d.ts +159 -0
  140. package/dist/src/tuition.js +311 -0
  141. package/dist/src/validate.d.ts +263 -0
  142. package/dist/src/validate.js +742 -0
  143. package/dist/src/version.d.ts +3 -0
  144. package/dist/src/version.js +38 -0
  145. package/dist/src/watcher.d.ts +275 -0
  146. package/dist/src/watcher.js +849 -0
  147. package/dist/src/witness/run.d.ts +299 -0
  148. package/dist/src/witness/run.js +1373 -0
  149. package/dist/src/witness/spec.d.ts +270 -0
  150. package/dist/src/witness/spec.js +475 -0
  151. package/dist/tsconfig.src.tsbuildinfo +1 -0
  152. package/gate-registry.yaml +526 -0
  153. package/gates.manifest.json +257 -0
  154. package/package.json +72 -3
  155. package/role-model-config.yaml +88 -0
  156. package/roles/README.md +128 -0
  157. package/roles/_shared-dispatch-contract.md +87 -0
  158. package/roles/adversarial-plan-reviewer.md +80 -0
  159. package/roles/clean-room-reviewer.md +140 -0
  160. package/roles/implementer.md +463 -0
  161. package/roles/investigator.md +138 -0
  162. package/roles/plan-writer.md +95 -0
  163. package/schemas/README.md +82 -0
  164. package/schemas/assurance-modes.schema.json +264 -0
  165. package/schemas/charter.schema.json +185 -0
  166. package/schemas/checklist.schema.json +114 -0
  167. package/schemas/cutover-state.schema.json +64 -0
  168. package/schemas/decision-record.schema.json +88 -0
  169. package/schemas/executor-record.schema.json +36 -0
  170. package/schemas/final-report.schema.json +90 -0
  171. package/schemas/finding.schema.json +106 -0
  172. package/schemas/gate-registry.schema.json +260 -0
  173. package/schemas/mechanism-index.schema.json +94 -0
  174. package/schemas/model-resolution.schema.json +362 -0
  175. package/schemas/plan.schema.json +300 -0
  176. package/schemas/report.schema.json +579 -0
  177. package/schemas/role-brief.schema.json +105 -0
  178. package/schemas/role-model-config.schema.json +90 -0
  179. package/schemas/status-line.schema.json +40 -0
  180. package/schemas/tuition.schema.json +191 -0
  181. package/schemas/verdict.schema.json +295 -0
  182. package/schemas/work-history.schema.json +183 -0
  183. package/schemas/write-bypass.schema.json +69 -0
  184. package/templates/charter.example.yaml +54 -0
  185. package/templates/decision-record.example.yaml +27 -0
  186. package/templates/final-report.example.yaml +80 -0
  187. package/templates/plan.example.yaml +87 -0
  188. package/templates/report.example.yaml +236 -0
  189. package/templates/warnings.md +74 -0
  190. package/templates/work-history.example.yaml +185 -0
  191. package/tuition/README.md +76 -0
  192. package/tuition/T-001.yaml +48 -0
  193. package/tuition/T-002.yaml +51 -0
  194. package/tuition/T-003.yaml +100 -0
  195. package/tuition/T-004.yaml +52 -0
  196. package/tuition/T-005.yaml +72 -0
  197. package/tuition/T-006.yaml +81 -0
  198. package/tuition/T-007.yaml +56 -0
  199. package/tuition/T-008.yaml +111 -0
  200. package/tuition/T-009.yaml +50 -0
  201. package/tuition/T-015.yaml +36 -0
  202. package/tuition/T-016.yaml +36 -0
  203. package/tuition/T-017.yaml +46 -0
  204. package/tuition/T-018.yaml +84 -0
  205. package/tuition/T-021.yaml +40 -0
  206. package/tuition/T-022.yaml +36 -0
  207. package/tuition/mechanism-index.yaml +256 -0
@@ -0,0 +1,326 @@
1
+ import type { Fleet } from "./fleet.ts";
2
+ /**
3
+ * Worktree pool over a project clone (kernel plan v1, M1-P3 step 3).
4
+ * BUILD from the contract (plan decision D-1, FM-026): a clean disposable
5
+ * worktree per task at <fleet>/worktrees/<task-id>, parallel-safe through
6
+ * unique paths, O_EXCL record creation, and git worktree add's own
7
+ * locking. That safety is claimed only at the width M1 actually uses:
8
+ * criterion 15's two concurrent creates, which are witnessed. This
9
+ * phase's own verification measured failures above roughly six-way
10
+ * concurrency on both the fetch and the worktree add, and hardening
11
+ * for that width is deferred to M5 (see the deferral list in
12
+ * delivery/work-history/m1-p3.md). Do not read this as a guarantee at
13
+ * arbitrary concurrency. Substrate-neutral: pure filesystem and git
14
+ * (DR-0007).
15
+ *
16
+ * Base resolution is the five binding steps of EXT-F-03: resolve the
17
+ * project's configured remote and its default branch, fetch that branch,
18
+ * record the fetched base SHA in the pool record (and the CLI emits it on
19
+ * stdout; M1-P4 spawn copies it into tasks/<id>/meta.json as baseSha),
20
+ * create the task branch and worktree directly from that exact SHA, and
21
+ * on fetch failure fail rather than silently use a stale local branch,
22
+ * unless --offline was explicitly passed, in which case the last fetched
23
+ * remote-tracking SHA is used and offline: true is recorded. The clone's
24
+ * local branches are never consulted: a stale local branch is never the
25
+ * base, whether behind or ahead of the remote.
26
+ *
27
+ * The pool record lives BESIDE the worktree (worktrees/<task-id>.pool.json,
28
+ * plain JSON per D-3), never inside it, so the record can never dirty the
29
+ * destroy-time cleanliness check (FM-059: no exemption list, ever).
30
+ *
31
+ * Destroy refuses a dirty worktree (uncommitted changes or untracked
32
+ * files) unless --discard, which is reserved for the teardown scout path
33
+ * (PR-010). A transient git index.lock during destroy is retried; the
34
+ * lock file is removed only under a fail-safe staleness proof (provably
35
+ * no holder via lsof plus mtime age beyond a threshold; any uncertainty
36
+ * means leave it and fail loudly), per FM-036 and FM-051.
37
+ */
38
+ /** Task branch created by the pool at the fetched base SHA. */
39
+ export declare function taskBranchName(taskId: string): string;
40
+ /** Task ids are single safe path segments. */
41
+ export declare const TASK_ID_PATTERN: RegExp;
42
+ export interface PoolRecord {
43
+ taskId: string;
44
+ project: string;
45
+ remote: string;
46
+ branch: string;
47
+ baseSha: string;
48
+ branchName: string;
49
+ offline: boolean;
50
+ createdAt: string;
51
+ }
52
+ export type PoolResult<T> = {
53
+ ok: true;
54
+ value: T;
55
+ } | {
56
+ ok: false;
57
+ reason: string;
58
+ };
59
+ /**
60
+ * THE BOUND ON A NETWORK-REACHING GIT SUBPROCESS (M4-P19 fix round).
61
+ *
62
+ * `spawnSync` with no `timeout` waits for the child forever. For a local
63
+ * git command that is harmless: it either answers or fails. For one that
64
+ * opens a socket it is not, and the failure mode is not a slow command,
65
+ * it is a command that NEVER RETURNS. Measured by the clean-room
66
+ * reviewer against head abde402: a remote pointed at a TCP listener that
67
+ * accepts and never speaks made `tiphys pool list` and `tiphys doctor`
68
+ * run until killed (exit 124 under `timeout 25`), where the same fixture
69
+ * on the phase base exited 0 in about a second.
70
+ *
71
+ * This bound is applied to `ls-remote --symref <remote> HEAD` only, and
72
+ * the reason it is safe THERE and not elsewhere is a property of the
73
+ * command rather than a judgement about it: that invocation transfers a
74
+ * ref advertisement and nothing else, so a legitimate one is bounded by
75
+ * round-trip latency. `git fetch` (src/pool.ts, src/teardown.ts) and
76
+ * `git push` (src/teardown.ts) transfer objects, so their legitimate
77
+ * duration IS unbounded and a wall-clock cap on them would abort real
78
+ * work. They are left unbounded deliberately, and they are reached only
79
+ * from a command the operator invoked to do that work, never from a
80
+ * reporting path; keeping reporting paths off the network entirely is
81
+ * the other half of this fix (see `reconstructPoolRecord`).
82
+ *
83
+ * TIPHYS_GIT_NETWORK_TIMEOUT_MS is a TEST SEAM in the style of
84
+ * TIPHYS_WATCH_TEST_HOLD (src/watcher.ts) and TIPHYS_LOCK_TEST_HOLD
85
+ * (src/commands/lock.ts): a test cannot afford to wait out the shipped
86
+ * bound, and a shipped bound short enough for a test would abort a
87
+ * legitimate ls-remote over a slow link. A value that is not a positive
88
+ * integer is IGNORED rather than honoured, so a malformed environment
89
+ * cannot silently remove the bound.
90
+ */
91
+ export declare const NETWORK_TIMEOUT_MS = 20000;
92
+ /**
93
+ * Exported as a PURE function so the validation has a witness that does
94
+ * not have to wait out a twenty-second bound to observe it. The
95
+ * end-to-end bound is witnessed separately, against a real remote that
96
+ * never answers; this is the arm that says a malformed environment
97
+ * cannot silently switch the bound off.
98
+ *
99
+ * `Number("")` is 0 and `Number("0x10")` is 16, so neither a blank value
100
+ * nor a hexadecimal one is passed through: the accepted set is exactly
101
+ * the positive integers, and everything else falls back.
102
+ */
103
+ export declare function resolveNetworkTimeoutMs(raw: string | undefined): number;
104
+ /** Exported for the contention-classification test. */
105
+ export declare function isTransientGitLockError(stderr: string): boolean;
106
+ export declare function recordPath(fleet: Fleet, taskId: string): string;
107
+ export declare function worktreePath(fleet: Fleet, taskId: string): string;
108
+ /**
109
+ * THE RECORD'S ENTRY TYPE IS ESTABLISHED BEFORE IT IS OPENED. A bare read
110
+ * here hung `tiphys pool destroy` forever with zero output against a named
111
+ * pipe at `worktrees/<id>.pool.json`; measured before the fix, `pool list`
112
+ * (which reads only the NAME) returned in the same second while
113
+ * `pool destroy --task t-0001` was killed at ten seconds. The two commands
114
+ * differ by whether this function runs, which is what makes the mechanism
115
+ * the open and not the command.
116
+ *
117
+ * A non-regular record is a REFUSAL rather than `undefined`: `undefined`
118
+ * already means "there is no record", and a caller that cannot tell that
119
+ * apart from "the record could not be opened" would rebuild a worktree over
120
+ * a record it never read.
121
+ */
122
+ export declare function readPoolRecord(fleet: Fleet, taskId: string): PoolRecord | undefined;
123
+ /**
124
+ * POST-RECLAIM RECONSTRUCTION (M4-D-12, kernel plan M4 section M4-P19).
125
+ *
126
+ * THE RULE, and it is the whole design: RECONSTRUCT FOR REPORTING, NEVER
127
+ * FOR DESTRUCTION. A reconstructed record exists in memory for the life
128
+ * of one command and is NEVER written to worktrees/<id>.pool.json, so a
129
+ * later reader can never mistake a reconstruction for an original.
130
+ *
131
+ * THE DEFECT IT CLOSES, measured rather than assumed. tasks/<id>/meta.json
132
+ * is TRACKED and survives a reclaim; worktrees/<id>.pool.json cannot,
133
+ * because it sits beside the worktree BY DESIGN so it can never dirty the
134
+ * destroy-time cleanliness check (see the module header above, FM-059).
135
+ * Teardown then refuses without a pool record and says so in terms
136
+ * (src/teardown.ts), so the plan's stated fallback of "recovery is manual
137
+ * teardown" does not work post-reclaim: the manual path is itself blocked.
138
+ *
139
+ * WHAT IS DERIVED AND WHAT IS NOT. meta.json carries six of the eight
140
+ * PoolRecord fields directly (taskId, project, baseSha, branchName,
141
+ * offline, createdAt). It carries NEITHER `remote` NOR `branch`, which are
142
+ * the project's configured remote and that remote's default branch. Those
143
+ * two are re-derived from git through the SAME two resolvers poolCreate
144
+ * uses, so a reconstruction is a repeat of the original derivation and
145
+ * never a remembered value.
146
+ *
147
+ * WHEN EITHER OF THOSE TWO CANNOT BE DERIVED THE RESULT IS INCOMPLETE AND
148
+ * NAMES THE FIELD. It is never filled with a plausible default. "origin"
149
+ * and "main" are right often enough to look harmless and wrong often
150
+ * enough to destroy work: a guessed default branch sends the landed-ness
151
+ * judgement at a ref that is not the project's default, and teardown's
152
+ * authorization to delete a task branch comes from exactly that judgement
153
+ * (V-1, the defect src/spawn.ts was rewritten to prevent). An unresolvable
154
+ * field is therefore a refusal, not a gap to fill.
155
+ */
156
+ export type ReconstructResult =
157
+ /** Every field derived. Safe to report, and safe to pass to a GATED path. */
158
+ {
159
+ kind: "complete";
160
+ record: PoolRecord;
161
+ }
162
+ /** meta.json read, but git could not answer for the named fields. */
163
+ | {
164
+ kind: "incomplete";
165
+ unresolved: string[];
166
+ detail: string;
167
+ }
168
+ /** No readable task meta, so there is nothing to reconstruct from. */
169
+ | {
170
+ kind: "absent";
171
+ reason: string;
172
+ };
173
+ /**
174
+ * What a caller of `reconstructPoolRecord` is permitted to do to answer.
175
+ *
176
+ * THE FIELD IS REQUIRED AND THE TYPE IS WHY (M4-P19 fix round). The
177
+ * reconstruction rebuilds `branch` through `resolveDefaultBranch`, which
178
+ * falls back to `git ls-remote` when `<remote>/HEAD` is unset locally,
179
+ * and that fallback opens a socket. `<remote>/HEAD` unset is not an
180
+ * exotic state: it is the NORMAL state of a clone made by `git init` +
181
+ * `git remote add` + `git fetch`, which is how this kernel's own tests
182
+ * and fixtures build one. So the fallback is reached on ordinary fleets,
183
+ * and a caller that must return, such as `pool list` or `doctor`, must
184
+ * not reach it.
185
+ *
186
+ * Measured against head abde402, where this option did not exist and
187
+ * every caller got the network: with the remote pointed at a TCP
188
+ * listener that accepts and never speaks, `tiphys pool list` and
189
+ * `tiphys doctor` ran until killed. Making the decision a required field
190
+ * rather than a defaulted one is the part of the fix that survives the
191
+ * next caller: adding one without choosing does not compile.
192
+ */
193
+ export interface ReconstructOptions {
194
+ /**
195
+ * True only for a caller the operator invoked to CHANGE something and
196
+ * which may therefore wait on a remote. False for every reporting
197
+ * path, which then reports `unreconstructable (unresolved: branch)`
198
+ * rather than blocking.
199
+ */
200
+ network: boolean;
201
+ }
202
+ /**
203
+ * Rebuild a pool record for taskId from tasks/<id>/meta.json and git.
204
+ * Reads only; writes nothing anywhere, ever.
205
+ */
206
+ export declare function reconstructPoolRecord(fleet: Fleet, taskId: string, options: ReconstructOptions): ReconstructResult;
207
+ export interface CreateOptions {
208
+ taskId: string;
209
+ project: string;
210
+ offline: boolean;
211
+ }
212
+ /**
213
+ * pool create (EXT-F-03 five steps; see module doc). Returns the pool
214
+ * record on success.
215
+ *
216
+ * On failure NOTHING IS REMOVED. The pool record, the worktree
217
+ * directory and the task branch may each survive, depending on how far
218
+ * the attempt got, and the reason line names exactly which of them did
219
+ * and the command that clears them. The automatic rollback this
220
+ * docstring used to promise was deleted deliberately: it served a
221
+ * concurrent-create path M1 never enters (parallelism is off until M5)
222
+ * and produced four consecutive rounds of defects, including deleting
223
+ * state it had not validated. Failing loudly and leaving state is the
224
+ * chosen contract, not an oversight.
225
+ */
226
+ export declare function poolCreate(fleet: Fleet, options: CreateOptions): Promise<PoolResult<PoolRecord>>;
227
+ /**
228
+ * Where an entry's pool record came from. `record` is an original read
229
+ * from worktrees/<id>.pool.json; the other two exist only after a reclaim
230
+ * has taken worktrees/ with it, and are computed fresh on every call.
231
+ */
232
+ export type PoolEntryOrigin = "record" | "reconstructed" | "unreconstructable";
233
+ export interface PoolListEntry {
234
+ taskId: string;
235
+ headSha: string;
236
+ origin: PoolEntryOrigin;
237
+ /**
238
+ * Set only for `unreconstructable`: what this listing could not establish.
239
+ * Usually the PoolRecord fields git could not answer for; `meta` means the
240
+ * task record itself was present and did not read, which is a different
241
+ * state from a task that is closed and from one that is not there.
242
+ */
243
+ unresolved?: string[];
244
+ }
245
+ /**
246
+ * One entry per pool record, with the worktree's current HEAD SHA, PLUS
247
+ * one per OPEN task that has no pool record beside it (M4-P19).
248
+ *
249
+ * The second group is what a reclaim leaves behind: tasks/ is tracked and
250
+ * survives, worktrees/ is gitignored and does not, so a task can be open
251
+ * with its record gone. Reporting only the first group makes those tasks
252
+ * invisible to `pool list` and to doctor, which is the state the plan
253
+ * calls a defect. Every such entry is marked, never silently blended in
254
+ * with the originals, and NOTHING here is written to disk.
255
+ *
256
+ * Closed tasks are excluded: a closed task is not in the pool, and
257
+ * listing every task this fleet ever finished as a missing worktree would
258
+ * make the report useless within a week.
259
+ *
260
+ * THIS FUNCTION OPENS NO SOCKET (M4-P19 fix round). It reads the
261
+ * filesystem and runs local git commands, and its reconstruction is
262
+ * asked for with `{ network: false }`. An entry whose default branch
263
+ * cannot be established from the clone alone is reported
264
+ * `unreconstructable (unresolved: branch)` rather than waited on. See
265
+ * `ReconstructOptions` for the measured hang that this closes.
266
+ */
267
+ export declare function poolList(fleet: Fleet): PoolListEntry[];
268
+ export interface LsofProbe {
269
+ available: boolean;
270
+ exitCode: number | null;
271
+ stdout: string;
272
+ }
273
+ /** Age a lock file must reach before a staleness proof is even considered. */
274
+ export declare const STALE_LOCK_AGE_MS = 300000;
275
+ /**
276
+ * Fail-safe staleness proof for a git lock file (FM-036, FM-051): true
277
+ * only when the lock exists, its mtime age exceeds the threshold, and
278
+ * lsof is available and shows provably no holder (exit 1, empty stdout).
279
+ * Any uncertainty (lsof missing, erroring, or listing holders) is false:
280
+ * the lock is left in place and the operation fails loudly.
281
+ */
282
+ export declare function provablyStaleLock(lockFile: string, opts?: {
283
+ nowMs?: number;
284
+ ageThresholdMs?: number;
285
+ runLsof?: (path: string) => LsofProbe;
286
+ }): boolean;
287
+ export interface DestroyOptions {
288
+ taskId: string;
289
+ /** Override the dirty-worktree refusal (plan step 3, PR-010). */
290
+ discard: boolean;
291
+ /**
292
+ * Authorize deleting a task branch that carries commits beyond its
293
+ * recorded base (V-1). Deliberately distinct from discard, whose
294
+ * plan-defined meaning is the dirty-tree override only: conflating
295
+ * them would make the scout path silently destroy committed work.
296
+ * M1-P4 teardown passes this from its ship path after its landedness
297
+ * judgement, which makes the dependency on teardown explicit rather
298
+ * than assumed.
299
+ */
300
+ deleteBranchForce: boolean;
301
+ /**
302
+ * An IN-MEMORY reconstructed record (M4-P19), used ONLY when no record
303
+ * exists on disk. It is never written: `haveRecord` still comes from
304
+ * the file, so nothing here creates worktrees/<id>.pool.json and
305
+ * nothing unlinks a file that is not there.
306
+ *
307
+ * WHY THIS EXISTS AT ALL, since the whole design is "never for
308
+ * destruction". Without it, stage 2's base-sha gate has no base to
309
+ * compare against and returns its "pool record missing or unreadable"
310
+ * refusal, so the post-reclaim path would be blocked at the one gate
311
+ * that was ALREADY going to do the right thing. Passing the
312
+ * reconstruction in makes that gate WORK rather than abstain, which is
313
+ * strictly safer than the alternative of relaxing it. The caller is
314
+ * responsible for having derived it (src/teardown.ts's
315
+ * --from-reconstructed path is the only one), and `pool destroy` on
316
+ * the command line never sets it.
317
+ */
318
+ reconstructed?: PoolRecord;
319
+ }
320
+ /** What a completed destroy removed, for the operator's record. */
321
+ export interface DestroyOutcome {
322
+ deletedBranch?: string;
323
+ /** The branch tip at deletion time: the recovery handle (V-1). */
324
+ deletedSha?: string;
325
+ }
326
+ export declare function poolDestroy(fleet: Fleet, options: DestroyOptions): Promise<PoolResult<DestroyOutcome>>;