Skip to content

test(ui): semantic defect gate for inline scripts (#111 hardening)#113

Merged
jmagly merged 1 commit into
elder-plinius:mainfrom
lyubomir-bozhinov:ci/frontend-defect-gate
Jul 26, 2026
Merged

test(ui): semantic defect gate for inline scripts (#111 hardening)#113
jmagly merged 1 commit into
elder-plinius:mainfrom
lyubomir-bozhinov:ci/frontend-defect-gate

Conversation

@lyubomir-bozhinov

@lyubomir-bozhinov lyubomir-bozhinov commented Jul 22, 2026

Copy link
Copy Markdown
Contributor

✅ Now standalone — #112 has merged

Its dependency (#112, the fix for #111) merged on 2026-07-24, so I've rebased this onto current main. The diff is now just the one new commit — a single test file, +49/−1.

Chain: #111 (issue) → #112 (fix, merged) → this PR (the CI gate that stops #111 from recurring).


What & why

#111 shipped 8 conflict-concatenation scars into the 27,000-line SPA — and sailed straight through CI, because lint/test only ever look at src/. The product's primary surface has no static gate at all. #112's fix added a vm.Script parse test (catches outright syntax breakage). This PR adds the semantic layer parsing can't see — the shapes a bad auto-merge leaves behind that still parse but are always bugs.

The gate

A new check in the existing test file runs ESLint's high-precision "possible problem" rules over each inline <script>:

no-redeclare, no-unreachable, no-dupe-keys, no-dupe-args, no-dupe-else-if, no-duplicate-case, no-const-assign, no-import-assign, no-class-assign.

Deliberately minimal, additive, dependency-free:

  • No new dependencyeslint is already a devDependency; used via its Linter API.
  • No eslint.config.js or ci.yml change — rides the existing npm test.
  • No flakiness — pure static analysis, no browser/server. (A Playwright boot-smoke was considered and deliberately deferred: on a backendless CI its coverage largely overlaps this, while adding a browser dependency and timing flakiness.)

Precision over recall — each script is linted in isolation and the rule set is only "always-a-bug" checks, so it's false-positive-free on the real file. Two rules are excluded, reasons documented in-code:

  • no-undef / no-unused-vars — the SPA relies on hundreds of cross-<script> and browser globals a per-block lint can't see (would flood).
  • no-func-assign — the app legitimately monkey-patches navigateTo (wraps it to add CTF-range init).

Validation

  • 0 findings on main (no false positives).
  • RED-proven: the gate rejects the pre-fix tree (catches the duplicate response).
  • Confirmed it catches each scar shape (dup-decl, unreachable-after-return, dup-key).
  • tsc --noEmit clean; npm run lint adds 0 errors/warnings; full suite 647 green.

Relates to #111 / #112.

 hardening)

elder-plinius#111 shipped 8 bad-auto-merge scars into the SPA past a CI that only ever
lints/tests `src/` — the 27k-line docs/index.html had (and still has) no
static gate. The parse test added with the elder-plinius#111 fix catches outright syntax
failures; this adds the *semantic* layer that parsing misses.

It runs ESLint's high-precision "possible problem" rules programmatically
over each inline <script> (no new dependency — `eslint` is already a
devDependency; no eslint.config or CI change — rides the existing `npm test`):
no-redeclare, no-unreachable, no-dupe-keys, no-dupe-args, no-dupe-else-if,
no-duplicate-case, no-const-assign, no-import-assign, no-class-assign — the
exact shapes a conflict-concatenating merge leaves behind.

Tight, always-a-bug rules, each script linted in isolation → zero false
positives on the real file. no-undef / no-unused-vars are excluded (the SPA
relies on cross-<script> and browser globals a per-block lint can't see) and
no-func-assign is excluded (the app legitimately monkey-patches navigateTo).

Verified: 0 findings on the fixed tree, and it rejects the pre-fix main
(catches the duplicate `response`). Full suite green.

Also drops a now-unused eslint-disable directive in the parse test.
@lyubomir-bozhinov
lyubomir-bozhinov force-pushed the ci/frontend-defect-gate branch from 210d726 to 837f3c7 Compare July 25, 2026 12:15
@lyubomir-bozhinov lyubomir-bozhinov changed the title test(ui): semantic defect gate for inline scripts (#111 hardening) — stacked on #112 test(ui): semantic defect gate for inline scripts (#111 hardening) Jul 25, 2026

@jmagly jmagly left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Reviewed PR #113 at 837f3c7cd2cc5288eaa3be226fc0947789a6cff3.

No blocking findings.

Verification:

  • GitHub Actions T3MP3ST CI / test: success
  • npm run typecheck: pass
  • focused UI gate: 3/3 pass
  • npm run lint: 0 errors, baseline warnings only
  • Public-input threat preflight: low risk

The semantic rules are narrowly scoped to high-confidence defects and complement the syntax gate without adding a dependency.

@jmagly
jmagly merged commit 32b8170 into elder-plinius:main Jul 26, 2026
1 check passed
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.

2 participants