@bluewombat/conductor 0.8.0 → 0.9.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.
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # Conductor
2
2
 
3
- Kernel package, not a Transformer: sequences Transformers for one FeatureStandard. It
3
+ Kernel package, not a Transformer: sequences Transformers for one TicketStandard. It
4
4
  writes the WorkLedger before it acts. Isolated workspaces are a consequence of
5
5
  that state.
6
6
 
@@ -30,9 +30,9 @@ npm install
30
30
  | Build | `npm run build` |
31
31
 
32
32
  There is no CLI in this implementation. The caller injects a WorkLedger and a
33
- Transformer Port (Isolation, Breakdown, Implementer, Integration).
33
+ Transformer Port (Isolation, Implementer, Integration).
34
34
 
35
- **Optional Authority.** When injected, Conductor offers the assembled feature
35
+ **Optional Authority.** When injected, Conductor offers the assembled ticket
36
36
  and does not fold it into WorkLineStable itself. See [SPECS.md](./SPECS.md) §8.
37
37
 
38
38
  ```ts
package/SPECS.md CHANGED
@@ -1,10 +1,10 @@
1
1
  # Conductor
2
2
 
3
3
  Not a Transformer. It has many operations, not one IN and one OUT.
4
- It sequences other people's jobs: WorkLedger commands, Isolation, Breakdown,
5
- Implementer, Integration. It does not store FeatureStandards, does not isolate a
6
- directory, does not split a Plan, does not run a Builder, does not fold a Child,
7
- and does not report to a FeatureManager.
4
+ It sequences other people's jobs: WorkLedger commands, Isolation, Implementer,
5
+ Integration. It does not store TicketStandards, does not isolate a directory,
6
+ does not run a Builder, does not fold a Child, and does not report to a
7
+ TicketTracker.
8
8
 
9
9
  Conductor writes the WorkLedger **before** it acts. Isolated workspaces are a
10
10
  consequence of that state, never the source of it.
@@ -15,7 +15,7 @@ consequence of that state, never the source of it.
15
15
  caller Conductor others
16
16
  ------ --------- ------
17
17
  run a Project check pause, reconcile WorkLedger
18
- claim or resume isolate / breakDown
18
+ claim or resume isolate
19
19
  write ledger, then act implement / integrate
20
20
  ← idle | done | escalated | paused | refused
21
21
  ```
@@ -35,9 +35,9 @@ same functions.
35
35
  | Import | `openConductor({ ledger, transformers, workLineStable, workspaceRoot })` | Import a Transformer package from `src/run/` |
36
36
  | Transformers | A value that implements the Transformer Port | Live under `src/run/` as a concrete Transformer import |
37
37
 
38
- The caller builds the transformers (`runIsolator`, `runBreakdown`, `runImplementer`,
39
- `runIntegrator`, closed over Planner / Builder / Gate argv) and passes them in.
40
- Conductor does not import `@bluewombat/isolator` (or the other three) from its
38
+ The caller builds the transformers (`runIsolator`, `runImplementer`,
39
+ `runIntegrator`, closed over Builder / Gate argv) and passes them in.
40
+ Conductor does not import `@bluewombat/isolator` (or the other two) from its
41
41
  run loop. The composition root that wires Transformers is the caller — Host
42
42
  (`packages/host/runtime`) — or a later thin adapter in this package.
43
43
 
@@ -51,15 +51,15 @@ Transformers do not import this package. WorkLedger does not import this package
51
51
  │
52
52
  │ Transformer Port + WorkLedger
53
53
  ▼
54
- transformers / ledger injected Isolation, Breakdown, Attempts,
54
+ transformers / ledger injected Isolation, Attempts,
55
55
  Integration, durable state
56
56
  ```
57
57
 
58
58
  | Layer | Owns | Does not own |
59
59
  | ------------ | ----------------------------------------------------------- | ------------------------------------------------ |
60
- | Conductor | Order of steps, pause, orphan destroy, when to call whom | FeatureStandard transitions, git, Builder, Gates |
61
- | Ledger | Legal transitions, bail, Plan freeze | Directories, Transformer outcomes |
62
- | Transformers | One Isolation / Breakdown / Attempt loop / Integration each | WorkLedger commands, pause, claim |
60
+ | Conductor | Order of steps, pause, orphan destroy, when to call whom | TicketStandard transitions, git, Builder, Gates |
61
+ | Ledger | Legal transitions, bail | Directories, Transformer outcomes |
62
+ | Transformers | One Isolation / Attempt loop / Integration each | WorkLedger commands, pause, claim |
63
63
 
64
64
  A caller never talks to Isolator through Conductor internals. It talks to
65
65
  `runProject`. The run loop never talks to `node:child_process`. It talks to
@@ -72,8 +72,7 @@ orphan destroy). It does not copy, merge, or create a workspace.
72
72
  Hard rules. Breaking one is a spec bug, not a refactor.
73
73
 
74
74
  1. **`src/run/` does not import a Transformer package** (`@bluewombat/isolator`,
75
- `@bluewombat/implementer`, `@bluewombat/integrator`,
76
- `@bluewombat/feature-breakdown`). It imports the Transformer Port type and
75
+ `@bluewombat/implementer`, `@bluewombat/integrator`). It imports the Transformer Port type and
77
76
  WorkLedger types. A test that fails if `run` grows those imports is part of
78
77
  this contract.
79
78
  2. **`src/run/` does not import `work-ledger` persistence adapters.** It talks
@@ -82,29 +81,21 @@ Hard rules. Breaking one is a spec bug, not a refactor.
82
81
  4. **Domain tests inject a Transformer Port and a WorkLedger.** They may use a
83
82
  test-double ledger (in the test file) and fake transformers that record call order.
84
83
  They do not require a Transformer `dist/`.
85
- 5. **The caller, not Conductor, chooses Planner / Builder / Gate argv.** Those
84
+ 5. **The caller, not Conductor, chooses Builder / Gate argv.** Those
86
85
  slots close over the transformer functions.
87
86
 
88
87
  ## 5. Transformer Port
89
88
 
90
- Four operations. Real Transformers or test doubles; the Port does not care.
89
+ Three operations. Real Transformers or test doubles; the Port does not care.
91
90
 
92
91
  | Operation | In (minimum) | Out (minimum) |
93
92
  | ----------- | ------------------------------------------------------------------------------------------------------------------ | --------------------------------------------------------------------------------------------------- |
94
93
  | `isolate` | `id`, `parent`, `child` (absolute paths), `durationMs` | `isolated` / `failed` / `invalid-invocation` / `interrupted` |
95
- | `breakDown` | FeatureStandard JSON (key, intention, optional title) | `planned` + subtasks + `planned_at`, or `refused` + code + reason, or `unavailable` / `interrupted` |
96
- | `implement` | `id`, intention, `workspace`, durations / attempt bound, optional definition of done, `report`, `stage`, `produce` | `validated` / `escalated` / `interrupted` / `invalid-invocation`, plus ordered Traces |
94
+ | `implement` | `id`, intention, `workspace`, durations / attempt bound, `report`, `stage`, `produce` | `validated` / `escalated` / `interrupted` / `invalid-invocation`, plus ordered Traces |
97
95
  | `integrate` | `id`, `parent`, `child`, `durationMs` | `integrated` / `conflict` / `failed` / `invalid-invocation` / `interrupted` |
98
96
 
99
- Conductor maps ledger fields into `breakDown` JSON. It does not reopen
100
- FeatureAdapter's closed shape. Recognised keys are `key`, `intention`, `title`.
101
-
102
- A Subtask carries the `definition_of_done` its Plan gave it. An assembly carries
103
- none: what it must meet is the Subtasks it is made of, and each was judged on its
104
- own.
105
-
106
- `stage` says what is being judged — one unit of work, or the feature they
107
- assemble into. They are not the same situation: a check that is right for one can
97
+ `stage` says what is being judged — the unit of work, or the work once
98
+ assembled. They are not the same situation: a check that is right for one can
108
99
  be wrong for the other. `produce` says whether the Task may make anything: a
109
100
  stage built only of already-validated work has nothing to make, and asking a
110
101
  producer to run there is how a correct result gets rewritten so a check expecting
@@ -121,7 +112,7 @@ whatever refused it — the first Gate that did not pass, or the producer's own
121
112
  detail. `ended` says an Attempt failed; `report` says why, and whoever drives the
122
113
  next one cannot invent it.
123
114
 
124
- `implement` Traces are Implementer's Traces. Conductor records each Subtask
115
+ `implement` Traces are Implementer's Traces. Conductor records each unit
125
116
  Trace as a WorkLedger Attempt (`ended`, and `report` / `refusedBy` when the
126
117
  Attempt did not end well) before it decides escalate vs integrate.
127
118
 
@@ -129,9 +120,9 @@ Attempt did not end well) before it decides escalate vs integrate.
129
120
  They are not required by the Port's outcome.
130
121
 
131
122
  An optional **Authority Port** (`submit` / `fold`) is not a transformer. When the
132
- caller injects one, an assembled feature is offered outside instead of being
123
+ caller injects one, an assembled ticket is offered outside instead of being
133
124
  folded into WorkLineStable by Integrator. `workLineTarget` names that work line
134
- for the Authority. `maxRefusals` (default 3) is how many times the Authority's
125
+ for the Authority; a Ticket that names its own `line` is offered to that one. `maxRefusals` (default 3) is how many times the Authority's
135
126
  Gates may send the work back before Conductor escalates.
136
127
 
137
128
  ## 6. Paths
@@ -142,20 +133,18 @@ assemblyValidate?, assemblyFixDeclared?, observe? })`. `assemblyValidate` says
142
133
  whether a local judge runs after align, with or without an Authority.
143
134
  `assemblyFixDeclared` says whether a refusal has anything to repair it with; a
144
135
  validate refusal escalates on the spot when it does not.
145
- `observe` is told, mid-pass, when the plan is recorded, when a Subtask is
146
- integrated (with the count), and when the work is submitted — awaited, and a
147
- throw from it changes nothing about the run.
136
+ `observe` is told, mid-pass, when the work is submitted — awaited, and a throw
137
+ from it changes nothing about the run.
148
138
  `workLineStable` and `workspaceRoot` are absolute directories. `workspaceRoot`
149
139
  must not be `workLineStable`. Conductor does not create `workLineStable`.
150
140
 
151
141
  Physical layout is this package's private choice:
152
142
 
153
143
  ```
154
- <workspaceRoot>/<key-segment>/feature
155
- <workspaceRoot>/<key-segment>/subtask-<id-segment>
144
+ <workspaceRoot>/<key-segment>/ticket
156
145
  ```
157
146
 
158
- `<key-segment>` and `<id-segment>` are one safe path segment each: a name made
147
+ `<key-segment>` is one safe path segment: a name made
159
148
  of letters, digits, `.`, `_` and `-` is kept as it is; anything else becomes a
160
149
  readable slug plus the first 8 hex digits of the SHA-256 of the original, so
161
150
  `github:tilap/site#1` is `github-tilap-site-1-<hash>` and two keys never share a
@@ -163,18 +152,14 @@ directory. There is no `%`: a workspace is where the Builder runs the
163
152
  project's own tools, and several (Vitest among them) refuse a path that looks
164
153
  URL-encoded. Conductor never uses the raw key as a directory name.
165
154
 
166
- **A declared path is the path.** Every step that needs the feature's workspace
167
- reads the one the WorkLedger declared for it and computes the layout's own only
168
- when none is declared, so a feature made under an earlier layout — escalated,
169
- then resumed — keeps its work and its branch where they are. A kept Subtask at
170
- an older path is destroyed with the one at the current path when it starts
171
- over, so its branch is free to be taken again. The Authority is handed the
172
- feature's workspace in `submit` (`workspace`), and works out nothing itself.
155
+ **A declared path is the path.** Every step that needs the workspace reads the
156
+ one the WorkLedger declared for it and computes the layout's own only when none
157
+ is declared. A unit that starts over destroys what is at that path first, so
158
+ its branch is free to be taken again. The Authority is handed the workspace in
159
+ `submit` (`workspace`), and works out nothing itself.
173
160
 
174
161
  It **declares** that path on the WorkLedger, **then** calls `isolate`. After
175
- `integrate` of a Subtask returns `integrated`, it deletes the Subtask directory
176
- and `clearWorkspace` for the Subtask. After `markDone`, it deletes the feature
177
- directory and `clearWorkspace` for the feature.
162
+ `markDone`, it deletes the directory and `clearWorkspace`.
178
163
 
179
164
  ## 7. Commands
180
165
 
@@ -184,97 +169,92 @@ command does not start a Transformer.
184
169
 
185
170
  | Command | Meaning | Refused when |
186
171
  | ------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------- |
187
- | `reconcile` | `expireBail` on expired keys. Destroy directories under `workspaceRoot` that are not on `listDeclaredWorkspaces`. Delete declared Subtask dirs after expiry. | Paths not absolute (constructor already threw) |
188
- | `pause` | In-process flag: no new `claim`, no new `startSubtask`, no `markMerging` / final fold into WorkLineStable. Current `implement` / `isolate` / `integrate` may finish | — |
172
+ | `reconcile` | `expireBail` on expired keys. Destroy directories under `workspaceRoot` that are not on `listDeclaredWorkspaces`. Delete the declared directory of a unit whose lease expired. | Paths not absolute (constructor already threw) |
173
+ | `pause` | In-process flag: no new `claim`, no new unit start, no `markMerging` / final fold into WorkLineStable. Current `implement` / `isolate` / `integrate` may finish | — |
189
174
  | `resume` | Clear the pause flag. Does not itself take work | — |
190
- | `runProject` | Reconcile, then take or resume the active FeatureStandard on that Project, and drive it until a terminal or wait state | `workLineStable` missing on disk |
175
+ | `runProject` | Reconcile, then take or resume the active TicketStandard on that Project, and drive it until a terminal or wait state | `workLineStable` missing on disk |
191
176
  | `cancel` | `ledger.cancel(key)` then destroy declared workspaces for that key | Ledger `point-of-no-return` |
192
- | `release` | `ledger.releaseBail(key)` then destroy the declared Subtask directory when one was recorded | Ledger `illegal-transition` / `not-found` |
177
+ | `release` | `ledger.releaseBail(key)` then destroy the declared directory when one was recorded | Ledger `illegal-transition` / `not-found` |
193
178
 
194
179
  `runProject` outcomes:
195
180
 
196
181
  | Outcome | Meaning |
197
182
  | ----------- | --------------------------------------------------------------------------------------------- |
198
- | `idle` | No `received` FeatureStandard and no active one on that Project |
199
- | `done` | The FeatureStandard is `done` in WorkLineStable |
200
- | `escalated` | Frozen for a human. Isolated Subtask workspace kept when a Subtask was in play |
183
+ | `idle` | No `received` TicketStandard and no active one on that Project |
184
+ | `done` | The TicketStandard is `done` in WorkLineStable |
185
+ | `escalated` | Frozen for a human. The workspace is kept for inspection |
201
186
  | `paused` | Stopped at a pause boundary. Ledger holds the current state |
202
187
  | `refused` | Constructor-level or ledger refusal the loop cannot handle (`persist-failed`, missing stable) |
203
188
 
204
- `runProject` does **not** wait for a human `ready`. After `escalated`, the
205
- caller (FeatureManager path) calls `ledger.resumeReady(key)` then `runProject`
189
+ `runProject` does **not** wait for a human `resume`. After `escalated`, the
190
+ caller (TicketTracker path) calls `ledger.resumeTicket(key)` then `runProject`
206
191
  again.
207
192
 
208
193
  ## 8. Happy path (ledger before act)
209
194
 
210
- One FeatureStandard, one Project. Pause flag is off.
195
+ One TicketStandard, one Project. Pause flag is off.
211
196
 
212
197
  1. `reconcile`.
213
- 2. If the Project already has an active FeatureStandard, resume it. Else `claim`.
198
+ 2. If the Project already has an active TicketStandard, resume it. Else `claim`.
214
199
  Empty → `idle`.
215
- 3. **Planning.** `breakDown`. On `planned`: `recordPlan` **before** any Isolation.
216
- On `refused`: `refusePlan`, return `escalated`. On `unavailable`: return
217
- `refused` with code `unavailable` (ledger stays `planning`; retryable). On
218
- `interrupted`: return `refused` with code `interrupted`. On
219
- `invalid-invocation`: return `refused` with code `transformer-invalid`.
220
- 4. **Feature workspace.** `declareWorkspace({ feature })` **then** `isolate`
221
- (parent = WorkLineStable, child = feature path). Failure: do not start
222
- Subtasks; `runProject` returns `refused` (`isolate-failed` or `transformer-invalid`)
223
- and leaves the ledger in `running` so a retry isolates again if the directory
224
- is missing. If a Submission is already recorded and the feature directory is
225
- gone, Conductor escalates `kind: "submitted"` rather than isolating again
226
- over what the Authority was shown. When a `warm` port is configured, prepare
227
- the Feature workspace next (install deps, …) before any Subtask Isolation —
228
- once per Feature in this Conductor instance, and again after a fresh
229
- Isolation. Failure: `refused` with `warm-failed` (or `interrupted` /
230
- `transformer-invalid`); the Feature directory is kept so the next
231
- `runProject` retries warm without re-isolating.
232
- 5. **Subtask loop** while `nextRunnable` is a Subtask and pause is off:
233
- 1. `startSubtask`.
234
- 2. `declareWorkspace({ subtask })` **then** `isolate` (parent = feature path).
235
- 3. `implement` in that child.
236
- 4. For each Trace, `recordAttempt` with the next number and that Trace's
200
+ 3. **The unit.** When the ledger is `running`, no lease is held and pause is
201
+ off: destroy what is at the workspace path, `declareWorkspace` **then**
202
+ `isolate` (parent = WorkLineStable, child = the workspace). Failure: no
203
+ lease was taken, so `runProject` returns `refused` (`isolate-failed` or
204
+ `transformer-invalid`) and a retry starts the unit again. When a `warm` port
205
+ is configured, prepare the workspace next (install deps, …) — each time the
206
+ workspace is made. Failure: `refused` with `warm-failed` (or `interrupted` /
207
+ `transformer-invalid`). Then `startUnit` (the lease) and `implement` in that
208
+ workspace.
209
+ 1. For each Trace, `recordAttempt` with the next number and that Trace's
237
210
  `ended`, plus `report` / `refusedBy` when present.
238
- 5. `validated` → `integrate` child into feature. `integrated` →
239
- `markSubtaskIntegrated`, delete child, `clearWorkspace` subtask.
240
- `conflict` → `escalate({ kind: "subtask", subtaskId })`, **keep** the child.
241
- 6. `escalated` from Implementer → `escalate({ kind: "subtask", subtaskId })`
242
- (Trace already recorded). Keep the child. The next `startSubtask` for
243
- that id **destroys** the kept Child first (resume from zero).
244
- 7. After a Subtask is marked integrated, if `pending_fingerprint` is set,
245
- `escalate({ kind: "plan" })` with a report that says the intention was
246
- edited in flight and what resume does — not that a Plan was refused,
247
- which is what `kind: "plan"` reads as without it. The ledger consumes
248
- the pending field. Resume of `kind: "plan"` unfreezes the Plan
249
- (`resumeReady`). A newer FeatureStandard body lands by `admit` of the
250
- corrected document (from `escalated` → `received`).
211
+ 2. `validated` → `markIntegrating`. The result stays loose in the
212
+ workspace; the Integration in 4.3 takes it up.
213
+ 3. `escalated` from Implementer → `escalate({ kind: "unit" })` (Trace
214
+ already recorded). Keep the workspace. `resumeTicket` returns the
215
+ Ticket to `running`, and the unit starts again from zero.
216
+ 4. After `markIntegrating`, if `pending_fingerprint` is set,
217
+ `escalate({ kind: "unit" })` with a report that says the intention was
218
+ edited in flight and what resume does. The ledger consumes the pending
219
+ field. A newer TicketStandard body lands by `admit` of the corrected
220
+ document (from `escalated` → `received`).
221
+ A `running` Ticket that holds a lease is `paused`: its lease runs out on
222
+ its own when nobody is on it.
223
+ 4. **The workspace must still be there** from `integrating` on. When it is
224
+ gone, Conductor does not make it again from the work line, which would drop
225
+ what was made: it escalates `kind: "submitted"` when the Authority holds a
226
+ Submission, `kind: "assembly"` otherwise.
227
+ 5. Pause is honoured before the unit starts, after Isolation, before align and
228
+ before `markMerging`.
251
229
  6. When the ledger is `integrating` and pause is off:
252
- 1. If `pending_fingerprint` is set, escalate `kind: "plan"` as in 5.7 and
230
+ 1. If `pending_fingerprint` is set, escalate `kind: "unit"` as in 3.4 and
253
231
  stop. Do not align.
254
232
  2. If a parked refusal or a Submission `last_report` is set (the parked one
255
- wins when both are), `implement` on the feature workspace with
233
+ wins when both are), `implement` on the ticket workspace with
256
234
  `stage: "assembly"`, `produce: true`, and that report **before** align.
257
235
  `escalated` → `escalate({ kind: "assembly" })`.
258
- 3. **Align.** `integrate` with WorkLineStable as **child** and the feature
259
- workspace as **parent**. `conflict` → return `refused` (`align-conflict`);
236
+ 3. **Align.** `integrate` with WorkLineStable as **child** and the
237
+ workspace as **parent**. What is loose in the workspace is first taken up
238
+ as one commit whose subject is the Ticket's title (or its intention's
239
+ headline); after a refusal it is the repair, with its own subject. `conflict` → return `refused` (`align-conflict`);
260
240
  state stays `integrating`. Cancel is still allowed. Retry `runProject`
261
241
  retries align. Do not `escalate({ kind: "merging" })` here: that would set
262
242
  `born_in_merging` and block cancel before WorkLineStable is the fold parent.
263
243
  4. **Validate**, when `assemblyValidate` is set — with or without an
264
- Authority. `implement` on the feature workspace with `stage: "assembly"`
244
+ Authority. `implement` on the ticket workspace with `stage: "assembly"`
265
245
  and `validate: true` (no gates, one attempt). `validated` →
266
246
  `clearParkedRefusal`, then continue to 5 or 6. `escalated`, retryable,
267
247
  under `maxRefusals` (the budget shared with `submission.refusals`), and
268
248
  `assemblyFixDeclared` → `recordParkedRefusal`, return `paused`. Do not
269
249
  continue to 5 or 6. `escalated` otherwise (blocking, at the budget, or no
270
250
  `assembly.fix` declared) → `escalate({ kind: "assembly" })`.
271
- 5. **Without an Authority.** `implement` on the feature workspace with
251
+ 5. **Without an Authority.** `implement` on the ticket workspace with
272
252
  `stage: "assembly"` and `produce: false` (judgement only). `validated` →
273
253
  `markMerging`. `escalated` → `escalate({ kind: "assembly" })`.
274
- Then **final fold**: `integrate` feature child into WorkLineStable.
275
- `integrated` → `markDone`, delete feature directory, `clearWorkspace`.
276
- `conflict` → `escalate({ kind: "merging" })`, keep the feature directory.
277
- 6. **With an Authority.** `submit` the assembled feature. `submitted` →
254
+ Then **final fold**: `integrate` ticket child into WorkLineStable.
255
+ `integrated` → `markDone`, delete ticket directory, `clearWorkspace`.
256
+ `conflict` → `escalate({ kind: "merging" })`, keep the ticket directory.
257
+ 6. **With an Authority.** `submit` the assembled ticket. `submitted` →
278
258
  `markSubmitted`, return `paused`. `refused` → `escalate({ kind: "submitted" })`
279
259
  with the refusal's reason as its report — the Publisher's or the
280
260
  Authority's own words, the only record of why the offer failed.
@@ -290,21 +270,19 @@ One FeatureStandard, one Project. Pause flag is off.
290
270
  ## 9. Pause and interrupt
291
271
 
292
272
  Pause is an in-process flag on the opened conductor. It is not stored in the
293
- WorkLedger (pause is Conductor admission, not a FeatureStandard state).
273
+ WorkLedger (pause is Conductor admission, not a TicketStandard state).
294
274
 
295
- Boundaries where pause is honoured: before `claim`, before `startSubtask`,
275
+ Boundaries where pause is honoured: before `claim`, before the unit starts,
296
276
  before align, before `markMerging`. A running `implement` finishes.
297
277
 
298
278
  Interrupt is the Transformer Port's problem (the same `interruptFlag` the Transformers
299
- already take). If a transformer returns `interrupted` after `startSubtask`
300
- (Subtask isolate, `implement`, or fold into the feature), Conductor does not
301
- mark the Subtask integrated. It calls `releaseBail` — the Subtask becomes
302
- `runnable` from zero, the declared Subtask directory is destroyed — and
303
- returns `refused` with code `interrupted`. The next process resumes without
304
- waiting for the bail clock. Interrupt during planning, feature isolate,
305
- align, assembly, or a Submission judgement leaves the ledger as the last
306
- successful command left it: those paths resume on the next `runProject`
307
- without a held Subtask.
279
+ already take). If `implement` returns `interrupted` once the lease is taken,
280
+ Conductor does not mark the unit done. It calls `releaseBail` — the Attempt
281
+ is spent, the declared directory is destroyed — and returns `refused` with
282
+ code `interrupted`. The next process starts the unit again without waiting for
283
+ the bail clock. Interrupt during Isolation, warm, align, assembly, or a
284
+ Submission judgement leaves the ledger as the last successful command left it:
285
+ those paths resume on the next `runProject` without a held lease.
308
286
 
309
287
  ## 10. Reconcile
310
288
 
@@ -314,10 +292,10 @@ After process start, and at the beginning of every `runProject`:
314
292
  2. Delete any directory under `workspaceRoot` whose absolute path is **not**
315
293
  on that list (orphans). Never delete `workLineStable`.
316
294
  3. `expireBail` for those declared keys, and for `activeOn(project)` when that
317
- FeatureStandard's bail is past expiry. Then delete a Subtask directory if
295
+ TicketStandard's bail is past expiry. Then delete the unit's directory if
318
296
  the ledger cleared it.
319
297
 
320
- The ledger decides Feature state. Disk never does. Conductor does not scan
298
+ The ledger decides Ticket state. Disk never does. Conductor does not scan
321
299
  every Project; `runProject` reconciles the workspaces on disk plus the Project
322
300
  it was asked to run.
323
301
 
@@ -329,11 +307,10 @@ it was asked to run.
329
307
  | `root-invalid` | `workspaceRoot` is not absolute, or equals `workLineStable` |
330
308
  | `persist-failed` | A ledger command returned `persist-failed` |
331
309
  | `interrupted` | A transformer returned `interrupted` |
332
- | `isolate-failed` | Feature Isolation did not return `isolated` |
333
- | `warm-failed` | Feature warm (when configured) did not return `warmed` |
310
+ | `isolate-failed` | Isolation did not return `isolated` |
311
+ | `warm-failed` | Warm (when configured) did not return `warmed` |
334
312
  | `align-conflict` | Align Integration returned `conflict`; state stays `integrating` |
335
313
  | `transformer-invalid` | A transformer returned `invalid-invocation` |
336
- | `unavailable` | `breakDown` returned `unavailable` (Planner did not answer) |
337
314
 
338
315
  Ledger codes (`project-busy`, `point-of-no-return`, …) pass through on `cancel`
339
316
  and when `claim` refuses.
@@ -351,21 +328,21 @@ Shipped:
351
328
  - `reconcile`, `pause`, `resume`, `runProject`, `cancel`, `release`
352
329
  - Happy path: align, assembly judgement (`produce: false`), `markMerging`, final fold
353
330
  - Authority path: offer, judge, `recordRefusal` / fold, no Integrator fold into WorkLineStable
354
- - `pending_fingerprint` consumed after a Subtask integrates and when entering `integrating`
331
+ - `pending_fingerprint` consumed when the unit ends and when entering `integrating`
355
332
  - Ledger-before-act, declared workspaces, orphan destroy
356
333
  - Isolation tests in §4
357
334
  - Pause boundaries
358
335
 
359
336
  Not shipped:
360
337
 
361
- - FeatureListener / FeatureAdapter / FeatureEmitter (the caller wires them
338
+ - Listener / Adapter / Emitter (the caller wires them
362
339
  through a manager package; Host's suite is the first such assembly)
363
340
  - CLI
364
341
  - Persistent pause across processes
365
- - A human `ready` daemon (caller invokes `resumeReady` then `runProject`)
342
+ - A human `resume` daemon (caller invokes `resumeTicket` then `runProject`)
366
343
  - SQLite, a second workspace layout
367
- - Consuming `pending_fingerprint` while the Feature is `submitted` (admit stores
368
- it; the next Subtask integrate / integrating entry is what consumes it)
344
+ - Consuming `pending_fingerprint` while the Ticket is `submitted` (admit stores
345
+ it; the next unit end / integrating entry is what consumes it)
369
346
 
370
347
  ## 13. Layout
371
348
 
@@ -380,28 +357,32 @@ src/
380
357
 
381
358
  ## 14. Acceptance
382
359
 
383
- 1. `runProject` on a Project with one `received` FeatureStandard calls `claim`
384
- then `breakDown` then `recordPlan` **before** any `isolate`.
385
- 2. `declareWorkspace` for the feature path is recorded **before** `isolate` of
386
- that path. Same for a Subtask path.
387
- 3. Fake transformers, one Subtask, all `validated` / `integrated`, no Authority:
388
- Feature ends `done`; `isolate` was called twice (feature, then Subtask);
389
- `integrate` was called three times (Subtask fold, align, final fold);
390
- assembly `implement` ran once on the feature workspace with `produce: false`.
391
- 4. `breakDown` `refused` → `refusePlan`; no `isolate`; outcome `escalated`.
392
- 5. `implement` `escalated` after Traces → each Trace is `recordAttempt`d;
393
- then `escalate`; no Subtask `integrate`; child directory not deleted by
394
- Conductor.
395
- 6. Subtask `integrate` `conflict` → `escalate`; child kept.
396
- 7. `cancel` of a `running` Feature → ledger `cancelled`; declared directories
360
+ 1. `runProject` on a Project with one `received` TicketStandard calls `claim`
361
+ then `isolate` then `implement`, and the workspace path is declared **before**
362
+ `isolate`.
363
+ 2. Fake transformers, all `validated` / `integrated`, no Authority: Ticket ends
364
+ `done`; `isolate` was called once; `integrate` was called twice (align, final
365
+ fold); `implement` ran twice — the unit, then the assembly judgement with
366
+ `produce: false`.
367
+ 3. A failed Isolation → `refused` (`isolate-failed`); no lease, no Attempt, no
368
+ `implement`.
369
+ 4. `implement` `escalated` after Traces → each Trace is `recordAttempt`d;
370
+ then `escalate({ kind: "unit" })`; no `integrate`; the directory is not
371
+ deleted by Conductor. After `resumeTicket` the unit starts from a fresh
372
+ workspace.
373
+ 5. `cancel` of a `running` Ticket → ledger `cancelled`; declared directories
397
374
  destroyed. `cancel` after `markMerging` → ledger `point-of-no-return`;
398
375
  WorkLineStable untouched.
399
- 8. A directory under `workspaceRoot` that is not declared is gone after
376
+ 6. A directory under `workspaceRoot` that is not declared is gone after
400
377
  `reconcile`. `workLineStable` is never deleted.
401
- 9. `pause` after `recordPlan` and feature isolate, before the first
402
- `startSubtask` → outcome `paused`; no `startSubtask`.
378
+ 7. `pause` after Isolation, before the unit starts → outcome `paused`; no
379
+ `implement`.
380
+ 8. `implement` `interrupted` → lease released, directory destroyed, `refused`
381
+ (`interrupted`).
382
+ 9. A workspace that is gone while the Authority holds a Submission → escalated
383
+ `kind: "submitted"`, and no second Isolation.
403
384
  10. `src/run/` has no import of `@bluewombat/isolator`, `@bluewombat/implementer`,
404
- `@bluewombat/integrator`, or `@bluewombat/feature-breakdown`.
385
+ or `@bluewombat/integrator`.
405
386
  11. Opening Conductor with a Transformer Port test double and a WorkLedger test
406
387
  double still passes 1–9. No Transformer `dist/` and no filesystem persist are
407
388
  required for those.
@@ -409,22 +390,23 @@ src/
409
390
  Gap, named: align `conflict` leaves `integrating` (`align-conflict`) rather than
410
391
  a first-class ledger kind. Do not hide that. A later WorkLedger command can
411
392
  close it. Assembly `escalated` uses `escalate({ kind: "assembly" })`;
412
- `resumeReady` returns that Feature to `integrating`.
393
+ `resumeTicket` returns that Ticket to `integrating`; a `unit` escalation returns
394
+ it to `running`.
413
395
 
414
396
  ## 15. Choices
415
397
 
416
398
  1. **Not a Transformer.** Sequencing many verbs is not Implementer-shaped.
417
- 2. **Injected Transformer Port.** Depending on four Transformer packages would make the
399
+ 2. **Injected Transformer Port.** Depending on three Transformer packages would make the
418
400
  run loop untestable without `dist/` and would freeze Isolation strategy
419
401
  inside Conductor. The caller wires Transformers.
420
402
  3. **Injected WorkLedger.** Conductor does not open persist. Glue already chose
421
403
  the adapter.
422
404
  4. **Ledger before act, always.** Directories that exist without a declaration
423
405
  are orphans and die.
424
- 5. **No Emitter in this package.** Reporting is FeatureEmitter. Conductor
406
+ 5. **No Emitter in this package.** Reporting is Emitter. Conductor
425
407
  returns a result; the caller reports.
426
- 6. **Pause is in-process.** A FeatureStandard state for pause would confuse
427
- `escalated` and `ready`. Restart clears pause; reconcile + bail remain.
408
+ 6. **Pause is in-process.** A TicketStandard state for pause would confuse
409
+ `escalated` and `resume`. Restart clears pause; reconcile + bail remain.
428
410
  7. **Stack: TypeScript on Node.js 24.20, Biome, `node:test` run through `tsx`.**
429
411
  Same as WorkLedger. Recorded here; commands live in this package's README.
430
412
 
package/dist/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  export type { Conductor, ConductorMoment, ConductorRefusalCode, OpenConductorOptions, ProjectRunResult, WarmOutcome, WarmPort, } from "./run/open-conductor.js";
2
2
  export { foldMessageOf, openConductor, subjectOf } from "./run/open-conductor.js";
3
- export { featureWorkspacePath, subtaskWorkspacePath } from "./run/paths.js";
4
- export type { AuthorityFoldResult, AuthorityPort, BreakDownResult, ImplementResult, SubmitInput, SubmitResult, TransformerPort, } from "./transformers/port.js";
3
+ export { ticketWorkspacePath } from "./run/paths.js";
4
+ export type { AuthorityFoldResult, AuthorityPort, ImplementResult, SubmitInput, SubmitResult, TransformerPort, } from "./transformers/port.js";
5
5
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,YAAY,EACV,SAAS,EACT,eAAe,EACf,oBAAoB,EACpB,oBAAoB,EACpB,gBAAgB,EAChB,WAAW,EACX,QAAQ,GACT,MAAM,yBAAyB,CAAC;AACjC,OAAO,EAAE,aAAa,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,yBAAyB,CAAC;AAClF,OAAO,EAAE,oBAAoB,EAAE,oBAAoB,EAAE,MAAM,gBAAgB,CAAC;AAC5E,YAAY,EACV,mBAAmB,EACnB,aAAa,EACb,eAAe,EACf,eAAe,EACf,WAAW,EACX,YAAY,EACZ,eAAe,GAChB,MAAM,wBAAwB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,YAAY,EACV,SAAS,EACT,eAAe,EACf,oBAAoB,EACpB,oBAAoB,EACpB,gBAAgB,EAChB,WAAW,EACX,QAAQ,GACT,MAAM,yBAAyB,CAAC;AACjC,OAAO,EAAE,aAAa,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,yBAAyB,CAAC;AAClF,OAAO,EAAE,mBAAmB,EAAE,MAAM,gBAAgB,CAAC;AACrD,YAAY,EACV,mBAAmB,EACnB,aAAa,EACb,eAAe,EACf,WAAW,EACX,YAAY,EACZ,eAAe,GAChB,MAAM,wBAAwB,CAAC"}
package/dist/index.js CHANGED
@@ -1,3 +1,3 @@
1
1
  export { foldMessageOf, openConductor, subjectOf } from "./run/open-conductor.js";
2
- export { featureWorkspacePath, subtaskWorkspacePath } from "./run/paths.js";
2
+ export { ticketWorkspacePath } from "./run/paths.js";
3
3
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AASA,OAAO,EAAE,aAAa,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,yBAAyB,CAAC;AAClF,OAAO,EAAE,oBAAoB,EAAE,oBAAoB,EAAE,MAAM,gBAAgB,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AASA,OAAO,EAAE,aAAa,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,yBAAyB,CAAC;AAClF,OAAO,EAAE,mBAAmB,EAAE,MAAM,gBAAgB,CAAC"}