chore(lint): adopt oxlint 1.67 canonical rule additions (selective, library posture)#99
Conversation
npm update (lockfile-only, in-range minor/patch refresh): - @vitest/coverage-v8 4.1.5 -> 4.1.7 - axios 1.16.0 -> 1.16.1 - oxlint 1.65.0 -> 1.67.0 - vitest 4.1.5 -> 4.1.7 - vue 3.5.33 -> 3.5.34 - vue-component-type-helpers 3.2.9 -> 3.3.2 - vue-router 5.0.6 -> 5.0.7 npm audit fix delta: - closes brace-expansion GHSA-jxxr-4gwj-5jf2 (moderate, transitive) - closes ws GHSA-58qx-3vcg-4xpx (moderate, transitive) - closes js-cookie GHSA-qjx8-664m-686j (high, transitive, also cleared by npm update range-resolution) - closes qs GHSA-q8mj-m7cp-5q26 partial — npm reports fixAvailable but the only nested copy is via @stryker-mutator/core -> typed-rest-client@2.3.1 -> qs@6.15.1; audit fix is a lockfile no-op without breaking Stryker's typed-rest-client pin This obsoletes the 6 open Dependabot PRs (#81, #90, #91, #92, #96, #97) — all were CI-red on the same baseline audit drift PR #95 was attempting to clear, and this sweep is a strict superset of PR #95's audit-fix payload. Verification (7 of 8 gates locally green): - Gate 1 npm audit: 2 moderate (qs/typed-rest-client under Stryker; dev-tree only, see Commander-disposition note in mission report) - Gate 2 format:check: PASS (145 files) - Gate 3 lint: PASS (oxlint 1.67.0, 0 warnings) - Gate 4 build: PASS (all 11 packages, dual ESM+CJS) - Gate 5 typecheck: PASS (all 11 packages) - Gate 6 lint:pkg: FAIL locally (documented queue #63 local-vs-CI parser disparity + queue #70 sideEffects Suggestion — CI is expected to pass per PR #95 precedent) - Gate 7 test:coverage: 528/528 tests PASS, 100% per-package thresholds met - Gate 8 test:mutation: PASS (all 11 packages >=90%; 100/94.81/97.18/100/97.30/92.50/91.20/92.73/96.67/98.36/93.33) Step 2E clean install (npm ci): PASS — no ERESOLVE; all 11 @script-development/* node_modules entries resolve to workspace symlinks (no nested registry copies, cascade-tax discipline intact). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Library-territory Correctness-only posture preserved per CLAUDE.md §Lint Rules. Adopts 7 rules from war-room canonical template (commit 321da5f): - no-implied-eval, prefer-regex-literals, getter-return (core ESLint correctness/security) - typescript/no-unnecessary-type-conversion, typescript/no-unnecessary-type-parameters (type-aware quality) - unicorn/no-useless-iterator-to-array, unicorn/import-style (perf + node-builtin discipline) Skipped additions documented inline in .oxlintrc.json (vue/*, jsx-a11y/*, typescript/no-unsafe-*, prefer-import-meta-properties, no-useless-assignment, vitest/* test-override additions, Vue 2->3 deprecation/Options-API rules, complexity/max-* limits). One trivial violation surfaced + fixed: scripts/lint-pkg.mjs node:path import switched from named to default to match unicorn/import-style firing direction. 4 call sites updated, behaviour unchanged. War-room canonical: templates/oxlintrc.json (commit 321da5f). Branch parent: chore/supply-corps-sweep-2026-05-26 (carries the 1.67 binary). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Deploying fs-packages with
|
| Latest commit: |
71ab0b4
|
| Status: | ✅ Deploy successful! |
| Preview URL: | https://9c22a655.fs-packages.pages.dev |
| Branch Preview URL: | https://chore-oxlint-1-67-canonical.fs-packages.pages.dev |
PR Reviewer · 9/10 · PASS
Findings
Actionmerge-ready |
…onical-adoption # Conflicts: # package-lock.json
Goosterhof
left a comment
There was a problem hiding this comment.
No blockers. Two concerns and two nits on a clean, well-documented config chore. The diff is exactly what the body advertises — 7 selectively-adopted oxlint rules with inline skip rationale, plus a 5-line node:path import-shape fix in scripts/lint-pkg.mjs. The library Correctness-only posture is respected and the skip table is honest about why the bulk rules stay out.
Concerns
The "Stacked on #98" narrative is stale and now actively misleading. The body says this PR is "Stacked on #98 (Supply Corps sweep — carries the oxlint 1.67 binary the new rules depend on)" and that "Once #98 merges this PR rebases onto fresh main." But #98 is CLOSED and was never merged (mergedAt: null, mergeCommit: null, closed 2026-05-29). The dependency the stacking narrative hangs on — oxlint 1.67 — is already on main regardless (package.json on main pins "oxlint": "^1.67"), and this PR reports MERGEABLE against main directly. So the stacking framing is no longer load-bearing: there's nothing to merge first and nothing to rebase onto. A reviewer reading the body will go looking for an open #98 and find a closed one. Rewrite the Summary to state the actual situation — #98 closed, oxlint 1.67 already on main, this PR stands alone — so the next reviewer doesn't have to reconstruct the merge history to trust the diff.
unicorn/import-style set to warn doesn't gate by default. Three of the adopted rules (no-unnecessary-type-parameters, no-useless-iterator-to-array, import-style) are warn, and the default lint script is oxlint . without --deny-warnings. So in normal CI these three are advisory only — they surface in output but exit 0. The body's verification matrix notes --deny-warnings also exits 0 today, which is the right thing to have checked, but unless --deny-warnings is the actual CI gate (not just a local spot-check), a future violation of these three lands green. Either confirm the CI lint step runs --deny-warnings (in which case warn and error are equivalent for gating and the severity split is purely cosmetic), or accept that these three are documentation-of-intent rather than enforcement. Worth one sentence in the body stating which it is.
Nits
The skip-rationale comment block lives inside the "rules": {} object as trailing // lines after the last real entry. It parses fine (oxlint reads JSONC and npm run lint passing proves it), but a trailing comment block with no following key is the kind of thing a future editor deletes by accident when adding the next rule. Consider a single leading block comment instead of a trailing one.
The node:path fix switches {join} to a default path import to satisfy import-style's per-builtin direction. Fine, behaviour-identical. The body already flags that the canonical template's §A rationale describes the rule as pushing named imports — directionally wrong for node:path — and routes that to the template maintainer. Good catch; nothing to change here.
Verdict
This is mergeable on substance. The only thing I'd want addressed before merge is the stale #98 narrative in the body — it's not a code defect but it's a correctness defect in the PR's own provenance story, and provenance is what a config-chore review trades on. Fix the body, confirm the --deny-warnings gating question, and ship.
jasperboerhof
left a comment
There was a problem hiding this comment.
Approved — reviewed, no blockers.
Summary
Selective adoption of the war-room canonical template's oxlint 1.55→1.67 rule additions (template commit
321da5f), respecting fs-packages' deliberate library Correctness-only posture (perCLAUDE.md§Lint Rules: "library posture is Correctness-only, opt-in per-rule for anything else").This is not a wholesale port — Vue/jsx-a11y/type-aware bulk rules are deliberately out of scope and the skip rationale is documented inline in
.oxlintrc.json.Standalone — no longer stacked. This PR was originally drafted stacked on #98 (Supply Corps sweep, which carried the oxlint 1.67 binary). #98 was closed without merging (2026-05-29); oxlint 1.67 is already on
mainregardless (package.jsonpins"oxlint": "^1.67"), so this PR stands alone, isMERGEABLEagainstmaindirectly, and needs nothing merged first.Rules adopted (7)
no-implied-evalsetTimeout("...")/setInterval("...")/new Function("...")callsites. No posture friction.prefer-regex-literalsnew RegExp("foo")→/foo/.getter-returntypescript/no-unnecessary-type-conversionString(x)/Number(x)/Boolean(x)noise on already-typed values.typescript/no-unnecessary-type-parametersunicorn/no-useless-iterator-to-array[...someArray]when result is iterated again.unicorn/import-styleimport path from 'node:path', notimport {join}). Complementsprefer-node-protocol.Deliberately NOT adopted (documented inline in
.oxlintrc.json)vue/*jsx-a11y/*typescript/no-unsafe-*familyunknown/anyat adapter boundaries (fs-adapter-store generic constraints).unicorn/prefer-import-meta-propertiesimport.metain CJS bundles cascades to build errors.no-useless-assignmentvitest/valid-expect-in-promise,vitest/prefer-strict-boolean-matcherscomplexity,max-params,max-depth,max-nested-callbacks,max-lines-per-functionSweep collateral (in-scope, ≤3 line fix per order §C)
scripts/lint-pkg.mjsline 25 —unicorn/import-stylefires onimport {join} from 'node:path'with diagnostic "Use default import for modulenode:path". Rule is bidirectional per-builtin (some builtins want named, some want default); fornode:pathit wants default. Switched toimport path from 'node:path'withpath.join(...)at the 4 call sites in this file. Behaviour unchanged. 5-line diff.Verification (8-gate matrix, run locally)
npm audit(--high)--audit-level=high; pre-existing baseline carried from Supply Corps sweepnpm run format:checknpm run lint--deny-warningsalso exits 0 today (no current warn-rule violations), but--deny-warningsis NOT the CI gatenpm run buildnpm run typechecknpm run lint:pkgsideEffectsadvisory × 11 [queue #70] + attw 0.18.2 "Cannot read properties of undefined (reading 'filename')" × 11 [PR #98 commentary]). Reproduced identically on parent branch — not introduced here.npm testnpm run test:coverageMutation testing not run — config-only change does not move the mutation surface; per-package Stryker config unchanged. 7/8 gates green; Gate 6 carries the documented pre-existing baseline that PRs #87, #88 and the 2026-05-15 wave already flagged.
Residual baseline carried forward (NOT introduced)
lint:pkgGate 6 — 22 fails identical to parent branchchore/supply-corps-sweep-2026-05-26. Tracked: enforcement queue fs-dialog: forward host <dialog> ARIA attributes via dialog.open() options (#67) #70 (sideEffectsmanifest compliance — but note PR chore: declare sideEffects: false across all 11 packages — closes queue #70 #88 already adopted"sideEffects": false, the suggestion fires because the wrapper packs from source-tree, not fromdist/— separate concern) + attw 0.18.2 known regression (PR chore: Supply Corps sweep — npm refresh + audit fix (3 advisories cleared) #98 commentary).npm audit— 2 moderate (qs, typed-rest-client) below--audit-level=high. Carried from Supply Corps sweep PR chore: Supply Corps sweep — npm refresh + audit fix (3 advisories cleared) #98npm audit fixrun.Commit shape
Single commit:
chore(lint): adopt oxlint 1.67 canonical rule additions selectively.2 files changed, 26 insertions, 6 deletions.
Execution report
reports/fs-packages/execution/2026-05-26-armorer-oxlint-1.67-adoption.mdin the war-room repo. Includes per-skip rationale, full 8-gate matrix, and Notes-for-the-General on the rule-direction wording issue.Test plan
npm run lint(oxlint w/ new rules) exits 0npm run lint -- --deny-warningsalso exits 0 (local check only — not the CI gate)npm run buildcleannpm run typecheckcleannpm test528/528npm run test:coveragecleanlint:pkgfailure matches parent branch (confirmed pre-existing, not introduced)🤖 Generated with Claude Code