Skip to content

parser: --max-errors N reports N+1 errors when the stop at the cap leaves a statement unrecovered — a cascade SPY0104 rides past the limit #2311

Closed

Description

@antonsynd

Class: when the parser reaches its --max-errors cap, the stop leaves the parser mid-statement. It then reports a cascade error the recovery would have absorbed, so the cap can report MORE errors than it allows.

Contract: --max-errors N reports at most N errors (plus the SPY0905 "further errors suppressed" note where that phase emits one).

Cells (built sharpyc @ 739ae54; P46 final verifier, re-measured by the lead):

Program Command Observed Expected
def f(): / x = = 1 / blank / def g(): / y = = 2 emit parse p.spy 2× error[SPY0100]: Unexpected token: Assign — (control)
same emit parse p.spy --max-errors 1 error[SPY0100]: Unexpected token: Assign + error[SPY0104]: Expected Dedent, got Assign, both at 2:9 1 error
three such functions --max-errors 2 3 errors 2

The same happens through run and build, which share the parser's cap. Semantic errors honour the cap (emit diagnostics on three undefined names prints 1 error + SPY0905).

Cure shape: the cap stops BEFORE the recovery that follows the Nth error would emit, at the one place the parser counts errors. Not a per-statement guard.

Activity

  1. added
    lane:messageOnly the wording, location, steer or code of a diagnostic or exception
    reach:programAn ordinary program a Python programmer would write hits it
    class-trackerThe one issue per class: carries the contract and the cell table
    on Oct 14, 2026
  2. antonsynd commented on Oct 15, 2026

    @antonsynd
    OwnerAuthor

    Batching 2026-10-14 @ 3f16f26 — charter .claude/plans/remediation-round-2026-09-20-batching.md §3.0, chore (order 0; directly after P54, beside #2261 part 2 — seam-free, one commit, no plan). Ruling R-HD (owner, 2026-10-14): (a) a chore — ONE error-cap seam at the parser's counting site so no recovery follows the Nth error, the catch-site copies removed, a closed-axis matrix.

    Contract: --max-errors N reports at most N errors (plus the SPY0905 note where that phase emits one). Lane / reach: message · program. Matrix: phase {parser, semantic (control)} × N {1, 2, default 25} × shape {statement, def body, class body, nested suite} × route {emit parse, run, build, LSP diagnostics}. Internals read at batching (grep-only @ 3f16f26): the cap is checked at five parallel catch sites (Parser.cs:541, :634; Parser.Definitions.cs:1153, :1330; Parser.Statements.cs:1377), each after the statement parse that already reported the cascade; only the first adds SPY0905 — contract §1's parallel-site meta-class; the chore counts them again. Guard: the matrix above; mutation (restore one catch-site copy or drop the seam → red) recorded in the commit body. Blast radius: Compiler.Tests parser + FrontEndParity (Lsp.Tests). Rejected: (b) fold into P62 (grammar; the cap is error accounting, ~40 groups out); (c) fold into P68 (lexer). Two-way. Class tracker: this issue.

  3. antonsynd commented on Oct 22, 2026

    @antonsynd
    OwnerAuthor

    Landed (chores band 2026-10-22) on dev @ 4d22212, PR #2346 to mainline. Whole-solution gate 81669/0/7 @ 4d22212 (measured), against 81093/0/7 @ be4664e.

    Commit 817c60e (R-HD a). Parser.RecordError is the single cap seam. Reaching the cap throws ParserErrorLimitException before any recovery can report a cascade, and the five catch-site copies are deleted. --max-errors N now reports at most N parser errors plus the SPY0905 note.

    Sibling filed: #2345. On the semantic phase, the cap counts only the type checker's own diagnostics. SPY0202, SPY0204, SPY0300 and validator errors are uncapped: five SPY0202 print at --max-errors 1. This issue's body called the semantic phase a control that honours the cap. That holds only for the codes it probed, so #2345 tracks the phase.

    The parser contract is met. Closing.

  4. added a commit that references this issue on Oct 22, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    class-trackerThe one issue per class: carries the contract and the cell tablelane:messageOnly the wording, location, steer or code of a diagnostic or exceptionreach:programAn ordinary program a Python programmer would write hits it

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions