vinta-ai-workflows 0.7.0-alpha37 → 0.7.0-alpha39

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-alpha39 on 2026-10-24 -->
11
+ <!-- pre-release: 0.7.0-alpha38 on 2026-10-22 -->
10
12
  <!-- pre-release: 0.7.0-alpha37 on 2026-10-20 -->
11
13
  <!-- pre-release: 0.7.0-alpha36 on 2026-10-18 -->
12
14
  <!-- pre-release: 0.7.0-alpha35 on 2026-10-16 -->
@@ -37,6 +39,88 @@ the project follows [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
37
39
 
38
40
  ### Added
39
41
 
42
+ - **`vinta-ai-maestro` UI: what a phase is running, and a way to stop it.**
43
+ The node view's gates panel is now a **Processes** panel. It lists the
44
+ phase's running processes: the agent's shell commands, marked as waiting
45
+ on it or in the background, and its gates. Two are shown, and the rest
46
+ open in a dialog. A two-click **Stop** ends a process and everything under
47
+ it (`POST /api/runs/<run>/nodes/<node>/processes/<pid>/stop`, journalled
48
+ `process_stopped`). The gates section below is unchanged. A phase waiting
49
+ on a background command no longer reads as stuck. It needs a live run and
50
+ a harness with one CLI process per session (claude-code, codex).
51
+ - **`vinta-ai-maestro`: resource pools shared by every run on the machine.**
52
+ A pool declared `scope: host` also counts every other maestro run holding
53
+ a pool of the same name, through lock files under
54
+ `~/.vinta-ai-maestro/host-leases/` (pid and run id only). Two runs on one
55
+ laptop then take turns at the full suite instead of running two at once.
56
+ The bootstrap now emits `scope: host` on the `test-suite` pool, and
57
+ `maestro.resources.<id>.scope` is in the config schema. `run` stays the
58
+ default.
59
+ - **`vinta-ai-maestro`: test databases as a gate input.** A gate may declare
60
+ `fresh_when`, globs of the files its state is built from (its
61
+ migrations). When one that matched at its last run in the integration
62
+ worktree is gone or different, the gate runs `fresh_cmd` even though the
63
+ tree moved forward. It is in the workflow schema, in
64
+ `maestro.gates.<type>` of the config schema, and in the bootstrap's
65
+ fresh-database question. `gate-cache invalidate <run> <gate> --databases`
66
+ asks for fresh state once.
67
+ - **`vinta-ai-maestro`: `exec --priority`.** In the integration worktree,
68
+ waits only for the current holder, ahead of every phase queued.
69
+ - **`vinta-ai-maestro`: `logs --failures <gate-log>`.** Prints the first
70
+ failing test in a gate log and the first line saying what went wrong, in
71
+ the operator's own terminal.
72
+ - **`vinta-ai-maestro`: chore `background: false`.** Tells a chore's turns
73
+ to run everything in the foreground.
74
+ - **`vinta-ai-maestro` UI: run analytics and the end-of-run report.** A new
75
+ `#/runs/<run>/analytics` page shows where the run's time is going while
76
+ it runs — working time by pipeline step (implementation, gates, review,
77
+ polish, integration), filtered by phase, wave, harness, crew member or
78
+ model, a breakdown grouped by any of those, what each gate and each chore
79
+ cost, and the critical path — with open activities timed live. Once the
80
+ run has ended the same page leads with the post-mortem drawn as a report
81
+ with a short diagnosis. The run view carries a "Where the time goes"
82
+ summary and a header button that reads Analytics while the run goes and
83
+ Report after. Two new reads back them: `GET /api/runs/:id/analytics` and
84
+ `GET /api/runs/:id/postmortem`.
85
+ - **`vinta-ai-maestro` UI: the integration worktree's record.** The run
86
+ view's worktree panel lists every step every phase took there, newest
87
+ first, each linked to its phase (`GET /api/runs/:id/integration`).
88
+ - **`vinta-ai-maestro` UI: the coordinator is a sidebar.** The run
89
+ coordinator's conversation moved out of the run view's grid into a
90
+ full-height sidebar on the right — from under the top bar to the bottom of
91
+ the window on a wide screen, a non-modal sheet otherwise, and on the phase
92
+ page too — opened from a header button and remembered across visits. The
93
+ conversation fills it and the question box sits at the bottom.
94
+ - **`vinta-ai-maestro` UI: every page fits a phone.** The top bar keeps to
95
+ one row (the mark alone stands for the brand below the `sm` breakpoint),
96
+ every two-column layout stacks, and every table scrolls inside its card
97
+ instead of widening the page.
98
+ - **`vinta-ai-maestro` UI: the run view's panels are a tiled grid.** Every
99
+ panel is one or two row units tall, fills its cell and scrolls inside it,
100
+ and short panels pack into the holes tall ones leave — no more band of
101
+ empty page under a short card beside a long one. The roster, "Decided
102
+ without you", the integration record and the phase page's integration
103
+ timeline show their newest five rows (newest first) with the whole record
104
+ in a paged dialog; the resource pools show the two in use (fullest first)
105
+ with the rest in a dialog. Selecting a node on the canvas scrolls its
106
+ roster row into view.
107
+ - **`vinta-dag-editor`: phase ids on the cards.** Each node card carries its
108
+ id (`p1`, `p2`, …) above its name, so the canvas names phases the way the
109
+ roster, the transcript and the plan do.
110
+ - **`vinta-dag-editor`: tooltips stay inside the canvas.** A tooltip is kept
111
+ whole within the viewport — pushed in from the edges and flipped above its
112
+ source when there is no room below — so the toolbar's and the edge cards'
113
+ tooltips no longer open into the clipped strip outside the graph.
114
+ - **`vinta-ai-maestro` UI: the graph goes full screen.** A button on the
115
+ canvas (run view, replay and plan review) takes it over the whole window
116
+ and frames the graph again for the larger box; Escape or the same button
117
+ brings it back.
118
+ - **`vinta-ai-maestro`: integration gate logs are live.** The integrator
119
+ records one `verify` step per gate, with the log's path, when the gate
120
+ starts rather than when the whole suite ends — so the phase page tails a
121
+ merged-tree gate's output while it runs. The step's wording is now
122
+ "gate `<id>` on the merged tree", with the outcome mark saying whether it
123
+ went red.
40
124
  - **`vinta-ai-maestro`: `post_merge`.** A workflow (or `maestro.post_merge`)
41
125
  may declare a command that runs in the integration worktree after git
42
126
  merges a branch by itself, with `{files}` set to the files both sides
@@ -1333,6 +1417,70 @@ the project follows [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
1333
1417
 
1334
1418
  ### Fixed
1335
1419
 
1420
+ - **`vinta-ai-maestro`: a setup that failed on unchanged inputs is not
1421
+ retried unattended.** A phase whose setup failed twice on the same inputs
1422
+ (the run base's tip, its dependencies' tips and the gates run on the
1423
+ merged base) is no longer retried by the `--retry-after` timer. Red base
1424
+ gates count too. The first retry still runs, so a flaky test gets its
1425
+ second chance. The question names the inputs, and under `--retry-after`
1426
+ the phase is retried as soon as one of them moves. One run retried three
1427
+ phases 37 to 40 times each on the same break, a full suite every time.
1428
+ - **`vinta-ai-maestro`: a wave that cannot be assembled parks the phase
1429
+ instead of failing it.** Building the wave inside the last phase's
1430
+ integrate step made any wave failure that phase's failure, and its whole
1431
+ pipeline ran again from the implementer. Now the phase parks in integrate,
1432
+ landed so its dependents start. `retry` rebuilds only the wave, `skip`
1433
+ finishes without it, and `stop` fails the phase with no automatic attempt.
1434
+ The merges already made on the wave are kept. A merge that ran out of fix
1435
+ rounds is retried from the tree its last fixer left: it is verified first
1436
+ and committed without spending a round when it passes. Journalled as
1437
+ `wave_failed`.
1438
+ - **`vinta-ai-maestro`: a cross-phase fix is made once.** An `integ-`
1439
+ branch is kept across attempts when its first dependency only moved
1440
+ forward (`refs/vinta-ai-maestro/cut/`), so a fix committed on the branch
1441
+ survives the next attempt. What a fixer changed on a merged tree that was
1442
+ already free of conflicts but still red is kept under
1443
+ `refs/vinta-ai-maestro/fixes/`. A later red merge tries those fixes before
1444
+ another fixer round, and keeps them only if the gates pass
1445
+ (`integration_fix_replayed`).
1446
+ - **`vinta-ai-maestro`: a killed gate's containers are checked, not
1447
+ assumed gone.** A docker call that times out under load is no longer read
1448
+ as "no containers". It is retried with more patience, the gate result
1449
+ records `orphan_check: failed`, and the next gate in that compose project
1450
+ sweeps first. A killed integration gate also makes the next run there use
1451
+ `fresh_cmd`.
1452
+ - **`vinta-ai-maestro`: a silent review is asked for its verdict before it
1453
+ fails.** A review turn that ended without its `VERDICT:` line (typically
1454
+ "waiting on the tests" after starting them in the background) is asked
1455
+ once more, in the same session, to finish in the foreground and state the
1456
+ verdict. Before, the phase was failed and restarted from the implementer.
1457
+ - **`vinta-ai-maestro`: abort and retry drop a phase's pause.** A phase
1458
+ that was paused, aborted and retried kept the pause, and the integration
1459
+ queue passed it over. `status` now shows a waiter paused in that queue as
1460
+ paused, not as held by whoever it queued behind.
1461
+ - **`vinta-ai-maestro`: red gate errors name the log instead of guessing.**
1462
+ Base, wave and merge-verify errors no longer call the failure "a
1463
+ regression between" the phases. They name the log and point at
1464
+ `logs --failures`. When the log reads as a stale test database and the
1465
+ gate has no `fresh_cmd`, the error says that instead.
1466
+ - **`vinta-ai-maestro`: a late `node answer` says who answered first.** It
1467
+ is `409 not_awaiting_answer` naming who answered and when, not a bare
1468
+ `operation_failed`.
1469
+ - **`vinta-ai-maestro`: a stalled Docker daemon is not reported as a
1470
+ missing password.** A database command through docker that times out
1471
+ checks `docker info`, and blames the daemon when it is slow or down.
1472
+ - **`vinta-ai-maestro` on Windows: a cancelled `exec` ends.** Cancelling a
1473
+ command run through `vinta-ai-maestro exec` sent the polite tree kill,
1474
+ which on Windows closes the shell and orphans the command; the orphan
1475
+ kept the output pipes open and the cancel hung. The kill is forceful
1476
+ there, as it already was for a gate.
1477
+ - **`vinta-ai-maestro`: a failing database command names its cause from
1478
+ stdout too.** `cmd.exe`'s own commands report why they failed on stdout,
1479
+ so a lane reset whose template was missing said only "exited 1". The tail
1480
+ of stdout is the cause when stderr said nothing.
1481
+ - **`vinta-ai-maestro`: `doctor` labels workflow files with forward
1482
+ slashes on every platform** (`.github/workflows/ci.yml`, never
1483
+ `.github\workflows\ci.yml`).
1336
1484
  - **`vinta-ai-maestro`: a review chore can no longer leave the lane dirty.**
1337
1485
  Whatever a review leaves uncommitted, such as a mutation experiment's
1338
1486
  reverted migration or a generated file, is set aside under a
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vinta-ai-workflows",
3
- "version": "0.7.0-alpha37",
3
+ "version": "0.7.0-alpha39",
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": {
@@ -470,6 +470,14 @@
470
470
  "type": "string",
471
471
  "minLength": 1
472
472
  },
473
+ "fresh_when": {
474
+ "description": "Globs, relative to the repository root, of the files the state `fresh_cmd` recreates is built from — the migrations, typically (e.g. `apps/*/migrations/*.py`). When a file that matched at the gate's last run in the integration worktree is gone or different now, the gate runs `fresh_cmd` even though the tree moved forward: a reused database keeps a migration that was rewritten or renamed under it. Files added since do not count. Ignored without `fresh_cmd`.",
475
+ "type": "array",
476
+ "items": {
477
+ "type": "string",
478
+ "minLength": 1
479
+ }
480
+ },
473
481
  "cold_cmd": {
474
482
  "description": "What a phase gate runs in place of `scoped_cmd` when the lane lacks a `scope_cache` file (e.g. `make test`, the suite in parallel, instead of a `--testmon` run that without `.testmondata` runs every test serially). Defaults to `cmd`. Must check at least what `scoped_cmd` does.",
475
483
  "type": "string",
@@ -537,6 +545,14 @@
537
545
  "type": "string",
538
546
  "minLength": 1
539
547
  },
548
+ "fresh_when": {
549
+ "description": "Globs, relative to the repository root, of the files the state `fresh_cmd` recreates is built from — the migrations, typically (e.g. `apps/*/migrations/*.py`). When a file that matched at the gate's last run in the integration worktree is gone or different now, the gate runs `fresh_cmd` even though the tree moved forward: a reused database keeps a migration that was rewritten or renamed under it. Files added since do not count. Ignored without `fresh_cmd`.",
550
+ "type": "array",
551
+ "items": {
552
+ "type": "string",
553
+ "minLength": 1
554
+ }
555
+ },
540
556
  "cold_cmd": {
541
557
  "description": "What a phase gate runs in place of `scoped_cmd` when the lane lacks a `scope_cache` file (e.g. `make test`, the suite in parallel, instead of a `--testmon` run that without `.testmondata` runs every test serially). Defaults to `cmd`. Must check at least what `scoped_cmd` does.",
542
558
  "type": "string",
@@ -604,6 +620,14 @@
604
620
  "type": "string",
605
621
  "minLength": 1
606
622
  },
623
+ "fresh_when": {
624
+ "description": "Globs, relative to the repository root, of the files the state `fresh_cmd` recreates is built from — the migrations, typically (e.g. `apps/*/migrations/*.py`). When a file that matched at the gate's last run in the integration worktree is gone or different now, the gate runs `fresh_cmd` even though the tree moved forward: a reused database keeps a migration that was rewritten or renamed under it. Files added since do not count. Ignored without `fresh_cmd`.",
625
+ "type": "array",
626
+ "items": {
627
+ "type": "string",
628
+ "minLength": 1
629
+ }
630
+ },
607
631
  "cold_cmd": {
608
632
  "description": "What a phase gate runs in place of `scoped_cmd` when the lane lacks a `scope_cache` file (e.g. `make test`, the suite in parallel, instead of a `--testmon` run that without `.testmondata` runs every test serially). Defaults to `cmd`. Must check at least what `scoped_cmd` does.",
609
633
  "type": "string",
@@ -671,6 +695,14 @@
671
695
  "type": "string",
672
696
  "minLength": 1
673
697
  },
698
+ "fresh_when": {
699
+ "description": "Globs, relative to the repository root, of the files the state `fresh_cmd` recreates is built from — the migrations, typically (e.g. `apps/*/migrations/*.py`). When a file that matched at the gate's last run in the integration worktree is gone or different now, the gate runs `fresh_cmd` even though the tree moved forward: a reused database keeps a migration that was rewritten or renamed under it. Files added since do not count. Ignored without `fresh_cmd`.",
700
+ "type": "array",
701
+ "items": {
702
+ "type": "string",
703
+ "minLength": 1
704
+ }
705
+ },
674
706
  "cold_cmd": {
675
707
  "description": "What a phase gate runs in place of `scoped_cmd` when the lane lacks a `scope_cache` file (e.g. `make test`, the suite in parallel, instead of a `--testmon` run that without `.testmondata` runs every test serially). Defaults to `cmd`. Must check at least what `scoped_cmd` does.",
676
708
  "type": "string",
@@ -741,6 +773,14 @@
741
773
  "type": "string",
742
774
  "minLength": 1
743
775
  },
776
+ "fresh_when": {
777
+ "description": "Globs, relative to the repository root, of the files the state `fresh_cmd` recreates is built from — the migrations, typically (e.g. `apps/*/migrations/*.py`). When a file that matched at the gate's last run in the integration worktree is gone or different now, the gate runs `fresh_cmd` even though the tree moved forward: a reused database keeps a migration that was rewritten or renamed under it. Files added since do not count. Ignored without `fresh_cmd`.",
778
+ "type": "array",
779
+ "items": {
780
+ "type": "string",
781
+ "minLength": 1
782
+ }
783
+ },
744
784
  "cold_cmd": {
745
785
  "description": "What a phase gate runs in place of `scoped_cmd` when the lane lacks a `scope_cache` file (e.g. `make test`, the suite in parallel, instead of a `--testmon` run that without `.testmondata` runs every test serially). Defaults to `cmd`. Must check at least what `scoped_cmd` does.",
746
786
  "type": "string",
@@ -816,6 +856,14 @@
816
856
  "semaphore"
817
857
  ]
818
858
  },
859
+ "scope": {
860
+ "description": "`run` (the default) counts this run's holders only; `host` also counts every other maestro run on the machine holding a pool of the same name, so two runs on one laptop take turns at the full suite.",
861
+ "type": "string",
862
+ "enum": [
863
+ "run",
864
+ "host"
865
+ ]
866
+ },
819
867
  "match": {
820
868
  "type": "array",
821
869
  "items": {
@@ -638,6 +638,14 @@
638
638
  ],
639
639
  "description": "`worktree` pools are provisioned lanes; `semaphore` pools are pure counters."
640
640
  },
641
+ "scope": {
642
+ "description": "`run` — the default — counts only this run’s holders. `host` also counts every other run on this machine holding a pool of the same name, through lock files under `~/.vinta-ai-maestro/host-leases/` (`VINTA_AI_MAESTRO_HOST_LEASES` moves them), so two runs on one laptop take turns at the full suite instead of running two at once. Only meaningful on a `semaphore` pool.",
643
+ "type": "string",
644
+ "enum": [
645
+ "run",
646
+ "host"
647
+ ]
648
+ },
641
649
  "match": {
642
650
  "description": "Command patterns that need this pool — `pytest*`, `pnpm test*`. `*` matches any run of characters and the rest is literal, compared against the whole command line with whitespace collapsed. On a harness that can enforce it, an agent running a matching command without `vinta-ai-maestro with <pool> --` in front of it is refused and told to take the lease. A guardrail against habit, not a sandbox: `bash -c` or a script that runs the same suite is not seen. Only meaningful on a `semaphore` pool.",
643
651
  "type": "array",
@@ -710,6 +718,14 @@
710
718
  "type": "string",
711
719
  "minLength": 1
712
720
  },
721
+ "fresh_when": {
722
+ "description": "Globs, relative to the repository root, of the files the state `fresh_cmd` recreates is built from — the migrations, typically (`apps/*/migrations/*.py`). When a file that matched at the gate’s last run in the integration worktree is gone or different now, the gate runs `fresh_cmd` even though the tree moved forward: a reused database keeps a migration that was rewritten or renamed under it. Files added since do not count. Ignored without `fresh_cmd`.",
723
+ "type": "array",
724
+ "items": {
725
+ "type": "string",
726
+ "minLength": 1
727
+ }
728
+ },
713
729
  "requires": {
714
730
  "default": [],
715
731
  "description": "Resource pool ids acquired before the gate runs, in canonical order.",
@@ -903,6 +919,10 @@
903
919
  "after_pr"
904
920
  ]
905
921
  },
922
+ "background": {
923
+ "description": "`false` tells this chore’s turns to run every command in the foreground and wait for it, even on a harness that keeps a session alive for background work. For a review whose turns keep ending on \"waiting on the tests\" with no verdict. Absent, the harness decides.",
924
+ "type": "boolean"
925
+ },
906
926
  "on_failure": {
907
927
  "default": "continue",
908
928
  "description": "`continue` — the default — journals a failed chore and moves on. A chore is polish, and losing an implemented phase to one that timed out is the worse trade. `fail` is for a chore whose output the phase is not correct without. A `review` chore ignores it: a review that did not approve, for any reason, is put to the operator.",
@@ -110,9 +110,9 @@ These bleed across sub-skills, so capture once now:
110
110
  ```
111
111
 
112
112
  Show it as a proposed edit and apply it only on the user's yes.
113
- - **Fresh database in the integration worktree.** Only when the test command keeps its database between runs (`--reuse-db`, `--keepdb`, a fixture that skips migrations on an existing schema). Maestro's integration worktree runs merges for different branches one after another, and a reused database applies each tree's migrations on top of the last tree's — one observed run had three merges fail on columns and tables that belonged to another branch. `AskUserQuestion` (header `Fresh DB`): `Recreate the database there when the tree changes (Recommended)`, `Keep reusing it`. On the first, propose the fresh form of the command (`--create-db` in place of `--reuse-db`, or `make test_reset test`), confirm it, and emit it as `maestro.gates.test.fresh_cmd`, plus `tuning.allowed_flags: ['--create-db']` when the flag form fits, so the run coordinator can add the flag without being refused for rewriting the command.
113
+ - **Fresh database in the integration worktree.** Only when the test command keeps its database between runs (`--reuse-db`, `--keepdb`, a fixture that skips migrations on an existing schema). Maestro's integration worktree runs merges for different branches one after another, and a reused database applies each tree's migrations on top of the last tree's — one observed run had three merges fail on columns and tables that belonged to another branch. `AskUserQuestion` (header `Fresh DB`): `Recreate the database there when the tree changes (Recommended)`, `Keep reusing it`. On the first, propose the fresh form of the command (`--create-db` in place of `--reuse-db`, or `make test_reset test`), confirm it, and emit it as `maestro.gates.test.fresh_cmd`, plus `tuning.allowed_flags: ['--create-db']` when the flag form fits, so the run coordinator can add the flag without being refused for rewriting the command. Then name the migration files from the inventory as globs (`apps/*/migrations/*.py`, `db/migrate/*.rb`, `prisma/migrations/**`) and emit them as `maestro.gates.test.fresh_when`: a phase that rewrites or renames one of its own migrations moves the tree forward and still leaves a reused database recording the old one, and these globs are what tell maestro so. Offer them as candidates in the same confirmation rather than as a second question.
114
114
  - **When the full suite runs.** Only on `Yes` above. `AskUserQuestion`: `After each review and on every merged tree (Recommended)`, `Only on merged trees`, `Only on merged waves`. The first is the default and emits nothing. `Only on merged trees` skips the per-phase full run after review (`maestro.defaults.verify_gates: scoped`), for a suite too slow to run once per phase. `Only on merged waves` also leaves multi-dependency bases unchecked (`verify_gates: scoped` and `base_gates: off`).
115
- - **A test-suite pool.** `AskUserQuestion`: `One suite at a time (Recommended for DB-backed suites)`, `Two at a time`, `No limit`. A limit emits `maestro.resources.test-suite` (`kind: semaphore`, `capacity` 1 or 2) and `maestro.gates.test.requires: [test-suite]`. Then offer the runner's command patterns as the pool's `match` (`pytest*`, `uv run pytest*`, `pnpm test*`), which makes agents take the lease before running tests by hand.
115
+ - **A test-suite pool.** `AskUserQuestion`: `One suite at a time (Recommended for DB-backed suites)`, `Two at a time`, `No limit`. A limit emits `maestro.resources.test-suite` (`kind: semaphore`, `capacity` 1 or 2, `scope: host`) and `maestro.gates.test.requires: [test-suite]`. `scope: host` makes the limit hold across every maestro run on the machine, not just within one: two runs on one laptop, each with a one-suite limit, otherwise run two suites at once — the contention the limit exists to prevent. Then offer the runner's command patterns as the pool's `match` (`pytest*`, `uv run pytest*`, `pnpm test*`), which makes agents take the lease before running tests by hand.
116
116
  - **Files git does not carry.** A maestro lane is a worktree and has only what git tracks. Read `.gitignore` for entries with a tracked `*.example` / `*.sample` / `*.template` sibling, the compose file's `env_file:` lines, and the gitignored settings module the framework imports (`DJANGO_SETTINGS_MODULE`'s local module, typically). Propose the list in a multi-select `AskUserQuestion` (header `Env files`), each path pre-selected; the user confirms or drops entries. → `maestro.project.env_files`. Every hook, gate and `manage.py` call in a lane depends on these, and a plan that omits them fails in ways that look like code problems. Nothing found → omit the key and say so.
117
117
 
118
118
  - **Test-tool caches git must not carry.** Gates in a lane write cache and report files into the worktree, and an agent's `git add -A` there commits whatever is not ignored. Read `.gitignore` for the outputs of the runners and gates selected above: `.testmondata*` (pytest-testmon's SQLite database, plus its `-shm` / `-wal` siblings — tens of MB), `.pytest_cache/`, `junit/` or `junit*.xml`, `coverage/`, `.coverage`, `.coverage.*`, `htmlcov/`, `coverage.xml`, `.nyc_output/`, `.vitest/` and `.jest-cache/` where those runners are in use. Then read `.pre-commit-config.yaml` (or the project's hook runner) for `check-added-large-files`: that hook checks staged files, so a testmon database that is not ignored fails every lane commit and every maestro merge commit (`project.hooks: run`), and looks like a hook problem rather than a missing ignore rule. Propose the missing entries in a multi-select `AskUserQuestion` (header `Cache ignores`), each pre-selected, with `Add the selected entries (Recommended)` meaning append them to `.gitignore` under a `# test-tool caches` comment. When one is already tracked, say so: ignoring it does not untrack it, and the human runs `git rm --cached <path>` themselves. Nothing missing → say so and add nothing.
@@ -387,6 +387,7 @@ maestro:
387
387
  test:
388
388
  cmd: <C.11 → maestro-only test command; omit to use commands.test_unit>
389
389
  fresh_cmd: <C.11 "Fresh database in the integration worktree" → the same command from a fresh test database, e.g. pytest --create-db -n auto; omit when the suite keeps no database between runs>
390
+ fresh_when: <C.11 "Fresh database in the integration worktree" → globs of the migration files, e.g. ['apps/*/migrations/*.py']; only alongside fresh_cmd>
390
391
  tuning:
391
392
  allowed_flags: <C.11 → ['--create-db'] alongside fresh_cmd, so the coordinator may add it; omit otherwise>
392
393
  cold_cmd: <C.11 "Cold lanes" → what runs while a lane has no scope cache, e.g. the parallel full suite; omit when the scoped template needs no cache>
@@ -396,6 +397,7 @@ maestro:
396
397
  test-suite: # only on a pool limit
397
398
  capacity: <1 | 2>
398
399
  kind: semaphore
400
+ scope: host
399
401
  match: <C.11 → runner command patterns, e.g. ['pytest*', 'uv run pytest*']>
400
402
  codegen: # C.11 → generators and file-modifying hooks; omit when none
401
403
  <step-id>: