LearnNewsExamplesServices
Frontmatter
id17512
titleA dismissed code-scanning alert leaves no trace in the repository
stateClosed
labels
documentationenhancementaisecurity
assigneesneo-opus-grace
createdAtAug 22, 2026, 12:23 AM
updatedAtAug 22, 2026, 2:41 AM
githubUrlhttps://github.com/neomjs/neo/issues/17512
authorneo-opus-grace
commentsCount1
parentIssuenull
subIssues[]
subIssuesCompleted0
subIssuesTotal0
contentTrust
projected
quarantined0
signals[]
blockedBy[]
blocking[]
closedAtAug 22, 2026, 2:41 AM

A dismissed code-scanning alert leaves no trace in the repository

Closed Backlog/active-chunk-18 documentationenhancementaisecurity
neo-opus-grace
neo-opus-grace commented on Aug 22, 2026, 12:23 AM

Context

Triaging the code-scanning queue surfaced a substrate gap that outlives any individual alert: CodeQL cannot express "this rule, on this path, is intentional", and Neo has nowhere in-repo to say it either.

Verified against the GitHub documentation rather than assumed:

  • query-filters exclude by query id or tagsnot by path.
  • paths / paths-ignore exclude a file from every query, not one.
  • No supported inline source-comment suppression for CodeQL alerts.

And the repository has no codeql-config.yml at all.github/workflows/codeql-analysis.yml runs stock, with no config-file:. So every disposition lives in the GitHub UI: unversioned, un-greppable, invisible to git blame, and unreviewable in a PR.

Live latest-open sweep: checked latest 6 open issues at 2026-08-21T22:3x UTC; gh search issues for code-scanning dismissal OR codeql ledger OR prototype enrichment returned zero. No equivalent exists.

The Problem

Neo deliberately enriches prototypes. js/prototype-pollution-utility will therefore fire on intentional framework code for as long as the framework exists — currently src/Neo.mjs:563,565. The operator's position is correct and is a design statement: "we know exactly what we are doing there."

The tempting fixes are both wrong, and one is measurably wrong:

approach why not
global query-filters exclusion of the rule would have hidden alert 113 — a genuine defect in generateDocsJson.mjs under the same rule id, fixed in PR #17496
paths-ignore: src/Neo.mjs blinds every query on the root file to suppress one

So per-alert dismissal is not a fallback — it is the only mechanism with the right granularity. That is a fine outcome for the suppression itself, and a bad one for the reasoning, which is the part that has to survive.

What actually decays: in six months someone reads Neo.merge, sees a for…in writing target[key] with no __proto__ guard, and has no way to learn that this was examined, that the 19 call sites were enumerated, and that the conclusion was deliberate. They either re-derive it, or "fix" intentional behaviour, or file the ticket again. The dismissal reason exists — in a UI they will not think to open.

The Architectural Reality

  • .github/workflows/codeql-analysis.yml — stock setup, no config-file:
  • src/Neo.mjs:552-570Neo.merge, the flagged site; for (const key in source) enumerates inherited and JSON-parsed __proto__ alike
  • learn/agentos/process/ — where Neo already keeps its durable process ledgers (contract-ledger.md, evidence-ladder.md, correction-culture.md); the natural home for a dismissal ledger

Measured reachability behind the disposition: 19 Neo.merge call sites across src/ and apps/, all fed author-controlled config — none from JSON.parse, fetch, response body, or query parameters.

The Fix

Two artifacts, neither of which suppresses anything — both make the reasoning durable where the scanner cannot:

  1. An in-source note at the Neo.merge site recording the intent and the reachability argument, so the code carries its own disposition.
  2. learn/agentos/process/code-scanning-dispositions.md — a ledger keyed by rule + path: the disposition, the reason, the evidence, the decider, the date. Reviewable in a PR, greppable, and a place for the next agent to check before filing a duplicate.

Deliberately not in scope: changing Neo.merge. An earlier draft of mine proposed guarding the three prototype keys. Withdrawn — the reachability is nil today, the cost lands on a hot-path config merge, and "a future caller might be undisciplined" is thin against an explicit statement of intent from the design owner.

Acceptance Criteria

  • src/Neo.mjs carries a note at the flagged site stating the intent, the reachability finding, and that the alerts are dismissed rather than unnoticed
  • learn/agentos/process/code-scanning-dispositions.md exists with one row per dismissed alert: rule id, path, disposition, reason, evidence, decider, date
  • The ledger records the mechanism finding — that path-scoped rule exclusion does not exist — so the next person does not re-research it and reach for a global filter
  • The ledger states the rule that alert 113 established: a shared rule id does not imply a shared disposition; each path is judged on intent
  • No production behaviour changes; no CodeQL configuration is added

Out of Scope

  • Dismissing alerts 62/63 — a human-owned action in the security tab. This ticket prepares the reasons; @tobiu applies them.
  • Any change to Neo.merge or to the class system's prototype work.
  • Adding a codeql-config.yml. Nothing here needs one, and adding an empty config invites the global-exclusion mistake later.

Avoided Traps

Treating "the scanner is wrong" as "nothing to record". The dismissal is correct and the reasoning behind it is load-bearing for the next reader. Those are separable, and only the first currently has a home.

Letting one rule id imply one disposition. Alert 113 fired under the same rule and was a real bug. Any artifact produced here must make that distinction explicit, or it becomes the justification for a blanket exclusion later.

Related

Retrieval Hint: codeql dismissal ledger prototype enrichment Neo.merge query-filters path scoping

Origin Session ID: 752da6ac-a6c3-447f-8847-1da4ce49deb8

Decision Record impact: none — process documentation, no ADR authority touched. Structure-map gate: N/A, no ai/ surface; the ledger follows learn/agentos/process/ sibling precedent.