vinta-ai-workflows 0.7.0-alpha13 → 0.7.0-alpha14

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