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
|
@@ -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>:
|