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
23 changes: 23 additions & 0 deletions .github/workflows/witnesses.yml
Original file line number Diff line number Diff line change
Expand Up @@ -226,6 +226,29 @@ jobs:
if '[' "$GUNBC_FLOOR_CLASS" '=' 'structural' ']' && '[' '-f' "$GUNBC_FLOOR_LOG" ']' && 'grep' '-q' 'Resource temporarily unavailable' "$GUNBC_FLOOR_LOG"; then GUNBC_FLOOR_CLASS='infra'; GUNBC_FLOOR_SIGNATURE='ResourceTemporarilyUnavailable'; fi
if (! '[' '-f' "$GUNBC_FLOOR_RECEIPT" ']') || '[' "$GUNBC_FLOOR_CLASS" '=' 'structural' ']' || ('[' "$GUNBC_FLOOR_CLASS" '=' 'infra' ']' && (! ('[' '-f' "$GUNBC_FLOOR_RECEIPT" ']' && 'grep' '-q' 'class=structural' "$GUNBC_FLOOR_RECEIPT"))) || ('[' "$GUNBC_FLOOR_CLASS" '=' 'none' ']' && (! ('[' '-f' "$GUNBC_FLOOR_RECEIPT" ']' && 'grep' '-q' 'class=structural' "$GUNBC_FLOOR_RECEIPT")) && (! ('[' '-f' "$GUNBC_FLOOR_RECEIPT" ']' && 'grep' '-q' 'class=infra' "$GUNBC_FLOOR_RECEIPT"))); then 'printf' 'class=%s\nsignature=%s\nexit=%s\n' "$GUNBC_FLOOR_CLASS" "$GUNBC_FLOOR_SIGNATURE" "$GUNBC_FLOOR_EXIT" > "$GUNBC_FLOOR_RECEIPT"; if '[' "$GUNBC_FLOOR_CLASS" '=' 'infra' ']'; then 'echo' '::error title=environment::floor_class='"$GUNBC_FLOOR_CLASS"' signature='"$GUNBC_FLOOR_SIGNATURE"' exit='"$GUNBC_FLOOR_EXIT"'; this is not a verdict about the diff. Attempt receipt: '"$GUNBC_FLOOR_RECEIPT"; fi; if '[' "$GUNBC_FLOOR_CLASS" '=' 'structural' ']'; then 'echo' '::error title=subject::floor_class='"$GUNBC_FLOOR_CLASS"' exit='"$GUNBC_FLOOR_EXIT"'; read the step log for the subject defect'; fi; fi
'exit' "$GUNBC_FLOOR_EXIT"
- name: Why this lane is red, and what would be a real finding
run: |
printf '%s\n' 'emit-build is a NON-REQUIRED detector lane. A red here does NOT block your merge:'
printf '%s\n' 'the required context is `witnesses`, and this job is not an input to it.'
printf '%s\n' ''
printf '%s\n' 'A RED IS CURRENTLY EXPECTED: main cannot self-host, and the break has this signature --'
printf '%s\n' ' E0573 PointerWidth at src/std_integer.rs'
printf '%s\n' ''
printf '%s\n' 'This notice names no owning pull request ON PURPOSE. Ownership of a standing break moves,'
printf '%s\n' 'and a stale pointer here would be read as authoritative by someone who has no other source.'
printf '%s\n' 'The SIGNATURE is the durable handle: search it to find whoever currently holds it.'
printf '%s\n' ''
printf '%s\n' 'WHAT TO DO: if the failure above matches that signature, this is not your defect and'
printf '%s\n' 'there is nothing for you to fix. Do not patch around it in your branch.'
printf '%s\n' ''
printf '%s\n' 'WHAT IS A REAL FINDING: a DIFFERENT error code, or a different emitted file. That is a'
printf '%s\n' 'second defect this lane just caught, and it should be reported rather than assumed to be'
printf '%s\n' 'the known one -- every break at this step shares cause=EmittedCompilerBuildFailed, so the'
printf '%s\n' 'cause line does not discriminate and the ERROR CODE is what you compare.'
printf '%s\n' ''
printf '%s\n' 'THIS STANDING RETIRES WHEN: a head of main on which `gunbc test //gunbc/instruments:self-host` and `gunbc test //gunbc/instruments:v2-native-cli` all exit zero'
printf '%s\n' 'If that already holds on main, this notice is stale: flip gunbc.emitted_subject_build_gate emit_build_standing to EmitBuildExpectedGreen.'
if: failure()
floor:
runs-on: [self-hosted, linux, arm64]
timeout-minutes: 90
Expand Down
157 changes: 156 additions & 1 deletion dag/gunbc/emitted_subject_build_gate.dag
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
module gunbc.emitted_subject_build_gate

import std.types { String, List }
import std.types { Bool, String, List }
import v2.std.algebra { list_map, list_append }
import extdeps.bazel.label { Label, render_label }
import extdeps.exec.command { ArgvCommand }
import gunbc.gunbc_cli_command { gunbc_test_command }
Expand Down Expand Up @@ -100,3 +101,157 @@ fn emitted_subject_build_command(row: EmittedSubjectBuildRow) -> ArgvCommand {
fn emitted_subject_build_step_name(row: EmittedSubjectBuildRow) -> String {
join(["emit and build ", emitted_subject_build_label_text(row: row)], "")
}

// ═══════════════════════════════════════════════════════════════════════════════════════════
// THE LANE'S STANDING, AND WHY IT IS A TYPED ROW RATHER THAN A SENTENCE IN A STEP
// ═══════════════════════════════════════════════════════════════════════════════════════════
//
// FROM THE MOMENT THIS LANE LANDED, EVERY PULL REQUEST IN THE REPOSITORY RUNS IT -- and while main
// cannot self-host, every one of them goes RED for a defect the author did not introduce and
// cannot fix. That is a standing cost this lane imposes on every other lane, and it is paid by
// whoever clicks the red X expecting to find their own mistake.
//
// The manager made exactly that mistake on gunbc#12043 with ONE instance in front of him: he read
// `mergeStateStatus: UNSTABLE`, took the red as a blocker, and dropped the PR from the merge card.
// It is now offered to every lane at once.
//
// WHY A TYPED STANDING AND NOT PROSE IN THE STEP. A note saying "this red is expected" is TRUE
// only while it is, and a lane still printing it after main self-hosts would be a lie that nobody
// owns -- the inert-annotation failure, on the one surface a stranger actually reads. The standing
// is a row, so retiring it is a visible edit with a name, and `EmitBuildExpectedGreen` makes the
// reassurance UNPRINTABLE the moment it stops being true.
//
// THE ROW CARRIES NO OWNING PR, AND THAT IS A CORRECTION RATHER THAN AN OMISSION. The first cut
// had an `owned_by` field naming gunbc#12070, which was FALSE within the hour: that repair was
// measured insufficient for this site -- it keeps a use-line when the provider's binding is a type
// declaration, and this binding is a variant -- and ownership then moved twice in one evening while
// two theories were proposed and falsified by the lanes that proposed them.
//
// THE LESSON IS ABOUT WHAT A TYPE PROTECTS. The standing being a typed row makes the REASSURANCE
// unprintable once it stops being true; it does nothing whatever for a volatile fact sitting in a
// field beside it. A `String` naming a PR is exactly as rottable inside a well-typed row as it
// would be in a comment, and this one rotted onto the surface a stranger reads before the PR that
// added it had even landed.
//
// SO THE FIELDS ARE RESTRICTED TO WHAT IS STABLE FOR THE STANDING'S LIFETIME: the signature, which
// is a property of the break, and the retirement condition, which is a capability. Ownership is a
// property of the ORGANISATION and belongs nowhere near a generated CI surface. The signature is
// also the durable handle -- searching for it finds whoever currently holds the investigation,
// which a stale PR number actively prevents.
//
// THE DISCRIMINATOR IS THE HALF THAT MATTERS, and the reassurance alone would be worse than
// nothing. A standing red teaches every lane to ignore this lane, which is how a detector dies
// without anyone deciding to kill it. So the row carries the KNOWN SIGNATURE and the message tells
// a reader what would be a genuinely new finding: a different error code, or a different emitted
// file. Matching red -- noise, do nothing. Different red -- a second defect, report it.
type NativeEmitBuildStanding
= EmitBuildExpectedGreen
| EmitBuildExpectedRed { known_signature: EmittedBuildSignature }

// THE SIGNATURE'S THREE PARTS ARE FIELDS, because the notice tells a reader to compare two of them
// SEPARATELY -- a different error code, or a different emitted file, is a new finding -- and a
// single string would leave that comparison to eyes (DESIGN section 2). The error code is rustc's
// own vocabulary; the path is the emitted crate's, relative to its root.
type EmittedBuildSignature {
error_code: String
symbol: String
emitted_path: String
}

fn render_emitted_build_signature(sig: EmittedBuildSignature) -> String {
join([sig.error_code, " ", sig.symbol, " at ", sig.emitted_path], "")
}

// THE RETIREMENT CONDITION IS NOT A FIELD: it is rendered from `emitted_subject_build_rows`, so it
// names exactly the instruments this lane runs, by their declared labels, and a subject added to
// the lane joins the condition without anyone restating it.
fn emit_build_standing_retirement() -> String {
join([
"a head of main on which ",
join(list_map(xs: emitted_subject_build_rows(), f: emitted_subject_build_retirement_clause), " and "),
" all exit zero",
], "")
}

fn emitted_subject_build_retirement_clause(row: EmittedSubjectBuildRow) -> String {
join(["`gunbc test ", emitted_subject_build_label_text(row: row), "`"], "")
}

// THE ONE ROW TO EDIT WHEN MAIN SELF-HOSTS AGAIN. Flipping it to `EmitBuildExpectedGreen` deletes
// the notice from every future run; leaving it stale keeps printing a reassurance for a red that
// is no longer expected, which is why the type has only two arms and no "probably fine" middle.
data emit_build_standing: NativeEmitBuildStanding = EmitBuildExpectedRed {
known_signature: EmittedBuildSignature {
error_code: "E0573",
symbol: "PointerWidth",
emitted_path: "src/std_integer.rs",
}
}

// THE LINES A LANE READS WHEN IT CLICKS THE RED X. Rendered from the standing row above AND from
// whether the lane blocks -- a SUPPLIED Bool, because that fact's one home is the lane row in
// `gunbc.compiler_gate_workflow` (`LaneBlocks` / `LaneAnnouncedNotBlocking`), which imports this
// module and composes the live notice. A hard-coded "does NOT block your merge" would go false the
// moment that row flips, on exactly the surface this rendering exists to keep honest.
//
// The retirement condition is PRINTED, so a reader who can see main self-host again knows the row
// is stale and what edit retires it. Nothing mechanically flips the row when the condition holds:
// that is review diligence, stated here rather than implied.
fn emit_build_standing_notice_for(standing: NativeEmitBuildStanding, lane_blocks: Bool) -> List<String> {
list_append(left: emit_build_lane_blocking_lines(lane_blocks: lane_blocks), right: emit_build_standing_lines(standing: standing, lane_blocks: lane_blocks))
}

fn emit_build_lane_blocking_lines(lane_blocks: Bool) -> List<String> {
if lane_blocks {
[
"emit-build is a REQUIRED lane: a red here BLOCKS your merge, through the required context `witnesses`.",
]
} else {
[
"emit-build is a NON-REQUIRED detector lane. A red here does NOT block your merge:",
"the required context is `witnesses`, and this job is not an input to it.",
]
}
}

// A BLOCKING LANE WITH A RED STANDING IS A CONTRADICTION, not a state to reassure anyone about:
// the flip trigger is main self-hosting, which is the standing's retirement condition. So that
// combination prints no "nothing for you to fix" -- it tells the reader the two rows disagree.
fn emit_build_standing_lines(standing: NativeEmitBuildStanding, lane_blocks: Bool) -> List<String> {
match standing {
EmitBuildExpectedGreen => [
"No standing break is declared, so a red here is a REAL FINDING -- most likely yours.",
]
EmitBuildExpectedRed { known_signature: sig } => if lane_blocks {
[
"",
"CONTRADICTION: this lane blocks, yet its standing still declares an expected red with signature",
join([" ", render_emitted_build_signature(sig: sig)], ""),
"The lane was to become required only once main self-hosts, which retires that standing.",
"One of gunbc.compiler_gate_workflow's emit-build lane row or",
"gunbc.emitted_subject_build_gate emit_build_standing is stale. Report it; do not assume this red is yours or not.",
]
} else {
[
"",
"A RED IS CURRENTLY EXPECTED: main cannot self-host, and the break has this signature --",
join([" ", render_emitted_build_signature(sig: sig)], ""),
"",
"This notice names no owning pull request ON PURPOSE. Ownership of a standing break moves,",
"and a stale pointer here would be read as authoritative by someone who has no other source.",
"The SIGNATURE is the durable handle: search it to find whoever currently holds it.",
"",
"WHAT TO DO: if the failure above matches that signature, this is not your defect and",
"there is nothing for you to fix. Do not patch around it in your branch.",
"",
"WHAT IS A REAL FINDING: a DIFFERENT error code, or a different emitted file. That is a",
"second defect this lane just caught, and it should be reported rather than assumed to be",
"the known one -- every break at this step shares cause=EmittedCompilerBuildFailed, so the",
"cause line does not discriminate and the ERROR CODE is what you compare.",
"",
join(["THIS STANDING RETIRES WHEN: ", emit_build_standing_retirement()], ""),
"If that already holds on main, this notice is stale: flip gunbc.emitted_subject_build_gate emit_build_standing to EmitBuildExpectedGreen.",
]
}
}
}
55 changes: 53 additions & 2 deletions dag/gunbc/witness/compiler_gate_workflow.dag
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ module gunbc.compiler_gate_workflow

import std.types { Bool, Int, List, String }
import v2.std.optional { Present, Absent }
import v2.std.algebra { list_map, filter, list_append }
import v2.std.algebra { list_map, filter, list_append, length }
import extdeps.languages.yaml.types { YamlKeyValue, yaml_string, yaml_int, yaml_bool, kv }
import extdeps.languages.yaml.emit { serialize_yaml }
import extdeps.languages.yaml.gha_workflow { project_workflow_to_yaml }
Expand Down Expand Up @@ -95,8 +95,10 @@ import gunbc.heal_workflow { heal_same_repository_clause, heal_not_dependabot_cl
import gunbc.repo_self_build { repo_self_build_command, repo_self_clippy_command }
import extdeps.exec.command { shell_command_render }
import extdeps.github.expressions { interpolate, ContextAccess, Needs, default_expression_spellings }
import extdeps.github.log_annotations { emit_line_shell }
import gunbc.emitted_subject_build_gate {
EmittedSubjectBuildRow,
emit_build_standing, emit_build_standing_notice_for,
emitted_subject_build_rows,
emitted_subject_build_command,
emitted_subject_build_step_name
Expand Down Expand Up @@ -689,6 +691,48 @@ fn compiler_gate_emit_build_step(row: EmittedSubjectBuildRow) -> Step {
}
}

// THE NOTICE STEP RUNS ON FAILURE AND ONLY ON FAILURE, because that is the one moment a stranger
// is looking at this job. It is the LAST step, so it appears directly beneath the diagnostic a
// reader is trying to interpret rather than scrolled away above it.
//
// `if: failure()` rather than `always()`: a notice printed on a green run is noise on every
// passing PR in the repository, and the reassurance has no subject when there is nothing to
// reassure anyone about.
//
// THE QUOTING IS `extdeps.github.log_annotations` `emit_line_shell` AND NOT A SECOND SPELLING OF
// IT. That module already owns printf-one-line-shell-quoted for exactly this purpose, and a
// hand-rolled `echo '...'` here would be the section 3 fork -- with the usual downgrade attached,
// since a line containing an apostrophe would terminate its own quote.
//
// IT ECHOES RATHER THAN ANNOTATES. A `::error::` would add a second red to a job that already has
// one, and a `::notice::` on a failed job is rendered where nobody looking at the failure will
// read it. Plain stdout at the end of the step list is where the eye already is.
// THE LIVE NOTICE: the standing row composed with THIS lane row's blocking status, so "does NOT
// block your merge" is printed only while `compiler_gate_lane_rows` says so, and the one-word flip
// to `LaneBlocks` changes the notice in the same edit.
fn compiler_gate_emit_build_notice_lines() -> List<String> {
emit_build_standing_notice_for(
standing: emit_build_standing,
lane_blocks: length(xs: filter(xs: compiler_gate_blocking_rows(), predicate: fn(row) {
row.job_id == compiler_gate_emit_build_job_id
})) > 0
)
}

fn compiler_gate_emit_build_notice_step() -> Step {
RunStep {
name: Present { value: "Why this lane is red, and what would be a real finding" },
id: none,
run: join(list_map(xs: compiler_gate_emit_build_notice_lines(), f: emit_line_shell), "\n"),
shell: none,
env: none,
working_directory: none,
if_condition: Present { value: "failure()" },
continue_on_error: none,
timeout_minutes: none
}
}

fn compiler_gate_emit_build_subject_bound_steps() -> List<CompilerGateBoundStep> {
list_map(xs: emitted_subject_build_rows(), f: fn(row) {
CompilerGateBoundStep {
Expand All @@ -704,7 +748,14 @@ fn compiler_gate_emit_build_subject_bound_steps() -> List<CompilerGateBoundStep>
// instruments are invoked through. It is `compiler_gate_bound_steps` rather than a copy of it, so
// a change to the prelude cannot reach one lane and miss the other.
fn compiler_gate_emit_build_bound_steps() -> List<CompilerGateBoundStep> {
concat(compiler_gate_bound_steps(), compiler_gate_emit_build_subject_bound_steps())
concat(
concat(compiler_gate_bound_steps(), compiler_gate_emit_build_subject_bound_steps()),
[CompilerGateBoundStep {
step: compiler_gate_emit_build_notice_step(),
role: capability_neutral,
step_name: "Why this lane is red, and what would be a real finding",
}]
)
}

fn compiler_gate_emit_build_capability_closure_holds() -> Bool {
Expand Down
Loading
Loading