Commit Graph
6 Commits
Author SHA1 Message Date
swaitsandClaude Opus 5.5 7741e96eb3 refactor!: one way to serve books: the stdio server is gone (D-44)
check / check (push) Canceled after 0s
The owner (2026-10-23): "We should probably just delete the stdio path
altogether. THere's no point in that. And it sitting there unused will
just lead to bitrot. Nuke it?"

Books are served only by the books server (`wanderbooks server`),
reached by agents through the bridge (`wanderbooks mcp --book ID`),
which stays.

Removed: `wanderbooks dev-stdio`, the `ledger-mcp` binary, and
`ledger_mcp::run` (stdio and `--http` over a bare data dir), with all
that only that mode had:
- files the books make coming back inline: `HandedFile.content_base64`
  is gone, and `download` and `expires_at` are always there;
- books with no access log or backups: `books.access_log`,
  `books.backup` and `books.back_up_now` are always offered, by scope;
- the settings file read and reloaded (`legacy_files`), the vault key
  named by a file or `--vault-key-file`, and the books dir's
  key-inside-the-books and git checks (with `paths.rs`);
- `wire.rs` (the bridge frames an agent's lines itself);
- `books.settings`' file fields and `books.start`'s `settings_source`.

`BooksServer` is built one way, from `Served` (a book as the books
server serves it), in production and in the unit tests. An unknown tool
is now a protocol error (mcp-tools.md). Inline file input is unchanged.

Then the owner's three decisions (2026-10-23, the question tool):
(a) `books.import_settings` is removed entirely (118 tools): old books
come in whole by `wanderbooks books adopt`, which reads their settings
file once; ledger-config keeps its settings-file parsing only as far as
adoption uses it (`load` and the path-reading `effective_receipt_policy`
are gone), and `books.chart_template` gives its settings as
`books.set_setting` changes. (b) The viewer's loose-books-folder mode is
removed (`--data-dir`, `--books-toml`, `--vault-key-file`, the settings
file and config.json followed): it opens only books of the data root,
reading settings from the journal and the vault from the book's own
`vault/` and `keys/`. (c) `wanderbooks dev-stdio` has no stub: it is an
unknown command like any other word. Also: an upload's expiry past the
calendar is an error, never an empty string.

Tests: every suite that drove the stdio server moved to
crates/ledger-cli/tests/ and drives a real `wanderbooks server` on a
data root of its own (tests/common), handed files by their download;
mcp_stdio.rs is mcp_journeys.rs. Tests of what is gone are deleted and
listed in docs/testing.md. Docs: plan D-44 (D-18 superseded), STATUS,
testing, rules, mcp-interface, the handbook, README; justfile recipes.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01T3gXMVt7XJPi6ens1or9Dj
2026-10-23 19:45:18 -06:00
swaitsandClaude Opus 5.5 6c587086a0 feat(iif): carry each line's project in CLASS, the classes declared first
The P3 cutover review's open point 1: entries carry projects (classes,
B-37), but the QuickBooks Desktop file (B-34) left the CLASS field empty
on every line, and neither B-34 nor the README said so, though B-34 rule
6 says nothing changes silently.

Intuit's IIF Import Kit (vendored in docs/spec/sources/intuit-iif.md,
the kit's SHA-256 unchanged): the `!CLASS` header help says "Only the
NAME column is required" and a subclass's NAME is its parents' names
first, joined by colons; the kit's "Import First - List Declarations"
example declares `!CLASS` rows before any transaction, and its "2004
Deposit (Income)" example names the class line by line in CLASS. So the
file now declares every class in a `!CLASS` list after the accounts and
before `!TRNS`, and writes each line's class in CLASS (empty where the
line has none). Books with no class write no list, byte for byte as
before. A line whose class wasn't declared is refused
(IifError::UndeclaredClass), never written classless.

A class's NAME follows B-34's rules for an account's own name: plain
ASCII (rule 3), a colon written '-' (it would start a subclass),
trimmed, '?' if nothing is left, cut to 31 characters: Intuit's qbXML
Onscreen Reference gives `ClassAdd`'s Name "maxDT" : 31 (and 31 in the
Canadian, UK and Australian desktop editions; 100 only in Online), the
same as its `AccountAdd` Name (both JSON files vendored by SHA-256);
Conductor's QuickBooks Desktop API reference agrees and says the name is
case-insensitive. Classes whose NAMEs would match ignoring case get
" (id)", round after round, as accounts get " (code)", except that
among names that match, those already written differently from the
books (made safe, or tagged) yield first, a second " (id)" if need be:
a class's own name is kept unless another class's own name is the same
ignoring case (classes 1 "Café", 2 "Cafe", 3 "Cafe (1)" are written
"Cafe (1) (1)", "Cafe", "Cafe (1)"). Each class is tagged twice at most
and ids differ, so none is left alike (a hand-built list is refused). Each class name
written differently is an IifChange (IifField::ClassName), said one
line each in the warnings and in the package README, whose
"written differently" paragraph now names class names' limits; its IIF
line says CLASS is each line's project when there are classes. The MCP
and viewer notes count "account or class name(s)".

API: `iif_classes(ledger)` builds the list; `journal_to_iif` takes it
(`&[]` for none).

Docs: rules.md B-34 rule 8 with its sources; intuit-iif.md (the
`!CLASS` help, the list declarations and deposit examples, Intuit's SDK
department page, the qbXML Onscreen Reference's ClassAdd and AccountAdd
and Conductor's class reference, each with SHA-256);
mcp-interface.md (books.export iif, the package note); the bookspec
example iif-quickbooks-journal-file.toml (two projects: one carried and
renamed, one only declared; every line derived by hand); testing.md;
STATUS (open point 1 done; point 3 waits for the close, the owner said).

Tests: ledger-import
`iif_writes_each_lines_class_and_declares_the_classes_first`,
`iif_class_names_fit_quickbooks_and_every_change_is_listed`,
`iif_class_names_written_as_the_books_have_them_are_kept`,
`iif_refuses_an_undeclared_or_unfit_class`, property
`iif_class_names_never_clash`; ledger-package
`the_package_iif_carries_each_lines_project` and the bookspec example.
Broken to confirm: CLASS written empty fails the two exact-file tests,
the package test and the bookspec example; the " (id)" tag dropped fails
the names test and the property; tagging every name that meets (no
yielding) fails the kept-names test and the property (its shrunk case,
"A-B" beside "A\uFF1AB", kept in the regressions file).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01T3gXMVt7XJPi6ens1or9Dj
2026-10-22 19:31:18 -06:00
swaitsandClaude Opus 5.5 641184d3a3 viewer: the sidebar's links fit short windows
check / check (push) Canceled after 0s
The owner's viewer at 1479x519 (scale 1) showed Overview through half of
Accounts above the status card; Assets, Parties, Projects, Documents,
Company and Journal sat in a scroll area with no sign that it scrolled,
so the links seemed to go behind the status box.

The sidebar now gives way in steps, each only when the one before is not
enough, so a window where everything fit looks exactly as it did
(pixel-checked against main at 1440x920, tests/goldens):

1. The status card folds to its one summary line, "● Live · event 559 ·
   ✓ verified". Hovering it shows the three checks; right-click keeps the
   card's copy menu. The line is the fullest wording that fits the card
   (summaries), never cut off: a failed check is named ("⊘ Database
   differs", "⊘ 2 files damaged") before the event and the word "Live"
   are kept, and only then shortened to a count. Whatever the line
   leaves out, its tooltip says.
2. The rows tighten: the footer's menus, the gap under the header, the
   spacing between links, then the rows' height, down to 24 points, in
   the same font. The rail tightens the same way, also to 24 points.
3. Only then do the links scroll, with a soft fade and a chevron at each
   clipped edge (the rail's chevron sits centred on its own pill, clear
   of the icons), and the current page's link is scrolled into view
   whenever the page changes.

Links that overrun their room by under half a pixel count as fitting, so
the card folds where main's links began to lose a visible sliver, not a
point sooner at fractional scales.

At 1479x519 and scale 1 all twelve links show unscrolled in the sidebar,
and at 900x519 in the rail, in every footer state (Live, Snapshot, each
database state, damaged files, no Books menu).

Tests (tests/sidenav.rs, fixture books with a footer like the live one):
every height from 300 to 920 px at scales 1, 1.25, 1.5 and 2, sidebar and
rail, for each footer state: no link under the footer, links cut off only
when they scroll, and nothing scrolls from 519 px up at scale 1; the
owner's window in sidebar and rail; the folded line fits its card and
names a failed check, its tooltip the three checks; the scroll cue and
scrolling to the current link; the tall sidebar unchanged. Unit tests for
fit, its order of steps, the footer's memo and the folded line's
wordings.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01T3gXMVt7XJPi6ens1or9Dj
2026-10-22 14:00:25 -06:00
swaitsandClaude Opus 5.5 1304b9c0ad P3: dated 1099 decisions, payment methods and the card exception (defects 23, 12, 18, D-40)
check / check (push) Canceled after 0s
A vendor's 1099 decision is its own dated fact (files NEC or MISC, not
reportable with its reason, or undetermined), applied by each payment's
date. Payment methods are recorded; card and network payments are left
out and listed; a member's check through financing counts; a bank payment
with no method counts (D-40); $2,000 for payments after 2025. One
worksheet for the tool, the viewer and the CPA package.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01T3gXMVt7XJPi6ens1or9Dj
2026-10-21 12:12:26 -06:00
swaitsandClaude Opus 5.5 2c29d48ab9 P3: the IIF in plain ASCII with every change listed, and the CPA package as of one day (defects 7, 21)
The CPA package's general-journal.iif now holds every posted entry through
as_of (closing entries left out, D-36), written as plain ASCII with CR LF,
DOCNUM the entry id, QuickBooks Desktop's field limits and subaccount types
honoured, and every character written differently listed in the export's
warnings and the README (grouped by substitution, TINs masked). The 1099
worksheet stops at as_of too. PDFs print CJK, Arabic, Hebrew, Thai and
Devanagari (Noto fallbacks, OFL), and so does the viewer. has_full_tin reads
Unicode separators.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01T3gXMVt7XJPi6ens1or9Dj
2026-10-21 09:35:32 -06:00
swaitsandClaude Opus 5.5 5bc0633cdd P2 slice 6: the viewer
`wanderbooks gui [BOOK]` finds the data root, reads settings from the
journal, the vault of the book, presence through ops/, Save a copy /
Open on every document, Save the W-9, the Export menu, and colour
schemes. One builder for the CPA package and the 1099 worksheet
(ledger-package), shared by the server and the viewer.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01T3gXMVt7XJPi6ens1or9Dj
2026-10-20 11:14:21 -06:00