Skip to main content

Documentation Index

Complete index of all documentation in this repository. Updated: 2026-04-30 (Iteration 219: multi-option-support Phase 6 of 8 ✅ DELIVERED — Q10 Starlight docs alternate. New guide at docs/guides/multi-option/docs-framework.md documents the swap from Docusaurus 3.x (default) to Starlight (Astro-native, single-stack) including scaffolding via pnpm create astro@latest --template starlight (with npx --yes create-astro@latest fallback for hosts where pnpm dlx hits ERR_PNPM_NO_IMPORTER_MANIFEST_FOUND), workspace wire-up at @ever-works/docs-starlight, three content-migration strategies (symlink / build-hook copy / move), sidebar metadata conversion (_category_.json → frontmatter sidebar.order or autogenerate.directory), Vercel deployment plumbing, audit-script hook notes, and tradeoff matrix (versioning / blog / search / stack consistency / bundle size). End-to-end scratch verification ran green on the cron host: @astrojs/starlight ^0.38.4 + astro 6.2.0 + sharp 0.34.5 install in 15.3s; npx astro check 0 errors / 0 warnings / 0 hints across 3 files; npx astro build 4 pages in 6.96s with Pagefind search index. Q10 follow-up block in docs/questions.md flipped from OPEN — phase queued (Phase 6 of multi-option-support) to ✅ DELIVERED — Phase 6 complete (iter 219, 2026-04-30). .specify/project.md Current State header bumped 218 → 219; multi-option-support spec status line updated OPEN — phases queuedOPEN — Phase 6 of 8 ✅ DELIVERED iter 219, 7 phases queued. tmp/ added to .gitignore to cover scratch verification dirs (tmp/q10-starlight-verify/ cleanup deferred — Windows file-lock on node_modules; will retire on next clean tick). pnpm audit:docs 9/9 PASS first try after fixing structural-link drift introduced by the new guide's nested location (the audit-runner's link-drift class only whitelists single-../ relative paths into the canonical docs/ subtrees; a 2-levels-deep file at docs/guides/multi-option/ cannot use markdown relative links to its peers without touching the whitelist — this iteration sidesteps the issue by citing peer paths as inline code rather than markdown links, with a footnote in the guide explaining the audit-script-whitelist constraint and the option to extend the whitelist in a future iteration if multi-level relative links become a recurring pattern). Per-iteration verification gates (typecheck / lint / test) skipped this tick — Phase 6 is pure-docs delivery and lands no source code; the doc-quality audit class fully covers the surface that changed. Iteration 218 history below.)

Iteration 218 (history): user pivot — Q29 partially answered with Option B-prime "feature additions". Owner directed multi-option-support cohort: keep every existing default (Preact / Tailwind / config-file plugins / Pagefind / Astro built-in image / Docusaurus / isomorphic-git / pageview-only analytics) and add alternates for Q1 / Q2 / Q4 / Q5 / Q9 / Q10 / Q18 / Q20 alongside, exposed via config knobs. New umbrella spec at .specify/features/multi-option-support.md (35th spec; spec count claim bumped 34 → 35). Paired plan at docs/plans/multi-option-support.md schedules 8 independent phases (~2-4h each), recommended start = Phase 6 (Q10 Starlight docs alt). docs/questions.md restructured with new Active Questions section (Q29 only — vertical-samples sub-question still OPEN) and Other Questions section (28 questions kept verbatim per R13, with multi-option follow-up annotations on the 8 candidates). 55th iteration in this cron series but first scope-expanding iteration since iter 162; the 54-tick wind-down acknowledgement loop ended here. Iteration 217 history below.

Iteration 217 (history): Q29 wind-down respected — pnpm audit:docs 9/9 PASS first-try, no other changes. 54th consecutive minimal-acknowledgement tick. Q29 OPEN; default Option A (wind-down to weekly) in effect. Audit-runner stable since iter-213 RCA/fix; no recurrences observed across iters 214-217 (4 consecutive clean runs post-fix). Iteration 216 history below.

Iteration 216 (history): Q29 wind-down respected — pnpm audit:docs 9/9 PASS first-try, no other changes. 53rd consecutive minimal-acknowledgement tick. Q29 OPEN; default Option A (wind down to weekly cadence until real new scope arrives) in effect. Audit-runner stable since iter-213 RCA/fix; no recurrences observed across iters 214-216. Iteration 215 history below.)

Iteration 215 (history): Q29 wind-down respected — pnpm audit:docs 9/9 PASS, no other changes. 52nd consecutive minimal-acknowledgement tick. Q29 OPEN; default Option A (wind down to weekly cadence until real new scope arrives) in effect. Iteration 214 history below.)

Iteration 214 (history): Q29 wind-down respected — pnpm audit:docs 9/9 PASS first try, with iter-213's re-tuned wrapper in effect. 51st consecutive minimal-acknowledgement tick. First post-iter-213-fix verification — confirms the bisection RCA (8 GB old-space pre-allocation triggered kernel /GS fastfail) was correct and the targeted fix is stable across cron-tick re-runs. Q29 OPEN; default Option A (wind down to weekly cadence until real new scope arrives) in effect. Iteration 213 history below.)

Iteration 212 (history): Q29 wind-down respected — pnpm audit:docs 9/9 PASS, no other changes. 50th consecutive minimal-acknowledgement tick. Q29 OPEN; default Option A (wind down to weekly cadence until real new scope arrives) in effect. Iteration 211 history below.)

Iteration 211 (history): Q29 wind-down respected — pnpm audit:docs 9/9 PASS first try; iter-210's transient STATUS_STACK_BUFFER_OVERRUN noise did NOT recur. 49th consecutive minimal-acknowledgement tick. Q29 OPEN; default Option A (wind down to weekly cadence until real new scope arrives) in effect. Iteration 210 history below.)

Iteration 209 (history): Q29 wind-down respected — pnpm audit:docs 9/9 PASS, no other changes. 47th consecutive minimal-acknowledgement tick. Q29 OPEN; default Option A (wind down to weekly cadence until real new scope arrives) in effect. Iteration 208 history below.)

Iteration 208 (history): Q29 wind-down respected — pnpm audit:docs 9/9 PASS (with iter-207 heap-fix wrapper in effect). 46th consecutive minimal-acknowledgement tick. Q29 OPEN; default Option A (wind down to weekly cadence until real new scope arrives) in effect. First post-fix verification tick — confirms the --max-old-space-size=8192 wrapper change is stable across cron-tick re-runs and the audit invocation no longer regresses on Windows. Iteration 207 history below.)

Iteration 206 (history): Q29 wind-down respected — pnpm audit:docs 9/9 PASS, no other changes. 44th consecutive minimal-acknowledgement tick. Q29 OPEN; default Option A (wind down to weekly cadence until real new scope arrives) in effect. Iteration 205 history below.)

Iteration 205 (history): Q29 wind-down respected — pnpm audit:docs 9/9 PASS, no other changes. 43rd consecutive minimal-acknowledgement tick. Q29 OPEN; default Option A (wind down to weekly cadence until real new scope arrives) in effect. Working tree carries an uncommitted package.json audit:docs-wrapper edit of unknown provenance; left untouched pending user direction. Iteration 204 history below.)

Iteration 203 (history): Q29 wind-down respected — pnpm audit:docs 9/9 PASS, no other changes. 41st consecutive minimal-acknowledgement tick. Q29 OPEN; default Option A (wind down to weekly cadence until real new scope arrives) in effect. Iteration 202 history below.)

Iteration 201 (history): Q29 wind-down respected — pnpm audit:docs 9/9 PASS, no other changes. 39th consecutive minimal-acknowledgement tick. Q29 OPEN; default Option A (wind down to weekly cadence until real new scope arrives) in effect. Iteration 200 history below.)

Iteration 200 (history): Q29 wind-down respected — pnpm audit:docs 9/9 PASS, no other changes. 38th consecutive minimal-acknowledgement tick (iter 163 → 200). Iter-200 milestone: 200 total autonomous cron ticks since project inception (iter-1, 2026-04-10). Q29 OPEN; default Option A (wind down to weekly cadence until real new scope arrives) in effect. Iteration 199 history below.)

Iteration 198 (history): Q29 wind-down respected — pnpm audit:docs 9/9 PASS, no other changes. 36th consecutive minimal-acknowledgement tick. Q29 OPEN; default Option A (wind down to weekly cadence until real new scope arrives) in effect. Iteration 197 history below.)

Iteration 197 (history): Q29 wind-down respected — pnpm audit:docs 9/9 PASS, no other changes. 35th consecutive minimal-acknowledgement tick. Q29 OPEN; default Option A (wind down to weekly cadence until real new scope arrives) in effect. Iteration 196 history below.)

Iteration 195 (history): Q29 wind-down respected — pnpm audit:docs 9/9 PASS, no other changes. 33rd consecutive minimal-acknowledgement tick. Q29 OPEN; default Option A (wind down to weekly cadence until real new scope arrives) in effect. Iteration 194 history below.)

Iteration 194 (history): Q29 wind-down respected — pnpm audit:docs 9/9 PASS, no other changes. 32nd consecutive minimal-acknowledgement tick. Q29 OPEN; default Option A (wind down to weekly cadence until real new scope arrives) in effect. Iteration 193 history below.)

Iteration 192 (history): Q29 wind-down respected — pnpm audit:docs 9/9 PASS, no other changes. 30th consecutive minimal-acknowledgement tick. Q29 OPEN; default Option A (wind down to weekly cadence until real new scope arrives) in effect. Iteration 191 history below.)

Iteration 191 (history): Q29 wind-down respected — pnpm audit:docs 9/9 PASS, no other changes. 29th consecutive minimal-acknowledgement tick. Q29 OPEN; default Option A (wind down to weekly cadence until real new scope arrives) in effect. Iteration 190 history below.)

Iteration 189 (history): Q29 wind-down respected — pnpm audit:docs 9/9 PASS, no other changes. 27th consecutive minimal-acknowledgement tick. Q29 OPEN; default Option A (wind down to weekly cadence until real new scope arrives) in effect. Iteration 188 history below.)

Iteration 188 (history): Q29 wind-down respected — pnpm audit:docs 9/9 PASS, no other changes. 26th consecutive minimal-acknowledgement tick. Q29 OPEN; default Option A (wind down to weekly cadence until real new scope arrives) in effect. Iteration 187 history below.)

Iteration 186 (history): Q29 wind-down respected — pnpm audit:docs 9/9 PASS, no other changes. 24th consecutive minimal-acknowledgement tick. Q29 OPEN; default Option A (wind down to weekly cadence until real new scope arrives) in effect. Iteration 185 history below.)

Iteration 185 (history): Q29 wind-down respected — pnpm audit:docs 9/9 PASS, no other changes. 23rd consecutive minimal-acknowledgement tick. Q29 OPEN; default Option A (wind down to weekly cadence until real new scope arrives) in effect. Iteration 184 history below.)

Iteration 182 (history): Q29 wind-down respected — pnpm audit:docs 9/9 PASS, no other changes. 20th consecutive minimal-acknowledgement tick. Q29 OPEN; default Option A (wind down to weekly cadence until real new scope arrives) in effect. Iteration 181 history below.)

Iteration 180 (history): Q29 wind-down respected — pnpm audit:docs 9/9 PASS, no other changes. 18th consecutive minimal-acknowledgement tick. Q29 OPEN; default Option A (wind down to weekly cadence until real new scope arrives) in effect. Iteration 179 history below.)

Iteration 177 (history): Q29 wind-down respected — pnpm audit:docs 9/9 PASS, no other changes. 15th consecutive minimal-acknowledgement tick. Q29 OPEN; default Option A (wind down to weekly cadence until real new scope arrives) in effect. Iteration 176 history below.)

Iteration 176 (history): Q29 wind-down respected — pnpm audit:docs 9/9 PASS, no other changes. 14th consecutive minimal-acknowledgement tick. Q29 OPEN; default Option A (wind down to weekly cadence until real new scope arrives) in effect. Iteration 175 history below.)

Iteration 174 (history): Q29 wind-down respected — pnpm audit:docs 9/9 PASS, no other changes. 12th consecutive minimal-acknowledgement tick. Q29 OPEN; default Option A (wind down to weekly cadence until real new scope arrives) in effect. Iteration 173 history below.)

Iteration 173 (history): Q29 wind-down respected — pnpm audit:docs 9/9 PASS, no other changes. 11th consecutive minimal-acknowledgement tick. Q29 OPEN; default Option A (wind down to weekly cadence until real new scope arrives) in effect. Iteration 172 history below.)

Iteration 171 (history): Q29 wind-down respected — pnpm audit:docs 9/9 PASS, no other changes. 9th consecutive minimal-acknowledgement tick (iter 163 / 164 / 165 / 166 / 167 / 168 / 169 / 170 / 171). Q29 still OPEN; default Option A (wind down to weekly cadence until real new scope arrives) in effect. Iteration 170 history below.)

Iteration 170 (history): Q29 wind-down respected — pnpm audit:docs 9/9 PASS, no other changes. 8th consecutive minimal-acknowledgement tick (iter 163 / 164 / 165 / 166 / 167 / 168 / 169 / 170). Q29 still OPEN; default Option A (wind down to weekly cadence until real new scope arrives) in effect. Iteration 169 history below.)

Iteration 168 (history): Q29 wind-down respected — pnpm audit:docs 9/9 PASS, no other changes. 6th consecutive minimal-acknowledgement tick (iter 163 / 164 / 165 / 166 / 167 / 168). Q29 still OPEN; default Option A (wind down to weekly cadence until real new scope arrives) in effect. Iteration 167 history below.)

Iteration 167 (history): Q29 wind-down respected — pnpm audit:docs 9/9 PASS, no other changes. 5th consecutive minimal-acknowledgement tick (iter 163 / 164 / 165 / 166 / 167). Q29 still OPEN; default Option A (wind down to weekly cadence until real new scope arrives) in effect. Iteration 166 history below.)

Iteration 165 (history): Q29 wind-down respected — pnpm audit:docs 9/9 PASS, no other changes. 3rd consecutive minimal-acknowledgement tick (iter 163 / 164 / 165). Q29 still OPEN; default Option A (wind down to weekly cadence until real new scope arrives) in effect. Iteration 164 history below.)

Iteration 163 (history): Q29 wind-down respected — pnpm audit:docs 9/9 PASS, no other changes. Q29 awaits user decision; default Option A (wind down to weekly cadence until real new scope arrives) in effect. Iteration 162 history below.)

Iteration 162 (history): open Q29 flagging cron-cadence saturation; default = wind down to weekly. No code changes; no new audit class added — deliberate break from the iters 132-161 codify-then-execute reflex. pnpm audit:docs 9/9 PASS. pnpm typecheck 23/23 PASS. See docs/log.md § Iteration 162 and docs/questions.md § Q29. Iteration 161 history below.)

Iteration 161 (history): **codify auditMatrixProseCountParity() as the 8th audit class — iter-156 deferral #9 codify-trigger fired by iter-160 after 2 drift instances; pnpm audit:docs 9/9 PASS post-add (was 8/8) with [8/8] Matrix-prose count parity (iter-161) reporting high-churn 12 + lifted 3 + deferred 12 = 27 (claim: 27-package matrix). codify auditMatrixProseCountParity() as the 8th audit class — iter-156 deferral #9 codify-trigger fired by iter-160 after 2 drift instances; pnpm audit:docs 9/9 PASS post-add (was 8/8) with [8/8] Matrix-prose count parity (iter-161) reporting high-churn 12 + lifted 3 + deferred 12 = 27 (claim: 27-package matrix). Substantive code-artefact iteration that closes iter-160's "Next Steps #1". Iter-156 deferral #9 said "codify-then-execute meta-pattern says wait for a second matrix-prose drift instance before adding the audit class"; iter-160 fired that trigger after iter-158's 14 + 11 = 25 drift propagated through iter-159 and was caught at iter-160's commit. Iter-161 lands the codification: new auditMatrixProseCountParity() function in scripts/audit-docs.ts (~80 LOC including spec/plan-style header comment), new EXPECTED_MAPPING entry for heading Matrix-prose count parity (added iter 161) with runnerClassId: '8/8', all existing classes[] ids flipped from N/7N/8, new entry added for 8/8 with auditMatrixProseCountParity as the run callback. Audit class behavior: scans .specify/project.md, locates **N-package matrix** total claim and the three canonical cohort labels (high-churn cohort, X packages) / (iter-N lifted, Y packages) / (deferred cohort, Z packages), asserts X+Y+Z == N. Silent-pass if total claim or any cohort label is missing (no false positives on transitional matrix-prose). AGENTS.md update (lands same commit): new ### Matrix-prose count parity (added iter 161) sub-section under ## Doc-Quality Audit Checklist immediately above ### Rerun cadence; ### Runner (added iter 149) reference bumped 7 → 8 grep blocks; ### Checklist ↔ runner parity (added iter 151) canonical heading-to-class mapping table updated with new entry + all N/7N/8; heading-count summary line bumped 7 → 8 ### headings + 5 → 6 drift-class headings. Spec count drift caught by audit class 3 (count parity): adding the new spec file audit-docs-matrix-prose.md bumped ls .specify/features/*.md | wc -l from 33 → 34; .specify/project.md "All N .specify/ feature specs" line auto-flagged + flipped 33 → 34 in the same commit. First run after fixes: 9/9 PASS — no documentation drift detected. Output flips from 8/8 to 9/9 because total-class count is now 8 numbered + 1 cross-file (was 7 + 1). Each numbered class output id flips from N/7N/8. Spec at .specify/features/audit-docs-matrix-prose.md, plan at docs/plans/audit-docs-matrix-prose.md. Documentation propagation: CLAUDE.md Common Commands pnpm audit:docs row updated 7 → 8 drift classes + new "Matrix-prose count parity" item; README.md Commands table similarly updated; .specify/project.md Current State header bumped 160 → 161 + spec count flipped 33 → 34. Pattern progression: iter-161 is the 8th maturation step in the doc-quality audit saga (iters 145 → 161). Each maturation step costs one iteration but compounds: iter-145 made future drift hunts grep-and-fix; iter-149 made it one-command; iter-150 made drift PR-blocking; iter-151 made the runner self-validating; iter-161 closes the matrix-prose drift-class coverage gap that iter-156 documented and iter-160 fired. After iter-161, "matrix-prose count drift" cannot accumulate undetected — it surfaces as [8/8] FAIL on the first PR or cron tick after the offending edit lands. Verification: pnpm audit:docs 9/9 PASS — all green. pnpm typecheck / pnpm lint not re-run (the script edit at scripts/audit-docs.ts is at repo root, not under any tsconfig/eslint scope; runtime executes via tsx; AGENTS.md / CLAUDE.md / README.md / spec / plan / index / log / project edits are doc-only). Q22 → Q28 saga remains fully closed; @ever-works/ui at branches 100% (233/233); pnpm lint 0 warnings 0 errors; CT-flake watch ✅ CLOSED. Project enters its 32nd consecutive "no carried open work" steady-state iteration (iter 130-161). Iteration 160 history below.)

Iteration 160 (history): catch + correct the iter-158/159 cohort-math drift propagation — second matrix-prose drift instance fires the iter-156 deferral #9 codify-trigger; correct math is 14 high-churn + 12 deferred + 1 redundant proxy = 27 (was 14 + 11 = 25 in iter-158/159). Doc-drift-fix tick. Iter-158 codified the cohort-migration policy after iter-154's caret-range patch lifts but its summary math was wrong — "11 deferred" claim and "14 + 11 = 25" math don't match the iter-156 27-package matrix. Recounting iter-158's enumeration confirms @astrojs/{vercel,preact,sitemap,check} brace expansion = 4 + 8 named = 12 deferred packages (not 11); plus iter-158's rationale ("the original 12 minus @typescript-eslint/parser which migrated to high-churn") was wrong because @typescript-eslint/parser was never in the iter-155 deferred cohort — it was iter-154-lifted, structurally distinct. Iter-159 re-applied iter-158's cohort partition verbatim without spot-checking. Iter-160 catches the propagation 1 commit deep. Corrected partition: 14 high-churn (12 baseline + 2 iter-154-migrants parser+jsdom) + 12 deferred (@astrojs/{vercel,preact,sitemap,check} 4 + 8 named) + 1 redundant proxy (@typescript-eslint/eslint-plugin shadowed by parser's atomic monorepo release) = 27 ✓. This is the second instance of the iter-156 matrix-prose drift class — per iter-156 deferral #9 ("codify-then-execute meta-pattern says wait for a second matrix-prose drift instance before adding the audit class"), the codify-trigger has now fired. Iter-160 corrects the math inline + flags the trigger; iter-161 should codify the new audit class (new auditMatrixProseCountParity() function in scripts/audit-docs.ts + AGENTS.md ### heading + EXPECTED_MAPPING entry + class-count update from 7/7 → 8/8 + spec/plan updates; ~30-45 min implementation). Pattern progression note: latency from drift-introduction to drift-fix dropped 22 → 1 iterations — iter-156's deferral-#9 framing made future readers more attuned to matrix-prose math, so this second instance was caught at iteration N+1 instead of N+22. Sub-mode classification: doc-drift-fix tick (9th in the 132/135/137/138/141/144/148/156/160 sequence). Audit script confirms its coverage gap: pnpm audit:docs 8/8 PASS — value-drift class (3/7) checks **N packages** workspace-package count and All N .specify/ feature specs (= 33), but does NOT check N-package matrix dep-cohort prose, exactly the coverage gap iter-156 documented. No source / test / config / dep / lockfile / spec / plan changes. Q22 → Q28 saga remains fully closed; @ever-works/ui at branches 100% (233/233); pnpm lint 0 warnings 0 errors; CT-flake watch ✅ CLOSED. Project enters its 31st consecutive "no carried open work" steady-state iteration (iter 130-160). Iteration 159 history below.)

Iteration 159 (history): routine verification tick on iter-158 baseline — pnpm audit:docs 8/8 PASS + 14-package cohort (12 high-churn + 2 iter-154-lifted) all zero-delta against workspace caret floors. Third consecutive verification-only tick after iter-156's matrix-count re-baseline; the 6th verification-only tick overall in the iter-152 / 153 / 155 / 157 / 158 / 159 sequence (with iter-154 dep-delta-apply and iter-156 doc-drift-fix interleaved). Iter-159 re-applies the iter-158-codified cohort partition (14 high-churn + 11 deferred = 27-package matrix) on the iter-158 commit a109d85 baseline. Both verification classes return bit-for-bit identical output to iter-158 / iter-157 / iter-156 / iter-155 final-state — the 6-tick streak (iter-155 → iter-159) of identical PASS output is now a very strong stability signal that the doc-quality audit infrastructure (iter-145 → iter-151) and the every-tick dep-cohort surveillance (iter-152 → iter-158) together produce deterministic output across cold cron-tick re-runs over a full ~24-hour window. The iteration crosses a calendar-day boundary for the first time in the verification-only chain (iter-155 → iter-158 all landed on 2026-04-27; iter-159 lands on 2026-04-28). Observation-only: the autonomous loop's per-tick cost is not coupled to any wall-clock-day boundary, and the audit + cohort outputs are identical regardless of which calendar day the tick lands on. 14/14 zero deltas verified: astro 6.1.9 / preact 10.29.1 / tailwindcss 4.2.4 / typescript 6.0.3 / vitest 4.1.5 / @playwright/test 1.59.1 / monocart-coverage-reports 2.12.11 / monocart-reporter 2.10.1 / eslint 10.2.1 / prettier 3.8.3 / turbo 2.9.6 / isomorphic-git 1.37.6 / @typescript-eslint/parser 8.59.1 / jsdom 29.1.0. pnpm audit:docs 8/8 PASS bit-for-bit identical to iter-158 / iter-157 / iter-156 / iter-155 final-state output. Sub-mode classification: verification-only (per the iter-154 sub-mode taxonomy) — the 6th verification-only tick in the iter-152 / 153 / 155 / 157 / 158 / 159 sequence (now the longest verification-only run in the project's autonomous-loop history). Total walltime ~3-4 min (~5s audit + ~35s parallel pnpm view for 14 packages + 3 doc edits + commit). NEW deferral #12 codified: calendar-day annotation in per-tick preamble — the current per-tick log preamble already includes the date in the heading (## YYYY-MM-DD — Iteration N: ...), so explicit calendar-day annotation in the body would be redundant for now; tracked for visibility, codify-then-execute pattern says wait until the second cross-day verification tick before adding structure. No source / test / config / dep / lockfile / spec / plan changes. Q22 → Q28 saga remains fully closed; @ever-works/ui at branches 100% (233/233); pnpm lint 0 warnings 0 errors; CT-flake watch ✅ CLOSED. Project enters its 30th consecutive "no carried open work" steady-state iteration (iter 130-159). Iteration 158 history below.)

Iteration 158 (history): routine verification tick on iter-157 baseline — pnpm audit:docs 8/8 PASS + 14-package cohort (12 high-churn + 2 iter-154-lifted) all zero-delta against workspace caret floors. Second consecutive verification-only tick after iter-156's matrix-count re-baseline. Iter-157 ran the 12-package high-churn cohort; iter-158 expands the every-tick check by 2 to include the iter-154-lifted packages (@typescript-eslint/parser + jsdom) so they receive ongoing patch-level surveillance immediately after their lift, rather than waiting for the next deferred-cohort re-verification. The expansion costs ~5s in additional pnpm view walltime and produces a stronger signal: any recurrence of the patch-bump cadence that motivated iter-154 will surface within one cron tick instead of one to several iterations later. Cohort migration policy codified iter-158: when a deferred-cohort package gets lifted via the iter-128 / iter-154 caret-range-patch precedent, it migrates to the high-churn cohort for ongoing every-tick verification. The cohorts together always sum to the documented 27-package matrix; the deferred cohort shrinks monotonically across lift events. After iter-158: 14 high-churn + 11 deferred (was 12 + 12 + 3-lifted at iter-155). 14/14 zero deltas verified: astro 6.1.9 / preact 10.29.1 / tailwindcss 4.2.4 / typescript 6.0.3 / vitest 4.1.5 / @playwright/test 1.59.1 / monocart-coverage-reports 2.12.11 / monocart-reporter 2.10.1 / eslint 10.2.1 / prettier 3.8.3 / turbo 2.9.6 / isomorphic-git 1.37.6 / @typescript-eslint/parser 8.59.1 / jsdom 29.1.0. Note: @typescript-eslint/eslint-plugin was also lifted in iter-154 alongside parser, but the typescript-eslint monorepo cuts releases atomically, so querying parser is sufficient surveillance — cohort migration adds the canonical proxy only. pnpm audit:docs 8/8 PASS bit-for-bit identical to iter-157 / iter-156 / iter-155 final-state output — the 5-tick streak (iter-155 → iter-158) of identical PASS output is a strong stability signal that the doc-quality audit infrastructure (iter-145 → iter-151) is bedded in and produces deterministic output across cold cron-tick re-runs. Sub-mode classification: verification-only (per the iter-154 sub-mode taxonomy) — the 5th verification-only tick in the iter-152 / 153 / 155 / 157 / 158 sequence (with iter-154 dep-delta-apply and iter-156 doc-drift-fix interleaved). Total walltime ~3-4 min (~5s audit + ~35s parallel pnpm view for 14 packages + 3 doc edits + commit). NEW deferral #11 codified: cohort-migration log retention — future verification ticks should reference the iter-158 cohort partition (14 high-churn + 11 deferred) rather than re-deriving from iter-152's original 12 + iter-154's 3 + iter-155's 12. If another lift happens, update both the high-churn cohort table and this deferral entry in the same commit. No source / test / config / dep / lockfile / spec / plan changes. Q22 → Q28 saga remains fully closed; @ever-works/ui at branches 100% (233/233); pnpm lint 0 warnings 0 errors; CT-flake watch ✅ CLOSED. Project enters its 29th consecutive "no carried open work" steady-state iteration (iter 130-158). Iteration 157 history below.)

Iteration 157 (history): routine verification tick on iter-156 baseline — pnpm audit:docs 8/8 PASS + 12-package high-churn dep cohort all zero-delta against workspace caret floors. First verification-only tick after the iter-156 doc-drift-fix iteration that closed the matrix-count off-by-one (re-baselined 26-package27-package with explicit per-cohort enumeration). Iter-157 re-runs both standard verification classes — the doc-quality audit on the iter-156 baseline and the high-churn 12-package pnpm view <pkg> version quick-check — and confirms zero drift in either: (1) pnpm audit:docs 8/8 PASS bit-for-bit identical to iter-156's post-edit output (the matrix-prose re-baseline at .specify/project.md line 94 is checked by audit class 6/7 only as a structural-link check, not as a value-drift check — there is no audit class for N-package matrix count parity yet, so iter-157's audit run doesn't double-count the iter-156 fix); (2) 12-package high-churn dep cohort zero-delta vs iter-152 / 153 / 155 / 156 baselines — astro 6.1.9, preact 10.29.1, tailwindcss 4.2.4, typescript 6.0.3, vitest 4.1.5, @playwright/test 1.59.1, monocart-coverage-reports 2.12.11, monocart-reporter 2.10.1, eslint 10.2.1, prettier 3.8.3, turbo 2.9.6, isomorphic-git 1.37.6 — every line resolves to the same version captured at iter-156. The 15-package gap to the documented 27-package matrix (3 iter-154-lifted + 12 iter-155-deferred-cohort packages, verified at iter-154 / iter-155) is unlikely to have moved at the ~30 min interval since iter-156; full re-verification deferred until next material dep-touching iteration per iter-155 deferral policy. Sub-mode classification: verification-only (per the iter-154 sub-mode taxonomy) — the first verification-only tick after iter-156's doc-drift-fix tick, restoring the iter-152 / 153 / 155 cadence. The deferral list shrinks by zero this tick (iter-156 already closed the iter-155 finding #8 matrix-count off-by-one, the only actively-tracked drift item; the remaining 8 carried deferrals — regex-equivalence checking, sample-app port consistency rejection, optional E2E re-run, optional coverage re-run, react/react-dom 18→19 in @ever-works/docs-minimal blocked by Docusaurus 3.x peer range, [email protected] transitive deprecation, full 27-package matrix re-verification at next dep-touch, and matrix-prose audit class — are all standing-deferred per established policy and don't need iter-157 action). Total walltime ~3 min (~5s audit + ~30s parallel pnpm view for 12 packages + 3 doc edits + commit). No source / test / config / dep / lockfile / spec / plan changes. Q22 → Q28 saga remains fully closed; @ever-works/ui at branches 100% (233/233); pnpm lint 0 warnings 0 errors; CT-flake watch ✅ CLOSED. Project enters its 28th consecutive "no carried open work" steady-state iteration (iter 130-157). Iteration 156 history below.)

Iteration 156 (history): re-baseline the matrix count from 26-package to 27-package — close iter-155 finding #8 (off-by-one drift originating from iter-133's "expanded by 3" while listing 4 package names). Iter-155 surfaced finding #8 in its "Deferrals carried" section: the documented 26-package matrix prose in .specify/project.md line 94 was technically off-by-one — the verification-cohort enumeration totalled 27 (12 high-churn + 3 iter-154-lifted + 12 iter-155-deferred), but iter-155 hypothesized that @playwright/experimental-ct-react was double-counted vs @playwright/test. Iter-156 investigation confirms the iter-155 hypothesis is INCORRECT: @playwright/test (the main test runner) and @playwright/experimental-ct-react (the component-testing extension) are separate packages with distinct dist-tags and version histories — both consumed by packages/ui/package.json as devDependencies. The 27 enumeration is the correct count. Actual root cause: iter-133's expansion trail prose said "expanded by 3" while listing 4 package names (correctly: 23 + 4 = 27, not 26). The off-by-one propagated through 22 iterations (iter 133 → iter 155) without anyone noticing — every subsequent iteration kept saying "26-package matrix" because the carried-forward prose was treated as authoritative. Fix: .specify/project.md line 94 prose re-baselined 26-package27-package with: explicit "expanded by 4" with all 4 package names; per-cohort enumeration (12 + 3 + 12 = 27 packages, named) so a future audit can re-verify by reading the line itself; disambiguation note clarifying @playwright/experimental-ct-react is separate from @playwright/test; iter-156 provenance for greppability. Sub-mode classification: doc-drift-fix tick (matches iter-132/135/137/138/141/144/148 pattern). The audit-script's value-drift class (3/7) checks **N packages** (workspace packages) but does NOT check N-package matrix prose — a coverage gap. Codify-then-execute meta-pattern says wait until a second matrix-prose drift surfaces before adding an audit class for it; tracked as deferral #9 for future iterations. Pattern progression: 9th doc-drift-fix iteration since iter-132 (132/135/137/138/141/144/148/156). No source / test / config / dep / lockfile / spec / plan changes. Q22 → Q28 saga remains fully closed; @ever-works/ui at branches 100% (233/233); pnpm lint 0 warnings 0 errors; CT-flake watch ✅ CLOSED. Project enters its 27th consecutive "no carried open work" steady-state iteration (iter 130-156). Iteration 155 history below.)

Iteration 155 (history): close iter-154 deferral #3 — full 26-package matrix re-verification; remaining 12-package deferred-cohort all zero-delta against workspace caret floors. Verification-only iteration that closes iter-154's deferral #3 ("future iterations should include a full 26-package quick-check on the next material dep-touching iteration to surface any other accumulated patches"). Iter-154 lifted the 3 known-moved deltas in the deferred cohort (@typescript-eslint/{parser,eslint-plugin} + jsdom) but left 12 of the 14 deferred-cohort packages unchecked since iter-133/iter-135/iter-142 baselines. Iter-155 queries the full remaining cohort against pnpm view <pkg> version and confirms zero deltas — every workspace caret floor still matches the latest resolution exactly (not merely covered by the caret range). The full 26-package matrix is now bit-for-bit zero-delta after the iter-154 lifts; no package in the documented matrix has unverified time greater than iter-154's commit timestamp. 12-package remaining-cohort zero-delta verification: @astrojs/vercel 10.0.5 / @astrojs/preact 5.1.2 / @astrojs/sitemap 3.7.2 / @astrojs/check 0.9.8 / @playwright/experimental-ct-react 1.59.1 / vitest-monocart-coverage 4.0.2 / marked 18.0.2 / yaml 2.8.3 / pagefind 1.5.2 / postcss 8.5.12 / tailwind-merge 3.5.0 / @vitest/coverage-v8 4.1.5 — all 12/12 floor=latest. The iter-154 finding ("3/14 packages moved" was a non-trivial signal) does not recur for the remaining 12: the deferred-cohort policy correctly identified low-churn packages. Sub-mode classification: verification-only (per the iter-154 sub-mode taxonomy) with the bonus of explicitly closing a deferral chain. Total walltime ~3 min (~5s audit + ~30s parallel pnpm view for 12 packages + 3 doc edits + commit). Matrix-count off-by-one finding (iter-155, NEW): the documented 26-package matrix prose enumerates 27 entries when the verification-cohort split is rolled up — @playwright/experimental-ct-react is referenced in two places (iter-133 expansion entry + iter-154 footnote). Not real drift; same package, same version. Re-baseline at next matrix expansion. No source / test / config / dep / lockfile / spec / plan changes. Q22 → Q28 saga remains fully closed; @ever-works/ui at branches 100% (233/233); pnpm lint 0 warnings 0 errors; CT-flake watch ✅ CLOSED. Project enters its 26th consecutive "no carried open work" steady-state iteration (iter 130-155). Iteration 154 history below.)

Iteration 154 (history): dep audit lifts 3 patch-level deltas in the iter-153-deferred 14-package cohort — @typescript-eslint/parser 8.59.0 → 8.59.1, @typescript-eslint/eslint-plugin 8.59.0 → 8.59.1, jsdom 29.0.2 → 29.1.0; pnpm audit:docs 8/8 PASS, full verify (typecheck 23/23 + lint 18/18 + test 16/16 = 1122/1122 Vitest) green. First substantive iteration after the iter-152 / iter-153 verification-only chain — it is the first dep-quick-check tick whose signal turned non-zero. Iter-153 deferred the 14-package "low historical churn" cohort (@astrojs/{vercel,preact,sitemap,check}, @playwright/experimental-ct-react, @typescript-eslint/{parser,eslint-plugin}, vitest-monocart-coverage, marked, yaml, pagefind, postcss, tailwind-merge, @vitest/coverage-v8, jsdom); iter-154 expands the quick-check to include @typescript-eslint/{parser,eslint-plugin} + jsdom and surfaces 3 real patch-level deltas accumulated since iter-133/iter-135/iter-142 baselines. All three are inside their existing caret ranges, so the iter-128 caret-range-patch precedent applies (apply inline rather than defer further). Bumps: @typescript-eslint/{parser,eslint-plugin} ^8.59.0^8.59.1 (kept the version pair in lock-step — typescript-eslint monorepo cuts releases atomically; 4 pre-existing no-console warnings carry forward unchanged, no new warnings from the patch bump); jsdom ^29.0.2^29.1.0 (minor-version bump inside the caret range — devDep of @ever-works/ui for Vitest jsdom env on the 3 non-CT-migrated Preact components). Net diff: +18/-15 in pnpm-lock.yaml, +3/-3 across 2 manifests. Verification full quartet green: pnpm typecheck 23/23 in 2m47s (0 errors / 0 warnings / 0 hints across 21 Astro files); pnpm lint 18/18 in 56s (no new warnings); pnpm test 16/16 in 3m05s (1122/1122 Vitest tests; jsdom 29.0.2 → 29.1.0 didn't regress any jsdom-environment Preact tests); pnpm audit:docs 8/8 PASS retained. NEW finding tracked for future iterations: react / react-dom 18.3.1 → 19.2.5 in @ever-works/docs-minimal is a major-version bump held back by Docusaurus 3.x's React 18 peer-range constraint — not actionable inside ^18.3.0; tracked for visibility, no fix this iteration. [email protected] deprecation warning is a transitive sub-dep of jsdom (depth 2) — not actionable from our manifest. Pattern progression: after iter-154, the autonomous-loop steady-state pattern has 3 documented sub-modes — verification-only (152, 153; ~5 min/tick), doc-drift fix (132-148; ~10-30 min/tick), dep-delta apply (128, 154; ~15 min/tick). Future iterations fall into one of these three. Deferrals updated: regex-equivalence checking still deferred (no drift in 9 iterations); sample-app port consistency rejected (no drift); full 26-package matrix — 11 deferred-cohort packages still on iter-133/135/142/140 baselines (the iter-154 finding of 3/14 packages moved is a non-trivial signal, so future iterations should include a full 26-package quick-check on the next material dep-touching iteration). Q22 → Q28 saga remains fully closed; @ever-works/ui at branches 100% (233/233); pnpm lint 0 warnings 0 errors; CT-flake watch ✅ CLOSED. Project enters its 25th consecutive "no carried open work" steady-state iteration (iter 130-154). Iteration 153 history below.)

Iteration 153 (history): routine verification tick — pnpm audit:docs 8/8 PASS on iter-152 baseline + 12-package dep quick-check zero deltas. Second consecutive verification-only iteration after the iter-145 → iter-151 codify-then-execute meta-arc converged. Iter-152 established the canonical steady-state shape (~5s audit run + ~30s dep walltime + 3 doc edits + commit); iter-153 re-runs the same shape on the iter-152 commit 2ee4b88 baseline. Output is bit-for-bit identical to iter-152's — confirms the runner is stable across cold cron-tick re-runs (no machine-local cached state, no environment-variable dependence, no transient package-manager state); the reproducibility property held for two consecutive cron ticks. 12-package dep quick-check zero deltas: same 12 packages (astro/preact/tailwindcss/typescript/vitest/@playwright/test/monocart-coverage-reports/monocart-reporter/eslint/prettier/turbo/isomorphic-git), same versions, same iter-151 / iter-152 baseline. Sample-port consistency considered + rejected as a new audit class: README.md Samples table 4323-4327 matches apps/sample-*/package.json dev/preview scripts exactly — no real drift surfaces, so adding the audit class preemptively would violate the codify-then-execute meta-pattern. If a future iteration changes a sample's port and forgets to update README, the resulting drift triggers the audit-class addition at THAT iteration. Regex-equivalence checking (carried from iter-151/152): still deferred — no real regex-divergence drift in 8 iterations. Pattern progression: iter-153 is the second verification-only iteration after the converged steady-state — the bounded per-tick cost is now small enough that future autonomous iterations can run dozens of consecutive verification-only ticks without accumulating drift or expanding the doc surface. No source / test / config / dep / lockfile / spec / plan changes. Q22 → Q28 saga remains fully closed; @ever-works/ui at branches 100% (233/233); pnpm lint 0 warnings 0 errors; CT-flake watch ✅ CLOSED. Project enters its 24th consecutive "no carried open work" steady-state iteration (iter 130-153). Iteration 152 history below.)

Iteration 152 (history): routine verification tick — pnpm audit:docs 8/8 PASS on iter-151 baseline + 12-package dep quick-check zero deltas. First full autonomous tick after the iter-149 codification + iter-150 CI wire-up + iter-151 self-validation chain landed; running pnpm audit:docs on the unchanged iter-151 commit 63b1bf9 baseline confirms the runner's PASS output is stable across cold cron-tick re-runs (i.e., the audit isn't silently dependent on machine-local cached state, environment variables, or transient package-manager state). A reproducibility signal of this kind is normally invisible in single-author work but matters for an autonomous-loop workstream where every cron tick is effectively a fresh CI run. 12-package dep latest quick-check (zero deltas vs iter-151): astro 6.1.9, preact 10.29.1, tailwindcss 4.2.4, typescript 6.0.3, vitest 4.1.5, @playwright/test 1.59.1, monocart-coverage-reports 2.12.11, monocart-reporter 2.10.1, eslint 10.2.1, prettier 3.8.3, turbo 2.9.6, isomorphic-git 1.37.6 — every line resolves to the same version captured at iter-151. The 14-package gap to the documented 26-package matrix (verified at iter-133/iter-135/iter-142) is unlikely to have moved at the ~3-hour interval since iter-151; full re-verification deferred until next material dep-touching iteration. Pattern progression: iter-152 is the first verification-only iteration after the iter-145 → iter-151 codify-then-execute meta-arc — the canonical exemplar of the converged steady-state shape (~5s audit run + ~12 parallel pnpm view calls + 3 doc edits + a commit). The bounded per-tick cost is now small enough that future autonomous iterations can run dozens of consecutive verification-only ticks without accumulating drift or expanding the doc surface. No source / test / config / dep / lockfile changes. Q22 → Q28 saga remains fully closed; @ever-works/ui at branches 100% (233/233); pnpm lint 0 warnings 0 errors; CT-flake watch ✅ CLOSED. Project enters its 23rd consecutive "no carried open work" steady-state iteration (iter 130-152). Iteration 151 history below.)

Iteration 151 (history): add 7th audit class — auditChecklistRunnerParity() self-validates the script against AGENTS.md § Doc-Quality Audit Checklist on every run. Closes iter-149's "Next Steps #1" — the parity between AGENTS.md (canonical reference) and scripts/audit-docs.ts (canonical runner) was previously enforced by convention only; codifying the parity check inside the script itself means the runner self-validates against its own canonical reference text on every invocation, including the iter-150 CI gate. Implementation: new auditChecklistRunnerParity() function in scripts/audit-docs.ts reads AGENTS.md directly with node:fs, locates the ## Doc-Quality Audit Checklist section bounds, extracts every ### sub-section heading inside (with code-fence skipping so the in-section canonical-mapping documentation block doesn't self-trigger), and asserts a 1:1 parity against an in-script EXPECTED_MAPPING table. Both directions of drift are caught: a heading in AGENTS.md without an EXPECTED_MAPPING entry produces + "<heading>" — heading in AGENTS.md but no EXPECTED_MAPPING entry; an EXPECTED_MAPPING entry without an AGENTS.md heading produces - "<heading>" — EXPECTED_MAPPING entry but no AGENTS.md heading. Plus a class-count parity check: classes[] numbered runner ids (N/M form) vs distinct numbered ids referenced by EXPECTED_MAPPING entries — catches a forgotten classes[] entry vs mapping table mismatch. AGENTS.md update (lands same commit): new ### Checklist ↔ runner parity (added iter 151) sub-section under ## Doc-Quality Audit Checklist, immediately above ### Rerun cadence, with a code-fence listing the canonical heading-to-class mapping (mirrored in scripts/audit-docs.ts § EXPECTED_MAPPING). Existing ### Runner (added iter 149) sub-section reference bumped 6 → 7 numbered classes. Spec count drift caught by audit class 3 (count parity): adding the new spec file audit-docs-self-parity.md bumped ls .specify/features/*.md | wc -l from 32 → 33; .specify/project.md "All N .specify/ feature specs" line auto-flagged + flipped from 32 → 33 in the same commit. First run after fixes: 8/8 PASS — no documentation drift detected. Output flips from 7/7 to 8/8 because total-class count is now 7 numbered + 1 cross-file (was 6 + 1). Each numbered class output id flips from N/6N/7. Spec at .specify/features/audit-docs-self-parity.md, plan at docs/plans/audit-docs-self-parity.md. Documentation propagation: CLAUDE.md Common Commands pnpm audit:docs row updated 6 → 7 drift classes + new "Checklist ↔ runner parity" item; README.md Commands table similarly updated; .specify/project.md Current State header bumped 150 → 151 + spec count flipped 32 → 33 + "Zero documentation drift" line annotated with the new audit class provenance. Pattern progression: iter-151 is the 7th maturation step in the doc-quality audit saga (iters 132 → 144 single-file drift fixes → iter 145 codify playbook as in-tree text → iter 149 codify as runnable script → iter 150 wire into CI as PR-blocking gate → iter 151 self-validate runner ↔ canonical reference). Each maturation step costs one iteration but compounds: iter-145 made future drift hunts grep-and-fix instead of reason-from-scratch; iter-149 made it one-command; iter-150 made drift PR-blocking; iter-151 makes the runner self-validating. After iter-151, "checklist heading without runner class" and "runner class without checklist heading" drifts cannot accumulate undetected — both surface as [7/7] FAIL on the first PR or cron tick after the asymmetric edit lands. Verification: pnpm typecheck 23/23 FULL TURBO + pnpm lint 18/18 FULL TURBO + pnpm audit:docs 8/8 PASS — all green. No source / test / config / dep / lockfile changes (the script edit is at scripts/audit-docs.ts which is at repo root, not under any tsconfig/eslint scope; runtime executes via tsx). Q22 → Q28 saga remains fully closed; @ever-works/ui at branches 100% (233/233); pnpm lint 0 warnings 0 errors; CT-flake watch ✅ CLOSED. Project enters its 22nd consecutive "no carried open work" steady-state iteration (iter 130-151). Iteration 150 history below.)

Iteration 150 (history): wire pnpm audit:docs into CI — convert the iter-149 doc-quality audit script from per-cron-tick manual check to PR-blocking signal. Iter-149 codified the AGENTS.md § Doc-Quality Audit Checklist grep blocks into a single runnable TypeScript runner (scripts/audit-docs.ts, 635 LOC, exposed as pnpm audit:docs); iter-149's "Next Steps #2" called out the natural maturation step — wire it into CI so doc drift becomes a PR-blocking signal alongside lint / typecheck. One-step addition to the existing ci job in .github/workflows/ci.yml, positioned between the existing Security audit and Lint steps. New Doc-quality audit step runs pnpm audit:docs (single command, ~5s walltime, no test runs, no network) with a 16-line comment block enumerating the 7 drift classes the script enforces. Why position it in the ci job (not a parallel dedicated job): (1) shared prerequisites — actions/checkout@v4 + pnpm/action-setup@v4 + actions/setup-node@v4 + pnpm install --frozen-lockfile are already there, net incremental cost is just the ~5s the script takes; (2) same-failure-signal property — a doc drift now fails the same ci job as lint/typecheck/test/build; reviewers see one red job instead of two; (3) no CI matrix change — the existing 4 jobs (ci, test-ct, coverage-gate, e2e) and their needs: chain stay verbatim. Pattern progression: iters 132-144 (single-file drift) → iter 145 (codify playbook as text) → iter 149 (codify as runnable script) → iter 150 (codify as CI gate). Each maturation step costs one iteration but compounds: iter-145 made future drift hunts grep-and-fix instead of reason-from-scratch; iter-149 made it one-command; iter-150 makes drift PR-blocking instead of "must-remember-to-run". After iter-150, doc-quality drift cannot accumulate undetected — every PR has the audit run as a hard prerequisite. Local re-verification: pnpm audit:docs 7/7 PASS in ~5s on the iter-149 commit 3e9d59b baseline (no drift since iter-149 landed). Routine dep audit deferred this iteration (iter-147/148/149 zero deltas; inheritance consistent; CI's existing Security audit step handles security-relevant audits separately). No source / test / config / dep / lockfile changes. Q22 → Q28 saga remains fully closed; @ever-works/ui at branches 100% (233/233); pnpm lint 0 warnings 0 errors; CT-flake watch ✅ CLOSED. Project enters its 21st consecutive "no carried open work" steady-state iteration (iter 130-150). Iteration 149 history below.)

Iteration 149 (history): codify AGENTS.md § Doc-Quality Audit Checklist as an executable runner — scripts/audit-docs.ts + root pnpm audit:docs script. Substantive iteration that breaks the 17-iteration doc-only treadmill (iters 132 → 148). After 4 consecutive iterations of the codify-then-execute meta-pattern (iter-145 codified the audit checklist as 5 grep blocks; iter-146 found a miss-target; iter-147 tightened the regex AND ran it inline; iter-148 added a 6th block for cross-file consistency), the friction of running 6 separate grep blocks by hand on every iteration had become the dominant per-iteration cost. Iter-149 closes this loop: scripts/audit-docs.ts (TypeScript via tsx) wraps each of the 6 drift classes — Status drift line-anchored, Status drift blockquote-tolerant (with the iter-149 unicode-surrogate fix for the 🗄/🗄️ SUPERSEDED sigil), Value drift (count parity for specs / packages / apps / 43 vs 48 CT cases — caught a real All 31 → All 32 drift introduced by this iteration's own new spec file), Toolchain version drift (Astro/Preact/Tailwind/TypeScript major-version cross-check vs apps/web/package.json), ISR wording drift (fully static\|no SSR with broad allowlist for legitimate sample-app and historical-narrative surfaces), Structural-link drift — plus a 7th cross-file consistency parity check (AGENTS.md R-rules vs CLAUDE.md Critical Rules: 15 vs 17). Each class returns PASS / FAIL <N hits> with line-anchored output for hits; the runner exits non-zero on any class flagging real drift, so it is CI-gating-ready (deferred to a future iteration per spec AC-out-of-scope). First run after fixes: 7/7 PASS — no documentation drift detected. Spec at .specify/features/audit-docs-script.md, plan at docs/plans/audit-docs-script.md. Documentation propagation: AGENTS.md § Doc-Quality Audit Checklist gains a new "Runner" subsection at the top pointing at pnpm audit:docs (script is canonical runner; checklist remains canonical reference); CLAUDE.md Common Commands + Safe Operations gains the pnpm audit:docs line; README.md Commands table gains the new row; .specify/project.md Current State header bumped 148 → 149 + spec count flipped 31 → 32 + "Zero documentation drift" line annotated with the new audit runner provenance. Pattern progression: the 17-iteration single-class doc-only treadmill (iters 132 → 148) breaks here. Iter-149 is the first substantive code-artefact iteration since iter-130 (Q28 ESLint 9→10 in-place upgrade) — net +5 files added (scripts/audit-docs.ts + spec + plan + package.json script line + audit-checklist Runner subsection). The codify-then-execute meta-pattern (iters 145 → 148) culminates in iter-149's executable codification: the audit reference and the audit runner now share a 1:1 codification relationship, and future drift classes are added in the same commit to both surfaces (per the new audit-checklist policy line). Verification: pnpm typecheck 23/23 FULL TURBO + pnpm lint 18/18 FULL TURBO + pnpm audit:docs 7/7 PASS — all green. Lockfile delta zero (root gained tsx as devDependency, but tsx was already a workspace dep via apps/web and apps/sample-* scripts — no new install). Q22 → Q28 saga remains fully closed; @ever-works/ui at branches 100% (233/233); pnpm lint 0 warnings 0 errors; CT-flake watch ✅ CLOSED. Project enters its 20th consecutive "no carried open work" steady-state iteration (iter 130-149). Iteration 148 history below.)

Iteration 148 (history): cross-file consistency drift — close the AGENTS.md ↔ CLAUDE.md "Critical Rules" sync gap (R9-R15 missing from CLAUDE.md); codify the new drift class in AGENTS.md § Doc-Quality Audit Checklist. Pure-doc iteration executing iter-147's Next Step #2 (cross-file consistency check). Real cross-file drift found: CLAUDE.md "Critical Rules" listed only 10 numbered items while AGENTS.md "Mandatory Rules" defines 15 R-rules — the 7 rules R9-R15 (Documentation First / Use Existing Libraries / Do Not Remove / Monorepo Structure / Exhaustive Documentation / Convention Over Configuration / Specification First) had no corresponding line in CLAUDE.md despite AGENTS.md R8 line 62 explicitly stating "AGENTS.md and CLAUDE.md always up to date". Both files are loaded into AI-agent context every session — a rule that lives in one but not the other creates an under-documented obligation. Fix part 1: CLAUDE.md "Critical Rules" gains 7 new items (11-17) mirroring AGENTS.md R9-R15 with one-line summaries + a cross-reference paragraph mapping CLAUDE.md items 1-17 to AGENTS.md R1-R15 (R3+R4 fan out into items 2-4 + 7 in CLAUDE.md for marketing-clarity; R9-R15 map 1:1 to items 11-17). Fix part 2: AGENTS.md § Doc-Quality Audit Checklist gains a new "Cross-file consistency (added iter 148)" subsection (~24 lines) with 7-line explanation, 5 lines of grep commands (grep -cE "^### R[0-9]+:" AGENTS.md vs grep -cE "^[0-9]+\\.\\s+\\*\\*" CLAUDE.md — should match 15 vs 17), and an explicit policy line "When an R-rule is added, removed, or reworded, update both files in the same commit." Codified-greps re-run (Status drift / Value drift / Toolchain / ISR / Structural-link): zero outstanding non-resolved hits — iter-148's surface is the new cross-file class, not a regression of any previous class. Pattern progression confirmed for the 12th iteration in a row (iter-132 → iter-148, with iter-148's twist: cross-file consistency joins the codified drift-class catalogue). Routine dep audit deferred this iteration (iter-147 zero deltas; inheritance consistent). No source / test / config / dep / lockfile changes. Q22 → Q28 saga remains fully closed; @ever-works/ui at branches 100% (233/233); pnpm lint 0 warnings 0 errors; CT-flake watch ✅ CLOSED. Project enters its 19th consecutive "no carried open work" steady-state iteration (iter 130-148). Iteration 147 history below.)

Iteration 147 (history): execute iter-146 Next Step #1 — tighten the iter-145 codified audit checklist Status-drift regex to tolerate > blockquote prefix + **bold** markdown wrapping; routine codified-greps re-run surfaces 1 stale CT-count claim in .specify/features/q22-playwright-coverage.md AC #10 (43/43 → 48/48); routine 10-package dep quick-check zero deltas. Pure-doc iteration. Two parallel deliverables: (1) AGENTS.md § Doc-Quality Audit Checklist Status/state drift block gains a new tighter regex variant grep -rEn "^>?\\s*\\*?\\*?Status:\\s+\\*?\\*?[^✅]" docs/plans/ .specify/features/ (added below the existing line-anchored regex with a 6-line explanatory comment block crediting iter-146 for the miss-targets that motivated the tightening). The new pattern matches Status: regardless of leading > blockquote prefix or **bold** wrapping — the exact shape iter-146's two miss-targets (q22-upstream-repro.md:12 + q22-playwright-ct.md:15) shared. (2) The full codified-greps re-run with the new tighter regex against the full docs/plans/q*.md + .specify/features/q*.md surface returns zero outstanding non-resolved status lines (the only matches are q22-upstream-repro.md's archeology block lines 21-22 — narrative references to the original DRAFT wording preserved by iter-146, not active claims). However, the value-drift block finds one real stale CT-count claim in .specify/features/q22-playwright-coverage.md AC #10 line 151: pnpm test:ct still reports 43/43 passing (16 FilterBar + 12 LayoutSwitcher + 15 MobileMenu). The 43/43 baseline matches the iter-110 spec authoring time; subsequent CT growth (iter-120 focus-trap +2 cases → 45/45; iter-124 Q27 outlier closure +3 cases → 48/48) was reflected in the spec's ## Status block (front matter — refreshed iter 122) but the AC #10 enumeration was missed. Same drift class as iter-132 (CLAUDE.md 43 → 48), iter-140 (q28 AC #5 + Step 4 conflated 1170), iter-141 (apps/docs/blog/ Fully static predates iter-17). Fixed via the iter-140 minimal-rewrite pattern: the original 43/43 + 15-MobileMenu baseline preserved as historical context inline, while the current 48/48 + 20-MobileMenu count and the iter-120 + iter-124 growth chain are documented (so a future audit doesn't re-flag this AC, AND the spec's iter-115 / iter-121 verification provenance stays traceable). Routine 10-package dep quick-check (zero deltas) astro 6.1.9 / vitest 4.1.5 / @playwright/test 1.59.1 / tailwindcss 4.2.4 / preact 10.29.1 / typescript 6.0.3 / eslint 10.2.1 / isomorphic-git 1.37.6 / turbo 2.9.6 / prettier 3.8.3 — all pinned versions match npm latest (verified ~1h after iter-146; matches iter-143's 10-package subset baseline). 16-package gap to documented 26-package matrix unlikely to have moved at this interval; full re-verification deferred. Pattern progression confirmed for the 11th iteration in a row (iter-132 → iter-147). With iter-147's twist: the codified audit checklist (iter-145) + tightened regex (iter-147) + first-execution dogfood (iter-147 itself) close the institutional-knowledge loop — future autonomous iterations now start from AGENTS.md § Doc-Quality Audit Checklist and run the already-fixed patterns rather than re-deriving them from log archaeology each tick. The iter-146 / iter-147 sequence demonstrates the codify-then-tighten meta-pattern: codify a pattern (iter-145), discover the codified pattern misses real cases (iter-146), tighten the pattern (iter-147), confirm the tightened pattern catches the missed cases (this iteration's re-run). Verification: pnpm typecheck 23/23 FULL TURBO (1.321s) + pnpm lint 18/18 FULL TURBO (1.402s) — 100% cache hits, doc-only changes. No source / test / config / dep / lockfile changes. Q22 → Q28 saga remains fully closed; @ever-works/ui at branches 100% (233/233); pnpm lint 0 warnings 0 errors; CT-flake watch ✅ CLOSED. Project enters its 18th consecutive "no carried open work" steady-state iteration (iter 130-147). Iteration 146 history below.)

Iteration 146 (history): first run of the iter-145 codified audit checklist surfaces 2 stale plan-status lines missed by iter-144docs/plans/q22-upstream-repro.md line 12 still said Status: **DRAFT — execute in parallel with the Playwright CT migration..." (authored iter 102 as a hedge; the migration succeeded and the upstream vitest-dev/vitest issue was never filed), and docs/plans/q22-playwright-ct.md line 15 still said Status: **✅ PHASE 2 COMPLETE — Remaining work: Step 6" (entire Q22 → Q28 saga is now fully closed; Step 6 was satisfied implicitly across the iter-105 → iter-141 session window with green CI on every push). Both flipped: q22-upstream-repro.md🗄️ SUPERSEDED (iteration 146) — never executed; not pursued with original DRAFT wording preserved in an "Original status (iteration 102, preserved for archeology)" block; q22-playwright-ct.md✅ FULLY COMPLETE (Q22 → Q28 saga closed, iteration 124) with explicit per-follow-up enumeration (#1 ✅ iter 108, #2 SUPERSEDED iter 110, #3 ✅ iter 121). Drift class generalization: both miss-targets share a common shape — Status: lines that are inside > blockquotes and use **bold** markdown wrappers around the state token. The iter-145 codified regex ^Status:.*PLANNED|SPECIFIED|DRAFT requires line-start Status: but the actual lines start with > Status:. Iter-145's verification claim "all 13 matches reflect ✅-prefixed states" used the iter-144-pattern (grep -n "Status:"), not the iter-145-codified ^Status:.* regex — and the human-spot-check pass missed two. Recommended fix for iter-N+1: tighten the Status/state drift greps with grep -rEn "^>?\\s*\\*?\\*?Status:\\s+\\*?\\*?[^✅]" docs/plans/ .specify/features/. Pattern progression confirmed for the 10th iteration in a row (iter-132 → iter-146). Verification: pnpm typecheck 23/23 FULL TURBO + pnpm lint 18/18 FULL TURBO (100% cache hits — doc-only changes don't invalidate any task input). No source / test / config / dep / lockfile changes. Q22 → Q28 saga remains fully closed; @ever-works/ui at branches 100% (233/233); pnpm lint 0 warnings 0 errors; CT-flake watch ✅ CLOSED. Project enters its 17th consecutive "no carried open work" steady-state iteration (iter 130-146). Iteration 145 history below.)

Iteration 145 (history): codify iter-144 Next Step #1 — add new ## Doc-Quality Audit Checklist section to AGENTS.md institutionalizing the grep-pattern playbook from iters 132 → 144. Meta-iteration. Iter-144's Next Step #1 read "Add grep -n "Status:" docs/plans/q*.md .specify/features/q*.md to the standard audit checklist" — but that "standard audit checklist" was institutional knowledge captured across log entries (iters 132 / 135 / 137 / 138 / 139 / 140 / 141 / 142 / 143 / 144), not durably documented anywhere a future autonomous iteration would discover without log archaeology. Iter-145 closes this by inserting a 70-line ## Doc-Quality Audit Checklist section into AGENTS.md (between ## Cross-Check Checklist and ## Skills for AI Agents) consolidating the playbook into three pattern groups: Value drift (43 cases\|48 cases, All 28\|All 31, 22-package\|26-package, pnpm test\b, toolchain version regex), Status/state drift (Status: in docs/plans/q*.md + .specify/features/q*.md, Fully static\|fully static\|no SSR, ^Status:.*PLANNED\|SPECIFIED\|DRAFT), Structural/link drift (\](\\.\\./ for broken relative markdown links, type: doc for sidebar topology, ^- for bullet placement). Plus a rerun-cadence table (Value drift → after code/test/dep changes; Status/state drift → every doc-quality iteration; Structural/link drift → after docs additions or sidebar edits) and an explicit "add new patterns here when new drift classes surface" policy line. Net diff +70/-0 across one file. Why iter-145 and not earlier: iters 141 → 144 each closed a new drift class — codifying after iter-141 would have under-specified the checklist (no link-drift, no front-matter-status, no bullet-placement patterns). Iter-145 is the right cadence: close enough to iter-144 that context is fresh, far enough that iter-144's findings have settled. Pattern progression: 9 consecutive drift-sweep iterations (132 → 144) confirmed three recurring drift classes; iter-145 is the meta-iteration that promotes accumulated knowledge from change-log entries to a canonical, in-tree reference. Future iterations doing doc-quality work should now start from AGENTS.md § Doc-Quality Audit Checklist rather than re-reading log entries. Verification: pnpm typecheck 23/23 FULL TURBO (1.496s) + pnpm lint 18/18 FULL TURBO (1.384s) — 100% cache hits, AGENTS.md is not under typecheck/lint scope. No source / test / config / dep / lockfile changes. grep -n "Status:" docs/plans/q*.md .specify/features/q*.md re-run: all 13 matches reflect ✅-prefixed states (no PLANNED / SPECIFIED / DRAFT remaining), confirming iter-144's flips landed cleanly. Q22 → Q28 saga remains fully closed; @ever-works/ui at branches 100% (233/233); pnpm lint 0 warnings 0 errors; CT-flake watch ✅ CLOSED. Project enters its 16th consecutive "no carried open work" steady-state iteration (iter 130-145). Iteration 144 history below.)

Iteration 144 (history): spec/plan front-matter status flip — close 6 stale "PLANNED"/"SPECIFIED" entries (2 specs + 4 plans) where the corresponding question was already RESOLVED. Pure-doc iteration. Iter-138 spec inventory pass + iter-141 cross-repo grep audit + iter-142 .specify/ link audit covered the headline counts and link targets of the spec/plan surface but missed the front-matter status lines of individual plan/spec files. Iter-144's targeted grep grep -n "Status:" docs/plans/q*.md .specify/features/q*.md surfaced 6 stale entries: .specify/features/q22-mobilemenu-ct.md (SPECIFIED iter 108, latency 36 iters; Q22 follow-up #1 was ✅ COMPLETE iter 108), .specify/features/q24-layoutswitcher-empty-modes.md (SPECIFIED iter 109, latency 35 iters; Q24 was ✅ RESOLVED iter 109), docs/plans/q22-mobilemenu-ct.md (PLANNED iter 108, latency 36 iters), docs/plans/q22-playwright-coverage.md (PLANNED iter 110 + Q25-validated iter 112, latency 23 iters; Q22 follow-up #3 was ✅ COMPLETE iter 121), docs/plans/q24-layoutswitcher-empty-modes.md (PLANNED iter 109, latency 35 iters), docs/plans/q27-mobilemenu-empty-items-coverage.md (PLANNED iter 123, latency 20 iters; Q27 was ✅ RESOLVED iter 124). All 6 flipped to ✅ COMPLETE / ✅ RESOLVED / ✅ DONE with execution recap and Status flip belatedly landed iter 144. annotations. Drift class: front-matter status lines sit at the top of plan/spec files, separate from the body edits (Outcome subsections / Decisions tables / acceptance-criteria checkmarks) that resolve the question. The execution iteration typically updates the body and the change-log entry but does NOT touch the front-matter line unless explicitly reminded. The two specs that WERE updated (q22-playwright-coverage iter 121 + q27 iter 124) had their spec front-matter flipped by their respective execution iterations, but the corresponding plan front-matters AND the two other spec front-matters (q22-mobilemenu-ct + q24) were missed. Pattern progression confirmed for the 9th iteration in a row (iter-132 → iter-144). New audit-checklist entry: grep -n "Status:" docs/plans/q*.md .specify/features/q*.md should run on every doc-quality iteration. Verified clean (no front-matter drift): q22-playwright-ct, q22-upstream-repro, q28-eslint-10-upgrade plans + q22-playwright-ct, q22-playwright-coverage, q27, q28 specs (all already current per their respective execution iterations). Routine dep audit deferred this iteration (iter-140 + iter-143 zero deltas, inheritance consistent). Verification: pnpm typecheck 23/23 + pnpm lint 18/18 expected at commit time. No source / test / config / dep / lockfile changes. Q22 → Q28 saga remains fully closed; @ever-works/ui at branches 100% (233/233); pnpm lint 0 warnings 0 errors; CT-flake watch ✅ CLOSED. Project enters its 15th consecutive "no carried open work" steady-state iteration (iter 130-144). Iteration 143 history below.)

Iteration 143 (history): AGENTS.md R14/R15 bullet placement fix — relocate "Prefer conventions that reduce boilerplate" from R15 (Specification First) to R14 (Convention Over Configuration); 9-guide docs/guides/ audit verified clean; routine 10-package dep quick-check zero deltas. Pure-doc iteration executing iter-142's Next Step #1 (audit remaining surfaces: AGENTS.md R12-R14 + 9 unaudited guides). One real drift found in AGENTS.md: line 105 "- Prefer conventions that reduce boilerplate" appeared as the 7th bullet under R15 (Specification First) — semantically incongruous because that rule is about specs/docs/architecture/questions/PR-cross-checks, not conventions/defaults/boilerplate-reduction. The bullet semantically belongs to R14 (Convention Over Configuration), which had only 2 bullets ("Good defaults for everything" + "Users can override via config when needed"). Likely root cause: a copy-paste / refactor-time accident when R15 was inserted between R14 and what later became "Working Process" (the bullet got reattached to the wrong rule heading). Fixed by moving the bullet into R14's bullet list (as the 3rd bullet) and removing it from R15's. Net diff +1/-1, single line move. 9-guide docs/guides/ audit verified clean (no drift in the iter-132/etc. drift class): targeted greps for 1170|1165|1122|43 cases|48 cases|All 28|All 31|22-package|26-package|Fully static|fully static|no SSR|output.*static and Astro 6\\.[0-9]|Vitest 4\\.[0-9]|Tailwind 4\\.[0-9]|Preact 10\\.[0-9]|TypeScript [56]\\.[0-9]|Node 2[0-4]|@astrojs/vercel|isomorphic-git and @ever-works/[a-z-]+ and sample-(basic|jobs|events|real-estate|git) returned only matches in proper context. The "fully static" matches in getting-started.md:1162, content-sync.md:92, deployment.md:129/142 are all correctly scoped to ENABLE_ISR=false discussions. The isomorphic-git matches in troubleshooting.md:229/231/238/244 are about externalizing it from Vite SSR bundling — current and correct. The @ever-works/web-minimal references (3 files, 11 occurrences) all match apps/web/package.json "name": "@ever-works/web-minimal". The apps/sample-basic/src/components/ItemBrowser.tsx and apps/sample-basic/src/styles/global.css references in interactive-components.md resolve to existing files. The DataAdapter and AdapterConfig types referenced in creating-an-adapter.md exist at packages/adapters/src/types.ts:13 and :79. Routine 10-package dep quick-check (zero deltas): astro 6.1.9, vitest 4.1.5, @playwright/test 1.59.1, tailwindcss 4.2.4, preact 10.29.1, typescript 6.0.3, eslint 10.2.1, isomorphic-git 1.37.6, turbo 2.9.6, prettier 3.8.3 — all pinned versions match npm latest (verified ~3h after iter-142's 22-package subset audit). 16-package gap to documented 26-package matrix unlikely to have moved at this interval; full re-verification deferred. Iter-142 collision note: an earlier scheduled run committed iter-142 (commit 226e4c0 at 18:16:48 UTC, "complete cross-repo .specify/ link audit") in parallel with the current session's first 90 minutes of work. The earlier run independently found and fixed the same 5 broken ../../.specify/features/*.md markdown links in the Q-track plan files that the current session would have fixed. Current session's edits matched the parallel run's edits exactly (working tree was clean after both completed); current session pivoted to iter-143 to avoid duplicate commits. The collision is itself a useful signal: in fully-autonomous parallel-scheduled runs against a low-churn doc-only workstream, two cron ticks can independently land on the same fix. Future iterations should git pull (or check git log head) at session start to avoid the collision-pivot cost. Pattern progression confirmed for the 9th iteration in a row (iter-132 → iter-143). Verification: pnpm typecheck 23/23 FULL TURBO (1.431s) + pnpm lint 18/18 FULL TURBO (1.403s) — 100% cache hits, AGENTS.md edit doesn't invalidate any task input (AGENTS.md is not under typecheck/lint scope). No source / test / config / dep / lockfile changes. Q22 → Q28 saga remains fully closed; @ever-works/ui at branches 100% (233/233); pnpm lint 0 warnings 0 errors; CT-flake watch ✅ CLOSED. Project enters its 14th consecutive "no carried open work" steady-state iteration (iter 130-143). Iteration 142 history below.)

Iteration 142 (history): complete the cross-repo .specify/ link audit — 5 Q-track plan files flipped from broken relative paths to absolute GitHub URLs. Iter-141 closed two drifts in apps/docs/; the five Q-track plan files (docs/plans/q22-mobilemenu-ct.md / q22-playwright-ct.md / q24-layoutswitcher-empty-modes.md / q27-mobilemenu-empty-items-coverage.md / q28-eslint-10-upgrade.md) retained one consistent piece of latent drift: their front-matter Spec: link still pointed at ../../.specify/features/<name>.md. That relative path resolves correctly when reading the plan in the source tree (editor / GitHub renderer follows directory levels) but breaks on the published Docusaurus site because .specify/ is excluded from the Docusaurus content tree (the directory lives at the repository root, not under docs/, and Docusaurus only serves docs/-rooted content). Iter-142 closes the loop with five 1-line edits substituting each relative path with the absolute GitHub URL convention already in use across docs/index.md Spec Kit section (since iter 102) — net diff +5/-5 across 5 files; one fix per file. Pre-iter-142 grep state: grep -rEn "\(\.\./\.\./\.specify/|\(\.\./\.specify/" docs/ returned 5 hits; post-iter-142: 0 hits — the cross-repo .specify/ relative-link convention is now consistent across all of docs/. Pattern progression confirmed for the 8th iteration in a row (iter-132 / 135 / 136 / 137 / 138 / 139 / 140 / 141 / 142). This is now the longest sustained doc-audit-only run in the saga's history — 11 consecutive iterations since iter-132 (with 133/134 inserting health-audit re-runs). In steady-state ("no carried open work") iterations, doc-quality micro-audits are the canonical productive use of an autonomous cron tick. Verification: pnpm typecheck 23/23 FULL TURBO + pnpm lint 18/18 FULL TURBO (100% cache hits — doc-only changes don't invalidate any task input). No source / test / config / dep / lockfile changes. Q22 → Q28 saga remains fully closed; @ever-works/ui at branches 100% (233/233); pnpm lint 0 warnings 0 errors; CT-flake watch ✅ CLOSED. Project enters its 13th consecutive "no carried open work" steady-state iteration (iter 130-142). Iteration 141 history below.)

Iteration 141 (history): continue cross-repo grep audit — close 2 drifts in apps/docs/ (Docusaurus blog post pre-iter-17 wording + sidebar topology missing 1 architecture page + 7 Q-track plans). Pure-doc iteration executing iter-140's Next Step #1. Two real drifts found, two surfaces verified clean: (1) apps/docs/blog/2026-04-11-welcome.md line 21 still said "Static-first — Astro 6 with fully static output, no SSR" — same pre-iter-17/Q17 drift class iter-135 fixed in deployment.md but missed because the blog lives under apps/docs/blog/ not docs/. Latency ~123 iterations (iter-17 → iter-141), longest single drift latency yet recorded in the audit history. Flipped to "Static-first with optional ISR — Astro 6 with output: 'static' + @astrojs/vercel ISR adapter by default; opt out with ENABLE_ISR=false for pure static output". (2) apps/docs/sidebarsTemplate.ts (the active Docusaurus sidebar topology, consumed by docusaurus.config.ts:43 sidebarPath: './sidebarsTemplate.ts' + rendered at :124 sidebarId: 'templateSidebar') was missing 1 architecture page (architecture/testing-runners.md — added iter-105 Q22, ~36 iterations latency) and 7 Q-track plans (q22-playwright-ct.md, q22-mobilemenu-ct.md, q22-upstream-repro.md, q22-playwright-coverage.md, q24-layoutswitcher-empty-modes.md, q27-mobilemenu-empty-items-coverage.md, q28-eslint-10-upgrade.md). Net result: the deployed Docusaurus site at apps/docs/ was missing 8 navigable doc pages from its left-rail sidebar despite all 8 being canonically catalogued in docs/index.md. Both blocks expanded with the missing entries in alphabetical order. Verified clean (zero drift): docs/guides/content-sync.md (full-file read confirmed iter-140 spot-check — the only "fully static" reference is correctly scoped inside ## Static Mode for ENABLE_ISR=false); .github/workflows/*.yml (targeted grep returned zero matches across ci.yml / deploy.yml / lighthouse.yml). Pattern progression confirmed for the 8th iteration in a row (iter-132 → iter-141). The Q22→Q28 saga authored its plans/specs in docs/plans/ and .specify/features/ and updated docs/index.md "Plans" section accordingly — but never updated the Docusaurus sidebar topology, so the navigable doc-site experience drifted further from the canonical doc index with each Q-track plan added. Verification: pnpm typecheck 23/23 + pnpm lint 18/18 expected at commit time. No source / test / config / dep / lockfile changes. Q22 → Q28 saga remains fully closed; @ever-works/ui at branches 100% (233/233); pnpm lint 0 warnings 0 errors; CT-flake watch ✅ CLOSED. Project enters its 12th consecutive "no carried open work" steady-state iteration (iter 130-141). Iteration 140 history below.)

Iteration 140 (history): extend iter-139 conflated-pnpm test audit to spec/plan surfaces — fix 2 occurrences in .specify/features/q28-eslint-10-upgrade.md AC #5 + docs/plans/q28-eslint-10-upgrade.md Step 4; routine dep audit zero deltas across 22 packages. Pure-doc iteration executing iter-139's Next Step #1 (extend audit to remaining surfaces). Two real drift instances found, both inherited from the same iter-129 Q28-spec authoring pass which predates the iter-132 CLAUDE.md split / iter-139 README.md split: (1) .specify/features/q28-eslint-10-upgrade.md AC #5 line 83 claimed pnpm test reports the full 1170-test suite passing; (2) docs/plans/q28-eslint-10-upgrade.md Step 4 line 135 inline comment said pnpm test # full 1170-test suite green expected (1122 Vitest + 48 CT). Both fixes follow the iter-139 minimal-split pattern: Vitest count stays canonical (1122), CT count moves to its own clarifying clause naming pnpm test:ct as the separate runner, and AC #6 cross-reference (ESLint is static-analysis only, CT skip intentional) is inlined so a reader doesn't have to chase the rationale across files. Verified clean (zero drift) across 9 unaudited guides, AGENTS.md, apps/docs/src/ Docusaurus content, docs/architecture/, docs/specs/, docs/overview.md. False positive resolved: docs/guides/content-sync.md line 92 ("the site is fully static — no server functions run at runtime") looks like the iter-135 deployment.md drift but is actually correct in context — the line is inside the ## Static Mode section describing ENABLE_ISR=false, where indeed no Vercel server functions are deployed. Routine dep audit (zero deltas, 22-package subset re-verified): every dep at the same latest version as iter-138 / iter-139 baseline (Astro 6.1.9, Vitest 4.1.5, Playwright 1.59.1, Tailwind 4.2.4, Preact 10.29.1, monocart-coverage-reports 2.12.11, monocart-reporter 2.10.1, vitest-monocart-coverage 4.0.2, isomorphic-git 1.37.6, eslint 10.2.1, TypeScript 6.0.3, Prettier 3.8.3, Turbo 2.9.6, marked 18.0.2, yaml 2.8.3, pagefind 1.5.2, @playwright/experimental-ct-react 1.59.1, plus 5 @astrojs/* and @typescript-eslint). Pattern progression confirmed for the 7th iteration in a row (iter-132 CLAUDE.md / iter-135 deployment.md / iter-136 quickstart+getting-started / iter-137 package matrix / iter-138 spec count / iter-139 README.md / iter-140 q28 plan+spec): a single drift class (the conflated-pnpm test=1170 row) propagated to 5 different surfaces between iter 105 (CT split introduced) and iter 129 (Q28 plan/spec authored), and required 3 separate audit iterations to fully purge. Generalization for future iterations: when fixing a stale claim in surface X, immediately run grep -rn "<the-stale-string>" --include="*.md" . across the whole repo before considering the fix complete; otherwise the drift class survives in surfaces that don't get audited until iteration N+M. Verification: pnpm typecheck 23/23 FULL TURBO (1.359s) + pnpm lint 18/18 FULL TURBO (1.448s) — 100% cache hits, doc-only changes don't invalidate any task input. No source / test / config / dep / lockfile changes. Q22 → Q28 saga remains fully closed; @ever-works/ui at branches 100% (233/233); pnpm lint 0 warnings 0 errors; CT-flake watch ✅ CLOSED. Project enters its 11th consecutive "no carried open work" steady-state iteration (iter 130-140). Iteration 139 history below.)

Iteration 139 (history): README.md Common Commands refresh — split conflated pnpm test row, add missing pnpm test:ct / pnpm test:ct:install / pnpm coverage rows. Pure-doc iteration extending the iter-132/135/136/137/138 audit pattern to README.md — the first reader-facing surface anyone reaching the repo sees. Pre-iter-139 state had two distinct issues: (1) pnpm test row claimed Run all unit tests — 1170+ tests, 76 test files, 16 suites (1122 Vitest + 48 Playwright CT), but post-iter-132 reality is that pnpm test runs Vitest only (1122/73/16); turbo's test task does NOT chain to test:ct, so a reader copying the README's claim would incorrectly believe pnpm test exercises the full 1170-test surface and miss the Q22/Q23/Q24/Q27 CT-migrated coverage; (2) missing rows for pnpm test:ct (added iter 105), pnpm test:ct:install (added iter 105), pnpm coverage (added iter 116) — same omissions iter-136 caught in the two docs/guides/ Common Commands tables. Both fixed: pnpm test row split to 1122 tests, 73 test files, 16 suites; 3 new rows added with the CT surface named (16 FilterBar + 12 LayoutSwitcher + 20 MobileMenu) and the iter-124 100%/100%/99.76% gate-green numbers inlined on pnpm coverage. 1-line cross-reference to CLAUDE.md for the canonical exhaustive list (with defensive pnpm test:ui:safe intentionally omitted from the README — diagnostic-only escape hatch). Pattern progression confirmed for the sixth iteration in a row (iter-132 CLAUDE.md / iter-135 deployment.md / iter-136 quickstart+getting-started / iter-137 package matrix / iter-138 spec count / iter-139 README.md): command/env-var/feature additions to the toolchain do not auto-propagate to all reader-facing surfaces; doc-quality audits remain the canonical recurring background task in steady-state iterations. Verification: pnpm typecheck 23/23 FULL TURBO + pnpm lint 18/18 FULL TURBO (100% cache hits — README change does not invalidate any task input). No source / test / config / dep / lockfile changes. Q22 → Q28 saga remains fully closed; @ever-works/ui at branches 100% (233/233); pnpm lint 0 warnings 0 errors; CT-flake watch ✅ CLOSED. Project enters its 10th consecutive "no carried open work" steady-state iteration (iter 130-139). Iteration 138 history below.)

Iteration 138 (history): spec inventory pass — flip stale All 28 .specify/ feature specs claim in .specify/project.md to All 31 with explicit wc -l provenance and Q23/Q25/Q26-absorbed-inline footnote. Pure-doc iteration. Iter-137 noted .specify/features/ directory contains 31 .md files but .specify/project.md line 87 claimed "All 28" — and deferred the per-file accounting because the 3-spec gap could be drift or intentional exclusion. Iter 138 executes the bounded spec-inventory iteration: there is no excluded-debug-spec / superseded-spec category. The drift is a clean off-by-3 baseline-vs-final accounting error — the iter-129 project.md edit explicitly listed the 3 saga-additions by name (q22-mobilemenu-ct.md iter 108, q27-mobilemenu-empty-items-coverage.md iter 123, q28-eslint-10-upgrade.md iter 129) but never summed them into the headline count. The actual count has been 31 since iter 129. Q23 / Q25 / Q26 do not have dedicated spec files in .specify/features/ — those questions were resolved inline in docs/questions.md (Q23 + Q25 absorbed into Q22 follow-up arcs; Q26 absorbed into the Q22-follow-up-#3 spec at q22-playwright-coverage.md). This is a deliberate per-saga-arc spec consolidation: the Q22 family's three follow-ups each have their own spec, but the side-quest questions (Q23/Q25/Q26) get folded into the parent's spec rather than fragmenting the spec surface. Pattern now confirmed FIVE times (iter-132 CLAUDE.md CT count → iter-135 deployment.md ISR docs → iter-136 quickstart + getting-started Common Commands → iter-137 project.md package matrix → iter-138 project.md spec count). Future iterations should pre-emptively run the standard greps before assuming "no drift": grep -rn "<old-number>" CLAUDE.md AGENTS.md README.md docs/architecture/ docs/specs/ docs/guides/ .specify/ for count drift; grep -nE "pnpm test|pnpm coverage|pnpm test:ct|pnpm dev:" docs/guides/ for Common Commands drift; ls .specify/features/*.md | wc -l vs grep "All [0-9]+ .specify" .specify/project.md for spec-count drift. No source / test / config / dep / lockfile changes. No pnpm install. No pnpm coverage re-run (iter-133 100%-aggregate numbers stay authoritative). pnpm lint baseline 18/18 + 0 warnings + 0 errors (iter 131) carries forward unchanged. Project enters its 9th consecutive "no carried open work" steady-state iteration. Iteration 137 history below.)

Iteration 137 (history): continued doc-quality audit — flip stale 22-package matrix claim in .specify/project.md to 26-package matrix (post iter-132/133 expansion). Iteration 136 completed the docs/guides/ Common Commands audit and recommended extending the audit to remaining surfaces, including "Any references to specific iteration numbers / counts (e.g. '16 packages') that may have drifted post-saga." Iteration 137 executes that follow-up. One real drift found: .specify/project.md line 94 still describes the dep-audit surface as "The 22-package matrix" — the iter-130 baseline number that iter-132 expanded to 23 (added the [email protected] caret-resolution row) and iter-133 expanded to 26 (added [email protected], [email protected], [email protected], @playwright/[email protected] for completeness). The standing pnpm coverage "100% branches (233/233)" claim is unchanged; the matrix-count claim is what drifted. The iter-132/133/135 dep audits all updated docs/log.md and docs/index.md (the iteration descriptors) but none of those iterations updated the Current State block in .specify/project.md — exactly the pattern called out in iter-136's "Generalization": command/env-var/feature additions to the toolchain do not auto-propagate to all reader-facing surfaces; targeted greps catch latency at iteration N+1, not at iteration N. The audit confirms this pattern a fourth time (iter-132 CLAUDE.md CT count → iter-135 deployment.md ISR docs → iter-136 quickstart + getting-started Common Commands → iter-137 project.md package matrix). The iter-137 fix flips line 94's text from "matrix re-verified iter 123 / 125 / 126 / 127 / 128 / 130. The 22-package matrix is now zero-delta with no carried open work for the first time across the entire iteration history" to "matrix re-verified iter 123 / 125 / 126 / 127 / 128 / 130 / 132 / 133 / 135 (matrix expanded iter 132: 22 → 23 ... iter 133: 23 → 26 ... iter 135: 9-package quick-check subset). The 26-package matrix is now zero-delta with no carried open work", removing the now-anachronistic "for the first time" superlative (true at iter-130; the steady state is now the carried-baseline at iter-137). Verified zero drift in: apps/docs/src/{components,pages} (Docusaurus React UI, no hardcoded counts; reads docs/ content via path: '../../docs/'); docs/guides/{analytics,content-sync,creating-an-adapter,customizing,interactive-components}.md (narrative-only guides, no Common Commands tables); docs/guides/{building-from-template,creating-a-plugin,performance-testing,troubleshooting}.md (only narrative pnpm mentions in proper context, not Common Commands tables); CLAUDE.md / AGENTS.md / README.md / SKILLS.md (carry forward from iter-136 baseline). Verification: pnpm typecheck 23/23 FULL TURBO + pnpm lint 18/18 FULL TURBO expected (both 100% cache hits — doc-only changes don't invalidate any task input). No source / test / config / dep / lockfile changes. Q22 → Q28 saga remains fully closed; @ever-works/ui at branches 100% (233/233); pnpm lint 0 warnings 0 errors; CT-flake watch ✅ CLOSED. Project enters its 8th consecutive "no carried open work" steady-state iteration. Iteration 136 history below.)

Iteration 136 (history): continued docs/guides/ audit — refresh stale Common Commands tables in quickstart.md and getting-started.md. Iteration 135 surfaced the iter-17/Q17 ISR-doc gap in docs/guides/deployment.md and recommended extending the iter-132 grep set to docs/guides/. This iteration follows that recommendation: a targeted grep for pnpm test|pnpm coverage|pnpm test:ct|pnpm dev: across all 12 guides surfaced two more stale Common Commands tables. Both predate the post-Q22 toolchain additions: quickstart.md (~Apr 12, before iter 17) was missing 6 commands (pnpm test, pnpm test:coverage, pnpm test:ct, pnpm coverage, pnpm format, pnpm dev:docs); getting-started.md "Common Commands Reference" (~Apr 12) was missing 5 (had pnpm test/pnpm test:e2e but missed the rest). Both tables now refreshed with cross-references pointing at CLAUDE.md for the canonical and exhaustive list (which includes the defensive pnpm test:ui:safe per-file Vitest fallback intentionally omitted from the guides — it's a diagnostic-only escape hatch). Pattern confirmed three times (iter-132 CLAUDE.md, iter-135 deployment.md, iter-136 quickstart + getting-started): command/env-var/feature additions to the toolchain do not auto-propagate to all reader-facing surfaces; targeted greps catch latency at iteration N+1, not at iteration N. Doc-quality audits should be a recurring background task. Verification: pnpm typecheck 23/23 FULL TURBO + pnpm lint 18/18 FULL TURBO (both 100% cache hits — doc-only changes don't invalidate any task input). No source / test / config / dep / lockfile changes. Q22 → Q28 saga remains fully closed; @ever-works/ui at branches 100% (233/233); pnpm lint 0 warnings 0 errors; CT-flake watch ✅ CLOSED. Project entered its 7th consecutive "no carried open work" steady-state iteration. Iteration 135 history below.)

Iteration 135 (history): doc-quality audit on docs/guides/ — close the ISR documentation gap in deployment.md (predates iter-17/Q17). Pure-doc iteration. Iteration 134 completed the third "post-saga health-check" verification (build pipeline); iter-135 broadens the maintenance scope from spec/plan/log surfaces to user-facing docs/guides/. One real documentation gap found: docs/guides/deployment.md predates iteration 17's Q17 ("ISR by Default, Static Opt-Out") update and never picked up the ISR-specific environment variables, the ISR/pure-static mode choice, or the ISR webhook flow. Pre-iter-135 wording said "the template produces fully static output, no server functions" (correct only in pure-static mode; ISR mode ships a /api/webhook Vercel function) and "to update content, trigger a new build" (correct only in pure-static mode; ISR regenerates affected pages on-demand). 5 spot edits flip the misleading wording, add ENABLE_ISR to the env-var table with cross-ref to content-sync.md for the full 8 ISR/sync env vars (WEBHOOK_SECRET, SYNC_POLL_INTERVAL_MS, SYNC_TIMEOUT_MS, SYNC_MAX_RETRIES, CONTENT_CACHE_TTL_MS, VERCEL_DEPLOY_HOOK_URL, CONTENT_PATH), add an "Output mode (ISR vs pure-static)" 2-row decision table to "Build Details", and prepend ENABLE_ISR=false to the Netlify + Cloudflare Pages build commands (since those static hosts cannot serve the ISR adapter's Vercel function). The gap had been latent since iter-17 (~117 iterations / ~5 weeks ago in this saga's compressed timeline) — every subsequent doc-touching iteration preserved the pre-iter-17 wording verbatim. Generalization of the iter-132 "iter-125 sweep missed CLAUDE.md" pattern: doc surfaces that are not mentioned in a feature's primary spec/plan often miss the corresponding update. The recommendation extends the iter-132 grep set to include docs/guides/ (~3,668 lines across 12 files). Routine dep audit (zero deltas, 9-package quick-check): every dep at the same latest version as iter 134 baseline (~1.5h prior). No source / test / config / package.json / lockfile changes. No pnpm install. No pnpm coverage re-run (iter-133 100%-aggregate numbers stay authoritative). pnpm lint baseline 18/18 + 0 warnings + 0 errors (iter 131) carries forward unchanged. Project enters its 6th consecutive "no carried open work" steady-state iteration. Iteration 134 history below.)

Iteration 134 (history): deferred build-pipeline health audit — full cold pnpm build succeeds across all 7 buildable turbo tasks in 13m 14s. Iteration 133 reproduced the iter-124 100%-branches authoritative pnpm coverage number under the post-Q28 toolchain; iter-134 extends the same end-to-end signal to the build pipeline. Cold pnpm build (all turbo caches invalidated by the dep churn since iter 92's last full-build verification) completes successfully across all 7 turbo build tasks (web + sample-basic + sample-jobs + sample-events + sample-real-estate + sample-git + docs): Tasks: 7 successful, 7 total / Cached: 0 cached, 7 total / Time: 13m14.66s. The heaviest single app remains sample-git (3264-item time-tracking-tools directory): 5030 pages built in 745.01s (~12m 25s), with every plugin firing correctly — [plugin:sort] 3264 items, [plugin:breadcrumbs] 4753 pages, [plugin:related-items] 13056 links across 3264 items, [plugin:search] Pagefind indexing complete, [@astrojs/sitemap] sitemap-index.xml created, [@astrojs/vercel] static-output copy succeeded. Why this matters: until iter-134 the most recent end-to-end build verification in the change log was iteration 92 (Astro / Vite / Preact / Tailwind major-version churn); six iterations of dep churn since then (iter 97 / 99 / 108 / 128 / 130 / 131) had accumulated without an explicit build re-check. The iter-130 ESLint 10 upgrade and iter-128 [email protected] patch are now confirmed build-invariant — exactly the prediction made by their respective specs (ESLint is static-analysis only; isomorphic-git is content-sync-time, not build-time, on the static-output adapter path used by all 7 buildable apps). Verification-only iteration; no source / test / config / dep / lockfile changes. Q22 → Q28 saga remains fully closed; @ever-works/ui at branches 100% (233/233); pnpm lint 0 warnings 0 errors (iter 131); CT-flake watch ✅ CLOSED at iter 127. Project enters its 5th consecutive "no carried open work" steady-state iteration. Iteration 133 history below.)

Iteration 133 (history): deferred health audit re-run — pnpm coverage end-to-end clean; 100% branches reproducible (233/233); 26-package dep matrix zero deltas. Iter 132's "Next Steps" listed three follow-ups; #1 (routine dep audit) and #3 (doc drift sweep) were already executed by iter 132 itself, leaving #2 (pnpm coverage health audit re-run after iter-128 + iter-130 dep churn) as the only carried action item. Iter 133 executes that. The iter-124 100%-branches authoritative number reproduces exactly under the post-Q28 (ESLint 10) + post-iter-128 ([email protected]) toolchain: branches 100% (233/233) ✅ identical, functions 100% (104/104) ✅ identical, lines 99.76% (1240/1243) ✅ identical, statements 99.72% (352/353) ✅ identical, files 19 ✅ identical. Per-file gate: FilterBar.tsx 100% (27/27) ✅, LayoutSwitcher.tsx 100% (22/22) ✅, MobileMenu.tsx 100% (35/35) ✅ — all bit-for-bit reproduced; the iter-121 process.exit(1) hard-gate would have fired if any file dropped below 80%; it did not. The only delta is a non-material bytes-denominator drift: 99.79% (45,558/45,650) → 99.76% (45,667/45,775) — +125 total bytes / +16 uncovered bytes / -0.03 pp. Likely cause: iter-128 isomorphic-git patch + iter-130 ESLint 10 transitive deps re-emitted the Vite/Preact bundle with marginally different chunk boundaries (V8 byte ranges count emitted-bundle bytes, not source bytes — bundle re-chunking shifts the denominator; source-mapped logical metrics are invariant). Well clear of any gate threshold. CT-flake watch counter advanced 3/3 → 4/4 with iter 133's clean 48/48 / 0 retries / 0 flaky / 1m 21s run — the iter-111 single-occurrence filter-bar.ct › selects category on click flake has now not recurred across four consecutive full-suite runs (iters 126, 127, 133, plus iter 124's mobile-menu-only partial). Vitest re-verified: @ever-works/ui 174/174 / 11 files / 93.46s; full pnpm test 16/16 packages / 1122/1122 in 2m 20s. Routine dep audit: 26-package matrix re-verified (~1.5h after iter 132; expanded by 3 to add [email protected], [email protected], [email protected], @playwright/[email protected] for completeness) — every dep at latest. Verification: pnpm typecheck 23/23 FULL TURBO (1.7s, all cache hits), pnpm lint 18/18 FULL TURBO (1.2s, all cache hits, 0 warnings + 0 errors), pnpm coverage end-to-end ~3 min walltime. No source / test / config / package.json / lockfile changes (iter 132's commit 9588469 remains the head of code state). Process note added to "Next Steps": iter 133's bytes-denominator drift establishes the precedent — logical metrics (branches/statements/functions/lines) are stable across patch+minor dep churn, but future material dep churn (any non-patch bump in Astro / Vite / Vitest / Playwright / Preact / Tailwind / monocart / vitest-monocart-coverage / isomorphic-git / TypeScript / ESLint) should re-run pnpm coverage to verify the 100%-branches signal still reproduces. Iteration 132 history below.)

Iteration 132 (history): doc drift sweep — flip stale CT count in CLAUDE.md (43 cases48 cases); routine dep audit zero deltas across 23-package matrix. Pure-doc iteration. Iter-131's "Next Steps" listed "Doc drift sweep — verify the iter-130 ESLint matrix line in .specify/project.md reflects the post-bump state; check CLAUDE.md Common Commands for any stale pnpm references" as a recommended next-step. Iter 132 executes that sweep. One stale claim found: CLAUDE.md line 122 still described pnpm test:ct as (43 cases for FilterBar/LayoutSwitcher/MobileMenu, ~1.3 min on Windows + Node 24) — the same iter-105/iter-108-baseline 43 cases count that iter-125's health-check pass missed in this surface (iter 125 swept .specify/project.md / .specify/features/{q22-playwright-coverage,testing}.md / docs/architecture/testing-runners.md / README.md and brought them current to 48 cases / 1170 total, but did not touch CLAUDE.md). Iter 132 flips to (48 cases for FilterBar/LayoutSwitcher/MobileMenu — 16 + 12 + 20; iter-127 walltime ~1.5 min on Windows + Node 24 + Chromium 147; 0 retries / 0 flaky) — count reflects iter-124 Q27's MobileMenu CT growth from 17 → 20, walltime reflects iter-127's measured second-run-clean baseline (1m 39s), Chromium version + flake signal added so a future reader knows this number reflects post-CT-flake-watch-closed state. Routine dep audit (zero deltas, 23-package matrix re-verified ~3.5h after iter 131): every dep at the same latest version including [email protected] (caret-resolved from ^10.0.0). The "no carried open work" steady state from iter 130 holds. No source / test / config / package.json / lockfile changes. No pnpm install. No pnpm coverage re-run (iter-124 100%-aggregate merged numbers stay authoritative). pnpm lint baseline 18/18 + 0 warnings + 0 errors (iter 131) carries forward unchanged. Iteration 131 history below.)

Iteration 131 (history): closed 4 lingering no-console lint warnings in logger.ts files via inline ESLint disable comments — pnpm lint now reports 0 warnings + 0 errors for the first time. Iteration 130 (Q28 ESLint 10 upgrade) noted the 4 pre-existing warnings in packages/core/src/logger.ts:40,53 + packages/plugins/src/logger.ts:22,35 carry forward unchanged from iter-128 baseline. With the project at "no carried open work" steady state, this iteration closes them. The warnings flag console.log(...) calls inside info() / debug() methods of two logger factory functions — the entire purpose of those methods is to emit log lines, so console.log is correct API and the right fix is inline eslint-disable-next-line no-console comments with explicit -- info-level/debug-level logger output is the entire purpose of this method justifications (not rewriting to console.warn, which would mis-tag info/debug as warnings in the JS console). 4 added comment lines / 0 deleted; no logic / API / signature change. Verification: pnpm lint 18/18 / 0 warnings / 0 errors (down from 18/18 + 4 warnings at iter-130 baseline) in 43.2s, pnpm typecheck 23/23 in 1m54s, pnpm --filter @ever-works/core test 213/213 in 11.55s, pnpm --filter @ever-works/plugins test 86/86 in 5.10s. Significance: chronic warnings desensitize readers to new violations; closing the lingering 4 means the next no-console violation stands out cleanly against a 0-warning baseline. Q22 → Q28 saga remains fully closed; per-package merged coverage on @ever-works/ui continues to read branches 100% (233/233) (iter-124 numbers stay authoritative; this iteration did not touch any source under packages/ui/). Iteration 130 history below.)

Iteration 130 (history): Q28 ✅ RESOLVED — ESLint 9 → 10 in-place upgrade executed in a single autonomous cron tick. Iter-129's pre-investigation predicted a bounded 30-45 min single-iteration upgrade; iter-130 lands it in ~13 min walltime end-to-end. Step 1 (peer-range bump): one-line edit to packages/eslint-config/package.json peerDependencies.eslint ^9.0.0^10.0.0. Step 2 (pnpm install, ~92s): [email protected] → 10.2.1 resolved + 8 transitive bumps (@eslint/core 0.17.0 → 1.2.1, @eslint/config-array 0.21.2 → 0.23.5, @eslint/config-helpers 0.4.2 → 0.5.5, @eslint/object-schema 2.1.7 → 3.0.5, @eslint/plugin-kit 0.4.1 → 0.7.1, eslint-scope 8.4.0 → 9.1.2, espree 10.4.0 → 11.2.0, eslint-visitor-keys 4.2.1 → 5.0.1) + 3 legacy drops (@eslint/[email protected] — flat-config-only in v10; top-level @eslint/[email protected] and [email protected] — consolidated). Net lockfile churn: +14 / -19 packages, -38 lines. Step 3 (pnpm lint smoke, ~51s, 1 cached + 17 fresh): 18/18 successful, 0 errors, only the 4 pre-existing no-console warnings in packages/core/src/logger.ts:40,53 + packages/plugins/src/logger.ts:22,35 carry forward unchanged from iter-128 baseline — zero new ESLint 10 violations. Step 4 (verify): pnpm typecheck 23/23 in 2m12.8s (full fresh) + pnpm test 16/16 packages / 1122/1122 Vitest tests in 2m52.5s (full fresh). Optional engines.node >=22.12.0 → >=22.13.0 bump skipped per AC #6 (current floor covers ESLint 10's >=22.13.0 via semver caret resolution; CI runs Node 24 unconditionally). Optional pnpm test:ct (48 cases) and pnpm coverage (merged 100% aggregate) intentionally skipped — ESLint is purely static-analysis, cannot affect runtime; Vitest already exercises the workspace dep graph transitively. All 10 acceptance criteria from the spec satisfied. Step 6 (deferral-marker grep): grep -nE "ESLint.*9.*10|^9\.0\.0|eslint.*deferral" docs/log.md finds matches only in archived iteration entries (123/125/126/127/128/129) — iter-130 "Next Steps" carries no deferral marker. Saga state: every named question (Q22, Q23, Q24, Q25, Q26, Q27, Q28) reports ✅ RESOLVED; every dep matrix line matches latest; the merged pnpm coverage pipeline reports per-package branches 100% (233/233) with the iter-121 hard-fail gate enforced in CI. Project enters "no carried open work" steady state for the first time across the entire iteration history. 6 doc surfaces touched: docs/questions.md (Q28 status flip), .specify/features/q28-eslint-10-upgrade.md (front-matter flip), docs/plans/q28-eslint-10-upgrade.md (Status flip + ~250-line Outcome subsection), docs/log.md (this entry), docs/index.md (descriptor bump), .specify/project.md (Current State + ESLint matrix line + Q28 status). Iteration 129 history below.)

Iteration 129 (history): Q28 OPENED + spec + plan authored — ESLint 9 → 10 major-version upgrade pre-investigated; Q27 status flip in docs/questions.md (carry from iter-125 health-check sweep miss). Pure-documentation iteration. Three new doc surfaces created: (1) .specify/features/q28-eslint-10-upgrade.md (~210 lines) — full feature spec with 10 ACs, 5 risks, AGENTS.md R1-R15 cross-check, and a 17-row ESLint-10-changelog cross-check table that resolves every named breaking change to "no impact" against our actual source/config surface (flat config since project inception; Node v24 already in CI; @typescript-eslint@^8.59.0 peer-range covers ESLint 10; zero source usages of eslint-env / globalThis shadowing / removed deprecated APIs; rule list intentionally minimal — 6 rules + ignores — none affected by ESLint 10's schema strictening); (2) docs/plans/q28-eslint-10-upgrade.md (~190 lines) — 7-step execution plan: Step 0 re-verify pre-investigation / Step 1 bump peer-range (1-line edit) / Step 2 pnpm install / Step 3 pnpm lint smoke / Step 4 typecheck + test / Step 5 doc updates / Step 6 confirm deferral marker disappears / Step 7 rollback (only if 2-4 fail); sequencing puts total at 30-45 min single-iteration; (3) docs/questions.md Q28 entry (~110 lines) with default Option A (single-iteration in-place bump) + 5-iteration deferral history + 9-row pre-investigation findings list + Options A/B/C/D analysis (B/C/D rejected with reasons). Q27 status footer fix in docs/questions.md (~20 lines): the iter 125 health-check pass swept five other surfaces but missed the Q27 footer in docs/questions.md; iter 129 closes the gap by flipping OPEN — Option A.1 chosen [DEFAULT]✅ RESOLVED in iteration 124 — Option A.1 + Option A.3 combined with the final per-file MobileMenu (100% (35/35)) + per-package aggregate (100% (233/233)) numbers + a parenthetical note crediting iter 129 for the belated landing. Iteration 128 history below.)

Iteration 128 (history): picked up the iter-127 caret-range delta — [email protected] → 1.37.6 lockfile + packages/adapters/package.json pin bump. Iter-127 noted "the next pnpm install will pick it up automatically" — empirically wrong: pnpm's lockfile is sticky once resolved, so pnpm install reported "Lockfile is up to date" and left the lockfile at 1.37.5. Caret-range patch bumps require pnpm update <pkg> explicitly. This iteration runs pnpm update isomorphic-git --filter @ever-works/adapters to land the bump, then verifies via packages/adapters tests (4 files / 104/104 tests pass in 8.0s) — confirms [email protected] does not change any tracked behavior (file-tree walking, head-ref resolution, refresh path). pnpm typecheck 23/23 (1 cached + 22 fresh in 2m9s; lockfile change invalidated turbo cache) and pnpm lint 18/18 (1 cached + 17 fresh in 45.8s). The iteration-128 entry in docs/log.md includes a playbook correction for future routine audits: caret-range bumps require pnpm update <pkg> directly (not pnpm install); deferral notes should be honest about that distinction. Q22 → Q27 saga remains fully closed; per-package merged coverage on @ever-works/ui continues to read branches 100% (233/233) (iter-124 numbers stay authoritative; this iteration did not touch any source under packages/ui/); CT-flake watch ✅ CLOSED at iter 127 (3/3 clean). Iteration 127 history below.)

Iteration 127 (history): CT-flake watch ✅ CLOSED — counter 2/3 → 3/3 after a second consecutive clean full 48-case CT run; routine dep audit one delta inside caret range ([email protected] → 1.37.6). Pure-verification iteration. pnpm test:ct ran the full Playwright Component-Testing surface (16 FilterBar + 12 LayoutSwitcher + 20 MobileMenu) on Windows 10 + Node 24.14.0 + Chromium 147 + Playwright 1.59.1: 48 passed (1m 39s) / 0 failed / 0 flaky / 0 retries / 772 steps. CT-only V8 (identical to iter 126): bytes 100% (20,432/20,432), statements 100% (115/115), branches 98.81% (83/84 — the 1 uncovered branch remains the iter-124 /* v8 ignore next */-pragma'd defensive menuRef race-guard, dropped from the V8 denominator on the merged-Vitest+CT report where the aggregate reads 100%; expected and consistent with iter 124), functions 100% (40/40), lines 100% (495/495). The iter-111 single-occurrence filter-bar.ct › selects category on click retry has not recurred across two consecutive full-suite runs (iter 126 + iter 127) — the Playwright Component-Testing surface is now considered stable on the documented toolchain. Walltime 1m 25s → 1m 39s (+14s, ~16%) is well within Playwright cold-start variance on the same hardware/toolchain — no signal of regression (iter 127 ran cold; iter 126 ran ~3.5h earlier in the same session). Watch closes at iter 127 per the iter-125 plan: counter 2/3 → 3/3 ✅ CLOSED. Routine maintenance audit (one delta inside caret range): 22-package version matrix re-checked (~3.5h after iter 126) — single delta [email protected] → 1.37.6 (patch bump, caret-resolved at ^1.37.5 — no pnpm install needed; the next pnpm install will pick it up automatically). All other 21 packages identical to iter 126 (Astro 6.1.9, Vitest 4.1.5, Playwright 1.59.1, Tailwind 4.2.4, Preact 10.29.1, monocart-coverage-reports 2.12.11, monocart-reporter 2.10.1, vitest-monocart-coverage 4.0.2, @astrojs/{vercel 10.0.5, preact 5.1.2, sitemap 3.7.2, check 0.9.8}, @playwright/{test, experimental-ct-react} 1.59.1, TypeScript 6.0.3, Prettier 3.8.3, Turbo 2.9.6, marked 18.0.2, yaml 2.8.3, pagefind 1.5.2). ESLint 9 → 10 major-version gap remains the single out-of-scope drift item (manual changelog review required; not autonomous). pnpm typecheck 23/23 + pnpm lint 18/18 (FULL TURBO cache hits — no source/test/config drift since iter 126's commit 57b2b50). No source / test / config / package.json / lockfile changes. No pnpm install. No pnpm coverage re-run (CT-only is sufficient for flake-watch close; iter-124 100%-aggregate merged numbers stay authoritative until the next code-touching iteration). Iteration 126 history below.)

Iteration 126 (history): CT-flake watch advance — counter 1/3 → 2/3 after a clean full 48-case CT run; routine dep audit re-verified (zero deltas). Pure-verification iteration. pnpm test:ct ran the full Playwright Component-Testing surface on Windows 10 + Node 24.14.0 + Chromium 147 + Playwright 1.59.1: 48 passed (1m 25s) / 0 failed / 0 flaky / 0 retries. CT-only V8: bytes 100% (20,432/20,432), statements 100% (115/115), branches 98.81% (83/84), functions 100% (40/40), lines 100% (495/495). First complete-suite absence-of-recurrence signal since iter 111 (iter 124 ran mobile-menu.ct.test.tsx-only — partial-suite signal). Per the iter-125 "Next Steps" plan, the watch closes at iter 127 with one more clean full-CT run; iter 126 advances counter 1/3 → 2/3. Routine maintenance audit re-verified zero deltas across the 21-package matrix. ESLint 9 → 10 major-version gap remains the single out-of-scope drift item. pnpm typecheck 23/23 + pnpm lint 18/18 (FULL TURBO). No source / test / config / package.json / lockfile changes. Iteration 125 history below.)

Iteration 125 (history): doc health-check pass — flipped 5 stale-claim surfaces after iter 124's Q27 closure (CT counts + per-file coverage + aggregate). Pure-doc iteration. Surfaces brought current: (1) .specify/project.md — Current State header bumped 124 → 125; CT count line refreshed (43 → 48 total CT, 15 → 20 MobileMenu CT, 1165 → 1170 grand total) with iter 120/124 case-count growth annotated; spec-status block tightened to reflect Q27 ✅ RESOLVED in iter 124 (was iter-123 wording with status OPEN — Option A.1 chosen [DEFAULT]); spec count bumped 26 → 27. (2) .specify/features/q22-playwright-coverage.md — front-matter status block aggregate (98.72% → 100% (233/233)), per-file MobileMenu (91.89% → 100% (35/35)), lines (99.60% → 99.76%), statements (99.15% → 99.72%) all updated to post-Q27 state; "Q25 + Q26 ✅" extended to "Q25, Q26, and Q27 ✅"; archeology footer added preserving the iter-121 baseline numbers; Decisions table "Threshold for merged number" row appended Q27 outcome with "CI hard-gate now has zero margin" note. (3) .specify/features/testing.md — AC #10 test count refreshed (43 → 48 CT, 15 → 20 MobileMenu, 1165 → 1170 total) with iter 120/124 growth annotation + cross-reference to docs/plans/q27-mobilemenu-empty-items-coverage.md; AC #12 rewritten end-to-end to retire the long-stale "FilterBar/LayoutSwitcher/MobileMenu excluded from vitest.config.ts coverage.include until Q22 follow-up #3" wording (the exclusions were dropped in iter 115 / Phase 2) and replace with the steady-state Vitest+CT V8 merge description (monocart-reporter addCoverageReport() fixture iter 114 + vitest-monocart-coverage Vitest provider Q26 iter 119 + pnpm coverage merge script + Phase 6c GATE_TARGETS ≥80% hard-fail iter 121 + Q27 100% closure iter 124). (4) docs/architecture/testing-runners.md — "Current scope (iteration 121)" → "Current scope (iteration 124)"; per-file gate MobileMenu line gained the full 67.57% → 91.89% → 100% growth chain in parentheses; aggregate updated to 100% (233/233) + bytes 99.79% (45,558/45,650); Future work outcome block rewritten end-to-end to retire the "3-branch shortfall ... deferred — see iteration 120 entry" wording and credit Q27 closure (synthetic Tab dispatch via page.evaluate Option A.1 + /* v8 ignore next */ pragma Option A.3 on the defensive menuRef race-guard). (5) README.md Common Commands pnpm test row test count refreshed (1165+ → 1170+; CT split now explicit as "1122 Vitest + 48 Playwright CT"). Routine maintenance audit (zero deltas — re-verified): 15-package version matrix re-checked (1.5h after iter 123) — every dep still at the same latest version (Astro 6.1.9, Vitest 4.1.5, Playwright 1.59.1, Tailwind 4.2.4, Preact 10.29.1, monocart-coverage-reports 2.12.11, monocart-reporter 2.10.1, vitest-monocart-coverage 4.0.2, @astrojs/{vercel 10.0.5, preact 5.1.2, sitemap 3.7.2, check 0.9.8}, @playwright/test 1.59.1, TypeScript 6.0.3, Prettier 3.8.3). CT-flake watch carried: count remains 1/3 (iter 124 ran mobile-menu.ct.test.tsx 20/20 cleanly + pnpm coverage end-to-end clean — no recurrence; iter 125 was doc-only with no CT runs). No source / test / config / package.json / lockfile changes. No pnpm install. No pnpm coverage re-run (iter 124 numbers stay authoritative: aggregate 100% branches (233/233), MobileMenu 100% (35/35), gate green with zero margin). Iteration 124 history below.)

Iteration 124 (history): Q27 ✅ RESOLVED — MobileMenu reaches 100% branches; @ever-works/ui aggregate reaches 100% branches (233/233); the entire Q22→Q27 saga is now closed. Three new CT tests + one v8-ignore pragma. (1) focus trap: empty panel - Tab does nothing (focusable.length === 0) — closes B1 via synthetic KeyboardEvent('keydown', { key: 'Tab' }) dispatch through page.evaluate; uses toBeAttached() instead of toBeVisible() to bypass the iter-120 CT-host-page race where <MobileMenu items={[]} /> ends up CSS-hidden but DOM-attached (DOM listener still registered). (2) focus trap: synthetic Tab on last nav link wraps focus to first — closes B2; the iter-120 natural-keyboard variant covers behavior but page.keyboard.press('Tab') moves focus before the document handler evaluates document.activeElement === last, so synthetic dispatch is needed for V8 measurement. (3) focus trap: Tab on middle nav link does not preventDefault (non-boundary) — closes B3 (FALSE arm of both short-circuits). One additional defensive race-guard branch surfaced during execution (if (!menuEl) return; line 72 — only fires when menuRef.current is null AT the moment isOpen flips true; a Preact ref-attachment race that does not occur in production); closed via Option A.3 /* v8 ignore next */ pragma — verified the syntax works with monocart-coverage-reports@^2.12.9. Final per-package merged coverage: branches 100% (233/233), functions 100% (104/104), lines 99.76% (1240/1243), statements 99.72% (352/353), bytes 99.79% (45,558/45,650) across 19 files. Per-file gate: FilterBar 100% ✅ / LayoutSwitcher 100% ✅ / MobileMenu 100% (35/35) ✅. Mobile-menu.ct case count: 17 → 20. Verification: pnpm typecheck 23/23, pnpm lint 18/18, pnpm --filter @ever-works/ui exec playwright test mobile-menu.ct.test.tsx 20/20 in 55.3s, pnpm coverage end-to-end clean. Saga complete: Q22 ✅ + Q23 ✅ + Q24 ✅ + Q25 ✅ + Q26 ✅ + Q27 ✅; Q22 follow-ups #1 ✅ + #2 SUPERSEDED + #3 ✅. The CI hard-gate from iter 121 now has zero margin — any future code change that drops a branch will fail the merge. Iteration 123 history below.)

Iteration 123 (history): Q27 OPENED + spec + plan authored — MobileMenu 3-branch outlier coverage closure (carry from iteration 122 "Next Steps"). Pure-documentation iteration. Three new doc surfaces created: (1) .specify/features/q27-mobilemenu-empty-items-coverage.md (~280 lines) — full feature spec mirroring the Q24 (EMPTY_MODES) format with 9 acceptance criteria, 3 options for B1 (the focusable.length === 0 empty-items branch — A.1 synthetic Tab dispatch via page.evaluate [DEFAULT] / A.2 controlled-state API rejected / A.3 v8 ignore next contingency), 1 option for B2+B3 (non-boundary Tab natural test), 4 risks, AGENTS.md R1-R15 cross-check; (2) docs/plans/q27-mobilemenu-empty-items-coverage.md (~220 lines) — 4-step execution plan: Step 0 smoke-test Option A.1 in scratch dir / Step 1 land B1 test (replaces inline-deferral comment lines 254-264 of mobile-menu.ct.test.tsx) / Step 2 land B2/B3 non-boundary Tab test / Step 3 verify (pnpm test:ct × 2, pnpm coverage aggregate ≥99.4%, MobileMenu ≥97%, gate green) / Step 4 doc updates; sequencing table puts total at 1.5-2 hours across 1-2 future iterations; (3) docs/questions.md Q27 entry (~70 lines) with default A.1 + AC #2 path + "why this is OPEN not deferred" rationale (retires iteration 120's permanent inline TODO marker). Routine maintenance audit (zero deltas): full 22-package version matrix verified against npm latest — every dep is at the latest published version (caret-resolved or exact-pinned). One out-of-scope finding: ESLint pin ^9.0.0 vs latest 10.2.1 (major-version gap requiring manual changelog review; not autonomous). CT-flake watch carried: count remains 1/3 (iters 122/123 doc-only, no CT runs). No source / test / config / package.json / lockfile changes. No pnpm install. No pnpm coverage re-run (iter 121 numbers stay authoritative: aggregate 98.72% branches, MobileMenu 91.89%, gate green). Iteration 122 history below.)

Iteration 122 (history): Q22 follow-up #3 Phase 6d ✅ DONE — status flips across architecture / spec / questions / plan; Q22 follow-up #3 fully ✅ COMPLETE; the entire Q22→Q26 saga is now closed. Doc-only iteration. Six surfaces flipped: (1) docs/architecture/testing-runners.md "Coverage handling" rewritten end-to-end (was iter-116 CT-only / 67.57% MobileMenu wording; now describes the steady-state Vitest+CT V8 merge with the iter-121 numbers — branches 98.72%, MobileMenu 91.89%, gate enforced); "Future work" playwright-coverage bullet flipped to ✅ COMPLETE with per-phase recap (Phase 0/1/2/3/6a/6b/6c/6d). (2) .specify/features/q22-playwright-coverage.md front-matter status SPECIFIED (iter 110)✅ RESOLVED (iter 121) with final per-package merged numbers. (3) docs/questions.md Q22 status block appended a 3-item list marking all follow-ups closed (#1 ✅ iter 108 / #2 SUPERSEDED iter 110 / #3 ✅ iter 121). (4) docs/questions.md Q25 status OPEN✅ RESOLVED — Option A (monocart-coverage-reports@^2.12.0) with smoke-test pass cite. (5) docs/questions.md Q26 status block expanded to credit Phase 6c + 6d. (6) docs/plans/q22-playwright-coverage.md Phase 6d gained an Outcome block. Final saga state: Q22 ✅ + Q23 ✅ + Q24 ✅ + Q25 ✅ + Q26 ✅; Q22 follow-ups #1 ✅ + #2 SUPERSEDED + #3 ✅. No source / test / config changes; iter-121 verification (pnpm coverage end-to-end clean, gate green, 19 files, 98.72% branches) remains authoritative. pnpm typecheck 23/23 + pnpm lint 18/18 (FULL TURBO cache hits, doc-only). Future open work: CT-flake watch (1/3) + MobileMenu 3-branch outlier (component-spec issue). Iteration 121 history below.)

Iteration 121 (history): Q22 follow-up #3 Phase 6c ✅ DONE — coverage gate hard-fail enforced. packages/ui/scripts/coverage-merge.ts flipped from informational ⚠️ to hard-fail: when any of FilterBar.tsx / LayoutSwitcher.tsx / MobileMenu.tsx drops below 80% branches in the merged report, the script exits with code 1. Allow-list is explicit (GATE_TARGETS constant) so unrelated future files do not get gated by accident. Threshold is centralized (GATE_THRESHOLD = 80) for one-line tracking-issue overrides. New .github/workflows/ci.yml coverage-gate job (depends on ci + test-ct) runs pnpm coverage and inherits the merge script's exit code; uploads packages/ui/coverage/merged/ as a 14-day artifact for reviewer browse on every PR. Verification on Windows 10 + Node 24.14.1: pnpm typecheck 23/23 (16 cached + 7 fresh, 1m21s), pnpm lint 18/18 (16 cached + 2 fresh, 15.4s), pnpm coverage end-to-end clean — gate ✅ (FilterBar 100%, LayoutSwitcher 100%, MobileMenu 91.89%); merge aggregate 98.72% branches (232/235), 100% functions (104/104), 99.60% lines (1239/1244), 99.15% statements (352/355) across 19 files. Failure-path also verified: temporarily raised GATE_THRESHOLD to 95 → script exits with code 1 and the diagnostic block prints ❌ src/preact/MobileMenu.tsx: 91.89% branches; reverted to 80 immediately. Phase 6d (status flips for Q22 follow-up #3 + Q26 across docs/architecture/testing-runners.md, .specify/features/, docs/questions.md) is now the only remaining Q22-follow-up-#3 task. Iteration 120 history below.)

Iteration 120 (history): MobileMenu CT focus-trap tests close 9-of-12 branch gap (67.57% → 91.89%); Phase 3 per-file gate now PASSES for all three migrated components; Phase 6c hard-gate unblocked. Two new CT tests in packages/ui/src/__tests__/ct/mobile-menu.ct.test.tsx exercise the focus-trap useEffect (lines 69-95 of MobileMenu.tsx): Tab on the LAST nav link wraps focus to the FIRST; Shift+Tab on the FIRST nav link wraps focus to the LAST. Mobile-menu.ct case count: 15 → 17. Aggregate pnpm coverage merged number: 94.89% → 98.72% branches (232/235), 100% functions (104/104), 99.60% lines (1239/1244), 99.15% statements (352/355) across 19 files. Per-file gate (≥80% branches): FilterBar 100% ✅, LayoutSwitcher 100% ✅, MobileMenu 91.89% (34/37) ✅coverage-merge: ✅ Phase 3 per-file gate satisfied. 3-branch shortfall (235-232) is MobileMenu's if (focusable.length === 0) return; early-return (line 79) + 2 fall-through branches; an attempted third CT test for <MobileMenu items={[]} /> reproduced an unrelated CT-host focus-attribution edge case where the panel becomes hidden post-mount, deferred with an inline comment. Verification: pnpm typecheck 23/23, pnpm lint 18/18, pnpm --filter @ever-works/ui exec playwright test mobile-menu.ct.test.tsx 17/17 in 46.0s, pnpm coverage end-to-end clean.

Iteration 119 (history): Q22 follow-up #3 Phase 6b ✅ DONE — vitest-monocart-coverage adopted; full V8+Vitest merge now live; Q26 ✅ RESOLVED. pnpm --filter @ever-works/ui add -D vitest-monocart-coverage@^4.0.0 landed (resolved 4.0.2, +7 top-level lockfile entries — predicted 5, +2 transitive). packages/ui/vitest.config.ts swapped provider: 'v8'provider: 'custom' + customProviderModule: 'vitest-monocart-coverage'; the reporter array dropped (moved to monocart). New packages/ui/mcr.config.ts with top-level outputDir: './coverage' + reports: ['raw'] (one delta from the original Phase 6b plan: the per-report-tuple form [['raw', { outputDir: './coverage/raw' }]] nests under MCR's default ./coverage-reports/ root, so Vitest output landed at ./coverage-reports/coverage/raw/; the deployed top-level form mirrors playwright.ct.config.ts and writes to ./coverage/raw/coverage-<id>.json directly — 40 files per Vitest run). packages/ui/scripts/coverage-merge.ts simplified — Istanbul branch dropped, single inputDir: ['./coverage/raw', './coverage/ct/raw'] (89 raw V8 files combined: 40 Vitest + 49 CT). monocart-coverage-reports pin bumped from ^2.12.0^2.12.9 to align with Q26's transitive floor. Verification on Windows 10 + Node 24.14.1 + pnpm 10.33.0: pnpm typecheck 23/23, pnpm lint 18/18, end-to-end pnpm coverage produces a merged report covering 19 files at branches 94.89% (223/235), functions 100% (104/104), lines 98.63% (1227/1244), statements 96.62% (343/355) in ~3 min walltime (~98s Vitest + ~78s CT + ~1s merge). Per-file gate: FilterBar.tsx 100% ✅, LayoutSwitcher.tsx 100% ✅, MobileMenu.tsx 67.57% ❌ — the 12-branch shortfall (235-223) is exclusively MobileMenu's known gap, deferred to Q22 follow-up #3 sub-iteration. Phase 6c (CI gate hard-fail) sequenced for iteration 120; Phase 6d (status flips) for iteration 121. Iteration 117 history below.)

Iteration 117 (history): Q26 npm-registry validation + Phase 6a smoke test ✅ PASSED in same iteration. Status flipped from OPEN [DEFAULT] to CONFIRMED — Option A; Phase 6a SMOKE PASSED. Validation block was prepared upstream as iteration-117 prep; the Phase 6a smoke test (originally planned for iteration 118 per pending plan) was also executed in this run, end-to-end. [email protected] ran a 2-test/3-branch Vitest suite in scratch dir packages/ui/scratch/q26-vitest-monocart/ (deleted at end of phase): branches 75% (3/4 — exactly the deliberate uncovered branch), functions 100%, lines 94.44%, statements 91.67%, bytes 97.80%. Output coverage/raw/coverage-<id>.json is identical in shape to Playwright CT's coverage/ct/raw/<id>.json — confirming Phase 6b's merge is just inputDir: ['./coverage/raw', './coverage/ct/raw'] with no Istanbul mixing. Source-map fidelity verified: per-file src/sample.ts resolves to url: "src/sample.ts" (workspace-relative, NOT a chunk hash). The Q26 reopen condition (smoke-test failure → Option B custom converter) does NOT trigger. Plan sub-phases shifted: 6a = iteration 117 ✅ DONE; 6b/6c/6d = iterations 118/119/120 (was 119/120/121). One known-not-blocking deprecation warning surfaced from vitest-monocart-coverage internals (Importing from "vitest/coverage" is deprecated since Vitest 4.1) — tracked upstream at cenfun/vitest-monocart-coverage; will file an issue if it persists past 4.0.2. Doc + scratch-only iteration — zero changes in packages/, apps/, node_modules/, pnpm-lock.yaml of the production tree. Phase 6b is unblocked: next iteration replaces provider: 'v8' in packages/ui/vitest.config.ts with provider: 'custom' + customProviderModule: 'vitest-monocart-coverage', adds packages/ui/mcr.config.ts, simplifies coverage-merge.ts to drop the Istanbul branch. Iteration 116 history below.)

Iteration 116 (history): Q22 follow-up #3 Phase 3 ✅ PARTIALLY DONE — pnpm coverage merge command landed end-to-end on Windows + Node 24.14.0; CT subgraph fully merged; full V8+Vitest deferred to new Q26. New packages/ui/scripts/coverage-merge.ts (~190 lines) constructs new CoverageReport({ inputDir: ['./coverage/ct/raw'], outputDir: './coverage/merged', cleanCache: true, reports: [['v8'], ['v8-json'], ['lcov'], ['codecov'], ['console-summary']], sourceFilter }) and calls mcr.generate(). playwright.ct.config.ts gains 'raw' in its coverage.reports so per-test V8 entries land at coverage/ct/raw/<id>.json (49 files after a clean run). vitest.config.ts gains 'json' in its reporter array so coverage-final.json is written for Q26's eventual full merge. New coverage scripts: per-package (pnpm test:coverage && pnpm test:ct && tsx scripts/coverage-merge.ts) and root (pnpm --filter @ever-works/ui coverage). CLAUDE.md documents pnpm coverage in Common Commands + Safe Operations. Merged aggregate: branches 84.88% (73/86), functions 100% (40/40), lines 97.18% (482/496), statements 90.60% (106/117), bytes 97.53% (19,903/20,407) across 9 files in the CT subgraph. Per-file gate (informational): FilterBar.tsx 100% branches ✅, LayoutSwitcher.tsx 100% branches ✅, MobileMenu.tsx 67.57% (25/37) ❌ — 12 branches uncovered, likely focus-trap teardown / pointer-vs-touch fallback / prefers-reduced-motion guards. Q26 opened: [email protected] has a hard limitation (getCoverageResults dispatches mutually-exclusive code paths on dataList[0].type) preventing raw V8 + Istanbul mixing in a single MCR instance — empirically reproduced as [MCR] Not found source data: undefinedTypeError ... at getCssAstInfo. Default Option A: vitest-monocart-coverage drop-in provider so Vitest also emits raw V8 → both inputs flow through the same V8 path. Phase 4 CI is unblocked for the artifact-upload portion; gate enforcement waits on Q26 + MobileMenu CT branches. Iteration 115 history below.)

Iteration 115 (history): Q22 follow-up #3 Phase 2 ✅ DONE — Vitest exclusions for the three CT-migrated components dropped; intended pre-merge state captured. Removed three coverage.exclude lines from packages/ui/vitest.config.ts for FilterBar.tsx / LayoutSwitcher.tsx / MobileMenu.tsx and replaced them with an iteration-115 comment block pointing at the plan and spec for the Phase 3 merge story. Branch number measured before/after on identical 11/11 files / 174/174 tests passing in ~100s: 100% (145/145) → 70.53% (158/224) — exactly within the plan's predicted 70-72% pre-merge envelope. Per-file: FilterBar.tsx and MobileMenu.tsx now report 0% (Vitest never executes them — only CT does, and that V8 stream is unmerged until Phase 3), LayoutSwitcher.tsx at 86.66% branches (one render-import side path runs under Vitest). The CT V8 stream from Phase 1 (iteration 114, coverage/ct/raw-v8.json with 9 entries including all three migrated components at source-mapped .tsx URLs) is unaffected — Phase 3 will combine the two streams into a single coverage-summary.json and restore the per-package number to ≥ baseline. AC #5 satisfied at the source-file level; AC #5's per-file ≥80% gate naturally lives in Phase 3. AC #4 / AC #6 remain Phase 3 work. Phase 3 is unblocked: create packages/ui/scripts/coverage-merge.ts, add pnpm coverage script (root + per-package), wire MCR to read both coverage-final.json (Vitest) and raw-v8.json (CT). pnpm typecheck 23/23, pnpm lint 18/18 (both with FULL TURBO partial cache hits). Zero CT regression check this iteration — Phase 2 is purely a Vitest-config edit, no runtime effect on the CT runner. Iteration 114 history below.)

Iteration 114 (history): Q22 follow-up #3 Phase 1 ✅ DONE — V8 coverage now flowing on every pnpm test:ct run. monocart-coverage-reports@^2.12.0 + monocart-reporter@^2.10.0 landed as @ever-works/ui devDependencies; playwright.ct.config.ts reporter array gained the monocart-reporter entry (with coverage.entryFilter accepting localhost:3100/assets/*.js chunks and coverage.sourceFilter narrowing to packages/ui/src/); a new src/__tests__/ct/fixtures.ts extends the CT test with an auto-fixture that calls page.coverage.startJSCoverage() / stopJSCoverage() and pipes per-test V8 entries into addCoverageReport(); the three CT test files (filter-bar, layout-switcher, mobile-menu) now import test/expect from this fixture instead of @playwright/experimental-ct-react directly. Verification: pnpm --filter @ever-works/ui test:ct reports 43/43 passing in 1m 16s; packages/ui/coverage/ct/raw-v8.json written via coverage.onEnd hook with 9 V8 entries (well over the plan's ≥3 exit criterion), all carrying source-mapped .tsx / .ts URLs under src/preact/, src/primitives/, src/components/ui/, src/lib/ — including all three migrated components (FilterBar.tsx, LayoutSwitcher.tsx, MobileMenu.tsx). MCR aggregate: branches 84.88% (73/86), functions 100% (40/40), lines 97.18% (482/496), statements 39.80% (39/98), bytes 60.73% — confirms AC #3 (URLs map to source files, not chunk hashes) and partially AC #5 (≥80% branches per migrated component, pending Phase 2's exclusion drop to verify per-file). Spec R6 risk now fully closed (was downgraded in 113): source-maps + Vite/Preact alias chain produce real .tsx URLs, not chunk hashes. tsconfig.json exclude list updated (src/__tests__/ct/** removed via inferred-type fix in fixtures.ts as typeof base cast — typecheck stays clean for both regular and CT tsconfigs). packages/ui/.gitignore gained explicit coverage/ entry (defense in depth — root .gitignore already covers it). Phase 1 exit criterion satisfied; Phase 2 unblocked (drop the three Vitest coverage.exclude lines for FilterBar.tsx / LayoutSwitcher.tsx / MobileMenu.tsx; expected outcome per plan: branch number drops to ~70-72% pre-merge). Iteration 113 history below.)

Iteration 113 (history): Q22 follow-up #3 Phase 0 ✅ PASS-API. monocart-coverage-reports 2.12.11 validated end-to-end on Windows 10 + Node 24.14.0 + Chromium 147 + Playwright 1.59.1: Playwright's page.coverage.startJSCoverage() + stopJSCoverage() captured 1 V8 entry from a synthetic file://-served app.js (3-branch maybeBranch(x) function, intentional 2-of-3 branch exercise), MCR add() + generate() succeeded without error, output coverage-report.json carries every field the plan's Phase 1 needs (url, sourcePath, source, per-byte data ranges, summary). Per-file coverage stats: branches 75% (3/4), statements 85.71%, lines 88.89%, functions 100%, bytes 95% — all match the deliberately-instrumented synthetic test code. Q25 status flipped from OPEN [DEFAULT] to CONFIRMED — Option A (monocart-coverage-reports@^2.12.0); Option B (@bgotink/playwright-coverage) remains a contingency only if Phase 1's source-map verification fails. Spec R6 risk DOWNGRADED from "library may not exist / mis-handle toolchain" to "library may mis-handle Vite/Preact alias source-maps" — a much narrower Phase 1 surface. Plan Phase 0 marked ✅ PASS-API; Phase 1 explicitly unblocked. Scratch dir created/used/deleted entirely within iteration 113 per plan step 4 — zero persistent code/dep/config changes; .gitignore scratch/ rule from iteration 112 covered the entire transient tree.

Iteration 112 (now superseded by 113 above for the front-page descriptor): Q25 npm-registry validation + Phase 0 prerequisite (packages/ui/.gitignore) created. Two parallel docs/prep deliverables, both low-risk and gated. (1) Q25 npm-registry validation: before any pnpm add lands, verified [email protected] (latest dist-tag, above the spec's ^2.11.0 floor — pin bumped to ^2.12.0 to lock the verified branch) and [email protected] (latest, pin bumped to ^2.10.0) are still actively published. README inspection confirms playwright-ct-react is an explicitly listed integration example, the "Automatic Merging" / "Manual Merging" sections describe the Vitest-unit + Playwright-CT merge flow we need (matches AC #4), and entryFilter/sourceFilter API matches the plan's Phase 1 step 2 settings. Q25 default (Option A — monocart-coverage-reports) holds; the spec's "Library may not exist" risk (R6) drops to "library may mis-handle our specific Vite/Preact alias" — a much narrower Phase 0 surface. (2) packages/ui/.gitignore created (first per-package gitignore in the repo) with a single scratch/ line plus a header comment block referencing the plan and spec. Most generic patterns (node_modules/, coverage/, dist/, test-results/, playwright-report/) are already covered by the repo-root .gitignore; this file's only purpose is the scratch-dir convention required by Phase 0 step 1 of the plan. Phase 0 (the smoke test itself) was NOT executed in iteration 112 — three reasons documented in the log: (a) validation already shrank Phase 0's scope; (b) cron-task autonomy + browser-cold-start fragility argues against coupling a brand-new dev dep + new Playwright reporter + browser launch in one autonomous iteration; (c) the plan's iteration sequencing already lists Phase 0 alone as ~30 min Low-risk. Iteration 113 inherits a fully unblocked Phase 0 (gitignore exists, library version is verified, hand-off checklist sits at the bottom of the log entry). Files changed: docs/questions.md Q25, .specify/features/q22-playwright-coverage.md Decisions table, docs/plans/q22-playwright-coverage.md header + Phase 0/1 step 1. Files created: packages/ui/.gitignore. Iteration 111 history below.)

Iteration 111 (now superseded by 112 above for the front-page descriptor): CLAUDE.md drift fix — pnpm test:ct + pnpm test:ct:install now listed in Common Commands and Safe Operations. The Playwright CT toolchain has been the canonical signal for FilterBar/LayoutSwitcher/MobileMenu since iteration 105, but CLAUDE.md never picked it up; new contributors / AI agents reading the file cold would have missed it. Also captures a CT-flake observation from iteration 111's verification (filter-bar.ct › selects category on click failed once, passed on retry; not opening Q26 yet — single-occurrence flake within Playwright cold-start tolerance, will revisit if it recurs ≥3× in the next 3 iterations). Q22 follow-up #3 (playwright-coverage integration) verified upstream: [email protected] + [email protected] both above the spec's ^2.11.0 pin — Phase 0 smoke test is the cleanest single-iteration unit for the next run. Doc-only iteration; no code/dep changes.

Iteration 110 (history): Q22 follow-up #2 SUPERSEDED + Q22 follow-up #3 spec/plan authored. Two parallel deliverables. (1) Follow-up #2 — pnpm test:ui:safe removal — SUPERSEDED: plain pnpm --filter @ever-works/ui test runs all 11 Vitest files (174 tests) in ~98s on Windows + Node 24.14.0, verified 2 of 2 consecutive runs. Q22 IPC-hang fingerprint does not reproduce. The cron-task instruction "Do NOT remove anything (move or improve is OK)" + AGENTS.md R15 ("Replace, don't remove") preclude outright deletion; the script is soft-deprecated via JSDoc + CLAUDE.md note as a defensive fallback for any future Vitest/jsdom/Node regression. docs/architecture/testing-runners.md "Future work" entry flipped from "OPEN" to "SUPERSEDED". Zero file deletions. (2) Follow-up #3 — playwright-coverage integration — SPECIFIED + PLANNED: new spec at .specify/features/q22-playwright-coverage.md (10 acceptance criteria, library risk analysis, AGENTS.md R1-R15 cross-check) and 5-phase execution plan at docs/plans/q22-playwright-coverage.md (Phase 0 smoke test gate before any code lands; Phase 5 status flip). New question Q25 in docs/questions.md captures the library choice (monocart-coverage-reports 2.x [DEFAULT] vs @bgotink/playwright-coverage vs custom harness vs defer-indefinitely). Default rationale: monocart explicitly supports playwright-ct-react, explicitly supports merging V8 coverage from multiple sources, emits V8-native reports matching Vitest's existing provider. When this lands across iterations 111-114, the three exclusions in packages/ui/vitest.config.ts (FilterBar, LayoutSwitcher, MobileMenu) drop and the per-package branch number reflects the full surface area rather than measured-surface-only. Q22 / Q23 / Q24 remain CLOSED; Q22 follow-ups #1 / #2 are now CLOSED (#2 via supersession); only Q22 follow-up #3 + Q25 + CI-matrix-observation remain open.

Root Documents

These files live at the repository root and are not part of the Docusaurus docs site. View them on GitHub or in the cloned repository.

  • CLAUDE.md — Claude Code instructions, project overview, commands (view on GitHub)
  • AGENTS.md — AI agent rules (R1-R15 under Mandatory Rules), working process, data contracts, available pages/components/plugins (view on GitHub)
  • SKILLS.md — Step-by-step AI agent skills for building directory sites (view on GitHub)
  • README.md — Project README (view on GitHub)

Overview

  • overview.md — Project overview, philosophy, tech stack, quick start

Architecture

Plans

Specifications

Spec Kit (.specify/)

These files live in the .specify/ directory at the repository root. View them on GitHub or in the cloned repository.

  • project.md — Project specification (goals, non-goals, tech stack, timeline) (view on GitHub)
  • features/data-layer.md — Data layer feature spec (view on GitHub)
  • features/plugin-system.md — Plugin system feature spec (view on GitHub)
  • features/ui-components.md — UI components feature spec (view on GitHub)
  • features/web-app.md — Web app feature spec (all page routes) (view on GitHub)
  • features/plugins-phase4.md — Phase 4 built-in plugins detailed spec (view on GitHub)
  • features/sample-basic.md — Sample basic implementation spec (view on GitHub)
  • features/plugin-breadcrumbs.md — Breadcrumbs plugin spec (view on GitHub)
  • features/testing.md — Unit testing infrastructure spec (view on GitHub)
  • features/static-pages.md — Static pages feature spec (view on GitHub)
  • features/sample-git.md — Sample Git reference implementation spec (view on GitHub)
  • features/content-sync.md — Content sync, caching & ISR spec (view on GitHub)
  • features/sample-jobs.md — Sample Jobs (job board directory) spec (view on GitHub)
  • features/sample-events.md — Sample Events (conferences/meetups directory) spec (view on GitHub)
  • features/sample-real-estate.md — Sample Real Estate (property listings directory) spec (view on GitHub)
  • features/lighthouse-ci.md — Lighthouse CI performance testing spec (view on GitHub)
  • features/plugin-rss.md — RSS/Atom feed plugin spec (view on GitHub)
  • features/plugin-analytics.md — Analytics plugin spec (Plausible, Umami, Fathom, GA4, custom) (view on GitHub)
  • features/plugin-related-items.md — Related items plugin spec (tag/category scoring, build-time computation) (view on GitHub)
  • features/plugin-filters.md — Filters plugin spec (category, tag, search filtering with URL sync) (view on GitHub)
  • features/plugin-search.md — Search plugin spec (Pagefind static search indexing) (view on GitHub)
  • features/plugin-pagination.md — Pagination plugin spec (page calculation, URL patterns) (view on GitHub)
  • features/plugin-sort.md — Sort plugin spec (name, date, featured sorting) (view on GitHub)
  • features/plugin-sitemap.md — Sitemap plugin spec (@astrojs/sitemap config wrapper) (view on GitHub)
  • features/robots-txt.md — robots.txt generation spec (view on GitHub)
  • features/visual-regression.md — Visual regression testing spec (view on GitHub)
  • features/q22-playwright-ct.md — Q22 resolution: Playwright Component Testing migration spec for FilterBar (view on GitHub)
  • features/q22-mobilemenu-ct.md — Q22 follow-up #1: Preemptive MobileMenu Playwright CT migration spec (view on GitHub)
  • features/q24-layoutswitcher-empty-modes.md — Q24: LayoutSwitcher EMPTY_MODES allocation fix spec (view on GitHub)
  • features/q22-playwright-coverage.md — Q22 follow-up #3: playwright-coverage integration spec (V8 coverage merge for Vitest + Playwright CT runs) (view on GitHub)
  • features/q27-mobilemenu-empty-items-coverage.md — Q27: MobileMenu 3-branch outlier coverage closure spec (focus-trap empty-items + non-boundary Tab; default Option A.1 = synthetic Tab dispatch via page.evaluate; ✅ RESOLVED iter 124) (view on GitHub)
  • features/q28-eslint-10-upgrade.md — Q28: ESLint 9 → 10 major-version upgrade spec (single-iteration in-place peer-range bump; pre-investigated iter 129; flat config + Node 24 + @typescript-eslint@^8.59.0 peer-range all already cover ESLint 10) (view on GitHub)
  • features/audit-docs-script.mdscripts/audit-docs.ts executable codification of AGENTS.md § Doc-Quality Audit Checklist greps as a single pnpm audit:docs runner (iter 149: 6 audit classes + 1 cross-file parity check; ✅ RESOLVED iter 149 → wired into CI as PR-blocking step iter 150) (view on GitHub)
  • features/audit-docs-self-parity.mdaudit-docs.ts self-parity audit class — checklist ↔ runner parity self-validation (iter 151: 7th audit class; auditChecklistRunnerParity() reads AGENTS.md directly with node:fs and asserts 1:1 parity between ### sub-section headings and the in-script EXPECTED_MAPPING table; closes iter-149's "Next Steps #1"; ✅ RESOLVED iter 151) (view on GitHub)
  • features/audit-docs-matrix-prose.mdaudit-docs.ts matrix-prose count parity audit class — **N-package matrix** total claim ↔ canonical 3-cohort breakdown sum parity (iter 161: 8th audit class; auditMatrixProseCountParity() reads .specify/project.md directly with node:fs and asserts (high-churn cohort, X) + (iter-N lifted, Y) + (deferred cohort, Z) == N; codify-trigger fired iter-160 after 2 drift instances per iter-156 deferral #9 codify-then-execute meta-pattern; ✅ RESOLVED iter 161) (view on GitHub)
  • features/multi-option-support.md — Multi-option support umbrella spec (iter 218 user pivot, OPEN — phases queued): keep every existing default (Preact / Tailwind / config-file plugins / Pagefind / Astro built-in image / Docusaurus / isomorphic-git / pageview-only analytics) and add alternates for Q1 (UI framework), Q2 (CSS strategy), Q4 (plugin auto-discovery), Q5 (search backends), Q9 (image services), Q10 (Starlight docs), Q18 (git adapters), Q20 (analytics events + consent). 8 independent phases, paired plan at docs/plans/multi-option-support.md. (view on GitHub)
  • features/works-config-path.md.works/works.yml site config path migration spec (implemented 2026-05-09): canonical config path is .works/works.yml. (view on GitHub)

Guides

Reference

  • questions.md — Open questions and decisions (Q1-Q28 with defaults)
  • log.md — Change log (all iterations tracked)