Skip to content

Bound the number of markers one scan can produce #113

Description

@mbeacom

Follow-up from the review of #106, which wired inbound @adr markers into check and the Action. Shipped in v0.5.0.

The gap

The marker path bounds two dimensions and not the third. Files are capped at MARKER_SCAN_FILE_CAP = 3000 and each header window at MARKER_HEADER_WINDOW_BYTES = 8192, but markers-per-file is unbounded, and resolveSourceMarkers emits one finding per distinct (path, line, ref).

Measured against e92fe40:

  • A comma-packed // @adr 1000,1001,… line terminating inside the window yields 1,618 markers from 8,098 bytes.
  • The Action evaluates up to 2,999 changed files (it refuses only >= 3000), so the ceiling is roughly 4.85M finding objects — about 2.1 GB peak RSS and 2.8 s in sortFindings.
  • All of it is authored by the pull request, reachable from a fork on a read-only GITHUB_TOKEN.

Why this is not blocking

On ubuntu-latest it is a survivable transient. It cannot corrupt output and cannot fail the check: marker findings are warn/info, they are excluded from the rendered comment, and CheckOutcome.ok reads only error findings on changed ADR records.

The concern is a memory-constrained self-hosted runner, where an OOM surfaces through main().catch(…) into core.setFailed — pull-request-authored content failing a check run, which ADR-0021 and ADR-0022 both promise cannot happen.

Shape of a fix

marker-scan-capped already establishes the pattern: cap, then collapse the overflow into a single warn naming what was dropped. The open question is the number, which is a policy call rather than an implementation detail.

Worth recording alongside it: a single line longer than the window yields zero markers, because completeLinePrefix (packages/core/src/markers/scan.ts) drops the severed line. The amplification needs many terminated lines, or one ending just inside the window — which is why the naive "one enormous line" attack produces nothing.

Under ADR-0016, the cap test must be observed failing against an uncapped tree before it counts as coverage.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions