@caddis/cli 0.4.52 → 0.4.53
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/bundles/antigravity-plugin/CADDIS-GLOSSARY.md +1 -0
- package/bundles/antigravity-plugin/plugin.json +1 -1
- package/bundles/antigravity-plugin/repo_freshness.py +132 -5
- package/bundles/antigravity-plugin/scripts/caddis_checkout_guard.py +223 -0
- package/bundles/antigravity-plugin/scripts/caddis_docs_pr.py +284 -0
- package/bundles/antigravity-plugin/scripts/caddis_exit.py +2 -0
- package/bundles/antigravity-plugin/scripts/caddis_frontmatter.py +1 -0
- package/bundles/antigravity-plugin/scripts/caddis_gate.py +226 -195
- package/bundles/antigravity-plugin/scripts/caddis_glossary.py +3 -3
- package/bundles/antigravity-plugin/scripts/caddis_governor.py +48 -4
- package/bundles/antigravity-plugin/scripts/caddis_inventory.py +38 -0
- package/bundles/antigravity-plugin/scripts/caddis_lanes.py +294 -127
- package/bundles/antigravity-plugin/scripts/caddis_lineage_publish.py +458 -0
- package/bundles/antigravity-plugin/scripts/caddis_merge_chain.py +237 -0
- package/bundles/antigravity-plugin/scripts/caddis_notify.py +121 -0
- package/bundles/antigravity-plugin/scripts/caddis_prod_check.py +380 -0
- package/bundles/antigravity-plugin/scripts/caddis_redact.py +99 -0
- package/bundles/antigravity-plugin/scripts/caddis_relay_git.py +2 -2
- package/bundles/antigravity-plugin/scripts/caddis_review.py +1309 -0
- package/bundles/antigravity-plugin/scripts/caddis_roadmap.py +2056 -0
- package/bundles/antigravity-plugin/scripts/caddis_roadmap_run.py +2572 -0
- package/bundles/antigravity-plugin/scripts/caddis_routing.py +3 -2
- package/bundles/antigravity-plugin/scripts/caddis_rows.py +476 -0
- package/bundles/antigravity-plugin/scripts/caddis_spawn.py +8 -9
- package/bundles/antigravity-plugin/scripts/caddis_spend.py +415 -0
- package/bundles/antigravity-plugin/scripts/caddis_tidy.py +357 -20
- package/bundles/antigravity-plugin/scripts/caddis_todo.py +55 -0
- package/bundles/antigravity-plugin/scripts/caddis_workstreams.py +178 -19
- package/bundles/antigravity-plugin/scripts/caddis_worktree_close.py +349 -0
- package/bundles/antigravity-plugin/scripts/check_doc_coverage.py +0 -56
- package/bundles/antigravity-plugin/scripts/claudster_doctor.py +1 -1
- package/bundles/antigravity-plugin/scripts/enforcement_inventory.py +0 -1
- package/bundles/antigravity-plugin/scripts/oss_review.py +2 -2
- package/bundles/antigravity-plugin/scripts/roadmap-recheck.ps1 +89 -0
- package/bundles/antigravity-plugin/scripts/roadmap-run.ps1 +88 -0
- package/bundles/antigravity-plugin/scripts/setup_project_ai.py +43 -1
- package/bundles/antigravity-plugin/session_end_agy.py +3 -3
- package/bundles/antigravity-plugin/skills/_registry.md +2 -6
- package/bundles/antigravity-plugin/skills/best-practices/agents/best-practices-referencer.md +1 -1
- package/bundles/antigravity-plugin/skills/best-practices/agents/codebase-context-builder.md +1 -1
- package/bundles/antigravity-plugin/skills/best-practices/agents/task-intent-analyzer.md +1 -1
- package/bundles/antigravity-plugin/skills/catchup/SKILL.md +7 -0
- package/bundles/antigravity-plugin/skills/cloud-phases/SKILL.md +1 -1
- package/bundles/antigravity-plugin/skills/cross-review/SKILL.md +5 -2
- package/bundles/antigravity-plugin/skills/feature-plan/SKILL.md +29 -83
- package/bundles/antigravity-plugin/skills/handoff/SKILL.md +77 -48
- package/bundles/antigravity-plugin/skills/implement/SKILL.md +87 -147
- package/bundles/antigravity-plugin/skills/migrate-dir/SKILL.md +1 -1
- package/bundles/antigravity-plugin/skills/mmr/SKILL.md +5 -2
- package/bundles/antigravity-plugin/skills/office-documents-official/SKILL.md +24 -0
- package/bundles/antigravity-plugin/skills/park/SKILL.md +0 -1
- package/bundles/antigravity-plugin/skills/pr-merge/SKILL.md +8 -14
- package/bundles/antigravity-plugin/skills/prd/SKILL.md +2 -10
- package/bundles/antigravity-plugin/skills/roadmap/SKILL.md +259 -0
- package/bundles/antigravity-plugin/skills/roadmap/assets/plan-resume-prompt.md +77 -0
- package/bundles/antigravity-plugin/skills/roadmap/assets/render-check.template.mjs +68 -0
- package/bundles/antigravity-plugin/skills/roadmap/assets/review-protocol.md +78 -0
- package/bundles/antigravity-plugin/skills/roadmap/assets/roadmap.template.md +32 -0
- package/bundles/antigravity-plugin/skills/roadmap/assets/value-check.template.py +161 -0
- package/bundles/antigravity-plugin/skills/ship/SKILL.md +14 -14
- package/bundles/antigravity-plugin/skills/ship-merge/SKILL.md +6 -0
- package/bundles/antigravity-plugin/skills/ship-pr/SKILL.md +33 -14
- package/bundles/antigravity-plugin/skills/spawn-session/SKILL.md +4 -8
- package/bundles/antigravity-plugin/warm_start_agy.py +1 -3
- package/bundles/antigravity-plugin-extras/plugin.json +1 -1
- package/bundles/antigravity-plugin-extras/skills/_registry.md +1 -2
- package/bundles/antigravity-plugin-extras/skills/agent-orchestration/SKILL.md +5 -5
- package/bundles/antigravity-plugin-extras/skills/cross-review/SKILL.md +5 -2
- package/bundles/antigravity-plugin-extras/skills/runner-move/SKILL.md +214 -0
- package/bundles/codex/.codex/skills/docs/office-documents-official/SKILL.md +24 -0
- package/bundles/codex/.codex/skills/workflow/best-practices/agents/best-practices-referencer.md +1 -1
- package/bundles/codex/.codex/skills/workflow/best-practices/agents/codebase-context-builder.md +1 -1
- package/bundles/codex/.codex/skills/workflow/best-practices/agents/task-intent-analyzer.md +1 -1
- package/bundles/codex/.codex/skills/workflow/roadmap/SKILL.md +259 -0
- package/bundles/codex/.codex/skills/workflow/roadmap/assets/plan-resume-prompt.md +77 -0
- package/bundles/codex/.codex/skills/workflow/roadmap/assets/render-check.template.mjs +68 -0
- package/bundles/codex/.codex/skills/workflow/roadmap/assets/review-protocol.md +78 -0
- package/bundles/codex/.codex/skills/workflow/roadmap/assets/roadmap.template.md +32 -0
- package/bundles/codex/.codex/skills/workflow/roadmap/assets/value-check.template.py +161 -0
- package/bundles/codex/AGENTS.md +5 -4
- package/bundles/manifest.json +3 -3
- package/package.json +1 -1
- package/bundles/antigravity-plugin/skills/advisory-hub/SKILL.md +0 -233
- package/bundles/antigravity-plugin/skills/advisory-hub/reference/context-template.md +0 -214
- package/bundles/antigravity-plugin/skills/advisory-hub/reference/hub-handbook.md +0 -233
- package/bundles/antigravity-plugin/skills/advisory-hub/reference/report-contract.md +0 -94
- package/bundles/antigravity-plugin/skills/advisory-hub/reference/succession.md +0 -118
- package/bundles/antigravity-plugin/skills/resume/SKILL.md +0 -6
- package/bundles/antigravity-plugin/skills/review/SKILL.md +0 -6
- package/bundles/antigravity-plugin/skills/spawn-hub/SKILL.md +0 -341
- package/bundles/antigravity-plugin/skills/statusline/SKILL.md +0 -6
- package/bundles/antigravity-plugin/skills/validate-phase/SKILL.md +0 -143
- package/bundles/antigravity-plugin-extras/skills/data-lineage/SKILL.md +0 -158
- package/bundles/antigravity-plugin-extras/skills/data-lineage/scripts/convert_doc_to_confluence.py +0 -1430
- package/bundles/antigravity-plugin-extras/skills/golden-plan/SKILL.md +0 -586
- package/bundles/codex/.codex/skills/workflow/advisory-hub/SKILL.md +0 -233
- package/bundles/codex/.codex/skills/workflow/advisory-hub/reference/context-template.md +0 -214
- package/bundles/codex/.codex/skills/workflow/advisory-hub/reference/hub-handbook.md +0 -233
- package/bundles/codex/.codex/skills/workflow/advisory-hub/reference/report-contract.md +0 -94
- package/bundles/codex/.codex/skills/workflow/advisory-hub/reference/succession.md +0 -118
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: office-documents-official
|
|
3
|
+
description: Hint for Office and PDF file work. Use when the user asks to create, edit, read or convert a Word .docx, PDF, PowerPoint .pptx or Excel .xlsx file. caddis does not ship these skills; points to Anthropic's official document-skills plugin.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Office and PDF files: use Anthropic's document-skills
|
|
7
|
+
|
|
8
|
+
caddis does not include skills for Word (.docx), PDF, PowerPoint (.pptx) or Excel (.xlsx) files.
|
|
9
|
+
These skills belong to Anthropic. Anthropic publishes them as the `document-skills` plugin.
|
|
10
|
+
|
|
11
|
+
## Install (Claude Code)
|
|
12
|
+
|
|
13
|
+
```
|
|
14
|
+
/plugin marketplace add anthropics/skills
|
|
15
|
+
/plugin install document-skills@anthropic-agent-skills
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
Source: https://github.com/anthropics/skills (see its README, section "Claude Code").
|
|
19
|
+
|
|
20
|
+
## What to do
|
|
21
|
+
|
|
22
|
+
1. If the plugin is installed, use its `docx`, `pdf`, `pptx` or `xlsx` skill for the file type. Do not work from this note.
|
|
23
|
+
2. If the plugin is not installed, tell the user the two commands above. Then ask if they want to install it first.
|
|
24
|
+
3. If the user cannot install it, say what you can do without it. For example, write the content as Markdown and let the user convert it.
|
package/bundles/codex/.codex/skills/workflow/best-practices/agents/best-practices-referencer.md
CHANGED
|
@@ -44,7 +44,7 @@ description: >-
|
|
|
44
44
|
constraints pattern, and surfaces anti-patterns around breaking changes.
|
|
45
45
|
</commentary>
|
|
46
46
|
</example>
|
|
47
|
-
model:
|
|
47
|
+
model: sonnet
|
|
48
48
|
---
|
|
49
49
|
|
|
50
50
|
**Note: The current year is 2026.** Use this when searching for recent documentation and patterns.
|
package/bundles/codex/.codex/skills/workflow/best-practices/agents/codebase-context-builder.md
CHANGED
|
@@ -46,7 +46,7 @@ description: >-
|
|
|
46
46
|
finds slow query examples, and identifies existing performance tests.
|
|
47
47
|
</commentary>
|
|
48
48
|
</example>
|
|
49
|
-
model:
|
|
49
|
+
model: sonnet
|
|
50
50
|
---
|
|
51
51
|
|
|
52
52
|
**Note: The current year is 2026.** Use this when referencing recent patterns or documentation.
|
|
@@ -48,7 +48,7 @@ description: >-
|
|
|
48
48
|
considerations: caching, N+1 queries, database indexes, async processing.
|
|
49
49
|
</commentary>
|
|
50
50
|
</example>
|
|
51
|
-
model:
|
|
51
|
+
model: sonnet
|
|
52
52
|
---
|
|
53
53
|
|
|
54
54
|
**Note: The current year is 2026.** Use this when referencing recent patterns or documentation.
|
|
@@ -0,0 +1,259 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: roadmap
|
|
3
|
+
description: "Track milestones across plans in .caddis/roadmaps/<slug>/: next batch, typed blockers, rollup. Every change is a docs PR via caddis_roadmap.py."
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Roadmap
|
|
7
|
+
|
|
8
|
+
**Core rule:** the roadmap file on `origin/main` is the only truth; every change to it, by a tool or a human, is a
|
|
9
|
+
small docs PR, so it is ordered and recorded in git history. The tool's PRs are merged automatically on green checks
|
|
10
|
+
by `caddis_merge_chain.py --docs-only`; a repo that wants a human to review them protects its default branch.
|
|
11
|
+
|
|
12
|
+
`scripts/` below is the caddis scripts folder: `${CLAUDE_PLUGIN_ROOT}/scripts` in an installed plugin, `scripts/` in
|
|
13
|
+
the caddis source repo.
|
|
14
|
+
|
|
15
|
+
## The folder
|
|
16
|
+
|
|
17
|
+
`.caddis/roadmaps/<slug>/` holds:
|
|
18
|
+
|
|
19
|
+
| Path | What |
|
|
20
|
+
|---|---|
|
|
21
|
+
| `roadmap.md` | Milestones and Blockers tables (start from `assets/roadmap.template.md`) |
|
|
22
|
+
| `decisions.md` | decision register; a `Depends on` change cites an id from here |
|
|
23
|
+
| `cards/` | one **card** per unit of work handed to a lane or a reviewer: scope, files, pass criteria |
|
|
24
|
+
| `reports/` | what comes back from a card |
|
|
25
|
+
| `.local/` | machine-local: `changes.jsonl` (audit of the tool's PRs), the runner's `runner.jsonl` and `STOP` (its lock and other state are in `<git common dir>/caddis-runner/roadmap-<slug>/`) |
|
|
26
|
+
|
|
27
|
+
Plans stay in `.caddis/plans/`. Add `.caddis/roadmaps/*/.local/` to the repo's `.gitignore`. The write lock is not in
|
|
28
|
+
the folder: it is `<git common dir>/caddis-roadmaps/<slug>.write.lock`, so every worktree of the repo shares it.
|
|
29
|
+
|
|
30
|
+
## The format
|
|
31
|
+
|
|
32
|
+
```markdown
|
|
33
|
+
Runner host: <runner-host>
|
|
34
|
+
|
|
35
|
+
## Milestones
|
|
36
|
+
| ID | Milestone | Phases | Depends on | Exit check | Status | Owner | Target |
|
|
37
|
+
|---|---|---|---|---|---|---|---|
|
|
38
|
+
| S1 | Lines load | p-alpha#1, p-alpha#2 | - | `python scripts/check_s1.py` | todo | runner | WD3 |
|
|
39
|
+
|
|
40
|
+
## Blockers
|
|
41
|
+
| Milestone | Type | Reason | Check |
|
|
42
|
+
|---|---|---|---|
|
|
43
|
+
| S2 | data-condition | GPU rows not loaded | `python scripts/rows_ready.py` |
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
- **Status:** `todo`, `in-progress`, `code-done/data-pending`, `done`, `not-needed`. There is no `blocked` status: a
|
|
47
|
+
milestone is blocked when it has a Blockers row.
|
|
48
|
+
- **Blocker types:** `owner-gate`, `external`, `shared` (a shared file, the GPU, the merge line, another session),
|
|
49
|
+
`calendar`, `data-condition`. A new `calendar` blocker needs an ISO date `YYYY-MM-DD` in Check
|
|
50
|
+
(`block --type calendar --check 2026-11-01`); a date is not a command, so it needs no `--by-owner`.
|
|
51
|
+
- **Owner:** `runner` (or empty) lets the runner take it; a session name means that session does it by hand.
|
|
52
|
+
- **Phase ref** `p-alpha#2` = Phase 2 in the Tracker of `.caddis/plans/p-alpha.md` or `.caddis/plans/done/p-alpha.md`.
|
|
53
|
+
It is done only when its Tracker Status starts with `done` or a check mark **on origin**. Refs work inside one repo.
|
|
54
|
+
- **Runner host:** the one machine whose runner may run this roadmap. Write a placeholder such as `HOSTNAME` in
|
|
55
|
+
shared examples.
|
|
56
|
+
- A `Depends on` change cites a decision id in the Milestone cell: `S9 (dep waived: TC94)`. `check` warns otherwise.
|
|
57
|
+
- **Strict sections.** `## Milestones` and `## Blockers` hold only blank lines, one table whose every line starts with
|
|
58
|
+
`|`, and prose with no unescaped `|` set apart from the table by a blank line. Anything else is a parse error.
|
|
59
|
+
A roadmap allows only headings, plain paragraphs, lists and pipe tables: no code fences, no HTML, no setext
|
|
60
|
+
headings, no control or non-ASCII whitespace characters.
|
|
61
|
+
- **A malformed roadmap fails closed.** A row with the wrong cell count, a `|` line outside a table, a near-miss
|
|
62
|
+
heading such as `## Blockers (open)`, an id that is not `[A-Za-z0-9_-]+`, an unknown Status or blocker type, or a
|
|
63
|
+
phase ref to a missing plan: every command but `check` exits 4 and prints the errors. Fix the file by a PR.
|
|
64
|
+
|
|
65
|
+
## Commands
|
|
66
|
+
|
|
67
|
+
Every command runs `git fetch origin` and reads `origin/<default>`, never the working tree. Exit check and Check
|
|
68
|
+
commands run in a temporary worktree of `origin/<default>` (the merged code), with no stdin, killed with their whole
|
|
69
|
+
process tree on timeout.
|
|
70
|
+
|
|
71
|
+
```bash
|
|
72
|
+
python scripts/caddis_roadmap.py status --roadmap <slug> [--json] # "<done> of <total> done; next <id>; ..."
|
|
73
|
+
python scripts/caddis_roadmap.py next --roadmap <slug> [--json] # exit 0 found, 1 nothing ready (reasons)
|
|
74
|
+
python scripts/caddis_roadmap.py check --roadmap <slug> # parse errors, unknown refs or types
|
|
75
|
+
python scripts/caddis_roadmap.py set --roadmap <slug> --id S1 --col Status|Owner|Target --value <v> [--by-owner] [--reason "<r>"]
|
|
76
|
+
python scripts/caddis_roadmap.py block --roadmap <slug> --id S2 --type <type> --reason "<text>" [--check "<cmd>" --by-owner]
|
|
77
|
+
python scripts/caddis_roadmap.py unblock --roadmap <slug> --id S2 --type <type> --reason "<text>" [--check "<cmd>"] [--by-owner]
|
|
78
|
+
python scripts/caddis_roadmap.py rollup --roadmap <slug> --id S1
|
|
79
|
+
python scripts/caddis_roadmap.py recheck --roadmap <slug>
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
`next` picks the first milestone in table order that is `todo` or `in-progress`, whose `Depends on` are all `done` or
|
|
83
|
+
`not-needed`, with no Blockers row, Owner `runner` or empty, and a phase not yet merged. It returns that phase.
|
|
84
|
+
|
|
85
|
+
## Rules a runner trusts
|
|
86
|
+
|
|
87
|
+
- **Only `rollup` writes `done`.** `set --value done` exits 4. `rollup` needs every phase merged on origin, every
|
|
88
|
+
`Depends on` milestone `done` or `not-needed`, and no open blocker other than `data-condition` (exit 1 names it),
|
|
89
|
+
then runs the Exit check (300 s): pass -> `done`; fail with a `data-condition` blocker -> `code-done/data-pending`;
|
|
90
|
+
fail otherwise -> an `external` blocker
|
|
91
|
+
`exit check failing (exit <n>)` (never the command's output). A milestone with no phase refs and no Exit check is
|
|
92
|
+
refused (exit 4).
|
|
93
|
+
- **Owner-only changes:** `set` Status `not-needed`, any `set` Owner, `unblock` of an `owner-gate`, and `block --check`
|
|
94
|
+
(recheck runs that command unattended later). They need `--by-owner` and are refused headless: `CADDIS_HEADLESS`
|
|
95
|
+
or `CLAUDECODE` in the environment (even empty), stdin not a terminal, or on
|
|
96
|
+
Windows stdin not a console (a NUL stdin is headless).
|
|
97
|
+
- **`unblock` removes one blocker.** When two rows share milestone, type and reason, it exits 4 until `--check`
|
|
98
|
+
names the row's Check text.
|
|
99
|
+
- **`recheck` clears `data-condition` blockers**, each row whose own Check passed (120 s), **and `calendar`
|
|
100
|
+
blockers whose Check date has passed** (UTC; no command runs). A `calendar` row whose Check is `-` stays until
|
|
101
|
+
someone runs `unblock`. Other types stay.
|
|
102
|
+
- **`not-needed` needs a reason.** `set --col Status --value not-needed --by-owner` also needs
|
|
103
|
+
`--reason "dropped: <why>"` or `--reason .caddis/parking-lot/<file>.md` (the file must be on origin). A reason with
|
|
104
|
+
`|` or a line break exits 4. The same docs PR adds `- <id> not-needed: <reason> (YYYY-MM-DD)` under `## Notes`
|
|
105
|
+
(the section is added at the end when missing).
|
|
106
|
+
- **Old blockers are listed.** `status` (and so the runner's toast) ends with
|
|
107
|
+
`old blockers: <id> <type> (<N> days), ...`, oldest first, for each blocker row older than 14 days. The age is the
|
|
108
|
+
date of the newest commit on origin that added that exact row (`git log -S`): the roadmap never stores a date, and
|
|
109
|
+
a row that was cleared and added again counts from the new add.
|
|
110
|
+
- **Commands run the merged code.** Editing a check script or a Check in the working tree changes nothing until it
|
|
111
|
+
merges.
|
|
112
|
+
|
|
113
|
+
## How a write lands
|
|
114
|
+
|
|
115
|
+
`set`, `block`, `unblock`, `rollup` and `recheck` take the write lock (after 30 s, a lock whose holder is dead on
|
|
116
|
+
this host, or an empty or non-JSON lock older than 60 s, is taken over), branch `roadmap/<slug>-<id>-<utc>` from
|
|
117
|
+
`origin/<default>` in a temp worktree, commit `docs(roadmap): <slug> <id> <change>`, push, open a PR, and hand it to
|
|
118
|
+
`caddis_merge_chain.py --docs-only`. `gh` uses the account in `GH_TOKEN` when it is set. Git network calls time out
|
|
119
|
+
after 120 s, `gh` after 60 s and the merge chain after 1800 s (exit 3); none can wait on a credential prompt. `--dry-run` prints the diff
|
|
120
|
+
and `would run: <cmd>` lines, and runs and writes nothing. Exit codes: 0 clean, 1 blocked, 3 could not run, 4 error
|
|
121
|
+
(malformed roadmap, refused change, bad usage).
|
|
122
|
+
|
|
123
|
+
## The runner
|
|
124
|
+
|
|
125
|
+
`roadmap-run.ps1 -Roadmap <slug>` (a shim over `scripts/caddis_roadmap_run.py --roadmap <slug>`) runs the roadmap
|
|
126
|
+
unattended; `-Plan <slug>` runs one plain plan instead (the two are exclusive). It starts only on the roadmap's
|
|
127
|
+
`Runner host` (else exit 3). Each iteration:
|
|
128
|
+
|
|
129
|
+
1. `next`. Nothing ready: stop `BLOCKED nothing ready` (exit 1); the notification carries the `status` line. When
|
|
130
|
+
the roadmap is finished (every milestone `done` or `not-needed`) the runner also removes its worktree if it is
|
|
131
|
+
clean (only session relay files left), and keeps it, saying so in the stop line, if not. With the worktree gone it
|
|
132
|
+
also deletes the local `caddis/roadmap/<slug>/*` branches merged into `origin/<default>` and names the others.
|
|
133
|
+
2. Print `next: <milestone> <plan>#<phase>` (`next` and the batch claim happen under one repo-level claim lock).
|
|
134
|
+
A phase whose `**Lane:**` line does not start with this engine (`claude`, `agy`, `codex`), names a cloud session
|
|
135
|
+
or the owner, or that has **no Lane line**, is not run (fail closed): the runner adds
|
|
136
|
+
`block --type owner-gate --reason "phase <n> lane: <lane>"` (`lane: none` when there is no line) and goes on.
|
|
137
|
+
3. A `todo` milestone is set `in-progress` (a docs PR). Every session of a roadmap runs in ONE dedicated worktree,
|
|
138
|
+
`%TEMP%/caddis-roadmap-<slug>-<8 hex of the repo's git common dir>`: made with `git worktree add --detach` from `origin/<default>` on the first
|
|
139
|
+
session, reused on restart, recorded in the runner folder, never the `-Repo` checkout (plan mode keeps working in
|
|
140
|
+
the given checkout). In that worktree the runner makes a fresh branch `caddis/roadmap/<slug>/<plan>-p<n>` from
|
|
141
|
+
`origin/<default>` (it refuses a branch of that name already on origin that it did not make) and ONE session runs
|
|
142
|
+
`assets/plan-resume-prompt.md` on it (if a blocked session left uncommitted work in the worktree, the runner
|
|
143
|
+
stops `BLOCKED roadmap worktree has uncommitted work from <branch>` instead, and a session branch that already
|
|
144
|
+
holds commits not on `origin/<default>` is never reset: `BLOCKED <branch> has unpublished commits from an earlier
|
|
145
|
+
session`; the owner decides), with `{{slug}}` = the plan and
|
|
146
|
+
`{{phase}}` = the phase. Every session gets its own fresh branch (also after an OWNER-GATE or BLOCKED one), so a
|
|
147
|
+
blocked phase's commits never reach another PR. Sessions stay on that branch and never push.
|
|
148
|
+
4. Relay `STATUS: CONTINUE` with new commits on that branch: the **runner** checks that the session is still on it
|
|
149
|
+
and did not touch `.caddis/roadmaps/` (else `FAILED`, nothing published), then, in this order: writes a persistent
|
|
150
|
+
claim `<git common dir>/caddis-runner/claims/<plan>#<n>.json`, pushes the branch, opens a PR (`gh api`, the account
|
|
151
|
+
from `GH_TOKEN`) titled `<plan> phase <n>: <phase title>`, writes the PR URL into the claim, records the wait in its
|
|
152
|
+
runner folder's `waiting.json` (ref, PR, milestone, branch, claim and its hash, the roadmap hash; never in the last
|
|
153
|
+
stop), and stops `BLOCKED waiting for merge <plan>#<phase> <pr url>` (exit 1). A run killed between the claim and
|
|
154
|
+
`waiting.json` leaves a claim nothing names: the next start stops on it as an orphaned claim. On restart, GitHub
|
|
155
|
+
must confirm the PR merged before any branch is deleted; a done Tracker row with the PR still open or closed
|
|
156
|
+
unmerged stops `BLOCKED <ref> Tracker row is done but PR <url> is not merged` and keeps the branch, the claim and
|
|
157
|
+
`waiting.json`. The claim keeps the phase held (`next`, other roadmaps and plan mode skip or refuse it) until the PR
|
|
158
|
+
merges or closes. A run started while the PR still waits stops at once (`BLOCKED still waiting for merge of <ref>:
|
|
159
|
+
<url>`) and changes nothing. Once it merges, the recheck task restarts the runner. The restart first checks that the merged
|
|
160
|
+
origin roadmap is the one it published against (a hash, then the frozen tables; any difference is `FAILED roadmap
|
|
161
|
+
changed`), rolls the milestone up FIRST (when every phase is merged), then removes the claim and the phase's
|
|
162
|
+
branch (locally and on origin: whoever makes a branch removes it when its PR merges), and goes on with `next`.
|
|
163
|
+
An own claim that neither the waiting record nor `pending-rollup.json` names (a run killed between the claim and
|
|
164
|
+
the wait) stops the start `BLOCKED orphaned claim <file> from a killed run`; the owner checks the branch and its PR
|
|
165
|
+
and deletes the claim.
|
|
166
|
+
CONTINUE with the phase already merged on origin: `rollup` when every phase is merged, then back to 1. CONTINUE
|
|
167
|
+
with no new commits and nothing merged stops FAILED. `STATUS: OWNER-GATE <r>` becomes an `owner-gate` blocker,
|
|
168
|
+
`STATUS: BLOCKED <r>` an `external` one; then back to 1. `STATUS: FAILED` stops.
|
|
169
|
+
5. Every `**Risk:** high` phase done on the branch and not yet reviewed clean (record in the runner's own folder:
|
|
170
|
+
`<git common dir>/caddis-runner/roadmap-<slug>/reviewed/<plan>.json`; another runner's record does not count) is
|
|
171
|
+
reviewed BEFORE step 4 writes the claim and publishes
|
|
172
|
+
(`caddis_review.py --plan --phase --runs 2`): exit 0 publishes;
|
|
173
|
+
exit 1 starts one fix session, then one more review; exit 1 again stops `BLOCKED review`, exit 3, 4 or any other
|
|
174
|
+
code `BLOCKED review not run` (neither restartable); the review cost counts against the USD caps.
|
|
175
|
+
|
|
176
|
+
Stops (each one notifies and releases the lock): a STOP file (`~/.caddis/STOP` or `.local/STOP`), any cap (10 h,
|
|
177
|
+
12 sessions, 120 min and USD 25 per session, USD 150 total; per run, in memory; the global agy spend cap of
|
|
178
|
+
`caddis_spend.py` still counts across runs), a lock or batch claim that cannot be written
|
|
179
|
+
(`BLOCKED claim not written`, before any session), the agy spend cap refusing a reservation, three sessions
|
|
180
|
+
with no newly merged phase, a roadmap write that fails, and the **snapshot guard**: one baseline for the whole run.
|
|
181
|
+
The Milestones and Blockers tables (every cell of every row, rows added, removed or moved) and the `Runner host` line
|
|
182
|
+
are frozen. Every origin read (each `next`, after the runner's own writes, after each session) is compared with the
|
|
183
|
+
previous one; the only differences allowed are the exact edits the runner itself made and recorded for that read: a
|
|
184
|
+
Status it set, a blocker row it added, and what a rollup's audit entry (`changes.jsonl`) says it actually wrote.
|
|
185
|
+
Anything else stops the run `FAILED roadmap changed`.
|
|
186
|
+
Each runner has its own state folder, `<git common dir>/caddis-runner/roadmap-<slug>/` (plan mode: `plan-<slug>/`):
|
|
187
|
+
lock, last stop, options, branches, worktree path, the saved roadmap text. `claims/` and `claim.lock` are shared at
|
|
188
|
+
the top level. The runner hashes its own folder (recursively) and its own claims before and after every session; a
|
|
189
|
+
change there stops the run `FAILED runner state changed` (not restartable). Another runner's writes never stop it. A restart checks that the claim its
|
|
190
|
+
waiting-for-merge stop records is still there with the same content; a missing record, claim or hash is
|
|
191
|
+
`FAILED own claim missing or changed` (not restartable). During the upgrade window a plan-mode lock of the base
|
|
192
|
+
version (`.caddis/plans/.local/<slug>/runner.lock`, read only) still holds its plan while its pid runs and the lock
|
|
193
|
+
file is newer than that process's start (else it is ignored). Roadmap slugs
|
|
194
|
+
match `^[a-z0-9][a-z0-9-]{0,62}$` everywhere (both scripts and `caddis_roadmap.py`). The launch options are kept
|
|
195
|
+
in memory and re-written at every stop, so a changed options file can never raise the caps.
|
|
196
|
+
|
|
197
|
+
The runner never passes `--by-owner`. Every session and every `caddis_roadmap.py` call it starts gets
|
|
198
|
+
`CADDIS_HEADLESS=1`. The runner lock is `<git common dir>/caddis-runner/roadmap-<slug>/runner.lock` (a plan-mode
|
|
199
|
+
runner: `plan-<slug>/runner.lock`), so every worktree sees it. It holds `{"host", "pid", "started_utc", "batch", "max_hours"}`. On
|
|
200
|
+
this host it is stale when its pid is not running, or the process now holding that pid started after `started_utc`
|
|
201
|
+
(pid reuse after a reboot; when the start time cannot be read, it counts as live). Another host's lock is stale when it
|
|
202
|
+
is older than its own `max_hours` plus 1 h. A stale lock is removed with a notification; a live lock is exit 3. A
|
|
203
|
+
plan-mode lock holds the whole plan (`batch` `<plan>#*`). `next` skips a phase another live lock holds, and plan mode
|
|
204
|
+
refuses a plan that a roadmap lock names, at start and before every session. `-DryRun` prints the chosen batch,
|
|
205
|
+
the session command, the worktree and any pending rollup, skips the host check, writes no files and starts nothing; it
|
|
206
|
+
does run `git fetch`, which updates the remote-tracking refs. `-GhAccount <login>` (recorded in the launch options,
|
|
207
|
+
passed on by the recheck task and in the printed task) makes every gh call of the runner and of `--last-stop` use
|
|
208
|
+
GH_TOKEN from `gh auth token -u <login>`; on a machine with several gh logins, give the repo's account. A gh call that
|
|
209
|
+
cannot answer (gh missing, 401, 404) is an error, never "not merged": the run stops
|
|
210
|
+
`BLOCKED gh cannot see <repo> with account <login>`, notified and recorded.
|
|
211
|
+
|
|
212
|
+
`roadmap-recheck.ps1 -Roadmap <slug> -Repo <path>` starts `roadmap-run.ps1 -Roadmap <slug>` detached only when:
|
|
213
|
+
the runner's last recorded stop (next to its lock) is `BLOCKED nothing ready` or there is none, and `recheck`
|
|
214
|
+
cleared a blocker; or the last stop is `BLOCKED waiting for merge` and GitHub says that PR merged
|
|
215
|
+
(`--last-stop` asks GitHub only and fetches nothing; the restarted runner checks the Tracker row on origin under its
|
|
216
|
+
lock; in that tick recheck does NOT run `recheck`, because a cleared blocker would change the roadmap the restart
|
|
217
|
+
checks against its hash). If GitHub says merged but the Tracker row is not done, the restart
|
|
218
|
+
removes the claim and stops `BLOCKED <ref> merged but its Tracker row is not done` (the owner decides). A `BLOCKED nothing ready` stop also records the batches that
|
|
219
|
+
another runner's lock or claim held; once every one of those holders is gone, `--last-stop` says `freed:` and recheck
|
|
220
|
+
restarts the runner even with no blocker cleared. A plan in flight anywhere (a live lock or a claim on any of its
|
|
221
|
+
phases) holds the whole plan for every other roadmap and for plan mode. At the top of each run the runner rolls up
|
|
222
|
+
every milestone that waits only for its rollup (Status not finished, every phase merged, and the same rule as
|
|
223
|
+
`next`: no blocker, dependencies finished, Owner the runner); `--last-stop` says `rollup-ready:` for such a milestone,
|
|
224
|
+
so recheck restarts the runner. A sweep rollup that writes nothing stops `BLOCKED rollup of <id> wrote nothing`
|
|
225
|
+
(recorded, not restartable) and is not retried or reported until the roadmap changes. The dry run lists them first. If
|
|
226
|
+
the owner edits the roadmap during a merge wait, the restart stops `FAILED roadmap changed ...` and names the
|
|
227
|
+
recovery: `roadmap-run.ps1 -Roadmap <slug> -AcceptRoadmap` (owner only, refused headless) takes the runner lock (a live
|
|
228
|
+
runner refuses it), prints the diff from the published baseline, asks you to type `accept` (or `--yes`), and accepts
|
|
229
|
+
the origin roadmap as the new baseline of the wait; the next start goes on. With `-DryRun` it prints the diff only. `--last-stop` uses `--gh-account`, else the account the run recorded
|
|
230
|
+
in its launch options. In all cases the lock must be absent or stale; for the agy engine `caddis_spend.py check` must exit 0 too (a
|
|
231
|
+
claude-engine roadmap needs no spend-cap file). A restart after a merge writes `pending-rollup.json` in its runner
|
|
232
|
+
folder, runs the rollup first, then removes the claim and the branch, and only then the file. Every stop records
|
|
233
|
+
itself: a failed rollup, a crash or a STOP file before that is not restartable (the owner decides), and the next start
|
|
234
|
+
finds the file and does the rollup first. A merged
|
|
235
|
+
branch checked out in another checkout is kept locally (HEAD never moves outside the roadmap worktree).
|
|
236
|
+
Any FAILED stop (the snapshot guard, a crash), a cap or a STOP file needs the owner: recheck prints why and starts
|
|
237
|
+
nothing; the owner's next manual run records a new last stop. A runner records the last stop `running` as soon as it
|
|
238
|
+
holds the lock, so a run killed without a stop (a reboot, a kill) also needs the owner; an unexpected exception
|
|
239
|
+
records `FAILED crash: <type>` and notifies once. Recheck restarts with the launch options the last run recorded
|
|
240
|
+
(engine, model, caps), each cap clamped to at most the built-in default (the options file is writable), never higher.
|
|
241
|
+
`roadmap-run.ps1 -Roadmap <slug> -PrintRecheckTask` prints a PowerShell block (`New-ScheduledTaskAction`,
|
|
242
|
+
`New-ScheduledTaskTrigger` every 2 hours, `Register-ScheduledTask`) for the owner to paste; it registers nothing. The
|
|
243
|
+
task runs only while you are logged on unless you add `-User` and `-Password` to `Register-ScheduledTask` (or set that
|
|
244
|
+
option in Task Scheduler).
|
|
245
|
+
|
|
246
|
+
## Limits
|
|
247
|
+
|
|
248
|
+
Sessions are cooperative (our own sessions): the runner guards against mistakes and runaway spend, not against a
|
|
249
|
+
deliberately hostile session, which runs as the same OS user and could change anything the runner can. The state
|
|
250
|
+
tripwire catches accidents in a runner's own state only. In particular, a session in another worktree of the repo can
|
|
251
|
+
delete or rewrite ANOTHER runner's claim or lock under `<git common dir>/caddis-runner/`; that is not caught while it
|
|
252
|
+
happens, and the victim runner fails closed only at its next restart (own claim missing or changed, orphaned claim). Caps are per run; the agy spend cap is the only limit across runs. Each roadmap has one
|
|
253
|
+
worktree, removed when the roadmap is finished and the worktree is clean.
|
|
254
|
+
|
|
255
|
+
Owner-only rules are enforced by this tool; a direct PR that edits `roadmap.md` bypasses them; the runner stops
|
|
256
|
+
when an owner-gate row disappears; repos that need more protect their default branch.
|
|
257
|
+
On Windows, a check's grandchild started in the instant before the job object is attached can escape the tree kill;
|
|
258
|
+
checks are owner-written, so this is accepted. Headless detection cannot see a process started in a fresh console with
|
|
259
|
+
the markers removed: anything that runs this tool unattended (the runner, scheduled tasks) must set `CADDIS_HEADLESS=1`.
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
---
|
|
2
|
+
type: prompt
|
|
3
|
+
title: Plan resume prompt for {{slug}}
|
|
4
|
+
description: The prompt for one fresh runner session of the plan {{slug}} (runner plan mode). It does one batch and ends with a status line.
|
|
5
|
+
status: current
|
|
6
|
+
timestamp: {{date}}
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
You are a fresh session for the plan `{{slug}}`. Do ONE batch, then stop.
|
|
10
|
+
|
|
11
|
+
In the commands below, `<scripts>` is the caddis scripts folder `{{scripts}}` (put it in quotes if it holds a space).
|
|
12
|
+
Use the scripts in that folder; do not look for them in another caddis install.
|
|
13
|
+
|
|
14
|
+
## 1. Read
|
|
15
|
+
|
|
16
|
+
1. The plan `.caddis/plans/{{slug}}.md`: its goal, its decisions, its tracker. Every decision binds you.
|
|
17
|
+
2. The relay `.caddis/relay/{{slug}}.md`. Its "Next step" says where to start.
|
|
18
|
+
3. The open-work list `.caddis/open-work.md`, when it exists.
|
|
19
|
+
|
|
20
|
+
## 2. Step 0: reconcile
|
|
21
|
+
|
|
22
|
+
The relay can be old. Before you act, compare it with the real state: the plan tracker, worktrees, local branches, open
|
|
23
|
+
pull requests and remote branches. If they disagree, trust the real state. Fix the relay and the tracker. Do not build on a
|
|
24
|
+
guess.
|
|
25
|
+
|
|
26
|
+
## 3. Pick the batch
|
|
27
|
+
|
|
28
|
+
A batch is ONE tracker phase (the first row that is not done and not blocked), or ONE named batch that the plan or the relay
|
|
29
|
+
names. If no row can start, end with the status line that says why (an owner gate, a block, or FAILED).
|
|
30
|
+
|
|
31
|
+
The phase number chosen by the roadmap runner (empty: choose the batch yourself as above): {{phase}}
|
|
32
|
+
When it holds a number, that phase is the batch. Do only that phase.
|
|
33
|
+
|
|
34
|
+
Roadmap mode (a number above): the runner, not you, publishes the work. The runner made the branch you are on
|
|
35
|
+
(`caddis/roadmap/<roadmap>/<plan>-p<n>`, fresh from the default branch). Stay on it: never switch or create a branch,
|
|
36
|
+
never push, never open a pull request, and never edit anything under `.caddis/roadmaps/` (the runner refuses to
|
|
37
|
+
publish a branch that does). Commit the phase there, with its tracker row set to `done`. When you end with
|
|
38
|
+
`STATUS: CONTINUE` and new commits on that branch, the runner pushes it, opens the pull request and stops with
|
|
39
|
+
`BLOCKED waiting for merge`; the recheck task restarts the runner after the merge.
|
|
40
|
+
|
|
41
|
+
## 4. Work
|
|
42
|
+
|
|
43
|
+
- Do ONE batch with `/caddis:implement` discipline: tests first, the phase's exit gate, a commit per phase.
|
|
44
|
+
- agy sessions only: run `python {{scripts}}/caddis_spend.py check` before each agy call. Stop at the cap (exit 1 over
|
|
45
|
+
the cap, 3 not configured).
|
|
46
|
+
- You may do everything except pass an owner gate. Never pass an owner gate. Never raise a cap. Never delete a STOP file.
|
|
47
|
+
- The runner reviews `risk: high` phases. A phase marked `**Risk:** high`: do not halt for it and do not run the
|
|
48
|
+
review yourself. When its exit gate is green, set its row `done` and end with `STATUS: CONTINUE`. The runner then
|
|
49
|
+
reviews it twice and, on findings, starts one fix session.
|
|
50
|
+
- Set the tracker row of the batch to `done` (with its evidence) when its exit gate is green. Set open-work rows with
|
|
51
|
+
`python <scripts>/caddis_rows.py set` (by row id and column name).
|
|
52
|
+
|
|
53
|
+
## 5. Write the relay
|
|
54
|
+
|
|
55
|
+
Write the relay with `python <scripts>/caddis_workstreams.py put --require-status {{slug}} <file>`. Write `<file>` outside
|
|
56
|
+
the repo (for example in the temp folder). Read the current relay first with `python <scripts>/caddis_workstreams.py read {{slug}}`;
|
|
57
|
+
keep its frontmatter shape (`type: relay`, `workstream: {{slug}}`, `branch`, `session_id`, `plan`, `generated.at`). The LAST
|
|
58
|
+
non-empty line must be exactly one of these four:
|
|
59
|
+
|
|
60
|
+
```
|
|
61
|
+
STATUS: CONTINUE
|
|
62
|
+
STATUS: OWNER-GATE <P>-OG<n>
|
|
63
|
+
STATUS: BLOCKED <owner>
|
|
64
|
+
STATUS: FAILED <reason>
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
Use `STATUS: CONTINUE` only when the next batch can start with no owner input. A missing or bad line counts as FAILED.
|
|
68
|
+
An owner gate id has the form `<P>-OG<n>`: the plan's 2 to 4 capital-letter prefix (for example `PM-OG1`). Name the gate
|
|
69
|
+
in the plan's decisions with that id. Any other form is a bad line.
|
|
70
|
+
|
|
71
|
+
## 6. Notify and end
|
|
72
|
+
|
|
73
|
+
When the status is not CONTINUE, call the `PushNotification` tool as your last action. Put the plan, the status line and the
|
|
74
|
+
next step in the message. After the call succeeds, print the line `PUSH-SENT`. The runner looks for that marker. Without it,
|
|
75
|
+
the runner sends the notification itself.
|
|
76
|
+
|
|
77
|
+
Then end the session.
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
// Render check template. Copy it into the app (for example frontend/render-check.mjs) so CI and prod checks can run it.
|
|
2
|
+
//
|
|
3
|
+
// Usage:
|
|
4
|
+
// node render-check.mjs --base http://localhost:5173 --path /dashboard --expect kpi-total --expect chart-main
|
|
5
|
+
// node render-check.mjs --prod https://app.example.com --path /dashboard --expect kpi-total --channel msedge \
|
|
6
|
+
// --allow-auth app.example.com
|
|
7
|
+
// node render-check.mjs --base http://localhost:5173 --path /dashboard --expect kpi-total --prove-it-can-fail
|
|
8
|
+
//
|
|
9
|
+
// Options:
|
|
10
|
+
// --base <url> | --prod <url> Origin to test (local or prod). One of them is required.
|
|
11
|
+
// --path <path> Page path. Default "/".
|
|
12
|
+
// --expect <testid> A data-testid that must be visible. Repeat it.
|
|
13
|
+
// --channel <name> Browser channel, for example msedge. Default: bundled chromium.
|
|
14
|
+
// --allow-auth <host> Host that may use the current Windows login (NTLM). Repeat it.
|
|
15
|
+
// --settle <ms> Wait after network idle. Default 3000.
|
|
16
|
+
// --prove-it-can-fail Add a test id that does not exist. The run must then exit 1.
|
|
17
|
+
// Exit codes: 0 all checks pass, 1 a check failed, 4 bad arguments.
|
|
18
|
+
import { chromium } from 'playwright'; // or: import { chromium } from '@playwright/test';
|
|
19
|
+
|
|
20
|
+
const args = process.argv.slice(2);
|
|
21
|
+
const opt = (name) => { const i = args.indexOf(name); return i >= 0 ? args[i + 1] : undefined; };
|
|
22
|
+
const all = (name) => args.flatMap((a, i) => (a === name ? [args[i + 1]] : []));
|
|
23
|
+
|
|
24
|
+
const origin = opt('--prod') ?? opt('--base');
|
|
25
|
+
if (!origin) { console.error('give --base <url> or --prod <url>'); process.exit(4); }
|
|
26
|
+
const path = opt('--path') ?? '/';
|
|
27
|
+
const settle = Number(opt('--settle') ?? 3000);
|
|
28
|
+
const expected = all('--expect');
|
|
29
|
+
const allowAuth = all('--allow-auth');
|
|
30
|
+
if (args.includes('--prove-it-can-fail')) expected.push('testid-that-does-not-exist');
|
|
31
|
+
if (expected.length === 0) { console.error('give at least one --expect <testid>'); process.exit(4); }
|
|
32
|
+
|
|
33
|
+
const launch = { headless: true };
|
|
34
|
+
if (opt('--channel')) launch.channel = opt('--channel');
|
|
35
|
+
if (allowAuth.length) launch.args = [`--auth-server-allowlist=${allowAuth.join(',')}`];
|
|
36
|
+
|
|
37
|
+
const failures = [];
|
|
38
|
+
const browser = await chromium.launch(launch);
|
|
39
|
+
for (const width of [1440, 400]) {
|
|
40
|
+
const context = await browser.newContext({ viewport: { width, height: 900 } });
|
|
41
|
+
// Dark theme seeded before any page script runs. Change the key and value to match the app.
|
|
42
|
+
await context.addInitScript(() => { try { localStorage.setItem('theme', 'dark'); } catch { /* ignore */ } });
|
|
43
|
+
const page = await context.newPage();
|
|
44
|
+
let consoleErrors = 0;
|
|
45
|
+
page.on('console', (m) => { if (m.type() === 'error') consoleErrors += 1; });
|
|
46
|
+
page.on('pageerror', () => { consoleErrors += 1; });
|
|
47
|
+
|
|
48
|
+
await page.goto(new URL(path, origin).toString());
|
|
49
|
+
await page.waitForLoadState('networkidle');
|
|
50
|
+
await page.waitForTimeout(settle);
|
|
51
|
+
|
|
52
|
+
if (consoleErrors > 0) failures.push(`${width}px: ${consoleErrors} console error(s)`);
|
|
53
|
+
const overflow = await page.evaluate(() => document.documentElement.scrollWidth > window.innerWidth);
|
|
54
|
+
if (overflow) failures.push(`${width}px: horizontal scroll`);
|
|
55
|
+
for (const id of expected) {
|
|
56
|
+
const visible = await page.getByTestId(id).first().isVisible().catch(() => false);
|
|
57
|
+
if (!visible) failures.push(`${width}px: data-testid "${id}" is not visible`);
|
|
58
|
+
}
|
|
59
|
+
console.log(`${width}px: console errors ${consoleErrors}, horizontal scroll ${overflow ? 'yes' : 'no'}`);
|
|
60
|
+
await context.close();
|
|
61
|
+
}
|
|
62
|
+
await browser.close();
|
|
63
|
+
|
|
64
|
+
if (failures.length) {
|
|
65
|
+
for (const f of failures) console.error(`FAIL ${f}`);
|
|
66
|
+
process.exit(1);
|
|
67
|
+
}
|
|
68
|
+
console.log('PASS render check');
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
---
|
|
2
|
+
type: reference
|
|
3
|
+
title: Review protocol
|
|
4
|
+
description: The review method one model can rely on - invariants, inputs and writers, shared state, execute what the change promises, tests, docs, then severity (only blocking stops the merge; each finding needs a reproduction), one FINDING line per finding and an END REVIEW line. caddis_review.py sends it to every review run.
|
|
5
|
+
status: current
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# Review protocol (generic, any diff)
|
|
9
|
+
|
|
10
|
+
You review a diff. You do NOT edit, create or delete files, and you do not commit. You may read files and run commands
|
|
11
|
+
(tests, dry runs, the commands that plans, cards and docs name). Work through ALL steps in order. Do not stop at the
|
|
12
|
+
first finding. Include a short section per step, in order.
|
|
13
|
+
|
|
14
|
+
## Step 1 - Purpose and invariants
|
|
15
|
+
Read the card, the plan or design section it cites, and the diff. Write the list of INVARIANTS this change must keep:
|
|
16
|
+
safety limits, gates, money caps, isolation between runs or users, path containment, "X can never cause Y". Include
|
|
17
|
+
invariants that the surrounding system relies on, not only the ones the card names.
|
|
18
|
+
|
|
19
|
+
## Step 2 - Inputs and who controls them
|
|
20
|
+
List every input the changed code reads: files, file sections, env vars, CLI args, other processes' output, the clock,
|
|
21
|
+
the home folder. For EACH input write: who or what can write it (the owner, an unattended session, another runner,
|
|
22
|
+
a test, a template), and when. Then, for each invariant from step 1, ask: can any writer of any input break it, by
|
|
23
|
+
accident or on purpose? This includes the agent or session the code is meant to limit.
|
|
24
|
+
|
|
25
|
+
## Step 3 - Shared state and concurrency
|
|
26
|
+
List state that two runs, two kinds of target, or two processes could share (files, locks, relays, logs, caches).
|
|
27
|
+
Can they collide? Can one read the other's output as its own?
|
|
28
|
+
|
|
29
|
+
## Step 4 - Execute what the change promises
|
|
30
|
+
Run the tests the card names. Then run every command that the plan, its exit gates, the docs or the skill text say
|
|
31
|
+
should work for this change (dry runs, the documented usage lines), exactly as written. Use the repo's OWN fixtures
|
|
32
|
+
and example files, not ones you build, and run unattended scripts (hooks, runners) as they are really run (as a script,
|
|
33
|
+
with a real payload). Compare risky behaviour with the parent commit when the change claims to fix or tighten
|
|
34
|
+
something. Report any that fail or that cannot work as documented.
|
|
35
|
+
|
|
36
|
+
## Step 5 - Tests
|
|
37
|
+
For each new or changed test: could it pass for the wrong reason (no assertion that can fail, mocked away the thing
|
|
38
|
+
under test)? Does it depend on the real machine (home folder, real STOP files, network, clock, cwd)? Which new
|
|
39
|
+
behaviour has no test, especially the negative cases (placeholders, malformed input, edge values)?
|
|
40
|
+
|
|
41
|
+
## Step 6 - Docs and contracts
|
|
42
|
+
Compare every doc, skill, prompt asset and usage line touched by or describing this feature with the code. List each
|
|
43
|
+
mismatch (paths, flags, names, steps that do not exist or no longer apply). Check that every tool the new mode is told
|
|
44
|
+
to use supports the new mode.
|
|
45
|
+
|
|
46
|
+
## Step 7 - Report
|
|
47
|
+
Severity rule. Only **blocking** stops the merge, so use it with care:
|
|
48
|
+
- **blocking** = a defect that breaks a stated invariant from step 1 (safety, security, isolation, a gate passing when
|
|
49
|
+
it should fail, a crash of something that runs unattended), or loses or corrupts work or data, or breaks a money cap,
|
|
50
|
+
or makes a documented command fail. Use it even if other limits make the defect unlikely.
|
|
51
|
+
- **should-fix** = a real defect that does not stop the merge: it goes on a follow-up list. Examples: a missing
|
|
52
|
+
negative test, a doc that is wrong in a way that does not make a command fail, an error message that misleads.
|
|
53
|
+
- **nit** = style and wording.
|
|
54
|
+
|
|
55
|
+
Every finding needs a concrete reproduction: a command, an input or a test that shows the failure, written in the
|
|
56
|
+
failure scenario. A finding without a reproduction is a **nit**, whatever its severity would otherwise be. Do not
|
|
57
|
+
write "might", "could in theory" or "a future change may": show it or call it a nit.
|
|
58
|
+
|
|
59
|
+
The gate exits by the findings. A **blocking** finding fails it. **should-fix** and **nit** findings do not: they are
|
|
60
|
+
listed in the report under "Follow-up (not blocking)". The tool allows 3 completed review rounds for a phase; the 4th completed round
|
|
61
|
+
ends with "stop, the owner decides". Report every real defect once, with its true severity, so that one round is
|
|
62
|
+
enough.
|
|
63
|
+
|
|
64
|
+
End your answer with the findings, one line per finding, in exactly this form (no bullets, no bold, no code block):
|
|
65
|
+
|
|
66
|
+
```
|
|
67
|
+
FINDING <n> | <severity> | <file>:<line> | <one-sentence failure scenario>
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
`<n>` counts from 1, `<severity>` is `blocking`, `should-fix` or `nit`. Put the reproduction in the one sentence
|
|
71
|
+
(for example `... ; reproduce: python x.py --flag with an empty file`). If you have no findings, write the line
|
|
72
|
+
`NO FINDINGS` instead. The very last line of your answer is `END REVIEW <count>`, where `<count>` is the number of
|
|
73
|
+
FINDING lines (`END REVIEW 0` after `NO FINDINGS`). A review whose last line is missing or whose count is wrong is
|
|
74
|
+
treated as not run. Do not write a verdict line: the gate reads the findings only.
|
|
75
|
+
No other line may contain the word FINDING followed by a number, anywhere in the line (in any case, also as
|
|
76
|
+
`finding-1`, `finding #1`, `finding (1)`, after a bullet, a `>`, a table `|` or any other text): such a line that is
|
|
77
|
+
not a complete FINDING line also makes the review count as not run. In your step sections, write "issue 1", not
|
|
78
|
+
"finding 1".
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
# <slug> roadmap
|
|
2
|
+
|
|
3
|
+
Runner host: HOSTNAME
|
|
4
|
+
|
|
5
|
+
The roadmap file on `origin/main` is the only truth. Change it with `scripts/caddis_roadmap.py` (each change is a small
|
|
6
|
+
docs PR), never by a direct push. Only `rollup` sets a milestone `done`.
|
|
7
|
+
|
|
8
|
+
## Milestones
|
|
9
|
+
| ID | Milestone | Phases | Depends on | Exit check | Status | Owner | Target |
|
|
10
|
+
|---|---|---|---|---|---|---|---|
|
|
11
|
+
| S1 | <what is true when it is done> | <plan>#1, <plan>#2 | - | `<command that exits 0 when S1 holds>` | todo | runner | <date> |
|
|
12
|
+
|
|
13
|
+
## Blockers
|
|
14
|
+
| Milestone | Type | Reason | Check |
|
|
15
|
+
|---|---|---|---|
|
|
16
|
+
|
|
17
|
+
## Notes
|
|
18
|
+
|
|
19
|
+
- Status: todo, in-progress, code-done/data-pending, done or not-needed (blocked = has a Blockers row).
|
|
20
|
+
- Blocker types: owner-gate, external, shared, calendar or data-condition (Check: a command, added by the owner
|
|
21
|
+
only; recheck runs it in a worktree of origin/main and clears that row on exit 0). A calendar blocker's Check is
|
|
22
|
+
an ISO date YYYY-MM-DD; recheck clears the row once that date has passed.
|
|
23
|
+
- Status not-needed needs --reason "dropped: why" or --reason .caddis/parking-lot/file.md; the reason is added
|
|
24
|
+
below as "- id not-needed: reason (date)".
|
|
25
|
+
- status lists each blocker row older than 14 days as "old blockers: id type (N days)"; the age comes from git.
|
|
26
|
+
- A malformed section (wrong cell count, a row without a leading pipe, a line right after the table, a pipe in
|
|
27
|
+
prose, a second table, a renamed heading) stops every command: fix it by a PR. Escape a pipe in prose as \|.
|
|
28
|
+
- This file allows only headings, plain paragraphs, lists and pipe tables: no code fences, no HTML, no setext
|
|
29
|
+
headings, no control or non-ASCII whitespace characters. GitHub would hide or move lines the parser reads, so
|
|
30
|
+
each one is a parse error.
|
|
31
|
+
- Owner: runner (or empty) = the runner may take it; a session name = that session does it by hand.
|
|
32
|
+
- A Depends on change cites a decision id from decisions.md in the Milestone cell: `S9 (dep waived: D4)`.
|