TerminalView's build tree doesn't wrap content in a Scrollable — scroll is handled by translating PointerScrollEvent into PgUp/PgDown keyInput. The ScrollController parameter, _scrollableKey, internal _scrollController, _scrollToBottom helper, and its five call sites were all dead: _scrollableKey.currentState was always null because no Scrollable in the tree carried the key, so _scrollToBottom's jumpTo never fired. Drops: - public scrollController parameter on TerminalView - _scrollableKey + _scrollController fields - the didUpdateWidget swap block and dispose call - _scrollToBottom + the five call sites - KeyboardVisibilty wrapper (its only callback was _scrollToBottom, now a no-op; the widget remains a reusable primitive under ui/ for future use) - the matching tests in terminal_view_test.dart Same shape as T-93 (dead onTapUp wiring) and T-95 (dead tertiary tap surface) — public API that no caller used + internal state that no path executed. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
17 KiB
Decisions
Confirmed decisions, open questions, and rejected alternatives for clide.
Decisions are split by domain. When unsure where a record belongs: if it constrains how we build, it's architecture. If it defines what ships to users, it's extensions / accessibility. If it defines how we verify, it's testing. If it defines what the toolchain looks like, it's tooling. If it defines how the team works, it's process.
Cross-domain records live in one file with [D-NNN]-shaped cross-
references in related files. Split threshold: when any file exceeds
~350 lines, review whether it should split (see settled-reach's
questions-*.md split pattern for precedent).
Domain files
| File | Domain |
|---|---|
| architecture.md | Core, rendering, IPC, kernel, panel manager |
| extensions.md | Extension contract, Lua runtime, grain, contribution points |
| accessibility.md | A11y + i18n policy, WCAG gates |
| testing.md | Test pyramid, drivers, client-side constraint |
| tooling.md | Toolchain, supply chain, CI, ignore strategy |
| process.md | Q&D system, kanban, commit conventions, changelog |
| rejected.md | Rejected alternatives across all domains |
| questions.md | Master index of open questions |
| questions-architecture.md | Architecture Qs |
| questions-extensions.md | Extension Qs |
| questions-accessibility.md | A11y / i18n Qs |
| questions-testing.md | Testing Qs |
| questions-process.md | Process + tooling Qs |
Record shape
Confirmed decisions (D-NNN):
### D-NNN: Short title
- **Date:** YYYY-MM-DD
- **Decision:** one-sentence summary, then details.
- **Rationale:** why this over alternatives.
- **Cost:** known downsides / what we're accepting.
- **Raised by:** who proposed / endorsed.
Domain-specific fields (Kill switch:, Evaluation reports:,
Amendment:, Cross-reference:) are additive. Amendments are inline
and dated: **Amendment (YYYY-MM-DD):** …. Cross-references use
markdown anchor links with the full slug:
[D-5](architecture.md#d-5-dart-core-ptyc-peer).
Open questions (Q-NNN):
### Q-NNN: Short question-form title
- **Status:** Open | Partially resolved → [D-NNN] | Resolved → [D-NNN]
- **Question:** ...
- **Context:** ...
- **Assigned to:** (optional)
- **Source:** (optional)
Rejected alternatives (R-NNN):
### R-NNN: Short rejected-option title
- **Rejected:** YYYY-MM-DD
- **Reason:** ...
- **Cross-reference:** [D-NNN] (what was picked instead)
Claiming an ID
Until the pql planning subcommands land (Q-21),
claim IDs by inspecting the highest existing D-NNN / Q-NNN /
R-NNN in the target file and incrementing.
Once pql decisions claim D <domain> "title" exists, use that —
same semantics, no race on concurrent sessions.
Querying
pql decisions … reads decisions/*.md and writes .pql/pql.db
(gitignored; markdown is the source of truth).
Common queries:
pql decisions list --type confirmed --domain architecture
pql decisions show D-5 --with-refs
pql decisions coverage # D-records without tickets
pql decisions validate # pre-push parser gate
pql ticket board # kanban view of tickets
Adding a decision
- Edit the appropriate domain file.
- Follow the record shape above.
- Run
pql decisions validate(also runs inmake push-check). - Commit. The SQLite index rebuilds from markdown on any
pql decisions sync.
Decisions
- D-1: CLI-first, not MCP — architecture
- D-3: pql as supporter tool; clide wraps, never duplicates — architecture
- D-4: Ignore file strategy — architecture
- D-5: Dart core; sidecar dissolved;
ptycas pql-peer — architecture - D-6: CLI and event surface contract — architecture
- D-7: App root is bare
WidgetsApp— architecture - D-8: Feature-first folder layout — architecture
- D-9: Three-tier theme pipeline — architecture
- D-10: State management —
ChangeNotifier+ListenableBuilder— architecture - D-11: Panel manager is kernel; layout is data; three-column is a preset — architecture
- D-12: Kernel admission rule — mandatory shared singletons only — architecture
- D-13: Git hardcoded in kernel project-loader — architecture
- D-14: Two-tier disable — kernel locked, everything else extension-shaped — architecture
- D-15: Extension grain — container-level, multi-contribution — extensions
- D-16: Built-ins in Dart, third-party in sandboxed Lua — extensions
- D-17: Panels are extension-shaped from day one — extensions
- D-18: YAML for themes + manifests; JSON for i18n catalogs — extensions
- D-19: Lua runtime as
ptyc-peer supporter tool — extensions - D-20: A11y is a Tier-0 contract — accessibility
- D-21: i18n is a Tier-0 contract (fframe pattern + locale-fallback chain) — accessibility
- D-22: WCAG-AA contrast gate on bundled themes — accessibility
- D-23: Test pyramid — seven layers — testing
- D-24: Golden tests — primitives only, Alchemist + Ahem — testing
- D-25: Mocks — mocktail at IO, hand-rolled fakes for ChangeNotifiers — testing
- D-26: Web driver — raw Playwright + Flutter semantics — testing
- D-27: Startup regression gate — testing
- D-28: Test organisation — mirror
lib/intest/— testing - D-29: Pre-push gate — fast layer only — testing
- D-30: Tests are client-side only — testing
- D-31: Prefer-zero-deps, exact-pin — tooling
- D-32: CI — Gitea primary, Linux-only runners, not yet activated — tooling
- D-33: Golden-output ignore pattern —
coverage.*excludes output, not scripts — tooling - D-34: Q&D record system — process
- D-35: Kanban / waterfall, not Scrum — process
- D-36:
.claude/is committed project surface, managed through the IDE — process - D-37: Commit conventions per git-commit skill — process
- D-38: Changelog discipline — Keep a Changelog 1.1.0 — process
- D-39: Planning tooling lives in pql, not clide — process
- D-40: [SUPERSEDED] Python stopgap under
tools/scripts/plan— process - D-41: Claude panes — one primary per repo, tmux-backed — architecture
- D-42: Dependencies documented in
licenses.yaml— tooling - D-43: Design handoff — adopt token palettes, reject Material wrapper — architecture
- D-44: Four bundled themes — clide, midnight, paper, terminal — architecture
- D-45: Syntax highlighting tokens in the theme pipeline — architecture
- D-46: Core frame builtins vs shipped extensions boundary — extensions
- D-47: Interaction model — Claude-is-home layout — architecture
- D-48: Chrome budget — no tabs, no breadcrumbs, keyboard-first — architecture
- D-49: Editor mode — inline above Claude, viewer swap — architecture
- D-50: Context auto-behavior — right panel reacts to Claude — architecture
- D-51: Panel collapse — 12px spine with badge — architecture
- D-52: Focus mode — full-window takeover — architecture
- D-53: State persistence across sessions — architecture
- D-54: Keyboard map — canonical shortcuts — architecture
- D-55: Claude pane internal tabs for multi-session — architecture
- D-56: Dissolve daemon process; Flutter app hosts IPC server — architecture
- D-57: Frameless custom chrome with per-column 24px hats — architecture
- D-58: Format engines are adoptable dependencies — tooling
- D-59: Bundled git via dugite-native — tooling
- D-60: No network on default launch path — tooling
- D-61: Dependency vetting checklist — tooling
- D-62: Dependency removal process — tooling
- D-63: Vendored binary rebuild process — tooling
- D-64: No telemetry — architectural commitment — architecture
- D-65: License compatibility matrix — tooling
- D-66: Line coverage gate at 95%, ratcheted from current — testing
Open questions
- Q-1: Authorisation granularity on the IPC socket — architecture
- Q-2: Back-pressure on event streams — architecture
- Q-3: Event persistence + audit/undo — architecture
- Q-4:
.canvasschema compatibility with Obsidian — architecture - Q-5: IPC wire-format stability +
schema_version:— architecture - Q-6: Window chrome — native frame vs frameless custom — architecture
- Q-7: macOS app bundle signing / notarisation — architecture
- Q-8: Extension API shape — widgets, subcommands, both? — extensions
- Q-9: Lua runtime vendoring — extensions
- Q-10: Extension manifest
schema_version:— extensions - Q-11: Coverage gates — hard thresholds vs soft reporting — testing
- Q-12: Screen-reader automation (axe-core via Playwright) — testing
- Q-13: Web production-mode a11y — accessibility
- Q-14: i18n plurals / gender / date-format tooling — accessibility
- Q-15: Editor tab — full LSP vs tree-sitter-only highlight — process
- Q-16:
tree-sitter-dartgrammar maintenance — process - Q-17: Icon set growth — process
- Q-18: Theme hot-reload in release builds — process
- Q-19: (withdrawn) — process
- Q-20: Kernel DB service — namespaced SQL access? — process
- Q-21: Pql absorbs planning vs keeps separate — architecture
- Q-22: Ticket persistence strategy — architecture
- Q-23: SSH-remote development — run clide against a remote workspace — architecture
- Q-25: Body text face — mono everywhere vs Josefin Sans UI + mono code — architecture
- Q-26: Small screen layout (< 1000px) — architecture
- Q-27: Two-editor split — architecture
- Q-28: Terminal strip scope — shell only or logs/errors/tests — architecture
- Q-29: Branch picker location — architecture
- Q-30: Focus behavior when editor is dirty and viewer is peeked — architecture
- Q-31: XWayland fallback for frameless — proper Wayland protocol needed — architecture
Rejected
- R-2: Go sidecar — rejected
- R-3:
MaterialApproot — rejected - R-4: Flutter
intl+ ARB codegen for i18n — rejected - R-5: Patrol test runner — rejected
- R-6: Nerd-font glyph icons — rejected
- R-7:
CupertinoApproot — rejected - R-8: Riverpod / Provider / BLoC for state — rejected
- R-9: Port planning tooling into clide — rejected
- R-10: Python-script stopgap under
tooling/db/— rejected - R-11: Permanent stopgap — rejected
- R-12: MaterialApp wrapper from design handoff — rejected