feat: add lint feedback (in-isolate extraStrict + external Biome CI gate)#57
Merged
jonnyparris merged 3 commits intomainfrom May 7, 2026
Merged
feat: add lint feedback (in-isolate extraStrict + external Biome CI gate)#57jonnyparris merged 3 commits intomainfrom
jonnyparris merged 3 commits intomainfrom
Conversation
Layers noUnusedLocals, noUnusedParameters, noImplicitReturns, and noFallthroughCasesInSwitch on top of the user's tsconfig when the agent opts in. A real linter (oxlint, biome) can't run in-isolate — biome's wasm bundle is 8 MB gzipped, well over the Workers script size budget, and oxlint ships only Rust-native binaries. extraStrict reuses the already-bundled TypeScript compiler to surface ~30% of what a linter would catch at zero extra bundle cost. The flag is opt-in per call so existing typecheck behaviour is unchanged and the user's tsconfig still wins by default. When the caller asks for it, the four flags override whatever tsconfig set.
External lint check, configured in biome.jsonc and run by the existing dodo-verify workflow. Biome can't be loaded in-isolate (8 MB gzip wasm bundle, Workers script size limit is 10 MB compressed and dodo already spends ~1.5 MB on the bundled typescript compiler). The CI gate is the agent's only feedback loop for unused-imports / suspicious patterns; the in-isolate `typecheck` tool with `extraStrict: true` covers the TypeScript-side overlap. Scope is intentionally narrow: correctness + suspicious rules only. Formatting is off (the project hasn't adopted a formatter and that's a separate decision). Style rules are off too — they generate too much noise on the existing codebase to be a useful CI gate without weeks of cleanup. The current rule set is what biome already finds and what we can fix in this PR. Findings cleaned up in this commit: - src/artifacts-read.ts: drop unused `err` binding from a routine catch - src/mcp.ts: delete dead patchSession() function (no callers) - src/user-control.ts: drop unused `now` binding in DELETE handler - test/architecture-gaps.test.ts: drop redundant devUser lookup - test/compaction-e2e.test.ts: drop unused sessionId destructure - test/dodo.test.ts: drop dead initText that read but never parsed body The Biome 2.x `experimentalScannerIgnores` field is deprecated; using the `!!` negation prefix in `files.includes` instead.
Self-audit findings on this PR before merge: 1. biome.jsonc had four `"off"` rule entries (noUnusedFunctionParameters, useExhaustiveDependencies, noExplicitAny, noEmptyBlockStatements) that were dead config. With `recommended: false` on the rules block, every rule defaults to off — explicit "off" entries don't change behaviour and just add noise. Verified by removing them and re-running biome: identical output. 2. javascript.linter.enabled: true was the default when linter.enabled is true. Also dead. Removed. 3. The smoke test only covered two of the four extraStrict flags (noUnusedLocals, noImplicitReturns). Added cases for the other two (noFallthroughCasesInSwitch via TS7029 and noUnusedParameters via TS6133) so every flag claimed in the PR description has executable coverage. No source-code or workflow changes — pure config + test cleanup.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Two-layer lint feedback for Dodo. No real linter (oxlint, biome) can run inside a session DO — both ship as either Rust-native binaries or wasm bundles too large for the Workers 10 MB compressed script limit (Biome's wasm-bundler is 8 MB gzipped on its own, dodo already uses ~1.5 MB on
typescript). So this PR builds the next-best thing.Layer 1 — In-isolate:
typechecktool gains anextraStrict: trueoption that layersnoUnusedLocals,noUnusedParameters,noImplicitReturns, andnoFallthroughCasesInSwitchon top of the user's tsconfig. Reuses the already-bundled TypeScript compiler. Zero extra bundle weight. The agent gets sub-second feedback for unused-locals, missing-returns, and switch-fallthrough.Layer 2 — External (CI): Biome runs in
dodo-verify.ymlfor every PR and dispatched verify run. Catches unused imports + suspicious patterns + double-equals + the wider rule set. Configured inbiome.jsoncwith correctness + suspicious rules only — formatting is intentionally off (separate decision), style rules are off (would need weeks of cleanup to be useful as a gate).What's in the diff
feat(typecheck): add extraStrict flag(commit 1)src/typecheck.ts: newextraStrictoption onTypecheckOptionsandEXTRA_STRICT_OPTIONSmapsrc/agentic.ts: tool surface gains the flag, description updatedsrc/coding-agent.ts: system prompt mentions the flag and explicitly notes there's no in-isolate linterscripts/smoke-typecheck.mjs: 3 new test cases covering unused-locals, implicit-returns, and tsconfig-override behaviourfeat(ci): add Biome lint gate(commit 2)biome.jsonc(new): rule set scoped to correctness + suspicious. Uses Biome 2.x!!negation infiles.includes(theexperimentalScannerIgnoresfield is deprecated)package.json:npm run lintandnpm run lint:fixscripts;@biomejs/biomeas a dev dep.github/workflows/dodo-verify.yml: newLint (Biome)step before typecheck and testsAGENTS.md: new "Linting" section explaining the two layers and whypatchSession()in mcp.ts, unusederrbinding in artifacts-read.ts, unusednowin user-control.ts, three unused destructures in testsValidation
npm run typecheck✅npm run lint✅ (clean — 108 files, 0 errors)npm test✅ (630/630 passing)npm run test:typecheck-smoke✅ (9/9 including the 3 new cases)Why not just bundle Biome?
The
@biomejs/wasm-bundlerpackage is 34 MB raw / 8 MB gzipped. Workers' compressed script size limit is 10 MB. After the existing typescript bundle (~1.5 MB gzip) and dodo's own code, there's no room. Confirmed by inspecting the published package — there's no smaller subset distribution.Why not oxlint?
oxlint ships as platform-specific Rust-native binaries (
oxlint-darwin-arm64, etc). No wasm or pure-JS distribution exists in 2026. The@oxc-parser/wasmpackage is deprecated. Even the parser-only path would only give us AST without the rule engine.Future work
If oxc ships a wasm linter, or if Biome publishes a slimmed-down lint-only wasm bundle, we can revisit and load it in-isolate — that would close the feedback gap to sub-second. For now, the CI gate is the practical path.