Repository navigation
CENSUS-IMAGE 0A: one seeded-image derivation, a measured identity, and the census envelope grammar - #11731
Conversation
…, and the census envelope grammar
Generalizes extdeps.provisioning.ubuntu_seeded_install_media{,_remaster} (parent ruling (A))
instead of minting a second image authority: the seed payload, stage roster, volume id and pinned
dates are build inputs; the image identity is the sha256 read off the written ISO; publication is
create-only (hard link, refuse on a taken name) with read-back and a derivation record consumers
resolve and re-measure. srv3 is rewired onto the same derivation in this change.
Adds gunbc.machine_intake_host_capture_envelope (stage roster + framing, rendered and parsed from
one set of rows; the program is a RECONSTRUCTION from artifacts/bmc/mtcollins1-host-capture.txt)
and gunbc.machine_intake_mtcollins1_census_image (live-session early-commands seed, every installer
section interactive, built and published inside srv2's /srv/bmc export).
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…rrors, a misplaced image argument, the deleted static ISO path Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…built program's bash-emit dissolution trigger (review 68602) Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
Addressed review 68602 in 0a3703a:
|
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…lass, attempt=3 roster, srv3 runbook - resolve_seeded_image: a record whose image was removed resolves SeededImageRecordedImageAbsent and publish rebuilds into the free name; an unreadable image is SeededImageUnobservable, never diverged. New local-wet claim drives the real resolver through absent / diverged / resolved. - seeded_install_media_builder_revision: declared below-ceiling class with a capability-grain next-rung trigger (gunbc.recurring_failure_mode a_hand_bumped_builder_revision_keys_a_derivation). - host_capture_census_stages carries attempt=3's sections with its argv; dmesg-full is the one declared omission (already on the console stream the envelope is written to). - srv3 runbook names the derivation/resolve route instead of the deleted static path. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
Addressed review 68615 in 6dd390c:
|
…(review 68635) Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
Addressed review 68635 in dd1385d.
The frontier retires when both land and call these functions. They are not wired in this PR because stage 0B/0C is the job that runs on srv2 hardware, and stage 0D edits #11484, which eager-owl-205 owns. |
…ousBareNameRead once the census publish path reaches v2.std.text) Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…re gets an executing reader Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
Addressed review 68664 in 07bd82c:
|
…onstructors (floor AmbiguousBareNameRead) Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
Addressed review 68712 in 56655cf. The census witness module now declares its imports explicitly (std.logic / std.types / std.string_type, extdeps.provisioning.ubuntu_seeded_install_media, gunbc.machine_intake_mtcollins1_boot_artifact, gunbc.machine_intake_host_capture_envelope, gunbc.machine_intake_mtcollins1_census_image, v2.std.live_tree), matching every sibling in dag/test/claim/machine_intake/. On whether it was executing: several witness files elsewhere in the tree carry no import block and are resolved implicitly, which is why it was written that way, and the floor's own refusals on this branch have been |
# Conflicts: # dag/gunbc/srv3/srv3_os_install_diagnostic.dag
…nd the action-use census reads every workflow through it extdeps.languages.yaml is now a bounded-subset reader and writer whose contract is meaning, not text: every document ingest_yaml_source ACCEPTS denotes, under the YAML 1.2.2 core schema, exactly the YamlValue it returns, and every construct outside the declared subset is REFUSED with the line it sits on -- never reinterpreted as a string, never dropped. The writer is the same contract turned around: ingest_yaml_source(emit_yaml(v)) == v, or a refusal naming the path it could not write. WHAT WAS WRONG (source audit on #11663, comment 5743133113; each verified against the code before it was fixed). The reader had no refusal arm -- unrecognized text became a string -- so `{uses: x}` was a string, a single-quoted scalar kept its quotes, `\n` and `\q` were neither decoded nor refused, a quoted key kept its quotes, `key: # c` became the string "# c", a `|` literal lost the line break it clips, and a flow sequence split on the literal ", " (so `[a,b]` was one element and `["a, b", c]` split inside the quotes). The writer filtered a literal's empty lines out, wrote `|` for text with no final break, and wrote the string "123" unquoted, which reads back as an int. WHY THE WITNESSES DID NOT SEE IT: they compared serialize(parse(x)) with serialize(expected), and the round trip was emit(parse(emit(v))) == emit(v). Both compare the WRITER's text, so a loss in the writer masked the same loss in the reader -- the "blank lines are kept" claim could not fail for that reason -- and a type change the writer re-spells identically passed. Rostered as gunbc.recurring_failure_mode bounded_reader_reinterprets_what_it_does_not_model. THE SUBSET is declared in the reader's module header, construct by construct, with its refusals. Accepted: the core schema (null, bool, int in decimal/0o/0x, float with exponent and .inf/.nan, otherwise string); both quote styles on one line, with every escape section 5.7 names; quoted keys; one-line flow sequences and the empty flow mapping; `|`, `|-` and `|+` with auto-detected indentation; block collections at any increasing indentation, compact `- key: value` items, compact nested `- - x`, and a sequence at its key's own column; comments and empty lines between nodes. Refused, each with its own located reason: folded scalars, indentation indicators, anchors, aliases, tags, directives, document markers, explicit `?` keys, flow mappings, nested or multi-line flow collections, multi-line plain and quoted scalars, a comment after a value, a duplicate key, a tab in leading whitespace, a line ending in whitespace, and every character YAML's printable set excludes or this reader cannot tell from whitespace. THE WITNESSES NOW COMPARE DECODED STRUCTURE. test.claim.yaml_ingest_witness compares parse(text) with hand-written values, one conformance claim per construct, each with a red control that must name its line and reason; test.claim.yaml_emit_witness compares parse(emit(v)) with v over strings and multi-line texts built to break plain-versus-quoted and chomping, plus the writer's refusals by path. Four planted reader defects (clip drops its break, unknown escapes pass, duplicate keys admit, plain text never resolves) and three planted writer defects (empty lines filtered, always `|`, digit strings unquoted) each turned their own control red. THE CENSUS READS EVERY EXECUTED FILE THROUGH THE MODELED READER, and the line projection is deleted with its frontier row (gunbc.action_use_admission realized_workflow_action_uses, uses_line_reading, uses_value_text, uses_site_of, realized_workflow_projection_frontier_rows). A use is taken from where GitHub reads one -- jobs.<id>.uses and jobs.<id>.steps[<i>].uses -- so the site is where the key sits, a quoted or escaped `uses` key is decoded and read, and a script line spelled like a `uses:` key is script content. test.claim.action_use_admission_witness carries one claim per workflow file, joined to the directory listing by identity in both directions, so a workflow added without a claim refuses by name. THE BUDGET IS A CONSTRAINT, AND IT IS MET WITHOUT A SECOND READER. The census claim over the largest committed workflow (.github/workflows/fleet-converge.yml, 912 lines) measures 67,692 eval steps against v2.workflow.required_floor's 72,300 per new witness, re-derived by claim_batch on that claim. The reader was 138,483 steps on that file before this change and is ~61,000 after, reading it correctly: a block is split into its entries by marking the line breaks at its own indentation with a sentinel the document is already refused for, so deeper lines and literal bodies are never walked line by line. Three cost-shape defects found on the way are fixed at their owning links: admission admitted every occurrence of a use where the question is per (site, text) (realized_distinct_uses), the manifest join scanned every reading per use (action_manifest_readings_by_producer), and std.types commit_sha_text_holds ran a lambda per character of every 40-character head. THE COMMITTED WORKFLOWS ARE REGENERATED, and the diff is only what the old writer got wrong: 46 `run: |` become `|-` (the scripts carry no final line break) and 11 become `|+` (they end in a blank line the old writer dropped); MALLOC_ARENA_MAX and fetch-depth are quoted, because they are STRINGS in the model and unquoted they read back as ints. A DUPLICATED CONTRACT EPOCH IS NOW THE READER'S REFUSAL, not a count downstream: an ingested mapping cannot hold a key twice, so gunbc.required_ci_epoch_observation RequiredCiEpochDuplicated is deleted as the lower-rung handling the climb obsoletes (DESIGN section 4b), and its control stays, asserting the reader's located refusal. NOT IN THIS COMMIT: gunbc.os_install_emit autoinstall_user_data still calls the writer's old total entry point, so this tree does not typecheck yet. Its refusal has to travel as a typed outcome to the srv3 install-media build input (parent ruling), and #11731 is rewriting that chain now; sleek-ferret-265 and I agreed #11731 lands first and this branch rebases onto it. The PR stays draft until then. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…o replay takes neutral map parameters Main's floor_route_gap chunk_17 (fabric db wet) and mine collided; mine is renumbered chunk_18 and both are in the chunks list. ReplayBuildPinnedDates takes map_one/map_two source and iso-path again; /boot/grub/grub.cfg is authored in the provisioning module that owns the medium's layout. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…mise as a bet xorriso runs left to right, so both -volume_date commands now follow the -map commands; issued before them, the freshly mapped seed and grub.cfg would have carried the build instant. The SeededInstallMediaPinnedDates annotation no longer states byte-identical rebuild as settled: it states what is established, what is not, what would settle it (the srv2 build-twice control), and why nothing silently depends on it -- a non-reproducible rebuild publishes a different name rather than a wrong image. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
Addressed review 68762 in 7f9e9da. Both halves were right.
Worth adding explicitly, since it bears on how much weight the bet carries: nothing silently depends on it. If a rebuild is not byte-identical it measures a different digest, so it publishes under a different name; create-only publication replaces nothing and the record names whichever bytes were actually built. The cost of the bet being wrong is a second published image, not a wrong one. That is now in the annotation too. Executed evidence on this branch, since CI no longer runs the floor (main's #11742 replaced the required |
# Conflicts: # dag/extdeps/tools/coreutils_stat.dag
# Conflicts: # src/v2/workflow/floor_route_gap.dag
|
CI note: this PR's Repair is cut as its own one-file PR against a clean main base: #11780. Once it lands I will merge main again here and CI should clear. |
Ledger-Repair-Judged: docs/design-rung-drops.md Ledger-Rows-Repaired: docs/design-rung-drops.md namespace_wave_admission_wall_removed Heal-Candidate-Run: 35485963825
Review 69300. HistoricalStageNewlyIntroduced could never be accepted. A newly introduced stage has no section in the historical capture, so the Absent arm answered false before that disposition was reached, while roster_matches_bindings counted the stage as carried and passed: the first stage anyone added would have gone green on the dry claim and permanently red on the wet one, and the wet failure would have read as a capture problem rather than a checker problem. The disposition is now decided before the historical section is demanded, and it still has to earn itself -- if the capture DOES carry the section, the row is wrong about history and it fails. census_historical_capture and HistoricalCaptureIdentity had no reader, and the wet claims bound the capture by path literal, so the row's stated job -- constraining the producer to that committed digest and byte count -- was performed by nothing. Rather than delete it, the job is now done: both existing claims read the path from the row, and a new claim checks the recorded sha256 and byte count against the bytes on disk. The bindings are statements about ONE artifact and the file sits in a worktree where anything may rewrite it, so this is also the brief's digest-disagreement refusal, which had no executing claim until now. The new claim is enrolled on both the wet schedule and the floor route-gap chunk; an unenrolled claim is the defect review 69157 already caught here once. Evidence: mtcollins1_census_image_local_wet_test 7 PASS / 0 FAIL, and the compared values are real -- measured sha256 a9b880c3..fd2a and 270880 bytes both match the committed rows. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
Both findings fixed at
The disposition is now decided before the historical section is demanded. It still has to earn itself: if the capture does carry the section, the row is wrong about history and it fails. So the arm is reachable and discriminating in both directions rather than being a permanent
I did not delete this one. Unlike The new claim is enrolled on both the wet schedule and the floor route-gap chunk — an unenrolled claim is the defect review 69157 caught here once already. Evidence: — sent from sleek-ferret-265 |
Side-chat wall (review 5261076419). host_capture_marker_matches compared
host_capture_run_identity_value(a.run) against
host_capture_run_identity_value(run) -- the projected TEXT only -- so
HistoricalAttemptOrdinal { ordinal: "3" } and KernelBootId { boot_id:
"3" } were the same run, and an envelope begun by the historical program
could be closed by a kernel boot. That is the confusion the two forms
were introduced to end, reintroduced one layer down in the comparison.
An attempt ordinal and a boot id are drawn from different spaces, so a
shared spelling between them means nothing.
host_capture_run_identity_same matches over both identities: same arm
with equal payload matches, different arms never match regardless of
text.
The two controls the suite lacked, both enrolled:
the_same_text_under_two_identity_forms_is_not_one_run -- attempt=3
begin with boot-id=3 end must refuse, and the reverse order too.
the_same_text_under_one_identity_form_is_one_run -- the positive
control, so the refusal is the FORM discriminating and not the text
failing to compare.
The RED is verified discriminating rather than assumed: with the
comparison temporarily reverted to text-only the file measured 21 PASS /
1 FAIL, failing exactly the cross-form claim while the positive control
still passed. Restored, it measures 22 PASS / 0 FAIL.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
briansrls
left a comment
There was a problem hiding this comment.
SOURCE SIGN-OFF — exact head 9ab8c6f.
This supersedes my REQUEST_CHANGES review 5261076419. The remaining identity wall is closed:
- host_capture_run_identity_same is constructor-aware and total: HistoricalAttemptOrdinal compares only with HistoricalAttemptOrdinal, KernelBootId only with KernelBootId, and cross-constructor pairs are false regardless of equal payload text.
- host_capture_marker_matches consumes that equality rather than projecting both identities to String.
- the_same_text_under_two_identity_forms_is_not_one_run covers both directions (attempt=3 begin / boot-id=3 end, and the reverse).
- the_same_text_under_one_identity_form_is_one_run is the positive control for both identity forms.
- The recorded mutation is discriminating: restoring text-only comparison yields 21/22 with exactly the cross-form claim red while the positive control remains green; the repaired source yields 22/22.
The commit changes only the envelope comparison and the hermetic witness. The previously accepted bounded-envelope, workload pass-status/full-coverage, measure-derived footprint, one-observation-per-case, and 19-stage historical-binding walls remain intact. The 7/7 local-wet receipt is on the parent source; this exact delta does not touch the wet file, and its same-form behavior is directly covered by the new exact-head positive control.
All four exact-head checks are green. No srv2 publication is required here; 0B/0C/0D remain declared frontiers.
APPROVE for enqueue on this exact SHA.
…branch was scoped The invariant is not "these four files". It is that `git grep -nE "^[[:space:]]+//" -- '*.dag'` returns ZERO files, AT THE HEAD BEING MERGED INTO. Main moved: #11731 landed two more files carrying indented annotations, so the four-file repair no longer cleared the wall. dag/gunbc/machine_intake/host_capture_historical_binding.dag 7 NEW dag/gunbc/target_binding.dag 5 dag/gunbc/namespace/namespace_reference_derived_residency_qualification.dag 4 dag/gunbc/floor_memory_demand.dag 4 dag/test/claim/machine_intake/mtcollins1_census_image_local_wet_test.dag 3 NEW dag/gunbc/cloudflare/r2_permission_group_observe.dag 1 Six files, twenty-four lines; the census returns zero at this head. Both new blocks are body-position rather than merely indented — one inside a `match` arm, one inside a `test fn` body — so neither could be fixed by changing a column. Each joins the leading annotation of the declaration it sits in, restated so it is true of that declaration rather than of the arm it sat in: - host_capture_historical_binding.dag — the NewlyIntroduced-is-decided-first rationale becomes a statement about the fold's ordering. - mtcollins1_census_image_local_wet_test.dag — the substring-absence rationale becomes a statement about how the claim below asserts. This is the third time today the census has been the thing that moved: the parse log missed one file, a correct census dropped a line that produced no parse FAIL, and now a correct census went stale because main moved under it. The population is whatever the census says at the head you are merging into. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Three §4c body annotations hoisted to module-item grain (host_capture_historical_binding, runner_microvm_boot_probe, mtcollins1_census_image_local_wet_test), and floor_route_gap chunk_20's seven 'tail:' fields whose value sat on the next line -- a parse refusal that orphaned every annotation in the file -- joined onto one line like every other chunk. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…t_capture_historical_binding and runner_microvm_boot_probe to module grain (they refuse to parse and red every floor run) Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…left in chunk_20 (expected expression, found Newline; reds every floor run) Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…now moved three times Census on current main is seven files, twenty-seven lines. The new one is `dag/gunbc/runner/runner_microvm_boot_probe.dag` (3 lines); the other six are unchanged. Four files, then six after #11731, now seven. Each scoping was correct for the head it was taken against and stale by the time the PR was ready. That is a property of the rate `.dag` files are landing, not of the repair — and it is the strongest argument for landing the parse repairs quickly rather than perfecting them. The new block is body-position, inside a `match` arm within `runner_microvm_boot_probe_wet`, so it could not be fixed by changing a column. It joins the leading annotation of that function and is restated to be true of the fold rather than of the arm it sat in: the executor login comes from the host's roster row, so the host binding is resolved before any login is named, and a probe on a host with no roster row reports BootNotAttempted rather than an image or console verdict. `git grep -nE "^[[:space:]]+//" -- '*.dag'` returns ZERO files at this head. No proofs re-taken. The A/B and the CI evidence already in this PR establish the mechanism, and three more relocated lines do not change what the repair does. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…11731 (no ISO on the runner) and the schedule now says so Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…-image rendered-program row from the schedule (red on main since #11731) with its reason and return trigger Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
… refusal against #11731's seeded-image design The srv3 chain and the Mt. Collins census image are both built from one rendered user-data body, so both derivations carry the renderer's outcome and ride the refusal arms gunbc.seeded_install_media_publish already has; the readback chain refuses before its first leg when there is no build key to find a record by. Direct readers of the build input that only need the stem or the label read the rows the input is built from; witnesses that need an input's shape supply the body. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
CENSUS-IMAGE 0A: one seeded-image derivation, a measured identity, and the census envelope grammar
Stage 0A of the Mt. Collins census image (work item
adhoc-6b13c807-a40; parent decisions from eager-owl-205 are summarized below).What recovery found
artifacts/bmc/mtcollins1-host-capture.txt, attempt=3, Preserve mtcollins1 hardware-census and boot-path evidence #10965). It ran in the live environment (tmpfs workload, sr0 mounted), so no Curtin recut is needed. Its seed and program were never committed, and the medium's stock volume label shows the ISO wasn't built by any modeled route. The capture program here is therefore a reconstruction from that file's ENVELOPE/SECTION/ARGV/EXIT lines, and it is labelled as one.extdeps.provisioning.ubuntu_seeded_install_media{,_remaster}, the xorriso-boot_image any replaythat keeps the arm64 El Torito/ESP boot intact (srv4 fleet subsumption + BMC virtual-media install path + modeling cleanup #7027), used by srv3. A standaloneCensusImageBuildInputwould have been a second authority (§3). Parent ruled (A): generalize it, and rewire srv3 in the same change (root cut, no two representations).The change
extdeps.provisioning.ubuntu_seeded_install_media:UbuntuSeededInstallMediaBuildInput. The payload is a parameter (rendered user-data plusNoCloudSeedFiles); the volume id is a parameter; dates are pinned; the stem and builder revision are fields. Every field reachesseeded_install_media_build_key. Identity is measured:UbuntuSeededInstallMediaBuilt { build_key, output_digest, image_name }, whereimage_name = <stem>-<first 16 hex of the output sha256>.iso.…_remaster:seeded_install_media_stageverifies the stock sha256 before building (the upstream digest). It then extracts, writes the seed, patches grub, runsxorriso.Iso.ReplayBuildPinnedDates(-volume_date uuid/all_file_dates, so identical inputs reproduce identical bytes), and reads the digest off the written file. The old sidecar, the input-hash identity and the rebuild-in-place-when-stale path are deleted.gunbc.seeded_install_media_publish:publish_seeded_image/resolve_seeded_image.BmcExportBoundary(admitted against the export's ownership requirement) andHostArtifactsDirectory.gunbc.machine_intake_boot_image_fetch: the stock fetch's publish is now create-only too (BootImagePresentWithDifferentDigest).boot_image_published_pathis the single composition of export dir + name.gunbc.machine_intake_host_capture_envelope: one grammar, read in both directions (§4). The stage roster and framing are declared once; the program renderer and the verdict parsers read the same rows.gunbc.machine_intake_mtcollins1_census_image:mtcollins1_seeded_image_input(stages, stem, volume_id)applied to the census roster.early-commandsruns/cdrom/gunbc-census/capture.shwithinteractive-sections: ["*"]. If the power-off fails, the unit waits at the installer and no unattended storage step is reachable.autoinstall "ds=nocloud;s=/cdrom/gunbc-census/" console=ttyAMA0,115200, labelGUNBC_MTC1_CENSUS_2404_3.mtcollins1_census_image_publishbuilds from the stock medium in/srv/bmcand publishes into the same export.ActuatorStepImageUnresolved). The install diagnostic compares measured sha256 to measured sha256. Two predicates that had no consumer and existed only over the deleted static path are removed.Witnesses
test.claim.mtcollins1_census_image(hermetic, supplied captures):sync, then the halt;test.claim.mtcollins1_census_image_local_wet(the inhabitance half, local-wet lane, triple-enrolled): the attempt=3 capture parses under the reconstructed grammar; the renderer's program executed undershparses back, including a nonzero stage exit and shell quoting.Declared frontiers (not in this PR)
mtcollins1_census_image_publishruns on srv2 through the fleet-converge workflow (host=srv2), building and publishing in the same job so the image never leaves the host that serves it. The wet byte-level controls run there: rebuild twice gives the same digest, and changing one seed byte gives a different digest. Hermetic CI has no stock ISO or xorriso; the derivation key's sensitivity is what is witnessed here.gunbc.machine_intake_host_capture_envelope, and the verdict REDs (begin without end, nproc ≠ 160, 160 elsewhere, CE/UE > 0, write failure, media) land in approval loop D: converge materialization, loopback bind, mtcollins1_boot mode #11484's witness.mtcollins1_census_machineis the envelope's machine name; approval loop D: converge materialization, loopback bind, mtcollins1_boot mode #11484'smtcollins1_boot_machineshould import it rather than restate it.gunbc.bmc_virtual_mediasrv4_virtual_media_source) names a hand-built ISO by literal path. No srv4 build input exists, so it is outside this derivation rather than a second representation of it. Flagged, not changed.endby callingmtcollins1_seeded_image_inputwith an extended roster. That gives a different image with its own digest and name; the signed boot subject binds only the census image.🤖 Generated with Claude Code