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
1 change: 1 addition & 0 deletions dag/test/claim/build_cache_endpoint_observe_test.dag
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
module test.claim.build_cache_endpoint_observe

import v2.std.live_tree { LiveTreeDisposition, SubstrateInputsOnly }
import gunbc.build_cache_instance { ProcessIdentity }
import extdeps.systemd.unit_file { systemd_unit_file_lines }
import std.materialization_ladder { string_list_contains }
Expand Down
1 change: 1 addition & 0 deletions dag/test/claim/ci/ci_budget_tree_witness_test.dag
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
module test.claim.ci_budget_tree_witness

import v2.std.live_tree { LiveTreeDisposition, ReadsLiveTree }
import gunbc.ci_runner_placement { resolve_session_slice }
import gunbc.ci_runner_target { FleetSelfHosted, ci_runner_target_ram_speed_budget }
import gunbc.ci_budget_tree {
Expand Down
12 changes: 9 additions & 3 deletions dag/test/claim/executor_privileged_operation_witness_test.dag
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import gunbc.fabric_cell_effect { fabric_cell_slice_desired_directives }
import extdeps.systemd.unit_file { slice_cpu_quota, slice_cpu_quota_unbounded, systemd_slice_directive_line }
import gunbc.fleet_intent_network { operator_host_srv2, operator_host_srv4 }
import gunbc.runner_host_deploy { admitted_deploy_for, RunnerHostDeploy }
import gunbc.executor_privileged_operation { sudoers_argument_word }

data live_tree_disposition: LiveTreeDisposition = SubstrateInputsOnly

Expand Down Expand Up @@ -179,19 +180,23 @@ test fn witness_population_tracks_the_slot_roster() -> Bool {
// throttle the ruling forbids. That negative is a LINE-TERMINAL `%`: a percentage grant is the
// only sudoers line that ends in one, whereas a `%group` principal line begins with it, so the
// clause names the CPU grant and not every future row that happens to carry the character
// (review 68479).
// (review 68479). THE SUDOERS SIDE IS READ IN SUDOERS' OWN SPELLING: since #12563 every grant word
// passes through gunbc.executor_privileged_operation sudoers_argument_word, which escapes `=` as
// sudoers(5) documents, so the file carries `CPUQuota\=` and the bare directive line can never
// appear in it. The claim renders the assignment through that same escape rather than transcribing
// the escaped literal, so the two sides stay one word under the grammar that joins them.
test fn witness_fabric_slice_cpu_quota_grant_is_the_declared_directive() -> Bool {
let ds = fabric_cell_slice_desired_directives()
let desired_lines = join(map(ds, d => systemd_slice_directive_line(directive: d)), "\n")
match gunbc_runner_slot_cpu_quota() {
CpuQuotaResolved { threads: t } => {
let assignment = systemd_slice_directive_line(directive: slice_cpu_quota(threads: t))
string_contains(s: srv3_runner_host_sudoers(), pattern: assignment)
string_contains(s: srv3_runner_host_sudoers(), pattern: sudoers_argument_word(w: assignment))
&& string_contains(s: desired_lines, pattern: assignment)
}
SlotCpuQuotaUnbounded => {
let assignment = systemd_slice_directive_line(directive: slice_cpu_quota_unbounded())
string_contains(s: srv3_runner_host_sudoers(), pattern: join([assignment, "\n"], ""))
string_contains(s: srv3_runner_host_sudoers(), pattern: join([sudoers_argument_word(w: assignment), "\n"], ""))
&& string_contains(s: desired_lines, pattern: assignment)
&& !string_contains(s: srv3_runner_host_sudoers(), pattern: join(["%", "\n"], ""))
}
Expand Down Expand Up @@ -326,3 +331,4 @@ fn wt_srv3_deploy() -> RunnerHostDeploy {
Absent => wt_missing_deploy()
}
}

1 change: 1 addition & 0 deletions dag/test/claim/host/host_allocation_conservation_test.dag
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ module test.claim.host_allocation_conservation
// the only way to execute a row was a whole-tree floor run. The imports below are what it was
// already using; making them explicit costs nothing and buys a witness you can execute while you
// are writing it, which is the difference between finding a defect now and finding it in CI.
import v2.std.live_tree { LiveTreeDisposition, SubstrateInputsOnly }
import std.types { String, Bool, Int, List }
import std.measure { ByteSize, byte_size, hardware_thread_count_value }
import extdeps.cpu.ampere { altra_max_m12830_catalog }
Expand Down
24 changes: 21 additions & 3 deletions dag/test/claim/host/host_converge_slice1_witness_test.dag
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import std.types { Bool, NonEmptyStr, List, String }
import gunbc.host_effect { LocalShell }
import gunbc.runner_host_deploy { runner_index_seq }
import extdeps.systemd { systemd_memory_max_property, MemoryMax, systemd_tasks_max_property, parse_systemd_task_limit_show }
import gunbc.host_converge { Drifted, PerSlotMemoryCap, VerdictConverged }
import gunbc.host_converge { ConvergeVerdict, Drifted, PerSlotMemoryCap, VerdictConverged }
import gunbc.fleet_intent_network { operator_host_srv1 }
import gunbc.runner_unit_live_read {
gunbc_srv1_runner_unit_live_read_fixture,
Expand Down Expand Up @@ -249,11 +249,28 @@ test fn witness_tasks_verdict_desired_count_converges_and_offbyone_drifts() -> B
}
}

// THE VERDICT IS READ BY A MATCH OVER ITS OWN TYPE, NOT COMPARED TO A BARE `Absent`. `Absent` names
// two constructors here -- the Optional arm this claim matches on one line up, and
// gunbc.host_converge ConvergeVerdict's arm, which this module never imported -- and an `==` operand
// carries no expected type to choose between them. Executed: the subject returns the verdict arm
// for "" and the comparison was false, so the claim could not go green whatever the subject did.
// A match on a ConvergeVerdict scrutinee is typed by the scrutinee, enumerates the other two arms,
// and the "512" conjunct is the discriminating red: a verdict function that answered Absent for
// everything satisfies the first two conjuncts and fails this one.
fn tasks_verdict_is_absent(v: ConvergeVerdict) -> Bool {
match v {
VerdictConverged => false
Drifted => false
Absent => true
}
}

test fn witness_tasks_parse_empty_or_junk_is_absent_verdict() -> Bool {
match host_converge_slice1_tasks_knob(host: operator_host_srv1) {
Present { value: knob } =>
host_converge_slice1_tasks_verdict(limit: parse_systemd_task_limit_show(raw: ""), knob: knob) == Absent
&& host_converge_slice1_tasks_verdict(limit: parse_systemd_task_limit_show(raw: "not-a-count"), knob: knob) == Absent
tasks_verdict_is_absent(v: host_converge_slice1_tasks_verdict(limit: parse_systemd_task_limit_show(raw: ""), knob: knob))
&& tasks_verdict_is_absent(v: host_converge_slice1_tasks_verdict(limit: parse_systemd_task_limit_show(raw: "not-a-count"), knob: knob))
&& !tasks_verdict_is_absent(v: host_converge_slice1_tasks_verdict(limit: parse_systemd_task_limit_show(raw: "512"), knob: knob))
Absent => false
}
}
Expand Down Expand Up @@ -312,3 +329,4 @@ test fn witness_tasks_guard_boundary_equality_refuses() -> Bool {
&& host_converge_slice1_tasks_headroom_refuses(current: 16385, target: 16384)
&& !host_converge_slice1_tasks_headroom_refuses(current: 16383, target: 16384)
}

25 changes: 23 additions & 2 deletions dag/test/claim/live_deploy/emit_test.dag
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import gunbc.live_deploy.spec {
DeploymentDependencyStep,
ensured_subject_identity,
deployment_fabric_storage_steps,
deployment_approval_broker_front_door_steps,
deployment_fabric_storage_serve_endpoint,
EnsuredPackage,
EnsuredManagedHostDirectory,
Expand Down Expand Up @@ -816,19 +817,38 @@ fn spec_owned_paths(spec: DeploymentSpec) -> List<String> {
}


// THE TWIN MIRRORS PRODUCTION AS AN IDENTITY JOIN ON ARTIFACT KIND, NOT A COUNT. The host-singleton
// members -- the fabric storage placement's two and, since #12747, the approval broker's front door --
// are named by the functions that decide them and subtracted from production by path; every other
// production member must have a twin member of the same kind and vice versa, and the twin must own
// no host singleton at all. The count form this replaces (`twin + fabric == live`) went red the day
// #12747 added a second host-scoped member, though nothing about the twin was wrong.
fn live_host_singleton_paths(live: DeploymentSpec) -> List<String> {
concat(
deployment_fabric_storage_steps(instance: srv1_live_dashboard_instance(), names: live.names),
deployment_approval_broker_front_door_steps(instance: srv1_live_dashboard_instance()),
) |> map(s => s.path as String)
}

test fn a_twin_deployment_on_one_host_collides_with_nothing() -> Bool {
let live = deployment_spec_srv1()
let twin = srv1_twin_spec()
let live_paths = spec_owned_paths(spec: live)
let twin_paths = spec_owned_paths(spec: twin)
let singletons = live_host_singleton_paths(live: live)
let live_instance_scoped = filter(deployment_owned_steps_retract_order(spec: live), l => !any(singletons, h => h == (l.path as String)))
let twin_steps = deployment_owned_steps_retract_order(spec: twin)
deployment_plan_host_identity(spec: live) == deployment_plan_host_identity(spec: twin)
&& !(deployment_plan_listen_port(spec: live) == deployment_plan_listen_port(spec: twin))
&& !(live.service.unit_name == twin.service.unit_name)
&& !(live.service.repo_root == twin.service.repo_root)
&& !(live.service.serve_binary == twin.service.serve_binary)
&& count(live_paths) > 0
&& count(twin_paths) + count(deployment_fabric_storage_steps(instance: srv1_live_dashboard_instance(), names: live.names)) == count(live_paths)
&& count(live_instance_scoped) > 0
&& all(singletons, h => any(live_paths, l => l == h))
&& all(live_instance_scoped, l => any(twin_steps, t => t.kind == l.kind))
&& all(twin_steps, t => any(live_instance_scoped, l => l.kind == t.kind))
&& count(deployment_fabric_storage_steps(instance: srv1_lab_dashboard_instance(), names: twin.names)) == 0
&& count(deployment_approval_broker_front_door_steps(instance: srv1_lab_dashboard_instance())) == 0
&& all(twin_paths, t => !any(live_paths, l => l == t))
}

Expand Down Expand Up @@ -1775,3 +1795,4 @@ test fn the_fabric_storage_unit_binds_its_door_socket_and_its_route_proxies_to_i
&& (route.backend as String) == join(["unix:", fabric_storage_door_socket() as String], "")
&& (match route.mount { ServeRootMount => true ServeSetPath { path: _ } => false })
}

26 changes: 20 additions & 6 deletions dag/test/claim/runner/runner_lifecycle_witness_test.dag
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import std.logic { Bool }
import std.types { list_length, NonEmptyStr }
import std.measure { byte_size, byte_size_count }
import gunbc.runner_unit { runner_slot_unit_name }
import gunbc.runner_slot_allocation { srv3_fabric_first_slot, srv4_fabric_first_slot }
import gunbc.runner_lifecycle {
runner_slot_add_sequence_for,
RunnerSlotAddSequence,
Expand Down Expand Up @@ -171,13 +172,25 @@ fn sequence_registers_with_github(seq: RunnerSlotAddSequence) -> Bool {
// them registrable.
//
// BOTH DIRECTIONS ARE ASSERTED BECAUSE ONLY ONE OF THEM IS THE SAFETY CLAIM AND ONLY THE OTHER
// PROVES THE GATE IS NOT VACUOUS. A gate that refused everything would satisfy the fabric row
// alone; srv4-06 is the control -- the same slot index on a host of the same committed width --
// and it must still receive the full twelve-step GitHub sequence.
// PROVES THE GATE IS NOT VACUOUS. A gate that refused everything would satisfy the fabric rows
// alone, so each fabric member is paired with a control on ITS OWN HOST: the slot one below it.
//
// BOTH SIDES ARE READ FROM THE MEMBERSHIP AUTHORITY, NOT TYPED AS SLOT LITERALS. The previous
// control was srv4-06, chosen as "the same index on a host of the same width" when srv4 carried
// no fabric member; gunbc.runner_slot_allocation srv4_fabric_first_slot made srv4-06 a fabric
// slot on 2026-09-18, the control became a second fabric row, and the claim went red for a reason
// it had nothing to say about. Deriving the subjects from srv3_fabric_first_slot and
// srv4_fabric_first_slot means a moved fabric member moves the claim with it; the control below
// each is a GitHub member by construction of the carve (the second fabric member sits ABOVE the
// first, gunbc.runner_slot_allocation fabric_second_slot_index).
fn fabric_member_refuses_and_its_neighbour_registers(fabric: RunnerSlotIdentity) -> Bool {
!sequence_registers_with_github(seq: runner_slot_add_sequence_for(host: fabric.host, slot_index: fabric.slot_index))
&& sequence_registers_with_github(seq: runner_slot_add_sequence_for(host: fabric.host, slot_index: fabric.slot_index - 1))
}

test fn the_fabric_slot_cannot_be_registered_and_the_gate_is_not_vacuous() -> Bool {
!sequence_registers_with_github(seq: runner_slot_add_sequence_for(host: operator_host_srv3, slot_index: 6))
&& sequence_registers_with_github(seq: runner_slot_add_sequence_for(host: operator_host_srv4, slot_index: 6))
&& sequence_registers_with_github(seq: runner_slot_add_sequence_for(host: operator_host_srv3, slot_index: 5))
fabric_member_refuses_and_its_neighbour_registers(fabric: srv3_fabric_first_slot())
&& fabric_member_refuses_and_its_neighbour_registers(fabric: srv4_fabric_first_slot())
}

// THE COLLISION ROW. Before the suffix fork was dissolved, runner_incarnation enumerated indices 1
Expand Down Expand Up @@ -211,3 +224,4 @@ test fn the_suffix_is_unchanged_across_the_committed_range() -> Bool {
&& runner_slot_index_suffix(index: 5) == "05"
&& runner_slot_index_suffix(index: 6) == "06"
}

Original file line number Diff line number Diff line change
Expand Up @@ -1013,7 +1013,7 @@ data unimported_bare_provider_dispositions: List<UnimportedBareProviderDispositi
UnimportedBareProviderDisposition { file: "dag/test/claim/build_cache_endpoint_observe_test.dag", name: "ObservationCurrent", standing: ActiveDebt },
UnimportedBareProviderDisposition { file: "dag/test/claim/build_cache_endpoint_observe_test.dag", name: "RunnerWidthDerived", standing: ActiveDebt },
UnimportedBareProviderDisposition { file: "dag/test/claim/build_cache_endpoint_observe_test.dag", name: "RunnerWidthUnresolved", standing: ActiveDebt },
UnimportedBareProviderDisposition { file: "dag/test/claim/build_cache_endpoint_observe_test.dag", name: "SubstrateInputsOnly", standing: ActiveDebt },
UnimportedBareProviderDisposition { file: "dag/test/claim/build_cache_endpoint_observe_test.dag", name: "SubstrateInputsOnly", standing: Retired { cause: ImportsFixed } },
UnimportedBareProviderDisposition { file: "dag/test/claim/build_cache_endpoint_observe_test.dag", name: "admit_ensure_build_cache_instance", standing: ActiveDebt },
UnimportedBareProviderDisposition { file: "dag/test/claim/build_cache_endpoint_observe_test.dag", name: "gunbc_runner_committed_width", standing: ActiveDebt },
UnimportedBareProviderDisposition { file: "dag/test/claim/build_cache_ensure_test.dag", name: "SubstrateInputsOnly", standing: ActiveDebt },
Expand All @@ -1025,7 +1025,7 @@ data unimported_bare_provider_dispositions: List<UnimportedBareProviderDispositi
UnimportedBareProviderDisposition { file: "dag/test/claim/capacity_pool_witness_test.dag", name: "length", standing: ActiveDebt },
UnimportedBareProviderDisposition { file: "dag/test/claim/census_app_acquisition_refusal_probe_witness_test.dag", name: "filter", standing: Retired { cause: ImportsFixed } },
UnimportedBareProviderDisposition { file: "dag/test/claim/cgroup_v2_memory_hard_limit_witness_test.dag", name: "length", standing: Retired { cause: ImportsFixed } },
UnimportedBareProviderDisposition { file: "dag/test/claim/ci/ci_budget_tree_witness_test.dag", name: "ReadsLiveTree", standing: ActiveDebt },
UnimportedBareProviderDisposition { file: "dag/test/claim/ci/ci_budget_tree_witness_test.dag", name: "ReadsLiveTree", standing: Retired { cause: ImportsFixed } },
UnimportedBareProviderDisposition { file: "dag/test/claim/ci/ci_failure_class_witness_test.dag", name: "CommandNotFound", standing: ActiveDebt },
UnimportedBareProviderDisposition { file: "dag/test/claim/ci/ci_failure_class_witness_test.dag", name: "ExitFailure", standing: ActiveDebt },
UnimportedBareProviderDisposition { file: "dag/test/claim/ci/ci_failure_class_witness_test.dag", name: "FloorFailed", standing: ActiveDebt },
Expand Down Expand Up @@ -1294,7 +1294,7 @@ data unimported_bare_provider_dispositions: List<UnimportedBareProviderDispositi
UnimportedBareProviderDisposition { file: "dag/test/claim/hand_lens_host_bridge_scaffold_watchdog_test.dag", name: "transport_script_position_scaffold_row", standing: ActiveDebt },
UnimportedBareProviderDisposition { file: "dag/test/claim/hetzner_cost_quote_witness_test.dag", name: "SubstrateInputsOnly", standing: ActiveDebt },
UnimportedBareProviderDisposition { file: "dag/test/claim/hetzner_listing_witness_test.dag", name: "obligation", standing: Retired { cause: NotAReference } },
UnimportedBareProviderDisposition { file: "dag/test/claim/host/host_allocation_conservation_test.dag", name: "SubstrateInputsOnly", standing: ActiveDebt },
UnimportedBareProviderDisposition { file: "dag/test/claim/host/host_allocation_conservation_test.dag", name: "SubstrateInputsOnly", standing: Retired { cause: ImportsFixed } },
UnimportedBareProviderDisposition { file: "dag/test/claim/host/host_hygiene_liveness_test.dag", name: "SubstrateInputsOnly", standing: Retired { cause: ImportsFixed } },
UnimportedBareProviderDisposition { file: "dag/test/claim/host/host_phase_status_witness_test.dag", name: "CiRunnerParticipation", standing: ActiveDebt },
UnimportedBareProviderDisposition { file: "dag/test/claim/host/host_phase_status_witness_test.dag", name: "DeclaredGap", standing: ActiveDebt },
Expand Down