commit 67774255ed3e8f0ff24152150fc3af9eb2e025f2 (tree)
parent be6348de8fff59009870240433ef337849b5be25
Author: Motiejus Jakštys <motiejus@jakstys.lt>
Date: Mon, 16 Feb 2026 21:28:50 +0000
add skill
Diffstat:
2 files changed, 285 insertions(+), 0 deletions(-)
diff --git a/stage0/.claude/skills/fix-stages/SKILL.md b/stage0/.claude/skills/fix-stages/SKILL.md
@@ -0,0 +1,150 @@
+---
+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
+./zig3 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
+./zig3 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
+./zig3 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
+./zig3 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
@@ -0,0 +1,135 @@
+# 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
+./zig3 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
+./zig3 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
+./zig3 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 `./zig3 build` commands, use *only* `./zig3 build *-zig0`. Other
+ `./zig3 build` commands may start building/testing zig itself, which takes
+ ages and is wholly unnecessary.