Skip to content

YAML ingest/emit: bounded-subset correct-meaning contract; retire the action-use line projection - #11730

Merged
gunbai-bot[bot] merged 34 commits into
mainfrom
session/still-lynx-398
Sep 24, 2026
Merged

gunbai-bot[bot] merged 34 commits into
mainfrom
session/still-lynx-398

Conversation

@gunbai-bot

@gunbai-bot gunbai-bot Bot commented Sep 19, 2026 •

Copy link
Copy Markdown
Contributor

Summary

extdeps.languages.yaml was an emit-only projection with a reader that reinterpreted whatever it did not model as a string. This makes the pair a bounded-subset reader/writer with a correct-meaning contract: every document the reader accepts has its correct YAML 1.2.2 meaning within a declared subset, and everything outside that subset is refused with a located reason — never reinterpreted, never silently dropped. The writer is the same contract turned around: for every value it emits, ingest_yaml_source(emit(v)) == v, and a value it cannot write that way is refused with the path to it.

That then makes the reader affordable enough for gunbc.action_use_admission's census to read every committed .github/workflows file through it, which is the trigger that retires the line projection realized_workflow_action_uses and its dissolution row realized_workflow_projection_frontier_rows. Both are deleted here.

Every wrong-meaning case in the source audit (#11663, comment 5743133113) is fixed and each has a claim with a red control:

  • plain scalars resolve under the core schema (123 is an int, yes is a string) and unrecognized text no longer silently becomes a string;
  • flow sequences split on commas outside quotes ([a,b] is two elements; ["a, b", c] is not split inside the quotes);
  • single quotes are dropped and '' decoded; double-quoted escapes decode and an invalid escape like \q refuses;
  • mapping keys are decoded, and a plain key the core schema reads as a non-string refuses;
  • flow mappings are read as mappings, not strings;
  • | clips to exactly one trailing newline, |- strips, |+ keeps; empty lines inside a literal are kept (the emitter used to filter them out — a semantic loss).

Why the witnesses are new rather than edited

The old ingest claims compared serialize(parse(x)) == serialize(expected), so a loss in the writer hid a loss in the reader — the "blank lines are kept" test could not fail for that reason. The old round-trip helper compared emit(parse(emit(v))) == emit(v), which a type change (YamlString "123" → YamlInt) passes. Both comparisons are gone:

  • test.claim.yaml_ingest_witness — 24 claims comparing ingest_yaml_source(text) against a hand-written value, one construct at a time, each paired with a refusal that must name its line and its reason.
  • test.claim.yaml_emit_witness — 9 claims comparing decoded structure, ingest_yaml_source(emit(v)) == v, over 39 tricky strings and 13 multi-line strings as values, keys and flow entries.

Refusal travels rather than being swallowed

serialize_yaml became emit_yaml -> EmittedYaml | YamlEmitRefused { path, reason }, so the five workflow generators, the compiler gate, and the srv3 seeded-install-media chain carry a typed outcome to their consumers instead of a string. gunbc.required_ci_epoch_observation's RequiredCiEpochDuplicated arm is deleted — the reader now refuses a duplicate mapping key, so that state is unreachable (DESIGN §4b: dissolution on climb).

The budget: what was cut, what the floor is, and why this PR is held

Judged against a line, not a point. .github/workflows/fleet-converge.yml is now 135,149 bytes, up from 89,935 when this reader was first fitted. It is a generated file other lanes grow, so a flat budget turns this required claim red on someone else's change. On merged main the claim measured 95,843 against the flat 72,300.

After the cuts below it measures 76,337. That is the measured floor of every remedy the cost standing admits, and it is still over the flat budget. A 2026-09-23 ruling admitted a per-entry allowance for claims whose subject is a whole corpus file. The ruling is an operator default-approval on timeout, not a deliberated ruling. #12134 landed that allowance: budget = base + per_entry × entry_count, where the census's own parse derives the count, and a claim over the per-entry rate still goes red. This PR adds the census to v2.workflow.required_floor corpus_census_roster.

Measured at this head: 1,140 entries, derived budget 101,200, census 82,717 steps. That is about 18% margin, and about 72.6 steps per entry against the declared 80. realized_census_cost_standing now names that judge and records the model as ruling-admitted. "Raising the claim's eval-step budget", per-entry rate included, stays a refused remedy.

What was cut (real work, never the population).

  • The reader's accepted-path block walk is rewritten, not added to. yaml_entry returns the pair a mapping holds. It reads one-line, nested and literal entries directly and hands every other chunk to yaml_entry_general. That function is now the only refusal reading: the separate multi-line read dispatcher and yaml_literal_entry are deleted.
  • Each routing decision is a function of exactly what it reads, so a shape the document repeats is decided once:
    • an entry's first line (yaml_first_line_route)
    • a sequence item's head (yaml_item_head_opens_mapping)
    • a block's indentation (yaml_indent_marks)
    • a mapping's key sequence (yaml_key_sequence_is_clean, with an exact per-key fallback when a decoded key holds a control character)
    • a flow sequence's inner text (yaml_flow_inner_is_plain)
    • a literal's leading whitespace (yaml_line_lead)
  • The census traversal's own cost shape. realized_jobs_reading flattens each job into its use readings in document order. It no longer threads a stop flag through every step or copies the accumulated uses at every use; the first refusal in that order is the one the stopping scan reported. realized_distinct_uses pushes instead of copying.
  • gunbc.action_use_admission realized_census_cost_standing's remedy now names both repairs.

Repeated-shape slope. Measured over workflow step items of one shape with distinct content per repetition, between 20 and 40 items. Identical repetitions are memoized by the evaluator and read as nearly free, which makes a naive repeated-shape measurement misleading. The cost per added step item went from about 1,013 to about 830 steps.

Why the floor is where it is. Every evaluated expression node costs one step. The remaining cost is per distinct line and per block, and each is near its node floor:

  • the one-line entry path: about 45 steps per distinct line
  • block setup: about 35–50 per block
  • yaml_lookup's per-field filter: about 4 per field

Going well under 72,300 would need a new string builtin, which is Rust seed growth and not done here, or one of the standing row's refused remedies. The subject also keeps growing, so any constant cut is spent again.

The instrument, not the figures. Every number here is re-derived by claim_batch --source-root dag --source-root src/v2 --entry dag/test/claim/action_use_admission_witness_test.dag --functions census_fleet_converge_uses_are_modeled_and_executed_exactly, read from its [witness] line. The per-component split came from a temporary per-line step counter in the seed interpreter. It was a local instrument only and is not committed.

The std.types predicate

std.types commit_sha_text_holds is respelled as sixteen whole-string removals. Both that and the per-character spelling are linear, so this buys a constant factor in the interpreter, not a cost-shape repair (review 70343). The comment says so, and it names the dissolution trigger: the per-character evaluation cost fixed at its source. It was admitted by an operator ruling (stern-carp-604, 2026-09-20), not by this diff. test.claim.std_commit_sha_text_witness keeps the per-character spelling as an oracle, with a failing case for each refusal cause.

What CI establishes

The floor's whole-blob dag/std/types.dag kernel guard used to refuse this PR's changed-witness planning. That refusal was a defect, and #12087 fixed it; this branch integrates main after #12087. The floor now plans and runs the changed witnesses. Two things it found on this branch:

emit-build's E0573 PointerWidth red is inherited from main and owned by #12070.

Test plan

Run with a seed built from this tree:

  • claim_batch --entry dag/test/claim/yaml_ingest_witness_test.dag: 31/31
  • claim_batch --entry dag/test/claim/yaml_emit_witness_test.dag: 11/11
  • claim_batch --entry dag/test/claim/action_use_admission_witness_test.dag: 34/34, with the census claim at 82,717 against its derived budget of 101,200
  • claim_batch --entry dag/test/claim/corpus_census_allowance_witness_test.dag: 5/5
  • claim_batch --wet --entry dag/test/claim/srv3/srv3_seeded_install_media_real_execution_witness_test.dag: PASS
  • src/v2/test/claim/local_repo_wet_terminal_test.dag: all pass
  • gunbc run --entry dag/gunbc/instruments/generated_artifact_gate.dag --function main: no drift

Landing-checklist evidence added:

  • Route test over a real workflow. a_real_uses_line_respelled_outside_the_subset_refuses_and_respelled_inside_it_reads_the_same rewrites heal-publish.yml's first uses: line into five spellings.
    • A flow sequence, an alias and an empty value must each make the file unreadable, never an empty or unchanged population.
    • A quoted key and a spaced colon are the same YAML key, so they must read exactly the original population. This differs from the checklist, which listed them as refusals: refusing them would give a valid spelling the wrong meaning, which is the defect this reader replaces. quoted_escaped_and_spaced_uses_keys_are_read_and_script_text_is_not already pins that meaning.
    • A mutation moving quoted_key into the must-refuse set turns the claim red.
  • Block scalars against an independent reader. literal_{clip,strip,keep}_chomping_matches_the_independent_reader_for_every_trailing_blank_count cover |, |- and |+, each with 0, 1 and 3 trailing empty lines, at document end and before a following key, over a body with a more-indented line. All 18 expected values were produced by the npm package yaml v2 parsing the same bytes as YAML 1.2, and are written as literals.
  • No dag/test/claim/scratchprobe/* residue: the repeated-shape probes were local and are deleted.

🤖 Generated with Claude Code

…jection scaffold on its carrier; close two projection holes

extdeps.languages.yaml.ingest:
- YamlLine table: each line's indent, text and ignorability computed once, read
  by every parse function (was re-derived several times per line and per level).
- yaml_all_digits stops at the first non-digit by branching (the eager && recursed
  to the end of every plain value -- the operand-demand divergence recorded as
  realization_arms_diverge_on_whether_the_program_refuses).
- block literals collected as a slice (end found by one field test per line).
- mapping/sequence loops fetch the line record once per iteration.
Measured (claim_batch eval_steps): witnesses.yml 127,947 -> 58,073;
fleet-converge.yml 296,572 -> 138,484 (budget 72,300 per claim).

gunbc.action_use_admission:
- realized_workflow_projection_frontier_rows marks the line projection as the
  operator-approved scaffold (#11663) with its dissolution trigger,
  folded by gunbc.census_closure_frontier.
- uses-key detection ignores whitespace before the colon (`uses  :`), and a quoted
  key carrying an escape refuses (`"us\u0065s":`) -- the projection cannot decode it.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
gunbc-ci-auto-heal and others added 9 commits September 20, 2026 00:15
…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>
# Conflicts:
#	.github/workflows/fleet-converge.yml
#	.github/workflows/heal-publish.yml
#	.github/workflows/witnesses.yml
#	dag/extdeps/languages/yaml/ingest.dag
…e reader keeps `.inf`/`.nan` numeric

WHY THIS FOLLOWS THE READER/WRITER CHANGE. emit_yaml refuses a value it cannot write with its
meaning, and gunbc.os_install_emit autoinstall_user_data renders cloud-init's user-data -- bytes that
are written into the seeded ISO's NoCloud seed AND hashed into the media's identity. So the refusal
has nowhere to be absorbed: a document the writer will not write leaves no media to name (parent
ruling on #11730, arm A: carry it as a typed outcome to the consumers).

WHAT NOW CARRIES IT
- gunbc.os_install_emit autoinstall_user_data returns AutoinstallUserData = Rendered | Refused, the
  refusal naming the value's path through yaml_emit_refusal_text.
- gunbc.srv3_seeded_install_media_artifact: srv3_seeded_install_media is Srv3SeededInstallMedia =
  Derived { artifact } | Refused { reason }. The body-dependent rows (the user-data body, the content
  hash, the artifact row) live INSIDE the derived arm, because each is a function of the rendered
  bytes.
- THE INSTALL PATH STAYS TOTAL, and that is a modelling fix rather than a workaround: the seeded
  media's file name is made of the stock point release and the host it seeds, neither of which is
  seeded content. extdeps.provisioning.ubuntu_seeded_install_media now names those two facts
  (ubuntu_seeded_install_media_install_path_for / _filename_for) and the row-taking spellings are
  derived from them, so srv3's install path -- which the NBD serve intents, the actuator scope and the
  diagnostic all read -- no longer depends on a derivation that can refuse.
- gunbc.host_effect_realize refuses the remaster into NotConverged with the derivation's reason;
  gunbc.srv3_os_install_diagnostic exposes srv3_os_install_attempt() = Intended { intent } |
  Unavailable { reason } over srv3_os_install_attempt_intent_for, so no intent names the content hash
  of something that was never written; gunbc.generated_artifact_emit routes the refusal into
  ArtifactGenerationRefused, which it already had.

THE DIAGNOSTIC WITNESS SUPPLIES ITS HASH AND INTENT AT THE BOUNDARY. Its claims discriminate the
diagnostic fold over an observation, not the media's derivation, so deriving the pair per claim would
re-execute the renderer and the hash once per claim (DESIGN section 3's standing rule). The pairing
obligation is one claim that runs the REAL route --
the_production_attempt_intent_carries_the_derived_media_hash -- joining the production derivation's
hash to the production intent's, and asserting the rendered body is a cloud-config.

A DEFECT MY OWN CONFORMANCE CLAIM CAUGHT, worth recording because it is this change's own failure
class. While cutting the reader's cost I let the numeric fast path skip the core-schema word map --
but `.inf`, `.nan` and their signed spellings START with numeric characters, so `.NaN` came back a
string: a bounded reader reinterpreting what it does model. core_schema_resolves_null_bool_int_float
went red on the spot. yaml_resolve_numeric_grammar now consults the word map on its miss path, and
the word map stays the single authority for those spellings.

MEASURED AFTER MERGING main, whose fleet-converge authority grew the largest committed workflow from
912 to 973 lines: the census claim over it is 70,897 eval steps against the 72,300 new-witness budget
(claim_batch on test.claim.action_use_admission_witness). The margin is 1,403 steps, about 2%, and it
is honest to say that is thin: the next growth of that workflow's authority will need another cut at
the reader's per-entry cost, which is where 619 of those entries are paid. Cuts that landed here:
chunking a block without the sentinel pass when it holds no deeper line, reading a nested `key:`
before splitting the line, one indentation test per block instead of two, and screening a literal's
blank lines instead of counting them per line.

main's `first`/`last` now return an optional (#11626), which the reader reads as
`join(xs.take(n: 1), "")` -- that element or "" -- rather than unwrapping an optional per line.
main's new gunbc.compiler_gate_workflow, which now emits witnesses.yml, routes the writer's refusal
like the other generators; the census claims name the actions each file actually carries after that
move (checkout and setup-rust-toolchain in witnesses.yml, upload-artifact in heal.yml).

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…plan records the round-trip oracle names

The claim over the largest committed workflow sits a low single-digit
percentage under the floor's new-witness budget, and its subject -- a
generated workflow -- grows from authorities other lanes edit. That is a
standing fact about the claim, not a fact about this change, so it is
recorded on gunbc.action_use_admission realized_census_cost_standing with
the instrument that re-derives it, the remedy (cut the reader's per-entry
cost, where the ~619-unit largest file spends it), and the remedies that
are refused: a raised budget, a second reader, a declared cost drop, or
dropping a file from the census. A witness joins the row's subject to a
file the census actually reads.

gunbc.plans.emission_ingestion_inverse said yaml was emit-only and failed
the round-trip oracle. It no longer is: the reader reads a declared
bounded subset, the writer decides its shapes through that reader's own
predicates, and test.claim.yaml_emit_witness holds ingest(emit(v)) == v
over decoded values. The record now says so, and says what it still does
not buy -- the writer is a shared reading of the subset, not a row-driven
inverse.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
# Conflicts:
#	.github/workflows/fleet-converge.yml
#	.github/workflows/witnesses.yml
#	dag/gunbc/witness/compiler_gate_workflow.dag
# Conflicts:
#	.github/workflows/heal-publish.yml
#	.github/workflows/heal.yml
#	.github/workflows/witnesses.yml
#	dag/gunbc/witness/compiler_gate_workflow.dag
main's #11791 grew .github/workflows/fleet-converge.yml, and the census
claim over it measured 74,002 eval steps against the new-witness budget of
72,300 -- over. gunbc.action_use_admission realized_census_cost_standing
names the only admissible remedy for exactly this, and refuses the others:
cut the reader's per-entry cost, never raise the budget, add a second
reader, or declare a drop. This is that cut. It is 74,002 -> 70,436,
measured per step by claim_batch over the same claim.

WHERE THE COST WAS, MEASURED RATHER THAN GUESSED. A scratch probe parsed
documents of one repeated shape each and divided: a one-line `key: value`
entry costs about 87 eval steps, a two-line step mapping under a sequence
about 243. The committed workflows are mostly step lists, so the sequence
and multi-line paths carry the claim, not the one-line path. Two of the
four cuts below were aimed at the one-line path before that probe ran and
returned 1,828 and 30 steps respectively; the probe is why the last two
went where they did.

The cuts, in the order they were measured:

- ONE MAP LOOKUP FOR THE KEY'S START, replacing a scan of the refused
  starts plus an unconditional core-schema word lookup. Only the six
  starts a core-schema word can begin with consult the word map, and the
  value half is not computed until the entry is known to have one `: `.

- NESTED IFS WHERE THE TESTS WERE CONJOINED. `&&` and `||` evaluate both
  sides, so `yaml_entry_multiline` paid all five of its tests to learn
  what the first already decided -- on every literal block and every
  sequence item. The order is now cheapest-and-most-selective first.
  (The eager-`&&` question itself belongs to gunbc.recurring_failure_mode
  realization_arms_diverge_on_whether_the_program_refuses; this module
  only stops depending on short-circuiting it does not have.)

- ONE PASS INSTEAD OF THREE over each block's entries and items. Both
  block folds built an intermediate list of results that the accepted path
  -- every chunk of every committed workflow -- never inspected, so that
  the refusal walk could be handed it. The refusal walks now re-read the
  chunk they are about to refuse on, and a refused sequence item is
  detected the way a refused mapping entry already was: from the join
  sentinel it produces, which no accepted scalar can hold because the
  reader refuses U+0001 anywhere in a document.

The contract is unchanged and is still established by execution: the 24
ingest conformance claims, the 9 emit round-trip claims and all 33 census
claims pass, each red control still red.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The row named the one-line entry path as where the next cut goes. A probe
over documents of one repeated shape each says otherwise: the committed
workflows are step lists, and a two-line step mapping under a sequence
costs about 243 eval steps against about 87 for a one-line entry, so the
sequence and multi-line paths carry the claim. An authority that points a
future reader at the wrong path is worse than one that says nothing, so
the row now names the measured paths and tells the next author to
re-measure rather than trust the sentence.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@gunbai-bot
gunbai-bot Bot marked this pull request as ready for review September 20, 2026 09:26
gunbc-ci-auto-heal and others added 2 commits September 20, 2026 10:00
…rkaround at it

Review 69056 approved this PR and named one thing worth fixing: the
sixteen nested `replace` calls in std.types commit_sha_text_holds route
around a language-layer cost -- one interpreter evaluation per lambda in
`all(chars(...))` -- in the most-shared type module, with no row anywhere.
That is DESIGN section 4b(2): a class below its ceiling with no named
trigger, so it never ranks for climbing.

The row is its own class rather than a receipt on
nested_membership_scan_where_a_map_primitive_exists, because that class is
a QUADRATIC shape repaired by a better data structure. Here both forms are
linear and the program's shape is already correct: only the evaluator's
constant differs, so there is no algorithmic defect to point at and the
repair is in the evaluator, not the module. The row carries a second
instance from this same change -- the `&&` chain in the YAML reader
re-authored as nested ifs -- which is what makes it a class rather than an
incident, and its trigger names the capability that returns
commit_sha_text_holds to the form that says what it means.

The declaration now names the row instead of only explaining its own cost.

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

Review 69075: the cost standing carried "about 87 eval steps" and "about
243" in a NonEmptyStr data row and in its comment, twelve lines after the
same row asserts that the numbers are not transcribed because DESIGN
section 6 says to name the instrument. That is the section's own failure
mode, and the reviewer is right that it makes the row's advice rot the
moment the reader changes.

The figures are gone from both places. Deleting them alone would have
left the remedy unable to say WHICH path to cut, which is the thing the
row exists to say -- so the probe that produced them is now a committed
instrument, test.probe.yaml_shape_cost_probe, and the remedy names it and
says to run it before cutting. The probe parses documents of one repeated
shape each, so the difference between two readings says which path a
corpus of that shape spends in.

That instruction is not ceremony: the first two cuts made against an
unmeasured guess about which path carried the cost returned almost
nothing, and this probe is what redirected them. The probe also records
the trap that caught its own first version -- repeated keys are a
duplicate, so a naive generator measures a refusal rather than a read.

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

gunbai-bot Bot commented Sep 20, 2026

Copy link
Copy Markdown
Contributor Author

Both findings in review 69075 are correct. One is fixed; the other is escalated rather than decided by me, which is the point the review makes.

Transcribed figures — fixed in 2e8e65c

The row asserted it did not transcribe its numbers twelve lines after transcribing them. Deleting them alone would have left the remedy unable to say which path to cut, which is the thing the row exists to say — so the probe that produced them is now a committed instrument, test.probe.yaml_shape_cost_probe, and the remedy names it and says to run it before cutting. That instruction is not ceremony: my first two cuts were aimed at the one-line entry path on an unmeasured guess and returned almost nothing; the probe is what redirected them to the sequence and multi-line paths.

std.types — escalated, not self-admitted

The review is right that the diff does both halves of what DESIGN §5 separates: it lands the workaround and writes the row admitting it. I have not tried to resolve that by arguing in the diff. I took the review's other option first — "a different cut" — and it did not reach:

attempt result
key start-class map + hoisted value split −1,828
nested ifs for eager && on the multi-line path −883
one pass instead of three in both block folds −825
short-circuiting chunk/item/value predicates −30
scan_to_eol for first-line extraction not callable — contract row in std.primitives, no interpreter declaration
index_by for the key map not bound for List<YamlKeyValue> (the known index_by registry algebra gap)
consolidating yaml_entry_general onto shared helpers +1,135 — reverted

The last row is the useful one: an interpreted call costs its arguments and its body, so factoring a hot path into shared helpers loses. That is why the two key predicates in the reader deliberately do not call each other.

Measured, reproduced, against the 72,300 new-witness budget: 70,436 with the std.types spelling, 73,754 without it — over by 1,454. The spelling is worth 3,318 steps at two different merge bases.

I also corrected a figure of my own: the PR body said 69,496. That reading was taken at an earlier merge base and I could not reproduce it; the reproducible pair is the one above, and I will fix the body.

One hypothesis falsified cleanly, since it is the interesting part. I expected the eager && in commit_sha_text_holds — head.length() == 40 && all(chars(...)) — to be walking forty characters for every @v4 tag. Guarding it with a nested if changed the figure by zero: every ref this census validates is already forty hex, because the admission requires commit pinning. The per-character walk is genuine work, not waste, so there is no free repair hiding there.

What remains is restructuring so a sequence item stops re-entering the full block setup for a two-line compact mapping. That is a real change to extdeps.languages.yaml.ingest with a yield I cannot bound in advance, and it deserves its own PR and review rather than being appended here.

So the choice — admit the std.types spelling externally with the filed row as its trigger, or hold this PR until that restructuring lands — is escalated to my parent. Per §5 the admission is not mine to grant in the diff that needs it, and if it is granted I will record on the carrier who granted it rather than leave the row reading as self-authorised.

Separate, and not part of that question

On the last green head the floor lane printed required-ci: FAILED PHASE floor refused ... ChangedWitnessObservationFailed with phases_failed=1, and step 8 still exited 0 — so the job and the aggregating lane both reported success. The cause is that editing dag/std/types.dag makes the base side unreconstructable, so the changed-witness sublane refuses to plan. The consequence worth noting here: on that head CI was not judging the budget claim this PR is about. I will confirm it reproduces before filing it as its own finding.

— sent from still-lynx-398

…an external ruling

Review 69075 refused this correctly: the diff landed a respelling of
std.types commit_sha_text_holds AND wrote the row admitting it, which
DESIGN section 5 separates -- an author who can write a scaffold can
equally write a row claiming it was approved. The admission is now
external (operator ruling, stern-carp-604, 2026-09-20), and it comes with
three conditions, all of which make the change stand on better ground
than it did.

THE JUSTIFICATION IS THE PREDICATE'S OWN COST SHAPE, NOT A BUDGET
SOMEWHERE ELSE. A per-character recursion in a hot, widely-shared
predicate is the bare-minimum-cost defect DESIGN section 6 makes standing:
it is fixed regardless of the realized n, because n is not a time-stable
fact. This predicate is what every caller admitting a pinned ref runs, and
nothing bounds how many refs a caller holds tomorrow. A claim budget
elsewhere in the tree fitting afterwards is a CONSEQUENCE, and the
annotation now says so and names what the spelling computes, so a reader
does not have to reconstruct "forty lowercase hex digits" from sixteen
replace calls.

THE EQUALITY IS THE CLAIM, AND IT IS HOMED IN STD. The new
test.claim.std_commit_sha_text_witness keeps the per-character spelling as
an oracle and claims the two answer the same on every input either can be
given, with a red per refusal cause: the lengths either side of forty,
uppercase, the characters adjacent to both ranges on both sides, and the
empty string. Nothing in that module asserts a step count -- a step count
is a property of the evaluator, and the contract is the answer. The
equality's red is reachable and was executed: respelling one stripped
character from `f` to `F` turns it red, so it discriminates rather than
decorating.

THE SELF-WRITTEN ROW IS DELETED, ruling cited in its place. The margin row
on gunbc.action_use_admission stands and is sharper: it now says the
remedy is the structural reader cut and that this is its own change --
each sequence item re-enters the whole block setup for what is often a
two-line compact mapping -- and it refuses one more remedy by name, so
this respelling cannot be read as a precedent for buying margin with a
second one.

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

gunbai-bot Bot commented Sep 20, 2026

Copy link
Copy Markdown
Contributor Author

Review 69118 read head 2e8e65c; e78927a is now pushed and changes two of its three legs at the root. The third — the empirical one — is the sharpest part of the review, and I ran it rather than argued it.

The measurement you asked for

either re-run the committed probe/claim_batch and show this predicate is actually load-bearing on the budget post-dedup, or restore the all(chars(...)) form

Both spellings, current head, minutes apart, after the realized_distinct_uses dedup that is in this same diff, against the 72,300 new-witness budget:

std.types commit_sha_text_holds census_fleet_converge
all(chars(...)), main's form 73,754 — over by 1,454, the required claim reds
sixteen replace calls 69,496 — under, 3.9% margin

So the hypothesis that dedup removed the pressure is falsified. You were right that the class row's own sentence ("forty lambda evaluations for every head on every admission") overstated it — after dedup it is roughly ten distinct heads per file, not every occurrence. But ten forty-character walks is still ~4,200 eval steps, which is more than the whole margin. The row that said "every admission" is deleted, so that overstatement goes with it.

I could not have shown you this by reading, which is the point your RUN IT BEFORE CUTTING citation was making — so thank you for insisting on it; it is now the reason the change stands rather than an assertion about it.

The two DESIGN legs

You were right on both, and neither is answered by argument:

  • the self-written row — per_element_lambda_cost_unrolls_a_predicate_into_scalar_operations.dag is deleted. An operator ruling (stern-carp-604, 2026-09-20) is cited in its place. §5 says approval is external to the diff; it now is, and the carrier records who granted it rather than leaving the row to read as self-authorised.
  • the comment declaring its own workaround status — rewritten. It no longer says "this is a workaround and is filed as one". It says what the predicate computes — forty characters, each a lowercase hex digit — and justifies the spelling on its own cost shape under §6's bare-minimum-cost rule: a per-character recursion in a hot, widely-shared predicate is fixed regardless of realized n, because n is not time-stable. The budget fitting afterwards is named as a consequence, not the reason.

What the change now owes, and pays

test.claim.std_commit_sha_text_witness (new, homed in std, not beside a caller) keeps the all(chars(...)) form as an oracle and claims the two spellings answer the same on every input either can be given — the lengths either side of forty, uppercase, the characters adjacent to both ranges on both sides, the empty string, a branch name. The equality is the contract; nothing in the module asserts a step count.

Its red is reachable and I executed it: respelling one stripped character from f to F turns the equality claim red. A green equality between two spellings of the same function would otherwise be decoration.

On the remedy pointing elsewhere

You are right that test.probe.yaml_shape_cost_probe points the census remedy at the reader's per-entry cost, and that remedy is unchanged — four measured reader cuts are in this PR, and the cost standing still names the structural reader cut, its own change, as what happens next. The predicate is a separate fix admitted on separate grounds; it is not the census remedy and the carrier now refuses, by name, respelling another shared predicate to buy margin.

— sent from still-lynx-398

Review 69135 found that dag/test/probe/yaml_shape_cost_probe.dag carries
no imports while naming five things from other modules, in a directory the
floor excludes from strict resolution -- so nothing would ever tell me.
Checking it turned up a second defect the review did not reach: the
committed file has NO `test` markers at all. Floor discovery and
claim_batch both key on that marker, so the tool this row named as the way
to run the instrument reported nothing whatsoever and exited 0. The
artifact designated as the authority for the census-cost remedy could not
produce a measurement.

The repair is not to add the imports. dag/test/probe/ is documented as
MUST-NOT-RESOLVE: every module there is a designed refusal, consumed as
SOURCE TEXT by gunbc.compile_diagnostic_census census_of(probe_source(..))
rather than as a module in a closure, and each declares that in its header.
A runnable instrument in that directory is wrong however well it is
spelled, and making it resolve would push it against the convention the
exclusion exists to protect.

So it is deleted. What review 69075 actually asked for -- stop
transcribing figures, name what re-derives them -- still holds, and the
row still carries no numbers: it names claim_batch against the floor's
budget, which is a live entry point, and states the METHOD for locating
the expensive path in one sentence. DESIGN section 6 draws the line at
whether a measurement is worth an entry point; this one is re-derived in
minutes from the claim vocabulary that already exists, so it is a method
and this row now says so, including why no probe stands beside it.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@briansrls
briansrls added this pull request to the merge queue Sep 20, 2026
@briansrls
briansrls removed this pull request from the merge queue due to a manual request Sep 20, 2026
gunbc-ci-auto-heal and others added 2 commits September 20, 2026 15:16
Review 69151: the claim named "every executed workflow file has a census
claim" only joined the hand-authored roster to the directory listing. It
never looked for the per-file claim. The hole has exactly the shape this
census exists to close: a lane adds .github/workflows/new.yml, the claim
reds, the author adds the NAME to the roster, the claim greens -- and that
file's `uses:` are admitted by nobody while a claim asserting per-file
coverage reports SUCCESS. A silent widen (DESIGN section 5) under a name
the evidence did not establish (section 4b rung honesty).

The claim now reads this module's own test declarations through the
floor's own scanner -- v2.workflow.floor_naming_hygiene
floor_discovery_scan_test_decl_names, the same producer floor discovery
uses, rather than a second scanner minted here -- and requires, for each
rostered file, a claim under the name that file derives. Adding a roster
row without its claim reds.

PROVEN BY EXECUTION, because a coverage claim whose red nobody has seen is
the thing under review here: renaming census_heal_uses_are_modeled_and_
executed_exactly so heal.yml keeps its roster row and loses its claim
turns this claim RED, and the rest of the file stays green (32 pass, 1
fail, and the one failure is this claim). Restored, it is green at a cost
well inside the new-witness budget.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
# Conflicts:
#	.github/workflows/fleet-converge.yml
#	dag/extdeps/languages/yaml/ingest.dag
#	dag/gunbc/action_use_admission.dag
#	dag/gunbc/recurring_failure_mode/provider_substituted_action_runtime.dag
#	dag/test/claim/action_use_admission_witness_test.dag
@briansrls
briansrls added this pull request to the merge queue Sep 20, 2026
@github-merge-queue
github-merge-queue Bot removed this pull request from the merge queue due to failed status checks Sep 20, 2026
@gunbai-bot

gunbai-bot Bot commented Sep 20, 2026

Copy link
Copy Markdown
Contributor Author

Status: held, not abandoned. The authoring session (still-lynx-398) archived in the wind-down and this PR re-homed to me. I am recording its exact state rather than forcing it in, because it cannot land honestly today. Two independent reasons, both measured:

1. The census claim is over its ceiling at this head. census_fleet_converge measured 69,496 eval steps before the last main merge and 73,335 after, against the 72,300 new-witness budget. Nobody touched this lane; merging main grew .github/workflows/fleet-converge.yml from 1041 to 1100 lines through #11565, #11607 and #11788. The four green checks above are not evidence to the contrary: on this branch the floor's changed-witness sublane refuses (ChangedWitnessObservationFailed, because the PR touches dag/std/types.dag) and the lane still exits 0 — the fail-open that #11861 fixes. Landing on that green would ship a claim that reds the moment #11861 lands.

I had approved exactly one bounded cut for this (the sequence/multi-line path the measurement already located, ~1,035 steps needed). It was never made before the session archived.

2. Merging main now conflicts with a concurrent rewrite of the same subject. #11731 (CENSUS-IMAGE 0A) landed the seeded-image derivation and rewrote the srv3 chain this PR's emitter-refusal plumbing was written against: 26 conflict hunks across 8 files, including dag/gunbc/host/host_effect_realize.dag and the srv3 install-media modules. That is not a textual resolution — it means re-deriving where the writer's refusal travels in #11731's design. I aborted the merge rather than guess in a chain that reaches real machine state.

What is done and worth keeping (all on this branch, checks green): extdeps.languages.yaml as a bounded-subset reader/writer with the correct-meaning contract; every wrong-meaning case from the #11663 source audit fixed and witnessed by decoded-structure comparison, each construct with a red control, verified by planting four reader and three writer defects and watching each turn its own control red; the action-use line projection and its frontier row deleted, with the census reading all six committed workflows through ingest_yaml_source, one claim per file joined to the directory listing by identity.

What the next session must do, in order: rebase onto main after #11875 (the parse repair) lands; re-derive the writer's refusal path against #11731's seeded-image design rather than re-applying this branch's srv3 hunks; make the one bounded reader cut and re-derive the census cost with claim_batch eval_steps over ingest_yaml_source on the largest committed workflow; land only when that claim is inside its ceiling with real margin — never by raising the budget, splitting the claim, or restoring a second reader.

Carried as roadmap node action-use-yaml-reader-contract (#11857), with the margin residue as workflow-census-claim-budget-margin.

— sent from stern-carp-604

@gunbai-bot
gunbai-bot Bot marked this pull request as draft September 20, 2026 18:57
gunbai-bot Bot pushed a commit that referenced this pull request Sep 21, 2026
Operator wind-down (2026-09-20): step back to v1 performance and v2 migration;
record progress and remaining items as project items.

- action-use-yaml-reader-contract: the bounded-subset YAML contract and the
  deletion of the action-use line projection (#11730, held).
- required-lane-exit-on-refused-phase: the required lane exits 0 on a refused
  phase, with runs 35503853026 and 35510547600 as receipts (#11861).
- workflow-census-claim-budget-margin: cut the reader's per-entry cost so the
  census is not one unrelated workflow edit from red.
- action-runtime-epoch-observation: nothing reads the epoch date against a clock,
  and a runner-host override is unobserved.
- namespace-relocation-batch-grain: one relocation should not cost one admission
  file per consuming declaration.

ROADMAP.md regenerated through gunbc.roadmap_authority expected_roadmap_md.

HISTORY NOTE: this branch is rebuilt on origin/main. The previous head carried a
merge made with -s ours, which recorded main as merged while keeping this side of
every file -- silently reverting main's changes in 17 unrelated files. That merge
is discarded rather than fixed forward, so nothing of main's is lost.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
gunbai-bot Bot pushed a commit that referenced this pull request Sep 21, 2026
Operator wind-down (2026-09-20): step back to v1 performance and v2 migration;
record progress and remaining items as project items.

- action-use-yaml-reader-contract: the bounded-subset YAML contract and the
  deletion of the action-use line projection (#11730, held).
- required-lane-exit-on-refused-phase: the required lane exits 0 on a refused
  phase, with runs 35503853026 and 35510547600 as receipts (#11861).
- workflow-census-claim-budget-margin: cut the reader's per-entry cost so the
  census is not one unrelated workflow edit from red.
- action-runtime-epoch-observation: nothing reads the epoch date against a clock,
  and a runner-host override is unobserved.
- namespace-relocation-batch-grain: one relocation should not cost one admission
  file per consuming declaration.

Rebuilt on current main (other lanes keep appending nodes at the same point);
ROADMAP.md regenerated through gunbc.roadmap_authority expected_roadmap_md.
Verified like for like: main 51 PASS, mine 51 PASS, identical FAIL set, 0 errors.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
gunbai-bot Bot pushed a commit that referenced this pull request Sep 21, 2026
Operator wind-down (2026-09-20): step back to v1 performance and v2 migration;
record progress and remaining items as project items.

- action-use-yaml-reader-contract: the bounded-subset YAML contract and the
  deletion of the action-use line projection (#11730, held).
- required-lane-exit-on-refused-phase: the required lane exits 0 on a refused
  phase, with runs 35503853026 and 35510547600 as receipts (#11861).
- workflow-census-claim-budget-margin: cut the reader's per-entry cost so the
  census is not one unrelated workflow edit from red.
- action-runtime-epoch-observation: nothing reads the epoch date against a clock,
  and a runner-host override is unobserved.
- namespace-relocation-batch-grain: one relocation should not cost one admission
  file per consuming declaration.

Rebuilt on current main again (sixth time: other lanes keep appending nodes at
the same point). The five rows are byte-identical to the head verified at
d5dc91b -- main 51 PASS, mine 51 PASS, identical FAIL set, 0 errors --
and ROADMAP.md is regenerated on this head through expected_roadmap_md.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
gunbc-ci-auto-heal and others added 8 commits September 23, 2026 02:37
…kflow projections from their authorities

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…ost shape

Both spellings are linear; the gain is the interpreter's per-character
lambda cost. Say so, keep the operator ruling, and name the dissolution
trigger: that cost fixed at its source (review 70343).

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…te fleet-converge.yml from its authority

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
#11730 changed this file's import, so its identity entered the changed set
and the floor refused with changed_witness_planned_without_terminal_verdict
(run 35816045125): the file sat in bin_witness_wet_entries, which has had no
executing consumer since 2026-08-15. Reclassify it LocalRepoWetLane and enrol
it in local_repo_wet_schedule, as its sibling fetch file was on 2026-09-09.
Measured wet on this tree before enrolment: it holds.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…yed on their complete inputs

The accelerator walk returns the pair a mapping holds, reads one-line,
nested and literal entries directly, and hands every other chunk to the
general reading, which is now also the only refusal reading (the
multi-line read dispatcher is deleted). Each routing decision is a
function of exactly what it reads -- an entry's first line, an item's
head, a block's indentation, a mapping's key sequence, a flow sequence's
inner text -- so a shape a document repeats is decided once.

Measured with test-local repeated-shape claims (distinct content per
repetition) and a per-line step profile: census_fleet_converge
95,843 -> 76,936; slope 1,013 -> 830 steps per added step item. All
YAML ingest (26) and emit (11) witnesses unchanged and green.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
realized_jobs_reading flattens each job into its use readings in
document order instead of folding a stop flag through every step and
copying the accumulated uses at every use; the first refusal in that
order is the one the stopping scan reported. realized_distinct_uses
pushes instead of copying. The block split decides its chunks in one
expression. action_use_admission witnesses 33/33, yaml ingest 26/26,
emit 11/11.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…side the reader cut

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…g against an independent reader

a_real_uses_line_respelled_outside_the_subset_refuses_and_respelled_inside_it_reads_the_same
rewrites heal-publish.yml's first uses: line into a flow sequence, an
alias and an empty value (each must make the file unreadable, never an
empty or unchanged population) and into a quoted key and a spaced colon
(the same YAML key, so exactly the original population). A mutation
moving quoted_key into the must-refuse set turns it red.

The three literal_*_chomping claims cover |, |- and |+ with 0, 1 and 3
trailing empty lines, at document end and before a key, over a body with
a more-indented line; every expected value was produced by the npm
package yaml v2 parsing the same bytes as YAML 1.2.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…he fleet-converge census and record the allowance model

fleet-converge.yml is regenerated from its authority. The census over it is
rostered in v2.workflow.required_floor corpus_census_roster and judged
against corpus_census_eval_step_allowance: measured at this tree, the
census's own parse reads 1,098 entries, the derived budget is 97,840, and
the claim performs 76,337 steps (about 69.5 per entry against the declared
80). realized_census_cost_standing now names that judge and records the
per-entry model as ruling-admitted (stern-carp-604, 2026-09-23, operator
default-approval on timeout); raising the budget, its rate included,
stays refused.

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

@briansrls briansrls left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

APPROVED FOR MERGE on exact head be779362b29e1746c937fd3a71b1c1cd2357e1f7.

No additional direct-exit native bundle is required. The earlier direct-exit concern was specifically that piping claim_batch through a filter could preserve the filter's status instead of the producer's. That ambiguity is no longer carrying the merge conclusion: the exact-head required CI run completed successfully, and the required floor executed census_fleet_converge_uses_are_modeled_and_executed_exactly as a changed witness on the real acceptance path. It derived entry_count=1098, budget_steps=97840, then admitted the measured eval_steps=76337 — 21,503 steps of margin — under the separately merged #12134 per-entry authority.

The remaining checklist is discharged: #12087 restores truthful base reconstruction for the std.types edit; route controls prove unsupported forms refuse while quoted/spaced spellings of the same YAML key preserve the same action population; the 18 block-scalar cases are checked against the independent npm yaml v2 implementation; ingest/emit/action-census/allowance claim bundles are green; scratch probes are absent; GitHub reports CLEAN; and an exact-head source approval already exists.

A separate native wrapper around the same claim execution would duplicate the evidence route rather than close a remaining gap. This approval is for this SHA; a source change requires re-verdict.

@gunbai-bot
gunbai-bot Bot added this pull request to the merge queue Sep 23, 2026
@github-merge-queue
github-merge-queue Bot removed this pull request from the merge queue due to failed status checks Sep 23, 2026
…rge.yml from its authority

The merge queue ejected be77936 on generated-artifact agreement: main moved
that workflow's authority after the approved head, so the composed revision
carried stale generated bytes. This commit is the merge and the
regeneration only. Census at this tree: 76,804 eval steps against a derived
budget of 98,560 (1,107 entries).

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

gunbai-bot Bot commented Sep 23, 2026

Copy link
Copy Markdown
Contributor Author

Re review 70622, which asks the merger to confirm the commit_sha_text_holds ruling exists: it does. On 2026-09-20 at 11:34:25Z, this lane (stern-carp-604) sent still-lynx-398 a dashboard message answering its escalation ("Admit a std.types spelling change … or hold #11730?") with option A, as the external admission review 69075 asked for, with conditions. The comment's constant-factor wording was corrected afterwards, in response to review 70343. — sent from stern-carp-604

@gunbai-bot
gunbai-bot Bot added this pull request to the merge queue Sep 23, 2026
@github-merge-queue
github-merge-queue Bot removed this pull request from the merge queue due to failed status checks Sep 23, 2026
gunbc-ci-auto-heal and others added 2 commits September 23, 2026 20:29
…rge.yml from its authority

The merge queue ejected 676b743 on generated-artifact agreement again (#12011
changed that workflow on main after it). Merge and regeneration only. Census
at this tree: 77,869 eval steps against a derived budget of 101,200 (1,140
entries).

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

The accelerated block walk carried a refused entry, sequence item or flow
entry as a value holding U+0001 and found refusals by scanning for it. A
document whose decoded content legitimately held U+0001 (a double-quoted
\x01) was then refused as if an item had been: in-band signalling that
DESIGN section 5 forbids and the tell of this PR's own row
bounded_reader_reinterprets_what_it_does_not_model.

YamlEntryRead becomes YamlEntryAccepted | YamlEntryRefused { line, reason };
yaml_entry, yaml_item_read and yaml_flow_plain_entry return typed readings;
blocks find a refusal by counting accepted readings against chunks and
locate it in the readings already made (no re-read). yaml_block_pair,
yaml_entry_read and every sentinel comparison are deleted; U+0001 survives
only as yaml_line_join_mark, source-text punctuation no value, key or
refusal can hold.

Discriminating reds: a_decoded_u0001_is_content_as_an_item_a_value_and_a_key
fails on the previous reader and passes here;
red_a_flow_fast_path_refusal_is_typed_without_the_document_precheck calls
the flow readers directly. yaml ingest 31/31, emit 11/11,
action_use_admission 34/34, corpus_census_allowance 5/5. Census 82,717
eval steps (was 77,869) against a derived budget of 101,200.

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

gunbai-bot Bot commented Sep 23, 2026

Copy link
Copy Markdown
Contributor Author

Review 70673's finding is correct and is fixed at d8994b4: refusals are now a typed arm (YamlEntryAccepted | YamlEntryRefused { line, reason }, YamlBlockResult for items, YamlScalarResult for flow entries), blocks detect a refusal by counting accepted readings and locate it in the readings already made, and every U+0001 sentinel comparison is deleted. The sentinel was not only a structural risk: a valid document with a decoded \\x01 sequence item was refused as if an item had been — a_decoded_u0001_is_content_as_an_item_a_value_and_a_key fails on the previous head and passes now. U+0001 remains only as yaml_line_join_mark, source-text punctuation. Census: 82,717 eval steps vs derived budget 101,200.

— sent from tidy-ant-630

@briansrls briansrls left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

APPROVED FOR MERGE on exact head d8994b4df4a0710c485bc20f7da2a1e9ecbee6ef.

I re-reviewed the complete source delta from parent 983ac5aaa94d942d1e72a2da0102cd3f727d13c0; it changes only dag/extdeps/languages/yaml/ingest.dag and dag/test/claim/yaml_ingest_witness_test.dag. No source blocker remains.

The in-band refusal channel is removed end-to-end:

  • mapping entries now carry YamlEntryAccepted | YamlEntryRefused { line, reason };
  • sequence item readers carry YamlBlockResult;
  • flow-entry fast paths carry YamlScalarResult;
  • their aggregators derive accepted populations from those typed outcomes and scan the same outcomes for the first refusal.

No caller now compares a semantic key or value against U+0001, and no refusal is reconstructed by re-reading a value. The direct typed paths preserve first-refusal ordering and line accounting, and every accelerator delegates to the same canonical lower-level reader with the same arguments. U+0001 remains only as yaml_line_join_mark, private punctuation inserted into raw source after the document precheck; raw U+0001 is refused while decoded \x01 is ordinary semantic content.

The new decoded-U+0001 claim discriminates the former live defect across sequence item, mapping value and mapping key. The precheck-bypass red directly exercises the flow accelerators and establishes typed refusal without relying on whole-document screening.

Exact-head CI is fully green: compiler, clippy, both native emit-build targets, required floor, and aggregate witnesses. The floor completed measurement publication/adjudication and generated-artifact agreement. The corpus census is 82,717 steps against a derived 101,200-step allowance for 1,140 entries, approximately 18% margin.

Nonblocking metadata: the PR body still reports the prior 29/29 ingest count and prior 76,337/97,840 census. Refresh it to 31/31 and 82,717/101,200, and remove the stale “still open” line; a body-only edit does not move the source SHA.

This approval is exact-head scoped. Any subsequent source movement requires re-review.

@gunbai-bot
gunbai-bot Bot added this pull request to the merge queue Sep 23, 2026
Merged via the queue into main with commit 8197ed5 Sep 24, 2026
5 checks passed
@gunbai-bot
gunbai-bot Bot deleted the session/still-lynx-398 branch September 24, 2026 02:15
@briansrls
briansrls restored the session/still-lynx-398 branch September 24, 2026 02:16
gunbai-bot Bot pushed a commit that referenced this pull request Sep 24, 2026
…s YamlEmitRefused arm (main's #11730 replaced serialize_yaml)

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
gunbai-bot Bot pushed a commit that referenced this pull request Sep 24, 2026
Main's #11730 also changed std.types; the merge conflicted in both mirrors.
Regenerated by --required-regen from the merged .dag; a second regen is
byte-identical.

Co-Authored-By: Claude Opus 5.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