vinta-ai-workflows 0.7.0-alpha13 → 0.7.0-alpha15

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 (2) hide show
  1. package/CHANGELOG.md +131 -2
  2. package/package.json +1 -1
package/CHANGELOG.md CHANGED
@@ -7,6 +7,8 @@ the project follows [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
8
  ## [0.7.0] — YYYY-MM-DD
9
9
 
10
+ <!-- pre-release: 0.7.0-alpha15 on 2026-09-16 -->
11
+ <!-- pre-release: 0.7.0-alpha14 on 2026-09-16 -->
10
12
  <!-- pre-release: 0.7.0-alpha13 on 2026-09-16 -->
11
13
  <!-- pre-release: 0.7.0-alpha12 on 2026-09-15 -->
12
14
  <!-- pre-release: 0.7.0-alpha11 on 2026-09-15 -->
@@ -23,6 +25,18 @@ the project follows [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
23
25
 
24
26
  ### Added
25
27
 
28
+ - **`vinta-ai-maestro gate <gate-id>` runs a declared gate from inside an agent
29
+ turn.** A phase used to run its full gate suite five or six times a round —
30
+ implementer, reviewer, fixer, reviewer again, then the authoritative `gate`
31
+ node — and only the last of those consulted the gate cache or the resource
32
+ pool. Agents now ask the daemon for a gate by id: the result is cached on the
33
+ same `(gate id, lane tree hash)` key the `gate` node reads, the gate's
34
+ resources are held by the daemon rather than by whichever agent remembered to
35
+ wrap the command, and the id resolves to the plan's own command so a scoped
36
+ approximation cannot be reported as the gate. Each run is journalled as a
37
+ `gate_result` event and a `gate_run` transcript entry under the GATE band,
38
+ whoever asked for it.
39
+
26
40
  - **A project declares what makes a lane runnable.** `project.env_files` copies
27
41
  ignored configuration into each worktree, `project.setup_cmd` runs an
28
42
  idempotent setup hook on provisioning and recycle, and the fixed
@@ -185,10 +199,33 @@ the project follows [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
185
199
  claimed per review turn rather than per phase — it has one session ledger and
186
200
  two concurrent reviews would collide over it — so one reviewer on a three-lane
187
201
  plan is a queue at the review step and not a serialised run.
202
+ - **"Cheapest qualified" has one exception, and it is about sessions.** A
203
+ member who already holds a session this phase would genuinely resume takes
204
+ it ahead of a cheaper member who would have to start cold — even when they
205
+ are more senior than the phase needs, and even when the member the plan
206
+ named is free. What it buys is the context a cold session spends its first
207
+ turn rebuilding; what it costs is the dearer model for that phase, which is
208
+ the smaller of the two bills. **The tier floor is untouched**: warmth
209
+ reorders the members who already qualify and never widens them, so a warm
210
+ junior still cannot take a Tier 3 phase.
211
+ - **Only when a session is genuinely already up.** "Warm" means the scheduler
212
+ asked its own session-reuse rules and got a yes — same pinned lane, same
213
+ harness, under the turn ceiling, not poisoned by a failed phase. A member
214
+ who has merely run before is not warm, because a promotion bought on a
215
+ resume that is then refused pays the senior's rate *and* cold-starts
216
+ anyway. With nobody warm, staffing is exactly what it was: a session is
217
+ being opened either way, and the plan's own level wins.
218
+ - An operator who picks the member by hand on a retry gets that member. A
219
+ saving nobody asked for does not overrule an explicit answer.
188
220
  - The run view reports who actually worked against who the plan said would.
189
221
  `substituted` is the figure to read beside a cost that overran: every
190
222
  substitution ran at or above the budgeted tier, so a run can be entirely green
191
- and still have been staffed dearer than planned.
223
+ and still have been staffed dearer than planned. The phases promoted to reuse
224
+ a warm session are counted **within** that figure and reported apart from it —
225
+ a peer covering for a busy member costs what the plan budgeted, while a warm
226
+ promotion is the scheduler deliberately trading model rate against cold
227
+ starts, and folded together a run that promoted everything to the top tier
228
+ would read as an ordinary busy wave.
192
229
 
193
230
  - **`implement-plan` runs independent phases in parallel.** The plan now carries a
194
231
  dependency graph and the conductor schedules against it: a phase starts as soon as
@@ -303,10 +340,43 @@ the project follows [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
303
340
  it rather than only in a log beside it. The operator's own steering stays the
304
341
  operator's (§7), even though the adapter echoes it back on the agent's event
305
342
  stream. Transcripts written before this render exactly as they did, with no
306
- bands.
343
+ bands. The band stays pinned to the top of the scroller while its own run of
344
+ rows goes past, so the agent you are reading is named without scrolling back
345
+ to where it started — in the phase transcript and in the monitor conversation
346
+ alike.
307
347
 
308
348
  ### Changed
309
349
 
350
+ - **A session cannot inherit a machine's decision to stop compacting.** All
351
+ three harnesses compact automatically when their context fills — there was
352
+ never a flag to turn on — but each honours an environment variable that turns
353
+ it off, and an agent spawned on a machine carrying one would run a long phase
354
+ straight into a wall it was supposed to be able to survive. Those variables
355
+ are now stripped from every child the daemon spawns, and claude-code's own
356
+ setting is reasserted in the per-lane file beside its permission rules. The
357
+ window itself is left alone: an operator who narrowed theirs compacts earlier,
358
+ which is not the failure this guards against. A harness that compacts declares
359
+ it, and a compaction the harness reports is a transcript row like any other.
360
+
361
+ One consequence worth knowing: `max_session_turns` used to be a proxy for "this
362
+ session is nearing a context window it will die on". That death no longer
363
+ happens, so the ceiling now guards a different thing — a session whose memory
364
+ was replaced by a summary of itself, and which answers just as confidently.
365
+
366
+ - **Agent prompts name gates by id rather than printing their commands.** The
367
+ implementer's step 4 was descriptive — "Outer gate… These run against your
368
+ lane:" followed by the gate commands — and implementers were observed reading
369
+ it as a note about what would run later, finishing the scoped inner loop and
370
+ never running a gate at all. It is imperative now, and every role that runs a
371
+ gate (implementer, reviewer, fixer, and the continuation of each) is pointed
372
+ at `vinta-ai-maestro gate <id>`. The fixer prompts no longer say to re-run the
373
+ gates "until they are green", which contradicted the commit protocol directly
374
+ below them and left fixers running out the turn with the work uncommitted;
375
+ they now say to commit and report FAILURE when a gate cannot be turned green.
376
+ Implementers and fixers report which gates they ran and what each returned —
377
+ a record for the reviewer to check against, explicitly not a licence for the
378
+ reviewer to skip running them itself.
379
+
310
380
  - **Phase branches base on their dependencies, not on the previous phase.** A phase
311
381
  with no dependencies cuts from the default branch; one with a single dependency
312
382
  cuts from that phase's branch; one with several cuts from a
@@ -360,8 +430,67 @@ the project follows [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
360
430
  is only as good as the `healthcheck` a service declares: without one, compose
361
431
  returns as soon as the container starts and `createdb` races the server.
362
432
 
433
+ - **A merge conflict goes to the most senior member who wrote one of its
434
+ sides.** The conflict fixer was staffed from `defaults` and ignored the roster
435
+ entirely, so on a tiered crew a collision between two Tier 4 phases was handed
436
+ to a default-tier agent that had read neither of them — the hardest merge in
437
+ the run going to the least contextualised agent available, and resolved by
438
+ guessing which side looked more finished.
439
+
440
+ `Integrator` already knows which nodes own the contested paths, and `node_crew`
441
+ already records who took each one; this is the join. Highest tier among them
442
+ wins, on that member's own `model` and `harness`, and a tier tie breaks on
443
+ member id the way roster substitution breaks its own. An unstaffed workflow
444
+ still resolves through `defaults`, unchanged, and so does a conflict whose
445
+ nodes cannot be resolved to a member.
446
+
447
+ What is carried is the member's **capability, not their session**. A phase's
448
+ session ran in that phase's lane; the fixer runs in the integration worktree,
449
+ where the files in dispute are half-merged and unlike anything that session
450
+ saw — resuming there would give the agent confident, false memories of exactly
451
+ the files it is merging. The prompt tells the fixer which side is its own, and
452
+ in the same breath that it is a fresh session and must read rather than
453
+ recall.
454
+
363
455
  ### Fixed
364
456
 
457
+ - **A member's reviews were counted as phases they took.** `node_crew` is
458
+ written for both seats — the reviewer's claim carries `role: 'reviewer'`, the
459
+ implementer's omits it — and the staffing rollup read neither, so every phase
460
+ a member reviewed was folded into the count of phases they implemented. On any
461
+ run with reviewers that inflated the number the rollup exists to put beside
462
+ the plan's estimate, and inflated `asPlanned`, which the run view divides by.
463
+ The two seats are counted apart now rather than one of them dropped: a review
464
+ is real work by a real member, and a member who only reviewed is neither a
465
+ phase-taker nor idle.
466
+
467
+ - **An agent taking a lease left the resource panel showing the one before it.**
468
+ The scheduler's own gate-pool transitions are journalled as `gate_pool`
469
+ events, so the browser re-reads the snapshot when one lands. An agent's lease,
470
+ taken through `vinta-ai-maestro with`, was only a row in the `leases` table —
471
+ correct in the daemon's projection and announced to nobody. A projection
472
+ nobody is told changed is a projection nobody sees change, so the panel showed
473
+ whatever holders it had last time some unrelated event happened to arrive, and
474
+ the waits it was stalest about were the agent ones, which are the long ones.
475
+ The broker now journals `agent_lease` on both edges. A renewal writes nothing:
476
+ it is a heartbeat on a lease already reported, and journalling it would bury
477
+ the two rows that are transitions under a liveness log.
478
+
479
+ - **An agent waiting for a semaphore could be overtaken without bound.** A
480
+ `vinta-ai-maestro with` wait is served in fifteen-second hops so no client
481
+ timeout has an opinion about it, and each hop used to abort the underlying
482
+ `pools.acquire`. Aborting leaves the pool queue, and the next POST re-entered
483
+ it — at the tail, behind every waiter that had arrived in the meantime. Since
484
+ a gate run holds a capacity-1 semaphore for minutes, an agent lost that race
485
+ on hop after hop while the scheduler's own in-process waiters, which never
486
+ leave the queue, did not. The pool's aging rule could not help: aging reserves
487
+ against waiters *behind* the aged one, and the waiters that overtook it are in
488
+ front of it. A `202` now carries a `waitToken` naming the wait, the client
489
+ sends it back, and the daemon keeps the one queue entry — one arrival time,
490
+ one place in line — across the whole wait. A parked wait whose client stops
491
+ hopping is reaped after a minute, releasing the slot if one was granted to it
492
+ while nobody was watching.
493
+
365
494
  - **The monitor's conversation could never be written on Windows.** It is kept
366
495
  under a reserved node id that becomes a directory, and that id was
367
496
  `monitor:conversation` — a colon, chosen because no phase id may contain one,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vinta-ai-workflows",
3
- "version": "0.7.0-alpha13",
3
+ "version": "0.7.0-alpha15",
4
4
  "description": "Bootstrap AI tooling (AGENTS.md, skills, sub-agents) across Claude Code, Codex, Cursor, and VS Code + GitHub Copilot.",
5
5
  "type": "module",
6
6
  "bin": {