Skip to content

chore(lint): turn on the rules that would have caught the dead code - #7037

Merged
waleedlatif1 merged 1 commit into
stagingfrom
deslop-next
Aug 24, 2026
Merged

chore(lint): turn on the rules that would have caught the dead code#7037
waleedlatif1 merged 1 commit into
stagingfrom
deslop-next

Conversation

@waleedlatif1

Copy link
Copy Markdown
Collaborator

Three lint rules were "off", so nothing enforced them. I measured each, fixed the sites, and enabled them where the cost is bounded.

What changed

Rule Violations Action
performance/noAccumulatingSpread 2 fixed both → enabled repo-wide
correctness/noUnusedVariables + noUnusedFunctionParameters 633 repo-wide, 6 under packages/ fixed the 6 → enabled at error for packages/**
suspicious/noDocumentCookie 3 not enabled — see below

The accumulating spreads were real

Both are O(n²) reducers, now Object.fromEntries:

  • stores/workflows/workflow/store.ts — rebuilds a block's subBlocks on every block duplication
  • secrets-manager.tsx — rebuilds a Record from every workspace env var

Why packages/** and not everywhere

apps/sim carries 627 of the 633. That is a sweep of its own, and a rule switched on with 627 outstanding warnings teaches people to scroll past it. Scoped to packages/**, the cost was 6 fixes and the coverage is 979 files, permanently.

This is the rule class whose absence let #7019 happen — eleven unread loggers, a whole unimported file, write-only locals. No gate could see any of it.

One fix is narrower than it looks

Two of the six were isWorkflowRunning in workflow-renderer: destructured, never read, in both the block and subflow views. My first instinct was to delete the prop — that was wrong twice over, and type-check caught it:

  • A test passes it (this package type-checks its tests; apps/sim doesn't)
  • The app passes it, from workflow-block.tsx:1243 and subflow-node.tsx:78

Its TSDoc claimed it "holds every block's action swell open." Nothing reads it, so that behavior does not exist today. Implementing it is a UX call — there is adjacent logic deliberately not pinning the toolbar during a handoff — and deleting the prop breaks two callers.

So only the unused binding goes, the prop stays in the interface, and the TSDoc now states the truth instead of describing behavior that isn't there. Wiring it up or dropping it from the callers is a follow-up for someone who knows the intended UX.

Not enabled

  • noDocumentCookie (3 sites, all in the sidebar store) — its fix is the CookieStore API, which is a browser-support decision, not a lint cleanup.
  • useExhaustiveDependencies — 384 errors. Noted, not attempted.

Verification

  • All 26 workspaces type-check
  • bun run lint:check exits 0
  • Both enabled rule sets report zero across their scopes
  • 113 + 14 + 332 tests pass across workflow-renderer, workflow-persistence, stores/workflows, and settings
  • Confirmed the rule can fail: reintroducing the spread turns lint:check red, restoring it goes green

One pre-existing suppressions/unused warning in shell-layout.test.ts is untouched — it is on staging too and unrelated.

Three rules were off, so nothing enforced them. Measured, fixed the sites, and
enabled them where the cost is bounded.

`noAccumulatingSpread` — 2 violations, both real O(n²) reducers, both now
`Object.fromEntries`. One duplicates a block's subBlocks on every block
duplication; the other rebuilds a Record from every workspace env var. Enabled
repo-wide.

`noUnusedVariables` / `noUnusedFunctionParameters` — 633 repo-wide, but only 6
under `packages/`. Fixed those 6 and enabled both at error for `packages/**` via
an override, which permanently covers 979 files. `apps/sim`'s remaining 627 are
left deliberately: that is a sweep of its own, and a rule enabled with 627
outstanding warnings teaches people to ignore it.

This is the class of rule whose absence let the dead code in #7019 accumulate —
eleven unread loggers, a whole unimported file, write-only locals — none of which
any gate could see.

Two of the six were in `workflow-renderer`, where the fix is narrower than it
looks. `isWorkflowRunning` is destructured-but-unread in both the block and
subflow views, and the app passes it from `workflow-block.tsx` and
`subflow-node.tsx`. Its TSDoc claimed it "holds every block's action swell open";
nothing reads it, so that behavior does not exist. Removing the prop breaks the
callers and implementing it is a UX decision — there is adjacent logic
deliberately not pinning the toolbar during a handoff. So only the unused binding
goes, and the TSDoc now says what is true.

Not enabled: `noDocumentCookie` (3 sites, and its fix is the CookieStore API,
which is a browser-support call) and `useExhaustiveDependencies` (384 errors).
@vercel

vercel Bot commented Aug 24, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
docs Ready Ready Preview Aug 24, 2026 6:07pm

Request Review

@cursor

cursor Bot commented Aug 24, 2026

Copy link
Copy Markdown

PR Summary

Low Risk
Mostly lint gates and equivalent refactors; renderer prop contract is unchanged aside from documentation.

Overview
Turns on Biome performance/noAccumulatingSpread repo-wide and correctness/noUnusedVariables / noUnusedFunctionParameters at error level for packages/**, after fixing every violation in scope.

The two spread-in-reduce hot paths are rewritten to Object.fromEntries: workspace secrets save builds the personal env map, and block duplication rebuilds cloned subBlocks. Under packages/, unused bindings are cleaned up (mock emit param, validateWorkflow catch, loop/parallel forEach destructuring). In workflow-renderer, isWorkflowRunning stays on the public props but is no longer destructured in the views; TSDoc now states callers still pass it and nothing reads it today (hold-open-on-run was never wired).

Reviewed by Cursor Bugbot for commit 67ad7eb. Configure here.

@greptile-apps

greptile-apps Bot commented Aug 24, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR enables accumulating-spread linting repository-wide and unused-binding linting for packages/**, then fixes the existing violations without changing intended behavior.

  • Replaces two quadratic object-spread reducers with Object.fromEntries.
  • Removes or renames unused bindings in testing, SDK, persistence, and renderer packages.
  • Retains the existing isWorkflowRunning view props while documenting that the views do not currently consume them.

Confidence Score: 5/5

The PR appears safe to merge, with the collection rewrites and unused-binding cleanups preserving existing behavior.

The new lint scopes are valid, both performance rewrites retain the reducers’ key and value semantics, and all removed bindings were demonstrably unused.

Important Files Changed

Filename Overview
biome.json Enables noAccumulatingSpread globally and scopes unused-variable and unused-parameter errors to package files using a valid override.
apps/sim/app/workspace/[workspaceId]/settings/components/secrets/components/secrets-manager/secrets-manager.tsx Replaces an accumulating-spread reducer with an equivalent linear-time environment-variable record construction.
apps/sim/stores/workflows/workflow/store.ts Rebuilds cloned subblocks with Object.fromEntries while preserving per-value structured cloning and key semantics.
packages/testing/src/mocks/socket.mock.ts Marks an intentionally unused mock callback parameter with the underscore convention recognized by the configured lint rule.
packages/ts-sdk/src/index.ts Removes an unused catch binding from workflow validation without changing its false-on-error behavior.
packages/workflow-persistence/src/subflow-helpers.ts Removes unused tuple bindings while preserving loop and parallel conversion behavior.
packages/workflow-renderer/src/subflow/subflow-node-view.tsx Stops destructuring an unread prop and accurately documents its retained compatibility-only status.
packages/workflow-renderer/src/workflow-block/workflow-block-view.tsx Stops destructuring an unread prop and accurately documents that no hold-open behavior is implemented by the view.

Reviews (1): Last reviewed commit: "chore(lint): turn on the rules that woul..." | Re-trigger Greptile

@waleedlatif1
waleedlatif1 merged commit cae80c5 into staging Aug 24, 2026
30 checks passed
@waleedlatif1
waleedlatif1 deleted the deslop-next branch August 24, 2026 18:10
waleedlatif1 added a commit that referenced this pull request Aug 24, 2026
* refactor(auth): drop the isProduction prop nothing on the signin path reads

Same shape as the `isWorkflowRunning` removal: declared, required, threaded
through every layer, and never read at the end of the chain.

`SocialLoginButtons` declares `isProduction: boolean` as a REQUIRED prop and
never reads it, so every caller had to produce and forward a value that was
discarded. Neither `login-form` nor `signup-form` reads it either — each only
declares it, destructures it, and passes it down. `signup-form` forwards it twice,
through its own inner `SignupFormContent` hop.

With the chain gone, `getOAuthProviderStatus` has no consumer for the
`isProduction: isProd` it returned: the pages destructured it only to forward it,
and `/api/auth/providers` already takes just the three availability flags. So the
return value and its `isProd` import go too.

`isProduction` stays alive where it is genuinely used — `verify-content.tsx`
branches on it and hands it to `useVerification`, and imports `isProd` directly
rather than through this helper. That path is untouched.

Found by the rule enabled in #7037: it was the only `.tsx` unused-parameter
warning in `apps/sim`.

(cherry picked from commit 331c2ed)

* refactor: drop two more props declared, threaded, and never read

Same shape as the two already in this PR, found by sweeping the rest of the
unused-parameter list for params callers actively compute and pass.

`FieldItem.level` is the worse of the two. It is a required `level: number` that
the component never reads, and `FieldTreeNodes` exists to thread it: declared,
destructured, handed to `FieldItem`, and incremented on every recursion
(`level={level + 1}`) from a `level={0}` seed. So a depth counter was carried
through an arbitrarily deep tree to feed a component that ignores it. Indentation
comes from the nested wrapper divs (`ml-1.5 pl-2.5`, `ml-3 pl-2.5`), not from the
counter — removing it changes no rendering.

`useMentionMenu`'s `onContextSelect` is a required prop carrying the TSDoc
"Callback when a context is selected". The hook never invokes it, so that
contract is unimplemented and a future caller would reasonably rely on it.

Only the dead hand-off goes there. `addContextNotified` stays: the caller invokes
it directly at five sites, and the ref sinks behind it keep its identity stable
for those. Context selection has always worked because the caller does the work
itself, not because the hook calls back.

(cherry picked from commit 110ba76)

* refactor: drop two more dead prop chains in the sub-block editor

`GroupedCheckboxList` declares `title` (required) and `maxHeight` and reads
neither. It renders its own hardcoded copy instead — `Select PII Types to Detect`
for the header and `PII types` for the field label — so a block author who sets
`title` on a `grouped-checkbox-list` subBlock gets silence, and the
`maxHeight = 400` default implies a scroll ceiling that is never applied. Both
props go, along with the two values `sub-block.tsx` was passing.

`flatTagList` was threaded through the recursive tag renderers to a dead end:
declared on `NestedTagRendererProps`, inherited by `FolderContentsProps`,
destructured in both, forwarded once more, and read by neither. Its real consumer
is `flatTagIndexMap`, built from it at the top level and documented "Map from tag
string to index for O(1) lookups" — so the array was being carried alongside its
own index through arbitrary nesting depth. The top-level memo and its length
checks stay; only the descent goes.

Note the component's copy is PII-specific while its name and props present as
generic. Renaming it is a separate call, not made here.

Both removals were caught mid-flight by `tsc`: my line patterns also matched a
live `flatTagList` on `KeyboardNavigationHandler` and a live `title` on `Switch`,
which is exactly why the type-check runs before the commit and not after.

(cherry picked from commit 5db44f3)

* refactor(custom-blocks): drop the workspaceId three mutation hooks never use

`usePublishCustomBlock`, `useUpdateCustomBlock` and `useDeleteCustomBlock` each
take `workspaceId?: string` and never read it. `custom-block-detail.tsx` passes it
to all three.

The parameter looks like it was meant to narrow the invalidation to
`customBlockKeys.list(workspaceId)`, but `lists()` is the level CLAUDE.md's
targeted-invalidation rule actually prescribes, and it is a correct superset. So
the invalidation is right as written and the parameter is simply vestigial —
removing it is the honest fix, and narrowing the key would be a separate call
with its own risk of under-invalidating.

Worth recording that these three were reported to me as having zero callers and
therefore being dead exports. They are not: the search that produced that claim
omitted `apps/sim/ee`, where all three are used.

(cherry picked from commit 2d0854a)
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