Phase log 47: Phase 32.2: the last controls (2026-10-08)
Goal
Close the three items of the 32.2 row (phase log 46): (a) the 15 unreached data-action kinds, (b) selects/checkboxes/toggles, (c) role="button" divs and the lock screens' submit buttons.
What was built
tests/probe.ts:probeKindsaccepts an asyncresetand anafterResethook (lets a reset click "Run Scan" and then clear the toast it raised).tests/efficacy-surfaces.test.ts+efficacy-surfaces-silent.json(empty): surfaceshealth(vault with a weak entry and an empty bundle; click#health-scan-btn; probe#health-results [data-action]),settings(sidebar sections minustags, so "+ Show" exists;#settings-overlay [data-action]),icons(openIconPicker();#icon-picker-overlay [data-action]),feeds(aRemoteVaultStoreinstance withlistCalendarFeeds/revokeCalendarFeedstubbed,renderTimeline();#tl-feed-list [data-action]). Names are<surface>:<action>.tests/efficacy-settings.test.ts+efficacy-settings-silent.json: for each of the 19 inputs/selects in the Settings overlay plus 5 segmented/theme groups, change it, press Save, and requireSettings.getAll()to differ. Onlysettings-backup-pwis silent (an action's password field), allowed with that reason.tests/efficacy-cards.test.ts: selector now includes#bundle-suggest [data-action]; reset clearsdismissedBundleSuggestions(a Dismiss probe persisted into the next probe).tests/efficacy-config.test.ts:extras(type)adds anenv_filechunk (docker), a docker service with a${Alpha}env field, a wg_peer with a vault-reference field, an nginx_key + nginx_server, and a certificate entry forexample.com.tests/honest-controls.test.ts+7 tests: banner Accept creates a bundle, banner Dismiss stores'twin'(lower-cased), a${ref}badge from a config view shows the entry, a health-scan finding for a filtered-out entry shows it, unlock and re-lock screens refuse an empty password visibly, Enter on therole=buttoncard icon opens the icon picker.
Bugs found and fixed
- Accept/Dismiss on the "bundle them?" banner were dead in the real app.
renderBundleSuggestioninserts#bundle-suggestbefore#card-grid; everydata-actionhandler is a delegated listener on#card-grid, so clicks on the banner never reached it. Fix (src/ts/vault.ts): the grid handler becameonGridClick, still bound to#card-grid, plus a document-level delegate for clicks inside#bundle-suggest. The banner is created lazily, hence the document delegate rather than a direct listener. - Jumping to an entry showed nothing when something hid it.
jump-ref(the→ vaultbadge in the config view) andhealth-jumpexpanded the card and repainted, but with a project selected the config view replaced the grid, and with a search/tag/project filter active the card was filtered out. New exportedrevealEntry(entry)inrender.ts(switch panel,clearAllFilters()when the entry is not ingetFiltered()or a project is selected, expand it and its pool, render, flash the card found by id after the repaint). Both call sites use it.health-jumppreviously used adata-idxcaptured before an 80 ms timeout; it now re-finds by id. - Probe artefact removed: a dismissed suggestion persisted in settings and silenced the next "accept" probe.
Findings left (32.3 row in AGENTS.md)
copy-chunk-env("Copy (resolved)") is unreachable: it is rendered insiderenderChunkCardonly fordocker_servicechunks, which the docker project draws withrenderDockerServicesCard(that card hascopy-env). It is the onedata-actionkind still unreached (101/102). Evidence is the probe plus reading the call sites (render.ts 1878-1986); deletion not done becausediffAndStashCopyand the handler need a check for other users first.- Sampling is per kind (6 instances); per card type would catch a control broken for one type only.
Verification
npm run checkgreen: prettier, eslint--max-warnings 0, tsc, vitest 71 files / 1364 tests.- Fault injection: with the document delegate renamed to a selector that matches nothing and the
clearAllFilters()call inrevealEntryremoved, exactly four tests failed (banner Accept, banner Dismiss, config-view jump, health jump); restored from copies and the suite re-ran green. - Not run:
cargo test, ui-lab (no Rust touched; the banner/jump fixes are DOM behaviour that only a real window fully confirms: the ui-lab does not drive them).
Traps
- Settings probe presses Save, which writes settings to
localStoragein jsdom;reset()reopens Settings each time but the stored values persist across probes inside one test. Order-independent so far because each control is flipped once, from whatever state it has. Settings.set('dismissedBundleSuggestions', ...)stores providers lower-cased.st.storereplaced by aRemoteVaultStorein the feeds surface;fresh()callsresetState, which does not restorest.store. The feeds surface is last insurfaces; if you add one after it, setst.storeyourself.- Pre-existing uncommitted changes in the tree (fixtures,
index.html) are not from this step.