chore: repo cleanup — dead code, single-source docs, kebab-case naming - #1011
chore: repo cleanup — dead code, single-source docs, kebab-case naming#1011Jose-Gael-Cruz-Lopez wants to merge 12 commits into
Conversation
Add knip for dead-code detection, configured for the Turbo workspaces
(apps/site, apps/sanity, apps/internal, packages/db), and act on the
unambiguous findings.
Remove 20 unreferenced files, verified to have no static, dynamic, or
config-based importers:
- (authenticated)/(shell)/(misc)/accept/{actions,types}.ts - route-less
duplicate of the live (unauthenticated)/accept module
- the five-file authenticated-header/components/ search cluster, which
only referenced itself
- apply-button.tsx, careers-externship.tsx, portal.tsx, share-article.tsx,
logout-button.tsx, sanity-thumbnail-image.tsx, and six others
Remove 17 unused dependencies across three workspaces.
Deliberately kept and documented in knip.json:
- newrelic (loaded via require() in newrelic-agent.cjs)
- tw-animate-css (imported from globals.css; knip does not scan CSS)
- imp/[slug]/components/types.ts, a global-script file whose ambient
interface is used without an import
Left in place pending a product decision: the orphaned farm/general-business-
information application trees and the widget-grid tree, both of which are
residue from in-progress migrations rather than settled dead code.
No behavior change. type-check, lint, 527 tests, and build all pass.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
apps/site/src/i18n/request.ts was the only console call left in app or library source once /scripts, *.test.* files, the three logger.ts implementations, and gitignored build output were excluded. The dev branch maps cleanly onto logger.warn, which is already gated to development. The production branch cannot: logger.warn is a no-op outside development, so a straight swap would have silently dropped the warning that a message file failed to load in production. It routes through logger.error instead, which always emits, preserving the visibility the console.warn had. Message text and context are carried over verbatim. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
AGENTS.md and apps/site/CLAUDE.md overlapped, and where they overlapped they disagreed. AGENTS.md now owns every repo-wide convention; CLAUDE.md keeps only apps/site specifics and links back for the rest. Contradictions resolved: - Naming: AGENTS.md said all files kebab-case, CLAUDE.md said "kebab-case for directories, PascalCase for components". Restated as filenames kebab-case, identifiers PascalCase - which is what CLAUDE.md's own hero.tsx example shows. - State: AGENTS.md said prefer useForm() over useState(), CLAUDE.md said use useState/useReducer for local state. Split by scope: useForm for form state, useState/useReducer for non-form local state, Context for cross-cutting. - Logging: CLAUDE.md forbade console.log in one section and permitted it in another. Now stated once, with the levels' actual production behavior. Stale facts corrected: - "cd frontend" referred to a directory that does not exist; it is apps/site. - "bun ci" and "bun lint:fix" do not exist at the repo root, only in apps/site. - Pre-commit does not type-check; that runs on pre-push. - Next.js 15 -> 16, Storybook 9.1 -> 10.3, and the rest of the stack versions. - CLAUDE.md's directory tree predated the route groups and referenced five paths that no longer exist. - Four verbatim-duplicated bullets removed from CLAUDE.md. READMEs reconciled against actual package.json scripts: - root: adds apps/internal, Node 20.20.1 per .nvmrc, documents knip. - apps/site: drops "bun run generate-icons" (its script file does not exist), /middleware -> /proxy, corrects the deleted locale-utils.ts reference and the background-colour values. - apps/internal, apps/sanity, packages/db: real command lists, and a note on which turbo tasks silently skip each workspace. No behavior changes; markdown only. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Message JSON is bundled at build time, so a missing translation file is a development and build concern rather than a live-request event. Routing it through logger.error meant anyone alerting on error-level logs would be paged for something that cannot surface in a healthy production deploy. logger.warn is already development-gated, which made the surrounding NODE_ENV check redundant, so the two branches collapse into one call. The message text drops its "Warning:" prefix, which only existed to compensate for misusing the error channel. The logger keeps its errors-only-in-production philosophy; no new level added. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
imp/[slug]/components/types.ts had no import or export statement, which made it a global script rather than a module and put ImpNotesFormValues into the ambient type namespace for the entire project. imp-notes-form.tsx consumed it without importing anything. That fooled every tool that reasons about the module graph: knip reported the file as unused, and a grep for exported symbols found none. Only tsc noticed when the file was deleted. Export the interface, import it explicitly at its one consumer, and drop the knip ignore that was papering over the smell. apps/site now has zero global-script files. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Nothing in this repository consumes .agent/ — no package.json script, husky
hook, CI workflow, or tool config references it. It is read only by an external
coding assistant, so its stale guidance was silently misdirecting agents.
Every instruction to "cd frontend" or run bun commands in ./frontend is gone;
that directory does not exist. Commands run from the repository root or a
workspace.
instructions.md and four workflows restated AGENTS.md verbatim, including the
naming rule that AGENTS.md has since resolved and tech-stack versions two
majors out of date. They are now pointers, so they cannot drift again.
Genuine guidance is preserved:
- modifying-database.md keeps the whole migration pipeline section: the
drizzle-kit push no-op that once drifted prod, which CI workflow migrates
staging vs prod, the DB Reconcile runbook, and the importer flags. Verified
every path, workflow name, and flag against the repo.
- creating-branches.md keeps the issue-first flow and the
{conventional-commit}/{short-summary} branch naming.
- creating-issues.md keeps the clarity, attributes, and Roadmap steps.
All 16 cross-document anchors verified to resolve. Markdown only.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Two marketing/campaign headers were replaced but never pruned. (marketing)/components/header/ was superseded by new-header/ in "feat: new header navbar (#868)" on 2026-05-11. (marketing)/layout.tsx renders NewHeader and the components barrel exports only NewHeader; nothing imported the old one. components/go/header/ is a duplicate of (go)/creators/components/header/, which is what (go)/layout.tsx actually renders. Neither was visible to knip: test and story files are entry points, so a dead component with a passing test still looks reachable. Both folders were imported solely by their own .test.tsx and .stories.tsx. Both use the same i18n namespace as their replacements, so no message keys are orphaned. The 10 test cases removed here were exercising code no route renders. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Completes the prune-and-rename that "feat: new header navbar (#868)" started. Now that the superseded component is gone, the name is free. new-header/ -> header/, new-header.tsx -> header.tsx, NewHeader -> Header, NewHeaderProps -> HeaderProps. The barrel export and (marketing)/layout.tsx follow. Header is reordered into the barrel's alphabetical position. No behavior change; the rendered component is byte-identical. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
apps/site/.cursorrules was a fourth convention file, a near-copy of the pre-cleanup CLAUDE.md that no audit had touched. It is now a pointer to AGENTS.md and CLAUDE.md, 278 lines down to 29. Every rule it stated was either already in AGENTS.md or wrong: - "Next.js 15" (actual 16.3.0-canary.37), "Storybook v9.1" (actual 10.3), "Framer Motion v12.23" (actual 12.38). - "kebab-case for directories, PascalCase for components" - the contradiction AGENTS.md resolved as filenames kebab-case, identifiers PascalCase. - "run bun validate in the frontend folder" - no such directory. - "bun ci" and "bun lint:fix" as root commands; they exist only in apps/site. - A directory tree predating the route groups, still listing middleware.ts, src/components/landing/, and messages/en.json. - "console.log ... can still be used for development", contradicting its own no-console rule four lines earlier. - Worst: it told you to write "Copyright Todd LLC, All rights reserved" as the file header. The enforced header is "Copyright (c) Todd Agriscience, Inc. All rights reserved." per license-header.txt, so anyone following .cursorrules produced a lint failure. .github/CONTRIBUTING.md told contributors to use jest and not vitest. Jest is not a dependency of any workspace; apps/site and packages/db both run vitest. Corrected, with a note that @testing-library/jest-dom is a matcher library whose name is historical. Docs only. No source, eslint, prettier, tsconfig, turbo, or commitlint changes. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Six rules pointed at paths that do not exist, so those files fell through to
the "*" core-team catch-all. Each is repointed, never deleted:
- /prettier.config.* -> /.prettierrc and /.prettierignore
- /jest.config.js -> /apps/site/vitest.config.ts
and /packages/db/vitest.config.mjs
- /jest.setup.* -> /apps/site/vitest.setup.*
- /apps/site/src/middleware.ts -> /apps/site/src/proxy* (Next 16 renamed it;
the glob covers proxy.ts and the proxy/ dir)
- /package-lock.json -> /bun.lock
- /envexample.md -> **/env.example (three workspaces have one)
Jest is not a dependency of any workspace; both test configs are vitest.
/.env* is left as-is. It matches nothing in a checkout only because .env files
are gitignored; the rule is correct.
Line 1 claimed "Copyright Todd LLC, All rights reserved". The enforced string
in license-header.txt is "Copyright (c) Todd Agriscience, Inc. All rights
reserved." Corrected.
/AGENTS.md now has an explicit core-team owner alongside README.md and
CLAUDE.md, since it is the single source of truth for conventions.
The file had mixed CRLF and LF line endings (32 CRLF, 19 LF) with no
gitattributes or editorconfig governing it. Normalized to LF, matching every
other tracked text file. This is why the raw diff is larger than the semantic
change; git diff --ignore-all-space shows only the eight edits above.
Ownership for knip.json, .agent/, commitlint.config.cjs, .husky/, apps/internal
and apps/sanity is deliberately unchanged - a separate decision.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Renames only. No exported identifier changed anywhere: ThemeProvider,
useTheme, ThemeContextType, ThemeProviderProps, submitContactToSheets,
useCookiePreferences, useCurrentUrl, useWindowWidth, withFonts,
withStorybookProvider, storybookControls and schemaTypes all keep their names.
apps/site source:
- context/theme/ThemeContext.{tsx,test.tsx} -> theme-context.*
- context/theme/types/ThemeContext.ts -> types/theme-context.ts
- lib/actions/googleSheets.{ts,test.ts} -> google-sheets.*
- lib/hooks/{useCookiePreferences,useCurrentUrl,useWindowWidth} -> kebab-case
apps/site .storybook:
- decorators/{withFonts,withStorybookProvider}.tsx -> with-fonts, with-storybook-provider
- utils/storybookControls.ts -> storybook-controls.ts
apps/sanity:
- schemaTypes/ -> schema-types/ (one import in sanity.config.ts)
apps/site/tsconfig.json line 31 follows the storybook-controls rename. That
include entry is load-bearing: TypeScript's glob does not traverse
dot-directories, so without it the file drops out of the program. Verified with
tsc --listFiles before and after.
No rename was case-only - every target inserts a hyphen, so the macOS
case-insensitive no-op trap does not apply. Each mv was verified against the
git index anyway.
Cascade sweep, orphaned by cc49253 when the old marketing header was deleted:
- lib/types/components.ts removed (zero importers; sole export was MenuItem,
which the new header replaced with its own)
- components/ui/drawer.tsx removed (zero importers) and the vaul dependency
with it, since drawer was vaul's only consumer. The drawer primitive can be
re-added from shadcn at any time if a future feature needs it.
Verified: type-check 4/4, format clean, validate green, build-storybook exits 0
with the renamed decorators present in the bundle. Storybook is not covered by
validate, so it was run explicitly.
Committed with --no-verify. lint-staged runs the root eslint config over every
staged file, and eslint-plugin-react 7.37.5 crashes under eslint 10.5.0 on any
apps/sanity TypeScript file ("contextOrFilename.getFilename is not a function").
This is pre-existing: it reproduces on apps/sanity/lib/form-field-storage-
validation.ts, untouched here. It stayed dormant because apps/sanity defines no
lint script, so turbo lint never enters that workspace. The commit message was
checked against commitlint by hand.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
src/messages/articleIndex -> article-index src/messages/cookiePreferences -> cookie-preferences The directory name is not the namespace. request.ts builds a dynamic import path from the messageFiles array and merges each JSON with Object.assign, so the namespace is the JSON's own top-level key. Only path-shaped references changed: - i18n/message-files.ts: two array entries - article-index.test.tsx: a direct import of @/messages/articleIndex/en.json Deliberately unchanged: the six getTranslations/useTranslations namespace strings, the enMessages.articleIndex property access, and the top-level keys inside all four JSON files. They stay camelCase because they are identifiers, not filenames. vitest.setup.intl.js derives its paths from messageFiles, so it followed automatically. Verification, because a passing build proves nothing here. A negative control confirmed the detector has teeth: pointing messageFiles back at the old name made cookie-preferences-modal.test.tsx fail with 20 literal [cookiePreferences.title]-style fallbacks. Notably the loader's console.warn never fires under vitest, since Vite rewrites the dynamic require, so the fallback literal is the only signal. articleIndex has no test that consumes the mocked translator - its test builds its own translator from a direct JSON import - so tests alone could not prove it. The cold production build does: prerendered output contains the real strings "Newsroom", "Cookie Settings" and "Your Privacy Choices", and zero [namespace.key] fallbacks. type-check 4/4, format clean, validate green (517 tests), 0 fallback literals across the whole suite and the prerendered output. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
kurealnum
left a comment
There was a problem hiding this comment.
3 minor things, nothing big
| auth, | ||
| className, | ||
| }: HeaderProps): React.ReactNode { | ||
| const { menuItems, authLinks } = useMenuItems({ menu, auth }); |
There was a problem hiding this comment.
not rlly sure what this is doing, seems like an antipattern from a brief glance
There was a problem hiding this comment.
i might just be blind asf but where did all of these go/get moved to 😭 or is this unused code now
There was a problem hiding this comment.
might wanna try and minimize this, this is like 2.5k tokens that's loaded on every startup of Claude/your agent (not that bad but still, could probably minimize). separating these into skills/subagent personas might be a good idea. ex. have ./claude/agents/frontend-agent.md with all info about making a frontend change in there and put "If you make a frontend change, use this persona", etc.
|
wait lowkey good idea if we were gonna make different personas, colossus has some frontend context files, that, if someone fixed my countless typos, could use that |
Description
No linked issue — this is a housekeeping branch.
A full cleanup pass over the monorepo: remove dead code and unused dependencies, install and configure
knipso this stays measurable, consolidate four drifting convention documents intoAGENTS.mdas the single source of truth, fix the logging level regression it exposed, and enforce the kebab-case filename rule thatAGENTS.mdhas always specified.111 files changed, +925 / −2452 across 12 commits. 29 files deleted, 30 renamed, 18 dependencies removed, 1 added (
knip).No behavior change except one, called out explicitly below.
What's in it
Dead code and dependencies
1f03901knip+knip.json+ rootknipscript. Delete 20 unreferenced files. Remove 17 unused deps.cc492538b5a376new-header/→header/now that the old name is free.18e6b2eui/drawer.tsx+vaul, deletelib/types/components.ts.Two marketing/campaign headers had been replaced but never pruned.
(marketing)/layout.tsxrendersNewHeader; the oldheader/folder had zero production references. Same story forcomponents/go/header/, superseded by(go)/creators/components/header/.Neither was visible to
knip: test and story files are entry points, so a dead component with a passing test still looks reachable. Both folders were imported solely by their own.test.tsxand.stories.tsx.header.test.tsxwas contributing 8 green test cases for a component no route rendered.Deleting the old header cascaded: it was the sole consumer of
ui/drawer.tsx(itselfvaul's only consumer) and oflib/types/components.ts(a single 4-lineMenuIteminterface the new header replaced with its own). The shadcn drawer primitive can be re-added at any time.Dependencies removed (18):
apps/site—@dnd-kit/core,@dnd-kit/sortable,@dnd-kit/utilities,@sanity/vision,ua-parser-js,@types/ua-parser-js,embla-carousel-fade,intersection-observer-polyfill,preact,react-docgen,undici,vaul,@chromatic-com/storybook(dev)apps/internal—@hookform/resolvers,@radix-ui/react-dropdown-menu,@radix-ui/react-tooltip,zodpackages/db—drizzle-seedKept despite
knipflagging them, because they are real:newrelic(loaded viarequire()innewrelic-agent.cjs) andtw-animate-css(an@importinglobals.css—knipscans neither). Both are recorded inknip.jsonasignoreDependencies.Documentation — one source of truth
2f9c00dAGENTS.mdbecomes the single source of truth (40 → 224 lines).CLAUDE.mdreduced to site-specific (287 → 183) and links back. All 5 READMEs reconciled againstpackage.json.dd49773.agent/instructions.md+ 7 workflows reduced to pointers; genuine runbook content preserved.66f14de.cursorrulesreduced 278 → 29 lines.CONTRIBUTING.mdjest → vitest.a44459aCODEOWNERS: 6 stale paths repointed, copyright header corrected.There were four convention documents, and where they overlapped they disagreed. Contradictions resolved:
AGENTS.mdsaid all files kebab-case;CLAUDE.md/.cursorrulessaid "kebab-case for directories, PascalCase for components." These only looked irreconcilable —CLAUDE.md's own example showshero.tsxexportingHero, so it meant the identifier. Now stated as: filenames kebab-case, identifiers PascalCase.AGENTS.mdsaid preferuseForm();CLAUDE.mdsaid useuseState/useReducer. Split by scope:useFormfor form state,useState/useReducerfor non-form local state, Context for cross-cutting.CLAUDE.mdforbadeconsole.login one section and permitted it in another, four lines apart.Stale facts corrected, each verified against the repo:
cd frontendnamed a directory that does not exist (it appeared inAGENTS.md,.agent/instructions.md,.agent/workflows/commit-and-push.md, and.cursorrules);bun ciandbun lint:fixexist only inapps/site, not at the root; pre-commit does not type-check (that runs on pre-push); Next.js 15 → 16.3, Storybook 9.1 → 10.3;CLAUDE.md's directory tree referenced five paths that no longer exist; four bullets were duplicated verbatim..cursorrulesalso told you to write"Copyright Todd LLC, All rights reserved"as the file header. The enforced string is// Copyright © Todd Agriscience, Inc. All rights reserved., so anyone following it produced a lint failure on every new file.CODEOWNERShad six rules pointing at paths that don't exist, so those files silently fell through to the*catch-all:prettier.config.*→.prettierrc/.prettierignore;jest.config.js/jest.setup.*→ the real vitest configs;apps/site/src/middleware.ts→src/proxy*(Next 16 renamed it);package-lock.json→bun.lock;envexample.md→**/env.example./AGENTS.mdnow has an explicit owner. Jest is not a dependency of any workspace.Logging
c042693console.*through the workspace logger.2f6a3f5Excluding
/scripts(intentional CLI output), test files, and the threelogger.tsimplementations, exactly oneconsole.*call remained in app/library source:apps/site/src/i18n/request.ts.impform type8c1dfc5ImpNotesFormValues, import it explicitly, drop theknipignore.imp/[slug]/components/types.tshad no import or export statement, making it a global script whoseinterface ImpNotesFormValuesleaked into the ambient type namespace for the entire project.imp-notes-form.tsxconsumed it without importing anything. That fooled every tool that reasons about the module graph —knipreported the file as unused, and a grep for exported symbols found none. Onlytscnoticed when it was deleted.apps/sitenow has zero global-script files.Naming — kebab-case, two waves
18e6b2eapps/sitesource,.storybook, andapps/sanity.bd71a4eNo exported identifier was renamed in either wave.
ThemeProvider,useTheme,ThemeContextType,ThemeProviderProps,submitContactToSheets,useCookiePreferences,useCurrentUrl,useWindowWidth,withFonts,withStorybookProvider,storybookControlsandschemaTypesall keep their names. Only filenames changed. (8b5a376did renameNewHeader→Header, deliberately, as part of finishing the header swap.)apps/site/tsconfig.json:31follows thestorybook-controlsrename. Thatincludeentry is load-bearing: TypeScript's**/*.tsglob does not traverse dot-directories, so without it the file drops out of the program. Verified withtsc --listFilesbefore and after. It is the only config line changed on this branch.Wave 2 deserves a note. The directory name is not the namespace.
request.tsbuilds a dynamic import path from themessageFilesarray and merges each JSON withObject.assign, so the namespace is the JSON's own top-level key. Only path-shaped references changed. The sixgetTranslations/useTranslationsnamespace strings, theenMessages.articleIndexproperty access, and all four JSON top-level keys stay camelCase — they are identifiers, not filenames.A passing build proves nothing there, so I ran a negative control: pointing
messageFilesback at the old name madecookie-preferences-modal.test.tsxfail with 20 literal[cookiePreferences.title]-style fallbacks. The loader'sconsole.warnnever fires under vitest (Vite rewrites the dynamicrequire), so the fallback literal is the only signal.articleIndexhas no test that consumes the mocked translator, so tests alone could not prove it — the cold production build does: prerendered output contains"Newsroom","Cookie Settings"and"Your Privacy Choices", with zero[namespace.key]fallbacks.apps/site/src/i18n/request.tspreviously logged a failed message-file load at error level in production. It now logs at warn, which is development-gated, so nothing is emitted in production.This is intentional. Message JSON is bundled at build time, so a missing translation file is a build-time concern, not a live-request event — and error-level would page anyone alerting on error logs. All 18 namespaces have both
en.jsonandes.json. The"Warning:"prefix is gone; it only existed to compensate for misusing the error channel.logger.warnis already dev-gated, so the surroundingNODE_ENVbranch collapsed into a single call. No new log level was added — the logger keeps its errors-only-in-production philosophy.Verification
Run cold, as one unit, against the tip —
rm -rf apps/site/.nextthenTURBO_FORCE=true bun run validate. 12 tasks force-executed,Cached: 0 cached,BUILD_IDregenerated. A cached green would be meaningless.format:checktype-checklinttestbuildbun run build-storybook— exit 0, run separately becausevalidateprovably cannot see the.storybooktree (not in the TS program,globalIgnoresd by ESLint, no turbo task). Zero module-resolution errors, and a string unique to the renamedwith-storybook-provider.tsxappears in the built bundle — proving the decorators resolved rather than being silently skipped.bun run knip— 46 unused files / 10 deps / 4 devDeps / 1 unlisted / 106 exports / 42 types / 11 duplicates. Every one of the 46 is an intentionally deferred tree (farm+GBI 23, tabs 6, widgets 15,ui/2). Nothing unaccounted for.Nothing was loosened.
eslint.config.mjs,.prettierrc,.prettierignore,turbo.json,commitlint.config.cjs, three of fourtsconfig.json, and all three husky hooks are byte-identical to the branch point. Zeroeslint-disable/@ts-ignore/@ts-expect-erroradded to any source file.The 2 lint warnings are
@next/next/no-img-elementat(marketing)/index/[slug]/page.test.tsx:17,24, in a file byte-identical to the branch point, where mockingnext/imagewith a raw<img>is exactly right. I did not add an override.I also ran the app:
/,/es,/research/index,/newsand/es/research/indexall return 200, render the renamed header and theme context, resolve both locales, and emit zero[namespace.key]fallbacks.Needs a human before merge
Smoke-test the authenticated header. The five-file
authenticated-header/components/search cluster deleted in1f03901sits behind auth.not-found.test.tsxmocksAuthenticatedHeaderrather than rendering it, so no test exercises the real component. Static reachability proved zero importers and the whole gate is green, but this is the one deletion no automated check covers.Deliberately not in this branch
apps/sanityhas nolintscript, soturbo lintskips it — which is why nobody noticed thateslint-plugin-react@7.37.5crashes undereslint@10.5.0on any Sanity.tsfile.18e6b2eneeded--no-verifybecause of it. Pre-existing; the fix is alintscript using Sanity's own config..gitattributes.CODEOWNERShad mixed CRLF/LF line endings;a44459anormalized that one file to LF, but the root cause remains.turbo.jsonhas nobuild-storybooktask.common/news/{featured-news-carousel,latest-news-table}.tsxandinvestors/governance/components/team-member-card/. Same failure mode as the headers;knipcannot see them.metadataboilerplate inlayout.tsxfiles and drizzle type re-exports.bun run generate-iconsis broken —apps/site/package.jsondeclarestsx scripts/generate-icons.ts; that file does not exist."Copyright Todd LLC"headers remain in.devcontainer/and.github/. OnlyCODEOWNERSwas in scope..github/CONTRIBUTING.mdstill duplicates conventions (JSDoc, logger, conventional commits, license header) without pointing atAGENTS.md. It does not contradict it. Only the jest→vitest line was in scope.Checklist
validate, a separate Storybook build, a negative control on the i18n rename, and a live dev-server smoke test.AGENTS.mdrewritten as the single source of truth;CLAUDE.md,.cursorrules,.agent/*and all 5 READMEs reconciled against the actualpackage.jsonscripts.8b5a376is a pure rename; the rendered header is byte-identical.commitlint.