← board

Synapse library — proper compile check (Track B)

Why this is Track B

The dialect/compiler side of consuming Synapse is largely done (Track A): {$mode delphi} core, dotted unit names, {$IF DECLARED}, directive-if-numeric. What remains to actually compile Synapse is RTL availability and source compatPosix.* shim units, Classes/SysUtils surface, syncobjs, the blocking socket face — i.e. library work built with the pinned stable compiler. So the activity belongs to Track B; genuine compiler/language gaps it surfaces get filed back as Track A tickets.

The task

Once --mimic-fpc lands (Track A), run a proper Synapse compile pass and catalogue the blocker classes — this replaces the old ad-hoc directive-wall probing with a real attempt:

  1. Drive with test/manual/try_synapse_compile.sh and the external/synapse smoke units (start with the leaf units: synautil, synaip, synacode, then blcksock).
  2. Build with $(PXX_STABLE) + --mimic-fpc. Do not rebuild the compiler.
  3. For each failure, classify:
    • RTL gap (missing/short unit or routine) → fix in lib/rtl (our own from-scratch RTL, FPC naming — never port real FPC RTL; see the own-RTL strategy memory) or a Posix.* shim, and add a make lib-test smoke.
    • Compiler/language gap → file a focused Track A ticket (e.g. pull a slice from [[feature-mode-delphi-remaining]]); do not work around it in the lib.
  4. Record the running blocker list + the furthest unit reached in [[feature-networking]] (or here), so progress is visible across sessions.

Expectations / known edges

Done when

A defined Synapse subset (target: the blocking HTTP client path) compiles with $(PXX_STABLE) --mimic-fpc and a smoke unit exercises it under make lib-test, with every remaining gap either fixed in lib/rtl or filed as a Track A ticket.

Recon 2026-06-22 (first --mimic-fpc pass, leaf units)

Ran program p; uses <unit>; per leaf with --mimic-fpc (fresh compiler). mimic acceptance MET: every failure is now missing-RTL or a concrete compiler gap, NOT a directive/branch error — units get past jedi.inc into the FPC path. First blocker per unit:

Track A spinoff filed + FIXED: [[bug-var-open-array-fixed-arg-length]] (a var array of T param got a wrong length from a static-array argument — var and field, on synacode's ArrByteToLong/MD5 path); also [[bug-static-array-length-direct]] (1-D).

Re-probe 2026-06-22 (after the Track A fixes) — Track A blockers CLEARED

Same leaf sweep with --mimic-fpc after the capital-array keyword fix (b5c0252) and the var-open-array fixes. Every remaining first-blocker is now RTL (no parse/codegen/dialect gap surfaces):

So the Track A (compiler) side of the Synapse path is, for the leaf set, done for now. The compiler no longer trips on Synapse dialect/parse/codegen.

Track B next (RTL breadth, the gating units):

  1. unixutil — small POSIX util shim unit.
  2. dynlibsLoadLibrary/GetProcAddress/UnloadLibrary over the PAL dynlib surface (PXX_HAS_DYNLIB).
  3. Move / FillChar — System memory primitives, auto-available without uses. Now unblocked for Track B as plain RTL functions: untyped var/const parameters landed (Track A, [[feature-untyped-parameters]], aafd222), so these are writable in lib/rtl directly: Move(const Source; var Dest; Count) + FillChar(var X; Count; Value: Byte) over @Source/@Dest. Caveats: Move must be overlap-safe (memmove — copy backward when dst>src and ranges overlap; the internal PXXMemMove is forward-only/memcpy); FillChar needs a byte fill (only PXXMemZero exists). Auto-load so they resolve without uses.

Once these land, re-run and record the next class (expected: Classes/SysUtils surface depth).

Scoping 2026-06-22 (Synapse source installed)

Ran tools/install_externals.sh (geby/synapse @ 9c590c1, shallow clone into the gitignored external/synapse). Scoped the gating unixutil blocker to size the RTL shims — it is a multi-unit chain, not one small unit:

This is a deep RTL-breadth cascade (BaseUnix/Classes/SysUtils depth follows), so it wants a dedicated push rather than opportunistic slices. The analysis above is the starting point.

Keystone 2026-06-22 — dynlibs gates the ENTIRE leaf path

Re-probing uses synautil on v38 (untyped params landed): first wall is still unixutil, but synautil unconditionally uses ... SynaFpc, and SynaFpc itself uses dynlibs (under {$IFDEF FPC}). So dynlibs is required even for the "simple" leaf units (synautil/synaip/asn1util/synachar), not just synsock/blcksock. SynaFpc needs only TLibHandle + LoadLibrary / FreeLibrary / GetProcAddress / GetProcedureAddress / UnloadLibrary / NilHandle — it wraps them; Synapse tolerates LoadLibrary returning the nil handle (that path just means "optional lib, e.g. SSL, unavailable").

So an honest minimal dynlibs (FPC signatures; LoadLibrary -> NilHandle, GetProcAddress -> nil until a real PAL loader exists) unblocks compilation and the no-dynamic-lib (plain-HTTP, no-SSL) path. It is NOT a workaround for a compiler bug — libc-free POSIX genuinely has no runtime loader; PalHasDynlib returning True on posix is the actual inconsistency to fix (set it False, or add real PalDlOpen over libc when a "link-libc" profile is chosen — a deliberate design decision, file separately). Recommended order for the dedicated push: dynlibs (stub) -> unixutil/Unix/BaseUnix -> verify SysUtils/Classes depth. (Coordination: Move/FillChar are owned elsewhere on Track B; keep dynlibs/the unix shims separate from them.)

Progress 2026-06-24 — dynlibs + unix shims LANDED; blocked on a directive bug

Track B RTL landed (all with make lib-test smokes):

With these the uses chain of synautil/synaip/asn1util/synachar fully resolves. Furthest reached: synautil now passes the uses clause and stops at a Track A compiler bug — spurious unterminated conditional directive on synautil + jedi.inc (jedi alone OK, synautil sans jedi OK, together fail). Filed urgent: [[bug-conditional-directive-miscount-synautil]]. No lib workaround (Platonic).

Blocker stack now (leaf set):

  1. [[bug-conditional-directive-miscount-synautil]] (Track A, urgent) — gates synautil/synaip/asn1util/synachar at the directive phase.
  2. After that: synafpc/synautil need StrLCopy (and likely sibling strings-unit routines) — RTL gap, Track B.
  3. Move/FillChar — owned separately on Track B.

Also open from earlier: [[bug-hex-char-code-literal]] (Track A, urgent) for synacode's #$NN set constants.

Progress 2026-06-24 (cont.) — synafpc COMPILES; StrLCopy/Sleep landed

Leaf-set re-probe (v50, --mimic-fpc):

unit state
synafpc OK
synautil/synaip/asn1util/synachar blocked on [[bug-conditional-directive-miscount-synautil]] (Track A)
synacode needs Move/FillChar (RTL; intrinsic future = [[feature-move-fillchar-intrinsics]])
synsock/blcksock next gap: uses unit not found sockets (FPC Sockets unit — RTL, Track B)

Spinoff bug filed while verifying the hex fix: [[bug-set-of-char-const-corrupts-char-codegen]] (Track A, urgent) — a set of char typed constant corrupts Ord(char-var) codegen; Synapse uses such constants, so it threatens correctness later.

Track B next (not blocked on Track A): Move/FillChar RTL, then the sockets unit for synsock/blcksock.

Progress 2026-06-24 (cont. 2) — sysutils breadth; synacode hits {$R-} at emit

Added to lib/rtl/sysutils.pas (all smoked in test/lib_strpchar): Move (overlap-safe/memmove) + FillChar (interim home — see [[feature-move-fillchar-intrinsics]]; FPC's is System/no-uses), IntToHex, StringOfChar. synacode resolves all of these now.

synacode new wall: {$R-} at emit — [[bug-r-directive-toggle-treated-as-resource]] (Track A, urgent). The {$R} lexer reads the range-check toggle -/+ as a resource filename; the error only fires at emit, so it was masked until synacode started passing semantics. Latent since 2026-05-30, not a v50 regression.

Spinoff: const-string-index quirks folded into [[bug-set-of-char-const-corrupts-char-codegen]] (untyped string const index → garbage char, worked around in IntToHex; typed const s: string = ... → parse error).

Track A urgent queue now (all block Synapse):

  1. [[bug-conditional-directive-miscount-synautil]] — synautil/synaip/asn1util/synachar.
  2. [[bug-r-directive-toggle-treated-as-resource]] — synacode (and the above, at emit).
  3. [[bug-set-of-char-const-corrupts-char-codegen]] — correctness.

Track B (not blocked): sockets unit → synsock/blcksock (+ our own net lib / HTTP, async-aware — see the design note to come).

Re-probe 2026-06-24 (cont. 3) — sockets unit advanced synsock; new gaps

Leaf/socket/protocol sweep (v53, --mimic-fpc, all current RTL):

unit state
synafpc OK
synautil/synaip/asn1util/synachar [[bug-conditional-directive-miscount-synautil]] (Track A)
synacode [[bug-r-directive-toggle-treated-as-resource]] at emit (Track A)
synsock/blcksock/httpsend/ftpsend/smtpsend advanced past sockets (unit now exists) → next: termio (added, trivial), then [[bug-unit-qualified-constant-not-resolved]] (Track A) on ssfpc's FIONREAD = termio.FIONREAD;

Track B added lib/rtl/termio.pas (FIONREAD/FIONBIO/FIOASYNC). After the qualified-const bug clears, the next RTL gaps for the socket path are the sockets address-string helpers (StrToNetAddr/NetAddrToStr/HostToNet/IPv6 variants) and a netdb shim (THostEntry/GetHostByName/ResolveName/+6/ TProtocolEntry/TServiceEntry, over lib/rtl/dns), then Classes depth (TStream — itself Track-A-blocked). syncobjs already exists.

Synapse is now heavily Track-A-gated: directive-miscount, R-toggle, qualified-const (+ string-cmp / Read-Write-names / untyped-method-params for the Classes it needs). Track B shim work past synsock waits on the qualified-const fix.

Re-probe 2026-06-25 (v55) — {$R-} fixed; synacode COMPILES + partially runs

{$R-} fix (v55) + all the RTL/compiler fixes mean synacode now compiles fully, joining synafpc. Leaf set:

unit state
synafpc, synacode compile OK
synautil/synaip/asn1util/synachar [[bug-conditional-directive-miscount-synautil]] (Track A, open)
synsock/blcksock [[bug-unit-qualified-constant-not-resolved]] (termio.FIONREAD, Track A, open)

synacode functional dogfood (--mimic-fpc): EncodeBase64('hello world') = aGVsbG8gd29ybGQ=correct. But DecodeBase64 returns garbage and MD5 segfaults at runtime — both index/process const lookup tables (ReTableBase64, the MD5 state), so this is the const-table-index / managed-Move runtime codegen family ([[bug-set-of-char-const-corrupts-char-codegen]] and relatives). Compiling is necessary but not sufficient — synacode needs those runtime codegen bugs fixed (Track A) for correct Base64-decode/MD5. A minimal repro from synacode's Decode4to3Ex / MD5 path would sharpen the Track A ticket.

Two leaf units down (compile); the rest gated on directive-miscount / qualified-const, and full synacode correctness on the const-codegen runtime bugs.

Re-probe 2026-06-28 (v83) — prior Track A gates cleared; two new bugs found

All previously open Track A blockers are now in done/: [[bug-conditional-directive-miscount-synautil]], [[bug-unit-qualified-constant-not-resolved]], [[bug-set-of-char-const-corrupts-char-codegen]], [[bug-proc-typed-call-const-record-arg]].

Fresh probe at v83 with --mimic-fpc:

unit state
synafpc, synacode compile OK (unchanged)
synautil/synaip/asn1util/synachar [[bug-chr-builtin-shadows-param-name]] (Track A, new) — CountOfChar(…; Chr: char): Chr treated as built-in, rejected as param name
synsock/blcksock/httpsend [[bug-consteval-named-type-cast]] (Track A, new) — ssfpc.inc: INVALID_SOCKET = TSocket(NOT(0)) fails ConstEval

Both bugs filed 2026-06-28. When Track A fixes them, re-probe to find the next wall.

TRIAGE (2026-06-30, multi-agent verify)

UPDATE (verify): both listed Track A blockers (bug-chr-builtin-shadows-param-name, bug-consteval-named-type-cast) are now in done/. Re-probe 'uses synautil --mimic-fpc' advances past them to a NEW wall: 'too many array constant elements' (candidate focused Track A ticket / capacity bump). Track B compile target still open.

Re-probe 2026-07-11 (v201, opus-night)

uses synautil --mimic-fpc now dies at jedi.inc: PXX evaluates {$...} directives inside (* ... *) comments, and jedi.inc's big doc comment (lines 48-699) contains example directives with 14.2 float literals → "unexpected character" (misreported at synautil.pas:458 via the include splice). Same lexer bug the New-ZenGL ladder hit the same night — [[bug-pascal-directive-inside-paren-star-comment]], prio raised to 65 since it walls BOTH corpora. Without --mimic-fpc the probe instead takes the Kylix path and stops at uses libc (expected). Next wall after the lexer fix is presumably the previously-noted "too many array constant elements".

2026-07-12: lexer walls DOWN — next wall is RTL surface

With bug-pascal-directive-inside-paren-star-comment resolved (both the expansion-pass comment bug AND a second find: jedi.inc's {$MODE DELPHI} leaked NestedComments into every unit lexed after it — fixed per-unit), uses synautil --mimic-fpc now parses the entire unit and fails on SEMANTICS: undefined variable (DayOfWeek) at synautil's date code — a lib/rtl sysutils surface gap (Track B, this ticket's own lane). The directive/lexer era of this ticket is over.

2026-07-12 (later): RTL surface batch landed, next wall = Move(Pointer(v)^, ...)

Iterated synautil's undefined-symbol walls at v202+HEAD:

2026-07-12 (later 2): untyped Pointer(p)^ expression form FIXED; wall = method by-ref args

Pointer(expr)^ now parses (builtin-cast branch grew a deref postfix, modeled as a Byte lvalue — address-identical for untyped params; test_ptr_untyped_deref in test-core). synautil advances to Stream.read(PAnsiChar(Result)^, Len) — the METHOD-call by-ref argument path still resolves bare idents only: filed [[bug-cast-deref-as-varparam-arg]] (Track P, prio 50). That is now the single wall in front of the whole synautil compile.

2026-07-12 (morning): full-unit probe matrix at HEAD + ESys errno batch

unit state
synafpc, synacode compile OK
synautil, synaip, asn1util, synachar ONE wall: [[bug-cast-deref-as-varparam-arg]] (Stream.read(PAnsiChar(x)^, …) method by-ref arg)
synsock, blcksock, httpsend, smtpsend, pop3send, ftpsend were ESysEINTR ConstEval — fixed (42 ESys* errno consts added to lib/rtl/baseunix); now stop at [[bug-pascal-nested-variant-record-tagged]] (ssfpc.inc TVarSin)

So the ENTIRE Synapse stack is behind exactly TWO Track P parser tickets: cast-deref-as-varparam-arg (prio 50) and nested-variant-record-tagged (prio 55). Runtime caveat once compiling: synacode's DecodeBase64/MD5 had const-table codegen corruption historically (Track A fixes since landed in done/) — re-verify values, don't assume.

Session log 2026-07-12 (opus-p, Track P+B)

HTTP chain GREEN end-to-end. synsock, synautil, synaip, asn1util, synacode, blcksock, httpsend, smtpsend, pop3send all compile with --mimic-fpc -Fuexternal/synapse -Fulib/rtl -Fulib/rtl/platform/posix. Runtime smoke: THTTPSend.HTTPMethod('GET', 'http://example.com/') → 200, 559 bytes, body matched — over our own sockets/DNS RTL, no libc.

Parser fixes this session (commits 541f8fda, 2b2a0c29, +HTTP-chain commit): nested variant records w/ tagged discriminant (TVarSin, SizeOf=28 = FPC), cast-deref by-ref args (PChar(s)^), qualified type refs (sockets.Tin6_addr), const concat of named char consts (CRLF = CR + LF), metaclass const/var init (TSSLClass = TSSLNone), class aliases (TOptionList = TList), FField.Free / property.Free, @obj.field, f(...)^ untyped deref, SizeOf(obj.field), System.X-beats-param, proc-property invocation, MAX_METHFIX 8192, and the CRITICAL AllocParam SymBlockId recycling bug (on-handler poisoned the next routine's params — pre-existing in v202).

RTL additions: sockets (fpGetPeerName/fp{Set,Get}SockOpt/fpIoctl, in6 union arms, NetAddrToStr(6)/StrToNetAddr(6), HostToNet/NetToHost), netdb shim over lib/rtl/dns, unix.GetHostName, sysutils (GetTempFileName, SetString, StrToInt64Def, LastDelimiter, AdjustLineBreaks), classes (TStrings LoadFromStream/SaveToStream/Assign/AddStrings, writable TStream.Size).

Remaining:

Update 2026-07-12 (later, opus-p)

Log