Repository navigation
STAGE-2 PR-1: fleet-resource model (per-type baselines + shared build pool) + §3 jobserver single-authority - #5663
Conversation
…essions derived together, fail-closed End the hand-tuned 4/6 runner counts AND the 4g/31.25G session-reservation forks by deriving both from one measured host budget as conserving siblings. - ci_runner_placement: runner count now conserves against a DERIVED session slice (host_ram - overhead - per_session_cap*concurrency = runner_slice; runner_count = runner_slice / 24GiB whole-run cgroup peak). Replaces the session-blind (host-overhead)*0.8 path that over-committed when sessions co-reside. Operating point (per_session_cap C, concurrency N) is an operator choice, committed UNSOUND -> both legs fail-closed until set. operating_curve() renders the C/N vs runners vs measured-peak-coverage tradeoff, grounded in 13 live srv2 samples. - ci_floor_measurement: measured per-session peak distribution (min 0.28/median 2.06/ max 8.27 GiB) replaces the 31.25G cap and 4g admission knob (both non-measurements). REGIME-1 (C*N, shipping) and REGIME-2 (aggregate-peak, gated on the systemd-oomd floor keystone) named in-model. Per-run 24GiB peak marked Measured-CONSERVATIVE with the cgroup-VmHWM sharpening follow-up named. - runner_deploy_emit: manifest renders both legs + the operating curve; committed at .github/fleet-runner-deploy.manifest and wired into generated_artifact_registry so the floor's GeneratedArtifactDriftGate is the single drift authority (additive row, no structural floor change). - ci_budget_tree: conserving host BudgetNode repointed to the unified session slice, srv1+srv2, REGIME-1 conservation by construction (byte_size_saturating_sub). Within-run spawn-width budget de-conflated onto its own carrier (live value unchanged) so the inter-run fail-closed plan never zeroes the live floor width. - Removed hand fallbacks (conservative_high=10, cap_enforced flag) -> no silent fail-open. - Witnesses rewritten: fail-closed-live + measured-fixture-positive with discriminating REDs. Live apply (srv1/srv2 runner counts, dashboard reservation, oomd floor) is operator-owned. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
… cluster The dashboard review flagged OperatingPointRow.min_runner_count: Int via the M12 unit-modeling pre-scan. Per the reviewer's own note the counts are a pre-existing UNIFORM bare-Int pattern (session_concurrency, coverage_count, sample_count, and the pre-existing RunnerHostDeployment.runner_count) and a cardinal Int per DESIGN sec 2 (like rank_count/contact_count). Converting one field alone is the forked-logic trap. Resolve at the CLUSTER with one modeled data-decl marker (NOT a comment; // is parse- walled post-#5579): gunbc_ci_count_field_measure_followup names the whole count cluster and its dissolve-on = the M12 value-Measure / HardwareThreadCount-style count-carrier sweep, to land for all fields together. Wired into the witnesses so the marker (and the REGIME/footprint/provenance follow-up markers) are execution-referenced, not dead. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…solve-on convention The re-review re-flagged min_runner_count: Int and offered: make the cluster-sweep deferral explicit "via a feature: tag matching the convention." Done — the cluster marker now carries `dissolve-on feature:M12-cardinal-count-value-measure-sweep`, the same feature:<slug> dissolve-on convention used elsewhere (free-monoid-entry, T-13). The marker also records the substantive §2 case: these are cardinal counts (like the codebase-wide bare-Int rank_count/contact_count/processor_count/approval_count and the lens's own index/ordinal exemptions), and unit_modeling is an advisory region-3 RatchetForever that is not floor-enrolled and does not gate CI. Cluster-sweep disposition, no per-field conversion. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…DeployArtifact The floor's generated_artifact_drift_witnesses (registry-completeness witness, separate from the drift gate I verified locally) hardcodes count(registry) == 4 + plans and enumerates each known artifact. Adding RunnerDeployArtifact made it 5 + plans. Update the count and add registry_contains + artifact_is_committed assertions for RunnerDeployArtifact. Root: I ran the drift GATE locally (file vs generated) but not this registry-count WITNESS (the discovering consumer) — DESIGN §5: green-by-execution means the real consumer runs. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…md keystone
Parent ask: make REGIME-2 a real selectable operating-MODE, not only NAMED, so the
operator's pick lands as a 1-line set regardless of regime.
Structural add (single authority = SessionReservationMode):
- Regime1WorstCase { point } -> slice = cap C * concurrency N (worst-case)
- Regime2AggregateOomd { ceiling, n,
aggregate_reservation, oomd_enforcement }
-> slice = measured AGGREGATE; C kept only as the per-session oomd eviction ceiling
- SessionReservationModeUnset (committed default; fail-closed -> PlanUnsound)
resolve_session_slice dispatches on the mode. REGIME-2 is fail-closed behind TWO gates,
neither guessed:
(a) aggregate_reservation = SessionAggregateUnmeasured until a measured aggregate-
concurrent-peak series lands (the 13 per-session samples are NOT an aggregate);
(b) oomd_enforcement = OomdUnverified until per-cgroup memory.max + systemd-oomd is
verified live (the KEYSTONE = srv2-reboot fix AND REGIME-2 enabler).
Both gates -> SessionSliceUnresolved -> the manifest stays UNSOUND by construction.
Discriminating witness witness_regime2_reserves_aggregate_not_product proves REGIME-2
reserves the measured aggregate (15GiB), NOT ceiling*n (128GiB). Renamed the committed
authority gunbc_ci_session_operating_point -> gunbc_ci_session_reservation_mode; updated
runner/session/budget-tree consumers; regenerated the drift-gated manifest.
Witnesses green by execution: runner_placement_holds, ci_budget_tree_holds,
generated_artifact_drift_witnesses all true.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Parent ruled KEEP the Regime2AggregateOomd shell with one honesty condition: the opaque aggregate_reservation must carry a NAMED dissolution-trigger marker (modeled data-decl, not a comment per #5579), so it is an honest forward-composing scaffold per DESIGN §6, not parallel-representation debt. Add gunbc_ci_regime2_aggregate_dissolution_marker (dissolve-on stage:per-type-baseline-build-pool): the single aggregate is the coarse collapse of overhead + Σ(container-type baselines) + capped shared_build_pool, where the build pool is the EXISTING ctrl-jobserver (scheduling) + ctrl-sccache (caching) = the two arms of std.realization RealizedStep already unifying GHA + session builds. Wired into witness_followup_markers_documented so it stays floor-covered (not an inert decl). Witness green by execution; manifest unchanged (markers are not rendered). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…elines + conserving host budget Models the fleet host budget as host = overhead + Sigma(container baselines) + capped shared build pool + headroom, fail-closed throughout, dissolving the #5650 Regime2 aggregate-reservation coarse stand-in into its grounded decomposition. - extdeps/ctrl/jobserver.dag: the ONE build-pool authority (cite-don't-copy). Jobserver tokens are INSTALLER-DERIVED (memory-bounded), NOT a baked 120: derive_jobserver_tokens = min(nproc-margin, fit_count_floor(mem-reserve, mib_per_job)) -> ~66 on a 128-core/125GiB host. CtrlJobserverCitation committed Absent (fail-closed; /opt/ctrl root-only), flip-to-Cited is a later 1-line fill. - gunbc/fleet_container.dag: per-type idle baselines (GhaRunner 300MiB, AgentSession 450MiB, measured live), fail-closed BaselineResolution (no silent zero). - gunbc/fleet_host_budget.dag: build = ONE shared RealizedStep (CreateIfAbsent+Share); derived oomd_actuation_floor; fail-closed HeadroomResolution; conserving BudgetNode with capped_build_pool = min(nominal, room); runner_slice_cap VALUE refines the existing 55/70% drop-in. fleet_host_plan Unsound on any of {jobserver-absent, baseline-unmeasured, headroom-unsound, oomd-unverified}. - test/claim/fleet_host_budget_test.dag: fleet_model_holds green by execution, with discriminating fail-closed + overcommit RED witnesses. D1 (HostJobserverFifo -> CtrlJobserverConfig) left UNAPPLIED pending sign-off (load-bearing compute_fabric edit); diff verified clean, zero consumers. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…marker dissolution
Parent checkpoint (i) requires three green-by-execution witnesses; the build had
capped-conservation but not the other two. Add:
- RunnerSliceCapEffectiveness (CapEffective{bytes} | CapUnbounded) + runner_slice_cap_drifted:
models the REAL over-commit vector -- 10-resource-caps.conf MemoryMax set ON DISK
(70391285350) while the effective runtime cgroup is CapUnbounded (INFINITY) -> drift=true;
reconciled (CapEffective with the disk cap) -> false. Fixture red-receipt is discriminating.
Live-read arm (systemctl show effective MemoryMax) is the D2 effectful floor gate, fail-closed
off-host.
- witness_5650_marker_dissolution: the coarse #5650 Regime2 aggregate_reservation dissolves into
the fine STAGE-2 decomposition; proven by EXACT conservation -- overhead + Sigma(baselines) +
capped_build_pool + headroom + runner_slice_cap == host (nothing lost/double-counted), with the
fine parts distinct + non-zero, referencing the live #5650 marker.
fleet_model_holds green (15 witnesses); runner_placement_holds + ci_budget_tree_holds unbroken.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…Fifo references CtrlJobserverConfig The jobserver token count now has ONE home: extdeps.ctrl.jobserver.CtrlJobserverConfig (the cited installer-derivation authority). product.compute_fabric's HostJobserverFifo provider-constraint stops carrying its own token_cap:Int literal and instead references the single authority by config_ref, making the duplicate unwritable by construction (§3) rather than reconciled by a check (§5 validation anti-pattern). Verified: HostJobserverFifo + token_cap each had exactly ONE occurrence (the type decl), zero constructors, token_cap never read -> breaks no consumer. Layer direction product -> extdeps is the legal downward import. All three witness suites (fleet_model_holds / runner_placement_holds / ci_budget_tree_holds) green by execution after the change. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
… bare Int Review 32115 hard-blocker: nproc / margin / the derived token count are hardware-thread counts, and HardwareThreadCount (std.measure, = Measure<Count,One,Nat>) is the canonical authority ALREADY consumed by compute_fabric (CpuRequirement.min_threads). Bare Int here was a §3 consume-never-fork violation (distinct from #5650's ungrounded cardinal counts, which have no carrier). Fixed by construction, not a dissolve-on tag: - CtrlJobserverConfig.margin: Int -> HardwareThreadCount - derive_jobserver_tokens(nproc: HardwareThreadCount, ...) -> HardwareThreadCount (extract values for the min/monus arithmetic, reconstruct at the boundary) - jobserver_build_pool_bytes / nominal_build_pool / fleet_host_plan_for nproc params -> HardwareThreadCount; FleetHostPlanDerived.effective_build_tokens -> HardwareThreadCount; the nproc: 128 literal -> hardware_thread_count(count: 128). All suites green by execution: fleet_model_holds (incl tokens-memory-bound-binds=66<120), runner_placement_holds, ci_budget_tree_holds. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
Thanks — both addressed. Finding 1 (HardwareThreadCount hard-blocker) — fixed by construction in
This is the construction fix (consume the existing authority), not a Finding 2 (parallel
Per DESIGN's recurring failure mode "state-space conflation (an — sent from cool-boar-883 |
…derflow (review 32119 minor) The grounded numeric tower realizes Nat as a native Int, so `nproc_v - margin_v` is integer (not monus) subtraction: proven by execution that nproc=8/margin=64 yielded a negative token count flowing silently into jobserver_build_pool_bytes (a §5 fail-open wrong value, not a typed error). Fix at the carrier, single-authority: add hardware_thread_count_saturating_sub to std.realization_width (sibling of byte_size_saturating_sub / bounded_host_spawn_width, the saturating-sub home) and consume it in derive_jobserver_tokens. margin>=nproc now saturates to 0 tokens (degenerate-but-sound: a host that cannot build). Coverage: new discriminating witness witness_margin_exceeds_nproc_saturates (nproc=8/margin=64 -> 0 tokens) wired into fleet_model_holds. All three suites green by execution: fleet_model_holds, runner_placement_holds, ci_budget_tree_holds. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
Thanks — verified the minor note against the code and it's actually a real fail-open, not merely defensive, so I pushed a fix ( The grounded numeric tower realizes Fix at the carrier, single-authority: added — sent from cool-boar-883 |
…ion (review 32126 §5 note) The reviewer flagged baseline_or_zero -> byte_size(0) on BaselineUnmeasured as a fail-open SHAPE (§5 construction-over-validation): dead-in-flight (shielded by the upstream BaselineResolved gate in fleet_host_plan_for) but a helper named "or zero" still concedes the bad state is writable. Worse, the gate RESOLVED both baselines then DISCARDED the bytes (`bytes: _`) and re-resolved via baselines_sum with the zero fallback (resolve-discard-reresolve). Construction fix (per the reviewer's pointer "refuse to call baselines_sum outside the resolved branch"): resolve once at the gate, bind the resolved ByteSize (`bytes: rb` / `bytes: sb`), and flow them forward. baselines_sum and fleet_host_budget_tree now take resolved ByteSize, not FleetContainerType. baseline_or_zero is DELETED -> the zero arm is unwritable; the only sink for an unmeasured baseline is FleetHostPlanUnsound at the gate. Test: single-source the fixture baseline bytes (runner_idle_bytes/session_idle_bytes + fixture_baselines) so the arithmetic witnesses carry no zero-fallback either. witness_baseline_unmeasured_unsound already proves unmeasured -> Unsound. All three suites green by execution: fleet_model_holds, runner_placement_holds, ci_budget_tree_holds. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
Took the non-blocking §5 note and dissolved it by construction ( You're right that Tests single-source the fixture baseline bytes so no zero-fallback shape survives there either; — sent from cool-boar-883 |
…dget model Consume #5663's conserving fleet_host_budget.runner_slice_cap as the single authority for the GHA runner-slot count, dissolving the §3 fork where the runner slice had two homes (ci_runner_placement.host_runner_slice = host-overhead- session_slice vs fleet_host_budget.runner_slice_cap = host-overhead-baselines- sccache_build_pool-headroom). - CPU-core term unified with spawn_width: new std.realization_width.cpu_cores_available (nproc - margin) is the ONE CPU-core authority. ctrl jobserver cpu_bound now reads it (token count byte-identical), fleet_host_budget exposes effective_runner_cpu_cap from it, and the runner count = int_min(memory_fit, cpu_cores_available) -- the spawn_width min-over-cores shape, minus the >=1 floor (a runner count of 0 is valid -> fail closed). - enforce flag (§5 live-enforcement gate): RunnerSlotEnforcement committed Unenforced because the runner-slice MemoryMax drop-in is inert (effective MemoryMax=INFINITY); a derived count would assume a cap the host does not enforce. Model-sound but live-unenforced still fails closed. - fail-closed fallback: budget-model Unsound OR enforcement Unenforced -> PlanUnsound; no silent legacy-slice fallback (kills the old conservative-fallback fail-open). - sccache named reservation: budget child build_pool -> sccache_build_pool. - consumable per-host emit: runner-deploy lines carry runner_count + per_slot_memory_max_bytes + build_tokens, one line per host, or the typed Unsound reason gracefully (no partial line). Committed manifest correctly emits UNSOUND (preconditions left as-is per §5 guardrail). - operating curve reframed to SESSION-side coverage only (runner count is now independent of the session operating point). Witnessed by execution (claim_batch) -- dual direction: (a) live/committed -> Unsound manifest with typed reason, no host lines; (b) OomdEnforced+HeadroomSet+Enforced spliced test-locally -> real per-host count+cap+tokens. fleet_model_holds, runner_placement_holds, realization_width_witnesses, ci_budget_tree_holds all green. ci_budget_tree.runner_pool_bytes_at left as a named follow-up (separate consumer). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…required data name extdeps/ctrl/jobserver.dag declared its anchor as `ctrl_jobserver_authority`, but the extdeps_external_authority_gate projector (read_external_authority_anchor_from_items) matches the data def by the EXACT name `extdeps_external_authority_anchor`. So jobserver projected as Absent -> a "missing:extdeps.ctrl.jobserver" violation, turning extdeps_external_authority_live_clean_tree_holds() false on main (landed via #5663/#5670). That is the batch-2 failure my PR inherited through the merge (corpus_live_clean_tree_holds / corpus_live_anchored_modules_clean_holds + extdeps_external_authority_gate_passes all RED). Rename the data def to the required name (no other ref to ctrl_jobserver_authority exists in dsl/ or src/v2/). Verified: both authority witnesses flip GREEN, my oomd witness stays green. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
dsl/extdeps/ctrl/jobserver.dag (landed via #5663) named its external-authority anchor `ctrl_jobserver_authority`, but the gate projector (read_external_authority_anchor_from_items) matches the data def by the EXACT name `extdeps_external_authority_anchor`. So jobserver projected as Absent -> missing:extdeps.ctrl.jobserver -> corpus_live_clean_tree_holds / extdeps_external_authority_gate_passes RED in batch-2 for EVERY PR. 1-line rename (no references to the old name in dsl/ or src/v2/); both authority witnesses flip GREEN (verified by execution). Same fix as valiant-pike #5677 (05b75fe); whichever lands first carries it, the other is a no-op on rebase. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
extdeps.ctrl.jobserver (from #5663) declared its external-authority anchor as `ctrl_jobserver_authority`, but the host-fed clean-tree scanner (extdeps_shape_transport_policy_project::read_external_authority_anchor_from_items) requires the exact name `extdeps_external_authority_anchor` — so the module read as anchor-Absent and corpus_live_clean_tree_holds / extdeps_external_authority_gate have been RED on main since #5663, masked by the self-hosted runner CI backlog (main runs never completed). Surfaced on this PR's floor run. One-line rename to the convention every other extdeps module follows; anchor var was unreferenced. corpus_live_clean_tree_holds + corpus_live_anchored_modules_clean now PASS. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…(verify-effective, fail-closed) (#5687) * WIP: CI-humming MANAGER (ROADMAP §4): own the CI-humming plan as single autho * WIP: CI-humming MANAGER (ROADMAP §4): own the CI-humming plan as single autho * Fix main-red extdeps_external_authority_gate: jobserver anchor name dsl/extdeps/ctrl/jobserver.dag (landed via #5663) named its external-authority anchor `ctrl_jobserver_authority`, but the gate projector (read_external_authority_anchor_from_items) matches the data def by the EXACT name `extdeps_external_authority_anchor`. So jobserver projected as Absent -> missing:extdeps.ctrl.jobserver -> corpus_live_clean_tree_holds / extdeps_external_authority_gate_passes RED in batch-2 for EVERY PR. 1-line rename (no references to the old name in dsl/ or src/v2/); both authority witnesses flip GREEN (verified by execution). Same fix as valiant-pike #5677 (05b75fe); whichever lands first carries it, the other is a no-op on rebase. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Brian Searls <briansrls@gunb.ai> Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…hor in extdeps.ctrl.jobserver extdeps_external_authority_live_clean_tree_holds() scans for a declaration named specifically `extdeps_external_authority_anchor`; `ctrl_jobserver_authority` was invisible to it, causing the corpus clean-tree test to fail. Bug was introduced in #5663 (on main); CI on main was stalled (queued) so it was not caught there. Verified green locally before push. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…ty anchor name #5663 added dsl/extdeps/ctrl/jobserver.dag with its ExternalAuthority anchor declared as `ctrl_jobserver_authority` instead of the single-authority canonical name `extdeps_external_authority_anchor` that all 189 other extdeps modules use and that read_external_authority_anchor_from_items() keys on. The lens therefore projected the anchor as Absent → live_anchored_modules_clean RED fleet-wide (a §3 nicknaming of the anchor decl). Rename to the canonical name; no other references. Verified by execution: corpus_live_anchored_modules_clean_holds, corpus_live_clean_tree_holds, and extdeps_external_authority_gate_passes all flip false→true with this one-line rename. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…nical decl name dsl/extdeps/ctrl/jobserver.dag declared its ExternalAuthority anchor as `ctrl_jobserver_authority` (from #5663). The extdeps external-authority floor gate (run_extdeps_external_authority_ci_gate, in ci_spec/ci_floor_plan) projects the anchor ONLY from a data decl named exactly `extdeps_external_authority_anchor` (the §3 single-authority convention all 189 other extdeps modules follow). The bespoke name made the projector read the module as anchor-Absent -> live-corpus clean-tree witness false -> ci floor red FLEET-WIDE on every PR (inherited by #5678 via its main-merge). Rename to the canonical decl name (zero other references). Gate goes ExitFailure -> ExitSuccess by execution; v2 corpus_live_clean_tree_holds false -> true. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…osed fallback, CPU-core term unified with spawn_width, sccache named reservation, emit consumable per-host count (#5674) * WIP: Wire runner-slot count to derived budget model: enforce flag, fail-close * WIP: Wire runner-slot count to derived budget model: enforce flag, fail-close * STAGE-2 PR-2: wire runner-slot count to the derived fleet-resource budget model Consume #5663's conserving fleet_host_budget.runner_slice_cap as the single authority for the GHA runner-slot count, dissolving the §3 fork where the runner slice had two homes (ci_runner_placement.host_runner_slice = host-overhead- session_slice vs fleet_host_budget.runner_slice_cap = host-overhead-baselines- sccache_build_pool-headroom). - CPU-core term unified with spawn_width: new std.realization_width.cpu_cores_available (nproc - margin) is the ONE CPU-core authority. ctrl jobserver cpu_bound now reads it (token count byte-identical), fleet_host_budget exposes effective_runner_cpu_cap from it, and the runner count = int_min(memory_fit, cpu_cores_available) -- the spawn_width min-over-cores shape, minus the >=1 floor (a runner count of 0 is valid -> fail closed). - enforce flag (§5 live-enforcement gate): RunnerSlotEnforcement committed Unenforced because the runner-slice MemoryMax drop-in is inert (effective MemoryMax=INFINITY); a derived count would assume a cap the host does not enforce. Model-sound but live-unenforced still fails closed. - fail-closed fallback: budget-model Unsound OR enforcement Unenforced -> PlanUnsound; no silent legacy-slice fallback (kills the old conservative-fallback fail-open). - sccache named reservation: budget child build_pool -> sccache_build_pool. - consumable per-host emit: runner-deploy lines carry runner_count + per_slot_memory_max_bytes + build_tokens, one line per host, or the typed Unsound reason gracefully (no partial line). Committed manifest correctly emits UNSOUND (preconditions left as-is per §5 guardrail). - operating curve reframed to SESSION-side coverage only (runner count is now independent of the session operating point). Witnessed by execution (claim_batch) -- dual direction: (a) live/committed -> Unsound manifest with typed reason, no host lines; (b) OomdEnforced+HeadroomSet+Enforced spliced test-locally -> real per-host count+cap+tokens. fleet_model_holds, runner_placement_holds, realization_width_witnesses, ci_budget_tree_holds all green. ci_budget_tree.runner_pool_bytes_at left as a named follow-up (separate consumer). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * T0: fix runner-slice double-subtract — runner_slice = host−overhead−session_worstcase−headroom; count = min(mem, build_tokens, cpu) (#5680) * tesgen analysis (#5664) * WIP: tesgen analysis * WIP: tesgen analysis * Wiring-liveness oracle + compile-time lens: plan carrier + roadmap §4 (carrier-modeled) --------- Co-authored-by: Brian Searls <briansrls@gunb.ai> * Slice C: Host metrics extdeps shapes (#5636) * WIP: Slice C: Host metrics extdeps shapes * Slice C: Host metrics extdeps shapes (§3 single-authority shape modeling) Model host metrics data structures in extdeps/os following DESIGN.md §3 de-fusion (shape/transport/policy separation): - proc_meminfo.dag: /proc/meminfo output structure (ProcMeminfo type with memory metrics fields, MemoryMetric for individual key-value pairs) - systemd.dag: systemctl is-active output structure (SystemdUnitActiveState coproduct, SystemdUnitStatus record with wire contract for snake_case encoding) - free.dag: free -b output structure (MemoryStats and SwapStats records in FreeOutput container) All three modules anchor to external authorities (man7.org) per extdeps convention. Test witnesses prove shape construction and invariant checking via executable Bool assertions (mem_available <= mem_total, etc). Each module models shape only; transport (how to fetch) and policy (when/where to call) remain absent, per single-authority principle. Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com> * Fix: Add NonEmptyStr casting in witness tests (as NonEmptyStr for name fields) * WIP: Slice C: Host metrics extdeps shapes * Fix: resolve unit type violations in host metrics extdeps shapes Replace bare Int fields with proper Measure types in host metrics modules: - proc_meminfo.dag: all memory fields now use Kibibyte (Measure<Memory, Kibi, Nat>) - free.dag: all memory/swap fields now use ByteSize (Measure<Memory, One, Nat>) - Import Memory and Kibi variants from std.measure following §3 single-authority principle - Update test witnesses to cast numeric literals to Measure types - Rename proc_meminfo.dag field value_kibibytes → value for consistency with Kibibyte type Addresses blocking review: unit type violations violate §3 single-authority principle. Establishes Measure as single authority for all physical quantity modeling per std.measure.dag. Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com> * FIX: systemd.dag wire contract with execution + inert carrier roster * Fix fmt: normalize roster comment alignment Cargo fmt --all normalized spacing on SecretValue roster entry. Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com> * WIP: Slice C: Host metrics extdeps shapes * Address PR feedback: consolidate Kibibyte alias, remove trivial assertions, mark systemd parallel-representation 1. Move Kibibyte alias from proc_meminfo.dag to std/measure.dag (canonical location per §3 single authority) 2. Update proc_meminfo.dag and witness test imports to consume Kibibyte from std.measure 3. Remove trivial >= 0 assertions on Nat-carried ByteSize values in free witness test (non-discriminating) 4. Add dissolve-on markers to systemd parse/label functions pending contract-driven derivation (§3 parallel-representation scaffold) Addresses: claude/claude-opus-4-7 REQUEST_CHANGES feedback on #5636 Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com> * WIP: Slice C: Host metrics extdeps shapes * FIX: Add missing List import to systemd.dag systemd_parse_label_derivation_debt data declaration uses List<NonEmptyStr> but the file lacked the corresponding std.list import. Adding it resolves the compilation error. Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com> * FIX: Remove stale inert carrier roster entries Remove 5 entries that now have external consumers: - Kibibyte (imported by witness tests) - MemoryMetric (imported by witness tests) - MemoryStats (imported by witness tests) - SwapStats (imported by witness tests) - SystemdUnitActiveState (imported by witness tests) Keep FreeOutput, ProcMeminfo, SystemdUnitStatus which still meet inert criteria. Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com> * Revert "FIX: Remove stale inert carrier roster entries" This reverts commit 8c06981. * WIP: Slice C: Host metrics extdeps shapes * FIX: Correct witness test syntax for .dag language Three test files had unsupported syntax: 1. os_systemd_witness_test.dag: Bool literals must be lowercase (true/false, not True/False). Changed lines 16, 17, 23, 24 to use correct .dag syntax. 2. os_proc_meminfo_witness_test.dag: Cannot cast Int to Kibibyte with 'as' operator. Changed all Kibibyte casts to record literal syntax: Kibibyte { count: N }. 3. os_free_witness_test.dag: Cannot cast Int to ByteSize with 'as' operator. Changed all ByteSize casts to byte_size(count: N) constructor calls. Added byte_size import to std.measure imports. Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com> * Trigger CI run * Retrigger CI (previous run stuck in queue) * FIX: Remove 5 stale inert carrier roster entries Removed entries that gained consumers when host metrics types (Kibibyte, MemoryMetric, MemoryStats, SwapStats, SystemdUnitActiveState) were integrated into extdeps modules: - Kibibyte: moved to std/measure.dag, now imported by proc_meminfo.dag - MemoryMetric, MemoryStats, SwapStats: now consumed by proc_meminfo.dag / free.dag - SystemdUnitActiveState: now consumed by systemd.dag Remaining roster: 11 entries (AccessPolicy, CargoDependency, CargoPackage, FilePermissions, FloorWitnessRow, FreeOutput, GitCliReportedVersion, ProcMeminfo, ReactHookSite, SecretValue, SystemdUnitStatus). * WIP: Slice C: Host metrics extdeps shapes * Revert "WIP: Slice C: Host metrics extdeps shapes" This reverts commit 6bc985a. * Retrigger CI --------- Co-authored-by: Brian Searls <briansearls1@gmail.com> Co-authored-by: Claude Haiku 4.5 <noreply@anthropic.com> * Slice B: Docker container stats extdeps shapes (#5635) * WIP: Slice B: Docker container stats extdeps shapes * Fix: correct imports for Nat type in docker shapes Move Nat import to std.nat module where it is defined. Remove unused BlkioStats from witness test imports. Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com> * WIP: Slice B: Docker container stats extdeps shapes * Fix: Docker shapes de-fuse, duration carriers, wire contract consumption Address four review findings from claude/opus-4-7 and bold-ant-53: 1. **Duration semantics** — CPU times require std.measure carriers, not bare Nat. Added Nanosecond = Measure<Time, Nano, Nat> and Microsecond = Measure<Time, Micro, Nat> to std.measure.dag. Updated container_stats.dag and container_inspect.dag to type: - cpu_usage fields (total, kernel, user, system) as Nanosecond - cpu_period and cpu_quota as Microsecond 2. **Single-authority consolidation** — Extracted docker_default_endpoint, docker_wire_contract, docker_external_authority_anchor to new extdeps/docker/endpoint.dag. Both container_stats.dag and container_inspect.dag now import from endpoint. 3. **Networks fidelity** — Changed from hardcoded eth0 field to Networks.interfaces list of NetworkInterface (name, stats) to match Docker API's arbitrary interface names. 4. **Wire contract consumption** — Added parse_container_state and container_state_wire_label functions to decode/encode ContainerState. Added 13 discriminating test functions: parsing all variants, case-sensitivity check, invalid input rejection, roundtrip validation. Compilation clean on docker-specific code (3 pre-existing errors in unrelated doc_reachability_witness_test.dag). Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com> * Refine: Remove inert docker_wire_contract, add memory_stats working-set gap marker 1. **Remove inert orphan** — docker_wire_contract: VariantEncoding in endpoint.dag was imported but never used. Wire contract for ContainerState is consumed via parse_container_state/container_state_wire_label functions, not via a VariantEncoding data row. Removed from endpoint.dag and dropped unused VariantEncoding imports from container_stats.dag. 2. **Add working-set gap marker** — Honest ratchet documenting known partial coverage: MemoryStats.usage includes page cache (inactive_file), true working-set = usage - stats.inactive_file from Docker stats sub-map. Marks dissolution trigger B2 (models stats sub-map with inactive_file and policy uses working_set not raw usage). Compilation clean. Ready for sign-off. Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com> * WIP: Slice B: Docker container stats extdeps shapes * Add tracked-debt markers for three dissolve-on patterns 1. **variant↔string fork (container_state)** — parse_container_state and container_state_wire_label are hand-forked forward/backward arms of one mapping (§4 violation: one grammar, two procedures). Single rowset with bidirectional derivation dissolves the fork and eliminates silent divergence risk. Trigger: B3 models ContainerState wire facts as single authority. 2. **BlkioValue.value unit ambiguity** — Same Nat field carries parent-dependent units (bytes, time, count) invisible to type system (§5 violation). Docker wire format constraint. Remedy: typed per-list accessors returning ByteSize| Nanosecond|Nat or parent-tagged union. Trigger: B3 models BlkioValue with discriminated unit type. 3. **docker_default_endpoint String vs Uri** — Typed as bare String but module imports Uri; anemic-leaf (§2/§5). Same file uses Uri for authority anchor. Ground endpoint as Uri variant carrying socket/http/https/fd schemes. Trigger: B3 grounds docker endpoint with Uri type. All three tracked per §6 framework: honest ratchet markers with named dissolution triggers and layer they belong to (B3 modeling layer). Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com> * WIP: Slice B: Docker container stats extdeps shapes * Fix: Add dissolve-on markers for anemic-leaf and error-response scaffolds Address REQUEST_CHANGES review findings by adding honest ratchet markers for remaining scaffolds per §6 pattern: 1. **HostConfig/ContainerConfig anemic leaves** (container_inspect.dag:76-78) - cap_add/cap_drop, exposed_ports, port_bindings, volumes, volumes_from, device_requests (HostConfig); env, cmd, entrypoint, labels, volumes, exposed_ports (ContainerConfig) are structured concepts flattened to bare List<String>? (§2 violation: anemic leaves) - Trigger B3: ground each as typed coproduct (PortBinding record, EnvVar record) or decomposed with named axes 2. **NetworkSettings bare-string fields** (container_inspect.dag:104-108) - gateway, ip_address, mac_address should be typed network carriers (IpAddress, MacAddress) not bare String? - Lower stakes since std/network primitives don't exist yet, but marks structured-validation gap (§5 fail-closed) - Trigger B3: introduces network address carriers in std/ or extdeps 3. **Error responses as opaque strings** (both files) - 404/500 => String collapses two distinct error shapes, violates §5 - Docker returns structured JSON error objects with reason/message - Trigger B3: model as ErrorDetail coproduct (NotFound | ServerError variants with typed failure details) All markers follow §6 self-flagged scaffold pattern with closure/, root cause, and B3 dissolution trigger. Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com> * Fix: Ground ContainerStateDetail.error with ErrorMessage type ContainerStateDetail.error was typed as bare String?, violating bare-primitive-nicknames-concept modeling coherence. Error messages are a semantic concept that must be grounded in a type. Added type ErrorMessage = String to carry the semantic meaning, replacing bare String usage. This grounds the concept per §3 (single authority) and §2 (minimize anemic leaves). Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com> * Fix: Remove unused import of VariantEncoding/StringVariant/VariantNaming/AsAuthored Dead remnants from the old wire-contract approach. These imports are not used anywhere in the file and violate §3 (minimize redundancy). Removing them eliminates potential compile errors and cleans up the module's actual dependencies. Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com> * Address review findings: add cpu_percent ratio tracking + fix Optional matcher consistency - Add dissolve_on_cpu_percent_ratio_carrier to container_stats.dag documenting bare Float? unit modeling gap (§5); triggers B3 grounding with Ratio/PercentagePoint type alias - Fix container_inspect.dag optional accessors to use consistent Present/Absent pattern instead of null matching (all three: memory_limit, cpu_quota, cpu_period) Both findings valid from claude/claude-opus-4-7 review #5635. Dissolve-on marker ensures tracking discipline; pattern consistency prevents silent wildcard-fallthrough risk. Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com> * Add dissolve markers for ContainerStateDetail redundancy + container_state_is_running symmetry - Add dissolve_on_container_state_detail_redundant_bools documenting parallel status coproduct + redundant bool fields allowing illegal states; marks for B3 resolution via bool predicates derived from status only - Add dissolve_on_container_state_predicate_family for symmetry with parse/wire-label pair (both marker-tracked); documents handrolled predicate helper discipline gap and marks for B3 consolidation Both findings from claude/claude-opus-4-7 review #5635 (non-blocking nits, but valuable tracking discipline). Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com> * Add dissolve marker for HostConfig.memory_swap -1 unlimited convention loss HostConfig.memory_swap: ByteSize? loses Docker wire convention where -1 encodes 'unlimited'; Nat-backed ByteSize cannot represent -1, causing fidelity gap at extdeps boundary. Added dissolve_on_memory_swap_unlimited_convention marker documenting the gap and B3 trigger (coproduct variant or tagged union to preserve wire semantics). Finding from claude/claude-opus-4-7 review #5635 (APPROVE, non-blocking). Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com> * Fix: Remove unescaped braces in dissolve_on_hostconfig_containerconfig_anemic_leaves string Unescaped { and } in the example text caused .dag parser to treat them as template interpolation markers, failing on colon in field names. Rephrase example without braces. Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com> * WIP: Slice B: Docker container stats extdeps shapes * Fix: Test all container state roundtrips instead of unused list binding Remove unused `states` binding and expand roundtrip test to verify all 5 ContainerState variants (Running, Paused, Exited, Dead, Restarting) roundtrip correctly through parse/wire-label functions per review feedback. Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com> * WIP: Slice B: Docker container stats extdeps shapes * Fix REQUEST_CHANGES architectural violations per parent guidance Three fixes applied per Section-8 guidance: Fix 1 — Remove container_state_is_running predicate (§2/§3) - Delete function and dissolve_on marker (lines 163-168) - Callers now inline: match state { Running => ... _ => ... } - Update test file imports and remove predicate-only tests - Keep predicate-using test (sample_inspect_has_running_state) via direct equality Fix 2 — Ground parse/wire-label fork via CoproductWireContract (§4) - Add container_state_wire_contract data item - Import CoproductWireContract, StringVariant, SnakeCase from std.serialization - Rename dissolve_on_variant_wire_fork_container_state to structural_coverage_gap_container_state_codec_hand_rolled - Update marker text to reference contract and remove B3 reference Fix 3 — Rewrite all B3 references with concrete triggers - container_inspect.dag (5 markers): wire-deserialization, Unlimited variant, typed carriers, network addresses, typed errors - container_stats.dag (3 markers): Ratio/PercentagePoint, typed errors, typed/tagged union Verification: gunbc compile --source-root dsl → 0 docker diagnostics Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com> --------- Co-authored-by: Brian Searls <briansrls@gunb.ai> Co-authored-by: Claude Haiku 4.5 <noreply@anthropic.com> Co-authored-by: Brian Searls <11205878+briansrls@users.noreply.github.com> * BMC onboarding: complete srv3 lifecycle orchestration (.dag) + GCP store §3 fix (#5661) * WIP: BMC onboarding lifecycle for new Altra server (BMC 192.168.1.192): model * BMC onboarding lifecycle: 4-phase model + Redfish write seam + read-only validation Models the onboarding of the operator's new Altra server (BMC 192.168.1.192) from factory-default login through cred-rotate, OS-install, and fabric-join as a .dag lifecycle over Redfish, building on the existing extdeps/bmc telemetry seam. - extdeps/bmc/types.dag: real DMTF Redfish write-side enums (BootSourceOverride target/enabled, ResetType, account role) with faithful wire-token projections. - extdeps/bmc/http.dag: interface shapes for the transition-effecting Redfish ops (GetServiceRoot read; SetAccountPassword, SetBootSourceOverride, ResetSystem writes) over the curl/netrc shell transport handler. Secrets ride a runtime request_body_file, never argv or the repo. - gunbc/bmc_onboarding.dag (workflow/policy): BmcOnboardingPhase + derived successor/completion + the new-server BmcOnboardingPlan (host .192, factory login, Stored rotated credential, Ubuntu Noble target, Pxe boot override). - gunbc/tools/bmc_onboard.dag: runnable READ-ONLY first-contact + inventory validation; write transitions are modeled but gated (not driven here). - test/claim witness: linear-DAG phase ordering + plan grounding, green by execution. Grounded against the live BMC at 192.168.1.192: factory creds (root/0penBmc) and the read path are confirmed; VirtualMedia is absent on this OpenBMC firmware, so OS-install is modeled via boot-source-override (Pxe) + ComputerSystem.Reset. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * review #5563: drop redundant phase_order roster (§3 single authority) bmc_onboarding_next_phase is now the sole authority for the linear successor relation; the standalone bmc_onboarding_phase_order list duplicated it. The witness already proves the full 4-phase ordering + completeness via the per-phase next_tag chain (FactoryDefault->1->2->3, FabricJoined->terminal), so the roster's phase_count check was subsumed. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * review #5563: rename bmc_onboard -> bmc_onboard_validate (honest tool name, §5) The tool only performs the read-only FactoryDefault validation (GetServiceRoot + GetSystem); it does not drive cred-rotate/OS-install/fabric-join. Naming it bmc_onboard_validate stops the name from advertising the full lifecycle the BmcOnboardingPhase model describes, and frees the bmc_onboard name for the future (gated) full-lifecycle driver. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * WIP: BMC onboarding lifecycle for new Altra server (BMC 192.168.1.192): model * review #5563: delete bmc_onboarding_is_complete (single-caller predicate) The predicate had one caller (the witness) and the witness's next_tag chain already proves completion (FabricJoined -> -1 = terminal; others -> 1/2/3). Deleted the helper and its now-redundant witness lines; next_phase remains the sole authority for the linear successor relation. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * WIP: BMC onboarding lifecycle for new Altra server (BMC 192.168.1.192): model * WIP: BMC onboarding lifecycle for new Altra server (BMC 192.168.1.192): model * bmc_onboard: rotate+reauth leg of the onboarding orchestration (compile-verified, live-gated) Assemble the credential-rotation leg of orchestration C over new_altra_onboarding_plan, now that Lane B (#5634) landed the Redfish auth-as-Secret seam on main: materialize the netrc + PATCH body via Filesystem.Write (executable file effect), SetAccountPassword (Redfish write), then reauth with the new credential to VERIFY the rotation took — fail-closed if rejected. The minted Secret is declassified to String exactly once, explicitly (the Secret type forbids accidental exposure). Verified by execution: gunbc compile --source-root dsl => 464 modules, 471 files, 0 diagnostics — the legs typecheck and compose. LIVE execution is operator-fenced (first destructive write); live-correctness of account_id/body shape is confirmed only by the gated run against .192, not this typecheck. Not a *_test.dag, so it does NOT auto-enroll as a floor witness (no false CI-coverage claim). §5 debt (named): the netrc + body files transiently hold the credential on disk at default umask with no post-run unlink; dissolution = mode-0600 file write + unlink leg. gen+store leg (entropy mint #5633 -> base64 -> GCP store) wires in once #5633 lands; os-install leg pends Lane E (#5638). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * bmc_onboard: complete srv3 onboarding orchestration (acquire→gen+store→rotate→reauth→os-install) Assemble the full lifecycle as one .dag workflow over new_altra_onboarding_plan + srv3_os_install_plan, now that all four lanes (entropy #5633, auth-Secret #5634, OS-install #5638) landed on main: acquire — GetServiceRoot + factory-login GetSystem (read; proven live earlier) gen — mint a credential from OS entropy (extdeps.entropy Urandom), FAIL-CLOSED on the Optional (never a fabricated/empty credential — dissolves the witness scaffold's empty-string arm per cool-lynx's dissolution trigger) store — base64 of the same octets -> GCP AddVersion (durability) under the plan's secret id; token via gcloud rotate+reauth — Filesystem.Write netrc + PATCH body, SetAccountPassword, reauth with the NEW credential to verify the rotation took (fail-closed) os-install — re-materialize netrc with the NEW credential (factory netrc is now stale), SetBootSourceOverride(Pxe,Once) + ResetSystem(ForceRestart) via the Lane-E wire fns to boot srv3 into the PXE/autoinstall path Legs chain on ProcessExit so any failure short-circuits. The minted Secret is declassified to String exactly once, explicitly (the type forbids accidental leak). Verified by execution: gunbc compile --source-root dsl => 480 modules, 488 files, 0 diagnostics. The pure wire-shape builders (netrc line, Redfish PATCH/POST JSON bodies, GCP secret name) have by-execution witnesses — all 5 green via --claim-run. The live Redfish/GCP/entropy legs are OPERATOR-FENCED (destructive); their live correctness is confirmed only by the gated run against .192, not this typecheck. §5 debt (named): netrc/body files transiently hold the credential on disk at default umask with no unlink; dissolution = mode-0600 file write + unlink leg. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * WIP: BMC onboarding lifecycle for new Altra server (BMC 192.168.1.192): model * WIP: BMC onboarding lifecycle for new Altra server (BMC 192.168.1.192): model * review #5661: mark bmc_credential_bytes + JSON-concat scaffolds; add cred-only entry point Address review #32107: - bmc_credential_bytes: Int gets a 🟡 marker riding extdeps.entropy's entropy_count_bytes_unit_debt (same bytesize-argv-interpolation dissolution) — no longer an unmarked *_bytes-on-Int. - the concat-built Redfish PATCH/POST bodies get a 🟡 dissolve-on marker (safe for the current base64url-credential + enum-wire call sites, which the body-shape witnesses pin; dissolution = a structured JSON-object encoder authority). Also adds bmc_assimilate_srv3_credential — a credential-only entry point (acquire -> gen -> store(read-back gated) -> rotate -> reauth, STOPPING before os-install) so the live BMC credential assimilation can run while no PXE/install server exists yet (running the full bmc_onboard_srv3 would reset srv3 into a dead PXE boot). Refactors the shared store+rotate into bmc_store_and_rotate (no duplication). Compile clean (488 files, 0 diagnostics); body-shape witnesses green. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * WIP: BMC onboarding lifecycle for new Altra server (BMC 192.168.1.192): model * WIP: BMC onboarding lifecycle for new Altra server (BMC 192.168.1.192): model * WIP: BMC onboarding lifecycle for new Altra server (BMC 192.168.1.192): model * WIP: BMC onboarding lifecycle for new Altra server (BMC 192.168.1.192): model * WIP: BMC onboarding lifecycle for new Altra server (BMC 192.168.1.192): model * fmt: collapse resolve_auth call site to one line (cargo fmt --check) The auth_input fix's call-site edit split the let-binding across two lines; rustfmt wants it on one (fits in width). cargo fmt --all --check now clean — this was the rust_tests CI failure on 311ff38 (fmt gate), not a logic issue. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * WIP: BMC onboarding lifecycle for new Altra server (BMC 192.168.1.192): model * bmc_onboard: dissolve the entropy decode→encode identity round-trip (§2, review #32137) mint_credential_octets base64_decode'd Urandom.octets_b64 to List<UInt8>, then credential_from_octets base64_encode'd it straight back — base64_encode∘base64_decode is identity, so the octets intermediate (and the Optional failure mode that could only trip on a base64_decode bug, never on real Urandom output) bought nothing. Collapse to one fn: mint_bmc_credential() = Urandom.ReadBytes(count).octets_b64 as Secret. The credential IS the base64 entropy string directly — same string set on the BMC, stored as the GCP payload, and compared in the read-back gate (identity preserved; the BMC password is byte-for-byte what it was). Drops the std.encoding + std.integer{UInt8} imports and the unused ExitFailure. Fail-closed now lives at the Urandom service call (nonzero exit raises). Compile 488/0, body witnesses green. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Brian Searls <briansearls1@gmail.com> Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * WIP: Wire runner-slot count to derived budget model: enforce flag, fail-close * WIP: Wire runner-slot count to derived budget model: enforce flag, fail-close * Fix main-red regression: lens-test v2_source_roots missing dsl root after 5647 disposition import, plus regen 2 github pipeline snapshots after 5644 restructure (#5672) * WIP: Fix main-red regression: lens-test v2_source_roots missing dsl root afte * Resolve merge conflicts: take main's v2_layer_roots() and typed-field assertions #5668 landed equivalent fixes using the single-authority helper; resolve all four conflicted files to main's version. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> --------- Co-authored-by: Brian Searls <briansearls1@gmail.com> Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com> * ROADMAP §1: CI-humming operations plan (un-throttle runner slots from the modeled budget) (#5682) Single CI-operations authority for the ▸ NOW host-operation-on-.dag milestone: runner-slot starvation root cause (build-pool/runner-slice double-count derives runner_slice_cap ≈ 0), the 3-axis budget (smart-pike #5674), verified-effective caps, the std reconcile carrier, SessionSliceEnforcement (the safe-apply gate), and oomd demoted to backstop per the §5 construction-over-precondition insight. Linked from ROADMAP §1 (orphan-doc lens). Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com> --------- Co-authored-by: gunbai-bot[bot] <289086189+gunbai-bot[bot]@users.noreply.github.com> Co-authored-by: Brian Searls <briansearls1@gmail.com> Co-authored-by: Claude Haiku 4.5 <noreply@anthropic.com> * Resolve merge: keep counted-once runner_slice_cap (4-arg, no build_pool subtract) + import RunnerSliceCapEffectiveness from ci_floor_measurement single-authority home (drop #5687 5-arg double-subtract form per bright-stag §2/§3 2026-06-23 ruling) Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Brian Searls <briansearls1@gmail.com> Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Co-authored-by: gunbai-bot[bot] <289086189+gunbai-bot[bot]@users.noreply.github.com>
…the fleet model (#5678) * WIP: .dag-driven PXE/autoinstall provisioning lane (the assimilate-controller * PXE/autoinstall slice 1: emit srv3 Ubuntu autoinstall user-data * WIP: .dag-driven PXE/autoinstall provisioning lane (the assimilate-controller * Fix main-red floor: jobserver external-authority anchor must use canonical decl name dsl/extdeps/ctrl/jobserver.dag declared its ExternalAuthority anchor as `ctrl_jobserver_authority` (from #5663). The extdeps external-authority floor gate (run_extdeps_external_authority_ci_gate, in ci_spec/ci_floor_plan) projects the anchor ONLY from a data decl named exactly `extdeps_external_authority_anchor` (the §3 single-authority convention all 189 other extdeps modules follow). The bespoke name made the projector read the module as anchor-Absent -> live-corpus clean-tree witness false -> ci floor red FLEET-WIDE on every PR (inherited by #5678 via its main-merge). Rename to the canonical decl name (zero other references). Gate goes ExitFailure -> ExitSuccess by execution; v2 corpus_live_clean_tree_holds false -> true. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Brian Searls <briansrls@gunb.ai> Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
… auth step (apply-ready) (#5676) * WIP: GCP token automation for BMC assimilation: scoped service account + Work * Keyless GCP token for BMC assimilation: WIF-federated SA + GHA auth step (apply-ready) Make shell.GCloud.AuthPrintAccessToken() resolve on the self-hosted GitHub Actions runner with no pasted token. The .dag effect is unchanged; this is the host/CI config behind it plus the apply-ready GCP infra the operator runs. - extdeps/github/actions.dag: WorkflowPermissions.id_token + google_auth_action - workflow_yaml_project.dag: emit id-token permission - extdeps/cloud/gcp/iam.dag: ground roles/secretmanager.secretVersionAdder - gunbc/assimilate/bmc_token_federation.dag: identity facts, 2 resource-level secret bindings (single authority), WIF provider/principalSet, keyless auth step + smoke workflow emit - docs/runbooks/bmc-assimilator-wif-setup.md: exact apply-ready gcloud/WIF/GHA artifacts + scoped-key local fallback + least-privilege verification Least-privilege (one secret, two secretmanager roles, no project-wide) and keyless emission proven by execution in dsl/test/claim/bmc_token_federation_witness_test.dag (6 witnesses, all PASS). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * WIP: GCP token automation for BMC assimilation: scoped service account + Work * Ground §3 duplication in bmc_token_federation: derive bindings from constants + records Addresses review #5676 (claude-opus-4-7) single-authority findings: - bindings derive member (from sa_email), secret, project from the data constants via bmc_secret_binding() — no re-typed literals - role names sourced from iam.dag (role_secretmanager_secret_accessor / _version_adder), which common_roles now references too — one authority, and the new secretVersionAdder row gains a consumer - WIF resource-path + principalSet projection moved to reusable helpers in extdeps/cloud/gcp/gcp.dag (wif_provider_resource / wif_principal_set_for_repo), derived from the WifProvider/WifPool records; removed the ad-hoc concat ladders and duplicate scalar id/issuer data rows 7 witnesses still PASS; allowlist discriminating-red unchanged. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * WIP: GCP token automation for BMC assimilation: scoped service account + Work * Fix pre-existing main-red: rename jobserver anchor to required name extdeps.ctrl.jobserver (from #5663) declared its external-authority anchor as `ctrl_jobserver_authority`, but the host-fed clean-tree scanner (extdeps_shape_transport_policy_project::read_external_authority_anchor_from_items) requires the exact name `extdeps_external_authority_anchor` — so the module read as anchor-Absent and corpus_live_clean_tree_holds / extdeps_external_authority_gate have been RED on main since #5663, masked by the self-hosted runner CI backlog (main runs never completed). Surfaced on this PR's floor run. One-line rename to the convention every other extdeps module follows; anchor var was unreferenced. corpus_live_clean_tree_holds + corpus_live_anchored_modules_clean now PASS. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Brian Searls <briansrls@gunb.ai> Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…leet model (#5692) * WIP: .dag-driven PXE/autoinstall provisioning lane (the assimilate-controller * PXE/autoinstall slice 1: emit srv3 Ubuntu autoinstall user-data * WIP: .dag-driven PXE/autoinstall provisioning lane (the assimilate-controller * Fix main-red floor: jobserver external-authority anchor must use canonical decl name dsl/extdeps/ctrl/jobserver.dag declared its ExternalAuthority anchor as `ctrl_jobserver_authority` (from #5663). The extdeps external-authority floor gate (run_extdeps_external_authority_ci_gate, in ci_spec/ci_floor_plan) projects the anchor ONLY from a data decl named exactly `extdeps_external_authority_anchor` (the §3 single-authority convention all 189 other extdeps modules follow). The bespoke name made the projector read the module as anchor-Absent -> live-corpus clean-tree witness false -> ci floor red FLEET-WIDE on every PR (inherited by #5678 via its main-merge). Rename to the canonical decl name (zero other references). Gate goes ExitFailure -> ExitSuccess by execution; v2 corpus_live_clean_tree_holds false -> true. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * PXE/autoinstall slice 2a: emit srv3 proxyDHCP dnsmasq.conf from the fleet model Install-server config emit -- same Realization as ci.yml / autoinstall user-data (slice 1), new medium. PURE emit, no host effect. - extdeps.formats.dnsmasq: cited dnsmasq.conf authority (thekelleys.org.uk example), typed DnsmasqDirective model rendered via the shared std.layout fold (no per-format render engine). - extdeps.provisioning.dhcp_client_arch: RFC4578/IANA option-93 processor-arch code table (BiosX86=0/UefiX86_64=7/UefiArm64=11/HttpBootX86_64=16/ HttpBootArm64=19), keyed off the unified extdeps.toolchain.types.Architecture (mapping, not a parallel boot-arch enum) x ClientNetworkBootMode. - extdeps.provisioning.network_boot: ClientNetworkBootMode + DhcpBootDirection + UEFI network bootloader artifact (grubnetaa64/x64.efi), cited UEFI spec. - extdeps.uri.uri_wire: scheme+locator -> wire string (consumed by the emit). - gunbc.install_server_emit: project InstallServerSpec -> dnsmasq.conf directives. - ProxyDhcpDnsmasqArtifact { spec } registered like AutoinstallUserDataArtifact; committed provisioning/srv3/dnsmasq.conf, drift-gated identically. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * slice 2a review: network_address_of_cidr uses |> first, not fold-as-head Review finding (claude-opus-4-7, #5692): the fold(acc,seg => if acc=="" seg else acc) was an idiomatic head-of-list disguised as a fold. Use the builtin first Optional (Present/Absent), matching the http_path.dag / html.dag pattern; Absent falls back to the raw cidr. Emit byte-identical (drift gate ExitSuccess, dhcp-range=192.168.1.0,proxy unchanged), 3 emit witnesses still green. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Brian Searls <briansrls@gunb.ai> Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
#5679) * WIP: Wiring-liveness lens wave 1: dependence carrier + wired floor witness * Wiring-liveness lens wave 1: reachability kernel + wired floor witness Wiring-liveness = the cache-purity perturbation oracle read backwards (purity: same-in same-out; liveness: different-in different-out -- a declared input with no structural path to the output it feeds is a dead wire). Reuses std.dependency DependencyView/dependency_lens as the dependence carrier (no new dependence type minted). Distinct from unused_parameters: that asks referenced->=1x; this asks transitive-path- to-output (RED when an input is referenced only inside structure that itself never reaches the output). v2.lens.wiring_liveness: forward transitive reachability over the DependencyView graph; WiringRelation/WiringVerdict verdict carrier. Floor witnesses (src/v2/lens/wiring_liveness_test.dag), all POSITIVE test fns, green-by-execution + proven red-on-perturbation: - wiring_liveness_wired_input_reaches_output (RED if the subject wire is cut) - wiring_liveness_dead_input_is_unwired (RED if the lens goes lenient-always-Wired) - wiring_liveness_real_reflected_type_field_reachable (real-DATA kernel smoke over a resolve_type_node-reflected corpus type's live dependence graph -- the only real-corpus structure reflectable today) Honest boundary (in the construction_justification): this COMPILE-TIME wall covers only .dag-modeled / reflectable structure. The motivating GCP IAM auth_input bug lives in the Rust-seed resolve_auth realization, opaque to compile-time reflection = wave-2 opaque-realization witness. The corpus has NO fn/arrow/service-operation reflection (resolve_type_node + concept_decl_facts_live yield only TypeItem), so a corpus-wide scan of real fn params / service ops is also opaque today. WIDEN trigger: realization self-host + gunbc#5364 (.dag fn reflection). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * wiring-liveness: flatten Bool-isomorphic verdict + add reachability convergence early-exit Addresses #5679 review (claude-opus-4-7, non-blocking): - Drop WiringVerdict = Wired | Unwired + wiring_verdict_is_wired: a 2-variant coproduct isomorphic to Bool carrying nothing Bool doesn't (predicate dissolution / DESIGN section 2). wiring_relation_is_wired returns Bool directly. WiringRelation (3-field dependence bundle) stays -- not Bool-isomorphic. A richer verdict re-enters when the plan's declared-inert-vs-dead-wire 3rd state actually lands (model just-in-time). - wiring_reach_saturate now folds a WiringReachState { reached, stable } with a convergence early-exit (stop when the reached set stops growing), faithfully mirroring the affected_set closure fixpoint it was modeled on. Re-verified by execution (claim_batch): all 3 witnesses green; two-sided pin intact (lenient lens => dead-input RED; strict lens => wired RED). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * Fix main-red floor-skew: canonicalize ctrl/jobserver external-authority anchor name #5663 added dsl/extdeps/ctrl/jobserver.dag with its ExternalAuthority anchor declared as `ctrl_jobserver_authority` instead of the single-authority canonical name `extdeps_external_authority_anchor` that all 189 other extdeps modules use and that read_external_authority_anchor_from_items() keys on. The lens therefore projected the anchor as Absent → live_anchored_modules_clean RED fleet-wide (a §3 nicknaming of the anchor decl). Rename to the canonical name; no other references. Verified by execution: corpus_live_anchored_modules_clean_holds, corpus_live_clean_tree_holds, and extdeps_external_authority_gate_passes all flip false→true with this one-line rename. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Brian Searls <briansrls@gunb.ai> Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
… the post-wall data:String marker fleet — migrate each region (bytes_seam, anthropic closure rows, budget-tree leaves, #5605 consumed_input_closure rows, unit_must_run_staged_note) from prose data:String to typed Disposition fields (#5631) * WIP: Disposition carrier slice-2: ratchet disposition_redundancy lens over th * WIP: Disposition carrier slice-2: ratchet disposition_redundancy lens over th * Disposition carrier slice-2: extend Rust execution proof to all new regions Adds slice-2 region assertions to disposition_redundancy_lens_discriminates_by_execution: - region2 anthropic residual marks nonempty + fire on AnthropicToolDefinition - serde receipt all Terminal never fires (complementary green) - bytes/encoding markers nonempty + two Scaffolds fire on synthetic builtin_function_registry present - budget-tree markers nonempty + fire on job_peaks locator - rust_stage0_gates markers nonempty + fire on synthetic consumed_input convergence target Each region adds a nonempty probe (red-on-revert wiring check) plus a discriminating fire probe. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * WIP: Disposition carrier slice-2: ratchet disposition_redundancy lens over th * Disposition carrier slice-2: fix anthropic bind targets and update fire tests Items 2 and 3 in structural_coverage_gap_anthropic_messages_200_residual previously bound to existing types (AnthropicToolDefinition, AnthropicServerToolName), causing the lens to correctly fire RED when those names are in the present set — but they should bind to FUTURE carriers, not existing ones. Fixed: - Item 2: bind → MessagesToolUseBlock.NamedField{caller_payload} (field doesn't exist) - Item 3: bind → AnthropicServerToolUseSurface (type doesn't exist) Updated fire test to use AnthropicContainerResponse locator (item 1 bind, doesn't exist); renamed test fn to _fires_on_container_response. All 14 by-execution assertions green. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * WIP: Disposition carrier slice-2: ratchet disposition_redundancy lens over th * Drop stale region-2 anthropic test coverage superseded by #5644's CoverageClosureEntry migration The 4 anthropic.dag rows that slice-2 migrated to List<Disposition> (structural_coverage_gap_anthropic_messages_200_residual, rest_request_wire_serde_alignment_receipt, etc.) were superseded in the merge-commit by #5644 which gave them the richer List<CoverageClosureEntry> type. Remove the now-type-mismatched region-2 imports, data rows, and test fns from disposition_redundancy_test.dag, and the corresponding 3 Rust assertions from disposition_redundancy_lens_test.rs. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * Sync dsl-v2-defork-audit.md to .dag authority (drift gate fix) generated_artifact_drift_gate_passes failed: dsl-v2-defork-audit.md had 48 lines of hand-appended content beyond what its .dag authority generates. Regenerated via main_wet on dsl/tools/generated_artifact_gate.dag. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * Revert defork-audit .md deletion — restore §2A to origin/main exactly d240b33 incorrectly deleted 48 lines of real content (§2A: the 2026-06-23 Q2 census post-#5652) via main_wet. The drift gate red is an inherited main-red owned by silent-crab-350's forward fix; not ours to touch. Restoring docs/plans/dsl-v2-defork-audit.md to origin/main exactly. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * WIP: Disposition carrier slice-2: ratchet disposition_redundancy lens over th * fix: rename ctrl_jobserver_authority → extdeps_external_authority_anchor in extdeps.ctrl.jobserver extdeps_external_authority_live_clean_tree_holds() scans for a declaration named specifically `extdeps_external_authority_anchor`; `ctrl_jobserver_authority` was invisible to it, causing the corpus clean-tree test to fail. Bug was introduced in #5663 (on main); CI on main was stalled (queued) so it was not caught there. Verified green locally before push. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * WIP: Disposition carrier slice-2: ratchet disposition_redundancy lens over th --------- Co-authored-by: Brian Searls <briansearls1@gmail.com> Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
…tdeps/systemd unit-management interface plus oomd config surface, apt install-as-effect, and a gunbc install Realization that grounds OomdEnforced from a verify/show-effective read (#5677) * WIP: Model systemd-oomd as a dependency (pure .dag, no live execution): extde * WIP: Model systemd-oomd as a dependency (pure .dag, no live execution): extde * Model systemd-oomd as a dependency (pure .dag): reconcile carrier + systemd/oomd interface + apt install-effect + grounded OomdEnforced Shared std carrier (std/realization_reconcile.dag), first instance = oomd: - reconcile(apply_effect, show_read, grounding) -> Converged{evidence} | NotConverged{reason}. Substrate deviation from the pre-signed fn(R)->Grounding<E> param (v1 seed cannot type a fn-typed param returning a generic-applied enum); closest faithful form takes the grounding value and enforces the read-presence gate. Section-5 invariants kept: ReadAbsent => NotConverged (evidence impossible without an observed read); the verdict never depends on apply_effect (threaded as provenance only). extdeps systemd interface (consolidated under the existing extdeps.os.systemd home, reusing SystemdUnitActiveState from #5635 rather than minting a parallel enum): - extdeps/os/systemctl.dag: enable / start / set-property / daemon-reload / is-active / show-effective-property operation shapes + UnitFileState; unit is always a parameter. - extdeps/os/oomd.dag: oomd config surface (ManagedOOMMemoryPressure/Swap, pressure limit/duration, oomd.conf globals) + oomctl dump read; real names from oomd.conf(5) and systemd.resource-control(5). apt install-as-effect: - extdeps/apt.dag: Install operation (package is a parameter, no business literal) + systemd-oomd-defaults package, reusing the existing package-name concept. gunbc install Realization (sibling to os_install.dag), instance #1 of the carrier: - gunbc/oomd_install.dag: compose apt-install + runner-slice ManagedOOM drop-in + enable/start + a show-effective VERIFY that GROUNDS OomdEnforced. Pure .dag, no live execution: committed read is ReadAbsent, so the carrier derives OomdUnverified (fail-closed). OomdEnforced is derivable ONLY from a ReadObserved carrying an active unit AND effective ManagedOOMMemoryPressure=kill. Witness (claim_batch-discoverable), discriminating by execution: - managed read (active + kill) grounds OomdEnforced; unmanaged (auto), inactive, and absent reads stay OomdUnverified. Fail-open perturbation (auto also grounds) flips the witness RED, proving the grounding is real, not a constant. Does not touch committed gunbc_fleet_oomd_evidence (stays OomdUnverified until a real live verify runs through the carrier). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * WIP: Model systemd-oomd as a dependency (pure .dag, no live execution): extde * Fix main-red: name jobserver's external-authority anchor to the gate-required data name extdeps/ctrl/jobserver.dag declared its anchor as `ctrl_jobserver_authority`, but the extdeps_external_authority_gate projector (read_external_authority_anchor_from_items) matches the data def by the EXACT name `extdeps_external_authority_anchor`. So jobserver projected as Absent -> a "missing:extdeps.ctrl.jobserver" violation, turning extdeps_external_authority_live_clean_tree_holds() false on main (landed via #5663/#5670). That is the batch-2 failure my PR inherited through the merge (corpus_live_clean_tree_holds / corpus_live_anchored_modules_clean_holds + extdeps_external_authority_gate_passes all RED). Rename the data def to the required name (no other ref to ctrl_jobserver_authority exists in dsl/ or src/v2/). Verified: both authority witnesses flip GREEN, my oomd witness stays green. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * Fix tree-wide main-red: regenerate ROADMAP.md from authority (dedup merge-artifact CI-humming line) ROADMAP.md is a generated projection of gunbc.roadmap_authority (the GeneratedArtifactDriftGate enforces committed == expected_roadmap_md()). A textual git-merge of origin/main duplicated the '→ [CI humming]' line; the authority emits it once, so the committed file drifted and the floor drift gate returned Bool(false) (main has carried this red since the bad merge). Regenerated via main_wet on dsl/tools/generated_artifact_gate.dag; no hand-edit. Drift gate now green by execution. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * WIP: Model systemd-oomd as a dependency (pure .dag, no live execution): extde * Strengthen OomdEnforced grounding to a full conjunction; retarget to the SESSIONS slice (close the oomd-active-alone fail-open) Per the CI-humming critical path (bright-stag-194 / sharp-heron-321 / fierce-carp-462): OomdEnforced must NOT be satisfiable by systemd-oomd being active alone — an active oomd with no managed session cgroup has nothing to evict-within under aggregate pressure (zero protection), a §5 fail-open. ground_oomd_from_read now requires the full conjunction over the effective read: (a) the managed sessions slice EXISTS (b) effective ManagedOOMMemoryPressure == kill on the slice (c) per-session memory.max == C (the eviction ceiling) AND parent sessions.slice MemoryMax == the measured aggregate reservation — both BYTE ceilings, reusing the §3 single authority RunnerSliceCapEffectiveness (CapUnbounded => fail-closed) (d) ManagedOOMMemoryPressureLimit == intended PSI percent — a SEPARATE Percent fact, never conflated with the byte caps (systemd's MemoryPressureLimit takes a PSI percentage, not bytes) (e) systemd-oomd active AND enabled (UnitFileState == UnitEnabled) (f) oomctl confirms the slice is in oomd's managed set Thresholds (C, aggregate, PSI%) are PARAMETERS resolved from their single authorities (REGIME-2 oomd_eviction_ceiling / aggregate_reservation; policy PSI default 60), not minted here. Retarget: the ManagedOOM policy + drop-in now target the (held, not-final) sessions.slice — the oomd subject — not gunbc-runner.slice, which was both the wrong subject (the runner slice is hard-capped, never evicted) and a §3 nickname for the live system-actions-runner.slice. The slice literal is parameterized pending the operator-blessed docker cgroup-parent change. Committed model stays ReadAbsent => OomdUnverified (pure .dag, fail-closed). Witness green by execution: the all-facts-hold read grounds Enforced, and each single missing/wrong fact (slice absent, inactive, disabled, auto, wrong/unbounded per-session cap, wrong parent cap, wrong PSI %, oomctl unmanaged, unmeasured aggregate) fails closed — a discriminating red against the old fail-open. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * WIP: Model systemd-oomd as a dependency (pure .dag, no live execution): extde * Address review: ground oomd durations on std.measure Second; enumerate UnitFileState arms Two findings from claude-opus-4-7 review of #5677: 1. unit-modeling hard-block (extdeps/os/oomd.dag): the duration fields default_memory_pressure_duration / managed_oom_memory_pressure_duration were typed Seconds (a bare branded Int in std/types.dag), a flat scalar for a time quantity. std.measure already has the Time dimension + One scale + the Nanosecond/Microsecond precedent, and Seconds was used ONLY in oomd.dag — so this lands on the carrier (M9 DFS-attach, not a 🟡 defer): add Second = Measure<Time, One, Nat> (one row beside Nanosecond/ Microsecond) and type both fields Second / Second?, values second(30) / second(20). No flat scalar propagates into the policy authority. 2. §5 fail-open (gunbc/oomd_install.dag): unit_is_enabled matched UnitEnabled => true; _ => false over the closed 10-variant UnitFileState, hiding every future arm behind one false. Now enumerates all ten arms explicitly (like the sibling unit_is_active). UnitEnabledRuntime => false is deliberate: runtime-only enablement does not survive a reboot, which the grounding requires. Witness still green by execution; measure carrier tests green. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * Address review nits: String? grounding sentinel; promote Percent to std.types Non-blocking findings from claude-opus-4-7's approving review of #5677: 2. first_grounding_failure overloaded "" as the no-failure sentinel (a second representation of absence). Now returns String? — Absent = all checks pass, Present{reason} = first failure — and ground_oomd_from_read matches on it. No empty-as-absent straddle. 3. Percent was declared in the extdeps.os.oomd leaf, but a percentage is a universal (not oomd-specific) concept; the next caller would re-mint or import-up awkwardly. Promoted to std.types beside the other branded-Int scalars (Duration/Milliseconds/Seconds) that are collectively pending the value-Measure migration; oomd.dag and oomd_install.dag now import it from std. No fork (no std.Percent existed before). Finding 1 (the coproduct->Bool enforcement predicates) is left as-is — the reviewer called it defensible: they encode a domain semantic (only Active/UnitEnabled constitute enforcement; Activating/Reloading deliberately fail closed), not mechanical variant-equality, and the per-check failure_reason carries the located cause. Witness green by execution. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * Add gunbc_oomd_fleet_evidence seam for the fleet capacity gate (CI-humming PR2) sharp-heron-321's CI-humming PR2 needs to bind fleet_host_budget's gunbc_fleet_oomd_evidence (today a literal OomdUnverified, consumed by ci_runner_placement REGIME-2) to this PR's grounded result rather than hardcoding = OomdEnforced. Expose a single binding seam: gunbc_oomd_fleet_evidence(req: OomdGroundingThresholds) -> OomdEnforcementEvidence It grounds over the committed gunbc_oomd_show_effective_read, so it stays OomdUnverified (fail-closed) until a real live ReadObserved on the managed sessions slice grounds the full conjunction — §5 verify-the-realization, no test-greening literal flip. It returns OomdEnforcementEvidence directly so std.realization_reconcile.Reconciliation never leaks into fleet_host_budget (which carries product.budget_tree.Reconciliation) — sidestepping the documented flat-namespace collision. The read shape is internal, so the seam is stable across future grounding-conjunct additions (e.g. a session-membership check coordinated with fierce-carp's cgroup-parent PR). Witness exercises it green (fail-closed on the committed ReadAbsent). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * WIP: Model systemd-oomd as a dependency (pure .dag, no live execution): extde * Address RC: ground Percent as a Measure in std.measure (not a std.types brand) The prior std.types Percent (branded Int) forked the unit-modeling authority — exactly what the in-tree dissolve_on (container_stats.dag:115: 'Ratio or PercentagePoint typed alias lands in std/measure') was authored against. It satisfied the trigger in name without grounding it in the Measure carrier, so container_stats.cpu_percent could not reuse it and the oomd percent fields consumed a forked unit (DESIGN §3 single authority + unit-modeling hard-block). Fix: add a Dimensionless quantity to std.measure and land type Percent = Measure<Dimensionless, One, Nat> (+ percent / percent_count) beside the other Measure aliases (Second/ByteSize/Hertz). Quantity is a phantom type param (never matched), so the new variant is additive. Removed Percent from std.types. extdeps/os/oomd.dag and gunbc/oomd_install.dag import it from std.measure; percent literals are percent(N); the PSI% grounding check compares via percent_count (no record == straddle). This gives percent ONE home in the Measure framework — container_stats's cpu_percent can now dissolve onto the same Dimensionless quantity (a future Ratio sibling) instead of a parallel brand. Predicate-dissolution finding is non-blocking (workflow-local, domain semantic) — left as-is, addressed in prior replies. Witness green by execution; measure carrier tests green. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * WIP: Model systemd-oomd as a dependency (pure .dag, no live execution): extde --------- Co-authored-by: Brian Searls <briansearls1@gmail.com> Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
STAGE-2 PR-1: fleet-resource model (per-type baselines + ONE shared build pool), pure
.dag, zero host effectsBuilds on #5650 (the
SessionReservationModeauthority). This is PR-1 of 2: the typed model + witnesses + the §3 single-authority fix. PR-2 (follow-on) emits the systemd units / admission / runner-slice-cap config as drift-gatedGeneratedArtifacts + the detection-only live-read floor gate.What it models
The operator's "unify the build between GHA-CI and agent sessions" — recognizing the expensive thing in both a runner and a session is the build (cargo, ~per-job memory envelope), already unified host-wide by the existing
ctrl-jobserver(scheduling) +ctrl-sccache(caching) services.extdeps/ctrl/jobserver.dag— citesinstall-ctrl-jobserver.shas the build-pool authority.CtrlJobserverConfig {margin, mem_reserve, mib_per_job}; tokens are installer-DERIVED (derive_jobserver_tokens = min(nproc - margin, fit(mem_total - mem_reserve, mib_per_job))), not a baked literal — on a 128-core/125GiB host this derives to 66 (the memory bound binds), not 120. Committed citation isCtrlJobserverAbsent(fail-closed;/opt/ctrlis root-only — flip toCitedis a later 1-line fill).gunbc/fleet_container.dag— per-type idle baselines as measuredResourceEnvelopes:GhaRunnerContainer~300 MiB,AgentSessionContainer~450 MiB (vs the 31.27 GiB docker cap = ~70× over-reservation).ContainerBaselineUnmeasuredfails closed (no silent zero).gunbc/fleet_host_budget.dag— the conserving host budget (reusesproduct.budget_treeBudgetNode+node_conserves):host = overhead + Σ(baselines) + capped_build_pool + headroom + runner_slice_cap. The build is a typedRealizedStep<Nano>(content-addressedCreateIfAbsentkeyed on the compile content-hash,materialization: Share= sccache,cost.space = mib_per_job) — the §2 grounding. Headroom is a fail-closed operator policy lower-bounded by a derivedoomd_actuation_floor.runner_slice_capis the conserving value for the existing10-resource-caps.confdrop-in (not a new cap). Every fail-closed path (Absent/Unmeasured/ headroomUnset/ below-floor /OomdUnverified) returnsFleetHostPlanUnsound; the livefleet_host_plan()is Unsound today.§3 single-authority (D1)
product.compute_fabric'sHostJobserverFifoprovider-constraint nowconfig_ref: CtrlJobserverConfiginstead of its owntoken_cap: Int— the jobserver token count has one home; the duplicate is unwritable by construction. Verified: zero constructors/readers broke.Verification (green by execution)
fleet_model_holds=true(15 witnesses): the fail-closed paths; tokens-memory-bound-binds (=66, not 120); capped-conservation (node_conserves+ an uncapped-overcommit discriminating RED); the disk≠live runner-slice drift red-receipt (the liveMemoryMax=INFINITYbug, the real over-commit vector, as a witness); and the #5650-marker dissolution (exact conservation: the coarse Regime2 aggregate = the fineΣbaselines + capped_build_pool, nothing lost).runner_placement_holds+ci_budget_tree_holdsunbroken.🤖 Generated with Claude Code