docs: record the true-decomposition pattern (ChatOverlayLayer) + handoff refresh

ai.md: Key patterns gains the 'true decomposition beats partial-shuffling'
rule + the glue-vs-component diagnostic (count OnPropertyChanged/SetProperty;
extract only zero/low-glue cohesive state blobs like chat's; leave binding glue
over already-extracted services alone; line count is a guideline not a goal).
ViewModels table row notes Chat.cs is now a thin facade over ChatOverlayLayer.

HANDOFF: everything through Commit G is pushed (origin/main=85893ea); the
remaining big decomposition is the scene-graph segment, flagged as design-needed
(not an unsupervised peel).
This commit is contained in:
2026-08-31 11:16:02 -07:00
parent 85893ea709
commit 84a038c498
2 changed files with 53 additions and 41 deletions
+51 -40
View File
@@ -2,46 +2,54 @@
## Branch / Commit State
**`main`**, working tree is **CLEAN**. `origin/main` == `1f4624c` (pushed).
**`main`**, working tree is **CLEAN**. `origin/main` == `85893ea` (pushed).
**Pushed** (reached `origin/main` == `1f4624c`, incl. tags): Phase 1 commit `0`
+ refactor commits `1..11`, **and Phase 2 commits `12..18`** (they were pushed
at the Phase-2 milestone; the old "Phase 2 local-only" claim below was written
before that push and is stale).
**Pushed** (reached `origin/main` == `85893ea`, incl. tags): Phase 1 commit `0` +
refactor commits `1..11` + **Phase 2 commits `12..18`** + the `Controls/index.md`
docs commit `cb54637` + **Phase 3 splits A–E** (tags `refactor-commit-A..E`) +
**Commit F (Recording, `refactor-commit-F`)** + **Commit G (ChatOverlayLayer,
`refactor-commit-G`)**. Everything is pushed; nothing local-only.
**LOCAL ONLY (Phase 3 — A, B, C, D, E) + the Controls doc commit** — policy
2026-08-30: no per-commit push; `git push` only at a user-agreed milestone /
"push it". **Push pending on explicit user approval:**
**Commit log (all pushed):**
| Commit | Hash | Tag | Payload |
|--------|------|-----|---------|
| docs | `cb54637` | — | `Controls/index.md` (missing per-directory map) |
| docs | `cb54637` | — | `Controls/index.md` |
| A | `6944db8` | `refactor-commit-A` | split `MainViewModel.cs` core → **495** |
| B | `31362d1` | `refactor-commit-B` | split `MainViewModel.Streaming.cs` → **330** |
| C | `fab2e09` | `refactor-commit-C` | split `MainViewModel.Background.cs` → **418** |
| D | `d3271a0` | `refactor-commit-D` | trim `SocialsDialogViewModel.cs` → **334** |
| E | `dcb3637` | `refactor-commit-E` | split `LayoutStore.cs` → 6 partials, **≤495** |
| E | `dcb3637` | `refactor-commit-E` | split `LayoutStore.cs` → 6 partials |
| F | `3107f92` | `refactor-commit-F` | extract recording concern → `MainViewModel.Recording.cs` |
| G | `85893ea` | `refactor-commit-G` | **first true decomposition** → `Services/ChatOverlayLayer.cs` |
## What's In Flight
Nothing code-in-flight — working tree clean, **Phase 3 complete**.
Nothing code-in-flight — working tree clean.
**Phase 3 result:** every production `.cs` is now **≤ 500 lines** (checked via
`git ls-files '*.cs'` minus tests; nothing exceeds 500). The 500-line count is a
**hard ceiling, not the goal** — each file was split **grouped by functionality**
so an AI can process one concern per file. Splits were **concern-driven**:
- `MainViewModel` → `.Sources.cs`/`.Web.cs`, `Streaming.cs` + `Streaming.Operations.cs`,
`Background.cs` + `Background.Model.cs`; `SocialSlotViewModel.cs` (row VM).
- `LayoutStore` (was 1402) → `Migrations.cs`/`Load.cs`/`Save.cs`/`Settings.cs`/
`Assets.cs` + a 47-line shell; `public partial class LayoutStore : IDisposable`.
**The directive (2026-08-31, user):** rewrite the project, breaking files into
**functional components to compliment AI retrieval/processing** — NOT line-count
chasing. Line count is a guideline for context management, not a design goal.
Every change: 0-warning build, `scripts/verify.sh` (246 pass + 2 known only),
explicit-file `scripts/scope-check.sh`, `ViewModels/index.md` tracker in the
SAME commit, tagged `refactor-commit-N`, no per-commit push.
**What was done:**
- **Phase 3 (A–E):** every production `.cs` ≤ 500, grouped by concern. These are
*partial shuffles* — same class, same shared state. Marginal for retrieval.
- **Commit F:** recording-output concern → `MainViewModel.Recording.cs` (partial).
- **Commit G — the real win:** `Services/ChatOverlayLayer.cs` is a genuine
owner-state component (buffer + renderer + timers + preview + live `RenderFrame`);
`MainViewModel.Chat.cs` 194 → 44 (thin binding facade). First true decomposition.
**Next:**
- If user says "push": `git push origin main && git push --tags` (6 commits:
`cb54637` + A–E, and tags `refactor-commit-A..E`).
**Expert diagnostic (recorded in `ai.md` → Key patterns):** the remaining partials
(Audio, Webcam, Background, Scenes, Socials…) are **binding glue over already-
extracted services** (`AudioMixer`, `CameraManager`, `ScreenCaptureManager`,
`ChatBoxRenderer`, `SocialValidator`). They have no cohesive owner-state blob to
peel — forcing extraction adds coupling. **Chat was the one clean peel.**
**Next (recommended):** the one remaining *genuine* big decomposition is the
**scene-graph segment** (the `Scenes`/`StagedScene`/element-inventory backbone
every feature hangs off). This is a real architectural redesign — a `SceneGraph`
owner-object with narrow seams — that touches the binding surface and needs
design review, NOT an unsupervised autonomous peel. Do not attempt it blind pre-1.0.
**Pending bus:** `ViewModels/index.md` Phase 3 tracker has rows A–E (closed);
Phase 3 marked COMPLETE. Watch-list (under limit, no action): `Controls/PreviewPane.xaml.cs`
@@ -75,7 +83,9 @@ Phase 3 marked COMPLETE. Watch-list (under limit, no action): `Controls/PreviewP
- MainViewModel refactor: **Phase 1 complete (11/11 partials)**, pushed.
- MainWindow.xaml refactor: **Phase 2 complete (6/6 controls)**, pushed at `1f4624c`.
- 500-line compliance: **Phase 3 complete (all 5 offenders ≤ 500)**, local-only A–E.
- 500-line compliance: **Phase 3 complete (A–E, all ≤500)**, pushed.
- **True decomposition: Commit G — `Services/ChatOverlayLayer.cs` shipped + pushed** (first owner-state component; pattern recorded in `ai.md`).
- **Next (design-needed, do NOT blind-peel):** the scene-graph segment (`SceneGraph` owner-object) — the one remaining genuine big decomposition; touches binding surface, needs review.
- TASK 3: 27/30 (preview compositor 16, text source 17, alerts 20 still open).
- TASK 4: ✅ shipped. TASK 9: items 1–3 shipped; 4–7 open. TASK 10: steps 1–7; Velopack pending.
- TASK 18: shipped, creator verification pending. TASK 19/23, 20, 21-A: shipped.
@@ -83,20 +93,21 @@ Phase 3 marked COMPLETE. Watch-list (under limit, no action): `Controls/PreviewP
## Session summary (2026-08-31)
- Ran the **500-line Phase 3 split to completion** under the standing "continue
without stopping" directive — no interruption prompts, no `question` tool.
- Commits A–E landed locally, each: cut → 0-warning build → verify (246 pass + 2
known) → scope-check → index.md in-commit → `git tag refactor-commit-{A..E}`.
- Ran the **500-line Phase 3 split to completion** (A–E), then the continuation.
- **Re-structuring principle (user correction, 2026-08-31):** split by
**functionality**, so an AI can process one concern per file; the 500-line
count is a **ceiling**, NOT the target. Do not pad or reshape code to a
number — group by concern and only split enough to stay under the ceiling.
- **Commit E (LayoutStore)** the biggest: 1402 → 6 concern-based partials
(Migrations/Load/Save/Settings/Assets/shell), default partial split.
count is a **ceiling**, NOT the target. Do not pad or reshape code to a number.
- **Correction of a false premise:** my plan to "extract FFmpegEncoder /
StreamHealthMonitor / FramePump" was a no-op — those already exist as
`Services/Encoder/*`. The honest seams were (F) the recording concern and
(G) the chat overlay.
- **Commit G = first TRUE decomposition:** `ChatOverlayLayer` owns chat state +
behavior; `MainViewModel.Chat.cs` 194 → 44 thin facade. This is the pattern
that actually compliments AI retrieval (one self-contained unit per feature),
unlike the partial shuffles of A–E, which only marginalize context because
every partial still shares the god-object's state.
- **Accident caught & recovered (Commit D):** a `> ViewModels/SocialsDialogViewModel.cs`
write that read from the file it was simultaneously truncating left the file at
1 line. Fixed IMMEDIATELY via `git checkout --` and re-ran the split. **Lesson**
(goes in `MyMistakes.md`): never `awk … > SRC` where `awk` also reads `SRC`;
stage every multi-block cut into temp files first, then assemble. All later
LayoutStore cuts did exactly that (read original once into temp files).
- Push checkpoint reached; awaiting explicit "push" for `cb54637` + A–E + tags.
write that truncated the file it was reading left it at 1 line; restored via
`git checkout --`, re-ran from temp files. **Lesson** in `MyMistakes.md`: never
`awk … > SRC` while awking SRC; stage cuts into temp files, then assemble.
- Everything through G is **pushed to `origin/main` (`85893ea`)** with tags A–G.