feat!: try a key's badges in order and stop at the first match - #75
Merged
Conversation
A badge's `match` is how a config says which values it wants, so a pattern that does not read the value is the config declining and not a badge falling short. Badges on one key are now a chain: each is tried in config order, the first to read the value draws, and the ones below it never run. A value no entry for the key reads draws nothing and reports nothing, whether or not those entries carry a `link`. That retires `Undrawn::Badge` and the row `no badge for <key>: no pattern reads this value`. It was written for a reader who had lost a reference, but it fires on every value a shared list was never meant to read — a `delivery_pr` badge reading `owner/repo#N` reports every bead carrying a URL or a bare number. A reader who does want to see every value of a key writes a last entry with a permissive pattern, which the existing schema already allows. `Undrawn::Link` and `Undrawn::Short` are unchanged. Those are a badge that read the value and then could not keep a promise its config made about the badge it drew, which is the case a reader cannot see for themselves.
A row carries one badge whether the chain stopped at the first entry that read the value or ran every entry and the others declined, so the choice between two entries on one key is invisible in a row and visible on a screen. This puts two entries on one key with the second permissive, and asserts the screen holds what the first drew and not what the second would have. Both assertions were checked against a weakened tree rather than left to read as passing. Disabling the fall-through guard fails the first. Making the second key's badge read its value and then fail its `link` puts that key's name back on the screen, which is what the second assertion looks for the absence of.
Shadowing existed to stop a project's entry and a shared entry both drawing for one value. First-match does that on its own, so replacing the shared entries for a key had no effect left except losing their shapes: a project naming `delivery_pr` to add a bare number stopped reading the qualified form the shared list already read. So `Config::badges_for_project` no longer replaces anything. A project's entries for a key stand where the first shared entry for that key stood and the shared entries follow them, in their own order. A project wins a value by being tried first, and a value its own entries do not read falls through to the shared shapes. What this gives up is suppression: a project can no longer silence a shared badge on a key it names. A test asserted that behaviour and its doc comment argued for it, worrying that shadowing half a key would leave a project drawing the shared wording for values it did not name. Ordering is now how a reader chooses exactly that, so the worry is answered rather than ignored.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
A badge's
matchis how a config says which values it wants. Until now a pattern that failed to read the value was treated as a badge falling short, and the row said so. That fires on every value a shared list was never meant to read. The livedelivery_prbadge readsowner/repo#N, andbdi-pj92records four closed beads carrying a URL or a bare number, so the bead window reported a reference lost where nothing had been promised about the shape.Badges on one key are now a chain. Each is tried in config order, the first to read the value draws, and the ones below it never run. A value no entry for the key reads draws nothing and reports nothing, whether or not those entries carry a
link. Graeme chose first-match over every-match because ordering then carries meaning. A reader who does want every value of a key writes a last entry with a permissive pattern, which the schema already allowed, so nothing here adds a key or a field.Breaking.
Undrawn::Badgeand the rowno badge for <key>: no pattern reads this valueare gone. A config with two entries on one key whose patterns both read a value drew both and now draws the first.Undrawn::LinkandUndrawn::Shortare untouched: those are a badge that read the value and then could not keep a promise its config made, which is the case a reader cannot see for themselves.Shadowing goes with it.
Config::badges_for_projectused to replace every shared entry for a key a project named. It did that to stop a project's entry and a shared entry both drawing for one value, and first-match now does that on its own. All the replacing still achieved was losing the shared shapes: a project namingdelivery_prto add a bare number stopped reading the qualified form. So a project's entries for a key now stand where the first shared entry stood, and the shared entries follow them. The project wins a value by being tried first, and a value it does not read falls through.That gives up suppression. A project can no longer silence a shared badge on a key it names. No config wanted to, but one test asserted it, and its doc comment argued for it: shadowing half a key, it said, would leave a project drawing the shared wording for values it did not name. Ordering is now how a reader asks for exactly that, so the worry is answered rather than dropped.
Two tests went with the retired variant rather than being rewritten around it. The model test asserting a report for an unreadable value is the retired behaviour itself. The row test asserting an anomaly's key reaches the row's notes has a sibling asserting exactly that for
Undrawn::Link, which carries the property alone now.Every behaviour claim here was checked against a deliberately weakened tree rather than left to read as passing. Disabling the fall-through guard makes the new pty test fail on the raw value. Making a key's badge read its value and then fail its
linkputs that key's name back on the screen, which is what that test's silence assertion looks for the absence of. Restoring shadowing makes the new snapshot test fail on the bead the shared entry reads.