@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 +3 -3
- package/SPECS.md +128 -146
- package/dist/index.d.ts +2 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/run/open-conductor.d.ts +12 -21
- package/dist/run/open-conductor.d.ts.map +1 -1
- package/dist/run/open-conductor.js +128 -259
- package/dist/run/open-conductor.js.map +1 -1
- package/dist/run/paths.d.ts +1 -2
- package/dist/run/paths.d.ts.map +1 -1
- package/dist/run/paths.js +2 -5
- package/dist/run/paths.js.map +1 -1
- package/dist/transformers/port.d.ts +12 -41
- package/dist/transformers/port.d.ts.map +1 -1
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Conductor
|
|
2
2
|
|
|
3
|
-
Kernel package, not a Transformer: sequences Transformers for one
|
|
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,
|
|
33
|
+
Transformer Port (Isolation, Implementer, Integration).
|
|
34
34
|
|
|
35
|
-
**Optional Authority.** When injected, Conductor offers the assembled
|
|
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,
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
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
|
|
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`, `
|
|
39
|
-
`runIntegrator`, closed over
|
|
40
|
-
Conductor does not import `@bluewombat/isolator` (or the other
|
|
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,
|
|
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 |
|
|
61
|
-
| Ledger | Legal transitions, bail
|
|
62
|
-
| Transformers | One Isolation /
|
|
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
|
|
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
|
-
|
|
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
|
-
| `
|
|
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
|
-
|
|
100
|
-
|
|
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
|
|
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
|
|
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
|
|
146
|
-
|
|
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>/
|
|
155
|
-
<workspaceRoot>/<key-segment>/subtask-<id-segment>
|
|
144
|
+
<workspaceRoot>/<key-segment>/ticket
|
|
156
145
|
```
|
|
157
146
|
|
|
158
|
-
`<key-segment>`
|
|
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
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
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
|
-
`
|
|
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
|
|
188
|
-
| `pause` | In-process flag: no new `claim`, no new
|
|
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
|
|
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
|
|
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`
|
|
199
|
-
| `done` | The
|
|
200
|
-
| `escalated` | Frozen for a human.
|
|
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 `
|
|
205
|
-
caller (
|
|
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
|
|
195
|
+
One TicketStandard, one Project. Pause flag is off.
|
|
211
196
|
|
|
212
197
|
1. `reconcile`.
|
|
213
|
-
2. If the Project already has an active
|
|
198
|
+
2. If the Project already has an active TicketStandard, resume it. Else `claim`.
|
|
214
199
|
Empty → `idle`.
|
|
215
|
-
3. **
|
|
216
|
-
|
|
217
|
-
`
|
|
218
|
-
`
|
|
219
|
-
`invalid
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
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
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
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: "
|
|
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
|
|
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
|
|
259
|
-
workspace as **parent**.
|
|
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
|
|
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
|
|
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`
|
|
275
|
-
`integrated` → `markDone`, delete
|
|
276
|
-
`conflict` → `escalate({ kind: "merging" })`, keep the
|
|
277
|
-
6. **With an Authority.** `submit` the assembled
|
|
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
|
|
273
|
+
WorkLedger (pause is Conductor admission, not a TicketStandard state).
|
|
294
274
|
|
|
295
|
-
Boundaries where pause is honoured: before `claim`, before
|
|
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
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
`
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
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
|
-
|
|
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
|
|
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` |
|
|
333
|
-
| `warm-failed` |
|
|
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
|
|
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
|
-
-
|
|
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 `
|
|
342
|
+
- A human `resume` daemon (caller invokes `resumeTicket` then `runProject`)
|
|
366
343
|
- SQLite, a second workspace layout
|
|
367
|
-
- Consuming `pending_fingerprint` while the
|
|
368
|
-
it; the next
|
|
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`
|
|
384
|
-
then `
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
`
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
then `escalate`; no
|
|
394
|
-
Conductor.
|
|
395
|
-
|
|
396
|
-
|
|
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
|
-
|
|
376
|
+
6. A directory under `workspaceRoot` that is not declared is gone after
|
|
400
377
|
`reconcile`. `workLineStable` is never deleted.
|
|
401
|
-
|
|
402
|
-
`
|
|
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
|
-
|
|
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
|
-
`
|
|
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
|
|
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
|
|
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
|
|
427
|
-
`escalated` and `
|
|
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 {
|
|
4
|
-
export type { AuthorityFoldResult, AuthorityPort,
|
|
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
|
package/dist/index.d.ts.map
CHANGED
|
@@ -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,
|
|
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
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,
|
|
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"}
|