aboutsummaryrefslogtreecommitdiff
path: root/todo.org
diff options
context:
space:
mode:
Diffstat (limited to 'todo.org')
-rw-r--r--todo.org22
1 files changed, 15 insertions, 7 deletions
diff --git a/todo.org b/todo.org
index 6337c2e6..fb1e2a45 100644
--- a/todo.org
+++ b/todo.org
@@ -41,6 +41,11 @@ Tags are additive. For example, a small wrong-behavior fix can be
=:bug:quick:=, and a feature that requires internal restructuring can be
=:feature:refactor:=.
* Emacs Open Work
+** TODO [#A] theme-studio contrast cell uses the wrong fg/bg pair :bug:theme-studio:
+The contrast readout on every item with two color selections (a fg AND a bg — the UI faces table and the package faces table) is computing the wrong pair. It needs to contrast the face's selected fg against the face's selected bg, not how the bg contrasts with the currently-selected (ground) bg.
+
+Investigation start: the two-color contrast cells are =paintUI= (UI faces, app.js ~line 740) and =buildPkgTable= (package faces, app.js ~line 430), both currently calling =contrast(effFg(fg), effBg(bg))= where =effFg(v)=v||MAP['p']= and =effBg(v)=v||MAP['bg']=. Reproduce a face that has BOTH a fg and a bg set, confirm the displayed ratio, and check whether it's actually evaluating selected-fg vs selected-bg or falling through to the ground bg. Fix so a two-color face always rates its own fg-on-bg. (Single-color contexts — the picker/palette-chip/plane checks that rate a color against the ground — are correct and out of scope.) Add a characterization gate (a #contrasttest hash gate) pinning fg-vs-bg for a two-color face.
+
** TODO [#C] Evaluate jamescherti essential-emacs-packages list :packages:research:
Review [[https://www.jamescherti.com/essential-emacs-packages/][James Cherti's essential Emacs packages]] for anything worth installing. Cross-check each candidate against what is already in the config (=modules/= + =init.el=), skip the ones already present, and shortlist the genuinely new ones with a one-line rationale. Future-installation research, not a commitment to install.
@@ -176,10 +181,13 @@ Phase 1. Palette anchors + OKLCH shade generation (reusing colormath.js), the RO
Phase 2. Initial state from seed() plus seedPkgmap for the non-org packages; all-tier reseed button with a scope-named overwrite warning, resetting non-org to their APPS defaults; regenerate dupre-revised.json. Gate: #selftest PASS; default-on-open equals seed(); artifact round-trip (regenerated dupre-revised.json imports back to the same seeded state); Chrome eyeball.
*** TODO Seeding-engine test surface :solo:tests:
Keep #seedtest, #selftest, the default-on-open check, the dupre-revised round-trip, node --check, and Chrome validation green.
-** DOING [#B] theme-studio refactor — extract app from generate.py :feature:theme-studio:refactor:
+** DONE [#B] theme-studio refactor — extract app from generate.py :feature:theme-studio:refactor:
+CLOSED: [2026-06-09 Tue]
Examined 2026-06-09. generate.py is 1378 lines, ~1300 of them a single triple-quoted string holding the whole app (CSS + HTML + ~1000+ lines of JS). That string is the root of every refactor here: the app logic can't be unit-tested (only =colormath.js= is, because it is the one extracted module); backslash-doubling in the string caused real bugs this session (the multi-line export strip, the =#deltatest= regex); and there is no lint, highlight, or brace-check until Chrome runs it. The rest of the directory is healthy: =colormath.js= (pure, 100/96 tested) and =build-theme.el= (13 small functions) are the model.
Run the whole set in NO-APPROVALS mode: TDD per stage (characterization hash tests before each behavior-preserving move; node unit tests as extraction makes logic importable), commit + push at each green stage. Tooling committed at c7518d6f before starting. Order:
+
+DONE (2026-06-09): Stages 1-5 + 7 landed and pushed (origin/main tip dd90eca9); Stage 6 deliberately skipped (optional, works today). generate.py went 1378→~500 lines; the app now lives in real files (styles.css, app.js, app-core.js) inlined at generate time. The escaping-bug class is gone (str.replace is literal), the dedup is done (unified dropdowns/sort/clear-unlocked, shared crHtml/mkStyleButtons/effFg helpers), and the pure app logic is unit-tested (app-core.js, 18 node tests). Three new permanent gates added along the way: =#locktest=, =#sorttest=, and the app-core integrity + node suite. =make theme-studio-test= = 13 python + 43 node + spliced-check + 8 hash gates, all green.
*** 2026-06-09 Tue @ 05:01:11 -0500 Stage 1 — #locktest net + extracted styles.css/app.js
Added the =#locktest= browser gate first (commit d04f44dd): it pins, across all three tiers, that mkLockCell disables a row's control (syntax swatch div via data-locked, UI select via .disabled) and that clear-unlocked wipes unlocked rows while skipping locked ones. Proved it goes red when a lock guard is removed.
@@ -196,12 +204,12 @@ Deliberately NOT done: the syntax bold/italic buttons (2 buttons, BOLD/ITALIC di
Verified behavior-preserving by diffing the runtime-rendered DOM (Stage 2 page vs Stage 3 page in headless Chrome): the only differences are inside the inline =<script>= source, never a built tr/td/button/span — the tables build identically. All hash gates + node + python green.
*** 2026-06-09 Tue @ 05:16:33 -0500 Stage 4 — unified syntax table onto the shared sort
Deleted =srt= + =D{}= (the syntax table's own sort); pointed its headers at =srtTable('legbody',col)= so all three tables share =srtTable=/=cellVal=/=applyTableSort= (commit d947944b). Mapping is exact: the legtable color cell is a swatch dropdown whose =data-val= is the hex (what =srt= sorted on via MAP[kind]); elements cell is text; first-click stays ascending. Syntax sorts on click only — it doesn't opt into the cross-rebuild persistence the UI/pkg tables get, preserving its prior behavior. Added a =#sorttest= gate (sort was untested): syntax sorts by color asc, reverses on re-click, sorts by element name; UI + pkg still sort. asc/desc pair is self-validating.
-*** TODO Stage 5 — parameterize clear-unlocked + effFg helper :solo:
-Three near-identical clear-unlocked functions → one parameterized over (collection, lock-key, reset). The =MAP[kind]||MAP['p']= effective-fg fallback appears 9x → one =effFg=/=effBg= helper. Node-unit-test both. Gate: clear-unlocked works per tier; hash gates green.
-*** TODO Stage 6 — (optional) namespace state + data-file the bespoke faces :solo:
-Group free module-level state (MAP/PALETTE/BOLD/ITALIC/UIMAP/PKGMAP/LOCKED/pkMode/pkModel) into a state object; consider moving the large inline org/magit/elfeed face dicts to json data files like =package-inventory.json=. Lower priority; works today.
-*** TODO Stage 7 — test surface :solo:tests:
-After extraction, add node unit tests for the now-importable app logic (the coverage payoff): dropdown value/format, lock + clear, row builders, sort, effFg. Keep all hash gates + node tests + python templating tests green via =make theme-studio-test=.
+*** 2026-06-09 Tue @ 05:20:22 -0500 Stage 5 — parameterized clear-unlocked + added effFg/effBg
+Collapsed the three clear-unlocked functions into =clearUnlockedRows(items,keyFn,resetFn)= (keyFn returns a row's lock key or null to skip; resetFn does the tier-specific clear) — #locktest already guards clear-unlocked-skips-locked per tier. Replaced the 9x =||MAP['p']= / =||MAP['bg']= effective-fg/bg fallback with =effFg(v)=/=effBg(v)= across syntax/UI/pkg render paths (commit 89d079fe). Behavior-preserving: rendered DOM (script stripped) byte-identical; all gates green. Node-unit-testing the pure pieces (effFg/effBg, clearUnlockedRows) deferred to Stage 7 with the rest of the importable-app-logic suite.
+*** 2026-06-09 Tue @ 06:03:04 -0500 Stage 6 — skipped (optional, deferred)
+Left undone deliberately. Grouping the free module-level state into a state object is churn with no functional gain (works today), and data-filing the inline face dicts is a generate.py size win unrelated to the refactor's goal (testable logic), which Stage 7 already achieved. Can be revived from this entry + the original plan if the generate.py face dicts ever need to become data. Not blocking anything.
+*** 2026-06-09 Tue @ 06:03:04 -0500 Stage 7 — extracted app-core.js + unit-tested the app logic
+The coverage payoff. Pulled the pure package-face model + dropdown option list into app-core.js (nameToHex, buildPkgmap, packagesForExport, mergePackagesInto, effResolve, optList — every dep a parameter, no DOM/globals), inlined like colormath.js (strip + placeholder + integrity). app.js keeps thin wrappers (pname/seedPkgmap/ddList/pkgEffFg/pkgEffBg) passing live PALETTE/APPS/PKGMAP, so no call site changed and the built DOM is byte-identical. Added test-app-core.mjs: 18 Normal/Boundary/Error tests (name resolution, seed/export/merge round trip, inherit chain incl. a cycle terminating at null, "(gone)" entry) + inline-integrity. Node suite 25→43; python +1 integrity. Commit dd90eca9. GOTCHA found+fixed pre-commit: a code comment that contained the literal token "APP_CORE_J" got inlined by str.replace too (placeholder tokens must not appear in prose that gets templated).
** TODO [#C] theme-studio terminal/ANSI colors :feature:theme-studio:
theme-studio represents GUI faces only; terminal colors aren't surfaced at all. Scope decided 2026-06-09: GUI-first faces, NOT full per-face display-class fallback. Two pieces: