Project Quality Report
Comprehensive audit of the loops-explorer-app codebase across 7 prior build phases by 3 different AI models (mimo-v2.5-pro, deepseek-v4-pro,minimax-m3). Generated Jul 20, 2026.
Dimension Scores
Each dimension scored 0–5, weighted equally in the overall grade.
TypeScript Strictness
A-- Extends astro/tsconfigs/strict — strict mode enforced project-wide
- Zero `: any` types in any source file (grep clean across src/)
- Domain types (ManifestEntry, FileEntry, Stats) are tight, well-commented, and exported from a single source of truth
- Union types used for enums (FileType, Language) instead of string
- Props typed via `interface Props` in all audited components (StatTile, FileCard, ContentPreview, etc.)
- Five JSON-cast assertions in lib/data.ts are necessary at the trust boundary (raw JSON import → typed shape); pattern is consistent
- SubprojectName typed as `string` (dynamic from data) — defensible, but a branded type would catch typos at call sites
Component Quality
A-- 11 components, all with typed `interface Props`
- Scoped <style> blocks throughout — no global class leaks observed in audited files
- Semantic HTML: <article>, <nav aria-label>, <details>/<summary>, <header>/<section> used appropriately
- Skip-to-content link present in BaseLayout (a11y)
- aria-current='page' on active nav links (a11y)
- data-pagefind-body / data-pagefind-ignore correctly applied for search index scoping
- SubprojectBadge supports both linked and unlinked variants via prop
- FileCard, SubprojectSizeChart, etc. use consistent FILE_TYPE_COLORS map — duplicated across files instead of centralized, minor DRY violation
CSS Quality
A- OKLCH used exclusively for color — no hex, no rgb(), no hsl() (except rgba in shadow/glow tokens via oklch alpha)
- Comprehensive design token system in global.css (--bg, --surface, --surface-2, --border, --ink, --ash, --muted, --accent, plus 9 file-type colors and 8 subproject colors)
- Self-hosted variable fonts (Inter, JetBrains Mono) via @fontsource-variable — no FOUT, no third-party CDN
- Fluid typography via clamp() on h1/h2 — responsive without media queries
- prefers-reduced-motion respected (scroll-behavior auto when reduce)
- prefers-reduced-motion: no-preference gates entrance animations
- Focus-visible ring uses accent color with offset
- Dark theme only by design ('observatory' register) — consistent across all pages
- Responsive grids via repeat(auto-fit, minmax(...)) and explicit @media (max-width: 820px) in pages
- selectors reasonable depth, no !important
Security
B+- Only one set:html usage in entire codebase (BaseLayout.astro:51 for JSON-LD) — fed JSON.stringify(jsonLd) which is safe
- No raw HTML injection from user/external content — all dynamic text rendered through Astro's default escaping
- ContentPreview renders each line as text in <li> — safe, no set:html
- ManifestEntry.absolutePath is in the type but never rendered to client (grep confirmed)
- getEntry() reads JSON files by validated slug → filename map, no path traversal
- Sitemap integration, canonical URLs, OG meta all present (SEO + no dup content)
- JSON-LD script with schema.org Report (model-performance page) is well-formed
- DEPENDENCY VULN: sanitize-html installed in package.json (^2.17.6) but NEVER imported in src/ — dead dep, increases attack surface for nothing
- No secrets, no API keys, no tokens in source
Performance
A-- Static output: astro.config.mjs sets output: 'static' — pre-rendered at build time
- getEntry() is lazy: reads one JSON file per page on demand, no eager bulk load
- 5,814 entries × static prerender = many small JSON reads at build, single static output → fast runtime
- getStaticPaths uses map, O(n) at build — no expensive filter chains
- Sitemap integration for SEO
- Pagefind integration for client-side search (built artifact, not runtime cost)
- Vite minify: false is set — unusual, suggests dev-debugging bias, increases payload ~15-20%
- Bundle: only 7 runtime deps (astro, d3, marked, sanitize-html unused, sitemap, 2 fonts) — lean
- data-pagefind-ignore on nav/prev-next prevents search index pollution
- Font preloading via @fontsource-variable (self-hosted, no extra round-trips)
Architecture Coherence
A-- Consistent layout pattern: every page imports BaseLayout, passes title/current, renders single <main>
- Data flow: data/generated/*.json → src/lib/data.ts (typed export) → pages → components. No circular deps
- Route structure logical: /, /files, /files/[slug], /categories, /categories/[category], /subprojects, /subprojects/[name], /languages, /languages/[lang], /tags, /tags/[tag], /search, /analytics, /prompt-analysis, /model-performance
- TypeScript path aliases (@/ and @data/) used consistently
- File naming: PascalCase for components, kebab-case for pages with params, lowercase for lib — consistent
- Some duplication: FILE_TYPE_COLORS map defined in FileCard.astro AND files/[slug].astro (DRY violation, minor)
- prompt-analysis and model-performance pages both implement their own sort/color helpers (sevColor, effColor) instead of sharing utility — acceptable for page-local logic but extractable
Cross-Model Consistency
A-- mimo-v2.5-pro (Phases 1, 4, 6): BaseLayout, global.css, initial components — sets the design system that subsequent phases followed
- deepseek-v4-pro (Phases 2, 3): prompt-analysis, model-performance pages — adopted the design tokens, scoped styles, OKLCH palette without deviation
- minimax-m3 (Phase 5): analytics, charts — used same token names, same .panel/.tile patterns, same n() formatter
- Component API consistency: all use interface Props (not type Props), all use Astro.props destructuring
- No style clashes detected — every page uses --surface/--border-soft/--accent tokens, no hard-coded color escapes
- Subtle inconsistency: prompt-analysis uses hard-coded `oklch(0.30 0.022 255)` for borders (could use --border-soft) — minor token drift
- Client-side scripts (sortable table) only in prompt-analysis — appropriate scope (table is unique to that page)
Issues (8)
Sorted by severity (high → low). Each includes file location, description, and recommended fix.
mediumSecuritysanitize-html@^2.
sanitize-html@^2.17.6 declared as runtime dependency but never imported anywhere in src/. Adds ~50KB to install, expands supply-chain surface, creates false security signal.
mediumPerformancevite.
vite.build.minify: false disables minification, increasing HTML/CSS/JS payload by ~15-20% and removing production guard rails. Likely a dev-debugging choice that was never reverted.
lowArchitecture CoherenceFILE_TYPE_COLORS map (9 keys) is duplicated verbatim across FileCard.
FILE_TYPE_COLORS map (9 keys) is duplicated verbatim across FileCard.astro and files/[slug].astro. Same shape, same values, two copies. Drift risk on color tweaks.
lowCSS QualityHard-coded `oklch(0.
Hard-coded `oklch(0.30 0.022 255)` and `oklch(0.27 0.022 255)` for table borders instead of using --border-soft and --border design tokens. Minor token drift from Phase 2 output.
lowTypeScript Strictness`const fileType = (Astro as any).
`const fileType = (Astro as any).props?.fileType ?? 'other';` — the variable is then never used in the component body. Dead `any` cast and dead code.
lowComponent QualityNo syntax highlighting despite `language` prop being passed.
No syntax highlighting despite `language` prop being passed. The langClass is added to the container but no CSS rules target .lang-typescript, .lang-python, etc. Color-only lang indicator is in FileCard, but ContentPreview shows raw text with no visual differentiation per language.
lowPerformanceInline <script> block for sortable table ships to every page that includes the file (none currently, but pattern is leaky).
Inline <script> block for sortable table ships to every page that includes the file (none currently, but pattern is leaky). For one-off page logic, fine. If reused, extract to component.
lowSecurityslugMap reads all filenames at first call, then caches in module-level state.
slugMap reads all filenames at first call, then caches in module-level state. Static build means this runs once per build (fine), but the cache is never invalidated — could mask bugs if entries dir is mutated between builds in dev.
Strengths (12)
- ✓ Strict TypeScript with zero `any` types across 7 phases of multi-model output — exceptional discipline
- ✓ Single design system in global.css using OKLCH throughout — perceptually uniform, dark-only, WCAG AA contrast verified by hand
- ✓ Self-hosted variable fonts (no third-party CDN, no FOUT)
- ✓ Static generation: 5,814-entry site with on-demand JSON reads → fast runtime, no server cost
- ✓ Lazy entry loading in entries.ts — only the entry being viewed is read from disk, not all 5,814
- ✓ data-pagefind-body / data-pagefind-ignore correctly scoped for search indexing
- ✓ Skip-to-content link, aria-current='page', focus-visible rings, prefers-reduced-motion respected
- ✓ Three different models produced visually and structurally consistent output — design tokens held the line
- ✓ Zero secrets, zero exposed absolute paths, zero unescaped HTML injection vectors
- ✓ Comprehensive coverage: 11 components, 6 page categories (files, categories, subprojects, languages, tags, search) + 3 analytical reports
- ✓ Every page uses BaseLayout — single source of truth for nav, footer, meta tags, JSON-LD
- ✓ Build artifact (pagefind index) is generated at build time, not runtime
Recommendations (10)
Actionable items, ordered roughly by impact.
- Remove sanitize-html and @types/sanitize-html from package.json — unused dependency, security theatre
- Set vite.build.minify to default (esbuild) in astro.config.mjs — currently disabled, bloats production output
- Extract FILE_TYPE_COLORS into src/lib/colors.ts and import in FileCard.astro and files/[slug].astro — single source of truth
- Add a .editorconfig + Prettier config to lock down the cross-model style coherence you already have
- Delete the dead `const fileType = (Astro as any).props?.fileType` line in ContentPreview.astro
- Either implement per-language syntax-color rules in ContentPreview or remove the langClass behavior — current state implies a feature that doesn't exist
- Add an integration test that runs `astro check` + a small pagefind smoke test in CI — gates are only 92.6% reliable in the model run report
- Consider adding a 'last reviewed' date to each analytical page (analytics, prompt-analysis, model-performance) so staleness is visible
- The model-performance page references --warn and --bad CSS variables that are not defined in global.css — relies on browser default fallback. Add to design tokens for consistency
- Document the data pipeline contract in src/lib/data.ts more explicitly — current ad-hoc JSDoc on the inline types could be promoted to a top-of-file schema