Six near-zero fixes, and the rule that found a third one nobody had opened the menu to see - #202
Merged
Merged
Conversation
…pened the menu to see A1, A2, A4, B1, B2 and D3 of STUDIO-UI-FIX-PLAN-2026-08-15, in one pass. Every guard was run red against the unfixed code part by part - twelve arms in three runs - and no part had an empty red set. A1 was written as two menu labels. The real work is the rule over every printed gesture, and the rule named THREE: New Query Tab printed Ctrl+N (which opens New Database), View > Refresh printed F5 (which runs the statement under the cursor), and Query > Execute printed F5 for ExecuteQueryCommand, which is on Ctrl+Shift+F5. The third was in no report because nobody had opened the Query menu looking for it. New Database now prints the Ctrl+N it has always owned. InputGesture on an Avalonia MenuItem is a label and binds nothing, so none of this changes what any key does - which is also why no existing rule could see it: the printed text is in neither KeyboardMap nor the list of KeyBindings. The new rule is the third direction, resolves each MenuItem's Command to its own name so that the tab strip's $parent path and the File menu's compare equal, normalises Enter against Return, carries four exemptions that are each a named decision, and asserts the SURFACE - 16 printed gestures, 12 checked - so that "nothing left to find" cannot read like "the folder moved". A2 is one string. Explorer.Summary had its nouns inside the format string with raw numbers passed in, so the status bar printed "1 views, 1 triggers" while the Database tab, over the same counts in the same second, printed "1 table" correctly through Localization.Plural. Four families existed; Count.Sequences is added to both catalogues. The fixture that could not see this is every fixture with none or several of something - StudioFixture has exactly one view and one trigger, and nothing had ever asserted its status line. A4: the page cache line opened with a bare separator on a database whose header predates the cache kind. Driven against a file written today the same line reads "clock . 1000 pages . holding 2 pages, 0 dirty", so the engine answers it and the older file simply does not carry it. The field is dropped with its separator rather than filled with an invented name. The composing function is static and public because every file this repository can write records the kind - a case over a real connection can only see the arm that was already right. B1: NoKey had every editing control disabled, correctly, while the status bar said "Editing table: NoKey" and the footer advertised Ctrl+S and Del. The gate is the tab's own IsReadOnly - the one CanAddRow, CanDeleteRow and CanCommit are computed from - and NOT the WorkspaceTabViewModel.IsReadOnly it shadows, which means the connection was opened read-only. The markup guard is structural: all seven hints must have a gated ancestor, so leaving one of the three status states open goes red. B2: the three storage options are vertically centred in a UniformGrid whose row height comes from the tallest description, and the outlier moves with the language - LSM in English, "In memory" in Russian. The lint is deliberately narrow: two or more radio buttons side by side with at least one wrapping description, which is the shape that produces the defect. The wide rule over all 66 horizontal sibling groups is not written, because it would report legend and caption rows and an exemption written for a false positive is a hole in a rule wearing a comment's clothes. D3 was recorded as an untranslated label and it is not. The caption has come from the catalogue since 2026-08-07; what fails is the MOMENT - it is written at startup and on a theme change, and nothing re-read it when the catalogue was swapped, so a language change left "Dark" on a Russian window. The new rule is about when rather than what: a caption a view writes from the catalogue must either be written by a static factory that constructs its own window, or its file must subscribe to LanguageChanged. Both dialogs pass on the first arm, so neither needed an exemption. Five of the six were driven in a freshly built Studio against the recreated calibration database, which now lives in Docs/calib rather than a scratchpad. A4 was not driven: it needs a file whose header predates the field. Studio 898 cases, up from 891. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
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.
A1,A2,A4,B1,B2andD3ofDocs/STUDIO-UI-FIX-PLAN-2026-08-15.md, in one pass. Every guard was run red against the unfixed code part by part — twelve sabotage arms in three runs — and no part had an empty red set.A1 — the printed gesture is the one that runs
Written up as two menu labels. The real work is the rule over every printed gesture, and the rule named three:
Ctrl+NCtrl+TF5Ctrl+RF5Ctrl+Shift+F5The third was in no report — nobody had opened the Query menu looking for it.
New Databasenow prints theCtrl+Nit has always owned.InputGestureon an AvaloniaMenuItemis a label and binds nothing, so none of this changes what any key does — and that is also why no existing rule could see it: the printed text is in neitherKeyboardMapnor the declaredKeyBindings, which is all the two existing rules compare. The new rule is the third direction. It resolves each item'sCommandto its own name so the tab strip's$parent[UserControl]…path and the File menu'sWorkspaceTabsVm.…compare equal, normalisesEnteragainstReturn, carries four exemptions that are each a named decision keyed by item and gesture, and asserts the surface — 16 printed, 12 checked — so "nothing left to find" cannot read like "the folder moved".Consequence written down rather than hidden: the Query menu no longer mentions
F5, whichWS-25made the primary run key. Adding an Execute statement item is a menu-content question and stays open.A2 — English plurals at one
Explorer.Summaryhad its nouns inside the format string with raw numbers passed in, so the status bar printed1 views, 1 triggerswhile the Database tab — same counts, same second — printed1 tablecorrectly throughLocalization.Plural. Four families existed;Count.Sequencesis added to both catalogues.The fixture that could not see this is any fixture with none or several of something.
StudioFixturehas exactly one view and one trigger, and nothing had ever asserted its status line.A4 — the page cache line opened with a bare separator
· 0 pages · holding 170 pages, 0 dirtyondemo.witdb. Driven against a file written today the same line readsclock · 1000 pages · holding 2 pages, 0 dirty, so the engine answers the question and the older file simply does not carry the value. The field is dropped with its separator rather than filled with a name invented for it.CacheLineis static and public on purpose: every file this repository can write records the kind, so a case driving a real connection can only ever see the arm that was already right.B1 — «Editing» over five disabled buttons
NoKeyhad every editing control[disabled], correctly, while the status bar saidEditing table: NoKeyand the footer advertisedCtrl+S: CommitandDel: Delete row.The gate is the tab's own
IsReadOnly— the oneCanAddRow,CanDeleteRowandCanCommitare computed from — and not theWorkspaceTabViewModel.IsReadOnlyit shadows, which means the connection was opened read-only. Two concepts, one name. The markup guard is structural: all seven hints must have a gated ancestor, so leaving one of the three status states open goes red.B2 — the storage options' baseline
Vertically centred in a
UniformGridwhose row height comes from the tallest description; the outlier moves with the language (LSM in English, «В памяти» in Russian), so a screenshot review pinned to one language blames the wrong control.The lint is deliberately narrow — two or more radio buttons side by side with at least one wrapping description, which is the shape that produces the defect. The wide rule over all 66 horizontal sibling groups is not written: it would report legend and caption rows, and an exemption written for a false positive is a hole in a rule wearing a comment's clothes.
D3 — and the plan's attribution was wrong
Recorded as a label built from a raw theme name. It is not: the caption has come from the catalogue since #139 (2026-08-07). What fails is the moment — it is written at startup and on a theme change, and nothing re-read it when the catalogue was swapped, so a language change left «Dark» on a Russian window. Same family as
C1.The sixth localisation rule is about when rather than what: a caption a view writes from the catalogue must either be written by a static factory that constructs the window it fills (built fresh per showing) or its file must subscribe to
LanguageChanged. The discriminator is mechanical, so both dialogs pass without an exemption.Driven, not only tested
Five of the six were driven in a freshly built Studio — the installed rc.1 is the unfixed build and can only reproduce — against the calibration database, which now lives in
Docs/calib/(gitignored, survives the session) and has theFlagNULL rowD1needs:Ctrl+T/Ctrl+N/Ctrl+Shift+F5/Ctrl+Ron screen in three menus;calib: 6 tables, 1 view, 2 indexes, 1 trigger, 0 sequences;NoKeyannounced as viewing with no footer hints,Marksstill editing with them;A4was not driven — it needs a file whose header predates the field — and its guard is over the composing function instead.One finding, not fixed here
Because the derived
IsReadOnlyshadows the base, a table on a read-only connection has every editing button enabled:UpdateStatusnever reads the connection's mode, so the refusal arrives from the engine after the person has typed. Behaviour rather than chrome, and not one of the six; recorded in the plan besideB1.Studio 898 cases, up from 891.
🤖 Generated with Claude Code