fix: follow-ups of the lot-v018 stack reviews #482

Merged
maximus merged 25 commits from review-followups-lot-v018 into main 2026-10-21 00:31:46 +00:00

25 commits

Author SHA1 Message Date
le king fu
c50ed53ba7 docs: the command that lists the hook harness users counts test files only (#437)
All checks were successful
PR Check — Frontend / frontend (pull_request) Successful in 2m8s
PR Check — Rust / rust (pull_request) Successful in 3m43s
Review 25974, suggestion 4: `grep -rl "test/hookHarness" src` printed
22 lines, the harness itself included; with --include='*.test.*' it
prints the 21 test files the sentence counts.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-20 20:15:31 -04:00
le king fu
13dca87d04 test(categories): a failed re-read of the categories shows in the window (#393)
Review 25974, suggestion 1 (Q6): the JSDoc, architecture.md and the PR
body say a failure of readCategoriesAgain shows in the hierarchy window,
and no test held it. The read is rejected once at the opening (the
diagnostic does not run on the old categories) and once after a
committed reattachment: each time the window shows the message, the
page's banner behind it stays empty, and saving is over.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-20 20:15:05 -04:00
le king fu
a17c1b7604 docs: placeListbox test header and CLAUDE.md module count (#429, #384)
All checks were successful
PR Check — Frontend / frontend (pull_request) Successful in 2m2s
PR Check — Rust / rust (pull_request) Successful in 3m52s
Review 25921, points 4 and 6: the header of placeListbox.test.ts still
listed the re-read after a render among what needs a DOM, though
CategoryCombobox.placement.test.ts pins it; only the paint and React's
skipped render remain. CLAUDE.md announced 10 command modules and listed
twelve: 12 modules, 10 of them with commands, 45 commands.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-20 19:43:18 -04:00
le king fu
b626bcbabe fix(i18n): say « become a parent » precisely, and what to do with budget amounts (#393)
Decision of Max of 2026-10-20 and review 25921, point 3. The #393
changelog entries, the guide tip and docs.categories.tips (FR and EN)
now say a category that still takes input cannot become a parent, and
that an existing parent, no longer inputable, accepts new subcategories
as before. The parent_has_budget message and the tip say amounts of any
year count, to be set to zero in the grid year by year, and that a
template cannot be edited, only deleted; the tip adds that zeroing a
past year also takes its planned amounts out of Budget vs Actual.

architecture.md: the rule and its reason, the hierarchy rows now
carrying is_inputable, readCategoriesAgain after a reattachment (a
form open on the orphan itself keeps its old parent: known limit), and
the hook harness users presented as a count with the command that lists
them (21 on 2026-10-20), not as an exhaustive list (25921, point 6).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-20 19:43:18 -04:00
le king fu
bc6610103b fix(categories): a reattachment keeps a form open behind the window (#393)
Review 25921, point 5 (pre-existing since #472): after a reattachment,
reattachOrphan reloaded through loadCategories, whose loading state
unmounted the detail panel, so a category form open behind the window
lost its unsaved changes. The silent re-read of checkHierarchy becomes
readCategoriesAgain (waits for a drag-and-drop's writes, a newer load
wins, no loading state), used by both; a failed re-read after a
reattachment now shows in the window, where the user is.

Also pins the guard « a newer load wins » (review 25921, R8): a load
started during the check's read lands, the check's older answer is
dropped.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-20 19:41:17 -04:00
le king fu
1386abd91e fix(categories): check a parent's content only when it would become one (#393)
Decision of Max of 2026-10-20 (review 25921): transactions, non-zero
budget amounts and active keywords are checked only while the target
still takes input (is_inputable = 1, the condition of markAsParent),
that is when it really becomes a parent and stops taking input. An
existing parent, no longer inputable, accepts a new or reattached
subcategory whatever it holds, as in every released version: the
refusal protected nothing there. All three codes and all three entry
points follow the rule; the hierarchy rows now carry is_inputable,
and createCategory reads them through its transaction's handle.

Also pins a negative amount, in the grid and in a template, as a
refusal (review 25921, R1/R2): the grid stores what is typed.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-20 19:40:04 -04:00
le king fu
273cf36eb7 fix(categories): the hierarchy check reads after the drag-and-drop's writes (#393)
All checks were successful
PR Check — Frontend / frontend (pull_request) Successful in 2m20s
PR Check — Rust / rust (pull_request) Successful in 3m52s
Self-review of the reload: updateCategorySortOrders writes one UPDATE
per category, each through the lock on its own, so a check opened right
after a drag-and-drop could read halfway and show half the move in the
tree. moveCategory keeps its write's promise, settled either way, and
checkHierarchy waits for it before reading. Pinned by a hook test with
the write held open.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-19 21:25:49 -04:00
le king fu
1a3fa1dcc9 docs: review follow-ups in REVIEW.md and architecture.md (#384, #437, #446, #449)
All checks were successful
PR Check — Frontend / frontend (pull_request) Successful in 2m22s
PR Check — Rust / rust (pull_request) Successful in 4m11s
REVIEW.md, outside « Niveaux »: a pitfall on the vitest tests that read
src-tauri/ (a PR touching only src-tauri/** skips check-frontend, review
25592 point 6), and, in the Release zone, the --locked relay to re-prove
when @tauri-apps/cli or cargo-xwin is bumped (review 25416 point 2).
architecture.md: the same relay, the six cargo metadata calls coming
from the Tauri CLI only (25416 point 3); the mount error of Transactions
wiped by the first debounced page read, and the banner cleared by
refreshFolder and browseFolder (25592 points 7 and 2); the catch-up
measurement asserts success, not duration, and PriceFetchControl among
the harness users (25443 points 1 and 5); the Ctrl+click note's reason
as read in tauri 2.10.2 and wry 0.54.1 (25487 point 5).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-19 21:11:34 -04:00
le king fu
9fc942d295 docs: CLAUDE.md tree recounted, ten command modules and three component folders (#384, #446)
Review 25592, point 5: the commands/ line said 3 modules and 17
commands; generate_handler! registers 45, in 10 modules (fs 7,
export_import 5, profile 8, license 11, auth 5, token_store 1,
entitlements 1, feedback 2, backup 3, balance 2), listed as in
docs/architecture.md. Review 25487, point 7: balance/ (12),
categories-migration/ (5) and onboarding/ (3) added, of the 138
components (non-test .tsx under src/components).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-19 21:11:34 -04:00
le king fu
e275a8ad8d docs: name the logs as the interface does in the #372 entry (#372)
Review 25424, point 3: the English interface never says "Journal" (the
card is "Logs"), the French one says "Journaux". Unreleased entry only.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-19 21:11:34 -04:00
le king fu
a2c4fd4685 test(budget): a collapsed sub-group last in its group keeps its subtotal (#446)
Review 25487, point 2 (R13): [A, z, Vide] gives z, Vide, A; dropping
the subtotal of an empty block at the final flush turned no test red.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-19 21:10:03 -04:00
le king fu
0df60f6042 test: the transfer tooltip, the cancel button and the opened notes row (#437)
Review 25443, point 2: the transfer icon's tooltip goes through t with
its account and direction (X4), LicenseKeyForm's cancel button through
t (X11), and the notes textarea opens under the row whose button was
clicked, read in the Fragment keyed by that row's id (X8).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-19 21:10:03 -04:00
le king fu
2389d51b48 test(settings): a late failure of the previous language keeps the history (#372)
Review 25424, point 1: the `if (!cancelled)` of ChangelogContent's
.catch had no test (V1). Modelled on the late-answer test: the French
file rejects after the English one was read, and the history still shows
the English notes, not the empty message.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-19 21:10:03 -04:00
le king fu
4f060ba7d7 test(i18n): the key guard's canary sees two modules, and lists leaves only (#453)
Review 25409, points 1 and 2: the canary now fails if both imports name
one file (T4), and a fixture pins that a missing branch is reported by
its leaves, never by its container (T1).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-19 21:10:03 -04:00
le king fu
f27bdc4afa test(rust): a file named like a sample folder is refused, nothing created (#384)
Review 25592, point 1: the pre-check reads exists(), not is_dir(); under
is_dir() a file named "Exemple Tangerine" let "Exemple Desjardins" be
created before create_dir failed with a raw "File exists". The
reviewer's test pins it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-19 21:09:01 -04:00
le king fu
ffe6288e4a test(import): the sample folder messages name the folder in both languages (#384)
Review 25592, point 3: the page's tests take the marked t and the key
guard compares no value, so a translation that lost {{name}} passed the
suite. The real locale files, through a real i18next with the app's
options, now render folderExists with the folder's name in French and in
English, and the two other codes without a leftover placeholder.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-19 21:09:01 -04:00
le king fu
48d1314d6d fix(import): clear the error banner when the folder is read again (#384)
Review 25592, point 2 (pre-existing): the banner of a refused sample
folder asks to refresh the list, yet survived a "Refresh" that went
through, and a folder change. refreshFolder, and browseFolder once a
folder is chosen, now clear the error before reading the folder, as
selectSource does; a failed rescan puts up its own error, and a
cancelled picker keeps the banner. The hook tests also pin browseFolder's
order (review 25487, point 1): the folder is set before its scan, so the
root files shown are the new folder's. Fixed entry in both changelogs.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-19 21:09:01 -04:00
le king fu
a52958aff3 docs: the open category list reads its position after each render (#429)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-19 21:06:22 -04:00
le king fu
5f2c4dd5bd fix(combobox): follow the input when a render moves it (#429)
Review 25431: a window centered on screen grows when its content
arrives, and moves its fields with no scroll nor resize; the open list,
placed in a portal, stayed where it was. While open, the combobox now
reads its position again after every render (useLayoutEffect without
dependencies); `keepPlacement` hands back the same state object for an
unchanged position, so React renders nothing more. Pinned by
CategoryCombobox.placement.test.ts (harness, useLayoutEffect mapped on
its useEffect, fake input) and keepPlacement's own tests. The boundary
test of placeListbox now sits at exactly 240 px below with room above
(point 1), and AddKeywordDialog's comment no longer claims the list is
cut (point 3).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-19 21:06:22 -04:00
le king fu
813ee07559 fix(i18n): name the eight getting-started steps in the dashboard help (#446)
Decision of Max of 2026-10-19 (review 25487, point 4):
docs.dashboard.steps[0] (FR and EN) and step 1 of the guide's Dashboard
section listed six of the eight steps. They now name the eight, by the
labels of onboarding.checklist.items, in the list's order, and say the
two visit steps are checked with the card's "Got it" or, for the
reports, a click on the outlined Trends card. A test holds the step to
the checklist's labels and order; the #446 changelog entries follow.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-19 21:03:59 -04:00
le king fu
a5b92b975e docs: the hierarchy window reads the categories again on opening (#393)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-19 20:59:27 -04:00
le king fu
7f25293669 test(categories): pin the rules the review of #393 left green (#393)
Review 25437, point 2: the loop named by its own smallest member, not by
a smaller id under it (RM1); the page hands the window every category,
not the tree (RM11); a category that is its own parent stays out of the
budget, and displaysAsRoot says so (RM15). RM7 (depth counted on active
categories at the service) is pinned in categoryService.test.ts by
1a36d4e, RM2 by be4b923.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-19 20:59:07 -04:00
le king fu
be4b923451 fix(categories): reload the categories before the hierarchy check (#393)
After a drag-and-drop, SET_TREE leaves state.categories with what the
tree shows, without the members of a loop: the window then showed "—"
for the orphan and offered a parent the service refused (review 25437,
point 1). checkHierarchy now reads the categories again before the
diagnostic, without the page's loading state, so a form open behind
the window stays as it is; a load started meanwhile wins. Pinned by a
drag-and-drop-then-check hook test, plus the refusal-then-success case
of the window's message (RM2).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-19 20:59:02 -04:00
le king fu
c8c8c068fc docs: a parent's budget amounts and keywords, the create path, node:sqlite in tests (#393)
The unreleased #393 entries now say the refusal covers budget amounts
and keywords and applies when a subcategory is created; guide tip and
architecture.md (validation, createCategory, out-of-scope drag-and-drop,
the node:sqlite test note) follow.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-19 20:51:29 -04:00
le king fu
1a36d4e618 feat(categories): refuse a parent that holds budget amounts or keywords, on create too (#393)
Decision of Max of 2026-10-19 (review 25437, point 3): a category that
holds direct transactions, a non-zero budget amount (budget_entries or
budget_template_entries) or active keywords cannot become a parent. The
check (`checkParentContent`) runs through the transaction's handle,
before any write, in `updateCategory` (changed parent), `reattachCategory`
and now `createCategory`, which writes its row and the parent's flag in
one transaction. Order: transactions, budget, keywords; the first found
is the refusal (`parent_has_budget`, `parent_has_keywords` added to
`CategoryHierarchyError`, translated in FR and EN).

The service tests run the content queries as written on node:sqlite,
tables created from consolidated_schema.sql.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-19 20:51:24 -04:00