Skip to content

SPARK-0: cited DGX Spark upstream product + NVIDIA fleet-management contracts in extdeps - #7874

Merged
briansrls merged 13 commits into
mainfrom
session/swift-crane-499
Aug 6, 2026
Merged

briansrls merged 13 commits into
mainfrom
session/swift-crane-499

Conversation

@gunbai-bot

@gunbai-bot gunbai-bot Bot commented Aug 5, 2026 •

Copy link
Copy Markdown
Contributor

Summary

Grounds the DGX Spark hardware ahead of physical arrival: a cited NVIDIA vendor catalog row (new IntegratedComputeSystemCatalogRow system shape — neither GpuModelCatalogRow nor CpuModelCatalogRow fit a sealed SoC desktop system), a transport/policy-agnostic model of the SSH-driven fleet-lifecycle tool contracts, and a procurement-intent carrier with reserved-not-enrolled srv5/srv6 identities. Does not touch fleet_intent.dag / fleet_intent_network.dag (HOST-0's parallel lane).

What's in each file

  • dag/extdeps/systems/types.dag — new IntegratedComputeSystemCatalogRow shape + CpuCoreCluster (heterogeneous big.LITTLE core clusters) + SystemNetworkPort. Scope note explains why the existing GPU-card and socketed-CPU shapes don't fit.
  • dag/extdeps/systems/nvidia.dag — DGX Spark catalog (two SKU rows, 1TB/4TB), citing docs.nvidia.com/dgx/dgx-spark/hardware.html and .../system-overview.html. Nests the existing GpuModelCatalogRow for the GB10 GPU. Every numeric field is traced to a verbatim quote in dgx_spark_grounding_note.
  • dag/extdeps/systems/nvidia_fleet_lifecycle.dag — operation-shape model of device_identity.py, hardware_config.py, os_build_identity.py, firmware_reporter.py, spark_updatectl.py, spark_diagctl.py, reset_reason_reporter.py from docs.nvidia.com/dgx/dgx-spark/enterprise-fleet-lifecycle.html: Collector/Controller class distinction, common envelope, the four documented failure classes. Transport (SSH) and business policy (which host, which window) are deliberately absent per DESIGN §3.
  • dag/gunbc/dgx_spark_procurement.dag — HardwareProcurementIntent (2 units ordered) and admit_dgx_spark_deployment, a construction wall that refuses to admit a DgxSparkDeployment without a real FleetLifecycleEnvelope observation. srv5/srv6 are reserved HostIdentity values scoped to this module only — not added to any enrollment roster.
  • dag/test/claim/dgx_spark_witness_test.dag — 9 witnesses, green by execution.

Citation gap (flagged, not filled)

GPU compute_capability (the CUDA sm_ number) is left none. The cited docs.nvidia.com pages don't state it, and the only sources naming "sm_121" are a ServeTheHome review and a blog post — not docs.nvidia.com citations, so not used. Noted in dgx_spark_grounding_note.

Test plan

Built and ran via claim_batch (not typecheck-only):

CTRL_BUILD_MODE=local RUSTC_WRAPPER= ctrl-build -- cargo build --bin claim_batch
./target/debug/claim_batch --source-root dag --source-root src/v2 \
  --entry dag/test/claim/dgx_spark_witness_test.dag \
  --functions w_catalog_row_nests_gpu_from_grounded_authority,w_two_skus_differ_only_in_storage_capacity,w_heterogeneous_cpu_core_count_derives_to_twenty,w_fleet_lifecycle_operation_class_distinguishes_collector_and_controller,w_only_the_controller_requires_a_change_window,w_tool_names_match_the_cited_page,w_procurement_intent_reserves_two_identities_not_enrolled,w_red_admission_without_evidence_refuses,w_admission_with_real_evidence_succeeds
PASS w_catalog_row_nests_gpu_from_grounded_authority
PASS w_two_skus_differ_only_in_storage_capacity
PASS w_heterogeneous_cpu_core_count_derives_to_twenty
PASS w_fleet_lifecycle_operation_class_distinguishes_collector_and_controller
PASS w_only_the_controller_requires_a_change_window
PASS w_tool_names_match_the_cited_page
PASS w_procurement_intent_reserves_two_identities_not_enrolled
PASS w_red_admission_without_evidence_refuses
PASS w_admission_with_real_evidence_succeeds

The RED control is w_red_admission_without_evidence_refuses: constructing a DgxSparkDeployment from vendor catalog data plus procurement intent alone (no FleetLifecycleEnvelope) must refuse — physical binding evidence is absent. w_admission_with_real_evidence_succeeds is the positive control proving the same function admits once that evidence is supplied.

  • Title describes the change.
  • Body summarises what and why.
  • Tests run: claim_batch, all 9 PASS (pasted above).
  • No secrets / credentials / large binaries staged.

gunbc-ci-auto-heal and others added 2 commits August 5, 2026 20:23
…rocurement intent, and RED-control witness

Adds three separated fact classes per DESIGN §3/§5:
- extdeps/systems/{types,nvidia}.dag: a new IntegratedComputeSystemCatalogRow
  shape (neither GpuModelCatalogRow nor CpuModelCatalogRow fit a sealed
  SoC-based desktop system) cataloging the DGX Spark from
  docs.nvidia.com/dgx/dgx-spark/{hardware,system-overview}.html, nesting the
  existing GpuModelCatalogRow for the GB10 GPU.
- extdeps/systems/nvidia_fleet_lifecycle.dag: operation-shape modeling of the
  SSH-driven fleet-lifecycle tools (device_identity.py, hardware_config.py,
  os_build_identity.py, firmware_reporter.py, spark_updatectl.py,
  spark_diagctl.py, reset_reason_reporter.py), transport- and
  policy-agnostic per DESIGN §3.
- gunbc/dgx_spark_procurement.dag: procurement intent (2 units, srv5/srv6
  reserved-not-enrolled identities) and admit_dgx_spark_deployment, a
  construction wall that refuses to admit a deployment without a real
  FleetLifecycleEnvelope observation.
- test/claim/dgx_spark_witness_test.dag: 9 witnesses, green by execution,
  including the RED control proving catalog+intent alone cannot admit a
  deployment.

Does not touch fleet_intent.dag or fleet_intent_network.dag (HOST-0's lane).
Citation gap: GPU compute_capability (sm_ number) left `none` -- not stated
on the cited pages; unofficial sources naming "sm_121" are not
docs.nvidia.com citations and are deliberately not used.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
@gunbai-bot
gunbai-bot Bot marked this pull request as ready for review August 5, 2026 20:46
…ssion wall)

FleetLifecycleEnvelope.duration_ms is now Milliseconds (std.types), not a
bare Int, matching the precedent at extdeps/bmc/serial_console.dag.

admit_dgx_spark_deployment previously admitted on ANY Present envelope
regardless of which tool produced it, so a spark_updatectl.py envelope
would incorrectly bind identity. It now checks envelope.tool against
DeviceIdentity's tool name and refuses with a distinct reason otherwise.
New witness w_red_admission_with_wrong_tool_evidence_refuses proves the
tightened wall by execution.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
@gunbai-bot

gunbai-bot Bot commented Aug 5, 2026

Copy link
Copy Markdown
Contributor Author

Both findings from review 49032 addressed:

  1. duration_ms: Int → Milliseconds (blocking): FleetLifecycleEnvelope.duration_ms in dag/extdeps/systems/nvidia_fleet_lifecycle.dag now uses std.types.Milliseconds, matching the SolConsoleCaptureReceipt.duration_ms precedent in dag/extdeps/bmc/serial_console.dag.

  2. Presence-only admission wall (substantive): admit_dgx_spark_deployment in dag/gunbc/dgx_spark_procurement.dag previously admitted on any Present { value: envelope } regardless of which tool produced it — correct, a spark_updatectl.py envelope would have wrongly bound identity. It now checks envelope.tool == fleet_lifecycle_operation_tool_name(op: DeviceIdentity) and refuses with a distinct reason ("wrong evidence tool") when it doesn't match. Added a new discriminating witness, w_red_admission_with_wrong_tool_evidence_refuses, that constructs an envelope tagged spark_updatectl.py and proves it refuses — so the tightened wall is green-by-execution, not just inspection-verified.

The third potential finding (core_count: Int vs cores: Int) — no change made, per your own pre-scan conclusion that it's a legitimate cardinal count, not a unit.

Full witness suite re-run after both fixes, all 10 PASS (9 original + the new wrong-tool RED control):

PASS w_catalog_row_nests_gpu_from_grounded_authority
PASS w_two_skus_differ_only_in_storage_capacity
PASS w_heterogeneous_cpu_core_count_derives_to_twenty
PASS w_fleet_lifecycle_operation_class_distinguishes_collector_and_controller
PASS w_only_the_controller_requires_a_change_window
PASS w_tool_names_match_the_cited_page
PASS w_procurement_intent_reserves_two_identities_not_enrolled
PASS w_red_admission_without_evidence_refuses
PASS w_admission_with_real_evidence_succeeds
PASS w_red_admission_with_wrong_tool_evidence_refuses

Command: ./target/debug/claim_batch --source-root dag --source-root src/v2 --entry dag/test/claim/dgx_spark_witness_test.dag --functions <all 10, comma-separated>

— sent from swift-crane-499

gunbc-ci-auto-heal and others added 2 commits August 5, 2026 21:06
…efused, witness both outcome fns

bold-eagle-107 (msg_2d71b55b) found the same capitalized True/False bug
one function over from the first fix: fleet_lifecycle_outcome_is_refused
had both arms broken (undefined variable on every input), invisible
because zero witnesses referenced it.

Fixed the literals and added two witnesses, each exercising both the
FleetLifecycleObserved and FleetLifecycleRefused arms so a single-arm
witness can't again pass over a broken arm:
- w_outcome_envelope_present_only_when_observed
- w_outcome_is_refused_distinguishes_observed_and_refused

Swept all five PR-changed files for further capitalized True/False in
code positions: none found. dgx_spark_catalog_row remains without a
direct-name witness but is exercised indirectly (constructs the two
catalog data rows every other witness dereferences).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
@gunbai-bot

gunbai-bot Bot commented Aug 5, 2026

Copy link
Copy Markdown
Contributor Author

review 49056: fixed. CpuCoreCluster.core_count in dag/extdeps/systems/types.dag was bare Int; it now carries HardwareThreadCount (std.measure), matching the precedent in extdeps.gpu.types.execution_lane_count and extdeps.bmc.types.core_count. Construction sites in nvidia.dag build it with hardware_thread_count(10), and integrated_compute_system_cpu_core_count unwraps via hardware_thread_count_value to keep its existing Int return (the witness w_heterogeneous_cpu_core_count_derives_to_twenty still compares against the literal 20). Re-ran the full 12-witness suite via claim_batch, all PASS. Pushed at 64f9d55.

— sent from swift-crane-499

…tity)

admit_dgx_spark_deployment checked only that the FleetLifecycleEnvelope came
from device_identity.py, not that its host matched the identity being
admitted -- an observation of srv6 could bind a deployment for srv5. Now
refuses on host mismatch, with a discriminating RED witness
(w_red_admission_with_mismatched_host_refuses).
@gunbai-bot

gunbai-bot Bot commented Aug 5, 2026

Copy link
Copy Markdown
Contributor Author

review 49071: fixed. admit_dgx_spark_deployment in dag/gunbc/dgx_spark_procurement.dag now requires identity == (envelope.host as HostIdentity) in addition to the tool check, refusing with a typed "host mismatch" reason when a valid device_identity.py envelope observes a different host than the identity being admitted. Added the discriminating RED witness w_red_admission_with_mismatched_host_refuses (srv6 admitted against an envelope with host=srv5 -> refuses). Full 13-witness suite re-run via claim_batch, all PASS. Pushed at f435e03.

— sent from swift-crane-499

memory_data_rate_mts was a bare Int for a MT/s domain rate. Ground it
on std.measure.Hertz (same pattern as GpuModelCatalogRow.boost_clock),
renaming to memory_data_rate to drop the now-redundant unit suffix.
Construction site in nvidia.dag now uses hertz(count: 4266000000)
instead of the bare literal 4266.
@gunbai-bot

gunbai-bot Bot commented Aug 5, 2026

Copy link
Copy Markdown
Contributor Author

Addressed review 49086 in 9bab0d2.

memory_data_rate_mts in dag/extdeps/systems/types.dag was a bare Int for an MT/s domain rate. Grounded it on std.measure.Hertz (the same carrier and constructor pattern already used for GpuModelCatalogRow.boost_clock via hertz(count: ...)), and renamed the field to memory_data_rate since the type now carries the unit — matching the boost_clock naming precedent rather than suffixing the abbreviation onto the field name. Updated the sole construction site in dag/extdeps/systems/nvidia.dag to hertz(count: 4266000000) (4266 MHz expressed in base Hz, consistent with how bandwidth/watt/bit_width are constructed elsewhere in that same file).

No witness in dag/test/claim/dgx_spark_witness_test.dag referenced the field directly, so no witness changes were needed; all 13 witnesses in that file pass by execution after the change.

One honest scope note: dag/extdeps/memory/types.dag's DramModuleCatalogRow.data_rate_mts: Int has the identical bare-Int MT/s pattern, but that file predates this PR and isn't touched by this diff, so it's out of scope here — flagging it rather than silently leaving it unmentioned.

gunbc-ci-auto-heal and others added 2 commits August 5, 2026 22:21
…on, dead-fn deletion)

Per review 49094: hoist five *_note: String prose blobs (DESIGN §4c
quarantine boundary) into leading // annotation blocks on their eligible
module-scope declarations across nvidia.dag, nvidia_fleet_lifecycle.dag,
types.dag, dgx_spark_procurement.dag, and dgx_spark_witness_test.dag.
Replace DgxSparkDeploymentRefused { reason: NonEmptyStr } with a closed
DgxSparkAdmissionRefusalReason coproduct (DeploymentAdmissionNoEvidence /
DeploymentAdmissionWrongTool / DeploymentAdmissionHostMismatch), matching
the sibling FleetLifecycleFailureClass pattern, and tighten the three RED
witnesses to assert on the specific variant rather than a reason:_
wildcard. Delete fleet_lifecycle_outcome_envelope and
fleet_lifecycle_outcome_is_refused (zero production consumers,
specification-without-execution) along with their now-dead witnesses and
synthetic-outcome helpers. All 11 dgx_spark witnesses proven green by
execution (claim_batch) after the change.

Also removes the temporary dag/tmp_probe_annotation_test.dag scratch file
used to empirically confirm // comment attachment before relying on it.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
@gunbai-bot

gunbai-bot Bot commented Aug 5, 2026

Copy link
Copy Markdown
Contributor Author

Addressed review 49094 in 49e3cd4:

  1. Prose-in-String (DESIGN §4c) — hoisted all five *_note: String blobs into leading // annotation blocks on their eligible module-scope declarations (nvidia.dag, nvidia_fleet_lifecycle.dag, types.dag, dgx_spark_procurement.dag, dgx_spark_witness_test.dag). Verified by execution that // on a real .dag module-scope declaration parses/compiles cleanly (empirical probe, not just reading the design doc) before doing the conversion at scale.

  2. Stringly-typed refusal reason (DESIGN §3/§5 undeclared-sum) — DgxSparkDeploymentRefused { reason: NonEmptyStr } is now DgxSparkAdmissionRefusalReason = DeploymentAdmissionNoEvidence | DeploymentAdmissionWrongTool { observed_tool } | DeploymentAdmissionHostMismatch { observed_host, requested_identity }, matching the sibling FleetLifecycleFailureClass pattern one file over. Tightened the three RED witnesses to assert on the specific variant (and its fields) instead of a reason: _ wildcard, so the coproduct is actually discriminated, not just present.

  3. Dead predicate/optional-collapse functions (§5 specification-without-execution) — deleted fleet_lifecycle_outcome_envelope and fleet_lifecycle_outcome_is_refused; both had zero production consumers, existing only to be witnessed by tests written to green them. Removed the now-dead witnesses and synthetic-outcome helpers with them.

All 11 remaining dgx_spark witnesses proven green by execution via claim_batch after the change (not just typecheck-clean).

@gunbai-bot

gunbai-bot Bot commented Aug 5, 2026

Copy link
Copy Markdown
Contributor Author

Re review 49110 (run against fbe5089, before the 49094 fix landed):

  1. Stray dag/tmp_probe_annotation_test.dag and 2. prose-in-String rows — both already resolved in 49e3cd4 (see the review-49094 reply above); that commit deleted the probe file and hoisted all five *_note: String blobs into // annotations.

  2. ByteSize basis marker on storage capacity — checked std.measure: there is no ByteBasis carrier there (the ByteBasis type referenced in DESIGN's open-threads log lives in extdeps.pricing.object_storage, scoped to ambiguous vendor-quoted billing-rate units like "GB-Mo" / "1 gibibyte hour" — a different problem than this row). ByteSize = Measure<Memory, One, Nat> here is already an exact resolved byte count, not a re-quoted vendor label: nvidia.dag's grounding comment states explicitly that "1 TB"/"4 TB" is read as the vendor's decimal marketing figure and converted to 1000000000000/4000000000000 bytes before construction, so the basis decision is made once, at the citation boundary, and the stored Nat carries no further ambiguity to disambiguate. Adding a ByteBasis tag to an already-decimal-resolved integer wouldn't remove any real uncertainty here — it would just re-state, in a second place, what the adjacent // comment already says once. Not changing this; happy to revisit if a concrete downstream comparison needs the tag.

Full witness suite (11/11) re-verified green by execution after 49e3cd4.

Per review 49122: on the DGX Spark's unified LPDDR5x SoC, the nested
nvidia_gb10_gpu_catalog.memory/.memory_bandwidth and the system-grain
IntegratedComputeSystemCatalogRow.memory/.memory_bandwidth are one
physical fact, not two independent ones -- re-asserting identical
128 GiB / 273 GB/s literals at both grains is a §3 parallel-representation
that can silently drift. Derive the system row's memory fields from the
already-cited GPU catalog row instead of re-literal-izing them.

All 11 dgx_spark witnesses re-verified green by execution.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
@gunbai-bot

gunbai-bot Bot commented Aug 5, 2026

Copy link
Copy Markdown
Contributor Author

Addressed the non-blocking finding in review 49122 in 4ce3f37: derived IntegratedComputeSystemCatalogRow.memory and .memory_bandwidth from nvidia_gb10_gpu_catalog.memory/.memory_bandwidth instead of re-asserting the same 128 GiB / 273 GB/s literals a second time at the system grain — a real §3 parallel-representation on the unified-memory SoC, worth fixing even though it didn't block.

All 11 dgx_spark witnesses re-verified green by execution after the change.

@gunbai-bot

gunbai-bot Bot commented Aug 5, 2026

Copy link
Copy Markdown
Contributor Author

Re review 49132: agreed this is a real DESIGN §3 shape, but declining to restructure the type in this PR.

IntegratedComputeSystemCatalogRow.memory/memory_bandwidth admitting a value independent of the nested GpuModelCatalogRow's is only a live risk once a second consumer with a genuinely DiscretePools-shaped SoC exists to disagree with it. Today there is exactly one consumer (DGX Spark, a UnifiedShared SoC), and both fields at that single construction site are already derived from nvidia_gb10_gpu_catalog (per review 49122), so the divergence the finding describes has no path to occur in the current corpus. Speculatively splitting the type into a MemoryTopology = UnifiedShared | DiscretePools sum now, with no second SoC shape to ground the DiscretePools arm against, would be modeling ahead of evidence rather than from it (DESIGN §6: don't design for hypothetical future requirements).

Left as the review's own suggested tracked item — the trigger is "before a second consumer lands," and that's the right time to ground the split against a real discrete-memory SoC rather than guess its shape now.

— sent from swift-crane-499

@gunbai-bot

gunbai-bot Bot commented Aug 5, 2026

Copy link
Copy Markdown
Contributor Author

CI's aggregate ci check failed at 4ce3f37 on extdeps_scope_placement_gate_passes (not a review finding — the merge-gated per-PR gate itself): the three new files under dag/extdeps/systems/ (nvidia.dag, nvidia_fleet_lifecycle.dag, types.dag) were added without the extdeps_model_scope: ExternalModelScope declaration + scope_carrier_paths roster entry that dag/gunbc/extdeps_scope_frontier.dag requires of every new extdeps module (DESIGN §3 "External upstream decomposition").

Fixed in 14fd9119fb9: each file now carries an extdeps_model_scope declaration pointing at its representative subject and citing the module's existing ExternalAuthority anchor(s) (nvidia.dag cites both its hardware and system-overview pages), and all three paths are added to scope_carrier_paths. Re-verified 11/11 dgx_spark witnesses PASS by execution after the change.

— sent from swift-crane-499

# Conflicts:
#	dag/gunbc/extdeps_scope_frontier.dag
@gunbai-bot

gunbai-bot Bot commented Aug 6, 2026

Copy link
Copy Markdown
Contributor Author

Addressed review 49149 (REQUEST_CHANGES) in commit 26c4d2c: dgx_spark_catalog_row in dag/extdeps/systems/nvidia.dag took a bare Int storage_capacity_bytes parameter despite the row field itself already being ByteSize — a unit-modeling gap per DESIGN's fail-closed/single-authority principles. Changed the fn to take storage_capacity: ByteSize directly (added ByteSize to the std.measure import) and updated both call sites (nvidia_dgx_spark_1tb_catalog, nvidia_dgx_spark_4tb_catalog) to pass byte_size(count: ...) instead of raw integer literals. Re-verified all 11 dgx_spark_witness_test.dag witnesses PASS by execution after the change.

The same commit also merges origin/main to resolve a CONFLICTING mergeable state: main had independently added dag/extdeps/os/debian.dag to scope_carrier_paths in dag/gunbc/extdeps_scope_frontier.dag, textually conflicting with this PR's own scope_carrier_paths additions for the three new extdeps/systems/*.dag files (fix for the earlier extdeps_scope_placement_gate_passes CI failure). Resolved by keeping both entries plus the three new paths, all deduped and in sorted order.

# Conflicts:
#	dag/gunbc/extdeps_scope_frontier.dag
@gunbai-bot

gunbai-bot Bot commented Aug 6, 2026

Copy link
Copy Markdown
Contributor Author

Resolved a second merge conflict against main in dag/gunbc/extdeps_scope_frontier.dag's scope_carrier_paths roster — main had independently added dag/extdeps/standards/web_annotation.dag at the same list position this branch's nvidia.dag/nvidia_fleet_lifecycle.dag/types.dag entries occupy. Merged both sets of entries in alphabetical order, verified no duplicates, and merged via git merge (no rebase, per repo policy) in cc4f9d4.

@gunbai-bot

gunbai-bot Bot commented Aug 6, 2026

Copy link
Copy Markdown
Contributor Author

Re review 49167's minor note on w_procurement_intent_reserves_two_identities_not_enrolled: agreed the witness is a shape assertion against its own constructing literal, not an independent oracle for "not enrolled." Deliberately not tightening it to assert against gunbc.fleet_intent's fleet_intent_known_hosts roster: that file is explicitly out of scope for this change per this module's own header comment (HOST-0/bold-eagle-107 is refactoring fleet_intent.dag/fleet_intent_network.dag concurrently), and importing it into this witness would create a live cross-session coupling that could spuriously break this PR on an unrelated concurrent refactor. The real non-enrollment claim is enforced structurally instead — dgx_spark_procurement.dag never imports or references those rosters, so srv5_reserved/srv6_reserved cannot appear in them by construction of this diff, which is the property that actually matters here. Leaving the witness as a construction/shape check, per the review's own "not worth blocking" verdict.

— sent from swift-crane-499

@briansrls
briansrls merged commit 2be8848 into main Aug 6, 2026
5 checks passed
@briansrls
briansrls deleted the session/swift-crane-499 branch August 6, 2026 02:09
@gunbai-bot

gunbai-bot Bot commented Aug 6, 2026

Copy link
Copy Markdown
Contributor Author

Recording one non-blocking finding as a follow-up, since this PR is merge-ready and the session that authored it has been archived.

Review 49167 flagged that w_procurement_intent_reserves_two_identities_not_enrolled compares the data value to the same literal list it was constructed from. That is the DESIGN §5 named class: a measurement compared against itself is a change detector, not a check — automating the literal's update would collapse the assertion to measure() == measure().

Not blocking, and the reviewer's judgment that the surrounding admission witnesses carry the real evidence is correct. But it is worth fixing rather than deleting, because the claim the witness is NAMED for is meaningful and currently unproven: srv5 and srv6 are reserved procurement identities that must not appear in any fleet_intent enrollment. The fix asserts that against an independent referent — walk the actual enrollment roster and assert neither reserved identity is a member — instead of restating the literal the row was built from. A discriminating control falls out for free: a synthetic enrollment carrying srv5 must red.

Small and self-contained. It converts a tautology into the wall the name promises. I will pick it up after the HOST-0/HOST-1 stack lands unless someone takes it first.

— sent from bold-eagle-107

gunbai-bot Bot pushed a commit that referenced this pull request Aug 6, 2026
…g lines

Main advanced three times during this resolution (#7766 heal-credential
recut, #7880, #7874, then 3c60c89). The first regeneration in this
worktree ran on top of a stale ci.yml left from before the second merge
and produced output that REVERTED #7766's heal improvements — the
`heal_commit_push` step id, the guarded bundle copy, `if-no-files-found:
error`, and the conditional upload. That artifact was discarded, not
committed: ci.yml was reset to main's version and regenerated from the
merged model, which is the only procedure that makes the generator a
function of the model alone.

Verified against a PINNED main SHA rather than the moving `origin/main`
ref, because main moved mid-resolution and an unpinned comparison made
main's newer content read as deletions this branch was making.

Final state vs 3c60c89:
  model:  3 files (ci_workflow, ci_workflow_expressions, ci_heal_job_witness_test)
  ci.yml: needs: [build, regen, heal_generated_artifacts]
          if: "!failure() && !cancelled()"

Witnesses: 27/27 PASS, including floor_job_waits_on_the_heal_preflight and
floor_job_still_runs_when_heal_is_skipped.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
briansrls pushed a commit that referenced this pull request Aug 6, 2026
…7882)

* Do not start the 65-minute floor on a branch already known to be drifted

The ci job named only [build, regen] as prerequisites and was not gated on
the generated-artifact heal result. A branch whose ci.yml or generated
artifacts had already been refused could therefore spend a full floor
budget on a runner before failing for a reason established minutes earlier.
That happened repeatedly on 2026-08-05.

ci now needs [build, regen, heal_generated_artifacts], with
ci_floor_upstream_clean_if = "!failure() && !cancelled()".

The expression is load-bearing, not decoration. A job whose needs include a
skipped job is skipped by default, and heal is pull_request-only, so adding
the dependency alone would silently stop the floor running on push-to-main,
merge_group and workflow_dispatch -- deleting main's unconditional cold
control while every PR stayed green.

Four cases, all deliberate:
  pull_request, no drift        heal exits 0, floor runs (heal is parallel
                                with regen, so no wall time is added)
  pull_request, author-commit   heal exits 1, floor skipped instead of
    required                    proving what the drift gate would refuse
  pull_request, heal repaired   heal exits 1 after SupersededByHealedHead,
                                so the floor no longer runs against a head
                                that is already obsolete
  push / merge_group / dispatch heal skipped, no failure, floor runs as before

Skipping the floor is not a fail-open. The ruleset requires the ci context
and a skipped job does not satisfy a required check, so drift now blocks the
merge rather than being a red the floor might have masked. What is removed
is wasted computation, not a gate: the refusal that causes the skip is
itself the typed, located diagnostic, emitted before the expensive stage.

Witnesses, green by execution, and the pair is the point. Proven
discriminating by temporarily setting the expression to success():
floor_job_still_runs_when_heal_is_skipped FAILS while
floor_job_waits_on_the_heal_preflight still PASSES -- which is exactly the
silent regression shape, dependency intact and condition wrong.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* Regenerate ci.yml against current main (author-committed workflow path)

The merge brought main's floor-peak wet-witness receipt emitter; the
generated-artifact merge driver keeps this side for generated paths, so
ci.yml had to be re-projected rather than text-merged. Output now differs
from origin/main by exactly the two gating lines this PR adds.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* Regenerate ci.yml against merged main: delta is exactly the two gating lines

Main advanced three times during this resolution (#7766 heal-credential
recut, #7880, #7874, then 3c60c89). The first regeneration in this
worktree ran on top of a stale ci.yml left from before the second merge
and produced output that REVERTED #7766's heal improvements — the
`heal_commit_push` step id, the guarded bundle copy, `if-no-files-found:
error`, and the conditional upload. That artifact was discarded, not
committed: ci.yml was reset to main's version and regenerated from the
merged model, which is the only procedure that makes the generator a
function of the model alone.

Verified against a PINNED main SHA rather than the moving `origin/main`
ref, because main moved mid-resolution and an unpinned comparison made
main's newer content read as deletions this branch was making.

Final state vs 3c60c89:
  model:  3 files (ci_workflow, ci_workflow_expressions, ci_heal_job_witness_test)
  ci.yml: needs: [build, regen, heal_generated_artifacts]
          if: "!failure() && !cancelled()"

Witnesses: 27/27 PASS, including floor_job_waits_on_the_heal_preflight and
floor_job_still_runs_when_heal_is_skipped.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* Fix the fail-open: the floor RUNS and refuses fast, it does not skip

review 49309 (cursor/composer-2.5) found that the first cut of this PR was
a fail-open on the only required merge gate. Confirmed on three independent
legs before changing anything:

  1. GitHub's troubleshooting-required-status-checks page: a job skipped by
     a conditional REPORTS SUCCESS, and a job skipped because a needed job
     failed "may not block merging".
  2. The live default-branch ruleset (id 16178731) names exactly one
     required context: `ci`. heal_generated_artifacts is not required.
  3. Composing them: heal fails -> ci skipped -> ci satisfies its own
     required check by being absent -> GeneratedArtifactDriftGate never
     runs -> drift merges while only a non-required job is red.

The change meant to remove wasted computation would have removed the wall.

WHAT CHANGED. The job condition is now `!cancelled()`, so ci runs whenever
the run is live -- including when an upstream job failed -- and the required
context always produces a real verdict. The refusal moved into an executing
first step that reads needs.<job>.result and exits 1 with a typed, located
FloorUpstreamAlreadyRed diagnostic. The budget saving is preserved: a runner
spin-up and a string compare, not a floor run.

heal may be `skipped` (it is pull_request-only) and the floor proceeds, so
main's cold control is intact; only `failure` refuses, covering both
HealAuthorCommitRequired and the deliberate SupersededByHealedHead exit.

MY NOTE WAS THE WORSE HALF AND IS RETRACTED IN PLACE. It asserted "a skipped
job does not satisfy a required check". That was written from reasoning, not
from a receipt -- the DESIGN section 5 trap of fluent output that was never
run. The replacement states the verified mechanism and cites both receipts.

A SECOND DEFECT, CAUGHT BY READING THE GENERATED ARTIFACT rather than the
model: the refusal step was first added to ci_floor_job_prelude_steps(),
which is shared, so it leaked into the regen job and into falsifier.yml. In
the regen job (needs: [build]) the referenced results do not exist, so the
guard would have compared "" != "success" and refused on EVERY run. It is now
composed into ci_job()'s own step list, and
floor_refusal_reaches_only_the_job_whose_needs_it_names is the control that
reds if it ever leaks again.

Witnesses: 30/30 PASS. floor_job_runs_even_when_an_upstream_job_failed
refuses both failure() and success() by name, and was proven discriminating
by reintroducing `!failure() && !cancelled()` and observing exit 1.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* Pin the refusal as exactly the first step (operator review)

The prior witness folded over ci_job().steps and asserted the refusal
existed SOMEWHERE. That does not pin the invariant the step exists for:
refusing BEFORE the expensive work. A future edit could move it after
checkout, toolchain setup or artifact download and the assertion would
stay green.

floor_refusal_is_exactly_the_first_step now matches list_head(ci_job().steps)
and requires it to BE the refusal step. Proven discriminating by moving the
step behind the prelude: the new witness FAILS while the old fold witness
still PASSES on the same tree, which is the operator's point demonstrated
rather than argued. The fold assertion is retained beside it because it
carries the script-content claims; the positional one carries the ordering.

The generated ci.yml is not separately asserted because the drift gate
already pins ci.yml == the model's projection, so model-first-step plus
drift-clean composes to workflow-first-step without a second reader.

Witnesses: 31/31 PASS.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: gunbc-ci-auto-heal <gunbc-ci-auto-heal@users.noreply.github.com>
Co-authored-by: Claude Opus 5 (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