Skip to content

refactor: remove duplicated declarations and unreferenced code (-1,819 lines) - #60

Open
fathiraz wants to merge 6 commits into
mainfrom
chore/ponytail-cleanup
Open

refactor: remove duplicated declarations and unreferenced code (-1,819 lines)#60
fathiraz wants to merge 6 commits into
mainfrom
chore/ponytail-cleanup

Conversation

@fathiraz

@fathiraz fathiraz commented Aug 8, 2026

Copy link
Copy Markdown
Owner

Why

The codebase grew through several architecture migrations that were additive — the old code
stayed and each new layer wrapped it. The result was a repo that declared the same message
contract twice, wrapped 36 octicons in 35 identical hand-written wrappers, inlined one sx
preset across 15 files while the shared helper for it already existed, and shipped 234 lines of
Effect Schema with zero importers.

This PR removes the accumulated duplication without changing any user-visible behaviour.

−1,819 lines from src/ (32,384 → 30,565), 17 files deleted, 5 dependencies dropped.

What changed

Five commits, each independently green and revertible.

chore: remove unreferenced code and dead exports

Code nothing referenced, verified by grep across src/, scripts/, config files and CI:

  • schemas-github.ts (234 lines) — zero importers; every GraphQL call goes through gql(),
    which hardcodes Schema.Unknown
  • renderPatError + its 5-branch Match block — only its own test called it; token-setup.tsx
    uses buildPatError, which is the better implementation (scoped token URL, expired-vs-invalid)
  • effect-test-helpers.ts — its sole consumer destructured the layer and discarded the recorded
    calls array, so the whole recording apparatus was dead
  • SearchSelectPanel debug apparatus, TokenSetupCard's mode/onOpenOptions (its only call
    site passes no props), getFields threaded through the sprint UI (both terminal consumers
    destructured it as _getFields), recentAssignees (never passed)
  • src/assets/images/old/ — 7 tracked binaries, 2.3 MB, referenced nowhere
  • 13 package.json scripts nothing invokes — CI calls pnpm wxt submit and the coverage script
    directly, not via these aliases

refactor: collapse duplicated icon and button-motion declarations

src/ui/icons.tsx contained zero hand-drawn SVGs — it imported 36 icons from
@primer/octicons-react and re-exported each behind an identical 3-line wrapper, 35 times.
Replaced with one factory. No call-site changes across the 28 consuming files. 217 → 93 lines.

Also replaced 16 byte-identical inline copies of the button-motion block with the
primerCss.buttonMotion() preset that already existed and already had 10 callers.

test: replace the custom toEqualValue matcher with vitest's toEqual

effect-assert.ts registered a matcher that wrapped values in Effect Data.* containers to get
deep equality — which toEqual already does. Verified rather than assumed: swapped all 39 call
sites and re-ran the suite. Deleting it empties vitest.setup.ts, so suite setup drops to 0 ms.

refactor: inline single-caller Effect service wrappers

project-service.ts, cache-service.ts, services.ts and runtime-ext.ts existed only so four
call sites could write yield* svc.foo() instead of yield* Effect.promise(() => foo()). Each
wrapped an already-existing async helper and had exactly one consumer.

refactor: replace derived message schemas with a hand-written ProtocolMap

schemas-messages.ts (688 lines) declared the message contract a second time. Its docstring
claimed handlers validated payloads with Schema.decodeUnknownSync/encodeSync — a repo-wide
grep found those calls in no handler. Six payload types were declared twice, and every
consumer imported the hand-written twin from messages.ts, never the schema.

chore: drop unused dependencies

@effect/platform-browser, @resvg/resvg-js, @types/marked, @vitejs/plugin-react,
vite-node — all with no source references, confirmed by a clean production build.

How equivalence was proven, not assumed

The ProtocolMap rewrite is the one change tsc alone cannot fully guarantee: method parameters
are bivariant, so a widened input (string where the schema said 'a' | 'b') would slip
through a plain A extends B check.

A temporary type-level scaffold compared each of the 35 entries' input and output mutually,
with tuple-wrapped conditionals so unions don't distribute. It was negative-tested — widening
bulkClose's reason to string made the build fail by name (Type 'true' is not assignable to type '"bulkClose"') — then removed once both sides matched exactly.

Deliberately not cut

  • Tippy.jsdesign-system/rgp/MASTER.md:184 makes it canonical and bans Primer's <Tooltip>
  • @primer/live-region-element — looks unused, but wxt.config.ts aliases it to a local stub
  • SelectionControl's variant prop — flagged as dead by the audit, but
    checkbox-portal-host.tsx does pass it
  • 9 near-miss buttonMotion copiesmakePreset shallow-merges, so an override supplying
    its own hover rule would replace the base and silently drop transform
  • The 8 per-file test render helpers — half wrap in ThemeProvider/BaseStyles, half render
    raw, and return shapes differ. Similar-looking, not duplicated.
  • Everything in the anti-abuse path: sequential queue, sleep(1000) between mutations,
    403/429 Retry-After handling

Test plan

Gate Before After
pnpm typecheck clean clean
pnpm lint 0 errors, 56 warnings 0 errors, 48 warnings
pnpm format clean clean
pnpm test 424 pass, 1 FAIL 408 pass, 0 fail
pnpm build green green (3.08 MB)

Test count fell 425 → 408 because 17 tests were deleted alongside the dead code they covered —
they asserted that exported strings were non-empty strings, that deliberately-empty functions
don't throw, and that Effect's Schema round-trips.

The pre-existing pnpm test failure is fixed: bulk-transfer-modal.test.tsx › renders count in title was timing out at 5 s while costing ~500 ms of real work — worker contention across the
43-file parallel suite. Raised testTimeout to 15 s.

Verified in a real browser

Loaded the built dist/chrome-mv3 unpacked in Chrome. Service worker starts with no errors; the
options page (TokenSetupCard, gear/check icons) and popup (eye icon, keyboard chips) both render
correctly with zero console errors.

Still to do before merge

  • Full 12-verb regression sweep on a live project board (needs an authenticated session and a
    configured PAT; bulk transfer additionally needs a destination repo)

Summary by cubic

Removes unused code and duplicated declarations to shrink the codebase with no user-visible changes. Net −1,819 LOC, 17 files deleted; build/typecheck/tests stay green (408 pass).

  • Refactors

    • Deleted dead modules, props, tests, and old images; simplified coverage script usage.
    • Replaced 36 icon wrappers with one factory; kept named exports; deduped button motion via primerCss.buttonMotion().
    • Dropped custom matcher and setup; switched tests to toEqual; increased Vitest testTimeout to 15s to deflake.
    • Inlined single-caller Effect service wrappers; replaced Effect.tryPromise(...).orDie with Effect.promise(...) in handlers.
    • Replaced schema-derived message typing with a hand-written ProtocolMap; removed unused schema files and snapshot tests.
  • Dependencies

    • Removed unused: @effect/platform-browser, @resvg/resvg-js, @types/marked, @vitejs/plugin-react, vite-node.

Written for commit d79010f. Summary will update on new commits.

Review in cubic

Deletes code that nothing in the repo references, verified by grep across
src/, scripts/, config files and CI workflows:

- src/lib/schemas-github.ts (234 lines) — zero importers; every production
  GraphQL call goes through gql(), which hardcodes Schema.Unknown
- renderPatError + its 5-branch Match block in errors.ts — only its own test
  called it; token-setup.tsx uses its own buildPatError, which is the better
  implementation (scoped token URL, expired-vs-invalid distinction)
- src/lib/effect-test-helpers.ts — its sole consumer destructured the layer
  and discarded the recorded calls array, so the whole recording apparatus
  was dead; inlined the two lines that test actually uses
- SearchSelectPanel debug apparatus (debugName prop, log callback,
  summarizeDebugValue, 10 call sites) — console.log-based instrumentation
- src/ui/step-indicator.tsx and src/features/field-helpers.ts — one export,
  one caller each; inlined into that caller
- src/background/bulk-handlers.ts — 13 lines calling four register functions
- TokenSetupCard mode/onOpenOptions props — its only call site passes no
  props, so every compact branch and the secondary button were unreachable
- getFields threaded through the sprint UI — both terminal consumers already
  destructured it as _getFields
- recentAssignees prop on BulkRandomAssignFlyout — never passed
- primerCss.borderedContainer and card (no callers); footerBorder was a
  byte-identical alias of divider
- duplicated fmt/daysLeft in sprint-progress-view — sprint-utils exports both
- duplicated 30-line "Sprint settings" button in sprint-table-widget
- clearMousedownPath, logger.info, BulkRandomAssignData — no callers
- 13 package.json scripts nothing invokes (CI calls `pnpm wxt submit` and
  the coverage script directly, not via these aliases)
- src/assets/images/old/ — 7 tracked binaries, 2.3 MB, referenced nowhere
- update-coverage-badge.mjs dual-mode: only the json-summary path is used

Also raises vitest testTimeout to 15s: bulk-transfer-modal's render test
costs ~500ms of work but exceeded the 5s default under worker contention.

typecheck clean, 413 tests pass, lint 0 errors (56 -> 52 warnings).
src/ui/icons.tsx contained zero hand-drawn SVGs: it imported 36 icons from
@primer/octicons-react and re-exported each behind an identical 3-line
wrapper, 35 times. Replaced with one `icon()` factory and one export per
glyph. No call-site changes across the 28 consuming files; still static
named exports, so tree-shaking is unaffected. 217 -> 93 lines.

The `Octicon` adapter's runtime `typeof size === 'string'` branch was dead —
every call site passes a numeric size — but the *type* must stay wide,
because Primer's TextInput.Action `icon` prop requires a component accepting
its own Size union. Kept the union, dropped the unreachable branch.

Also replaced 16 byte-identical inline copies of the button motion block
with the primerCss.buttonMotion() preset that already existed in
primer-css-helper.ts and already had 10 callers.

Left the 9 near-miss copies alone: makePreset shallow-merges, so an override
supplying its own '&:hover:not(:disabled)' would replace the base rule and
silently drop the transform. Those need a different fix, not this one.

typecheck clean, 413 tests pass, lint 0 errors (52 -> 51 warnings).
src/lib/effect-assert.ts registered a `toEqualValue` matcher that recursively
wrapped values in Effect Data.* containers so Equal.equals would do a deep
comparison — something vitest's built-in toEqual already does.

Verified rather than assumed: swapped all 39 call sites to toEqual and ran
the suite. 413/413 still pass, so the custom matcher was buying nothing. It
was in fact strictly weaker for Errors, since wrap() collapsed them to
{ name, message }.

Deleting it empties vitest.setup.ts (its only job was registering the
matcher), so that file and the setupFiles entry go too. Suite setup time
drops from ~11.7s to 0.

Left the eight per-file render helpers alone: they look alike but differ in
substance — half wrap in ThemeProvider/BaseStyles and half render raw, and
the return shapes differ (container vs {container, root} vs added
find/findAll). That is similar-looking code, not duplication.
project-service.ts, cache-service.ts, services.ts and runtime-ext.ts existed
only so four call sites could write `yield* svc.foo()` instead of
`yield* Effect.promise(() => foo())`. Each wrapped an async helper that
already existed, and each had exactly one consumer.

Replaced with four direct calls:
  field-handlers      getProjectFieldsData, resolveProjectItemIdsWithTitles
  hierarchy-handlers  getOrCachePreview, getOrCacheHierarchy

and dropped provideBackground from those runHandler calls.

Also collapsed the remaining
  Effect.tryPromise({ try: fn, catch: e => e as unknown }).pipe(Effect.orDie)
sites to Effect.promise(fn) — identical semantics, since both end with the
rejection as a fiber defect that runHandler's cause printer surfaces.

typecheck clean, 413 tests pass, lint 0 errors.
…lMap

schemas-messages.ts declared the message contract a second time — 688 lines
of Effect Schema whose only production consumer was a type-only import in
messages.ts. Its docstring claimed background handlers validated payloads
with Schema.decodeUnknownSync/encodeSync; a repo-wide grep found those calls
in no handler. The validation it documented did not happen.

Six payload types were declared twice (IssueRelationshipData,
DuplicateItemPlan, ItemPreviewData, HierarchyData, SprintProgressData,
IssueSearchResultData) and every consumer imported the hand-written twin from
messages.ts, never the schema. Three type-level helpers (SchemaInput,
SchemaOutput, DeepMutable) existed only to undo the readonly that Schema
introduced.

The replacement ProtocolMap is built from the interfaces messages.ts already
declared. Equivalence was proven, not assumed: a temporary scaffold compared
each of the 35 entries' input and output types mutually, using tuple-wrapped
conditionals so unions don't distribute and so method-parameter bivariance
can't hide a widened type. Negative-tested by widening bulkClose's `reason`
to string, which failed the check by name. The scaffold is removed in this
commit now that both sides match exactly.

Deleting it orphans schemas-errors.ts and schemas-storage.ts (their only
importer) and schema-snapshots.test.ts, which round-tripped schemas nothing
decodes with — it exercised effect/Schema, not this repo.

typecheck clean, 408 tests pass, lint 0 errors (51 -> 48 warnings).
Removed five packages with no source references, verified by grep across
src/, scripts/ and every config file, then confirmed by a clean production
build:

- @effect/platform-browser  never imported anywhere
- @resvg/resvg-js           no references (leftover from icon generation)
- @types/marked             marked has shipped its own types since v4
- @vitejs/plugin-react      supplied by @wxt-dev/module-react
- vite-node                 supplied by wxt

Kept @primer/live-region-element: it looks unused in src/ but wxt.config.ts
aliases it to src/lib/primer-live-region-stub.ts to avoid a customElements
error in content scripts, so the package name has to resolve.

Also removed the minimumReleaseAgeExclude block from pnpm-workspace.yaml —
it pinned exclusions for a minimumReleaseAge policy configured nowhere.

pnpm install / format / test / lint / typecheck all pass; wxt build green.
@ecc-tools

ecc-tools Bot commented Aug 8, 2026

Copy link
Copy Markdown

Analyzing 200 commits...

@ecc-tools

ecc-tools Bot commented Aug 8, 2026

Copy link
Copy Markdown

Analysis Complete

Generated ECC bundle from 6 commits | Confidence: 70%

View Pull Request #61

Repository Profile
Attribute Value
Language TypeScript
Framework React
Commit Convention conventional
Test Directory colocated
Changed Files (71)
Metric Value
Files changed 71
Additions 558
Deletions 2601

Top hotspots

Path Status +/-
src/lib/schemas-messages.ts removed +0 / -688
src/lib/messages.ts modified +258 / -7
src/ui/icons.tsx modified +56 / -180
src/lib/schemas-github.ts removed +0 / -234
pnpm-lock.yaml modified +0 / -166

Top directories

Directory Files Total changes
src/lib 27 1806
src/ui 5 412
src/features 16 372
src/background 8 309
. 4 199
Analysis Depth Readiness (evidence-backed, 43%)

ECC Tools uses this to decide whether recommendations should stay at commit-history/setup guidance or expand into CI, security, harness, reference-set, AI-routing, and team backlog work.

Area Status Evidence / Next Step
Commit history Ready 6 commits sampled
CI/CD signals Ready .github/workflows/coverage.yml, vitest.config.ts
Security evidence Missing Add AgentShield, audit, SARIF, SBOM, or security review evidence so recommendations can cover security posture.
Harness configuration Missing Add Claude, Codex, OpenCode, Zed, dmux, MCP, plugin, or cross-harness config evidence for harness-agnostic recommendations.
Reference/eval evidence Missing Add fixtures, golden traces, reference sets, or evaluator benchmarks so deeper recommendations have regression evidence.
AI routing and cost controls Ready src/features/token-setup.tsx
Team handoff and project tracking Missing Add roadmap, runbook, project, Linear, or follow-up tracking docs so generated work can land in a team queue.
Reference Set Readiness (0/7, 0%)
Area Status Evidence / Next Step
Deep analyzer corpus Missing Add analyzer fixture, golden, benchmark, or reference-set files that can catch analyzer regressions.
RAG/evaluator comparison Missing Add retrieval or evaluator reference-set comparison fixtures with expected ranking behavior.
PR salvage/review corpus Missing Add stale-PR, review-thread, reopen-flow, or salvage reference cases for queue cleanup automation.
Discussion triage corpus Missing Add public discussion triage fixtures, golden cases, or reference sets for informational, answered, and no-response classifications.
Harness compatibility Missing Add cross-harness, adapter-compliance, or harness-audit evidence for Claude, Codex, OpenCode, Zed, dmux, and agent surfaces.
Security evidence Missing Attach security evidence such as SBOMs, SARIF, audit reports, or AgentShield evidence packs.
CI failure-mode evidence Missing Add captured CI failure logs, dry-run fixtures, or troubleshooting docs for common workflow failure modes.
Likely Future Issues (4)
Severity Signal Why it may show up
MEDIUM Runtime config changes may ship without example or template updates 1 runtime config paths changed; 0 example or template config files changed
MEDIUM User-facing UI changes may ship without browser coverage 5 user-facing UI paths changed; 0 browser or e2e coverage files changed
MEDIUM Cost or token-risk changes may ship without budget evidence 1 cost/token-risk paths changed; 0 budget, usage, or cost validation artifacts changed
MEDIUM CI workflow changes may ship without failure-mode evidence 2 CI/test-runner paths changed; 0 CI failure-mode evidence artifacts changed
  • Runtime config changes may ship without example or template updates: The PR changes runtime config or deployment settings but does not update any obvious example env file or config template.
  • User-facing UI changes may ship without browser coverage: The PR changes components, pages, or other user-facing UI files without touching any obvious browser or end-to-end coverage.
  • Cost or token-risk changes may ship without budget evidence: The PR changes AI routing, usage, token budget, or model-call surfaces without touching obvious budget, usage-limit, or cost regression evidence.
  • CI workflow changes may ship without failure-mode evidence: The PR changes CI workflows or test-runner entrypoints without touching CI failure fixtures, captured logs, troubleshooting notes, or regression evidence.
Suggested Follow-up Work (4)
Type Suggested title Targets
PR chore: sync config templates for vitest.config.ts vitest.config.ts
PR test: add browser coverage for src/ui/icons.tsx + src/ui/modal-shell.tsx src/ui/icons.tsx, src/ui/modal-shell.tsx
PR test: add budget evidence for src/features/token-setup.tsx src/features/token-setup.tsx
PR ci: add failure-mode evidence for .github/workflows/coverage.yml + vitest.config.ts .github/workflows/coverage.yml, vitest.config.ts
  • chore: sync config templates for vitest.config.ts: Backfill example env files or config templates before a fresh setup drifts from the shipped runtime surface.
  • test: add browser coverage for src/ui/icons.tsx + src/ui/modal-shell.tsx: Backfill browser coverage before another user-facing UI change lands on the touched surface.
  • test: add budget evidence for src/features/token-setup.tsx: Backfill cost, token, or usage-limit validation before another model-routing change lands on the touched surface.
  • ci: add failure-mode evidence for .github/workflows/coverage.yml + vitest.config.ts: Backfill CI failure-mode evidence before another workflow or test-runner change lands on the touched surface.

Copy-ready bodies

chore: sync config templates for vitest.config.ts

## Summary
- Update the example env files, sample configs, or deployment templates that should mirror the changed runtime configuration surface.

## Why
- Backfill example env files or config templates before a fresh setup drifts from the shipped runtime surface.

## Touched paths
- `vitest.config.ts`

## Validation
- Update the repo example env file or config template that should reflect the new runtime settings.
- Run the setup, boot, or deployment validation flow that depends on the changed config surface.

test: add browser coverage for src/ui/icons.tsx + src/ui/modal-shell.tsx

## Summary
- Add browser or end-to-end coverage for the recently changed user-facing surface.

## Why
- Backfill browser coverage before another user-facing UI change lands on the touched surface.

## Touched paths
- `src/ui/icons.tsx`
- `src/ui/modal-shell.tsx`

## Validation
- Add or extend browser / e2e coverage for the changed component, page, or flow.
- Exercise the visible user journey that depends on the touched UI surface.

test: add budget evidence for src/features/token-setup.tsx

## Summary
- Add budget or usage-limit validation for the recently changed AI routing or model-call surface.

## Why
- Backfill cost, token, or usage-limit validation before another model-routing change lands on the touched surface.

## Touched paths
- `src/features/token-setup.tsx`

## Validation
- Add or extend budget, token, usage-limit, or model-routing regression coverage for the changed path.
- Verify the route still enforces plan limits, retry caps, fallback behavior, or explicit cost controls.

ci: add failure-mode evidence for .github/workflows/coverage.yml + vitest.config.ts

## Summary
- Add CI failure-mode evidence for the recently changed workflow or test-runner surface.

## Why
- Backfill CI failure-mode evidence before another workflow or test-runner change lands on the touched surface.

## Touched paths
- `.github/workflows/coverage.yml`
- `vitest.config.ts`

## Validation
- Add or update a CI failure fixture, captured failing log, troubleshooting note, workflow dry-run evidence, or regression test for the changed CI/test-runner behavior.
- Run the affected workflow or test-runner entrypoint locally or in CI and record pass/fail evidence.
Detected Workflows (1)
Workflow Description
refactoring Code refactoring and cleanup workflow
Generated Instincts (12)
Domain Count
git 2
code-style 3
architecture 1
testing 5
workflow 1

After merging, import with:

/instinct-import .claude/homunculus/instincts/inherited/refined-github-projects-instincts.yaml

Files

  • .claude/ecc-tools.json
  • .claude/skills/refined-github-projects/SKILL.md
  • .agents/skills/refined-github-projects/SKILL.md
  • .agents/skills/refined-github-projects/agents/openai.yaml
  • .claude/identity.json
  • .codex/config.toml
  • .codex/AGENTS.md
  • .codex/agents/explorer.toml
  • .codex/agents/reviewer.toml
  • .codex/agents/docs-researcher.toml
  • .claude/homunculus/instincts/inherited/refined-github-projects-instincts.yaml
  • .claude/commands/refactoring.md

ECC Tools | Everything Claude Code

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor auto review

No actionable issues found on changed lines.

No actionable issues found.

Generated automatically when this PR was submitted using Cursor CLI with --model auto.

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

1 issue found across 71 files

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="src/ui/icons.tsx">

<violation number="1" location="src/ui/icons.tsx:48">
P2: Consumers using the previously supported CSS-length or numeric-string `size` values can no longer type-check, and the runtime sizing fallback has been removed. Preserving the `number | string` prop and equivalent conversion/wrapper logic would maintain the existing icon sizing contract.</violation>
</file>

Reply with feedback, questions, or to request a fix.

Re-trigger cubic

Comment thread src/ui/icons.tsx

export type IconProps = {
size?: number | string
size?: OcticonSize

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: Consumers using the previously supported CSS-length or numeric-string size values can no longer type-check, and the runtime sizing fallback has been removed. Preserving the number | string prop and equivalent conversion/wrapper logic would maintain the existing icon sizing contract.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At src/ui/icons.tsx, line 48:

<comment>Consumers using the previously supported CSS-length or numeric-string `size` values can no longer type-check, and the runtime sizing fallback has been removed. Preserving the `number | string` prop and equivalent conversion/wrapper logic would maintain the existing icon sizing contract.</comment>

<file context>
@@ -30,188 +30,64 @@ import {
+
 export type IconProps = {
-  size?: number | string
+  size?: OcticonSize
   color?: string
-}
</file context>

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant