Skip to content

STAGE-2 PR-1: fleet-resource model (per-type baselines + shared build pool) + §3 jobserver single-authority - #5663

Merged
briansrls merged 15 commits into
mainfrom
stage2/fleet-container-build-pool
Jun 23, 2026
Merged

briansrls merged 15 commits into
mainfrom
stage2/fleet-container-build-pool

Conversation

@gunbai-bot

@gunbai-bot gunbai-bot Bot commented Jun 23, 2026

Copy link
Copy Markdown
Contributor

STAGE-2 PR-1: fleet-resource model (per-type baselines + ONE shared build pool), pure .dag, zero host effects

Builds on #5650 (the SessionReservationMode authority). 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-gated GeneratedArtifacts + 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 — cites install-ctrl-jobserver.sh as 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 is CtrlJobserverAbsent (fail-closed; /opt/ctrl is root-only — flip to Cited is a later 1-line fill).
  • gunbc/fleet_container.dag — per-type idle baselines as measured ResourceEnvelopes: GhaRunnerContainer ~300 MiB, AgentSessionContainer ~450 MiB (vs the 31.27 GiB docker cap = ~70× over-reservation). ContainerBaselineUnmeasured fails closed (no silent zero).
  • gunbc/fleet_host_budget.dag — the conserving host budget (reuses product.budget_tree BudgetNode + node_conserves): host = overhead + Σ(baselines) + capped_build_pool + headroom + runner_slice_cap. The build is a typed RealizedStep<Nano> (content-addressed CreateIfAbsent keyed 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 derived oomd_actuation_floor. runner_slice_cap is the conserving value for the existing 10-resource-caps.conf drop-in (not a new cap). Every fail-closed path (Absent / Unmeasured / headroom Unset / below-floor / OomdUnverified) returns FleetHostPlanUnsound; the live fleet_host_plan() is Unsound today.

§3 single-authority (D1)

product.compute_fabric's HostJobserverFifo provider-constraint now config_ref: CtrlJobserverConfig instead of its own token_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 live MemoryMax=INFINITY bug, 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_holds unbroken.

🤖 Generated with Claude Code

briansrls and others added 13 commits June 23, 2026 17:16
…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>
@gunbai-bot

gunbai-bot Bot commented Jun 23, 2026

Copy link
Copy Markdown
Contributor Author

Thanks — both addressed.

Finding 1 (HardwareThreadCount hard-blocker) — fixed by construction in f181ad3599. nproc, margin, and the derived token count now consume the canonical HardwareThreadCount (std.measure, = Measure<Count, One, Nat>) that compute_fabric already uses, rather than bare Int:

  • CtrlJobserverConfig.margin: Int → HardwareThreadCount
  • derive_jobserver_tokens(nproc: HardwareThreadCount, …) → HardwareThreadCount (values extracted for the min/monus arithmetic, reconstructed 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).

This is the construction fix (consume the existing authority), not a dissolve-on deferral — distinct from #5650's cardinal counts, which have no carrier. All three suites green by execution after the change (fleet_model_holds incl tokens-memory-bound-binds = 66 < 120, runner_placement_holds, ci_budget_tree_holds).

Finding 2 (parallel Optional<ByteSize>-shaped coproducts) — kept distinct by design, not folded. The three "absent" arms are semantically different states, not one repeated None:

  • RunnerSliceCapEffectiveness.CapUnbounded = the runtime cgroup has no limit (MemoryMax=INFINITY) — an unbounded/infinity reading, the actual drift bug.
  • HeadroomPolicy.HeadroomUnset = the operator hasn't chosen a policy — fail-closed pending a decision.
  • ContainerBaseline.ContainerBaselineUnmeasured = no measurement exists yet.

Per DESIGN's recurring failure mode "state-space conflation (an Option/None meaning >2 things — split into named variants)", collapsing these into a shared Optional<ByteSize> would conflate three distinct meanings into one None and lose the named reason at each site. The structural identity (X{bytes} | Y) is shallow; the meanings diverge. So this is a deliberate split-don't-conflate, not accidental duplication. (A future parameterized Absence<Reason> carrier that preserves the distinct reasons would be a separate, non-lossy consideration; a bare Optional would not.) Agreed it is non-blocking.

— 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>
@gunbai-bot

gunbai-bot Bot commented Jun 23, 2026

Copy link
Copy Markdown
Contributor Author

Thanks — verified the minor note against the code and it's actually a real fail-open, not merely defensive, so I pushed a fix (04fa715718).

The grounded numeric tower realizes Nat as a native Int, so nproc_v - margin_v is integer subtraction, not monus. Proven by execution: nproc=8 / margin=64 produced a negative token count that flowed silently into jobserver_build_pool_bytes — a §5 fail-open (wrong value, not a typed error), masked-but-not-fixed by the downstream nat_min with the memory bound.

Fix at the carrier, single-authority: added 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). Covered by a new discriminating witness witness_margin_exceeds_nproc_saturates wired into fleet_model_holds; all three suites (fleet_model_holds, runner_placement_holds, ci_budget_tree_holds) green by execution.

— 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>
@gunbai-bot

gunbai-bot Bot commented Jun 23, 2026

Copy link
Copy Markdown
Contributor Author

Took the non-blocking §5 note and dissolved it by construction (38ea8fb288) rather than deferring — it aligns with the project's construction-over-validation principle and the head moves at retarget anyway.

You're right that baseline_or_zero was a fail-open shape, and it was actually worse than it looked: fleet_host_plan_for resolved both baselines at the gate, then discarded the bytes (bytes: _) and re-resolved via baselines_sum with the zero fallback (resolve-discard-reresolve). Per your pointer ("refuse to call baselines_sum outside the resolved branch"): I now bind the resolved ByteSize at the gate (bytes: rb / bytes: sb) and flow them forward; baselines_sum and fleet_host_budget_tree take resolved ByteSize instead of FleetContainerType; baseline_or_zero is deleted. The only sink for an unmeasured baseline is now FleetHostPlanUnsound at the gate — the zero arm is unwritable.

Tests single-source the fixture baseline bytes so no zero-fallback shape survives there either; witness_baseline_unmeasured_unsound proves unmeasured → Unsound. All three suites green by execution.

— sent from cool-boar-883

Base automatically changed from session/cool-boar-883 to main June 23, 2026 20:48
@briansrls
briansrls merged commit 1bc7632 into main Jun 23, 2026
@briansrls
briansrls deleted the stage2/fleet-container-build-pool branch June 23, 2026 20:49
gunbai-bot Bot pushed a commit that referenced this pull request Jun 23, 2026
…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>
gunbai-bot Bot pushed a commit that referenced this pull request Jun 23, 2026
…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>
briansrls added a commit that referenced this pull request Jun 23, 2026
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>
briansrls added a commit that referenced this pull request Jun 23, 2026
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>
briansrls added a commit that referenced this pull request Jun 23, 2026
…(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>
gunbai-bot Bot pushed a commit that referenced this pull request Jun 23, 2026
…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>
briansrls added a commit that referenced this pull request Jun 23, 2026
…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>
briansrls added a commit that referenced this pull request Jun 23, 2026
…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>
briansrls added a commit that referenced this pull request Jun 23, 2026
…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>
briansrls added a commit that referenced this pull request Jun 23, 2026
…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>
briansrls added a commit that referenced this pull request Jun 23, 2026
… 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>
briansrls added a commit that referenced this pull request Jun 24, 2026
…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>
briansrls added a commit that referenced this pull request Jun 24, 2026
#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>
briansrls added a commit that referenced this pull request Jun 24, 2026
… 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>
briansrls added a commit that referenced this pull request Jun 24, 2026
…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>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant