Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
2 changes: 2 additions & 0 deletions DESIGN.md
Original file line number Diff line number Diff line change
Expand Up @@ -257,5 +257,7 @@ One row per class, each carrying its recognition rule and its receipts, as a fil

- Three local checks, each named with the CI step that executes it — a check named here with no executing step is a decoration (§4b): `cargo clippy --all-targets -- -D warnings` (`gunbc.repo_self_build` `repo_self_clippy_command`, the only command that compiles the integration-test and example targets, so a red there is invisible to every other step) runs as `rust_clippy_all_targets_step` in the `required-witnesses-build` job of `gunbc.witness_floor_workflow`, which runs on every pull request and on every merge_group (the queue's composed revision) and IS a required lane — so a clippy red blocks a merge; `cargo fmt --all --check` runs in the generated pre-commit hook (`gunbc.githooks_pre_commit_emit`). `cargo test --release -p v1-compiler --lib` (`repo_self_test_command`) IS NOT RUN BY ANY CI STEP as of the 2026-09-04 runner-capacity ruling, which deleted the `rust-unit-tests` job — it is local diligence, and its loss is a declared drop, `gunbc.rung_drop` `rust_unit_tests_off_the_merge_path`. `cargo test --workspace` is likewise local only: the test targets are compiled by the clippy step and run by nobody.
- one-time per clone: `git config core.hooksPath .githooks` — the only documented manual seed; generated pre-commit/pre-push hooks then idempotently converge `merge.generated-artifact.driver` and re-assert `core.hooksPath` via argv derived from `gunbc.repo_local_git_config` (clones that skip hooksPath degrade to vanilla text-merge for generated-artifact paths; drift gate still guards at CI). The driver REFUSES rather than answering `true`: git reaches a low-level merge driver only when both sides changed the path since the merge base — measured on a four-case matrix, one-sided and identical changes never reach it — and taking the ours side there dropped the other side's authority-derived bytes with no conflict, twice on #7836 against the stage0 seed. It now leaves the ours side in the worktree with no conflict markers, marks the path unmerged, and prints the regeneration recipe; the class is mechanically preventable, not structural, and its next-rung trigger is the commit-writer binding rows in `gunbc.commit_workflow`
- **`gunbc test <label>` is the dedicated CLI for invoking a v2 measurement, and a new one is a row rather than a flag** (operator ruling, 2026-09-16). The seam is `gunbc.target_binding` `TargetProducer` bound to a `gunbc.instrument_targets` label, and the host note says the extension shape outright: *adding one is a row in `instrument_registry` and an arm here; it is not a new route*. What that buys is not tidiness: the label carries its own refusal vocabulary, so an unknown or pattern label REFUSES with exit 2 rather than reporting a pass, and the three terminations stay distinct — 0 held, 1 an observation that did not hold, 2 no observation — which is the conflation §5 forbids, closed by construction for every instrument at once. The subject is the instrument's own fact and never a CLI option, so an invocation cannot quietly measure a different corpus while reporting the same target's standing. **What this rules out is the alternative that keeps suggesting itself:** a flag on `claim_executor`, whose ~20 flags are hand-parsed in a 2783-line `main` over 44,451 lines of `cli_run.rs` with NO `.dag` authority at all — v2 work that lands there is unmodeled by construction, and `--self-host` was withdrawn in the same change that added `//gunbc/instruments:self-host` rather than left standing beside it, because two routes to one fact is the §3 fork. `gunbc`'s own surface is modeled (`gunbc.cli_dispatch_surface` → `gunbc_cli_dispatch_generated.rs`); `claim_executor`'s is not, and the gap is the point.
- **Two CLIs, and which one a session wants is decided by which compiler is running.** `gunbc` is the SEED's CLI — `std.compiler_entry` `RetainedHostCliKernel`, a clap surface dispatching into hand-authored host Rust (`v1_compiler.cli_run`) — so its verbs are unreachable from a self-emitted binary BY CONSTRUCTION, not by omission: an emitted crate does not contain that module. The v2-exclusive door is `v2.cli.compile_cli`, `.dag` in `src/v2/cli/`, declaring the fourth driver `std.compiler_entry` `NativeCliDriver`. It parses argv, decides the verb, decides every refusal, decides what to emit and decides the process exit (`std.process` `ProcessExit`); its rendered main performs only the four operations no `.dag` fold can — read argv, walk and read the source roots the PLAN named, write stdout, set the status — and hands each back as a VALUE. **That boundary is measured, not chosen for taste:** a resource method on an ordinary `fn` is a located compiler refusal (`Filesystem.Read` off a plain function refuses with *receiver type 'Primitive(Filesystem)' establishes no method surface*), because resource operations resolve only inside a workflow function and are realized by the seed INTERPRETER, which an emitted binary is not running under. The shim shape is deliberately the capability `gunbc.source_root_eval_driver_seed_growth` names as the trigger retiring ITS row — *the rendered main becomes one call into that fold* — so the new door adds no seed debt. **Why a second entry module rather than a mode on the first:** one emitted crate has one entry point and the emitter admits exactly one `compiler_pipeline_entry` declaration per closure (`compiler_pipeline_entry_is_ambiguous` refuses two by name), and the CLI's closure reaches no part of `v2.compiler.compile`, so exactly-one holds by construction rather than by a flag choosing between them. The two generations are two instrument rows: `gunbc test //gunbc/instruments:self-host` is the seed emitting and building `v2.compiler.compile`, and `gunbc test //gunbc/instruments:v2-native-cli` is the seed emitting and building the CLI closure — two labels because they are two compilations, so a regression in either is reported under a name that says which. Neither is the second generation; that is the BUILT CLI emitting a closure, and it needs this door to exist first.
- explicit actuator (CI / tooling): `gunbc run --source-root dag --source-root src/v2 --entry dag/gunbc/repo/repo_local_git_config.dag --function converge`
- **CI** is one emission, `gunbc.witness_floor_workflow` → `.github/workflows/witnesses.yml`, invoking our own binary once per LANE: `claim_executor --required-ci --source-root dag --source-root src/v2 --required-lane build` and the same with `--required-lane witnesses`, in two parallel jobs, plus an aggregating job that carries the required context and reads BOTH lane results — that last is what makes a lane block rather than merely be waited on, so read `gunbc.witness_floor_workflow` `required_lanes_roster` for the current membership rather than this sentence. **The job roster is closed to growth: adding a job needs operator sign-off, because a job is a standing claim on a paid runner on every pull request and on every queued landing** — the 2026-09-04 ruling cut three of seven on that basis (`rust-unit-tests`, `fabric-evidence`, `emit-copy-qualification-battery`), and the reasoning an author owes before proposing a lane is stated at `witness_floor_lane_jobs`. The push-on-main trigger was CUT on 2026-09-15 under the same reasoning applied to an event rather than a job: with the merge queue enabled, the required run on the queue's composed revision proves the sha that lands, so the push run re-ran a proof that already existed — one required run per landing, not two. Which phases a lane owns is decided in the binary, never in the YAML — the partition is an exhaustive match, so a phase belonging to no job fails to compile. **Read the roster from the run's own announcement, not from here:** every required run prints one `phase <name>` line per phase it owns and one `ROUTED to lane <other>` line per phase it does not. Several capabilities that used to gate are currently declared rung drops — see §4b.
2 changes: 2 additions & 0 deletions dag/gunbc/design_document.dag
Original file line number Diff line number Diff line change
Expand Up @@ -272,6 +272,8 @@ fn building_checks_blocks() -> List<MarkdownBlock> {
ul(items: [
li(text: "Three local checks, each named with the CI step that executes it — a check named here with no executing step is a decoration (§4b): `cargo clippy --all-targets -- -D warnings` (`gunbc.repo_self_build` `repo_self_clippy_command`, the only command that compiles the integration-test and example targets, so a red there is invisible to every other step) runs as `rust_clippy_all_targets_step` in the `required-witnesses-build` job of `gunbc.witness_floor_workflow`, which runs on every pull request and on every merge_group (the queue's composed revision) and IS a required lane — so a clippy red blocks a merge; `cargo fmt --all --check` runs in the generated pre-commit hook (`gunbc.githooks_pre_commit_emit`). `cargo test --release -p v1-compiler --lib` (`repo_self_test_command`) IS NOT RUN BY ANY CI STEP as of the 2026-09-04 runner-capacity ruling, which deleted the `rust-unit-tests` job — it is local diligence, and its loss is a declared drop, `gunbc.rung_drop` `rust_unit_tests_off_the_merge_path`. `cargo test --workspace` is likewise local only: the test targets are compiled by the clippy step and run by nobody."),
li(text: "one-time per clone: `git config core.hooksPath .githooks` — the only documented manual seed; generated pre-commit/pre-push hooks then idempotently converge `merge.generated-artifact.driver` and re-assert `core.hooksPath` via argv derived from `gunbc.repo_local_git_config` (clones that skip hooksPath degrade to vanilla text-merge for generated-artifact paths; drift gate still guards at CI). The driver REFUSES rather than answering `true`: git reaches a low-level merge driver only when both sides changed the path since the merge base — measured on a four-case matrix, one-sided and identical changes never reach it — and taking the ours side there dropped the other side's authority-derived bytes with no conflict, twice on #7836 against the stage0 seed. It now leaves the ours side in the worktree with no conflict markers, marks the path unmerged, and prints the regeneration recipe; the class is mechanically preventable, not structural, and its next-rung trigger is the commit-writer binding rows in `gunbc.commit_workflow`"),
li(text: "**`gunbc test <label>` is the dedicated CLI for invoking a v2 measurement, and a new one is a row rather than a flag** (operator ruling, 2026-09-16). The seam is `gunbc.target_binding` `TargetProducer` bound to a `gunbc.instrument_targets` label, and the host note says the extension shape outright: *adding one is a row in `instrument_registry` and an arm here; it is not a new route*. What that buys is not tidiness: the label carries its own refusal vocabulary, so an unknown or pattern label REFUSES with exit 2 rather than reporting a pass, and the three terminations stay distinct — 0 held, 1 an observation that did not hold, 2 no observation — which is the conflation §5 forbids, closed by construction for every instrument at once. The subject is the instrument's own fact and never a CLI option, so an invocation cannot quietly measure a different corpus while reporting the same target's standing. **What this rules out is the alternative that keeps suggesting itself:** a flag on `claim_executor`, whose ~20 flags are hand-parsed in a 2783-line `main` over 44,451 lines of `cli_run.rs` with NO `.dag` authority at all — v2 work that lands there is unmodeled by construction, and `--self-host` was withdrawn in the same change that added `//gunbc/instruments:self-host` rather than left standing beside it, because two routes to one fact is the §3 fork. `gunbc`'s own surface is modeled (`gunbc.cli_dispatch_surface` → `gunbc_cli_dispatch_generated.rs`); `claim_executor`'s is not, and the gap is the point."),
li(text: "**Two CLIs, and which one a session wants is decided by which compiler is running.** `gunbc` is the SEED's CLI — `std.compiler_entry` `RetainedHostCliKernel`, a clap surface dispatching into hand-authored host Rust (`v1_compiler.cli_run`) — so its verbs are unreachable from a self-emitted binary BY CONSTRUCTION, not by omission: an emitted crate does not contain that module. The v2-exclusive door is `v2.cli.compile_cli`, `.dag` in `src/v2/cli/`, declaring the fourth driver `std.compiler_entry` `NativeCliDriver`. It parses argv, decides the verb, decides every refusal, decides what to emit and decides the process exit (`std.process` `ProcessExit`); its rendered main performs only the four operations no `.dag` fold can — read argv, walk and read the source roots the PLAN named, write stdout, set the status — and hands each back as a VALUE. **That boundary is measured, not chosen for taste:** a resource method on an ordinary `fn` is a located compiler refusal (`Filesystem.Read` off a plain function refuses with *receiver type 'Primitive(Filesystem)' establishes no method surface*), because resource operations resolve only inside a workflow function and are realized by the seed INTERPRETER, which an emitted binary is not running under. The shim shape is deliberately the capability `gunbc.source_root_eval_driver_seed_growth` names as the trigger retiring ITS row — *the rendered main becomes one call into that fold* — so the new door adds no seed debt. **Why a second entry module rather than a mode on the first:** one emitted crate has one entry point and the emitter admits exactly one `compiler_pipeline_entry` declaration per closure (`compiler_pipeline_entry_is_ambiguous` refuses two by name), and the CLI's closure reaches no part of `v2.compiler.compile`, so exactly-one holds by construction rather than by a flag choosing between them. The two generations are two instrument rows: `gunbc test //gunbc/instruments:self-host` is the seed emitting and building `v2.compiler.compile`, and `gunbc test //gunbc/instruments:v2-native-cli` is the seed emitting and building the CLI closure — two labels because they are two compilations, so a regression in either is reported under a name that says which. Neither is the second generation; that is the BUILT CLI emitting a closure, and it needs this door to exist first."),
li(text: "explicit actuator (CI / tooling): `gunbc run --source-root dag --source-root src/v2 --entry dag/gunbc/repo/repo_local_git_config.dag --function converge`"),
li(text: "**CI** is one emission, `gunbc.witness_floor_workflow` → `.github/workflows/witnesses.yml`, invoking our own binary once per LANE: `claim_executor --required-ci --source-root dag --source-root src/v2 --required-lane build` and the same with `--required-lane witnesses`, in two parallel jobs, plus an aggregating job that carries the required context and reads BOTH lane results — that last is what makes a lane block rather than merely be waited on, so read `gunbc.witness_floor_workflow` `required_lanes_roster` for the current membership rather than this sentence. **The job roster is closed to growth: adding a job needs operator sign-off, because a job is a standing claim on a paid runner on every pull request and on every queued landing** — the 2026-09-04 ruling cut three of seven on that basis (`rust-unit-tests`, `fabric-evidence`, `emit-copy-qualification-battery`), and the reasoning an author owes before proposing a lane is stated at `witness_floor_lane_jobs`. The push-on-main trigger was CUT on 2026-09-15 under the same reasoning applied to an event rather than a job: with the merge queue enabled, the required run on the queue's composed revision proves the sha that lands, so the push run re-ran a proof that already existed — one required run per landing, not two. Which phases a lane owns is decided in the binary, never in the YAML — the partition is an exhaustive match, so a phase belonging to no job fails to compile. **Read the roster from the run's own announcement, not from here:** every required run prints one `phase <name>` line per phase it owns and one `ROUTED to lane <other>` line per phase it does not. Several capabilities that used to gate are currently declared rung drops — see §4b."),
]),
Expand Down
Loading
Loading