Skip to content

Decisions index

Status: living | Audience: anyone looking for where a decision is recorded | See also: ../README.md

Decisions are recorded inline, where they're made — in the design or development doc discussing the tradeoff, stamped (decision YYYY-MM-DD). This index exists only for discoverability: one row per decision, pointing at the doc that records it. Adding an inline stamp means adding a row here in the same commit; a row with no matching stamp, or a stamp with no row, means someone skipped half the rule.

The 2026-07-18 rows below were decided in the pre-code planning session, so they carry no issue references. Once work runs through issues, stamps take the form (decision YYYY-MM-DD, #NN).

Date Decision (one line) Recorded in Status
2026-07-18 Stack locked in one pass: Electron + TypeScript + React with electron-vite / electron-builder and the seed kit's governance toolchain development/TechStack.md § The stack Adopted
2026-07-18 ATC audio commits to all four behaviors: activity lights, one-click solo, stereo pan, priority auto-duck design/Audio.md § The unifying principle Adopted
2026-07-18 Ducking rule: duck only under a strictly-higher-priority active stream, to −12 dB, fast duck / slow release design/Audio.md § ATC streams Adopted
2026-07-18 Per-stream output-device routing for ATC streams design/Audio.md § ATC streams; development/TechStack.md § Why this stack Adopted
2026-07-18 Build sequencing within audio: lights → solo → pan → duck Implementation-Plan.md § Phase 2b Adopted
2026-07-18 Curated defaults + human-editable config file; no in-app management UI in alpha design/Video.md § Feed sourcing; design/Stakeholders/Command-Center-Enthusiast.md § Domain of awareness Adopted
2026-07-18 Live-stream discovery is on-demand only — no background polling design/Video.md § Feed sourcing Adopted
2026-07-18 Restore last session on relaunch: layouts, feed assignments, pop-outs, per-stream settings design/Video.md § Pop-outs and restore Adopted
2026-07-18 Tracking panel is a genuine embedded browser (the site refuses lightweight embedding — verified) design/Tracking.md § Features Adopted
2026-07-18 Tracking navigation stays minimal: back / forward / reload / home preset on Oshkosh design/Tracking.md § Features Adopted
2026-07-18 Tracking session and login persist across relaunches design/Tracking.md § Features Adopted
2026-07-18 Tracking panel lands in the walking skeleton — bounds-sync is the foundational layout risk Implementation-Plan.md § Phase 1 Adopted
2026-07-18 Kit's one-phase-in-progress rule adapted to one phase per track for the agent-assisted sprint Implementation-Plan.md § header + intro Adopted
2026-07-18 Alpha ships config-file-driven with unsigned builds; Casual Spotter gaps accepted and named design/Personas.md § Alpha priority; design/Stakeholders/Casual-Spotter.md § Value Adopted
2026-07-18 Public GitHub releases from a public repository design/Stakeholders/Programmer-Aviator.md § Value Adopted
2026-07-18 Governance solo-tuned for the sprint (no required reviews; protection on main only); tightens post-show design/Stakeholders/Programmer-Aviator.md § Not expected to Adopted
2026-07-18 Docs website is generated from docs/ by MkDocs Material — machinery in website/, Pages source moves to Actions, landing page becomes docs/index.md; ships with Phase 5 Implementation-Plan.md § Phase 5; development/TechStack.md § The stack Adopted
2026-07-18 Binary assets tracked with Git LFS from first commit; legacy-Pages pointer caveat accepted until the Phase 5 site build development/TechStack.md § The stack + Known limitations Adopted
2026-07-19 Packaged renderer served from a loopback HTTP server (127.0.0.1); app:// demoted to a logged fallback, because YouTube's IFrame API rejects the app:// origin (error 153) development/TechStack.md § Known limitations Adopted
2026-07-19 A muted higher-priority channel does not duck lower channels — its light still shows activity, but it never ducks audio the operator is actually listening to design/Audio.md § ATC streams Adopted
2026-07-19 Project renamed airshow-traffic-monitor / "Airshow Traffic Monitor" — airshow-generic identity; EAA AirVenture stays the first target, not the boundary README.md § intro Adopted
2026-07-19 Docs-site home is docs/README.md, not a new docs/index.md — MkDocs collides the two at the site root, and the plan-frozen Implementation-Plan.md links to README.md, so README.md stays the home and index.html is deleted (refines the 2026-07-18 "landing page becomes docs/index.md" row) development/Pages-deployment-runbook.md § Sequencing gotcha Adopted
2026-07-19 Session restore is one session.json (electron-store), held authoritative in memory and flushed atomically on a ~500 ms debounce (guaranteed flush on quit) development/TechStack.md § Session restore and pop-outs Adopted
2026-07-19 Missing-display window bounds are validated by a pure, Electron-free function that recentres/shrinks an off-screen window onto a connected display development/TechStack.md § Session restore and pop-outs Adopted
2026-07-19 Per-stream volume/mute/pan are session-restored; priority stays config-owned (re-derived from config.json each launch, never session-pinned) development/TechStack.md § Session restore and pop-outs Adopted
2026-07-19 Pop-outs are grid-only windows loading the same bundle at ?window=popout&id=N; feeds hand off from the main grid and return on close, and quit preserves pop-outs for restore development/TechStack.md § Session restore and pop-outs Adopted
2026-07-19 Field weather sourced from the free, keyless aviationweather.gov Data API (METAR+TAF JSON); fetched main-process-only with a descriptive User-Agent, polled no more than every 5 minutes development/TechStack.md § Known limitations Adopted
2026-07-19 ATC streams are on-demand: they start disconnected (no network activity), the status pill is the connect toggle, and the connected set is session-persisted and restored (staggered) on relaunch design/Audio.md § ATC streams Adopted
2026-07-19 Reconnect back-off for a wanted-but-down stream eases from fast retries to a slow ~60 s cadence after ~5 consecutive failures, shown as a calm "feed down" state instead of a climbing counter design/Audio.md § ATC streams Adopted
2026-07-19 v0.1.0 is a personal-use milestone and pipeline validation, not a launch: no promotion or distribution beyond the primary operator until LiveATC.net grants stream-use clearance (a hard gate on any announcement) Implementation-Plan.md § Milestone Adopted
2026-07-19 Channels are managed in-panel — an add-channel dialog lists an airport's LiveATC feeds; the panel rewrites the streams block of config.json (kept hand-editable and atomically written), superseding the 2026-07-18 "no in-app management UI in alpha" for ATC audio design/Audio.md § ATC streams Adopted
2026-07-19 Priority is the channel list's vertical order, set by drag or keyboard (rank 1 = top); it stays config-owned and re-derived each launch, so a hand-edit and a drag are the same edit design/Audio.md § ATC streams Adopted
2026-07-19 A bundled KOSH feed snapshot is the add-channel fallback when the LiveATC directory refuses automated access (Cloudflare); it can add channels offline but cannot report live feed status design/Audio.md § ATC streams Adopted
2026-07-19 Panel layout is a serializable split tree in session.panelLayout, rendered by a single-container canvas, retiring rrp and its LayoutStorage strings shared/panelLayout.ts Adopted
2026-07-19 design/brand/tokens.css is imported canonically (straight from design/brand/) into the renderer rather than copied, so there is one source of truth for the Wyvern Watch color/type/motion system renderer/src/main.tsx Adopted
2026-07-19 Barlow Semi Condensed + Inter ship as woff2 files committed to the repo (latin subset, ~141 KB total) rather than a Google Fonts CDN import, so type renders correctly offline at the airfield renderer/src/assets/fonts.css Adopted
2026-07-19 The System/Cream/Ember theme toggle drives nativeTheme.themeSource in the main process (not per-renderer CSS) and persists in SessionState.theme, so every window — including pop-outs — and the OS chrome follow one change instantly main/ipc.ts Adopted
2026-07-19 Panel-canvas leaves render in fixed id-sorted DOM order, never by tree position, so rearranging a panel can never force React to reorder (and thus reload) an embedded video iframe renderer/src/layout/canvasRenderOrder.ts Adopted
2026-07-19 The main window's uniform/emphasized/fill-panel video grid modes are retired in favor of per-panel maximize plus a per-feed fit/fill toggle; pop-outs keep their own uniform/emphasized/fill grid renderer/src/state/store.ts Adopted
2026-07-20 A returning video panel (a pop-out closing) always docks to the BOTTOM ROW of the video grid via a video-only-region insertVideoLeafBottom op, replacing insertPanelBalanced's largest-all-leaf-group heuristic for video reopens specifically, which could otherwise land the panel in the audio/weather column shared/panelLayout.ts Adopted
2026-07-20 Pop-out windows are combined via an explicit "Merge into…" control (no window-to-window drag), moving feeds into a chosen target window and closing the source design/Video.md § Pop-outs and restore Adopted
2026-07-20 Native menus (a Panels checkbox per panel id) plus a DOM Move-panel modal are the FR24-safe/accessible move paths landed first; pointer-driven header-drag-to-dock is deliberately deferred to feature/panel-drag-dock main/menu.ts Adopted
2026-07-20 Header drag-to-dock is custom pointer-event handling plus pure hit-testing against the canvas's own computed leaf rects — never elementFromPoint and not the browser's native HTML5 Drag and Drop API — with the native Panels/Layout menus and the DOM Move-panel modal kept as the FR24-safe, accessible fallbacks for the same move renderer/src/layout/useHeaderDrag.ts Adopted
2026-07-20 The react-resizable-panels dependency is removed: the panel layout is fully in-house (a serializable split tree, a single-container canvas render, custom splitters) after the last consumer (the main-window layout) moved off it in feature/panel-canvas-shell development/TechStack.md § Panel layout system Adopted
2026-07-20 The panel canvas (PanelCanvas/LeafFrame/Splitter/useHeaderDrag/DragOverlay, plus the shared leaf chrome in PanelChromeButtons) is window-agnostic: it reads/writes layout state only through a LayoutController interface delivered via React context, never the main window's useAppStore directly, so a future pop-out window can reuse the same canvas and video leaf body against its own state renderer/src/layout/LayoutController.ts Adopted
2026-07-20 Pop-out windows use the same panel canvas as the main window (per-window layout in PopoutState; the pop-out's own uniform/emphasized/fill-panel grid is retired in favor of maximize + per-feed fit/fill, refining the earlier 2026-07-19 row which still had pop-outs keeping that grid; the Layout Manager and named profiles stay main-window-only) design/Layout.md § Features Adopted
2026-07-20 The docs site is skinned with the Wyvern Watch brand — Material's design tokens re-pointed to Cream Classic / Ember, the app's own bundled Barlow Semi Condensed + Inter woff2 (no font CDN), and the brand favicon, logo, and OG social cards wired in (the last Phase 6 docs-site slice) website/mkdocs.yml + assets/brand/wyvern.css Adopted
2026-07-20 The site home is an advertisement: a full-bleed hero, screenshots, three-pillar pitch, and download CTAs render above the documentation index via website/overrides/home.html; docs/README.md keeps its doc-index body and stays the resolvable, plan-frozen root page (the ad sits on top of it) website/overrides/home.html Adopted
2026-07-20 The docs toolchain is pinned to MkDocs 1.x (mkdocs<2) because MkDocs 2.0 removes the plugin system and rewrites theming with no migration path — breaking Material for MkDocs and this site's overrides; mkdocs-material 9.x does not cap the core itself, so the pin lives in website/pyproject.toml. Zensical (the Material team's 1.x-compatible successor) is the eventual migration path development/TechStack.md § Known limitations Adopted
2026-07-20 Panels are held to their usable minimum size at RENDER time — clampTreeToMinPx rewrites each split's shares against the current pixel span before computeLayoutRects, so a panel can never collapse into an ungrabbable sliver; a shrunk window and compounding dock/move percentages are both corrected, not just a live splitter drag (the only place the min-px floor was applied before) shared/panelLayout.ts Adopted
2026-07-23 Docking a panel beside a neighbor whose parent split already runs the dock axis inserts it as a SIBLING of that neighbor, never a new same-orientation split wrapped around it (splitPanel, plus the root-dock join in movePanel) — a split nested inside a same-orientation split is a redundant level that paints a second, real, draggable divider mid-panel, the "phantom divider" that compounded over repeated docks/moves. Deliberately NOT a blanket normalizeTree flatten: that would also collapse the intentional FR24-over-video-grid grouping in the default layout and its resize-the-grid-as-a-unit behavior shared/panelLayout.ts splitPanel / movePanel Adopted