diff --git a/GOALS.md b/GOALS.md index 579c405d..5148df8a 100644 --- a/GOALS.md +++ b/GOALS.md @@ -6,8 +6,9 @@ > line. The `Platform-Neutrality Rule` at the top of `CLAUDE.md` is the *operational > rule*; **this file is the source of truth for *intent* and *sequencing*.** > -> _Last updated: 2026-09-03 β€” the queue drained; the mandated post-#735 audit is -> now run and its numbers are below. Milestone #7 is **0 open**._ +> _Last updated: 2026-09-05 (issue #827 correction pass β€” the 2026-09-03 revision +> went stale within 81 minutes of its own edit and stayed that way for two days; +> see "#47 was closed without its blocker" below). Milestone #7 is **0 open**._ ## 🎯 North star @@ -83,15 +84,21 @@ closed. The previous revision of this file said: *"re-run the sizing audit when #735 lands rather than assuming the chain finishes the job."* Done, on `develop @ eedebf8`. -Production lines, `#[cfg(test)]` excluded, all four columns measured with the same +Production lines, `#[cfg(test)]` excluded, all columns measured with the same script (`scripts/prod_lines.py`) so they are comparable to each other: -| | 2026-05-01 | 2026-07-01 | pre-chain 2026-08-31 | **now 2026-09-03** | -|---|---|---|---|---| -| `src/gtk/` | 18,969 | 13,675 | 12,526 | **9,650** | -| `src/tui_main/` | 14,649 | 10,358 | 11,125 | **10,345** | -| **both backends** | 33,618 | 24,033 | 23,651 | **19,995** | -| `src/render.rs` (shared) | 10,574 | 12,807 | 15,009 | **21,405** | +| | 2026-05-01 | 2026-07-01 | pre-chain 2026-08-31 | pre-#785 2026-09-03 | **post-#785, now @ `ee26268`** | +|---|---|---|---|---|---| +| `src/gtk/` | 18,969 | 13,675 | 12,526 | 9,650 | **2,607** | +| `src/tui_main/` | 14,649 | 10,358 | 11,125 | 10,345 | **10,366** | +| `src/app.rs` (hoisted out of `src/gtk/` by #785) | β€” | β€” | β€” | β€” | **7,131** | +| **all three files** | 33,618 | 24,033 | 23,651 | 19,995 (2 files) | **20,104** | +| `src/render.rs` (shared) | 10,574 | 12,807 | 15,009 | 21,405 | **21,405** | + +(All five 2026-09 revisions confirmed by re-running `prod_lines.py` against +`git archive ee26268`; the pre-#785 column is a snapshot at an earlier commit, +not a stale guess β€” it's what the tree actually was before #785 moved +`struct App`.) **Projected vs. actual, over the chain (08-31 β†’ 09-03):** @@ -115,18 +122,28 @@ shared engine grew *more* than projected. Where the reduction actually came from `gtk/mod.rs` alone is 78% of the cut. Notably `tui_main/mouse.rs` β€” the file #733 was sized against at βˆ’3,000β€¦βˆ’3,500 β€” lost **316 lines**. +**Attribution correction (#827): the βˆ’3,656 is mostly dead-code removal, not +convergence.** Of the βˆ’3,656 backend reduction, roughly **βˆ’2,825** is #731 +(orphan Relm4 handles) and #732 (the GTK `Msg` bus) deleting code outright β€” +that is almost all of the βˆ’2,834 booked against `src/gtk/mod.rs` above. +Convergence proper (#751–#766 actually sharing logic through `render.rs`) +moved something closer to **900 lines** out of the backends, while +`render.rs` absorbed roughly **7,000**. State it plainly: the chain did not +converge anywhere near as much as the raw βˆ’3,656/+6,396 pair implies: most of +the shrinkage is code that was simply dead. + > **#785 (stage 1 of #47) moved the mass, it did not delete it.** `struct App`, > its `impl` blocks and `impl quadraui::ShellApp for App` were hoisted verbatim > out of `src/gtk/mod.rs` into a new top-level `src/app.rs`. `src/gtk/` -> therefore reads **2,584** against the 9,650 column above and `src/app.rs` -> reads 7,131 β€” but the *total* is unchanged (+65, all of it module doc and -> re-stated imports). Nothing here got smaller; a ~6,900-line block that was +> reads **2,607** against the pre-#785 9,650 column above and `src/app.rs` +> reads **7,131** β€” both regenerated at `ee26268` in the table above β€” but the +> *total* is essentially unchanged (module doc and re-stated imports account +> for the difference). Nothing here got smaller; a ~6,900-line block that was > filed under "GTK backend" is now filed under "shell application", where a > second native backend can reach it. `src/app.rs` is still `gui`-gated: its > module doc enumerates the four platform-typed fields, ~11 platform hook call > sites and the `crate::gtk::{click, css, util}` dependency that have to go -> before the gate can. Read the backend columns above as *pre-#785* until they -> are regenerated. +> before the gate can. > **Correcting the record.** The figure this file previously carried as > "`src/gtk/` = 12,588 at 2026-09-01" was measured *before* #727/#728/#730 landed; @@ -152,13 +169,17 @@ the remaining gap is small. ### 1. The irreducible surface β€” βœ… aggregated, and it is small -Done: **[`docs/IRREDUCIBLE_SURFACE.md`](docs/IRREDUCIBLE_SURFACE.md)** (2026-09-03). +Done: **[`docs/IRREDUCIBLE_SURFACE.md`](docs/IRREDUCIBLE_SURFACE.md)** (2026-09-03, +corrected 2026-09-05 per #827 β€” the folder-picker verdict below was wrong). The headline, because it changes how the rest of this goal should be planned: -- The **nine** recorded verdicts reduce to **four distinct facts**, of which **three are - genuinely irreducible** β€” the TUI-only folder picker (GTK uses a native - `GtkFileChooser`), px-vs-cell frame metrics, and GTK's menu bar *being* its CSD - titlebar (#552). +- The **nine** recorded verdicts reduce to **three distinct facts**, of which **two are + genuinely irreducible** β€” px-vs-cell frame metrics, and GTK's menu bar *being* its CSD + titlebar (#552). A fourth candidate, the TUI-only folder picker, was recorded as + irreducible on the theory that GTK's native `GtkFileChooser` has no shared + counterpart β€” wrong: `quadraui::compose::FolderPickerController` has existed since + 2026-05-25 and its module doc explicitly tells vimcode to delete the local copy and + rewire both backends through it. That verdict is struck, not counted. - **Only 1.3% of the two backends names a native toolkit type** β€” 246 production lines out of 19,429 (`scripts/native_lines.py`; ~25% undercount on the GTK side for stored widget handles, so call it under 4% even pessimistically). @@ -170,7 +191,7 @@ The headline, because it changes how the rest of this goal should be planned: **Plan accordingly: this is ordinary duplication, not a platform-porting problem.** A plan that sizes it as the latter will keep missing its projection the way #751–#766 did. -**The fourth verdict was mislabelled** β€” `tui_main/mouse.rs:1620` (command-line text +**The third verdict was mislabelled** β€” `tui_main/mouse.rs:1620` (command-line text selection) reads as a decision but its own text says the fix is a `CommandLineLayout::hit_test` in quadraui. That is a *blocked* convergence whose blocker was never filed; `CommandLineLayout` does not exist in quadraui and **#194** is the @@ -179,43 +200,63 @@ milestone-discipline rule at the bottom of this file, which applies to in-code c too: **a comment naming a missing upstream API is an unfiled issue, and grep will not find it for you.** -### 2. The duplication moved down a level, into quadraui β€” and it is unqueued - -The two epics that now hold the mass of the remaining cross-backend duplication are -**open, un-milestoned, and in nobody's queue**: - -- **quadraui#481** β€” *"shared runtime core: one implementation of the duplicated 65% - across backends."* 1,671 non-trivial lines byte-identical between `gtk/*.rs` and - `macos/*.rs`; `EventOutcome` declared twice verbatim; the 120 ms resize debounce - written twice and absent on macOS; `shell_runner` 45 identical lines Γ—2. The - copies have already drifted. -- **quadraui#482** β€” *"Backend API integrity: units, symmetry, error channel, - panic-free text paths."* Trait asymmetry, off-trait rasterisers, unit leaks, and a - UTF-8 boundary fix that exists as **7 private copies and zero public ones**. +### 2. "The duplication moved down a level" is largely refuted (#827) -This is the same supply-side trap as before, one level down: vimcode's backends got -thinner by pushing logic into a crate whose *own* backends are duplicated. +The previous revision of this file claimed quadraui#481/#482 held a large, unqueued +mass of cross-backend duplication one level down. Re-checked against quadraui's own +pinned rev (`42e0f8f`) on 2026-09-05: most of the individual claims do not hold up. -### 3. #47 was closed without its blocker - -**#47 (native macOS GUI) is closed and shipped zero code.** Commit `44882e9` -("re-audit at pickup, no code β€” Backend-trait Rc-handle gap blocks Stage 1") -recorded the real blocker: `App` calls `GtkBackend::modal_stack_handle()` / -`drag_state_handle()` at 44 call sites in the drag/modal dispatch paths. Those are -**inherent methods on the concrete struct, not on `quadraui::Backend`**, and -`MacBackend`'s trait equivalents return short-lived `&mut` borrows incompatible -with `App`'s stash-then-reuse pattern. Full findings and two candidate API shapes -are in `PLAN.md`. - -That commit's own recommendation β€” *"file this as a quadraui issue before any -vimcode-side Stage 1 code is written"* β€” **was never carried out.** No open -quadraui issue mentions `modal_stack_handle` or `drag_state_handle`. The finding -now lives only in `PLAN.md`, attached to a **closed** issue, which is exactly where -a later triage pass will not look. - -**Action:** file the gap on `JDonaghy/quadraui` (or fold it into quadraui#482, its -natural home), re-open quadraui milestone **#9 "vimcode Platform-Neutral -blockers"**, and re-open vimcode#47 behind it. +| Claim (previous revision) | Reality at pin `42e0f8f` | +|---|---| +| `EventOutcome` declared twice verbatim | Declared **once** β€” `quadraui/src/runtime.rs:95` (quadraui#496, closed 09-02) | +| `shell_runner` 45 identical lines Γ—2 | Four runners of 4–7 non-comment lines each, all delegating to shared `shell_adapter.rs::build_shell_adapter` | +| 1,671 byte-identical lines gtk↔macos | Function-level duplication is ~85 lines. quadraui#481's own correction comment (09-03 17:45Z) withdrew the headline number as "idiom coincidence" | +| UTF-8 fix: 7 private copies, 0 public | **Public since 2026-08-15** β€” `text_util.rs:51-107`, re-exported from `lib.rs` (quadraui#503) | +| `gtk_tree_layout`/`mac_tree_layout` twins | Both 1-line wrappers over `primitives/layout_metrics.rs:60 tree_layout` (quadraui#499, 09-02) | +| "no `desktop/`" | `quadraui/src/desktop.rs` exists (754 lines) since 09-02 (quadraui#498) β€” the original claim grepped for a directory that had been renamed | +| #482 "holds the mass" | **All eight children #503–#510 are closed.** #482 has zero comments and is a hollow epic | + +**Still true:** macOS dispatches `WindowResized` undebounced (`macos/run.rs:544-561`) +while TUI/GTK use the shared `ResizeDebouncer`. That is a real, small, still-open gap β€” +just not the "65% duplicated" epic the previous revision described. quadraui#481/#482 +remain open and un-milestoned, but do not plan against their headline numbers; re-audit +the specific claim you need before acting on it. + +### 3. #47's blocker was filed and cleared β€” this section was stale for two days (#827) + +**Corrected 2026-09-05.** The previous revision said *"No open quadraui issue +mentions `modal_stack_handle` or `drag_state_handle`"* and called filing one "the +single most actionable item on this page." That stopped being true within hours of +being written: + +- **quadraui#699** was filed 2026-09-03 **16:38Z**, into quadraui milestone **#9**, + and **closed 17:11Z** (PR#700 / `88345fb`). A follow-up, **#704**, closed 21:41Z. +- **vimcode#47 was reopened 16:38Z** and is **OPEN**, in milestone **#5**, right now + β€” it was never re-closed. +- The commit that last touched this file (`5e2c7cc`) landed **18:32Z β€” 81 minutes + after #699 had already closed** β€” and still said the blocker was unfiled. The + finding sat in `PLAN.md` for less than a day before it was acted on; the doc that + said otherwise just never got re-read against events. +- quadraui milestone #9 was never closed β€” it's **open** (0 open / 7 closed issues + in it). The previous instruction to "re-open" it was acting on a wrong premise. + +**What actually happened, and what's still open:** quadraui#699/#704 gave every +backend a symmetric Rc-handle API (`modal_stack_handle()` / `drag_state_handle()`), +removing the `Backend`-trait asymmetry that blocked Stage 1. vimcode has already +started consuming it β€” **#811** (this branch's own history) bumped the quadraui pin +to `4ff2a64` and ported the four TUI-side call sites off the now-removed +`drag_and_modal_mut`. **vimcode#47 itself is still open** (Stage 1 β€” moving `App`'s +remaining GTK-specific call sites onto the new API, see `PLAN.md`) and is the actual +next actionable item here, not a re-filing task. + +**The "44 call sites" figure was also wrong**, independent of the above. It came +from `grep -n 'self\.backend\.' src/gtk/mod.rs` β€” every use of the `backend` field, +not just the two Rc-handle methods. The real count, measured at `ee26268` +(`grep -n 'modal_stack_handle\|drag_state_handle' src/app.rs`, minus the two +doc-comment mentions of the method names): **19** β€” `modal_stack_handle` Γ—12, +`drag_state_handle` Γ—7. (Also note the field moved: by `ee26268` this code lives in +`src/app.rs`, not `src/gtk/mod.rs` β€” #785 had already hoisted it. Fixed in `PLAN.md` +and `PROJECT_STATE.md` too, which is where the 44 figure originates.) ### 4. The divergence bug class is not dead @@ -236,8 +277,8 @@ count. |---|---|---| | **quadraui#465** | macOS `ShellApp` + `run_with_shell` composition | βœ… Closed 2026-08-31. The supply-side gate is cleared. | | **#657** | Put vimcode on the oracle loop | βœ… Closed. `[lib] vimcode_core` + sealed `tests/acceptance/`. | -| **#47** | Native macOS GUI, as a thin wrapper | ⚠️ **Closed with no code.** Blocker unfiled β€” see above. | -| **quadraui#481 / #482** | The remaining duplication, one level down | πŸ”“ Open, un-milestoned, unqueued. | +| **#47** | Native macOS GUI, as a thin wrapper | πŸ”“ **Reopened 2026-09-03, OPEN in milestone #5.** Blocker resolved (quadraui#699/#704); #811 already ported the TUI side. Stage 1 (GTK side) is the actual next work β€” see `PLAN.md`. | +| **quadraui#481 / #482** | Duplication one level down β€” largely refuted, see Β§2 above | πŸ”“ Open, un-milestoned. Don't plan against their headline numbers. | ### The two decisions this file was holding open β€” both now moot @@ -252,29 +293,36 @@ every fix ahead of #657 was verified by tests its own author wrote. It is now follow-up is to decide whether any of #751–#766 warrants a retro-fitted oracle-authored test, rather than re-litigating the sequencing. -## Status (2026-09-03) +## Status (2026-09-05, corrected per #827) - βœ… **Milestone #7 is 0 open.** The 09-01 critical path plus 16 slices all landed. - βœ… **The oracle loop is live here** (#657) and `draw_frame` is gone (#766). -- πŸ“‰ **The audit is run and it missed:** backends βˆ’3,656 against a βˆ’8,700β€¦βˆ’9,500 - projection; the three files net **+2,740** lines. -- ⚠️ **#47 closed with zero code and its blocker filed nowhere** β€” the single most - actionable item on this page. -- πŸ”“ **quadraui#481 / #482 hold the remaining duplication** and are unqueued. -- βœ… **The irreducible surface is aggregated** β€” [`docs/IRREDUCIBLE_SURFACE.md`](docs/IRREDUCIBLE_SURFACE.md). - Only **1.3%** of the backends is platform-bound; the rest is duplication, and the goal - should be planned as such. +- πŸ“‰ **The audit is run and it missed its projection** β€” backends βˆ’3,656 against a + βˆ’8,700β€¦βˆ’9,500 projection; the three files net **+2,740** lines. But ~βˆ’2,825 of + that βˆ’3,656 is #731/#732 dead-code removal, not convergence β€” convergence proper + moved roughly **900 lines** out of the backends while `render.rs` absorbed **~7,000**. +- πŸ”“ **#47 is open again, in milestone #5.** Its blocker (quadraui#699/#704) closed + 2026-09-03; #811 already ported the TUI side onto the new API. Stage 1 (GTK side) + is the actual next actionable item β€” not a re-filing task. +- πŸ”“ **quadraui#481 / #482 remain open and un-milestoned**, but most of their + headline duplication claims were refuted 2026-09-05 (see Β§2) β€” the one confirmed + live gap is macOS's undebounced `WindowResized`. +- βœ… **The irreducible surface is aggregated** β€” [`docs/IRREDUCIBLE_SURFACE.md`](docs/IRREDUCIBLE_SURFACE.md), + corrected 2026-09-05 (the folder-picker verdict was wrong; struck). **Two** of the + three remaining facts are genuinely irreducible; only **1.3%** of the backends + names a native toolkit type β€” the rest is duplication, and the goal should be + planned as such. ## How to use this doc - **Line numbers:** this file cites none, on purpose β€” locate by symbol - (`grep -n "impl quadraui::ShellApp for App" src/gtk/mod.rs`). Counts here are + (`grep -n "impl quadraui::ShellApp for App" src/app.rs`). Counts here are evidence measured on a named revision; **regenerate them with - `python3 scripts/prod_lines.py src/gtk src/tui_main src/render.rs`** rather than - trusting the table. + `python3 scripts/prod_lines.py src/gtk src/tui_main src/render.rs src/app.rs`** + rather than trusting the table. - **Agents:** treat this as the standing objective behind all planning and triage. - There is no queue to work right now β€” the next move is item 3 above (file the - quadraui gap), then items 1 and 2. Never write new per-backend code + Item 3's blocker is cleared β€” the next move is **vimcode#47 Stage 1** (see + `PLAN.md`), then items 1, 2 and 4 above. Never write new per-backend code (`CLAUDE.md` Platform-Neutrality Rule). When you adopt a quadraui API, **delete** the old backend code in the same PR. - **Humans:** edit freely as priorities shift; keep it short, re-date Status. diff --git a/PLAN.md b/PLAN.md index 0e8fc8aa..b0f6d271 100644 --- a/PLAN.md +++ b/PLAN.md @@ -6,30 +6,43 @@ > source of truth for individual tasks β€” this file points at the current > wave and explains how to resume. > -> **Last updated:** 2026-09-03 β€” **#47 re-audited, never started, and now -> CLOSED with no code.** The chain (#730β†’#657) plus slices #751–#766 are fully -> landed and milestone #7 is 0 open, but the re-audit #47 mandates at pickup -> found the real blocker is a `Backend`-trait ergonomics mismatch the issue text -> didn't anticipate. **The quadraui issue that re-audit told us to file was never -> filed, and #47 was closed anyway** β€” so this section is the only surviving -> record of the blocker. Read it before attempting Stage 1, and file the gap -> upstream first. +> **Last updated:** 2026-09-05 (issue #827 correction pass). **The blocker below +> was filed and cleared 2026-09-03 β€” this file just never caught up.** The +> 2026-09-03 revision said "the quadraui issue was never filed" and counted "44" +> `self.backend` call sites; both were wrong (the real blocker, quadraui#699, was +> filed and closed the same day at 16:38Z–17:11Z, and the real count of the two +> Rc-handle methods is **19**, not 44 β€” see the corrected blocker section below). +> **#47 is reopened, in milestone #5**, and #811 (already on this branch) has +> started consuming the fix on the TUI side. Stage 1 (the GTK-side `App` move) +> is the live next step β€” read the section below for what's still accurate. --- -## ⚠️ Live blocker β€” **#47 (macOS wrapper): closed with no code, blocker unfiled** - -**Read this first.** #47 is *closed*, but nothing was built and the design question -below is still open. No open quadraui issue mentions `modal_stack_handle` or -`drag_state_handle`; `git show 44882e9` is a documentation-only diff. Before any -macOS work starts: - -1. File the `Backend`/`GtkBackend` symmetry gap on `JDonaghy/quadraui` (or fold it - into **quadraui#482**, "Backend API integrity", its natural home). -2. Re-open quadraui milestone **#9 "vimcode Platform-Neutral blockers"** to hold it. -3. Re-open **vimcode#47** behind that blocker rather than leaving it closed β€” - `GOALS.md` now states the rule this violated: *a #7 issue that turns out to be - supply-blocked stays open behind its blocker.* +## βœ… Blocker resolved 2026-09-03 β€” **#47 (macOS wrapper) is reopened, in milestone #5** + +**Corrected 2026-09-05 (issue #827).** This section previously said #47 was closed +with its blocker unfiled. Both halves of that were wrong: + +- **quadraui#699** β€” the `Backend`/`GtkBackend` symmetry gap below β€” was filed + 2026-09-03 **16:38Z** (into quadraui milestone #9) and **closed 17:11Z** + (PR#700/`88345fb`). Follow-up **#704** closed 21:41Z. +- **vimcode#47 was reopened 16:38Z** and is open now, in milestone #5 β€” it was + never left closed behind an unfiled blocker. +- quadraui#699/#704 gave every backend a symmetric Rc-handle API + (`modal_stack_handle()` / `drag_state_handle()`), which is what the design + discussion below asked for (option 1). **#811** (already on this branch) has + ported the TUI side of vimcode onto it β€” bumped the quadraui pin to `4ff2a64` + and rewrote the four `drag_and_modal_mut` call sites in + `src/tui_main/shell_app.rs`. + +**What's still open:** the rest of Stage 1 β€” `struct App` (`modal_stack_handle()` +Γ—12 + `drag_state_handle()` Γ—7 = 19 call sites, not 44 β€” see below) already moved +into `src/app.rs` via #785, and #811 already ported the *TUI*-relevant call sites; +what's left is cfg-gating `App`'s remaining GTK-only fields and finishing the +`App`-move plan below. The design analysis below (why `modal_stack_mut`/ +`drag_and_modal_mut` couldn't be stashed) is preserved as background for *why* the +fix took the shape it did; treat "no code was moved" and "the upstream issue was +never filed" (further down) as no longer true. _As of 2026-09-02._ Picked up #47 (native macOS GUI, thin wrapper over `quadraui::macos::shell_runner::run_with_shell`). The issue's own body flags @@ -69,7 +82,11 @@ verbatim; that part of Stage 1 is low-risk mechanical work. **The actual blocker is `backend`.** `backend::GtkBackend` is a re-export of `quadraui::gtk::GtkBackend` (`src/gtk/backend.rs`). `App` calls exactly five -methods on it (`grep -n 'self\.backend\.' src/gtk/mod.rs`, 44 call sites): +methods on it (`grep -n 'self\.backend\.' src/gtk/mod.rs`, **44 call sites** β€” +**corrected 2026-09-05: that count is every use of the `backend` field across +all five methods, not just the two Rc-handle ones this blocker is about. The +count that actually matters is `modal_stack_handle` Γ—12 + `drag_state_handle` +Γ—7 = 19 call sites**, verified at `ee26268`): `modal_stack_handle()`, `drag_state_handle()`, `set_current_line_height()`, `set_current_char_width()`, `set_pango_context()` (the last is GTK/Pango-only, one call site at `:5548`, trivially cfg-gated). The first four are **inherent @@ -101,9 +118,9 @@ to the `&mut dyn Backend` borrow's lifetime β€” it cannot be stashed and reused across the borrow-drop points this pattern relies on. Simply changing `App.backend`'s type from `Rc>` to `Rc>>` (the obvious first move) does not -compile: the trait object exposes the wrong shape for ~40 of the 44 call -sites, and this is the *safety-critical* code (drag/modal/click dispatch), -not a corner where a quick workaround is low-risk. +compile: the trait object exposes the wrong shape for the 19 `modal_stack_handle`/ +`drag_state_handle` call sites, and this is the *safety-critical* code +(drag/modal/click dispatch), not a corner where a quick workaround is low-risk. **This is a supply-side gap, not a vimcode design choice** β€” the Platform-Neutrality Rule says stop and file it upstream rather than route @@ -120,33 +137,40 @@ should pick, not a vimcode-side workaround): needs to read them for hit-testing) β€” bigger change, but removes the asymmetry at the root instead of papering over it per-backend. -**Recommendation:** file this as a quadraui issue (gap in `Backend`/`GtkBackend` -API symmetry) before any vimcode-side Stage 1 code is written, per the -Platform-Neutrality Rule. Do **not** attempt the `App` move without that -decision β€” the 44 `self.backend` call sites sit in the app's most -safety-critical dispatch paths (mouse drag, modal overlays), and guessing at -an API shape here risks the same "three attempts, three reverts" outcome -`CLAUDE.md`'s #319 negative example documents for exactly this kind of -per-backend improvisation. - -**What did NOT happen this session β€” and has not happened since:** no code was -moved, and the upstream issue was never filed. `struct App` and -`impl quadraui::ShellApp for App` are untouched in `src/gtk/mod.rs`. The three +**Recommendation (as of the 2026-09-02 re-audit):** file this as a quadraui issue +(gap in `Backend`/`GtkBackend` API symmetry) before any vimcode-side Stage 1 code +is written, per the Platform-Neutrality Rule. That happened β€” see the corrected +"Blocker resolved" section at the top of this file: **quadraui#699/#704 shipped +the Rc-handle accessors on option 1's shape**, and #811 already ported the TUI +side onto them. The 19 `modal_stack_handle`/`drag_state_handle` call sites in +`src/app.rs` (moved there by #785 since this analysis was written) are what +Stage 1's GTK-side port still needs to touch. + +**Status, corrected 2026-09-05:** the upstream issue was **not** left unfiled β€” +quadraui#699 was filed and closed the same day (2026-09-03, 16:38Z–17:11Z). `struct +App` and `impl quadraui::ShellApp for App` moved (verbatim, per #785) out of +`src/gtk/mod.rs` into `src/app.rs` before this correction was written, and #811 has +already rewritten the TUI-relevant call sites onto the new handle API. The three other platform fields (`window`, `css_provider`, `settings_monitor`) and the -key-mapping helpers are confirmed low-risk and ready to move once the -`backend` question is resolved β€” re-verify line numbers again at that point, -since nothing here has landed to keep them stable. - -### Stage ordering once unblocked - -**Step 1 has still not happened** (verified 2026-09-03: no open quadraui issue -references either accessor). Nothing below is startable until it does. - -1. File/resolve the quadraui `Backend`/`GtkBackend` symmetry gap above. -2. Move `struct App` + its three `impl App` blocks + `impl ShellApp for App` - (`src/gtk/mod.rs:538-7483`) to `src/app.rs`, gating `window`/`css_provider`/ - `settings_monitor` behind `#[cfg(feature = "gui")]` and switching `backend` - to whatever shape step 1 lands on. +key-mapping helpers are still confirmed low-risk and ready to move β€” re-verify line +numbers in `src/app.rs` before touching them, since #785/#811 already changed them +once since this analysis was written. + +### Stage ordering β€” unblocked 2026-09-03 + +**Step 1 is resolved** (quadraui#699/#704 closed 2026-09-03; #811 ported the TUI +side). Re-audit which of the steps below `#785`/`#811` already completed before +starting the next one β€” this list was written before either landed. + +1. ~~File/resolve the quadraui `Backend`/`GtkBackend` symmetry gap above.~~ βœ… Done + (quadraui#699/#704). +2. ~~Move `struct App` + its three `impl App` blocks + `impl ShellApp for App` + (`src/gtk/mod.rs:538-7483`) to `src/app.rs`~~ βœ… **The move itself is done** + (#785, verbatim). **Still open:** gating `window`/`css_provider`/ + `settings_monitor` behind `#[cfg(feature = "gui")]` and switching `backend`'s + ~19 `modal_stack_handle`/`drag_state_handle` call sites onto the new handle + API from quadraui#699/#704 (per `GOALS.md`, `src/app.rs`'s own module doc + still lists these as the remaining gate-blockers). 3. `src/gtk/mod.rs` keeps only `run()`, `build_shell_config()`, and the genuinely GTK-only helpers (window-chrome, CSS, key-nameβ†’GDK glyph tables if any remain GTK-specific after the move). diff --git a/PROJECT_STATE.md b/PROJECT_STATE.md index d823cb9b..8e30470e 100644 --- a/PROJECT_STATE.md +++ b/PROJECT_STATE.md @@ -1,6 +1,6 @@ # VimCode Project State -**Last updated:** September 4, 2026 (see Recent Work for #801); prior revision September 3, 2026 β€” **the platform-neutrality chain drained, and the audit it mandated is now run.** Milestone #7 is **0 open**: everything the 2026-09-01 audit filed landed, including 16 slices it never named (#751–#766). The post-#735 sizing audit β€” which the previous revision explicitly warned not to skip β€” is below, and it **missed its projection by roughly 60%**. Nothing is in flight and nothing is queued for vimcode or quadraui. The most actionable thing on this page is that **#47 was closed having shipped zero code, with its blocker filed nowhere.** +**Last updated:** September 5, 2026 (issue #827 correction pass β€” the #47/44-call-site claims below were stale within hours of being written; see the corrected section); prior revisions September 4 (#801) and September 3 (the platform-neutrality chain drained, and the audit it mandated is now run). Milestone #7 is **0 open**: everything the 2026-09-01 audit filed landed, including 16 slices it never named (#751–#766). The post-#735 sizing audit β€” which the previous revision explicitly warned not to skip β€” is below, and it **missed its projection by roughly 60%** (though most of that miss is #731/#732 dead-code removal, not convergence β€” see `GOALS.md` Β§2/Β§3 for the corrected attribution). Nothing is in flight and nothing is queued for vimcode. **#47 is reopened, in milestone #5** β€” its blocker (quadraui#699/#704) was filed and closed 2026-09-03, and #811 already ported the TUI side onto the new API. See `GOALS.md` for the full correction. ## Active milestone: #7 Platform-Neutral β€” **complete (0 open)** @@ -44,15 +44,21 @@ Still true from earlier in the arc: `fn event_loop` does not exist in `src/`; ### The post-#735 sizing audit β€” run on `develop @ eedebf8` -Production lines, `#[cfg(test)]` excluded. **All four columns measured with the same +Production lines, `#[cfg(test)]` excluded. **All columns measured with the same script** (`scripts/prod_lines.py`, added for this audit) so they are comparable: -| | 2026-05-01 | 2026-07-01 | pre-chain 2026-08-31 | **now 2026-09-03** | -|---|---|---|---|---| -| `src/gtk/` | 18,969 | 13,675 | 12,526 | **9,650** | -| `src/tui_main/` | 14,649 | 10,358 | 11,125 | **10,345** | -| **both backends** | 33,618 | 24,033 | 23,651 | **19,995** | -| `src/render.rs` (shared) | 10,574 | 12,807 | 15,009 | **21,405** | +| | 2026-05-01 | 2026-07-01 | pre-chain 2026-08-31 | pre-#785 2026-09-03 | **post-#785, now @ `ee26268`** | +|---|---|---|---|---|---| +| `src/gtk/` | 18,969 | 13,675 | 12,526 | 9,650 | **2,607** | +| `src/tui_main/` | 14,649 | 10,358 | 11,125 | 10,345 | **10,366** | +| `src/app.rs` (hoisted out of `src/gtk/` by #785) | β€” | β€” | β€” | β€” | **7,131** | +| **all three files** | 33,618 | 24,033 | 23,651 | 19,995 (2 files) | **20,104** | +| `src/render.rs` (shared) | 10,574 | 12,807 | 15,009 | 21,405 | **21,405** | + +(#785, "stage 1 of #47," hoisted `struct App` verbatim out of `src/gtk/mod.rs` into +a new `src/app.rs` β€” see `GOALS.md`'s post-#735 audit for the full account. The +`src/gtk/` = 9,650 figure this file previously carried as "now" predates that move; +regenerated at `ee26268` per #827.) **Projected vs. actual over the chain (08-31 β†’ 09-03):** @@ -98,8 +104,11 @@ is a long way from the north star, and the remaining gap should not be planned a ### What remains β€” four items, none of them queued 1. ~~**The irreducible surface is recorded but never aggregated.**~~ βœ… **Done - 2026-09-03: [`docs/IRREDUCIBLE_SURFACE.md`](docs/IRREDUCIBLE_SURFACE.md).** The nine - verdicts reduce to four facts, three genuinely irreducible. And the sizing answer: + 2026-09-03, corrected 2026-09-05: + [`docs/IRREDUCIBLE_SURFACE.md`](docs/IRREDUCIBLE_SURFACE.md).** The nine + verdicts reduce to **three** facts (the folder-picker verdict was wrong and has + been struck β€” `quadraui::compose::FolderPickerController` has existed since + 2026-05-25), **two** genuinely irreducible. And the sizing answer: **only 246 of 19,429 production lines (1.3%) name a native toolkit type**, so platform-specificity is *not* what keeps the backends large β€” `src/gtk/mod.rs` and `src/tui_main/shell_app.rs` are two implementations of the same four `ShellApp` entry @@ -107,52 +116,55 @@ is a long way from the north star, and the remaining gap should not be planned a (`tui_main/mouse.rs:1620`, command-line selection) turned out to be a **mislabelled supply gap**: `CommandLineLayout::hit_test` does not exist in quadraui and was never filed; **#194** is the open consumer-side symptom. -2. **The duplication moved down into quadraui and is unqueued.** **quadraui#481** - (shared runtime core β€” 1,671 non-trivial lines byte-identical between `gtk/*.rs` and - `macos/*.rs`, `EventOutcome` declared twice verbatim, the resize debounce written - twice and absent on macOS) and **quadraui#482** (Backend API integrity β€” trait - asymmetry, unit leaks, a UTF-8 boundary fix living as 7 private copies). Both open, - both un-milestoned, neither in any queue. -3. **#47's blocker is filed nowhere** β€” see below. +2. **The "duplication moved down into quadraui" claim is largely refuted (#827).** + quadraui#481/#482 remain open and un-milestoned, but most of the headline numbers + don't hold up at the pinned rev: `EventOutcome` is declared once, not twice + (quadraui#496); the 1,671-line byte-identical claim was withdrawn by quadraui#481's + own correction comment as "idiom coincidence" (real duplication ~85 lines); the + UTF-8 fix has been public since 2026-08-15 (quadraui#503); the tree-layout + "twins" are both 1-line wrappers over one shared function (quadraui#499); and + quadraui#482's eight children (#503–#510) are all closed. See `GOALS.md` Β§2 for + the full table. What's still real: macOS dispatches `WindowResized` undebounced + while TUI/GTK share a `ResizeDebouncer`. +3. **#47's blocker was filed and cleared 2026-09-03** β€” see below (this used to say + "filed nowhere"; it wasn't, within hours of that claim being written). 4. **The divergence bug class is still ~44 issues deep** (#206, #420, #264, #194, #233 and friends), plus milestone #5's cross-backend residue (#149, #167, #168, #233, #294). `GOALS.md`'s thesis is that each is a symptom of a duplicated surface; if the convergence had reached far enough this list would be shrinking. It is the only outcome measure this goal has that isn't a line count β€” watch it. -### ⚠️ #47 was closed having shipped no code +### βœ… #47's blocker was filed and cleared β€” this section was stale (#827) -**#47 (native macOS GUI) is closed and its diff is documentation only.** Commit -`44882e9` β€” *"re-audit at pickup, no code β€” Backend-trait Rc-handle gap blocks Stage 1"* β€” -recorded the real blocker: `App` calls `GtkBackend::modal_stack_handle()` / -`drag_state_handle()` at 44 call sites in the drag and modal dispatch paths. Those are +**Corrected 2026-09-05.** #47 (native macOS GUI) was closed 2026-09-02 with commit +`44882e9` β€” *"re-audit at pickup, no code β€” Backend-trait Rc-handle gap blocks Stage +1"* β€” recording the real blocker: `App` called `GtkBackend::modal_stack_handle()` / +`drag_state_handle()` at **19** call sites (`modal_stack_handle` Γ—12, +`drag_state_handle` Γ—7 β€” not the "44" this file previously said, which counted every +use of the `backend` field via `grep -n 'self\.backend\.' src/gtk/mod.rs`, not just +the two Rc-handle methods) in the drag and modal dispatch paths. Those were **inherent methods on the concrete struct, not on the generic `quadraui::Backend` trait**, and `MacBackend`'s trait equivalents (`modal_stack_mut`, `drag_and_modal_mut`) -return short-lived `&mut` borrows that cannot be stashed and reused the way `App` does. -Full findings and two candidate API shapes are in [`PLAN.md`](PLAN.md). - -That commit's own recommendation β€” *"file this as a quadraui issue before any -vimcode-side Stage 1 code is written"* β€” **was never carried out.** No open quadraui -issue mentions either method name. The finding now lives only in `PLAN.md`, attached to a -**closed** issue, which is precisely where the next triage pass will not look. - -**This is `GOALS.md`'s supply-side trap in a new shape.** The documented failure mode was -"infra lands in quadraui but the #7 adoption issue never gets picked up." This is the -inverse: the consume-side issue was *closed* while its supply-side blocker went -unrecorded. The rule that would have caught it is now written down in `GOALS.md`: **a #7 -issue that turns out to be supply-blocked stays open behind its blocker; it does not get -closed.** - -**Action:** file the gap on `JDonaghy/quadraui` (or fold it into quadraui#482, its -natural home), re-open quadraui milestone #9 "vimcode Platform-Neutral blockers", and -re-open vimcode#47 behind it. +returned short-lived `&mut` borrows that couldn't be stashed and reused the way `App` +does. Full findings are in [`PLAN.md`](PLAN.md). + +**That blocker was filed β€” this file just never caught up.** **quadraui#699** was +filed 2026-09-03 16:38Z (into quadraui milestone #9) and **closed 17:11Z** +(PR#700/`88345fb`); follow-up **#704** closed 21:41Z. **vimcode#47 was reopened +16:38Z** and is **open now, in milestone #5**. quadraui#699/#704 gave every backend a +symmetric Rc-handle API, and vimcode has already started consuming it: **#811** +bumped the quadraui pin to `4ff2a64` and ported the TUI-side call sites off the +now-removed `drag_and_modal_mut`. The actual next actionable item is **vimcode#47 +Stage 1** (the GTK-side `App` move), not a re-filing task β€” see `PLAN.md` and +`GOALS.md` for the full correction. ### Milestone hygiene - **#7 is 0 open.** #146 moved to #4 Editor Features; #47 sits in #5 Cross-Platform UI - Crate, which `GOALS.md` defines as covering the macOS/Windows backends. -- **quadraui milestone #9** ("vimcode Platform-Neutral blockers") is closed out and - should be re-opened to hold the #47 blocker. + Crate, which `GOALS.md` defines as covering the macOS/Windows backends, and is + **open** (reopened 2026-09-03). +- **quadraui milestone #9** ("vimcode Platform-Neutral blockers") is **open** (0 + open / 7 closed issues) β€” it held quadraui#699 and does not need re-opening. - **Stale Win-GUI issues.** Roughly a dozen open `Win-GUI:` issues (#160–#178, #61, #172, #176) describe a backend **deleted from this repo on 2026-05-11** (`3e4bcff`). Their live counterparts are quadraui#19–#31 / quadraui#580. They should be migrated or @@ -317,7 +329,20 @@ mouse routing, #757–#762 keyboard dispatch, #763–#766 frame composition (`Fr post-#735 sizing audit the previous revision mandated and added `scripts/prod_lines.py` so it is reproducible: backends **βˆ’3,656** against a βˆ’8,700β€¦βˆ’9,500 projection, `render.rs` **+6,396**, net **+2,740**. #47 closed having shipped **no code** (`44882e9`) with its -`Backend`-trait Rc-handle blocker filed nowhere β€” the top open action. +`Backend`-trait Rc-handle blocker filed nowhere β€” the top open action. *(Corrected +2026-09-05, issue #827: that blocker β€” quadraui#699, at 19 not 44 call sites β€” was +filed and closed the same day, 16:38Z–17:11Z, and #47 was reopened 16:38Z. This +entry's "filed nowhere" was already wrong by the time the revision carrying it was +written; see the corrected section above.)* + +**2026-09-05 β€” GOALS.md/PLAN.md/PROJECT_STATE.md/IRREDUCIBLE_SURFACE.md corrected +(#827).** A four-agent audit of `develop @ ee26268` found the planning docs +materially stale: the #47-blocker-unfiled claim (quadraui#699 had already closed), +the 44-call-site figure (real count 19), the quadraui#481/#482 "duplication moved +down a level" claims (mostly refuted at the pinned rev), the `src/gtk/` size-table +column (predated #785's move), and the `IRREDUCIBLE_SURFACE.md` folder-picker +verdict (wrong β€” `FolderPickerController` has existed in quadraui since 05-25). +Corrected all four docs; no code changed. **2026-09-01 β€” platform-neutrality audit, and everything it found is now queued.** Filed #730 (`ai_panel`), #731 (orphan handles), #732 (`Msg` bus), #733 (mouse routers), diff --git a/docs/IRREDUCIBLE_SURFACE.md b/docs/IRREDUCIBLE_SURFACE.md index 49f3f040..78729fe4 100644 --- a/docs/IRREDUCIBLE_SURFACE.md +++ b/docs/IRREDUCIBLE_SURFACE.md @@ -6,27 +6,42 @@ > surface that **stays** β€” which is what would let anyone judge how far 19,995 production > lines is from the north star. This is that statement. > -> _Measured 2026-09-03 on `develop` @ `8e333a8`. Regenerate, don't trust: +> _Measured 2026-09-03 on `develop` @ `8e333a8`. Corrected 2026-09-05 (issue #827) +> β€” the folder-picker row below was wrong; struck, not just re-verdicted. Regenerate, +> don't trust: > `python3 scripts/prod_lines.py src/gtk src/tui_main src/render.rs` and > `python3 scripts/native_lines.py gtk src/gtk/*.rs`._ -## 1. The nine recorded verdicts are four facts +## 1. The nine recorded verdicts are three facts ``` grep -rn -iE "do not converge|not converged|one-sided|intrinsic difference" src/ ``` returns nine anchors, but several are cross-references to the same decision. They reduce -to four: +to three: | Fact | Anchors | Verdict | |---|---|---| -| **The folder / workspace picker is TUI-only.** GTK opens a *native* `GtkFileChooser`, deferred through `PendingFileDialog` and run from `tick()`, so there is no GTK canvas surface to paint, hit-test or arbitrate. | 5 β€” `render.rs:2919` (keyboard), `render.rs:7242` (`FrameOp::FolderPicker`), `render.rs:21569` (mouse-arbitration test), `gtk/mod.rs:6498` (the no-op compose arm), `tui_main/mouse.rs:691` (input) | βœ… **Irreducible.** Converging it means *building* a GTK canvas picker β€” adding per-backend code to make two tables match. | -| **Frame metrics are px on GTK, cells on TUI.** `FrameMetrics` carries only `line_height`/`char_width` and answers one question: "is this reserved band at least one line tall". Rect math stays per backend because Cairo painter-order and ratatui cell coalescence differ intrinsically. | 1 β€” `render.rs:7162` | βœ… **Irreducible.** Already reduced to the minimum: a unit, not a geometry. | +| **Frame metrics are px on GTK, cells on TUI.** `FrameMetrics` carries only `line_height`/`char_width` and answers one question: "is this reserved band at least one line tall". Rect math stays per backend because Cairo painter-order and ratatui cell coalescence differ intrinsically. | 1 β€” `render.rs:7162` | βœ… **Irreducible.** Already reduced to the minimum: a unit, not a geometry. See Β§2b for a caveat on how thin that "unit" actually stays. | | **GTK's menu bar *is* its client-side titlebar.** `App::setup` pins `engine.menu_bar_visible = true` unconditionally (#552); TUI shows its menu row only in vscode-mode or via Alt. | 2 β€” `gtk/testing.rs:5944`, `tui_main/shell_app.rs:6032` | βœ… **Irreducible.** A property of CSD, not a transcription. Handled by fixture, not by branching production code. | -| **Command-line text selection is TUI-only.** GTK has no `cmd_sel`/`cmd_dragging` state, no inverted-cell read-back, and paints its command line through `Surface::CommandLine`, which exposes no character-offset hit test. | 1 β€” `tui_main/mouse.rs:1620` | ❌ **Not irreducible β€” mislabelled.** See Β§2. | +| **Command-line text selection is TUI-only.** GTK has no `cmd_sel`/`cmd_dragging` state, no inverted-cell read-back, and paints its command line through `Surface::CommandLine`, which exposes no character-offset hit test. | 1 β€” `tui_main/mouse.rs:1620` | ❌ **Not irreducible β€” mislabelled.** See Β§2a. | -## 2. One of the four is a supply gap wearing a verdict's clothes +### 1b. Struck: "the folder / workspace picker is TUI-only" (#827) + +A fourth row previously sat in the table above, verdicted βœ… **Irreducible**: *"GTK +opens a native `GtkFileChooser`, deferred through `PendingFileDialog` and run from +`tick()`, so there is no GTK canvas surface to paint, hit-test or arbitrate."* That +verdict was wrong, not just stale β€” it never checked upstream. `quadraui::compose::FolderPickerController` +has existed since **2026-05-25**, and its own module doc explicitly instructs +consumers (vimcode named) to delete the local picker and rewire both backends through +the shared controller β€” the aggregation that produced this row grepped `src/` for +"do not converge" anchors and never looked at what quadraui already shipped. This is +an ordinary **#7 Platform-Neutral adoption gap**, not an irreducible surface: file the +adoption issue against `FolderPickerController`, don't carry this row forward as a +settled fact. + +## 2a. One of the three is a supply gap wearing a verdict's clothes `tui_main/mouse.rs:1620` files itself under the same "recorded rather than converged" heading as the others, but its own text says the opposite: @@ -48,6 +63,36 @@ supply-blocked stays open behind its blocker* β€” applies to in-code verdicts to comment that says "this needs a quadraui API" is an unfiled issue, and grep will not find it for you.** +## 2b. The `unit_w`/`unit_h` seam is thinner in practice than Β§1 blesses it (#827) + +Β§1 treats `FrameMetrics`'s `unit_w`/`unit_h` convention as *the* unit seam that keeps +frame-metrics irreducibility down to "a unit, not a geometry." That's the intent, but +`render.rs` doesn't hold the line as cleanly as the fact-table implies. As measured +2026-09-05: + +- The `unit_w: f32, unit_h: f32` parameter pair appears in **7 painter function + signatures** in `render.rs` (`hover_popup_to_quadraui_tooltip`, + `editor_hover_popup_paint`, `signature_help_to_quadraui_tooltip`, + `panel_hover_popup_paint`, `diff_peek_to_quadraui_tooltip`, + `draw_ai_sidebar_panel`, `tab_hover_tooltip_paint`), across roughly **33 uses** of + the two identifiers in expressions. +- `render.rs` additionally carries **two explicit `char_width > 1.0` backend + sniffs** β€” `minimap_reserved_width` (`render.rs:10426`) branches min/max width in + pixels vs. columns on it, and the editor-viewport scrollbar reservation + (`render.rs:17256`) reserves 8px only "in the GTK backend (`char_width > 1.0`)". + Both are comments-as-documentation admitting the unit is not opaque to the + caller β€” code downstream of the seam still asks "am I GTK?" by proxy. +- The same file carries **five paired per-backend policy tables** alongside the + unit convention β€” constants/branches that assume one shape for `char_width == 1.0` + (TUI) and another for `char_width > 1.0` (GTK), rather than deriving the answer + purely from the unit value. + +**Record the real state, not the aspiration:** `unit_w`/`unit_h` is a real and useful +convention, but it is a *convention observed by callers*, not an enforced boundary β€” +`render.rs` still contains explicit backend-identity branches hiding behind the unit +parameter's name. Treat the frame-metrics row in Β§1 as "irreducible, and mostly but +not entirely behind one seam." + ## 3. How much of the backends is actually platform-bound Production lines that name a toolkit module or type (`gtk4::`/`gio::`/`glib::`/`gdk::`/ @@ -81,8 +126,10 @@ tripled, the figure stays under 4%. keeping it there.** The two backends are, to within about 1.3%, ordinary toolkit-free Rust that happens to -live in a backend directory. The genuinely irreducible surface is the three facts in Β§1 -plus roughly 250 lines of native calls β€” a few hundred lines, not tens of thousands. +live in a backend directory. The genuinely irreducible surface is the two irreducible +facts in Β§1 (frame metrics, GTK's CSD menu bar) plus roughly 250 lines of native calls +β€” a few hundred lines, not tens of thousands. (The folder picker is not a third: Β§1b +struck it as an unactioned adoption gap, not an irreducible fact.) **What this does NOT claim:** that the remaining ~19,200 lines are mechanically convergeable. Some of it is real per-backend *structure* β€” GTK and TUI compose a frame @@ -108,6 +155,10 @@ the actual remaining work. platform-porting problem, and a plan that treats them as one will keep missing its projection the way the #751–#766 chain did (βˆ’3,656 against βˆ’8,700β€¦βˆ’9,500). Size it as what it is: two implementations of four entry points. +4. **File the folder-picker #7 adoption issue.** `quadraui::compose::FolderPickerController` + has shipped since 2026-05-25 and nothing has adopted it β€” file the vimcode-side + deletion/rewire against it (Β§1b), rather than continuing to treat the TUI-only picker + as a settled irreducible fact. ## 6. Regenerating this