fix: the projection registry renamed its fields, so the meter went invisible - #13
Merged
Merged
Conversation
…visible
`@deepseek-ai/dsh-session-projection` 0.1.1-rc.1 split the definition's single
`schema`/`view` pair into a host-side `stateSchema` and an OPTIONAL
`wire: { viewSchema, view }`. The registry reads those fields one by one and
never validates the definition it was handed, so the old spelling does not
fail — it reads as "this projection is host-only". The fold still ran, the
value never reached the browser, `useProjection('costMeter')` returned
undefined, and `CostMeterLine` returned null.
No error, no warning, no log line. The dock line simply stopped rendering,
which is why this looked like the meter "not working" rather than a crash.
`^0.1.0-rc.6` did not even cover the installed 0.1.1-rc.2 — npm excludes a
prerelease whose [major,minor,patch] no comparator names — so the one signal
that could have caught it was an unmet-peer warning nobody reads.
Register both spellings from one definition. Each registry reads the pair it
knows and ignores the other, so a single build is correct on either side of
the rename, and the peer range now names both prerelease lines.
`stateSchema` is new work, not a rename of the old `schema`: the old contract
kept checkpoints raw, the new one parses the persisted row before folding onto
it. Without it a resumed session throws on `def.stateSchema.parse`.
Verified live against dsh 0.1.1-rc.2: the dock renders
`¥0.2185 | off-peak | peak in 14h` on a real session, the card opens with the
per-model split and the account balance, and the tests fail on the old
spelling and pass on this one.
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.
What broke
@deepseek-ai/dsh-session-projection0.1.1-rc.1 (2026-08-21) renamed theprojection definition contract:
schema— validatesview(state)wire.viewSchemaview— always client-visiblewire.view, andwireis optionalstateSchema— parses the persisted row on restoreThe registry reads the definition field by field and never validates it, so
the old spelling does not throw. It reads as "this projection is host-only":
The fold kept running. The value never reached the browser.
useProjection('costMeter')returnedundefined,CostMeterLinereturnednull, and the composer dock line disappeared — no error, no warning, no logline anywhere.
The one signal that could have caught it was an unmet peer:
^0.1.0-rc.6doesnot match
0.1.1-rc.2, because npm only admits a prerelease when somecomparator names the same
[major, minor, patch]. Nobody reads pnpm's peerwarnings.
The fix
One definition carrying both spellings. Each registry reads the pair it knows
and ignores the other, so a single build is correct on either side of the
rename. The peer range now names both prerelease lines
(
^0.1.0-rc.6 || ^0.1.1-rc.1).stateSchemais genuinely new — it is not the oldschemarenamed. The oldcontract stored checkpoints raw; the new one feeds the persisted row through
stateSchemabefore folding onto it, so a definition without one throws on thefirst resumed session.
Verified
Live against dsh 0.1.1-rc.2 on a real session:
The card opens with the per-model split, the counterfactuals, and the account
balance from
/dsh-meter/balance. No page errors.Tests: 98 pass (15 new). The four that matter fail on the old spelling and
pass on this one — each stand-in registry reads exactly the fields its
published
lib/index.jsreads, because a stand-in weaker than production wouldmiss this again.