From 8e332d1bb2e480effafec4a69faf3146a356631f Mon Sep 17 00:00:00 2001 From: Brian Searls Date: Sun, 19 Apr 2026 20:32:40 -0400 Subject: [PATCH 1/4] docs: add Pure Bootstrap thesis claim + PB program design MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Adds a new §"Pure bootstrap (self-hosted stage0)" claim to THESIS.md §"Thesis claims — complete list". The claim formalizes what was implicit: editing compiler behavior must be a one-file .dag change, never paired hand edits to a Rust stage0 file. Inspired by v2's 97%-generated stage0 pattern (60 generated / 2 hand-maintained), the claim is mechanism-agnostic: emitted Rust committed to tree, not a binary-blob deserializer. v2's proven model guides v3's trajectory. docs/design-pure-bootstrap.md captures the nine-stage PB program (PB-0 ratchet through PB-8 graduation) with: - Current-state measurement (78 hand-maintained .rs in src/v3/compiler) - Target state (≤5 irreducible shim: CLI + runtime bridge) - Dependencies on existing lanes (SG-2/3/4, Lane 1e, TM-1) - Fixed-point acceptance gate (DB-8 extended to full compiler.dag) - Strict acceptance criteria (every .rs is generated OR listed in hand_maintained_src; no middle state) Co-Authored-By: Claude Opus 4.7 (1M context) --- THESIS.md | 22 ++++ docs/design-pure-bootstrap.md | 236 ++++++++++++++++++++++++++++++++++ 2 files changed, 258 insertions(+) create mode 100644 docs/design-pure-bootstrap.md diff --git a/THESIS.md b/THESIS.md index 2cbe138eaac..eeceaf72678 100644 --- a/THESIS.md +++ b/THESIS.md @@ -2062,6 +2062,28 @@ that's a gap. - Adding a CI gate, a Node field, or a target language requires editing one .dag file. +**Pure bootstrap (self-hosted stage0):** +- Editing compiler behavior requires editing `.dag` source only. + No matching hand edits to a Rust stage0 file. Cost-of-change + for any compiler concept — a new pass, a new substrate fact, + a new target-language detail — stays at 1. +- Stage0 is regeneratable from the `.dag` graph. Compiler + internals (tokenize, parse, lower, infer, emit, lenses, std + library) are emitted as Rust source and committed — not hand + authored. The hand-maintained surface is an irreducible shim + (CLI entry + runtime bridge), target ≤5 files. v2 achieves + this pattern at ~97% (2 hand-maintained of 62 stage0 files); + v3's trajectory is the Pure Bootstrap program (see + `docs/design-pure-bootstrap.md`). +- Fixed-point acceptance: v3 binary compiles `compiler.dag` → + produces bit-identical stage0 Rust + bit-identical emitted + artifacts. `compiler.dag`'s `hand_maintained_src` list + monotonically shrinks to the irreducible shim. +- Strictly stronger than "the compiler can compile itself": + the compiler's own source of truth is the `.dag` graph, and + the Rust tree is one realization of it — not a parallel + authority requiring manual sync. + **Modeling discipline:** - Every declared type has at least one structural consumer. - Every service boundary uses typed enums, not String/Bool proxies. diff --git a/docs/design-pure-bootstrap.md b/docs/design-pure-bootstrap.md new file mode 100644 index 00000000000..2739aa0e1f2 --- /dev/null +++ b/docs/design-pure-bootstrap.md @@ -0,0 +1,236 @@ +# Pure Bootstrap (PB program) + +**Thesis claim**: `THESIS.md` §"Pure bootstrap (self-hosted stage0)". + +Editing compiler behavior must be a one-file `.dag` change. No paired +hand edits to a Rust stage0 file. This document is the trajectory from +today (78 hand-maintained `.rs` files in `src/v3/compiler`) to the +irreducible shim (target ≤5 files). + +## Why this matters + +Every hand-maintained Rust file in `src/v3/compiler/src/` is a parallel +authority to the `.dag` declarations it mirrors. Parallel authorities +drift. Per `feedback_parallel_representation_debt`: when a canonical +source exists, consume it rather than scaffold. + +The cost-of-change principle in `CLAUDE.md` asks: "When the language +grows by one type, one expression, or one transport, how many files +need editing? The answer should be 1." Today the answer is 2+ (the +`.dag` authority plus the matching Rust stage0 file). Pure bootstrap +drives it to 1. + +## Inspiration: v2's model + +v2 achieves ~97% generated stage0: + +| File class | Count | LOC | +|---|---|---| +| Generated (`std_*`, `v2_compiler_*`, `extdeps_languages_*`) | 60 | ~88,000 | +| Hand-maintained (`cli_run`, `v2_interpreter`) | 2 | ~2,900 | +| **Total stage0** | **62** | **~91,000** | + +Key v2 properties (all replicated in v3's target end-state): + +1. **Emitted Rust committed to tree** — no `include_str!` runtime + bootstrap of `.dag` files. The std library's primed Dag is baked + into generated Rust constructors at regen time. +2. **Generated headers** — `// Generated by v2 compiler -- do not edit.` +3. **Regen cycle** — `v2 compile → .ci-output/src/*.rs → cp → cargo build` +4. **Hand shim scope** — CLI entry (argv parsing) + tree-walking + interpreter for the runtime service. Both are + user-facing-boundary concerns, not compiler internals. + +The "pure" part of pure bootstrap: **compiler internals have no hand +authority**. Only the system boundary does. + +## Current v3 state + +- **78 hand-maintained `.rs` files** (`src/v3/compiler/tests/integration/sg0_census_test.rs`). +- **4 generated**: lens files (`lens_cost_generated`, + `lens_provenance_generated`, `lens_unused_parameters_generated`, + `lens_structural_resolution_generated`). +- **`bootstrap.rs` uses `include_str!`** to load 7 `.dag` files at + runtime — v3 re-tokenizes, re-parses, re-lowers the std library + every `Dag::new()`. v2 doesn't do this. + +The 78-file gap decomposes: +- ~30 compiler core files (parse, lower, infer, emit, tokenize, ...) +- ~10 lens files (migrating to generated per SG-6) +- ~10 diagnostic / utility files (serialize, diagnostics, types, ...) +- ~15 test infrastructure files +- ~10 bin files (regen_*, self_host_fixed_point, ...) +- ~3 bootstrap / lib files + +## The PB program + +Nine stages, mapping to existing SG and Lane work where possible. + +### PB-0 — ratchet (unblocks everything) + +- SG-0 already tracks `hand_maintained_src` list. Add **PB count** + as a named column with a trend arrow. Ratchet only down. +- **Target trajectory**: 78 → 50 → 20 → 5. +- **Dependencies**: none. Dispatchable now. + +### PB-1 — bootstrap loader emission + +- Replace `bootstrap.rs`'s runtime `include_str!` + tokenize/parse/lower + with generated Rust constructors that build the primed Dag directly. +- Input: `dsl/std/*.dag`. Output: `bootstrap_generated.rs` that calls + `Dag::push_value`, `Dag::push_declaration`, etc. at `Dag::new()`. +- Matches v2's pattern (no runtime `.dag` parsing at bootstrap). +- **Dependencies**: Dag builder API (blocked on TM-1). + +### PB-2 — tokenize retire + +- `tokenize.dag` landed via SG-1. `regen_tokenize` produces + `tokenize_generated.rs` today. +- Retire `tokenize.rs` entirely — lib.rs routes through generated. +- **Dependencies**: SG-1 merge. +- **Counter delta**: -1 file. + +### PB-3 — parse retire + +- Requires `parse.dag` authority (currently SG-2 prep in-flight). +- SG-2 full cutover lane (#557 followup) completes this. +- **Dependencies**: SG-2 full cutover. +- **Counter delta**: -1 file (~2K LOC — the biggest single move). + +### PB-4 — lower retire + +- Requires `lower.dag` authority. SG-3 series is laying groundwork + (SG-3a retiring `operators.rs`). +- **Dependencies**: SG-3 series complete. +- **Counter delta**: -1 file + supporting files (~1K LOC). + +### PB-5 — infer retire + +- Requires `infer.dag` authority. +- SG-4 (SG-4-prep-a landed; full SG-4 dispatch queued). +- **Dependencies**: SG-4 complete. +- **Counter delta**: -1 primary file + helpers. + +### PB-6 — emit retire + +- Collapses `emit.rs`, `emit/rust_target.rs`, `emit/python_target.rs`, + `emit_go.rs`, `emit_python.rs`, `emit_rust.rs` into spec-driven + single walker + per-target spec tiles. +- **Dependencies**: Lane 1e complete. +- **Counter delta**: -6 to -8 files, -10K LOC. Biggest counter move. + +### PB-7 — full fixed-point + +- DB-8 already runs `self_host_fixed_point` in CI on a **fixture**. +- Extend to **full compiler.dag**: v3 compiles compiler.dag → emits + complete stage0 → git-diff clean against checked-in stage0. +- **Dependencies**: PB-2 through PB-6 complete. + +### PB-8 — graduation + +- `hand_maintained_src` list reaches ≤5 entries. +- Delete scaffolding: `include_str!` loader, runtime-parse paths, + census accommodations. +- **Dependencies**: PB-7 green. + +## Acceptance criteria (strict) + +1. Every `.rs` file in `src/v3/compiler/src/` is **either**: + - Generated (ends in `_generated.rs` and has the generated header), **or** + - Listed in `compiler.dag`'s `hand_maintained_src` (target: ≤5 entries). +2. `cargo run -p v3-compiler --release --bin regen_v3` produces + bit-identical Rust (cycle converges in 1 iteration). +3. CI gate: census partition matches directory contents (no + unlisted hand-maintained files, no unmarked generated). +4. No middle state: no file is "generated but hand-edited for + emergency reasons." Edge cases fail-closed via Diagnostic. + +## Irreducible shim (target state) + +Candidates for the ≤5 hand-maintained files: +1. **CLI entry** — clap argv parsing, stderr routing (analogous to v2's `cli_run.rs`). +2. **Runtime shell bridge** — filesystem ops, process spawn for `dag run` interpreter service (analogous to v2's `v2_interpreter.rs`). +3. **Build shim** — `build.rs` for build-script codegen glue. +4. **lib.rs** — module declarations; ideally generated, but depends on cargo's constraints. +5. **Possibly**: a minimal entry to `Dag::new()` that the generated bootstrap calls. + +If (4) and (5) can be generated, the shim is 3 files. + +## Measurement + +| Milestone | SG-0 PB count | Trigger | +|---|---|---| +| Today | 78 | — | +| Post-PB-2 | 77 | tokenize.rs deleted | +| Post-PB-3 | 76 | parse.rs deleted | +| Post-PB-4 | 75 | lower.rs deleted (+ support) | +| Post-PB-5 | 74 | infer.rs deleted | +| Post-PB-6 | 68 | emit files collapsed (~6 deletions) | +| Post-cleanup | ~50 | diagnostic/utility files migrated | +| Post-PB-7 | ~20 | test infra migrated | +| Post-PB-8 | ≤5 | graduation | + +## Dependencies map + +``` +PB-0 (ratchet) ──────────────┐ + ↓ +TM-1 (Dag builder) ──→ PB-1 (bootstrap loader) + ↓ +SG-1 (merged) ───────→ PB-2 (tokenize) +SG-2 full cutover ──→ PB-3 (parse) +SG-3 series ────────→ PB-4 (lower) +SG-4 complete ──────→ PB-5 (infer) +Lane 1e complete ──→ PB-6 (emit) ──────────┐ + ↓ + PB-7 (full fixed-point) + ↓ + PB-8 (graduation) +``` + +## Open questions + +1. **Binary blob vs. emitted Rust**: v2 uses emitted Rust; this doc + recommends the same for v3. A serialized `.blob` format was the + initial proposal — simpler stage0 but opaque in git. Emitted Rust + is human-readable and follows v2's proven pattern. +2. **Dag builder API scope**: TM-1 proposes `push_*` builders for + lens unit tests. PB-1 extends the same API for the bootstrap + loader. Design them together to avoid rework. +3. **`lib.rs` generation**: cargo expects `lib.rs` in a fixed path + with module declarations matching file layout. May need a + generator to materialize `lib.rs` from a declaration list. +4. **Graduation criteria for Lane 1e**: PB-6 depends on Lane 1e, but + Lane 1e's acceptance is currently "single walker + specs." Need + to verify that delivers a single emit file (not a slightly-reduced + three-file set). + +## Non-goals + +- **Not** a rewrite to a binary-blob format. v2's emitted-Rust + pattern works; follow it. +- **Not** removal of `cargo build` — stage0 remains a Cargo crate. +- **Not** eliminating bootstrap entirely — Dag::new() still runs, + but it calls generated constructors instead of parsing strings. + +## Relationship to other tracks + +- **SG program** (Self-Generation): SG retires specific Rust files + by authoring their `.dag` counterparts. PB is the **program that + names the endpoint**: SG-N deliverables feed PB-N stages. +- **TM program** (Test Migration): TM-1 (Dag builder API) is a PB-1 + prerequisite. Co-design. +- **Lane 1e**: PB-6 is Lane 1e's downstream graduation. When Lane 1e + ships, PB-6 lands the file retirement. +- **Lane 3c** (self-hosting cycle): PB-7's full fixed-point IS Lane + 3c's acceptance, extended from fixture scope to full-compiler scope. + +## Graduation trigger + +PB graduates when: +1. `hand_maintained_src.len() ≤ 5` in `compiler.dag` +2. DB-8 self-host fixed-point runs on full `compiler.dag` (not fixture) and passes bit-identically +3. CI census gate blocks unmarked hand-authored files + +At that point, the THESIS.md §"Pure bootstrap" claim is structurally +satisfied. The residual shim is the irreducible system boundary. From 436793823e55a3fc7ef763844cb57cb50a77e663 Mon Sep 17 00:00:00 2001 From: Brian Searls Date: Sun, 19 Apr 2026 20:52:18 -0400 Subject: [PATCH 2/4] docs(pure-bootstrap): fix PB-1 scope + precursor framing MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Addresses codex blocker review on PR #581: 1. PB-1 scope was too narrow. Original text scoped the emitted bootstrap loader to `dsl/std/*.dag` only. In reality, `Dag::new()` chains four authorities into one fixtures array: `std_fixtures` + `STAGED_FILES` + `V3_SPECS` + `COMPILER_FILES`. Rewrite PB-1 to cover all four; suggest staged per-authority substages (PB-1a/b/c/d) as an option. 2. PB-2..PB-5 framing was in present tense ("SG-1 merged, so X exists today"), which conflated authority-creation work (SG) with retirement work (PB). Reframed: two-step dissolution per concept — SG creates authority + generated companion; PB deletes the hand-maintained Rust file. Current-state section now names what's actually landed (tokenize triplet, operators retired, lens generated files). Note on codex's second blocker ("no v3 tokenize.dag, regen_tokenize, tokenize_generated.rs in the repo"): those files DO exist on main as of SG-1 landing (#556 + followups). Verified locally: src/v3/compiler/tokenize.dag — authority (180+ lines) src/v3/compiler/src/bin/regen_tokenize.rs — regen binary src/v3/compiler/src/tokenize_generated.rs — generated projection The reviewer's concern about framing is still valid (PB-2 is the retirement step, not the authority creation), but the factual claim that these files don't exist is incorrect. Responding on the PR with the verification. Co-Authored-By: Claude Opus 4.7 (1M context) --- docs/design-pure-bootstrap.md | 136 +++++++++++++++++++++++----------- 1 file changed, 91 insertions(+), 45 deletions(-) diff --git a/docs/design-pure-bootstrap.md b/docs/design-pure-bootstrap.md index 2739aa0e1f2..35f05a1f819 100644 --- a/docs/design-pure-bootstrap.md +++ b/docs/design-pure-bootstrap.md @@ -46,17 +46,29 @@ authority**. Only the system boundary does. ## Current v3 state -- **78 hand-maintained `.rs` files** (`src/v3/compiler/tests/integration/sg0_census_test.rs`). -- **4 generated**: lens files (`lens_cost_generated`, - `lens_provenance_generated`, `lens_unused_parameters_generated`, - `lens_structural_resolution_generated`). -- **`bootstrap.rs` uses `include_str!`** to load 7 `.dag` files at - runtime — v3 re-tokenizes, re-parses, re-lowers the std library - every `Dag::new()`. v2 doesn't do this. - -The 78-file gap decomposes: -- ~30 compiler core files (parse, lower, infer, emit, tokenize, ...) -- ~10 lens files (migrating to generated per SG-6) +**Hand-maintained**: **78 `.rs` files** (SG-0 census at +`src/v3/compiler/tests/integration/sg0_census_test.rs`). + +**Generated files on main** (partial dissolution already landed): +- `lens_*_generated.rs` (5 files: cost, cost_symbolic, provenance, + structural_resolution, unused_parameters) +- `tokenize_generated.rs` (SG-1 authority via `src/v3/compiler/tokenize.dag` + `regen_tokenize`; `tokenize.rs` is now a 23-line shim but still on census) +- `operators_generated.rs` (SG-3; `operators.rs` retired) +- `dag_{branch,cluster,cost,scalar}_generated.rs` +- `infer_helpers_generated.rs`, `serialize_generated.rs`, + `diagnostics_generated.rs`, `types_generated.rs` + +**Bootstrap inputs `Dag::new()` parses at runtime** (all four authorities): +1. **`std_fixtures`** — 7 `dsl/std/*.dag` files embedded via `include_str!` (`LOGIC_DAG`, `BIT_DAG`, `ALGEBRA_DAG`, `INTEGER_DAG`, `FLOAT_DAG`, `STRING_TYPE_DAG`, `TYPES_DAG`) +2. **`STAGED_FILES`** — `src/v3/std/*.dag` (build-script-enumerated) +3. **`V3_SPECS`** — `src/v3/spec/*.dag` (Rust/Go/Python language specs) +4. **`COMPILER_FILES`** — `src/v3/compiler/*.dag` (compiler.dag, pipeline.dag, tokenize.dag, operators.dag, regen.dag, runtime_mirrors.dag) + +All four chain into a single `fixtures` array that bootstrap.rs tokenizes + parses + lowers on every `Dag::new()`. **PB-1 must replace the runtime tokenize/parse/lower path for all four input authorities**, not just `std_fixtures`. + +**The 78-file gap decomposes** (approximate): +- ~30 compiler core files (parse, lower, infer, emit internals, tokenize shim, ...) +- ~10 lens files (SG-6 migrating to generated; some already done) - ~10 diagnostic / utility files (serialize, diagnostics, types, ...) - ~15 test infrastructure files - ~10 bin files (regen_*, self_host_fixed_point, ...) @@ -64,7 +76,12 @@ The 78-file gap decomposes: ## The PB program -Nine stages, mapping to existing SG and Lane work where possible. +Nine stages. Each stage is the **retirement step** that follows a +corresponding **authority-creation step** in the SG / Lane programs. +SG-N creates the `.dag` authority + its `_generated.rs` projection; +PB-N retires the hand-maintained Rust file that used to own the +concept. Two-step dissolution per concept: create authority, then +retire projection — not one. ### PB-0 — ratchet (unblocks everything) @@ -73,64 +90,93 @@ Nine stages, mapping to existing SG and Lane work where possible. - **Target trajectory**: 78 → 50 → 20 → 5. - **Dependencies**: none. Dispatchable now. -### PB-1 — bootstrap loader emission +### PB-1 — bootstrap loader emission (all four authorities) -- Replace `bootstrap.rs`'s runtime `include_str!` + tokenize/parse/lower - with generated Rust constructors that build the primed Dag directly. -- Input: `dsl/std/*.dag`. Output: `bootstrap_generated.rs` that calls - `Dag::push_value`, `Dag::push_declaration`, etc. at `Dag::new()`. +- Replace `bootstrap.rs`'s runtime `include_str!` + tokenize + parse + + lower for **all four input authorities** (`std_fixtures` + + `STAGED_FILES` + `V3_SPECS` + `COMPILER_FILES`, per current-state + section above). Covering only `dsl/std/*.dag` is insufficient — + `Dag::new()` today chains all four into a single `fixtures` array. +- Output: `bootstrap_generated.rs` that calls `Dag::push_*` builders + to construct the primed Dag directly at `Dag::new()`, with no + runtime tokenize/parse/lower path. - Matches v2's pattern (no runtime `.dag` parsing at bootstrap). -- **Dependencies**: Dag builder API (blocked on TM-1). +- **Dependencies**: Dag builder API (TM-1); generator that walks + the 4 authorities at build time and emits the constructor module. +- **Not done in one shot**: can stage per-authority (e.g., ship + `std_fixtures` first as PB-1a, then STAGED/SPECS/COMPILER as + PB-1b/c/d). Each sub-stage dissolves one include_str block + its + runtime parse path. ### PB-2 — tokenize retire -- `tokenize.dag` landed via SG-1. `regen_tokenize` produces - `tokenize_generated.rs` today. -- Retire `tokenize.rs` entirely — lib.rs routes through generated. -- **Dependencies**: SG-1 merge. -- **Counter delta**: -1 file. +- **SG-1 authority already landed**: `src/v3/compiler/tokenize.dag` + + `regen_tokenize` + `tokenize_generated.rs` all exist on main. +- `tokenize.rs` is already a 23-line shim routing to generated. +- **PB-2 work**: delete `tokenize.rs` entirely, route call sites + directly through `tokenize_generated.rs` (or a `pub use` in + `lib.rs`); remove from `hand_maintained_src`. +- **Dependencies**: none (authority landed). +- **Counter delta**: -1 file. Dispatchable now. ### PB-3 — parse retire -- Requires `parse.dag` authority (currently SG-2 prep in-flight). -- SG-2 full cutover lane (#557 followup) completes this. -- **Dependencies**: SG-2 full cutover. -- **Counter delta**: -1 file (~2K LOC — the biggest single move). +- **Authority creation**: in progress via SG-2 (parse cutover). + SG-2 prep (#557) snapshotted incumbent output; full cutover + authoring `parse.dag` + `regen_parse` + `parse_generated.rs` is + the SG-2 followup lane. +- **PB-3 work** (after SG-2 authority lands): delete `parse.rs`, + route through generated. +- **Dependencies**: SG-2 full cutover landed. +- **Counter delta**: -1 file (~2K LOC — biggest single hand file). ### PB-4 — lower retire -- Requires `lower.dag` authority. SG-3 series is laying groundwork - (SG-3a retiring `operators.rs`). -- **Dependencies**: SG-3 series complete. -- **Counter delta**: -1 file + supporting files (~1K LOC). +- **Authority creation**: requires `lower.dag`. SG-3 series retired + specific support files (operators.rs); full `lower.dag` authority + is larger scope and not yet on the SG queue. +- **PB-4 work** (after authority lands): delete `lower.rs` + support. +- **Dependencies**: lower.dag authority creation lane (to be named). +- **Counter delta**: -1 primary file + supporting files. ### PB-5 — infer retire -- Requires `infer.dag` authority. -- SG-4 (SG-4-prep-a landed; full SG-4 dispatch queued). -- **Dependencies**: SG-4 complete. -- **Counter delta**: -1 primary file + helpers. +- **Authority creation**: SG-4. SG-4-prep-a (result_port read + authority) landed. Full `infer.dag` + `regen_infer` + + `infer_generated.rs` triplet is the next SG-4 dispatch. +- **PB-5 work** (after SG-4 authority lands): delete `infer.rs` + + inference helpers that the generated module subsumes. +- **Dependencies**: SG-4 full dispatch. +- **Counter delta**: -1 primary file + helpers (~5-10 files). ### PB-6 — emit retire -- Collapses `emit.rs`, `emit/rust_target.rs`, `emit/python_target.rs`, - `emit_go.rs`, `emit_python.rs`, `emit_rust.rs` into spec-driven - single walker + per-target spec tiles. +- **Authority creation**: Lane 1e — single walker + per-target spec + tiles (`src/v3/spec/rust.dag`, `go.dag`, `python.dag`). Design doc + in `docs/single-emitter-design.md`. +- **PB-6 work** (after Lane 1e lands): delete `emit.rs`, + `emit/rust_target.rs`, `emit/python_target.rs`, `emit_go.rs`, + `emit_python.rs`, `emit_rust.rs` — everything consumed by the + spec-driven walker. - **Dependencies**: Lane 1e complete. - **Counter delta**: -6 to -8 files, -10K LOC. Biggest counter move. ### PB-7 — full fixed-point -- DB-8 already runs `self_host_fixed_point` in CI on a **fixture**. -- Extend to **full compiler.dag**: v3 compiles compiler.dag → emits - complete stage0 → git-diff clean against checked-in stage0. -- **Dependencies**: PB-2 through PB-6 complete. +- **DB-8 already runs** `self_host_fixed_point` in CI on a fixture + (`default_fixed_point_source`). +- **PB-7 work**: extend the gate's source input to `compiler.dag` + itself — v3 compiles `compiler.dag` → emits complete stage0 → + git-diff clean against checked-in stage0. +- **Dependencies**: PB-2 through PB-6 landed (generated Rust must + match checked-in stage0 bit-for-bit). ### PB-8 — graduation -- `hand_maintained_src` list reaches ≤5 entries. -- Delete scaffolding: `include_str!` loader, runtime-parse paths, - census accommodations. +- `hand_maintained_src` list reaches ≤5 entries (CLI entry + runtime + bridge + build shim + possibly lib.rs + bootstrap entry). +- Delete scaffolding: `include_str!` constants, runtime-parse paths, + census accommodations for not-yet-retired files. - **Dependencies**: PB-7 green. ## Acceptance criteria (strict) From e8217e0e5aee6924672b5dbf19ea05750e11d256 Mon Sep 17 00:00:00 2001 From: Brian Searls Date: Sun, 19 Apr 2026 22:12:47 -0400 Subject: [PATCH 3/4] docs(pure-bootstrap): correct COMPILER_FILES list Reviewer caught a factual error: the doc listed 6 files under COMPILER_FILES but only 5 exist at src/v3/compiler/*.dag on main. Incorrect listing: `compiler.dag, pipeline.dag, tokenize.dag, operators.dag, regen.dag, runtime_mirrors.dag` (6 files) Actual contents of src/v3/compiler/*.dag on main: - operators.dag - pipeline.dag - regen.dag - runtime_mirrors.dag - tokenize.dag `dsl/gunbc/compiler.dag` is a separate authority (not part of COMPILER_FILES), so removed it from the list and added a clarifying note. Co-Authored-By: Claude Opus 4.7 (1M context) --- docs/design-pure-bootstrap.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/design-pure-bootstrap.md b/docs/design-pure-bootstrap.md index 35f05a1f819..b57ff6f013b 100644 --- a/docs/design-pure-bootstrap.md +++ b/docs/design-pure-bootstrap.md @@ -62,7 +62,7 @@ authority**. Only the system boundary does. 1. **`std_fixtures`** — 7 `dsl/std/*.dag` files embedded via `include_str!` (`LOGIC_DAG`, `BIT_DAG`, `ALGEBRA_DAG`, `INTEGER_DAG`, `FLOAT_DAG`, `STRING_TYPE_DAG`, `TYPES_DAG`) 2. **`STAGED_FILES`** — `src/v3/std/*.dag` (build-script-enumerated) 3. **`V3_SPECS`** — `src/v3/spec/*.dag` (Rust/Go/Python language specs) -4. **`COMPILER_FILES`** — `src/v3/compiler/*.dag` (compiler.dag, pipeline.dag, tokenize.dag, operators.dag, regen.dag, runtime_mirrors.dag) +4. **`COMPILER_FILES`** — `src/v3/compiler/*.dag` (operators.dag, pipeline.dag, regen.dag, runtime_mirrors.dag, tokenize.dag). Note: `dsl/gunbc/compiler.dag` is a separate authority, not part of `COMPILER_FILES`. All four chain into a single `fixtures` array that bootstrap.rs tokenizes + parses + lowers on every `Dag::new()`. **PB-1 must replace the runtime tokenize/parse/lower path for all four input authorities**, not just `std_fixtures`. From 4f6eaafc305b9191e379074e8d286ef8563d35c1 Mon Sep 17 00:00:00 2001 From: Brian Searls Date: Sun, 19 Apr 2026 22:14:27 -0400 Subject: [PATCH 4/4] docs(pure-bootstrap): cite correct SG-0 ratchet authority Reviewer caught: PB-0 and acceptance criteria cited compiler.dag's hand_maintained_src as the SG-0 ratchet source, but the live SG-0 ratchet is actually EXPECTED_HAND_AUTHORED (in sg0_census_test.rs) partitioned against GENERATED_FILES (sourced from REGEN_OUTPUTS in build.rs). compiler.dag's hand_maintained_src field is the related-but-separate stage0 fixed-point diff exclusion list. Updated every reference to cite EXPECTED_HAND_AUTHORED as the authoritative SG-0 ratchet source, with a note that compiler.dag's list converges to the same set. Added explicit disambiguation in both Current v3 state and PB-0 sections. Co-Authored-By: Claude Opus 4.7 (1M context) --- docs/design-pure-bootstrap.md | 36 ++++++++++++++++++++++++++--------- 1 file changed, 27 insertions(+), 9 deletions(-) diff --git a/docs/design-pure-bootstrap.md b/docs/design-pure-bootstrap.md index b57ff6f013b..8a10ea2ffea 100644 --- a/docs/design-pure-bootstrap.md +++ b/docs/design-pure-bootstrap.md @@ -46,8 +46,15 @@ authority**. Only the system boundary does. ## Current v3 state -**Hand-maintained**: **78 `.rs` files** (SG-0 census at -`src/v3/compiler/tests/integration/sg0_census_test.rs`). +**Hand-maintained**: **78 `.rs` files** per the live SG-0 ratchet +(`EXPECTED_HAND_AUTHORED` in +`src/v3/compiler/tests/integration/sg0_census_test.rs`, partitioned +against `GENERATED_FILES` sourced from the producer-owned +`REGEN_OUTPUTS` manifest in `src/v3/compiler/build.rs`). Note: +`dsl/gunbc/compiler.dag`'s `hand_maintained_src` field is a +related-but-separate authority — it names files excluded from the +stage0 fixed-point diff (regeneration survival list), not the SG-0 +ratchet source. PB metrics below track the SG-0 ratchet. **Generated files on main** (partial dissolution already landed): - `lens_*_generated.rs` (5 files: cost, cost_symbolic, provenance, @@ -85,10 +92,18 @@ retire projection — not one. ### PB-0 — ratchet (unblocks everything) -- SG-0 already tracks `hand_maintained_src` list. Add **PB count** - as a named column with a trend arrow. Ratchet only down. +- SG-0's live ratchet (`EXPECTED_HAND_AUTHORED` ∖ `GENERATED_FILES` + partition in `sg0_census_test.rs`) already enforces the + hand-authored count. Add **PB count** as a named column with a + trend arrow. Ratchet only down. - **Target trajectory**: 78 → 50 → 20 → 5. - **Dependencies**: none. Dispatchable now. +- **Not the same as `compiler.dag`'s `hand_maintained_src`** — + that's the regeneration-survival list (which files don't get + overwritten by the emitter); SG-0's `EXPECTED_HAND_AUTHORED` + is the ratchet (which files are still hand-authored). Both + should shrink in sync; when they diverge, the SG-0 ratchet is + authoritative for PB count. ### PB-1 — bootstrap loader emission (all four authorities) @@ -115,7 +130,8 @@ retire projection — not one. - `tokenize.rs` is already a 23-line shim routing to generated. - **PB-2 work**: delete `tokenize.rs` entirely, route call sites directly through `tokenize_generated.rs` (or a `pub use` in - `lib.rs`); remove from `hand_maintained_src`. + `lib.rs`); remove from `EXPECTED_HAND_AUTHORED` (SG-0 ratchet) + and from `compiler.dag`'s `hand_maintained_src` (regen-survival list). - **Dependencies**: none (authority landed). - **Counter delta**: -1 file. Dispatchable now. @@ -173,8 +189,10 @@ retire projection — not one. ### PB-8 — graduation -- `hand_maintained_src` list reaches ≤5 entries (CLI entry + runtime - bridge + build shim + possibly lib.rs + bootstrap entry). +- `EXPECTED_HAND_AUTHORED` (SG-0 ratchet) reaches ≤5 entries (CLI + entry + runtime bridge + build shim + possibly lib.rs + bootstrap + entry). `compiler.dag`'s `hand_maintained_src` converges to the + same set. - Delete scaffolding: `include_str!` constants, runtime-parse paths, census accommodations for not-yet-retired files. - **Dependencies**: PB-7 green. @@ -183,7 +201,7 @@ retire projection — not one. 1. Every `.rs` file in `src/v3/compiler/src/` is **either**: - Generated (ends in `_generated.rs` and has the generated header), **or** - - Listed in `compiler.dag`'s `hand_maintained_src` (target: ≤5 entries). + - Listed in `EXPECTED_HAND_AUTHORED` (target: ≤5 entries; `compiler.dag`'s `hand_maintained_src` converges to the same set). 2. `cargo run -p v3-compiler --release --bin regen_v3` produces bit-identical Rust (cycle converges in 1 iteration). 3. CI gate: census partition matches directory contents (no @@ -274,7 +292,7 @@ Lane 1e complete ──→ PB-6 (emit) ──────────┐ ## Graduation trigger PB graduates when: -1. `hand_maintained_src.len() ≤ 5` in `compiler.dag` +1. `EXPECTED_HAND_AUTHORED.len() ≤ 5` (SG-0 ratchet authority); `compiler.dag`'s `hand_maintained_src` converges to the same set 2. DB-8 self-host fixed-point runs on full `compiler.dag` (not fixture) and passes bit-identically 3. CI census gate blocks unmarked hand-authored files