Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
aeda780
test-files.yml: run chosen test files on their full-test runners, wit…
thejackshelton Oct 8, 2026
5abc810
Cloud session bootstrap and DRAGON_REQUIRE_NATIVE (cloud migration it…
thejackshelton Oct 8, 2026
42c5c7e
test-files.yml: a summary job checks every requested file ran in one …
thejackshelton Oct 8, 2026
7413904
test-files.yml: the ref input is a full sha or a branch
thejackshelton Oct 8, 2026
892a687
setup:git and the landing driver share SETUP_GIT_CONFIG (rerere off, …
thejackshelton Oct 8, 2026
dc99465
ci:test-files: say where a dispatched run's checks are filed
thejackshelton Oct 8, 2026
579bce9
Cloud setup: hook on every SessionStart source, export DRAGON_REQUIRE…
thejackshelton Oct 8, 2026
4e5d626
Land: ci-only mode (LAND_CI=only), queued CI runs waited for, CI Andr…
thejackshelton Oct 8, 2026
57a223e
Merge remote-tracking branch 'origin/land-regen-ci' into land-ci-only
thejackshelton Oct 8, 2026
01028d3
Land: R3 tests build both ABIs' records from this tree, so they hold …
thejackshelton Oct 8, 2026
7e7f8fe
test-files: refuse a file the ref's own test-shards.ts groups elsewhe…
thejackshelton Oct 8, 2026
0104a55
Land: merge cloud-bootstrap (#219)
thejackshelton Oct 8, 2026
e3b21ae
Lane contract and AGENTS.md steps 2-4 for cloud lanes (cloud migratio…
thejackshelton Oct 8, 2026
27adbb5
Land: judge each CI job's queue and run time on its own (#222 Claude …
thejackshelton Oct 8, 2026
7c71160
Land: regenerate after merging cloud-bootstrap (#219)
thejackshelton Oct 8, 2026
42a11b6
Lane contract review fixes: direct-push full test, label-only regen t…
thejackshelton Oct 8, 2026
0347610
Lane contract: READY needs regen, typecheck and ci:test-files verdict…
thejackshelton Oct 8, 2026
8cec472
pr:review over REST only (gh-rest.ts), with --once for cloud sessions
thejackshelton Oct 8, 2026
3099f7b
Merge pull request #219 from compiled-run/cloud-bootstrap
thejackshelton Oct 8, 2026
28b45e4
Land: merge ci-test-files (#221)
thejackshelton Oct 8, 2026
a01848d
Land: merge land-ci-only (#222)
thejackshelton Oct 8, 2026
5e77488
Land: regenerate after merging ci-test-files (#221)
thejackshelton Oct 8, 2026
40f816a
Land: regenerate after merging land-ci-only (#222)
thejackshelton Oct 8, 2026
9dced02
Land: merge lane-contract-cloud (#223)
thejackshelton Oct 8, 2026
e2457b0
Land: regenerate after merging lane-contract-cloud (#223)
thejackshelton Oct 8, 2026
8a353d9
pr:review: an UNKNOWN mergeability is pending, not clean; REST lows (…
thejackshelton Oct 8, 2026
364cf16
Merge pull request #221 from compiled-run/ci-test-files
thejackshelton Oct 8, 2026
b13d66b
Merge pull request #222 from compiled-run/land-ci-only
thejackshelton Oct 8, 2026
76b7307
Merge pull request #223 from compiled-run/lane-contract-cloud
thejackshelton Oct 8, 2026
44fa07a
Land: merge pr-review-rest (#224)
thejackshelton Oct 8, 2026
d95156f
Land: regenerate after merging pr-review-rest (#224)
thejackshelton Oct 8, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions .claude/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
{
"hooks": {
"SessionStart": [
{
"hooks": [
{
"type": "command",
"command": "bash \"$CLAUDE_PROJECT_DIR\"/scripts/cloud-setup.sh",
"timeout": 900
}
]
}
]
}
}
26 changes: 25 additions & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,34 @@ permissions:
contents: read
jobs:
checks:
runs-on: ubuntu-latest
# ubuntu-24.04 x86_64, the image of Claude Code cloud sessions, so the cloud-setup steps below prove their bootstrap.
runs-on: ubuntu-24.04
steps:
- name: Check out
uses: actions/checkout@v4
# Before setup-node, so the runner has only its image's Node: scripts/cloud-setup.sh must install the pinned Node and pnpm.
- name: Cloud session bootstrap (scripts/cloud-setup.sh), run twice
run: |
set -euo pipefail
test "$(uname -s)-$(uname -m)" = Linux-x86_64
for round in 1 2; do
: > "$RUNNER_TEMP/env"
CLAUDE_CODE_REMOTE=true CLAUDE_ENV_FILE="$RUNNER_TEMP/env" scripts/cloud-setup.sh > "$RUNNER_TEMP/out-$round" 2> "$RUNNER_TEMP/err-$round" || { cat "$RUNNER_TEMP/err-$round"; exit 1; }
cat "$RUNNER_TEMP/err-$round" "$RUNNER_TEMP/out-$round"
# Stdout reaches Claude's context: one summary line only.
test "$(wc -l < "$RUNNER_TEMP/out-$round")" = 1 || { echo "::error::cloud-setup printed more than its summary line on stdout"; exit 1; }
(
# shellcheck disable=SC1091
. "$RUNNER_TEMP/env"
test "$(node -v)" = "v$(sed -n 's/^node //p' <(scripts/cloud-setup.sh --print-versions))" || { echo "::error::node is $(node -v) after sourcing CLAUDE_ENV_FILE"; exit 1; }
test "$(pnpm --version)" = "$(sed -n 's/^pnpm //p' <(scripts/cloud-setup.sh --print-versions))" || { echo "::error::pnpm is $(pnpm --version)"; exit 1; }
test "${DRAGON_REQUIRE_NATIVE:-}" = 1 || { echo "::error::DRAGON_REQUIRE_NATIVE is not exported as 1"; exit 1; }
pnpm typecheck
)
done
# The second run found Node and pnpm in place and installed nothing.
if grep -E 'installing (Node|pnpm)' "$RUNNER_TEMP/err-2"; then echo "::error::the second cloud-setup run reinstalled"; exit 1; fi
grep -q 'installing Node' "$RUNNER_TEMP/err-1" || { echo "::error::the first run did not install Node, so the install path is unproven"; exit 1; }
- name: Set up pnpm 10.33.2
uses: pnpm/action-setup@v4
with:
Expand Down
342 changes: 342 additions & 0 deletions .github/workflows/test-files.yml

Large diffs are not rendered by default.

10 changes: 5 additions & 5 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ Dragon CSS compiles regular CSS straight into native view properties, and proves
- **One source for both outputs.** The generated native code and the plain-data property list used by the test lanes come from the same compiler result, so they cannot disagree.
- **Remove pitfalls by design.** Platform-specific choices belong to the compiler, which resolves every element style for every reachable state from semantic analysis; web output is compiled from the same result when a native target is configured. Never ask the developer to know a platform difference the compiler can decide. See the design principles in docs/goals/milestone-1/goal.md.
- **Support facts live in the support profiles.** Import them; never restate them as literals in the compiler, docs or runtimes.
- **Before reporting work done, run `pnpm typecheck` and `pnpm test`,** and say exactly what passed.
- **Before reporting work done, run `pnpm typecheck` and the tests for what you changed,** and say exactly what passed. The full `pnpm test` runs once per landing, on the merged tree, in the landing driver; a change pushed straight to `master` never reaches the driver, so it gets its own full test first (Landing work, last paragraph). In a cloud session, platform-free test files run locally and Chrome and native files run through `pnpm ci:test-files`; never claim a Chrome or native file passed unless ci:test-files reported it. On the local Mac, any test file may run locally.
- **Publishing needs an explicit owner directive:** npm (the `dragon` package), new remotes, and pushes to `master` other than the two cases under Landing work.
- **Write in plain, concrete language.** Comments only where the code can't show a constraint, one line at most.

Expand All @@ -17,10 +17,10 @@ Dragon CSS compiles regular CSS straight into native view properties, and proves
Code reaches `master` only through a pull request that Macroscope has reviewed. The owner's standing directive allows the pushes and merges below, and nothing else.

1. **Branch.** `git fetch origin`, then branch from `origin/master` (or from the parent branch your task names; stacks are at most 2 deep). Keep one change per branch. Put regenerated outputs (vectors, captures, expected files) in their own commit whose message names the command that produced them. Run `pnpm setup:git` once per clone.
2. **Verify on your base.** Develop with targeted tests. At the end of the branch run `pnpm regen` once, then `pnpm typecheck` and `pnpm test`. Merge `origin/master` (then regen) only when GitHub reports a conflict, your parent has merged, or the landing driver asks; never rebuild a branch under a new name, merge its parent forward. Device-record tests that fail only for a missing device run are "device step pending"; the landing driver runs the device lanes.
3. **Audit, then open the PR.** Every review is paid by the size of the diff it reads, so make the first review count. Before the first push, audit every changed source and test file for these classes and fix every instance, with a test: external input used unchecked (JSON, CLI arguments, dumps, device records); error paths that pass silently; checks judged on a subset of the data; missing cleanup on failure. Keep the reviewed diff under about 150 KB and split larger work by theme. Review reads the code that produces generated or captured output, never the output: `.macroscope/ignore.md` covers it by shape (`captures/`, `generated/`, `out/`, `vectors/`, `expected-*/`, `*-oracle/`, `*.generated.*`); a PR that adds output anywhere else adds its ignore entry in the same PR. Then `git push -u origin <branch>`, then `gh pr create --base master --title '...' --body '...'` (a stacked PR uses its parent branch as the base). In the body, say what changed and exactly what passed. Give a written reason for every tolerance, check, test or fixture the PR changes or removes.
2. **Verify on your base.** Develop with targeted tests. Push work in progress early; a cloud session's VM can be reclaimed. At the end of the branch regenerate once (in a cloud session only on CI, through the `regen` label on the PR, so the lane contract opens the PR first; on the local Mac, `pnpm regen` is also allowed), then run `pnpm typecheck` and the targeted tests for what you touched (Chrome and native files through `pnpm ci:test-files` in the cloud). The full `pnpm test` is the landing driver's, except before a push straight to `master` (below). Merge `origin/master` (then regen) only when GitHub reports a conflict, your parent has merged, or the landing driver asks; never rebuild a branch under a new name, merge its parent forward. Device-record tests that fail only for a missing device run are "device step pending"; the landing driver runs the device lanes.
3. **Audit, then open the PR.** Every review is paid by the size of the diff it reads, so make the first review count. Before opening the PR, audit every changed source and test file for these classes and fix every instance, with a test: external input used unchecked (JSON, CLI arguments, dumps, device records); error paths that pass silently; checks judged on a subset of the data; missing cleanup on failure. Keep the reviewed diff under about 150 KB and split larger work by theme. Review reads the code that produces generated or captured output, never the output: `.macroscope/ignore.md` covers it by shape (`captures/`, `generated/`, `out/`, `vectors/`, `expected-*/`, `*-oracle/`, `*.generated.*`); a PR that adds output anywhere else adds its ignore entry in the same PR. Then `git push -u origin <branch>`, then create the PR. GraphQL may not pass the cloud's GitHub proxy, so use REST: `gh api repos/compiled-run/dragoncss/pulls -f base=master -f head=<branch> -f title='...' -F body=@<body-file>` (a stacked PR uses its parent branch as the base; on the local Mac, `gh pr create` also works). The lane contract lists the REST form of every other `gh` command a lane needs. In the body, say what changed and exactly what passed. Give a written reason for every tolerance, check, test or fixture the PR changes or removes.
Measure the reviewed size (the diff outside `.macroscope/ignore.md` paths); split at a theme seam only above Macroscope's limit, never after the fact. A stacked PR's base is its parent branch; GitHub moves it to `master` when the parent merges. CI runs on every branch push, so a stacked PR gets its CI run too. The worker that wrote the branch opens the PR.
4. **Read the review.** Run `pnpm pr:review <number> --wait`. It waits for CI and then for Macroscope's correctness review of the latest commit, and lists failed checks and every Macroscope finding nobody has answered. Macroscope only posts findings of Medium severity or higher, so every one it lists matters. When Macroscope skips with its monthly spending limit, the owner's standing directive lets the PR land without that review once CI passes and every earlier finding is answered; `pr:review` reports it as UNREVIEWED. The landing driver then requires a Claude correctness review of the PR's own diff (step 7) and stops the PR on any finding of Medium severity or higher.
4. **Read the review.** Run `pnpm pr:review <number> --wait`. It waits for CI and then for Macroscope's correctness review of the latest commit, and lists failed checks and every Macroscope finding nobody has answered. Macroscope only posts findings of Medium severity or higher, so every one it lists matters. When Macroscope skips with its monthly spending limit, the owner's standing directive lets the PR land without that review once CI passes and every earlier finding is answered; `pr:review` reports it as UNREVIEWED. The landing driver then requires a Claude correctness review of the PR's own diff (step 7) and stops the PR on any finding of Medium severity or higher. In a cloud session a command may run for at most 30 minutes, so run `pnpm pr:review <number>` without `--wait`: one poll that exits 0 only when clean. While CI or the review is still running, end your turn and poll again when resumed. Until pr:review is ported to REST it may fail at the cloud's proxy; the lane contract says what to do then.
5. **Answer every finding.** Fix it, push, and reply `Fixed in <sha>` in its thread; or reply with why the code is intentional. Reply with `gh api repos/compiled-run/dragoncss/pulls/<number>/comments/<id>/replies -f body='...'`. Never reply only to clear the list, and never edit `.macroscope/` to silence a finding. If a fix would break a rule above, find another fix that keeps the rule, or reply with why the finding doesn't apply.
6. **Repeat until Macroscope is done.** Every push gets a new, paid review, which may find new issues, so batch a whole round's fixes into one push. A round's fix needs a regen only when it changes generator inputs, and never a device run. From the third round on, re-audit every file that has had a finding, end to end, and fix every instance of each class before pushing. Go back to step 4 until a review of the latest commit leaves nothing unanswered. The loop runs unattended, with no round limit and no report to the owner. When a file keeps drawing findings, replace point fixes with a check that covers the whole class, such as a differential test against Chrome, before the next push.
7. **Land through the driver.** Only the landing driver (`pnpm land <queue-file>`, run by the PM) merges code into `master`, in queue order, in batches of up to `LAND_BATCH` PRs (default 4); the queue file holds one `<branch>:<pr>:<clean-head>` per line. It first checks each PR's CI and its review at its current head (a PR whose review is not clean is ejected before any build). It then builds one position per PR, each on the one before it (the first on the current `origin/master`): it merges the PR, runs `pnpm regen` and `pnpm typecheck`, runs the device lanes unless the position's device evidence stamp equals the previous position's (device-evidence.ts, `pnpm evidence:stamp --compare <previous>`), regenerates what the device record feeds, and checks the regen commit is regen-only and no floor falls. A conflict or a failed step ejects that PR and the chain continues. `pnpm test` runs once, on the top position; when it fails, the driver bisects the prefixes (proving `master` itself before it blames the first PR, and stopping with "master is red" if `master` fails), lands the passing prefix, fails the first failing PR with its own failing run, and requeues the PRs after it. Positions below the top get no full test of their own, so when publishing stops part-way the driver proves the tree `master` now rests on, and stops (label, comment, status) if it fails. An error outside the test while proving (install, checkout) stops the driver rather than blaming a PR. While a proven batch publishes, a builder process prepares the next batch (admission, positions, proof) on that batch's top in a second worktree (`LAND_PIPELINE=0` turns this off); the driver uses it only if the whole batch landed, and otherwise throws it away and prepares those PRs again on the new `master`. Then, PR by PR and only after the PR before it has merged, it pushes the PR's position to the PR branch, waits for CI and for `pnpm pr:review` to exit 0, and, while `pr:review` reports UNREVIEWED (Macroscope at its spending limit), requires a Claude correctness review of the PR's own diff (reviewed paths only) and stops on any finding of Medium severity or higher. For that, before the driver lands a queued PR, the PM has a review agent review the PR's diff at the queue line's clean head and write `/tmp/land-reviews/precomputed/<pr>.json` as `{ "pr": <n>, "head": "<clean-head sha>", "findings": [{ "severity", "file", "line", "summary", "failure_scenario" }] }`; the driver's default reviewer (`pnpm land:review-lookup`) fails the PR when that file is missing, malformed, for another PR or for another head. It then merges with `gh pr merge --merge --match-head-commit <sha>`, checks that `master`'s tree equals the commit's (docs/goals/** excepted), moves every open PR based on the merged branch to `master`, and deletes the branch last (GitHub closes a PR whose base branch is deleted). Every `master` merge commit therefore carries device evidence from its own tree. A failed check, a finding or a tree mismatch takes that PR out of the queue and back to its worker (steps 4–6), with the `landing-failed` label and a comment naming the failed step; the PRs after it in its batch are rebuilt on the new `master`, and the queue continues. Never retry a failed check until it goes green; fix the cause or report it (the driver retries only transient gh and git network errors). After each merge the driver runs `git pull --ff-only` in the main checkout. To reorder or pause the queue, `touch /tmp/dragon-land.stop` (or `kill -USR1` the pid in `/tmp/dragon-land.lock/pid`): the driver lands what it can of its current batch and exits without starting another. `kill -TERM` on that pid (the supervisor's) interrupts: the running step is killed with the driver's process group, the status says INTERRUPTED and names what merged, and no PR is failed. A merge in progress (from `gh pr merge` to the post-merge checks) finishes first; a second `kill -TERM` kills it at once. If an interrupted run left `master` on a merged position no full test has passed, the next run proves `master` first and logs a red result loudly, then carries on; a passing proof that contains that position clears the record.
Expand All @@ -30,7 +30,7 @@ Code reaches `master` only through a pull request that Macroscope has reviewed.
- The main checkout follows `origin/master`: after every merge, and before dispatching new work, run `git pull --ff-only` there. Never stash, reset or discard uncommitted edits to do it; if it can't fast-forward, report why.
- Before pushing anything straight to `master`, run `git pull --rebase origin master` first.

Two cases skip the pull request and push straight to `master`: PM board updates that touch only `docs/goals/**`, and small changes the owner asks for directly in the conversation (README wording, docs, config). Still run step 2 first.
Two cases skip the pull request and push straight to `master`: PM board updates that touch only `docs/goals/**`, and small changes the owner asks for directly in the conversation (README wording, docs, config). Still run step 2 first. Board-only `docs/goals/**` pushes need only step 2's `pnpm typecheck`. An owner-requested change never passes through the landing driver, so before pushing it run the full test of the exact commit you will push. On the Mac that is `pnpm test`. In a cloud session, push the commit to a scratch branch, run `gh workflow run full-test.yml -f sha=<sha>`, and wait for that run (titled `full test of <sha>`; `gh api "repos/compiled-run/dragoncss/actions/workflows/full-test.yml/runs?event=workflow_dispatch&per_page=50" --jq '.workflow_runs[] | select(.display_title == "full test of <sha>") | "\(.id) \(.status) \(.conclusion)"'`) to end in success. Rebase it onto the current `origin/master` before the test; if `master` moves before your push, rebase and run the full test again. Then push that same commit to `master` and delete the scratch branch, or ask the PM to delete it, since the cloud proxy refuses branch deletions.

Dispatched workers never push to `master` and never merge. A worker pushes its own branch, opens its PR (step 3), runs steps 4–6 until `pnpm pr:review` exits 0, and hands the clean head to the landing queue in its receipt. Lane rules: docs/goals/milestone-2-proof/lane-contract.md.

Loading
Loading