zig

fork of https://codeberg.org/ziglang/zig
Log | Files | Refs | README | LICENSE

commit dd762f7bcff6e02254e6291317a16575a282b0e0 (tree)
parent 3e75fb41a9176df8234fea8731506f0b4d697951
Author: Motiejus Jakštys <motiejus@jakstys.lt>
Date:   Wed, 18 Feb 2026 21:10:42 +0000

skills: replace port-astgen + fix-stages with unified enable-tests

Combine two specialized skills (port-astgen for astgen_test.zig,
fix-stages for stages_test.zig) into a single parameterized skill
that takes any test file as input. Improvements over the originals:

- Config table maps test files to modifiable/reference files
- Flush accumulated passing tests before dispatching worker
- Fast test-zig0 for per-iteration verification, valgrind only in final check
- Worker budget (~15 cycles) to avoid context exhaustion
- Guard rail: skip test after 2 consecutive no-progress
- Worker truncates output (tail -50) and never reads whole reference files
- Handles all failure types: parser, AstGen, and sema

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

Diffstat:
Astage0/.claude/skills/enable-tests/SKILL.md | 211+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Astage0/.claude/skills/enable-tests/worker-prompt.md | 145+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Dstage0/.claude/skills/fix-stages/SKILL.md | 150-------------------------------------------------------------------------------
Dstage0/.claude/skills/fix-stages/worker-prompt.md | 135-------------------------------------------------------------------------------
Dstage0/.claude/skills/port-astgen/SKILL.md | 163-------------------------------------------------------------------------------
Dstage0/.claude/skills/port-astgen/worker-prompt.md | 132-------------------------------------------------------------------------------
Mstage0/CLAUDE.md | 4++--
7 files changed, 358 insertions(+), 582 deletions(-)

diff --git a/stage0/.claude/skills/enable-tests/SKILL.md b/stage0/.claude/skills/enable-tests/SKILL.md @@ -0,0 +1,211 @@ +--- +name: enable-tests +description: Iteratively enable disabled tests in a given zig test file, fix divergences by mechanical porting from upstream, and commit. +allowed-tools: Read, Write, Edit, Bash, Grep, Glob, Task +disable-model-invocation: true +--- + +# Enable Tests — Orchestrator + +You manage the iterative loop of enabling disabled tests in a Zig test file. +For each iteration you enable a test, run it, and either batch-commit +passing tests or dispatch a worker to fix failures. + +**Input:** The test file is provided as the skill argument (e.g., +`stage0/astgen_test.zig`). If no argument is given, ask the user. + +**You do NOT**: analyze test output in detail, compare Zig/C code, or +edit C source files. The worker handles all of that. + +**CRITICAL RULES:** +1. **NEVER stop early.** Do not pause to ask the user if you should continue. + Do not summarize remaining work and wait. Keep looping until every disabled + test is enabled and passing. +2. **ALWAYS run the test command yourself before committing.** Never trust + the worker's claim that tests pass — verify it. +3. **Batch passing tests.** When multiple consecutive tests pass without code + changes, commit them together in one commit. + +## File Configuration + +Based on the test file argument, look up which files are in scope: + +| Test file | Modifiable files | Git-add list | Key reference files | +|---|---|---|---| +| `astgen_test.zig` | `astgen.c`, `astgen_test.zig` | `stage0/astgen.c stage0/astgen_test.zig` | `lib/std/zig/AstGen.zig`, `lib/std/zig/Ast.zig`, `lib/std/zig/Zir.zig` | +| `stages_test.zig` | `astgen.c`, `parser.c`, `sema.c`, `stages_test.zig` | `stage0/astgen.c stage0/parser.c stage0/sema.c stage0/stages_test.zig` | `lib/std/zig/AstGen.zig`, `lib/std/zig/Parse.zig`, `lib/std/zig/Ast.zig`, `lib/std/zig/Zir.zig`, `src/Sema.zig` | +| `sema_test.zig` | `sema.c`, `intern_pool.c`, `sema_test.zig` | `stage0/sema.c stage0/intern_pool.c stage0/sema_test.zig` | `src/Sema.zig`, `src/InternPool.zig`, `src/Air.zig` | + +All C source paths are under `stage0/`. Reference paths are relative to the +repository root. + +If the test file is not in the table, infer by inspecting the file's imports +and the types of failures it can produce. To add a new test file, add a row +with its modifiable C sources, git-add list, and upstream reference files. + +## Phase 0: Verify baseline is green + +Run the full test suite: + +```sh +cd ~/code/zig +./zig-out/bin/zig build test-zig0 -Dzig0-cc=tcc 2>&1 | tail -5 +``` + +If non-zero exit or failures: dispatch a worker (Step 4) with the failure +context. After the worker returns, follow Steps 5-7. Re-run Phase 0 until +clean. + +If clean: proceed to the main loop. + +## Main Loop + +Repeat until no disabled tests remain in the test file. + +### Step 1: Find the next disabled test + +Search the test file in priority order: + +**Priority A -- SkipZigTest lines:** +Search for lines matching: +``` +if (true) return error.SkipZigTest +``` +Pick the first one. Note the test name (the `test "..."` header above +the skip line) and the line number. + +**Priority B -- Commented corpus entries:** +Search for lines matching `//"..` inside the `corpus_files` tuple +(between `const corpus_files = .{` and `};`). Pick the first one. +Note the file name and line number. + +If neither is found, all tests are enabled -- go to Final Check. + +### Step 2: Enable the test + +**For SkipZigTest:** Comment out the `if (true) return error.SkipZigTest;` +line to enable the test. + +**For commented corpus entry:** Uncomment the line (remove `//` prefix). + +### Step 3: Smoke test + +```sh +./zig-out/bin/zig build test-zig0 -Dzig0-cc=tcc 2>&1 | tail -10 +``` + +### Step 4: Evaluate and dispatch + +**If it passes** -- go back to Step 1 and enable the next test. Accumulate +passing tests without committing yet. + +**If it fails** -- first, flush any accumulated passing tests. If there +are previously-enabled tests that passed without code changes, commit them +now before dispatching the worker. This isolates the worker's code changes +from the batch of trivially-passing tests: + +```sh +git add <git-add-list> +git commit -m "<test_file>: enable <accumulated list> + +Co-Authored-By: <model name>" +``` + +Then dispatch a worker: + +1. Read `.claude/skills/enable-tests/worker-prompt.md`. +2. Replace `{{TEST_CONTEXT}}` with: + - Test file name + - What was enabled: test name or corpus file path + line number + - First ~20 lines of test output from Step 3 (use `tail -20`) + - Modifiable C files (from the configuration table above) + - Key reference files (from the configuration table above) +3. Launch via the Task tool: + ``` + subagent_type=general-purpose + prompt=<the worker prompt with context filled in> + ``` + +### Step 5: Parse worker response + +Extract: +- `STATUS`: one of `pass`, `progress`, or `no-progress` +- `COMMIT_MSG`: a descriptive commit message + +If the worker response does not end with the expected STATUS format, +treat it as `no-progress` and verify the test file was reverted. + +### Step 6: Handle by status + +**If STATUS is `pass` or `progress`:** + +Verify before committing (use the fast test command, not valgrind): + +```sh +./zig-out/bin/zig build test-zig0 -Dzig0-cc=tcc 2>&1 | tail -10 ; echo "EXIT: $?" +``` + +Check: (1) EXIT is 0, (2) no test failures. If either fails, dispatch +another worker to fix. + +Only if clean, commit all accumulated changes: + +```sh +git add <git-add-list from configuration table> +git commit -m "<COMMIT_MSG> + +Co-Authored-By: <model name>" +``` + +If `progress` (not `pass`), the worker re-disabled the test. Commit +anyway -- the passing tests + partial fix are still valuable. + +**If STATUS is `no-progress`:** + +Worker should have re-disabled the test. Verify: + +```sh +git diff stage0/ +``` + +If there are accumulated passing tests, commit those: + +```sh +git add <git-add-list> +git commit -m "<test_file_name>: enable <list of tests> + +Co-Authored-By: <model name>" +``` + +If nothing to commit, revert and continue: + +```sh +git checkout -- <git-add-list> +``` + +### Step 7: Repeat + +Go back to Step 1. **Never stop early** -- continue until all disabled +tests are enabled. + +**Guard rail:** If the same test receives `no-progress` twice in a row, +skip it permanently (leave it disabled) and move to the next test. Log +which test was skipped. + +## Commit message conventions + +- Batch of passing tests: `"<test_file>: enable <file1>, <file2>, ..."` +- Worker fix + passing tests: use the worker's COMMIT_MSG +- If the list is too long: `"<test_file>: enable N files from <dir>/"` + +## Final Check + +When no disabled tests remain (or all remaining are permanently skipped), +run the full suite with valgrind (this is the only place where valgrind +is used -- per-iteration verification uses the fast `test-zig0` command): + +```sh +./zig-out/bin/zig build all-zig0 -Dvalgrind |& grep -v Warning | head -10 ; echo "EXIT: $?" +``` + +Must exit 0 with no unexpected output. diff --git a/stage0/.claude/skills/enable-tests/worker-prompt.md b/stage0/.claude/skills/enable-tests/worker-prompt.md @@ -0,0 +1,145 @@ +# Enable Tests -- Worker (single iteration) + +You are a worker agent fixing a test failure. The orchestrator has enabled a +test for you (either by uncommenting a corpus entry or by commenting out a +`SkipZigTest` line). Your job: diagnose the failure, port the fix from +upstream Zig to C, clean up, and return a result. + +This is a **mechanical translation** -- no creativity, no invention. When the +C code differs from Zig, copy the Zig structure into C. + +## Context from orchestrator + +{{TEST_CONTEXT}} + +## Workflow + +### Step 1: Run the test + +```sh +cd ~/code/zig +./zig-out/bin/zig build test-zig0 -Dzig0-cc=tcc 2>&1 | tail -50 +``` + +Capture the last ~50 lines. If tests pass, skip to Step 5. + +### Step 2: Determine failure stage + +From the output, identify the failure type: + +**Parser failure** (stack trace through `parser_test` or `expectAstConsistent`): +- AST node/token mismatch between C and Zig parsers +- Rendered output doesn't match source (canonical form) +- Fix target: `stage0/parser.c`, reference: `lib/std/zig/Parse.zig` + +**AstGen failure** (stack trace through `astgen_test` or `expectEqualZir`): +- `has_compile_errors` -- C AstGen emitted compile errors +- `expectEqualZir` -- ZIR instruction/extra/string mismatch +- `unhandled tag N` -- missing tag in `expectEqualData`/`dataMatches` +- Fix target: `stage0/astgen.c` (or test zig for unhandled tags), + reference: `lib/std/zig/AstGen.zig` + +**Sema failure** (stack trace through `sema` or Air checks): +- `has_compile_errors` -- C Sema emitted compile errors +- Air array null checks failed +- Fix target: `stage0/sema.c`, reference: `src/Sema.zig` + +### Step 3: Analyze the failure + +**For `has_compile_errors`:** Temporarily add `#include <stdio.h>` and +`fprintf(stderr, ...)` to `setCompileError()` (or the sema equivalent) +to find which error fires. Run the test again and note the function +and line. + +**For ZIR mismatch:** Note `inst_len`, `extra_len`, `string_bytes_len` +diffs and the first tag mismatch position. + +**For `unhandled tag N`:** Add the missing tag to `expectEqualData` and +`dataMatches` switch statements in the test file. + +**For parser failures:** Note the AST node index, expected vs actual +tag/token, and surrounding source context. + +### Step 4: Compare and port + +Find the upstream Zig function that corresponds to the failing code path. +Use the Task tool with `subagent_type=general-purpose` to search for and +read **only the specific function** in both implementations (C and Zig). +Do NOT read entire files -- request just the relevant function(s). + +Enumerate differences that affect output: +- Extra data written (field order, conditional fields, body lengths) +- Instruction tags emitted +- String table entries +- Break payload values +- AST node tags and token associations + +Apply the minimal mechanical change to match the upstream. Make ONE change +at a time. After each change, run: + +```sh +./zig-out/bin/zig build test-zig0 -Dzig0-cc=tcc 2>&1 | tail -20 +``` + +Check that no previously-passing tests broke. + +**Progress** means any of: +- `inst_len` / `extra_len` / `string_bytes_len` diff decreased +- First tag mismatch position moved later +- Compile errors resolved (even if other mismatch remains) +- AST mismatch moved to a later node + +### Step 5: Clean up + +1. Remove ALL `fprintf`/`printf` debug statements from C files. +2. Remove `#include <stdio.h>` if it was added for debugging. +3. Verify with: `grep -n 'fprintf\|printf' stage0/astgen.c stage0/parser.c stage0/sema.c` +4. If the test still fails: + - **For SkipZigTest:** re-add the `if (true) return error.SkipZigTest;` + line with a TODO comment describing the remaining diff. + - **For corpus entry:** re-comment the line (add `//` prefix back) and + add a TODO comment above it describing the remaining diff. +5. Final verification -- this must exit 0: + +```sh +./zig-out/bin/zig build test-zig0 -Dzig0-cc=tcc 2>&1 | tail -5 +``` + +### Step 6: Return result + +You MUST end your response with exactly this format: + +``` +STATUS: pass | progress | no-progress +COMMIT_MSG: <one-line descriptive message about what was ported/fixed> +``` + +- `pass` -- the enabled test now passes (entry remains enabled) +- `progress` -- partial progress was made (entry was re-disabled with TODO) +- `no-progress` -- no measurable improvement (entry was re-disabled) + +## Rules + +- **Mechanical copy only.** Do not invent new approaches. If the upstream does + X, do X in C. +- **Never remove zig-cache.** +- **NEVER print to stdout/stderr in committed code.** Debug prints are + temporary only. Before returning, grep for `fprintf|printf` in all C files + and remove any you find. +- **Do NOT commit.** The orchestrator handles all commits. +- **Functions must appear in the same order as in the upstream Zig file.** +- **Prefer finding systematic differences** instead of debugging by bisection. + Zig code is bug-free for the purposes of porting. When test cases fail, it + means the C implementation differs from the Zig one. Making implementations + consistent is the correct approach. +- From `./zig-out/bin/zig build` commands, use **only** `./zig-out/bin/zig build *-zig0`. + Other targets may build/test zig itself, which takes ages and is unnecessary. +- When reading upstream reference files, **never read the whole file**. + Use Grep to find the function, then Read with offset/limit to get only the + relevant section. AstGen.zig is 568K, Sema.zig is 1.6M -- reading them + whole will blow your context. +- **Budget your iterations.** If after ~15 test-fix cycles you have made + progress but cannot fully fix the test, stop iterating. Clean up (Step 5) + and report `progress`. The orchestrator will commit partial work and can + dispatch you again later. Do not exhaust your context chasing diminishing + returns. diff --git a/stage0/.claude/skills/fix-stages/SKILL.md b/stage0/.claude/skills/fix-stages/SKILL.md @@ -1,150 +0,0 @@ ---- -name: fix-stages -description: Iteratively enable commented-out corpus entries in stages_test.zig, fix parser/AstGen divergences, and commit. -allowed-tools: Read, Write, Edit, Bash, Grep, Glob, Task -disable-model-invocation: true ---- - -# Fix Stages — Orchestrator - -You manage the iterative loop of enabling corpus entries in `stages_test.zig`. -For each iteration you uncomment entries, test them, and either batch-commit -passing files or dispatch a worker to fix failures. - -**You do NOT**: analyze test output in detail, compare Zig/C code, or -edit `astgen.c`/`parser.c`. The worker handles all of that. - -**CRITICAL RULES:** -1. **NEVER stop early.** Do not pause to ask the user if you should continue. - Do not summarize remaining work and wait. Keep looping until every corpus - entry is uncommented and passing. -2. **ALWAYS run the test command yourself before committing.** Never trust - the worker's claim that tests pass — verify it. -3. **Batch passing files.** When multiple consecutive files pass without code - changes, commit them together in one commit. - -## Phase 0: Verify baseline is green - -Run the full test suite: - -```sh -cd ~/code/zig -./zig-out/bin/zig build test-zig0 -Dzig0-cc=tcc 2>&1 | tail -5 -``` - -If non-zero exit or failures: dispatch a worker (Step 4) with the failure -context. After the worker returns, follow Steps 5–7. Re-run Phase 0 until -clean. - -If clean: proceed to the main loop. - -## Main Loop - -Repeat until no commented-out entries (`//"..`) remain in `stages_test.zig` -`corpus_files`. - -### Step 1: Uncomment the next entry - -Search `stage0/stages_test.zig` for lines matching `//"..` inside the -`corpus_files` tuple. Pick the first one. Uncomment it (remove `//` prefix). - -### Step 2: Smoke test - -```sh -./zig-out/bin/zig build test-zig0 -Dzig0-cc=tcc 2>&1 | tail -10 -``` - -### Step 3: Evaluate result - -**If it passes** — go back to Step 1 and uncomment the next entry. Accumulate -passing files without committing yet. - -**If it fails** — proceed to Step 4 for the failing file. - -### Step 4: Dispatch worker - -1. Read `.claude/skills/fix-stages/worker-prompt.md`. -2. Replace `{{TEST_CONTEXT}}` with: - - File path that failed - - First ~20 lines of test output from Step 2 -3. Launch via the Task tool: - ``` - subagent_type=general-purpose - prompt=<the worker prompt with context filled in> - ``` - -### Step 5: Parse worker response - -Extract: -- `STATUS`: one of `pass`, `progress`, or `no-progress` -- `COMMIT_MSG`: a descriptive commit message - -### Step 6: Handle by status - -**If STATUS is `pass` or `progress`:** - -Verify before committing: - -```sh -./zig-out/bin/zig build all-zig0 -Dvalgrind |& grep -v Warning | head -10 ; echo "EXIT: $?" -``` - -Check: (1) EXIT is 0, (2) no unexpected errors. If either fails, dispatch -another worker to fix. - -Only if clean, commit all accumulated changes: - -```sh -git add stage0/astgen.c stage0/parser.c stage0/stages_test.zig -git commit -m "<COMMIT_MSG> - -Co-Authored-By: <model name>" -``` - -If `progress` (not `pass`), the worker re-commented the failing entry. Commit -anyway — the passing files + partial fix are still valuable. - -**If STATUS is `no-progress`:** - -Worker should have re-commented the entry. Verify: - -```sh -git diff stage0/stages_test.zig -``` - -If there are accumulated passing files (from previous Step 3a iterations), -commit those: - -```sh -git add stage0/stages_test.zig -git commit -m "stages_test: enable <list of files> - -Co-Authored-By: <model name>" -``` - -If nothing to commit, revert and continue: - -```sh -git checkout -- stage0/astgen.c stage0/parser.c stage0/stages_test.zig -``` - -### Step 7: Repeat - -Go back to Step 1. **Never stop early** — continue until all corpus entries -are uncommented. - -## Commit message conventions - -- Batch of passing files: `"stages_test: enable <file1>, <file2>, ..."` -- Worker fix + passing files: use the worker's COMMIT_MSG -- If the list of files is too long, use `"stages_test: enable N files from <dir>/"` - -## Final Check - -When no commented-out entries remain, run: - -```sh -./zig-out/bin/zig build all-zig0 -Dvalgrind |& grep -v Warning | head -10 ; echo "EXIT: $?" -``` - -Must exit 0 with no output. diff --git a/stage0/.claude/skills/fix-stages/worker-prompt.md b/stage0/.claude/skills/fix-stages/worker-prompt.md @@ -1,135 +0,0 @@ -# Fix Stages — Worker (single iteration) - -You are a worker agent fixing a corpus test failure in `stages_test.zig`. -The file fails either at the **parser stage** (C parser vs Zig parser) or the -**AstGen stage** (C AstGen vs Zig AstGen). Your job: diagnose the failure, -port the fix from upstream Zig to C, clean up, and return a result. - -This is a **mechanical translation** — no creativity, no invention. When the -C code differs from Zig, copy the Zig structure into C. - -## Context from orchestrator - -{{TEST_CONTEXT}} - -## Key files - -- `stage0/astgen.c` — C AstGen implementation (modify if AstGen failure) -- `stage0/parser.c` — C parser implementation (modify if parser failure) -- `stage0/stages_test.zig` — corpus test (re-comment entry if can't fix) -- `stage0/parser_test.zig` — parser test infrastructure (comparators) -- `stage0/astgen_test.zig` — AstGen test infrastructure (comparators) -- `lib/std/zig/AstGen.zig` — upstream AstGen reference (~14k lines) -- `lib/std/zig/Parse.zig` — upstream parser reference -- `lib/std/zig/Ast.zig` — AST node accessors -- `lib/std/zig/Zir.zig` — ZIR instruction definitions - -## Workflow - -### Step 1: Run the full test - -```sh -cd ~/code/zig -./zig-out/bin/zig build test-zig0 -Dzig0-cc=tcc 2>&1 -``` - -Record the full output. If tests pass, skip to Step 5. - -### Step 2: Determine failure stage - -From the stack trace, identify which stage failed: - -- **Parser failure**: stack trace goes through `parser_test.corpusCheck` - - `expectAstConsistent` — AST node/token mismatch between C and Zig parsers - - `expectEqualStrings` — rendered output doesn't match source (canonical form) - -- **AstGen failure**: stack trace goes through `astgen_test.corpusCheck` - - `has_compile_errors` — C AstGen emitted compile errors - - `expectEqualZir` — ZIR instruction/extra/string mismatch - - `expectEqualData` — specific data field mismatch - -### Step 3: Analyze the failure - -**For AstGen `has_compile_errors`:** Temporarily add `#include <stdio.h>` and -`fprintf(stderr, ...)` to `setCompileError()` in `astgen.c` to find which -`SET_ERROR` fires. Run the test again and note the function and line. - -**For AstGen `zir mismatch`:** Note `inst_len`, `extra_len`, -`string_bytes_len` diffs and the first tag mismatch position. - -**For parser failures:** Note the AST node index, expected vs actual tag/token, -and surrounding source context. - -### Step 4: Compare and port - -Find the upstream Zig function that corresponds to the failing code path. -Use the Task tool with `subagent_type=general-purpose` to read both -implementations and enumerate **every difference**. - -Focus on differences that affect output: -- Extra data written (field order, conditional fields, body lengths) -- Instruction tags emitted -- String table entries -- Break payload values -- AST node tags and token associations - -Apply the minimal mechanical change to match the upstream. Make ONE change at -a time. After each change, run: - -```sh -./zig-out/bin/zig build test-zig0 -Dzig0-cc=tcc 2>&1 | head -20 -``` - -Check that no previously-passing tests broke. - -**Progress** means any of: -- `inst_len` diff decreased -- `extra_len` diff decreased -- `string_bytes_len` diff decreased -- First tag mismatch position moved later -- Compile errors resolved (even if ZIR mismatch remains) -- AST mismatch moved to a later node - -### Step 5: Clean up - -1. Remove ALL `fprintf`/`printf` debug statements from `astgen.c`/`parser.c`. -2. Remove `#include <stdio.h>` if it was added for debugging. -3. If the test still fails: - - Re-comment the entry in `stages_test.zig` (add `//` prefix back). - - Add a TODO comment above it describing the remaining diff. -4. Final verification — this must exit 0: - -```sh -./zig-out/bin/zig build test-zig0 -Dzig0-cc=tcc 2>&1 | tail -5 -``` - -### Step 6: Return result - -You MUST end your response with exactly this format: - -``` -STATUS: pass | progress | no-progress -COMMIT_MSG: <one-line descriptive message about what was ported/fixed> -``` - -- `pass` — the enabled test now passes (entry remains uncommented) -- `progress` — partial progress was made (entry was re-commented with TODO) -- `no-progress` — no measurable improvement (entry was re-commented) - -## Rules - -- **Mechanical copy only.** Do not invent new approaches. If the upstream does - X, do X in C. -- **Never remove zig-cache.** -- **NEVER print to stdout/stderr in committed code.** Debug prints are - temporary only. Before returning, grep for `fprintf\|printf` in - `astgen.c`/`parser.c` and remove any you find. -- **Do NOT commit.** The orchestrator handles all commits. -- **Functions must appear in the same order as in the upstream Zig file.** -- **Prefer finding systematic differences** instead of debugging and hunting - for bugs. Zig code is bug-free for the purposes of porting. When test cases - fail, it means the C implementation differs from the Zig one. Making - implementations consistent is the correct approach. -- From `./zig-out/bin/zig build` commands, use *only* `./zig-out/bin/zig build *-zig0`. Other - `./zig-out/bin/zig build` commands may start building/testing zig itself, which takes - ages and is wholly unnecessary. diff --git a/stage0/.claude/skills/port-astgen/SKILL.md b/stage0/.claude/skills/port-astgen/SKILL.md @@ -1,163 +0,0 @@ ---- -name: port-astgen -description: Iteratively port AstGen.zig to astgen.c by enabling skipped corpus tests, finding divergences, and mechanically copying upstream code. -allowed-tools: Read, Write, Edit, Bash, Grep, Glob, Task -disable-model-invocation: true ---- - -# Port AstGen — Orchestrator - -You manage the iterative porting loop. For each iteration you either fix -existing failures or enable a new disabled test, dispatch a worker agent, -then verify and commit. - -**You do NOT**: analyze test output in detail, compare Zig/C code, or -edit `astgen.c`. The worker handles all of that. - -**CRITICAL RULES:** -1. **NEVER stop early.** Do not pause to ask the user if you should continue. - Do not summarize remaining work and wait. Keep looping until every test is - enabled and passing. -2. **ALWAYS run the test command (in Phase 0, below) yourself before - committing.** Never trust the worker's claim that tests pass — verify it. If - the test run fails (non-zero exit) or it emits any output, do NOT commit and - let the worker fix it. - -## Phase 0: Check for leftovers - -Before enabling anything new, run the **full** test suite: - -```sh -cd ~/code/zig -./zig-out/bin/zig build all-zig0 -Dvalgrind > /dev/null 2>&1 ; echo "EXIT: $?" -``` - -Also check for failures: - -```sh -./zig-out/bin/zig build all-zig0 -Dvalgrind 2>&1 | grep -iE 'FAIL|error:' | head -5 -``` - -If EXIT is non-zero or any FAIL/error lines appear: dispatch a worker -(Step 4 below) with context describing the failure — no test was -"enabled", just paste the output and tell the worker existing tests are -failing. After the worker returns, follow Steps 5–7 as normal. Re-run -Phase 0 until the full test suite passes before proceeding to the main -loop. - -If EXIT is 0 with no failures: proceed to the main loop. - -## Main Loop - -Repeat until no `SkipZigTest` lines AND no commented corpus entries -remain in `astgen_test.zig`. - -### Step 1: Find the next disabled test - -Search `stage0/astgen_test.zig` in priority order: - -**Priority A — SkipZigTest lines:** -Search for lines matching: -``` -if (true) return error.SkipZigTest -``` -Pick the first one. Note the test name (the `test "..."` header above -the skip line) and the line number. - -**Priority B — Commented corpus entries:** -If no SkipZigTest lines exist, search for lines matching `//"..\` inside -the `corpus_files` tuple (between `const corpus_files = .{` and `};`). -Pick the first one. Note the file name and line number. - -If neither is found, all tests are enabled — go to the final check. - -### Step 2: Enable the test - -**For SkipZigTest:** Comment out the `if (true) return error.SkipZigTest;` -line to enable the test. - -**For commented corpus entry:** Uncomment the line (remove the leading -`//`). - -### Step 3: Quick smoke test - -Run: -```sh -./zig-out/bin/zig build test-zig0 -Dzig0-cc=tcc 2>&1 | head -10 -``` -Capture only the first ~10 lines. This tells you pass/fail at a glance -without bloating your context. The worker will run the full test itself. - -### Step 4: Dispatch worker - -1. Read the file `.claude/skills/port-astgen/worker-prompt.md`. -2. Replace the placeholder `{{TEST_CONTEXT}}` with the actual context: - - What was enabled: test name + line number (SkipZigTest) or - corpus file name + line number (corpus entry) - - Whether this is a SkipZigTest or a corpus entry - - The first ~10 lines of test output from Step 3 -3. Launch via the Task tool: - ``` - subagent_type=general-purpose - prompt=<the worker prompt with context filled in> - ``` - -### Step 5: Parse worker response - -The worker returns a structured result. Extract: -- `STATUS`: one of `pass`, `progress`, or `no-progress` -- `COMMIT_MSG`: a descriptive commit message - -### Step 6: Handle by status - -**If STATUS is `pass` or `progress`:** - -**You MUST verify before committing.** Run: - -```sh -./zig-out/bin/zig build all-zig0 -Dvalgrind |& grep -v Warning | head -10 ; echo "EXIT: $?" -``` - -Check two things only: (1) EXIT is 0, (2) the ~10 lines of output -contain no unexpected errors. If either check fails, do NOT commit — -dispatch another worker to fix. - -Only if clean, commit: - -```sh -git add stage0/astgen.c stage0/astgen_test.zig -git commit -m "<COMMIT_MSG from worker> - -Co-Authored-By: <whatever model is running this>" -``` - -**If STATUS is `no-progress`:** - -Do NOT commit. The worker should have reverted the test file (re-added -SkipZigTest or re-commented the corpus entry). Verify with: - -```sh -git diff stage0/astgen_test.zig -``` - -If there are leftover changes (the entry is still enabled), re-comment -the corpus entry or re-add the SkipZigTest yourself. Then: - -```sh -git checkout -- stage0/astgen.c stage0/astgen_test.zig -``` - -Log that this test was skipped due to no progress and continue. - -### Step 7: Repeat - -Go back to Step 1. **Never stop early** — continue until all -`SkipZigTest` lines are gone AND all corpus entries are uncommented. - -## Final Check - -When no disabled tests remain, run: - - ./zig-out/bin/zig build all-zig0 -Dvalgrind - -If that fails, go back to Phase 0 (treat it as a leftover). diff --git a/stage0/.claude/skills/port-astgen/worker-prompt.md b/stage0/.claude/skills/port-astgen/worker-prompt.md @@ -1,132 +0,0 @@ -# Port AstGen — Worker (single iteration) - -You are a worker agent porting `AstGen.zig` to `astgen.c`. This is a -**mechanical translation** — no creativity, no invention. When the C -code differs from Zig, copy the Zig structure into C. - -The orchestrator has enabled a test for you (either by uncommenting a -corpus entry in `corpus_files` or by commenting out a `SkipZigTest` -line). Your job: diagnose any failure, port the fix, clean up, and -return a result. - -## Context from orchestrator - -{{TEST_CONTEXT}} - -## Key files - -- `stage0/astgen.c` — C implementation (modify this) -- `stage0/astgen_test.zig` — corpus tests (enable/skip tests here) -- `lib/std/zig/AstGen.zig` — upstream reference (~14k lines) -- `lib/std/zig/Ast.zig` — AST node accessors -- `lib/std/zig/Zir.zig` — ZIR instruction definitions - -## Workflow - -### Step 1: Run the full test - -```sh -cd ~/code/zig -./zig-out/bin/zig build test-zig0 -Dzig0-cc=tcc 2>&1 -``` - -Record the full output. If tests pass, skip to Step 5. - -### Step 2: Analyze the failure - -From the test output, determine the failure type: - -- **`has_compile_errors`**: Temporarily add `#include <stdio.h>` and - `fprintf(stderr, ...)` to `setCompileError()` in `astgen.c` to find - which `SET_ERROR` fires. Run the test again and note the function and - line. -- **`zir mismatch`**: Note `inst_len`, `extra_len`, `string_bytes_len` - diffs and the first tag mismatch position. -- **`unhandled tag N`**: Add the missing ZIR tag to the `expectEqualData` - and `dataMatches` switch statements in `astgen_test.zig`. - -### Step 3: Compare implementations - -Find the upstream Zig function that corresponds to the failing code -path. Use the Task tool with `subagent_type=general-purpose` to read -both implementations and enumerate **every difference**. - -Focus on differences that affect output: -- Extra data written (field order, conditional fields, body lengths) -- Instruction tags emitted -- String table entries -- Break payload values (operand_src_node) - -Do NOT guess. Read both implementations completely and compare mechanically. - -### Step 4: Port the fix - -Apply the minimal mechanical change to `astgen.c` to match the upstream. -Make ONE change at a time. After each change, run: - -```sh -./zig-out/bin/zig build test-zig0 -Dzig0-cc=tcc 2>&1 | head -20 -``` - -Check that no previously-passing tests broke. If your change causes -regressions (new FAILs or crashes that weren't there before), revert it -immediately. - -**Progress** means any of: -- `inst_len` diff decreased -- `extra_len` diff decreased -- `string_bytes_len` diff decreased -- First tag mismatch position moved later - -You should mark progress marker (whatever it is from the above) *in/near -the disabled test entry* (as a TODO comment on the SkipZigTest line or -above the commented corpus entry). - -### Step 5: Clean up - -1. Remove ALL `fprintf`/`printf` debug statements from `astgen.c`. -2. Remove `#include <stdio.h>` if it was added for debugging. -3. If the test still fails: - - **For a SkipZigTest test:** re-add the `if (true) return error.SkipZigTest;` - line with a TODO comment describing the remaining diff. - - **For a corpus entry:** re-comment the line in `corpus_files` (add `//` - prefix back) and add a TODO comment above it describing the remaining diff. -4. Final verification — this must exit 0 with no output: - - ./zig-out/bin/zig build all-zig0 -Dvalgrind |& grep -v Warning | head -100 - -### Step 6: Return result - -You MUST end your response with exactly this format: - -``` -STATUS: pass | progress | no-progress -COMMIT_MSG: <one-line descriptive message about what was ported/fixed> -``` - -- `pass` — the enabled test now passes (SkipZigTest was NOT re-added / - corpus entry remains uncommented) -- `progress` — partial progress was made (SkipZigTest was re-added with - TODO / corpus entry was re-commented with TODO above it) -- `no-progress` — no measurable improvement (SkipZigTest was re-added / - corpus entry was re-commented) - -## Rules - -- **Mechanical copy only.** Do not invent new approaches. If the upstream does - X, do X in C. -- **Never remove zig-cache.** -- **NEVER print to stdout/stderr in committed code.** Debug prints are - temporary only. Before returning, grep for `fprintf\|printf` in - `astgen.c` and remove any you find. -- **Do NOT commit.** The orchestrator handles all commits. -- **Functions must appear in the same order as in the upstream Zig file.** -- **Prefer finding systematic differences for catching bugs** instead of - debugging and hunting for them. Zig code is bug-free for the purposes of - porting. When test cases fail, it means the C implementation differs from the - Zig one, which is the source of the bug. So standard "bug hunting" methods no - longer apply — making implementations consistent is a much better approach - in all ways. -- From `./zig-out/bin/zig build` commands, use *only* `./zig-out/bin/zig build *-zig0`. Other `./zig-out/bin/zig build` - commands may start building/testing zig itself, which takes ages and is - wholly unnecessary. diff --git a/stage0/CLAUDE.md b/stage0/CLAUDE.md @@ -20,6 +20,6 @@ - no `cppcheck` suppressions. They are here for a reason. If it is complaining about automatic variables, make it non-automatic. I.e. find a way to satisfy the linter, do not suppress it. -- if you are in the middle of porting AstGen, load up the skill - .claude/skills/port-astgen/SKILL.md and proceed with it. +- if you are in the middle of enabling tests, load up the skill + .claude/skills/enable-tests/SKILL.md and proceed with it. - remember: **mechanical copy** when porting existing stuff, no new creativity.