Repository navigation
L0: close the recorded defects, and let a card show what is true now - #2
Merged
Merged
Conversation
Committed red on purpose. Two fail now — the source/state name collision and the unreported dead source. The third could not even compile, because `dispatch_reporting` did not exist; it is green in this commit because the API had to be added for the test to build at all. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
All three were recorded in §8 as found-and-not-fixed. Each is now enforced and each is held by a mutation rule. A `source` and a card `state` may no longer share a name. The component would have read the source — §5.3 was never violated and card state did not leak — but which of the two a name resolved to depended on lookup order rather than on anything the card said. A declared source nothing reads is refused: it is a fetch the host performs on every refresh for data that reaches no pixel. TWO shipped in the reference cards, not one. `series` and `aqi` both went unread the moment `StockPlot` and `AqiContour` began fetching their own data, and no test noticed either. Both are gone from the cards, and the four goldens still render — three at 0.00%, weather at 0.09% — because the widgets were already fetching that data. One implicit read has to be counted or the check rejects correct cards: resolving `copy.x` looks up `env.locale.lang` to choose a translation, and no path in the card names it. A purely syntactic scan called `env.locale` dead on two of the three reference cards. A state write now reports what it invalidated. `dispatch_reporting` returns a `DispatchOutcome` — what applied, which paths were written, which sources those writes made stale. `stale_sources` and `source_plan` already computed the answer and nothing joined them, so a host holding `true` could not tell what to refetch. `dispatch_with_data` keeps its bool for callers that do not care. THE MORE USEFUL FINDING is a test that had been passing for the wrong reason. `a_source_argument_path_must_be_declared` rejects a card carrying an undeclared path in a source argument, and its fixture ended `view root Rule()` — so the source went unread. Once unread sources were refused, the card was rejected for THAT instead, and the test passed with the rule it exists to protect switched off. The mutation harness reported it unprotected the moment the new rule landed, which is the entire reason that harness exists. The device tap harness gained the retry the render harness has documented since it was written. A one-shot check on a device that races reports false failures, and this one produced exactly one: the tap it called dead fired correctly by hand a minute later. 840 workspace tests, 19 mutation rules held, 0 unprotected, clippy clean. 4 goldens green on the 6T; the tap loop green. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
… what is true now
The stock detail worked only because the seeded blob already held a quote. It
now shows the live price on the 6T: $200.75 against the blob's $184.20, the
real company name, the real change percent, the real high and low.
`UiNode.bindings` is what makes it possible. Realization resolves `quote.last`
to a number, and from that point nothing downstream can tell it came from a
fetch — so a backend that could go and get it has no way to know it should.
`bindings` records the source and field per argument, ALONGSIDE the resolved
value rather than instead of it, and lowering emits `sys.stock("NVDA", "price")`
where the backend can answer and the seeded number where it cannot.
Three findings, none of which a unit test could have produced:
- `sys.stock` ACCEPTS "open" and cannot answer it. It resolves
`regularMarketOpen`, absent from the upstream response, while
`regularMarketDayHigh` and `…DayLow` beside it are present. It rendered
`$—` on device where the blob held a real opening price. A helper accepting
a key is not evidence that it can answer it — checked against a live
response, not against its documentation.
- Most formats do not survive concatenation. `money` is a "$" prefix and
`signed_pct` is what the VM already returns; `signed_money` puts the sign
outside the currency symbol, and `compact` and `ratio` need the number. The
table is in the code and the fallback is the safe direction: a seeded value
is stale but correct, a wrong concatenation is neither.
- ANYTHING THAT MEASURES TEXT MUST MEASURE WHAT IS DRAWN. Emitted and drawn
text are the same string until a value goes live, and then they diverge
completely: `"$" + sys.stock("NVDA", "price")` is 33 characters that render
as six. Sizing the hero by the emitted form dropped it 40pt → 24pt and
shifted the whole card up — a layout bug with no layout cause. `valued` is
split so the live path and the measuring path share one formatter and
cannot drift.
A LIVE CARD CANNOT BE ASSERTED BY A WHOLE-SCREEN GOLDEN. The harness now takes
a static band per case, and stock-detail declares the Mkt Cap / P/E row —
neither of which `sys.stock` exposes, so both stay seeded. Everything outside
the band is checked only for having rendered. That is weaker than the old
golden and true, where the old golden would have been stronger and false: it
would have been asserting a share price.
§5.11 records all of it, including the cost — `source_plan`'s dependency
ordering has no consumer on a backend that answers its own sources, and the
name translation lives in that backend's lowering.
842 workspace tests, 19 mutation rules held, clippy clean.
4 goldens green on the 6T; the tap loop green with live data.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
🤖 AI Code ReviewClaude CLI exited with code 1: ✅ No significant issues found. Tokens used: 0 | Powered by r9s.ai |
| "movers": [], "selected": "NVDA", "range": "m1", "env": {"locale":{}}, | ||
| "quote": {"name":"NVIDIA","last":184.2,"change":3.1,"pct":1.7,"open":181.0, | ||
| "high":185.6,"low":180.2,"volume":41200000.0, | ||
| "mktcap":4520000000000.0,"pe":58.3}, |
There was a problem hiding this comment.
🟠 Secret Detected (credit_card_visa)
Visa Credit Card Number detected: LLM validation unavailable - flagging conservatively
Match preview: 4520****0000
Remediation: Please review manually and remove if this is a real secret
| "movers": [], "selected": "NVDA", "range": "m1", "env": {"locale":{}}, | ||
| "quote": {"name":"NVIDIA","last":184.2,"change":3.1,"pct":1.7,"open":181.0, | ||
| "high":185.6,"low":180.2,"volume":41200000.0, | ||
| "mktcap":4520000000000.0,"pe":58.3}, |
There was a problem hiding this comment.
🟠 Secret Detected (credit_card_visa)
Visa Credit Card Number detected: LLM validation unavailable - flagging conservatively
Match preview: 4520****0000
Remediation: Please review manually and remove if this is a real secret
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.
Three commits, in the order they were done. The middle one closes the defects
§8 had recorded as found-and-not-fixed; the last one takes L0 from "renders the
blob it was seeded with" to "renders the live price".
The three recorded defects (
9cf195c)sourceand a cardstatemay no longer share a name. Nothing leaked —the component read the source, which §5.3 permits — but which of the two a
name resolved to depended on lookup order rather than on anything the card
said.
on every refresh for data that reaches no pixel. Two shipped in the
reference cards, not one:
seriesandaqiboth went unread the momentStockPlotandAqiContourbegan fetching their own data, and no test noticedeither.
dispatch_reportingreturns aDispatchOutcome— what applied, which paths were written, which sources thosemade stale.
stale_sourcesandsource_planalready computed the answer andnothing joined them.
One subtlety, or the check rejects correct cards: resolving
copy.xlooks upenv.locale.langimplicitly, and no path in the card names it. A purelysyntactic scan called
env.localedead on two of the three reference cards.And a test that had been passing for the wrong reason
a_source_argument_path_must_be_declaredrejects a card carrying an undeclaredpath in a source argument. Its fixture ended
view root Rule(), so the sourcewent unread — and once unread sources were refused, the card was rejected for
that instead. The test passed with the rule it exists to protect switched off.
The mutation harness reported it unprotected the moment the new rule landed,
which is the entire reason that harness exists.
A source can be answered by the backend (
db27733)The stock detail worked only because the seeded blob already held a quote. It now
shows $200.75 on the 6T against the blob's $184.20, with the real company
name, change percent, high and low.
UiNode.bindingsis what makes it possible: realization resolvesquote.lasttoa number, and from there nothing downstream can tell it came from a fetch. The
binding records the source and field per argument, alongside the resolved value,
so lowering can emit
sys.stock("NVDA", "price")where the backend can answer andthe seeded number where it cannot.
Three findings, none of which a unit test could have produced:
sys.stockacceptsopenand cannot answer it. It resolvesregularMarketOpen, absent from the upstream response, whileregularMarketDayHighand…DayLowbeside it are present. It rendered$—where the blob held a real opening price. A helper accepting a key is not
evidence it can answer it — verified against a live response, not documentation.
moneyis a"$"prefix andsigned_pctis what the VM already returns;signed_moneyputs the signoutside the currency symbol, and
compactandrationeed the number. Thefallback is the safe direction: a seeded value is stale but correct, a wrong
concatenation is neither.
"$" + sys.stock("NVDA", "price")is 33 characters that render as six. Sizingthe hero by the emitted form dropped it 40pt → 24pt and shifted the whole card
up — a layout bug with no layout cause.
A live card cannot be asserted by a whole-screen golden
The device harness now takes a static band per case.
stock-detaildeclares theMkt Cap / P/E row, which
sys.stockexposes neither of, so both stay seeded.Everything outside the band is checked only for having rendered.
That is weaker than the old golden and true, where the old golden would have been
stronger and false — it would have been asserting a share price.
Cost, recorded rather than discovered later
§5.11 states it:
source_planand its dependency ordering have no consumer on abackend that answers its own sources, and the translation between L0's capability
names and a backend's helper names lives in that backend's lowering.
Verification
--workspace --all-targets --all-features -D warnings: clean🤖 Generated with Claude Code