ADR index

An ADR (Architecture Decision Record) keeps a technical decision in the repo instead of scattering it across Issues and chat, so “why this shape” stays discoverable later. Expand a section below to read Decision, background, options, and consequences. The files under Docs/adr/ in git are the bilingual canonical source; when they diverge, Japanese wins.

Index

  • 0001 — Keep app-related trees under App/ · Accepted · Issue #134

  • 0002 — Split SPM targets into UI / Store / sources layers · Proposed · Issue #109

ADR-0001: Keep app-related trees under App/

Accepted · 2026-08-08 · Site out of scope · layout only, no behavior change

Fix the home for the app and verification artifacts as follows. Directories are renamed, not only moved — names like Sources / Tests read as “the whole repository’s sources,” which blurs scope.

App/
  Tokfuel*          … executable and libraries (was Tokfuel/Sources)
  Tests/
    UnitTests/      … what swift test runs
    IntegrationTests/ … integration (later)
    TestDocs/       … scenario design (not executed)
    E2E/            … end-to-end implementations (not under swift test)

Keep the product tree separate from Site / Docs / Scripts. Leave room for TestDocs and E2E under the same App/ parent.

App code lived in Tokfuel/Sources and tests in Tokfuel/Tests, referenced from a single SPM target. We needed in-repo homes for scenario design and end-to-end tests (#134). Putting those at the root or in separate trees multiplies “where do I look?” for app work.

  • Scattered homes make contributors hunt for the right place and mix unrelated changes in one PR.

  • Without a decided parent for TestDocs / E2E, ad-hoc conventions appear and clash with later module splits.

  • Root-level or Tokfuel/Sources names do not clearly mean “the product tree.”

  • 1 Status quo — TestDocs / E2E land elsewhere later; scatter and growth problems remain (rejected).

  • 2 Top-level siblings — entry points align but sit next to Site / Docs (rejected).

  • 3 Gather under App/ — one parent for app-related work; Site stays outside (adopted).

Discoverability, room to grow TestDocs / E2E, and fit with #109 (module split) favor option 3. Migration needs path updates but no behavior change.

  • One discovery entry for app-related work: App/.

  • Directory boundary between ops trees and product code.

  • Later module work can stay scoped as “inside the app.”

This decision does not cover relocating legal docs or renaming the repo root. Scope is App/ consolidation only. Full comparison tables live in the ADR files.

ADR-0002: Split SPM targets into UI / Store / sources layers

Proposed · 2026-08-08 · premise ADR-0001 · target boundaries, not another tree move

Stop using a single SPM target under App/. Split library targets by layer. Fix data flow and dependency direction as follows.

sources (Claude / Cursor / Codex / Budget …)  … fetch; expose APIs that yield data
        ↓
Store                                        … reshape in feature-named files; aggregate for UI
        ↓
UI                                           … render what Store provides

Dependencies: UI → Store → sources
Concrete wiring: App (executable)
  • Split sources by fetch axis. Keep only cross-cutting types in a thin TokfuelCore.

  • In Store, keep source-specific shaping in feature-named files (e.g. CursorUsage.swift) and assemble what UI consumes.

  • UI sees Store (and thin display types) only — not SQLite, retok, or dashboard APIs.

  • Keep Firebase, retok resources, and sqlite3 inside the source / Analytics targets that use them.

  • Do not change product behavior or the ground rules (local-only data, zero setup, unmodified retok, optional python3, no new packages).

Do not adopt feature-vertical splits that close UI pieces inside each source. The natural cut is fetch → shape → present. Splitting Claude / Cursor under sources is the lower layer only; UI and Store stay layered, not source-vertical.

  • Fix today’s Cursor cost — fetch in TokfuelCursor, shape in Store’s Cursor file, presentation-only tweaks in TokfuelUI.

  • Popover padding / shared layout — TokfuelUI only. Leave Store / sources alone if data is unchanged.

  • Cursor row data path — Cursor fetches → Store shapes → UsageStore-like aggregation → PopoverView-like display.

After ADR-0001 gathered code under App/, there was still a single target: UI, Store, networking, and cost math shared one directory (#109). Feature-vertical splits were compared to reduce PR collisions, but real data flow is “sources fetch, Store shapes, UI presents,” and cross-cutting UI edits remain. That cut is a layer boundary.

  • Store / UI / driver roles are document-only; the compiler cannot enforce them.

  • It is hard to tell from directory names whether a change is fetch, shape, or present.

  • Cross-cutting UI work and source-specific fetch work collide in the same tree.

  • 1 Status quo — boundary and clarity problems remain (rejected).

  • 2 Layers — matches data flow and UI cross-cuts; sources split underneath (adopted).

  • 3 Feature-vertical — helps source collisions but fights “fix UI together” (rejected).

  • 4 Many micro-layers — clarity cost too high for this size (rejected).

  • 5 Hybrid — vertical plus layers doubles boundary management (rejected).

  • Compile-time detection when UI reaches for SQLite or retok internals.

  • Clear change stories: fetch in Cursor target, shape in Store’s Cursor file, look in UI.

  • Store / UI can stay hotspots — split by feature-named and screen-named files; keep PRs small.

  • Untangle reverse deps (e.g. BudgetMonitor → UI) with callbacks / protocols before cutting targets.

How ADRs are written

One decision = one directory. Body filenames match the directory’s ID-slug. Both Japanese (.ja.md) and English (.md) are required. Bodies use Decision / Context / Consideration / Consequences / References; Consideration always includes the status-quo option.

  • Accepted — in force

  • Proposed / Draft — under discussion or review

  • Deprecated / Superseded / Rejected — kept for history

Large direction changes start as a GitHub Issue (label ADR), then land as an ADR once agreed. When you add an ADR or change its status, update the README catalog in the same PR.