feat: read the signer's at-rest report, keep capabilities across a trimmed status - #141
Merged
Merged
Conversation
heartwood-esp32 #192 adds at_rest ("none"/"pin"/"vault"/"encrypted") and
unlock_phone_count to FIRMWARE_INFO and get_status, so Sapwood no longer
has to guess the power-cut recovery mode from side effects it happened
to witness this session. resolveUnlockMode reads the new fields when a
signer sends them, treats an unrecognised value as unknown rather than
guessing, and falls back to the existing inferUnlockMode heuristic for
firmware that predates the report (released beta.17).
applyRelayStatus overwrote capabilities and slots to empty/zero whenever a get_status reply set truncated: true (the low-heap fallback that trims the request log and relay lists), breaking persona pairing until the next full poll. The truncated reply never carried those two fields to begin with, so carry the previous poll's values forward instead of clearing them; at_rest and unlock_phone_count need no such handling, since the firmware sends both fresh even on a truncated reply.
resolveUnlockMode's known override was set once by a PIN, seal or disable action and never reset, so it kept overruling a later at_rest report for as long as the tab stayed open. Add shouldRetireEncryptionKnown, comparing the report seen when the override was set against the latest one, so a differing report (a relay poll catching up, or a fresh USB read) lets the firmware's own answer take over again.
"Unknown: no vault key held here" and "Connect by USB to check" both blame missing information, but a firmware that sends an at_rest value this build does not recognise has told Sapwood something, just not something it understands yet. Add atRestUnrecognised to DeviceSummaryInput so the power-cut row can say "update Sapwood" instead, and update the doc comment on unlockMode, which still said "inferred" now that a firmware report is read directly when sent.
DevicePanel's summary row fed phoneCount (UnlockPhones' enumerated list, null until an authenticated session lists it) into deviceSummaryRows, so a locked signer with phones enrolled read as "(0 phones)". Pass effectivePhoneCount instead, which prefers the firmware's own unlock_phone_count, sent even while locked. Also wires up the two preceding fixes: encryptionKnown now records the at_rest value it was set against and retires once a later report disagrees (re-reading FIRMWARE_INFO after a seal or unseal, since it is otherwise only fetched at connect), and the "After a power cut" card shows the new unrecognised-report wording alongside the summary row.
TheCryptoDonkey
force-pushed
the
feat/at-rest-status
branch
from
September 26, 2026 00:53
284250e to
a460cd3
Compare
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.
Follows heartwood-esp32 #192, which added
at_restandunlock_phone_countto FIRMWARE_INFO and get_status.none,pin,vault,encrypted, plus the phone count) instead of inferring it. Older firmware (released beta.17) sends neither field, so Sapwood falls back to the old inference. An unrecognised value shows as unknown. An action taken this session still wins until the next poll.truncated: true) no longer clearscapabilitiesandslots. Before this, persona pairing broke until the next full poll.Tests: vitest 1040 passed (one unrelated flake in import-link.test.ts passes on rerun), svelte-check 0 errors, check:cli clean, chromium e2e 31 passed. mobile-webkit was not run (it can't run on this Mac).