scripts: land-work turns a resolved merge decision into a gated local commit (row 116, #1610)

Candidate manifest 8b4ab31014a124ec0e3abba44238976d6f4c9af48cbdb36c2c77d18f0137f888
from Darkwing's round 2 packet (0a4076e8e), on BASE 1223a0f37. No
manifest path changed between BASE and the landing target. Filbert
approved round 2 in 28468, closing C1 and D1 from round 1 (28464).
Sage reran the full gate at the landing target with the candidate
applied. The replay acceptance follows ruling sage-0204.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
2026-10-14 14:24:57 -05:00
co-authored by Claude Opus 5.5
parent 922cb8170b
commit 1f2ac5b848
6 changed files with 1021 additions and 0 deletions
+29
View File
@@ -118,6 +118,34 @@ succeeded run → clean target tree → path allowlist → syntax gates →
apply → policy suites → attribution commit. Any failure reverts.
Push is never automatic.
## Conductor (landing approved work)
```bash
scripts/land-work.sh <decision-id> [--base refactor] [--dry-run] [--subject TEXT]
[--attribution LINE] [--business ID] [--project ID]
```
Turns a merge decision the human resolved into one gated local commit on
`refactor` (#1610). It reads `<dataRoot>/bus/bus.sqlite` read-only through
`scripts/land-work/read.mjs` and checks that the human picked the raise's
approval option, that the question names one `work/vikunja-<p>-<t>`, and
that the task's latest `review.verdict` approves a commit C that the work
ref in the working repository still points at. It then applies
`git diff $(merge-base refactor C) C` in a detached worktree, checks the
patch-id, runs every package suite except `queue` and every
`scripts/test-*.sh`, and commits. The subject is the approval option's
text unless `--subject` overrides it, and `--attribution` replaces the last
line, `Applied-under: scripts/land-work.sh (conductor)`. `--business` and
`--project` are needed only when the config has more than one business file
or the business more than one project. The tool prints the line for the PM
and doesn't send it. `--dry-run` runs every check and the gate and writes
no ref. A refusal names its reason and exits 2; the reasons are listed at
the top of the script. The worktree, its `node_modules` link and its Docker
network are removed on every exit. The gate log directory stays and the
tool names it. Keep `TMPDIR` short: the gate inherits it, the cli suite
puts unix sockets under it, and a 46-byte `TMPDIR` failed 8 of those tests.
Push is a separate act.
## Maintenance
| Command | Purpose | Notes |
@@ -128,6 +156,7 @@ Push is never automatic.
| `scripts/test-release.sh` | Release selftests | 14 cases |
| `scripts/test-conductor.sh` | Auto-apply selftests (sandboxed) | 17 cases |
| `scripts/test-auth.sh` | Auth checkpoint selftests (no Docker) | 13 cases |
| `scripts/test-land-work.sh` | Land-work selftests (sandboxed, fake Docker) | 84 cases |
| `scripts/gitea-api.sh <METHOD> <path> [body]` | Gitea API helper; reads the JSON credential file or a raw per-seat token file | Token never on argv/stdout |
## Seat launch with registration (`scripts/mosaic`)