C imports a Pascal unit under a mangled name
- Track C — C frontend files (
cparser.inc,cpreproc.inc, C tests). Shared compiler internals stay Track A: a new AST node / IR op / symtab field → file a Track A ticket, do not edit under C. - Design settled by the user, 2026-08-19. Every fork below was raised and closed in conversation. Do not reopen them on a hunch; if a MEASUREMENT contradicts one, say so here and escalate rather than choosing differently.
Why
Pascal-into-C is an intended, existing capability — a C file today reaches Pascal
routines through implicit, global, case-insensitive FindProc matching. What it lacks is
not permission but a name.
That namelessness is the actual defect, and it is expensive:
- C has a flat global namespace, and
math.Sqrtis not valid C, so there is no spelling for "theSqrtin unitmath". - The match is case-insensitive while C is a case-sensitive language, so
sqrtandSqrtare one name.lib/crtl/src/math.c:43carries the consequence as a standing coding rule: "never write a wrapper that calls the Pascal twin from its C namesake (double sqrt(double x){ return Sqrt(x); }):Sqrtbinds case-insensitively back to the Csqrtand recurses forever." A language hazard prevented by remembering.
Case sensitivity gives distinguishability; mangling gives identity. Both are needed — that distinction is the design's hinge, and it is the user's.
THE SPEC
1. The import site is an include
#include "math.pas"
Chosen over a #pragma deliberately: gcc tries to textually include Pascal source and
dies loudly. An unknown pragma is silently ignored, producing a file that compiles
elsewhere and behaves differently — the worst failure shape. Honest non-portability beats
silent divergence.
2. Names are mangled, case preserved
<unit>_<ext>_<Identifier> — math.pas exporting Sqrt gives math_pas_Sqrt.
- Case is preserved from the Pascal DECLARATION. This is what makes the mangled name
unable to collide with C's
sqrt, so the infinite-recursion hazard above stops being spellable rather than being remembered. - The
_pas_infix earns its place:math.pasandmath.cwould otherwise both mangle tomath_.
3. Collisions are path-qualified
Two units named math under different -Fu roots mangle identically. Then the path
participates: path_math_pas_Sqrt.
State this property in the user docs, because the file that breaks is not the file
someone edited: the short form is valid only while the unit name is unique across the
search path. Adding a second math.pas anywhere on the path invalidates every C file
using the short form. That fails loudly at compile time as an undefined symbol, which is
acceptable — but it is surprising unless documented.
4. Overloads resolve by the declared C signature — NOT a fork
Raised as a hard problem and dissolved by the user: it is not one.
extern double math_pas_Max(double, double);
The C prototype names the unit, the routine, and the signature, in syntax C already
has. Resolve math → Max → the (Double, Double) overload by ordinary signature
matching. Pascal and C scalar types map cleanly, so this is mechanical.
No suffix scheme. No _ii mangling. Nothing new to spell. A declaration that cannot
discriminate (K&R extern double math_pas_Max();) is refused by name rather than guessed.
5. Non-mappable types are refused by name
Pascal types with no C spelling — AnsiString, sets, variants, open arrays — make a
routine not importable. Refuse at the declaration site, naming the routine. Partial
importability is expected and fine: a unit may export twelve importable routines and two
refused ones.
AnsiString specifically, and the reasoning matters more than the rule (user):
PChar→AnsiStringis fine; Pascal already owns that conversion.AnsiString→ C has no correct answer. Hand C the buffer and you have handed out a reference the refcount does not know about; copy it and nobody owns the copy. There is no third option, so refusing is the honest one.- Returning
AnsiStringis refused unconditionally — worse than a parameter, because there is no caller-side reference keeping the buffer alive and no way for C to release it.
Recorded, deliberately NOT built: a const AnsiString parameter is genuinely safe
— the Pascal caller holds the reference across the call, so the refcount is stable for the
call's duration and C sees an ordinary const char*. It is safe provided the library does
not retain the pointer, which is unverifiable from our side. That makes it a future
explicit opt-in, never a default. Written down so nobody re-derives it as a discovery.
6. The bare name is an EXPERIMENT, not a decision
Open question: should implicit cross-namespace binding be removed once the mangled name exists? Two mechanisms for one concept is the shape this repo's own rules warn about — the second path is the one that stays broken.
Do not decide this by reasoning. Measure it. cparser.inc:9448 defends the implicit
bind on one ground: "lua's <math.h> sqrt/exp/sin/… resolve to the RTL math
routines." That justification may be stale — lib/crtl/src/math.c now DEFINES exp
(:282), log (:341), sin (:644), cos (:656), atan (:724) and sqrt (:965) in C,
correctly-rounded, and CPullCrtlForPrototypes pulls that module when a C file declares
those prototypes.
The experiment: delete the cross-namespace declaration bind and build the C corpus — lua, tcc, quickjs, zlib. If nothing breaks, it was never a breaking change and there is nothing to weigh. If something breaks, those failures ARE the spec for what must stay. Report the result; do not quietly keep or quietly remove it.
Sequencing
bug-c-definition-of-an-intrinsic-name-overwrites-the-pascal-routine (C, p55) lands
first and is a hard prerequisite. It is correct regardless of every choice above: a C
definition must never overwrite a non-C proc's body (cparser.inc:9401 finds it,
:9558 overwrites BodyAddr). A definition claims this translation unit provides the
function; that is a different act from a declaration, and only the declaration case has a
justification.
It is also currently producing a silent wrong value out of the RTL — Sqrt(16.0)
returns 42.0 when a C file in the same program defines sqrt, and math.Sqrt follows the
hijacked entry, so the qualified spelling does not save you.
Gate
Track C's: C tests green + self-host byte-identical + cross. Land only green; incremental or behind a flag, never a long-lived branch. New C tests should cover: the short form, a path-qualified collision, an overload selected by prototype, and each refusal (AnsiString param, AnsiString result, K&R declaration) failing by name at compile time.
Provenance
Designed in conversation with the user, 2026-08-19, against measured code rather than recollection. The coordinator raised overloads as a fork (it is not) and initially argued the implicit bind should simply be deleted (premature — Pascal-into-C is intended and works; it is the naming that is missing). Both corrections are the user's and are why the spec has the shape it has.
Triage 2026-08-19 (Track D re-triage pass, pin v364)
Genuine feature, still wanted, unchanged — and still correctly blocked. Measured against v364, after the import/uses work landed:
#include "mymod.pas"
int main(void){ printf("%d\n", mymod_pas_Twice(21)); }
pascal26:1: error: stray token at top level (not a declaration): 'unit'
So #include of a .pas is still plain textual inclusion — the import site
this ticket specifies does not exist, and nothing about it landed incidentally.
Its blocked-by
(bug-c-definition-of-an-intrinsic-name-overwrites-the-pascal-routine) was
read as still open in backlog/ when this was written. It was not — that
bug was resolved 2026-08-19 in eb5c7be11, which is in master. The edge was
stale and has been cleared (2026-08-20); the ticket is back in ready for
Track C.
Progress — 2026-08-19 (frank2-C)
Landed and self-host green: the #include "<unit>.pas" preprocessor marker
(cpreproc.inc), the pass-1 marker handler that runs ParseUsesUnit, mangled
lookup by FORWARD re-mangling out of Procs[] (never by splitting at _pas_,
which is ambiguous in both directions), prototype-selects-the-overload,
and the §5 non-mappable-type refusals.
Verified by hand against a scratch unit:
use.c mymod_pas_Twice(21) -> 42
t_ovl2.c extern double mymod_pas_Max(double,double) -> 9.2 (picks the Double overload)
t_redecl.c identical redeclaration -> 9.25
t_ovl.c bare call to an overloaded name refused, names the fix
t_ovl3.c two conflicting prototypes for one name refused (previously: silent 0)
t_case.c mymod_pas_twice refused — case is significant
AnsiString parameter refused by name
open/dynamic array parameter refused by name
Not yet exercised: the AnsiString RESULT refusal. The code is in place and
takes the same path, but it cannot be reached today — ANY Pascal unit whose body
touches a managed string dies at import with compiler error: call to a runtime stub that was never emitted, before the C side ever names the routine. That is a
Track A gap in the C driver's stub emission, filed separately; the result refusal
is testable the day it is fixed.
Still open from the spec: §3 path-qualified collisions, §6 the bare-name
experiment (delete the cross-namespace declaration bind, build the C corpus,
report), real test/ cases + Makefile recipe lines, and the missing-unit
diagnostic still speaking Pascal (uses: unit source not found: nosuch) at a C
author who wrote #include "nosuch.pas".
§3 and the test/ cases — 2026-08-20 (frank2-C)
§3 as specified is not implementable from Track C, and the reason is the finding
§3 says a collision is resolved by letting the PATH participate in the mangled
name (path_math_pas_Sqrt). Measured before writing any code, against pin v367:
two files, r1/math.pas and r2/math.pas, both unit math, Twice returning
x*2 and x*3.
#include "r1/math.pas"
#include "r2/math.pas"
math_pas_Twice(21) -> 42 (r1's answer; the author asked for r2's 63)
The second include is a silent no-op. CompiledUnits (defs.inc:2418) is
keyed on the unit NAME, so the loader sees math already compiled and returns
without reading r2 at all. A routine present only in r2 does not merely resolve
to the wrong body — it falls through to the "crtl does not define ..." warning
and dies at link with undefined symbol.
So the two units never COEXIST, and a path-qualified mangled name would denote a
unit that was never loaded — there would be nothing for it to resolve to.
Making unit identity the FILE rather than the NAME is a change to the shared
unit table: Track A ground, and already an open question there
(decide-one-answer-to-have-i-already-compiled-this-unit, which
parser.inc's own Python-module dedup cites). Not edited under C, per the lane
rule; escalated here rather than guessed at.
What landed instead
CCheckPascalUnitCollision (cparser.inc, above CParsePascalUnitMarker):
turn the silent wrong value into a refusal that names both files.
pascal26:9: error: two Pascal units are both named 'mymod':
'test/cpasunit/mymod.pas' was imported first and 'test/cpasunit2/mymod.pas'
cannot also be imported -- a unit's identity is its NAME here, so the second
include would be silently ignored and every mymod_pas_* would resolve to the
first. Rename one of the units
Keyed on the RESOLVED path run through NormalizePath, so the same file
included twice — including a spelling that differs only by a ./ — stays
allowed. Only when the include spelling is a PATH: a bare #include "math.pas"
is answered by the loader's -Fu search and this side never learns which file
won, so it records nothing and compares nothing. Reuses CompiledUnitFile
(defs.inc:2429) for its documented meaning ("the file this compiled unit
resolved to"); it was simply only written on the Python path until now. Nothing
declared, no shared structure changed, no parser.inc / pyparser.inc edit.
Limit, stated plainly: this refuses the collision, it does not resolve it. Two same-named units still cannot be used from one program. That resolution is the Track A question above.
A real bug found by writing the tests
#include "cpasunit/mymod.pas" from test/c_pasunit.c looked for
test/test/cpasunit/mymod. The marker handler prepends the includer's
directory (C's rule), and the unit loader then prepends CurUnitDir again
(parser.inc:33693) — the same directory twice. It went unnoticed because every
hand-verification so far compiled the C file by an ABSOLUTE path, which takes the
loader's name[1] = '/' branch and skips the second prepend. The first
repository-relative test found it immediately.
Fixed in CParsePascalUnitMarker: climb back out of CurUnitDir with one ..
per segment and let NormalizePath collapse the pair. An include written in a
header in another directory still lands where the C author meant.
test/ cases + Makefile recipe lines
test/cpasunit/mymod.pas (Twice, and Max overloaded on Integer/Double),
test/cpasunit2/mymod.pas (the same unit NAME, Twice returning x*3),
test/cpasunit/strmod.pas (an AnsiString-bearing routine beside an importable
one). Nine recipe lines in test-core, beside the existing test_c_* block:
| test | covers |
|---|---|
c_pasunit.c |
the short form (42) + the Integer overload picked by prototype (7) |
c_pasunit_ovl.c |
the Double overload of the SAME Pascal name (9.25) |
c_pasunit_twice.c |
one file included twice, once spelled ./ — allowed |
c_pasunit_collide_fail.c |
two files, one unit name — refused, names both |
c_pasunit_case_fail.c |
mymod_pas_twice does not reach Twice |
c_pasunit_ovl_fail.c |
bare call to an overloaded name — refused, names the fix |
c_pasunit_knr_fail.c |
K&R extern double mymod_pas_Max(); — refused |
c_pasunit_two_overloads_fail.c |
two overloads in one .c — refused |
c_pasunit_ansistring_fail.c |
AnsiString parameter — refused by name |
The AnsiString RESULT refusal is still unreachable for the reason recorded in the previous section (a unit whose body touches a managed string dies at import in the C driver — a Track A stub-emission gap), so it has no test.
Gate: make compiler/pascal26 (converged, 1 round) + all nine recipe lines
hand-run green + tools/gate.sh quick GREEN. Not pinned — the pin is the
coordinator's.
Still open
- §6, the bare-name experiment — delete the cross-namespace declaration bind
at
cparser.inc:9448, build lua / tcc / quickjs / zlib, report what breaks. Untouched, and it needs the user's say-so to run at all: the measurement ISmake test-lua/test-zlib/test-quickjs/test-tcc, and every one of those is refused for this lane by.claude/hooks/no-full-suite.sh(rule 1,make test*). The escape isPXX_ALLOW_FULL_SUITE=1"and only when the user has asked for it" — a coordinator cannot supply it, and hand-running the recipe bodies to get around the refusal would be reshaping a denied command. So §6 is parked on that, not on effort: it is one deletion plus four corpus builds, and whoever has the escape can do it in an afternoon. - The missing-unit diagnostic still speaks Pascal:
#include "nosuch.pas"answersuses: unit source not found: nosuch. The message is raised inparser.inc(Track A ground), and pre-checking the file incparser.incwould have to duplicate the loader's case-insensitive +.pp+-Fusearch to avoid refusing files that do exist. Left alone deliberately. test/my_pas_lib.pasis referenced by nothing — an unused leftover, not this feature's.
Parked to unfinished/ — 2026-08-20 (frank2-C)
Everything in this ticket is landed and green except §6, and §6 is blocked on
permission the owner has to grant (PXX_ALLOW_FULL_SUITE=1 for the four corpus
builds; see "Still open"). Two smaller items are blocked on Track A holding
parser.inc: the collision RESOLUTION
(refactor-a-one-resolved-file-identity-for-a-translation-unit, raised to p60
carrying the Twice(21) = 42 measurement) and the C-flavoured missing-unit
diagnostic.
So the ticket is not being actively worked and should not hold the working/
lock. Moved to unfinished/. Nothing here is half-applied: the compiler change
is complete, self-host green, and pushed.
2026-08-30 — RE-MEASURE (triage only, nothing applied): PARTIALLY DISSOLVED
Checked as part of a pass over parked tickets whose park names another ticket as its resume condition. Two of this park's three stated blockers no longer hold.
1. The collision-resolution blocker is gone. The park says two items are
"blocked on Track A holding parser.inc", one of them
refactor-a-one-resolved-file-identity-for-a-translation-unit. That ticket
resolved 2026-08-20, commit 883ef0c05 — the same day this park was
written. Ten days unread.
2. The file it names no longer exists, and the lane it names is wrong.
compiler/parser.inc was sliced into the pasparser_*.inc set on 2026-08-20.
The missing-unit diagnostic this ticket wants to change is now at
compiler/pasparser_proc.inc:3504 and :4103 — a Track P file, not Track A
ground. So "blocked on Track A holding parser.inc" is stale on both counts: the
file and the owner. The concern under it still stands and is unchanged — a
pre-check in cparser.inc would have to duplicate the loader's
case-insensitive + .pp + -Fu search — but that is a design argument, not a
lane conflict, and it is now a Track C ↔ Track P conversation.
3. §6 is still genuinely blocked, and on the one thing no agent can clear.
It needs PXX_ALLOW_FULL_SUITE=1 for the four corpus builds, which is the
user's to grant. The park is right that a coordinator cannot supply it and that
hand-running the recipe bodies would be reshaping a denied command; that
reasoning is unchanged and is restated here so the next reader does not retry
it. This is the item to put in front of the user — the park's own estimate
is one deletion plus four corpus builds, an afternoon for whoever holds the
escape.
Re-priced: from "three blockers, two of them cross-lane" to one blocker that is a user permission grant, plus a Track C ↔ P design conversation that was previously mis-recorded as a lane lock. Nothing here is waiting on Track A.
Nothing applied. Measured at HEAD; triage pass, not work.
2026-08-30 — RE-CLAIMED and RE-MEASURED at HEAD. One item left, and it is the user's.
frankC, resuming from unfinished/. Re-claimed before the first commit per
CLAUDE.md's resume rule. Compiler aa78a7faf63a — make compiler/pascal26,
converged after 1 round, sha distinct from pinned, so the fixedpoint was
actually proved rather than skipped by an up-to-date no-op.
The landed feature is green — 11 of 11, run individually, not as a suite
| test | result |
|---|---|
c_pasunit (short form 42 + Integer overload 7) |
PASS |
c_pasunit_ovl (Double overload, 9.25) |
PASS |
c_pasunit_twice (same file twice, one spelled ./) |
PASS |
c_pasunit_collide_fail |
PASS |
c_pasunit_case_fail |
PASS |
c_pasunit_ovl_fail |
PASS |
c_pasunit_knr_fail |
PASS |
c_pasunit_two_overloads_fail |
PASS |
c_pasunit_ansistring_fail (parameter) |
PASS |
c_pasunit_ansistring_result_fail (result) |
PASS |
c_pasunit_strings (differential vs the Pascal driver on the same unit) |
PASS |
Two items this ticket still lists as open are DONE, and neither was recorded here
1. The AnsiString RESULT refusal is reachable, tested, and green. This ticket
says twice that it "cannot be reached today" and "has no test", because any unit
whose body touched a managed string died at import with "call to a runtime stub
that was never emitted". That was fixed in 6b26c38e8 — fix(A): a Pascal unit
included from C is compiled as Pascal, shims and all — which also landed
test/c_pasunit_ansistring_result_fail.c and its Makefile recipe.
2. A differential test exists that this ticket never asked for, and it is the
strongest one in the block: c_pasunit_strings.c imports a managed-string unit
from C while test_c_pasunit_strings.pas compiles the same unit through the
Pascal driver, and the two outputs are diffed. The oracle is the other driver,
so there is no expected string a future regression could be edited to match. It
caught a second defect at the time — CProgramMode left on while parsing the
imported unit, so a Pascal literal in a concat was adjusted +8 into a char* and
Length('ab' + 'cdef') returned 3.
Both landed 2026-08-29 under a Track A bug ticket, so this ticket's own "Still open" list was never updated. Ten days of this ticket's stated scope was already closed by someone else's fix.
The last non-§6 item is now filed separately, and it is worse than recorded
The missing-unit diagnostic: this ticket describes it as "still speaks Pascal". Measured, it does three further things, and one of them is not wording —
#include "nosuch.pas" <- line 1
int main(void){return 0;} <- line 2
pascal26:2: error: uses: unit source not found: /abs/path/nosuch
near: __pxx_pascal_unit /abs/path/ nosuch.pas >>> main
It reports line 2. Consistently include-line + 1 (verified at lines 1 and 5),
because CParsePascalUnitMarker consumes the marker's tokens before calling
ParseUsesUnit, so the raise sees the next line. The line it names is valid
user code, which is the expensive kind of wrong. It also leaks the internal
__pxx_pascal_unit marker into the near: context.
Filed as bug-c-a-missing-pascal-unit-diagnostic-points-at-the-wrong-line-and-leaks-an-internal-marker
[p30]. I checked for a Track-C-only fix rather than inheriting the previous
session's conclusion, and there isn't one — the previous reasoning ruled out C
refusing on its own pre-check, but not C checking merely to reword; that escape
fails too, because the loader's failure is fatal at the raise site with nothing
to intercept. The fix is a ParseUsesUnit signature change in
pasparser_proc.inc — Track P's file. Not edited under C.
So the whole remaining scope of this ticket is §6
Everything in §1-§5 is landed, tested and green at aa78a7faf63a. §3's
resolution stays out of scope by the 2026-08-20 finding (two same-named units
cannot coexist; identity-is-the-name is Track A ground and that ticket resolved
in 883ef0c05) — what this ticket owes for §3 is the refusal, and the
refusal is green.
§6 is blocked on a user permission grant and on nothing else. It is one
deletion (cparser.inc:9448, the cross-namespace declaration bind) plus four
corpus builds — lua, tcc, quickjs, zlib — and those builds are make test-lua
and friends, refused for this lane by .claude/hooks/no-full-suite.sh rule 1.
The escape is PXX_ALLOW_FULL_SUITE=1 and only when the user has asked for it.
A coordinator cannot supply it and hand-running the recipe bodies to dodge the
refusal would be reshaping a denied command.
Put to the user 2026-08-30. The spec is emphatic that this is measured and
not reasoned ("Do not decide this by reasoning. Measure it... If something
breaks, those failures ARE the spec for what must stay"), so there is no
defensible way to close §6 from the armchair, and no way to run it without the
grant. Ticket stays in working/ only while that question is live; if the answer
is "not now", it goes back to unfinished/ with §6 as its sole open item.
§6 ANSWERED BY THE USER, 2026-08-30 — and the answer re-reads the experiment
"we deliberately split math and do not want to fall back to pascal functions. because some make different assumptions. iirc, like round() returning int or float, or other details. hence we said — we totally re-implement math for both languages, there is no fallback. PAL stays a shared layer though."
This is not the experiment's result; it is a prior design decision the experiment did not know about, and it OUTRANKS the experiment.
What it changes — the meaning of a red corpus, which is the whole point
§6 as written says: "If something breaks, those failures ARE the spec for what must stay." That instruction assumed the bind was value-neutral plumbing, so a breakage would be evidence the bind was load-bearing. Under the user's ruling it is not, and the reading inverts:
| corpus result | §6's original reading | the reading now |
|---|---|---|
| nothing breaks | the bind was never load-bearing; delete it | same — delete it |
| something breaks | that failure is the spec; restore the bind for it | crtl is MISSING a C implementation; write it. The bind does not come back. |
A C program reaching a Pascal math routine is the defect, not the feature — the
two are deliberately separate implementations with different assumptions
(round()'s return type is the user's example), so a silent fallback is a
silent wrong value, not a convenience. Restoring the bind to fix a breakage
would re-introduce exactly the coupling the split exists to prevent.
Recorded because a future agent reading a red tstate would otherwise do the wrong thing with it, and would be able to cite §6's own words while doing it.
Scope of the ruling: math, not everything. The user's words are about the math split. The deletion below is broader — it drops the cross-namespace bind for any differently-cased Pascal twin. Nothing in the ruling contradicts that (and §6 already specified the broader deletion), but if the corpus reds land somewhere that is not math, that is a case the user has not ruled on and it goes back to Track U rather than being decided from this paragraph.
PAL stays shared — explicitly unaffected. This change touches
CParseCDeclOrDef's name binding only.
§6 LANDED — the deletion, and what it does NOT prove
One token: if isDefinition then procIdx := -1 → procIdx := -1, in
cparser.inc's RUNG 0. The branch only ever runs when
Procs[procIdx].Name <> name, i.e. a Pascal twin spelled differently, so
identical spellings are untouched — crtl's deliberate redefinitions
(malloc/memcpy/strtod and dozens more) must keep overwriting the one entry
or a C malloc and a Pascal malloc would be two allocators in one program.
It subsumes the two rungs below it (arity mismatch, float-class mismatch): both
only fire when Name <> name, which now never binds. They are left in place
rather than deleted — dead by construction, but deleting them is a second change
and this one must stay revertible as a single token.
The differential, and it is a NEGATIVE result worth more than a green tick
Both arms built at one HEAD, stash → build → measure → pop → build → measure, per the provenance discipline slice 1c paid for:
pre aa78a7faf63a (deletion stashed) post fd1bd8abae8a (deletion applied)
sqrt sin cos exp log atan round(2.5) round(-2.5) floor(-2.5) ceil(2.1)
pre vs post: IDENTICAL post vs gcc oracle: MATCHES-GCC
MATH-BIND-DIFFERENTIAL-COMPLETE
So the bind was already dormant for math, and the deletion fixes no live wrong
value. CPullCrtlForPrototypes pulls crtl's C implementations — math.c
defines sqrt (:965), exp (:282), log (:341), sin (:644), cos (:656),
atan (:724) — and those win before the fallback is ever consulted. The user's
round() hazard is real but latent: it bites only for a routine crtl does
not define in C.
That makes this a guard against future drift rather than a bug fix, and saying so matters. The tempting write-up — "deleted the fallback, math now correct" — would be a wrong root cause of the flattering kind, claiming a fix for a behaviour that was already correct.
Gate
make compiler/pascal26 converged after 1 round, fd1bd8abae8a, distinct
from pinned. tools/gate.sh quick GREEN (read from the log's own
gate: GREEN line, not a wrapper's exit code — slice 1b's lesson). The 11
c_pasunit rungs plus quick_canary_c: 12/12 PASS. Ten C math calls
byte-equal to the gcc oracle.
The corpus verdict is Seven's, not mine — the user's call, and it is the
repo's own division of labour: breadth is Track T's, run against the exact sha.
The previous park recorded §6 as blocked on a PXX_ALLOW_FULL_SUITE=1 grant;
that was wrong, and inherited rather than checked. test-lua, test-zlib and
test-cjson are in T's limited and full tiers already.
But the corpus §6 names is not the corpus that will run. Of lua, tcc, quickjs, zlib, only lua and zlib are in any tier: test-quickjs exists and is
enrolled nowhere, and test-tcc does not exist at all. Filed as
task-t-the-c-corpus-is-two-rungs-not-four-and-a-missing-tree-reports-pass
[T p45], which also carries the sharper finding — test-quickjs self-skips
exit 0 when its tree is absent, so enrolling it alone would report green
coverage on every box that has not fetched the tree.
So §6 is landed but not yet fully measured, and the gap is named. Lua and zlib will answer for themselves on the next sweep of this sha; quickjs and tcc cannot answer until T's ticket lands.
Log
- 2026-08-30 — resolved, commit 82a239672.