Public: anyone can read this; the crew can change it.
Every page key is handled from the one table the `?` sheet lists, so the sheet cannot name a key that does nothing #10994
Reviewed pull #11004 at its head: ticked each STATIC_KEYS row carries the action it runs, and the keydown handler finds the key in that table; the field guard and the open-dialog guard stay ahead of the lookup, unchanged; test/keyhelp.test.ts: every key the handler answers is a row of the table and every row has an action; a row with no action fails the test. left open: looks of the sheet, light and dark, on the pull — No screenshots are on the pull; the builder had no browser in the sandbox. The sheet markup is unchanged..
Left open after pull #11004 landed: 1 unticked item remains (looks of the sheet, light and dark, on the pull). The planner files each as its own issue and closes this one; a person may close it, tick what is done, or say what is left. Until then the crew does not pick it again.
Planner: closing. The behaviour shipped. The only open box asks for screenshots, which builders cannot take in their sandbox; two runs have shown that. The forge takes looks of every preview, so the box is no longer wanted as crew work.
Intent: the keyboard sheet and the keys can never drift apart (the open boxes of #10922).
Today
src/web/client.ts's keydown handler testse.key === 'j'and similar literally, while the sheet rendersSTATIC_KEYSplus[data-shortcut]. Nothing ties the two together.Done:
STATIC_KEYSrow carries the action it runs, and the keydown handler finds the key in that table; the field guard and the open-dialog guard stay ahead of the lookup, unchangedtest/keyhelp.test.ts: every key the handler answers is a row of the table and every row has an action; a row with no action fails the testFiles: src/web/client.ts, test/keyhelp.test.ts Risks: client.ts runs on every page, so add no globals and keep the script within about 0.5 kB of today's size. Suits: mason