← board

Twelve syntax-shaped %FAIL refusals: green for their own reason, or green by accident?

Where the number comes from

109fbebb1 (frankS) re-ran every curated %FAIL row and recorded why each is refused. 225 rows, 191 refused, grouping as:

group rows disposition
impossible operator overload 41 refused for the row's own reason
syntax-shaped 12 this ticket — unknown
undefined variable 11 refused for the row's own reason
"this file is a unit, not a program" 4 vacuous — auto-gated in 109fbebb1

The unit group is the proof that the question is worth asking: pxx has no standalone-unit compile, so it refused those rows for a property of the FILE KIND, and every one passed whatever it contained. tgeneric105 was counted as a pass on exactly that, and tgenfunc14/17/18 carried skip reasons describing a dialect-pass the compiler never reached the source to have. 4 curated rows, 9 in the corpus.

What "done" looks like

A disposition per row, in the row's own skip/notes line, saying which refusal it got and whether that refusal is the assertion. Two outcomes and both are wins:

Do not close this by counting. The question is per row and the instrument is reading the diagnostic, not grepping for one.

Why it is not the long tail ticket

[[task-pascal-conformance-long-tail]] is a catch-all list of known parser holes. This is the opposite direction: rows currently passing, where the pass may be an artefact. A hole found here feeds that ticket; the audit itself does not live there.

2026-09-06 (frankS) — all twelve dispositioned. SIX are vacuous.

Method: for each row, compile it, take the refusal, then probe the same construct in a context where it is LEGAL. That probe is the discriminator — a row refused at its own construct is only a real pass if pxx accepts that construct where the language allows it. Without it, "refused at the right token" and "does not support the token at all" are indistinguishable.

VACUOUS — refused by something that is not the row's subject (6)

row its subject what actually refused it
tgeneric100 unit-qualified specialize ugeneric99.TTest<LongInt> an error inside ugeneric99.pp, a used unit — the row's own source is never reached
tgeneric101 same identical, same other file
tclass14a stored is not supported on a CLASS property stored is not supported at all — probe: an ordinary published property ... stored False, which FPC accepts, is refused too
tclass10b a visibility section after type resets the section, so a field decl there is illegal the ORDER type private. Probe: private type is ACCEPTED, type private is not; FPC takes both, so the row dies before its own construct
tclass17 threadvar is not allowed in a class threadvar is not supported at any scope — probe: a program-level threadvar is refused
terecs21 same as tclass17 identical

LEGITIMATE — refused at the row's own construct (6)

row why the probe clears it
toperator7 the source is literally AValue = 1; under // this construction must fail, and pxx answers expected ':=' before '='. The row's exact rule.
terecs4 destructor in a RECORD. Probe: a destructor in a CLASS is accepted, so the refusal is about the record context.
tsealed5 sealed on an OBJECT. Probe: sealed on a CLASS is accepted. (Mechanism differs — pxx reads sealed as a field name — but the construct refused is the row's.)
tprop2 property at program level. Probe: property in a class is accepted.
tgeneric31 already documented in IsGenericRoutineHeaderAhead's own comment: the <-alone spelling used to ACCEPT this row, and was fixed precisely because it is %FAIL.
tgenfunc11 virtual on a generic method. Refused, and only reachable on code FPC also rejects, so it is a programmer error either way (CLAUDE.md: ask what the source MEANT). Fragile in mechanism — the zero-uses erase leaves the modifier — but overload; on the same shape is measured to work and run, so no legal program depends on it.

Not re-refused, per this ticket's own instruction

None of the six vacuous rows is being made to fail "properly" to keep it green. They are recorded as what they are. Three of them are a %FAIL row that pxx would pass on the rule if the parse gap closed, and two (tgeneric100/101) would need the OTHER file to parse first.

THREE COMPAT GAPS FELL OUT, and they are the actual value here

Each is a separate Track P ticket per this ticket's boundary, each measured by a probe on code FPC accepts:

Filed separately. Ranked on how much real code wants them, not on how the corpus row is spelled.

Log