chore(lint): make lint:pkg gate ANSI-invariant + declare sideEffects:false — closes queue #63 + #70 (supersedes #88)#101
Open
Goosterhof wants to merge 2 commits into
Open
Conversation
…I — queue #63 The lint:pkg wrapper captures publint stdout and matches PUBLINT_BLOCK_RE (/^(Suggestions|Warnings|Errors):$/m) to fail the gate on any advisory. In CI, publint colorizes its block headers (color-capable environment), emitting e.g. "\x1b[1m\x1b[34mSuggestions:\x1b[39m\x1b[22m". The leading SGR codes mean the line is not a bare "Suggestions:", so the regex never matched and the gate silently no-op'd — a CI false-NEGATIVE in which a genuine Warning/Error block would sail through undetected. Verified against raw CI logs: the gate had been a no-op in CI since publint 0.3.21 landed 2026-05-11; locally (plain-text, non-TTY) the regex matched and the gate fired correctly. Fix (belt-and-suspenders): spawn publint with NO_COLOR=1 AND strip residual ANSI SGR codes from captured stdout before the regex match, so the verdict is identical in every color environment (plain, TTY, FORCE_COLOR=1). ANSI_RE is built via String.fromCharCode(27) + RegExp() to avoid a control-char literal that oxlint's no-control-regex (Correctness) would reject. Header comment updated to record the verified CI-color root cause. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Adds "sideEffects": false immediately after "type": "module" in every packages/*/package.json. Clears the publint 0.3.21 Suggestion ("package appears to be consumed by bundlers but does not specify sideEffects") that the now-honest Gate 6 (queue #63 fix) flags as fatal, and lets consumers tree-shake under deep imports. Per-package side-effect audit re-run on current main (post-#87 streamRequest removal from fs-http): every package's src/index.ts is a pure re-export or a file whose top-level statements are imports, type declarations, and const/function factory declarations. console.*/document.*/window.*/ Object.defineProperty and the dialog body-scroll write are all inside function bodies (call-time, not module-evaluation). cached-adapter-store's top-level `new WeakMap()` is pure construction. No bare side-effect imports anywhere. All 11 cleared. CLAUDE.md gains a "No top-level side effects" Conventions bullet locking the convention so a future package author doesn't ship without the flag and re-fire Gate 6. Closes enforcement queue #70. Supersedes PR #88. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Deploying fs-packages with
|
| Latest commit: |
b5de5ea
|
| Status: | ✅ Deploy successful! |
| Preview URL: | https://ab8b72de.fs-packages.pages.dev |
| Branch Preview URL: | https://armorer-queue-63-70-lintpkg.fs-packages.pages.dev |
Contributor
PR Reviewer · claimed
|
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.
What & why
Two coupled fixes that make Gate 6 (
lint:pkg) actually enforce in CI and clear the only standing publint Suggestion.Verified ground truth (the polarity matters)
The
lint:pkgwrapper (scripts/lint-pkg.mjs) runspublint runper package with piped stdout, captures it, matchesPUBLINT_BLOCK_RE = /^(Suggestions|Warnings|Errors):$/m, and fails the gate on a match.\x1b[1m\x1b[34mSuggestions:\x1b[39m\x1b[22m. The leading SGR codes mean the line is not a bareSuggestions:, so the regex never matched → no failure pushed → the gate silently no-op'd. Verified against raw CI logs: this has been a no-op in CI since publint 0.3.21 landed 2026-05-11 — the 2026-05-18 and 2026-05-29mainruns both passedlint:pkgwhile publint printed the Suggestions block.So the real defect is a CI false-NEGATIVE: a genuine publint Warning/Error (e.g. a broken
exportsmap) would sail through CI undetected today. This PR does not "restore Gate 6 to green on main" — Gate 6 was never red in CI. It makes Gate 6 actually enforce in CI and clears the standingsideEffectsSuggestion.(For the record: PRs #86/#87 were red on the
npm auditstep, not Gate 6.)Changes
scripts/lint-pkg.mjs— ANSI invariance (closes queue fs-router 0.1.0 published peer-dep is stale (vue-router ^4.5.0 vs source ^5.0.6) — republish as 0.1.1 #63). Spawn publint withNO_COLOR=1and strip residual ANSI SGR codes from captured stdout before the regex match (belt-and-suspenders, verdict identical in every color environment).ANSI_REis built viaString.fromCharCode(27)+RegExp()to avoid a control-char literal that oxlint'sno-control-regex(Correctness) would reject. Header comment rewritten to record the verified CI-color root cause.packages/*/package.json—"sideEffects": false(closes queue fs-dialog: forward host <dialog> ARIA attributes via dialog.open() options (#67) #70). Added immediately after"type": "module". Clears the publint 0.3.21 Suggestion the now-honest gate flags as fatal; lets consumers tree-shake under deep imports.CLAUDE.md— "No top-level side effects" Conventions bullet locking the convention so a future package author doesn't ship without the flag and re-fire Gate 6.Load-bearing proof the no-op is fixed
npm run lint:pkg(plain), all packages havesideEffectsFORCE_COLOR=1 npm run lint:pkg, all packages havesideEffectsnpm run lint:pkg(plain), one package'ssideEffectsremovedSuggestions:)FORCE_COLOR=1 npm run lint:pkg, one package'ssideEffectsremovedThe bottom-right cell is the whole point: pre-fix, the colored run let the Suggestion through; post-fix it fails. Captured directly —
FORCE_COLOR=1 npx publint runemits\033[1m\033[34mSuggestions:\033[39m\033[22m(verified viaod -c), exactly the ANSI wrap that defeated the bare-line regex.Per-package side-effect audit (re-run on current
main, post-#87 streamRequest removal)Every package's
src/index.tsis a pure re-export or a file whose top-level statements are imports, type declarations, andconst/functionfactory declarations. All flaggedconsole.*/document.*/window.*/Object.defineProperty/ dialog body-scroll writes are inside function bodies (call-time, not module-evaluation). No bare side-effect imports anywhere.new WeakMap()is pure constructiondocument.bodywrite is call-time insideopen()DEFAULT_TIMEOUT_MSliteral + factory consts (streamRequest gone in 0.4.0)console.erroris call-time inside service methodsdocument/windowreads are call-timedefineComponentsetupgetCacheKeyhelper; all pure declarationsVerification — full 8-gate gauntlet, local
npm auditnpm run format:checknpm run lintnpm run buildnpm run typechecknpm run lint:pkgnpm run test:coveragenpm run test:mutationSupersedes #88
Folds PR #88's
sideEffects: falsemanifest changes + CLAUDE.md doctrine bullet into this PR, and adds the queue #63 ANSI fix that #88 was missing. #88 can be closed as superseded.Closes enforcement queue #63 + #70.