docs: notify agents + contributors of the MainWindow decomposition (#3351)#3564
Conversation
…3351) The #3351 split is only recorded in each MainWindow_*.cpp header comment — which you only see after opening the wrong file. This surfaces it up front, for both AI tools and humans, and closes the ownership gap the split opened. - MainWindow.cpp / MainWindow.h: point-of-use banner — "this file is not the home for new feature code; use the matching MainWindow_*.cpp sibling." - docs/architecture/mainwindow-decomposition.md (new): the TU map + a "where does my change go?" decision guide + the include/wiring conventions; linked from the docs/architecture index. - AGENTS.md: note the decomposition on the MainWindow architecture line and add an "Adding code to MainWindow" pattern (reaches all AI tools, since CLAUDE.md/GEMINI.md point here). - CONTRIBUTING.md: a "Working in MainWindow" note, and clarify in the review tiers that ONLY core MainWindow.{h,cpp} is maintainer-only. - CODEOWNERS: enforce maintainer-only on the two core files (which CONTRIBUTING already claimed but CODEOWNERS did not encode). The MainWindow_*.cpp siblings are deliberately LEFT on the Tier 3 reviewer default — broadening review of extracted feature code to the whole team was a goal of the decomposition. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Follow-up to the decomposition notice: the doc said WHERE a new subsystem goes but gave no criteria for WHEN a new MainWindow_*.cpp sibling is justified. Adds a section with a floor and a ceiling: - Default to extending an existing sibling; a new TU is for a distinct cohesive subsystem (~500+ lines) with no existing home — not a stray method or two. - Size is a signal, not a trigger; don't pre-create near-empty TUs. - Split an existing sibling only when it accretes a *second* subsystem. - The ceiling: once a TU is one cohesive subsystem at a reviewable size, STOP. Subdividing finer adds build cost (every sibling re-parses the ~1,000-line MainWindow.h; header edits rebuild all 8) and arbitrary seams without decoupling anything. If tempted to slice thinner, extract a real class instead (the #3557 direction) — the only move that shrinks the shared header and creates a compiler-enforced boundary. AGENTS.md table row + a short note cross-reference the new section. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The decomposition + new-TU sections grew the file past the stated count. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
NF0T
left a comment
There was a problem hiding this comment.
Content and structure are solid — the banners, AGENTS.md additions, CONTRIBUTING.md note, CODEOWNERS gating, and doc are all exactly the right response to the #3351 documentation gap.
One required fix before merge: the TU map in docs/architecture/mainwindow-decomposition.md is missing two of the nine sibling TUs. Both exist in CMakeLists.txt and have opening charters that make the entries easy to write:
| Missing TU | Charter (from file header) |
|---|---|
MainWindow_DspApplets.cpp |
wirePooDooTiles() + wireDspApplets() — PooDoo RX status tiles, P/CW/PHNE/EQ applets, client DSP family (Compressor / Gate / De-esser / Tube / Reverb / AetherDSP / PUDU TX+RX), TX signal-chain + PUDU monitor wiring |
MainWindow_Session.cpp |
wireDiscovery() / wireRadioModel() / wirePanLifecycle() — LAN/SmartLink discovery, RadioModel connection-state routing, pan-stream lifecycle; seeded as future RadioSession |
A contributor looking at the table before adding DSP applet wiring or session-scoped code wouldn't find the right TU — which is exactly the gap this PR is closing.
Side note on #3407: the new "Wiring split mirrors the widget's lifecycle" convention in the doc clarifies our earlier comment. The RxApplet::wfmActivated connection in the constructor is correct per that rule (singleton widget, wired once at construction → stays in MainWindow.cpp). Only the activateWFM() / deactivateWFM() / reflectWfmButtons() bodies still need to move to _DigitalModes.cpp per the decision table.
There was a problem hiding this comment.
Thanks for this, @ten9876 — surfacing the #3351 decomposition at the project level (point-of-use banners + canonical doc + AGENTS.md/CONTRIBUTING + the CODEOWNERS gap-close) is genuinely useful, and the layering across tools is well thought out. The banners are comments so there's no build risk, the AGENTS.md #adding-code-to-mainwindow anchor and the ../../CONTRIBUTING.md / ../../.github/CODEOWNERS relative links resolve correctly, the CODEOWNERS scoping-to-core-only is correct (there were no prior src/gui/ rules), and the "~440 lines" AGENTS.md figure now matches reality (it was stale at "~330").
One substantive issue, since this doc's whole job is to be the map agents consult before routing code:
The TU map is missing two sibling TUs, and the "8 today" count is off. The repo actually has 9 MainWindow_*.cpp siblings; the map in docs/architecture/mainwindow-decomposition.md lists 7. Missing:
MainWindow_Session.cpp(Phase 2c) —wireDiscovery()/wireRadioModel()/wirePanLifecycle(); the seed of the futureRadioSessionaggregate (#3445).MainWindow_DspApplets.cpp(Phase 2d) —wireDspApplets()/wirePooDooTiles(); client-DSP applet + PooDoo tile wiring.
Both are real MainWindow:: members carved out under #3351, so they belong in the map. Concretely:
- Add the two rows to the TU map table (the
Phasecolumn already fits — 2c/2d). - Update "there are 8 today" (in the When a new TU is warranted section) to 9.
- Minor consequence worth a glance: the decision-guide row "Connecting a newly-created radio object (slice/pan/VFO/DSP widget) →
MainWindow_Wiring.cpp" slightly overlaps these — pan-lifecycle wiring actually lives inMainWindow_Session.cppand DSP-applet wiring inMainWindow_DspApplets.cpp. Not blocking, but a one-line note ("session/pan-lifecycle wiring →_Session; DSP-applet wiring →_DspApplets") would keep an agent from landing it in the wrong sibling.
An incomplete map is the one failure mode that undercuts the goal here — an agent looking for where session/discovery or DSP-applet wiring goes wouldn't find a home and would likely default back to MainWindow.cpp, exactly what this is meant to prevent. Worth a quick pass to enumerate the siblings straight from ls src/gui/MainWindow_*.cpp so the map can't drift. Everything else looks good.
🤖 aethersdr-agent · cost: $6.0137 · model: claude-opus-4-8
…#3564 review) NF0T (blocking) and the bot both caught that the TU map listed only 7 of the 9 MainWindow_*.cpp siblings. Root cause: the original list was enumerated from the refactor/3351-phase2b-spots branch, which predates phases 2c/2d. - Add MainWindow_Session.cpp (Phase 2c — wireDiscovery/wireRadioModel/ wirePanLifecycle; seed of RadioSession #3445) and MainWindow_DspApplets.cpp (Phase 2d — wirePooDooTiles/wireDspApplets) to the TU map. - Decision guide: split the generic "wire a new radio object → _Wiring" row so discovery/connection/pan-lifecycle routes to _Session and DSP-applet/PooDoo wiring routes to _DspApplets (the overlap the bot flagged). - Fix the count: "8 sibling TUs" → 9 (10 files include MainWindow.h). - Complete the condensed enumerations in AGENTS.md (routing cell) and CONTRIBUTING.md (sibling list) to match. Verified the map against `ls src/gui/MainWindow_*.cpp` — all 9 present. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
Fixed in Root cause: I enumerated the sibling list from the Changes:
Verified the map against @NF0T — re your #3407 side note: agreed, and the Ready for re-review. |
There was a problem hiding this comment.
Thanks for this, @ten9876 — this is a well-targeted bit of documentation hygiene. The "documented only inside each sibling's header comment, which you see after opening the wrong file" framing is exactly the gap, and surfacing it at the point of use is the right instinct.
I verified the structural claims against the tree and they hold up:
- TU map is accurate. All nine
MainWindow_*.cppsiblings plusMainWindowHelpers.{h,cpp}andMainWindowShortcutState.hexist exactly as listed; the "9 siblings / 10 files include the header" counts are correct. - The AGENTS.md line-count bump is real, not a typo.
AGENTS.mdonmainis already 407 lines, so "~330" was stale; 407 + ~33 added ≈ "~440". Good catch correcting it. - CODEOWNERS does what the PR claims. The two exact-path lines are appended last, so under last-match-wins they gate only
MainWindow.{h,cpp}to@aethersdr/maintainerswhile the sibling TUs fall through to the*Tier-3 reviewer default — matching the stated "deliberately broad" intent. The inline comment warning against a futureMainWindow*glob is a nice touch.
Two minor, non-blocking points:
-
The
MainWindow.cppbanner's top rule line looks UTF-8-corrupted. In the diff, that first line's box-drawing run breaks with replacement characters (───���───) partway across, whereas theMainWindow.hbanner is clean. It's harmless to the build (it's a comment), but a little ironic in a banner whose whole job is to look clean to everyone who opens the file — worth re-saving that line as UTF-8 to matchMainWindow.h. Please double-check on your end, since this could in theory be a transport artifact rather than the committed bytes. -
CODEOWNERS header block vs. the new lines. The carefully-written tier narrative at the top (lines 1–52) maps
src/→ Tier 3 reviewers and frames Tier 1 as "governance, security, bot policy." The two new maintainer-gatedsrc/gui/MainWindow.{h,cpp}lines are source code at the maintainer tier — a genuine exception that the top-of-file model doesn't mention. The inline comment above the lines explains why well; consider a one-liner in the header block too (or noting it's an intentional source-code exception), so a reader following the tier model isn't surprised to findsrc/files at Tier 1.
Neither blocks merge. Nice work closing the ownership gap the split opened.
🤖 aethersdr-agent · cost: $2.4734 · model: claude-opus-4-8
NF0T
left a comment
There was a problem hiding this comment.
Both items from the CHANGES_REQUESTED are resolved. MainWindow_Session.cpp and MainWindow_DspApplets.cpp are now in the TU map with accurate charters drawn from their file headers, the sibling count is updated in the prose (9 TUs / 10 files), and the decision guide has two new disambiguation rows (_Session.cpp vs _Wiring.cpp for discovery/connection/pan-lifecycle; _DspApplets.cpp vs _Wiring.cpp for client-DSP applets). CONTRIBUTING.md and the AGENTS.md decision table are consistent with the updated map. Approved.
Why
The #3351 MainWindow decomposition is real in the code but invisible at the
project level — it's documented only inside each
MainWindow_*.cppheadercomment, which you only see after you've already opened the wrong file to add
code. This surfaces it up front for both AI tools and human contributors, and
closes an ownership gap the split opened.
What's in here (5 pieces)
MainWindow.cppandMainWindow.h—the one place everyone sees the instant they go to add code: "this file is
not the home for new feature code; use the matching
MainWindow_*.cppsibling." Reaches every tool (Copilot, Aider, a human in an editor), not
just ones that load AGENTS.md.
docs/architecture/mainwindow-decomposition.md— theTU map, a "where does my change go?" decision table, and the
include/wiring conventions (incl. the Qt 6.4.2 explicit-includes rule).
Indexed in the
docs/architectureREADME.MainWindowarchitectureline and adds an "Adding code to MainWindow" pattern. Since CLAUDE.md /
GEMINI.md / the Copilot + Aider files all point at AGENTS.md, this reaches
every AI tool at once.
clarification in the review-tier section.
(
MainWindow.{h,cpp}), which CONTRIBUTING already claimed but CODEOWNERSnever actually encoded.
Ownership decision (intentional)
Only core
MainWindow.{h,cpp}is maintainer-gated. TheMainWindow_*.cppsibling TUs are deliberately left on the Tier 3 reviewer default — widening
review/approval of extracted feature code to the whole reviewer team was a
primary goal of the decomposition, so feature work in a sibling TU doesn't
bottleneck on a maintainer. The CODEOWNERS comment documents this so a future
edit doesn't re-gate the siblings with a
MainWindow*glob.Verification
AetherSDRbuilds clean (banners are comments); all doc cross-links and theAGENTS.md anchor resolve.
🤖 Generated with Claude Code