Skip to content
Closed
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
4 changes: 2 additions & 2 deletions docs/thesis/doc-authority.md
Original file line number Diff line number Diff line change
Expand Up @@ -267,8 +267,8 @@ flowchart LR
- **Standing detection:** [`scripts/check_doc_refs.py`](../../scripts/check_doc_refs.py)
— every Markdown reference must resolve. `--all` produces the full census;
CI runs `--changed origin/main` so a touched doc with a dangling reference fails
review `[live]` — the `doc_refs` job is wired into the `ci` aggregator (fail-closed),
operator-authorized. Diff-scoped by design: no repo-wide sweep, no ratchet baseline —
review `[live]` — gate-3 (`scripts/v4-affected-tests-gate.sh` via `run_ci_pipeline`)
enforces this fail-closed. Diff-scoped by design: no repo-wide sweep, no ratchet baseline —
you fix a doc's references when you touch it.
- A new or touched doc that **restates** a fact owned elsewhere, instead of linking,
fails review.
Expand Down
92 changes: 85 additions & 7 deletions dsl/extdeps/github/log_annotations.dag
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ data annotation_notice_prefix: String = "::notice "
data annotation_group_prefix: String = "::group::"
data annotation_endgroup: String = "::endgroup::"
data annotation_set_output_prefix: String = "::set-output name="
data annotation_set_output_separator: String = "::"
data annotation_add_mask_prefix: String = "::add-mask::"
data annotation_stop_commands_prefix: String = "::stop-commands::"

Expand All @@ -36,20 +37,97 @@ fn emit_line_shell(line: String) -> String {
concat("printf '%s\\n' ", shell_single_quote(s: line))
}

// Property-form openers use `cmd + " "` (e.g. `::error file=…`); simple form is `cmd + "::" + message`.
fn annotation_prefix_to_simple_op(prefix: String) -> String {
replace(prefix, " ", "")
}

fn render_annotation_col_part(col: Int?) -> String {
match col {
Present { value: c } => concat(",col=", to_string(value: c))
Absent => ""
}
}

fn render_located_diagnostic(
cmd_prefix: String,
message: String,
file: String,
line: Int,
col: Int?
) -> String {
concat(
cmd_prefix,
"file=", file,
",line=", to_string(value: line),
render_annotation_col_part(col: col),
"::",
message
)
}

fn render_simple_diagnostic(cmd_prefix: String, message: String) -> String {
concat(annotation_prefix_to_simple_op(prefix: cmd_prefix), "::", message)
}

fn render_diagnostic_annotation(
cmd_prefix: String,
message: String,
file: String?,
line: Int?,
col: Int?
) -> String {
match file {
Present { value: f } =>
match line {
Present { value: ln } =>
render_located_diagnostic(
cmd_prefix: cmd_prefix,
message: message,
file: f,
line: ln,
col: col
)
Absent =>
render_simple_diagnostic(cmd_prefix: cmd_prefix, message: message)
}
Absent =>
render_simple_diagnostic(cmd_prefix: cmd_prefix, message: message)
}
}

fn render_log_annotation(annotation: LogAnnotation) -> String {
match annotation {
AnnotationError { message: m, file: _, line: _, col: _ } =>
concat("::error::", m)
AnnotationWarning { message: m, file: _, line: _, col: _ } =>
concat("::warning::", m)
AnnotationNotice { message: m, file: _, line: _, col: _ } =>
concat("::notice::", m)
AnnotationError { message: m, file: f, line: ln, col: c } =>
render_diagnostic_annotation(
cmd_prefix: annotation_error_prefix,
message: m,
file: f,
line: ln,
col: c
)
AnnotationWarning { message: m, file: f, line: ln, col: c } =>
render_diagnostic_annotation(
cmd_prefix: annotation_warning_prefix,
message: m,
file: f,
line: ln,
col: c
)
AnnotationNotice { message: m, file: f, line: ln, col: c } =>
render_diagnostic_annotation(
cmd_prefix: annotation_notice_prefix,
message: m,
file: f,
line: ln,
col: c
)
AnnotationGroup { title: t } =>
concat(annotation_group_prefix, t)
AnnotationEndGroup =>
annotation_endgroup
SetOutput { name: n, value: v } =>
concat(annotation_set_output_prefix, n, "::", v)
concat(annotation_set_output_prefix, n, annotation_set_output_separator, v)
AddMask { value: v } =>
concat(annotation_add_mask_prefix, v)
StopCommands { token: t } =>
Expand Down
86 changes: 85 additions & 1 deletion dsl/gunbc/ci.dag
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@
// Floor membership (operator bankruptcy, final): exactly 3 blocking gates —
// dsl compile-clean (full tree minus enumerated allowlist), fmt,
// affected-tests (fail-safe over-inclusive selector). No demote spine;
// corpus/lens/layering are tests gate-3 runs when affected.
// corpus/lens/layering plus retired-job consumers (doc_refs, timeout_budgets,
// regen_stage0 --verify, get-off-v3 compile_to_dag census) are scripts gate-3 runs.
//
// Consumers:
// dsl/gunbc/tools/ci_runner.dag — runtime execution via run_ci_pipeline()
Expand All @@ -21,6 +22,89 @@ type SourceRoot {

data dsl_root: SourceRoot = { path: "dsl" }

// ── Base build graph (sccache pre-warm) ─────────────────────────────
// One release cargo invocation warms sccache for every gate-3 lens/host
// binary before the script fan-out in ci_runner. Pin scope =
// rust-toolchain.toml + Cargo.lock (toolchain-pinned; matches the ci.yml
// cargo cache key and cache_interface ToolchainSpec invalidation).

type CiBaseBuildPackage {
name: String
}

type CiBaseBuildBin {
package: String
name: String
release_path: String
}

type CiBaseBuildGraph {
packages: List<CiBaseBuildPackage>
bins: List<CiBaseBuildBin>
pin_paths: List<FilePath>
}

data ci_base_build_graph: CiBaseBuildGraph = {
packages: [
{ name: "v2-compiler" },
{ name: "ci_claim_gate" },
{ name: "layering_imports_scan" }
],
bins: [
{ package: "v2-compiler", name: "gunbc", release_path: "gunbc" },
{ package: "v2-compiler", name: "claim_batch", release_path: "claim_batch" },
{ package: "v2-compiler", name: "discover_owned_data", release_path: "discover_owned_data" },
{ package: "v2-compiler", name: "claim_executor", release_path: "claim_executor" },
{ package: "ci_claim_gate", name: "ci-claim-gate", release_path: "ci-claim-gate" },
{ package: "layering_imports_scan", name: "layering_imports_scan", release_path: "layering_imports_scan" }
],
pin_paths: [
"rust-toolchain.toml",
"Cargo.lock"
]
}

// ── Base build graph projection (single authority → shell transport) ───

fn render_ci_base_build_package_flag(pkg: CiBaseBuildPackage) -> String {
concat("-p ", pkg.name)
}

fn render_ci_base_build_package_flags(graph: CiBaseBuildGraph) -> String {
graph.packages
|> map(pkg => render_ci_base_build_package_flag(pkg: pkg))
|> join(separator: " ")
}

fn render_ci_base_build_bin_flag(bin: CiBaseBuildBin) -> String {
concat("--bin ", bin.name)
}

fn render_ci_base_build_bin_flags(graph: CiBaseBuildGraph) -> String {
graph.bins
|> map(bin => render_ci_base_build_bin_flag(bin: bin))
|> join(separator: " ")
}

fn render_ci_base_build_prewarm_cargo_command(graph: CiBaseBuildGraph) -> String {
concat(
"cargo build --release ",
render_ci_base_build_package_flags(graph: graph),
" ",
render_ci_base_build_bin_flags(graph: graph)
)
}

fn ensure_ci_base_build_bin_release(bin: CiBaseBuildBin) -> String {
concat("test -x target/release/", bin.release_path)
}

fn ensure_ci_base_build_bins_shell(graph: CiBaseBuildGraph) -> String {
graph.bins
|> map(bin => ensure_ci_base_build_bin_release(bin: bin))
|> join(separator: " && ")
}

// ── Gate kind ───────────────────────────────────────────────────────

type GateSource
Expand Down
11 changes: 9 additions & 2 deletions dsl/gunbc/parse_allowlist.dag
Original file line number Diff line number Diff line change
Expand Up @@ -18,17 +18,24 @@ type ParseAllowlistEntry {

data dsl_v2_parse_allowlist: List<ParseAllowlistEntry> = [
{
path: { path: "dsl/gunbc/ci_emission.dag" },
path: "dsl/gunbc/ci_emission.dag",
tag: V2ParserDebt {
reason: "record-literal Workflow body after = requires v2 brace-body support",
ref: "gunbc/ci_emission.dag gunbc_ci_emission_binary_shim_workflow"
}
},
{
path: { path: "dsl/std/unicode.dag" },
path: "dsl/std/unicode.dag",
tag: V2ParserDebt {
reason: "fn expression body (= match) not accepted by v2 parser",
ref: "std/unicode.dag char_in_class"
}
}
]

// Gate-1 transport: one path per line for scripts/v2-dsl-full-tree-parse-gate.sh.
fn dsl_v2_parse_allowlist_paths_tsv() -> String {
dsl_v2_parse_allowlist
|> map(e => e.path)
|> join(separator: "\n")
}
76 changes: 67 additions & 9 deletions dsl/gunbc/tools/ci_runner.dag
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,21 @@

module gunbc.tools.ci_runner

import gunbc.ci { ci_pipeline, CIGate, CICommand, SourceRoot }
import gunbc.ci {
ci_pipeline,
CIGate,
CICommand,
SourceRoot,
ci_base_build_graph,
render_ci_base_build_prewarm_cargo_command,
ensure_ci_base_build_bins_shell
}
import std.process { ProcessExit, ExitSuccess, ExitFailure, exit_code_general_error }
import extdeps.shell
import extdeps.github.log_annotations {
LogAnnotation,
AnnotationError, AnnotationNotice, AnnotationGroup, AnnotationEndGroup,
render_log_annotation, emit_line_shell
render_log_annotation, emit_line_shell, shell_single_quote
}

// ── Result types ────────────────────────────────────────────────────
Expand Down Expand Up @@ -142,22 +150,64 @@ fn with_sccache_env(script: String) -> String {
concat("export RUSTC_WRAPPER=sccache CARGO_INCREMENTAL=0; ", script)
}

// ── Sccache pre-warm (base build graph per pin) ─────────────────────
// After modeled sccache upsert, one release cargo build warms every gate-3 binary
// before the script fan-out. Authority: gunbc.ci `ci_base_build_graph`.

fn prewarm_sccache_base_build_shell() -> String {
with_sccache_env(
concat(
"bash .github/ci-floor/with-sccache-retry.sh ",
render_ci_base_build_prewarm_cargo_command(graph: ci_base_build_graph)
)
)
}

func prewarm_sccache_base_build_graph() -> Bool {
let _ = emit_log_annotation(
AnnotationGroup { title: "Pre-warm sccache (base build graph per pin)" }
)
let result = shell.Exec.Run(script: prewarm_sccache_base_build_shell())
if result.success {
let _ = emit_log_annotation(
AnnotationNotice {
message: "[PASS] sccache pre-warm (ci_base_build_graph)",
file: none,
line: none,
col: none
}
)
let _ = emit_log_annotation(AnnotationEndGroup)
true
} else {
let _ = emit_log_annotation(
AnnotationError {
message: "[FAIL] sccache pre-warm (ci_base_build_graph)",
file: none,
line: none,
col: none
}
)
let _ = emit_log_annotation(AnnotationEndGroup)
false
}
}

fn dsl_compile_clean_shell(root: SourceRoot) -> String {
with_sccache_env(
concat(
ensure_gunbc_binary(), " && ",
"bash scripts/v2-dsl-full-tree-parse-gate.sh"
"V2_PARSE_SOURCE_ROOT=",
shell_single_quote(s: root.path),
" bash scripts/v2-dsl-full-tree-parse-gate.sh"
)
)
}

fn affected_tests_shell() -> String {
with_sccache_env(
concat(
ensure_gunbc_binary(), " && ",
ensure_ci_claim_gate_binary(), " && ",
ensure_claim_batch_binary(), " && ",
ensure_discover_owned_data_binary(), " && ",
ensure_ci_base_build_bins_shell(graph: ci_base_build_graph),
" && ",
run_logged_script(
inner: "bash scripts/v4-affected-tests-gate.sh",
log_label: "gate3"
Expand Down Expand Up @@ -274,7 +324,15 @@ func sccache_upsert_preflight() -> ProcessExit {

func run_ci_pipeline() -> ProcessExit {
match sccache_upsert_preflight() {
ExitSuccess => pipeline_to_exit(result: compute_pipeline_result())
ExitSuccess =>
if prewarm_sccache_base_build_graph() {
pipeline_to_exit(result: compute_pipeline_result())
} else {
ExitFailure {
code: exit_code_general_error,
reason: "CI pipeline: sccache base-build pre-warm failed"
}
}
ExitFailure { code: c, reason: r } => ExitFailure { code: c, reason: r }
}
}
Loading
Loading