vinta-ai-workflows 0.7.0-alpha10 → 0.7.0-alpha12

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/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-alpha12 on 2026-09-15 -->
11
+ <!-- pre-release: 0.7.0-alpha11 on 2026-09-15 -->
10
12
  <!-- pre-release: 0.7.0-alpha10 on 2026-09-15 -->
11
13
  <!-- pre-release: 0.7.0-alpha9 on 2026-09-14 -->
12
14
  <!-- pre-release: 0.7.0-alpha8 on 2026-09-14 -->
@@ -318,8 +320,104 @@ the project follows [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
318
320
  `plan/{plan-id}/lane-{phase-id}` branches, merged `--no-ff` into the single plan
319
321
  branch at each wave boundary, so the unit commits survive.
320
322
 
323
+ - **`project.prepare_cmd`, for the shared servers a run depends on.** A project
324
+ whose databases are `delivery: external` and whose services point at one Redis
325
+ has no long-lived containers of its own — the shape these fields recommend —
326
+ and that makes some *other* stack a hard dependency of every run. Nothing in
327
+ the package could bring it up. `setup_cmd` looks like the place and is not: it
328
+ runs per lane, long after the template database was created on a server that
329
+ had to be up for `createdb` to work at all.
330
+
331
+ It runs in the repository root **before anything else a run does** — before
332
+ the preflight, before the templates, before the first worktree — and again
333
+ before every lane recycle, so a server that dies mid-run is restored at the
334
+ next hand-off rather than failing every phase after it. Failure aborts with
335
+ the exit code and a bounded stderr tail, and says what the failure means
336
+ rather than only that a command exited. It must be idempotent, and `--wait`
337
+ is only as good as the `healthcheck` a service declares: without one, compose
338
+ returns as soon as the container starts and `createdb` races the server.
339
+
321
340
  ### Fixed
322
341
 
342
+ - **`doctor` checks that the shared servers answer.** It verified that binaries
343
+ existed and disk fitted, and never looked at a `server_url` — so a project
344
+ whose Postgres lives in another checkout's compose stack passed the preflight
345
+ with that stack down and died on the first `createdb`, before a worktree
346
+ existed. Each external database's server and each service URL is now probed
347
+ with a TCP connect, and a failure names the address that did not answer. A
348
+ compose-delivered database is deliberately not probed: the lane starts it.
349
+
350
+ The order matters as much as the check. `prepare_cmd` runs *before* the
351
+ preflight, so the check reports the world that hook just made rather than the
352
+ one in front of it.
353
+
354
+ - **A service's `create_cmd` runs with the lane's environment.** `reset_cmd`
355
+ always had it and `create_cmd` did not, so a `create_cmd` that reached for
356
+ `docker compose` ran against the lane's own compose file with no project name
357
+ and no override — booting a stack on the project's fixed host ports, which is
358
+ the collision the override exists to prevent, caused by the step that sets a
359
+ lane up.
360
+
361
+ - **`vinta-ai-maestro with` waits for the lock instead of giving up on it.** Its
362
+ usage said it blocked until the resource was granted, and it did — for about
363
+ five minutes, which is where Node's own `fetch` stops waiting for a response.
364
+ A test suite behind a capacity-1 semaphore beats that regularly. What the
365
+ agent saw was "could not reach the lease daemon", and what agents did with
366
+ that, repeatedly, was run the command without a lease: exactly the stampede
367
+ the pool exists to prevent, arrived at by an agent behaving reasonably.
368
+
369
+ The wait is the client's now. The daemon answers `202 still queued` within
370
+ seconds and **leaves its own queue behind it**, so nothing is granted to a
371
+ request that has gone away; the client loops until it is granted, saying so
372
+ once and then occasionally, so a transcript shows a wait rather than a
373
+ silence. Only answers that waiting cannot change — a resource this run does
374
+ not declare, a run that is no longer live — end it.
375
+
376
+ And when it does end that way, the refusal says what not to do about it.
377
+ "The resource lease was not granted" is an error with no alternative in it;
378
+ the rule against working around it now travels with the message rather than
379
+ sitting only in a prompt the agent read twenty minutes earlier. The prompt
380
+ says it too, including that waiting is the expected outcome and not a failure.
381
+
382
+ - **A retry gets a fresh fix budget.** `fix_rounds` was set to 0 when a node was
383
+ created and never again, so a phase that spent its whole budget on attempt 1
384
+ began attempt 2 already exhausted — one review, one fix, and the exhaustion
385
+ transition fired straight back. Seen with `max_fix_rounds: 4`: the retry got a
386
+ single round before the operator was asked again, forty seconds of work
387
+ standing in for four rounds of it. A retry that inherits the reason the last
388
+ attempt ran out is not a retry. It resets wherever a node is re-driven from
389
+ its pipeline's initial state — a capacity refusal, an automatic retry, the
390
+ operator's answer, the `retry` verb — which is one place rather than four.
391
+
392
+ - **The last fix is reviewed rather than failed unread.** `standard-phase`
393
+ checked the budget on the way *out* of `fix`, so the final fixer's work went
394
+ straight to `failed` with nothing looking at it. Two phases in one run ended
395
+ on a fixer reporting "all gates green, committed, tree clean" and were failed
396
+ anyway. The check now sits in front of the fixer, on both doors into it: every
397
+ fixer that runs is reviewed, and the review after the last one can still pass
398
+ the phase. Guarding only the review side left a red gate under a passing
399
+ reviewer looping forever, which is the other half of the same change.
400
+
401
+ `max_fix_rounds` still means the number of fixers a phase may spend. `0` now
402
+ means none, where before it let one run and failed the phase regardless.
403
+
404
+ - **Agents are told not to background their work.** An implementer started five
405
+ commands with `run_in_background: true` and closed its turn with "I'll wait for
406
+ the test result notification before continuing to the outer gate". There is no
407
+ notification: a headless session ends when the turn ends and whatever it
408
+ backgrounded is killed with it. Three sessions ended with no report and no
409
+ commit, and the reviewer failed each for uncommitted work — true, and not the
410
+ cause. Nothing had said so, and believing a tool that offers backgrounding will
411
+ still be there afterwards is not unreasonable.
412
+
413
+ - **The reviewer runs the gates instead of taking their word for it.** The prompt
414
+ asked it to confirm the outer gate was green, which an agent can do by reading
415
+ the implementer's report — one reused reviewer session reached a verdict in
416
+ under four minutes without running the project's tests at all. It is now asked
417
+ to run them, to say what they returned, and to treat being unable to run them
418
+ as a finding. Re-review rounds are asked again, because a session that
419
+ remembers running them last round is remembering a different tree.
420
+
323
421
  - **A retried phase keeps the commits the attempt before it made.** A failed
324
422
  phase re-enters its pipeline at the initial state, which runs `git_branch`
325
423
  again — and `checkout -B` moves an existing branch unconditionally, so attempt
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vinta-ai-workflows",
3
- "version": "0.7.0-alpha10",
3
+ "version": "0.7.0-alpha12",
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": {
@@ -331,6 +331,11 @@
331
331
  "additionalProperties": false,
332
332
  "description": "How a lane’s compose stack is isolated past `COMPOSE_PROJECT_NAME`."
333
333
  },
334
+ "prepare_cmd": {
335
+ "description": "Run in the repository root **before anything else a run does** — before the preflight, before the template databases, before the first worktree. Its job is to make the shared servers this project’s lanes connect to reachable: `docker compose up -d --wait db redis` for a stack in the root checkout, `brew services start postgresql` for a host install, nothing at all for a project whose lanes boot their own. `setup_cmd` cannot do this — it runs per lane, long after the template database has been created on a server that had to be up already. MUST be idempotent: it runs again before every lane recycle, which is what restores a server that died mid-run. Note that `--wait` only waits for services that declare a `healthcheck`; without one it returns as soon as the container is started, and `createdb` races the server.",
336
+ "type": "string",
337
+ "minLength": 1
338
+ },
334
339
  "setup_cmd": {
335
340
  "description": "The project’s own lane-setup command, run inside each freshly provisioned lane with that lane’s environment applied. The escape hatch for whatever a project needs that no field here describes. It MUST be idempotent: it runs again every time the lane is recycled for another phase.",
336
341
  "type": "string",