Skip to content

v0.2.7-dev

Pre-release
Pre-release

Choose a tag to compare

@splanck splanck released this 01 Jul 02:30

Viper Compiler Platform — Release Notes

Development Status: Pre-Alpha. Viper is under active development and not ready for production use.

Version 0.2.7 — Pre-Alpha (2026-06-30)

What this release is about

A hardening cycle continuing v0.2.6, with focused new capability in 3D, tooling, and the languages.

For 3D and game code, the renderer stops flickering frame-to-frame and gains spot-light shadows, a deterministic multi-threaded software rasterizer, node animation over a rebuilt glTF/FBX importer, and open-world streaming with navmesh export. ViperIDE becomes a real workbench — syntax highlighting, context menus, two-language formatting and language services, an activity bar with git source control, multi-root workspaces, an integrated terminal, and a VM debugger that steps, inspects locals, and evaluates watch expressions. A new agent-facing CLI (viper check/eval/explain) gives editors and scripts machine-readable diagnostics. The 2D drawing surface adds bitmap text and normalized gradients, and Zia gains integer-keyed maps and header-optional modules.

Underneath, the hardening backbone matters most to your running programs: recoverable runtime and asset-loader errors now fail closed — bad or hostile input returns null or a safe value instead of crashing — and one program produces identical results across the tree-walking VM and both bytecode engines, which now also run threaded Parallel/Pool callbacks. The GUI is re-skinned through a shared anti-aliased core, a codegen performance round retires the last -O0 demo carve-outs so every demo now builds at -O2, and Linux and Windows/MSVC both return to a fully green test suite.

  • Graphics3D flicker stabilized. Occlusion history with covered-streak gating, depth-fitted shadow cascades, LOD/impostor hysteresis, and terrain-horizon culling end per-frame triangle flicker; every backend validates draw-command index ranges.
  • Spot-light shadow maps (new). Shadow-casting spot lights share the directional shadow budget across all four backends, sampling with a perspective divide and cone-angle suppression.
  • glTF/FBX import & node animation (new). NodeAnimation3D/NodeAnimator3D play node, camera, and morph-weight clips; the FBX importer gains full transforms, cubic curves, PBR routing, and async loading.
  • Deterministic software rasterizer. A worker-pool rasterizer reproduces the single-threaded image bit-for-bit, so headless and CI renders stay reproducible while throughput scales with cores.
  • Open-world streaming & navmesh tooling (new). WorldStream3D cells load into a resident-byte budget, NavMesh3D.Export/Import round-trip versioned VNAVMSH2, and stream manifests resolve asset:// sidecars.
  • Runtime fails closed (repo-wide). Every recoverable runtime error now returns a safe sentinel instead of trapping, so malformed or hostile input degrades your program rather than crashing it; the lone exception — unrecoverable entropy/DRBG failure — aborts outright, so no path ever proceeds with predictable key material.
  • Asset loaders fail closed (new). Corrupt, truncated, or oversized 2D images and 3D models/scenes return null with queryable diagnostics; a shared count guard rejects any element count larger than its backing bytes, and libFuzzer harnesses keep the parsers crash-free.
  • Game3D degradation diagnostics (new). A process-wide Game3D.Diagnostics3D surface counts the rare correct-but-degraded fallbacks (brute-force broadphase, clamped CCD, evicted audio voices, navmesh-grid fallback) so smoke probes can assert a clean run.
  • Backend & audio telemetry (new). Opt-in Canvas3D backend counters (draws, dropped draws, mesh-cache hits/misses, stream uploads, fallback binds, active presentation path) and an audio-mixer diagnostics surface (renders, partial writes, xruns, recoveries, write failures) make a degraded render or audio path measurable rather than silent.
  • Audio effects and consolidation. Mix groups gain low-pass, high-pass, peaking EQ, delay, and reverb insert chains; spatial audio is consolidated under one runtime home (src/runtime/audio/).
  • IL & codegen invariants validate in release. The IL builder promotes debug-only invariants to release-mode validation, the verifier makes the EH resumetok a linear handler-provenance capability (ADR 0005), and codegen and the linker surface diagnostics instead of asserting.
  • Codegen performance round, and every demo at -O2. The AArch64 allocator unlocks all sixteen argument registers and caches spilled-operand reloads, and shares pre-RA copy-forwarding with x86-64 (six correctness fixes accompany the perf work); two optimizer fixes — verifier-accurate inliner type inference and SSA-reconstructing loop rotation — retire the last -O0 demo carve-outs so every demo now builds and runs at -O2.
  • Unified scalar semantics (new). Your program now produces identical values and trap behavior whether it runs on the tree-walking VM or either bytecode engine — a VM-neutral kernel backs all three; block/instruction storage also moves to stable-address containers so references survive edits.
  • Interpreted threaded callbacks (new). Parallel.For/Parallel.Invoke/Pool.Submit run their callbacks on the tree-walking and bytecode VMs — synchronously on the calling thread — while sequence-typed forms trap with explicit VM diagnostics rather than mis-dispatching to native; the shared default pool now drains before runtime-context teardown so a worker can't outlive the context it borrowed.
  • GUI refined-depth visual pass. A shared anti-aliased vg_draw core and new theme tokens route the whole widget set through one rounded, elevated style; ViperIDE gains vector toolbar icons and a GUI.GroupBox settings card, plus an IDE-facing toolkit round — general-purpose GUI.Grid/GUI.PopupList widgets, OutputPane cell metrics, logical-unit layout helpers, and a revision-generation Threads.Scheduler dimension (ADRs 0019–0024).
  • ViperIDE editor & debugging (new). The code editor gains Viper/IL syntax highlighting, a compiler-driven semantic-color overlay, indentation guides, right-click context menus, and read-only preview enforcement (ADRs 0007–0008, 0011), plus Zia and new BASIC formatting; the VM-backed debug adapter (viper run --debug-adapter) replaces v0.2.6's non-executing placeholder with pause/continue/step in-over-out, breakpoints, call stacks, locals, a current-line gutter marker, and non-blocking stop, and evaluates a selected expression or the identifier under the cursor against the stopped frame (ADR 0009) — alongside a Workspace.FileIndex.Status-backed project index (ADR 0010), persistent UI zoom, and build-duration/error status.
  • ViperIDE workbench surfaces (new). An activity bar swaps the file Explorer for a full git Source Control view (stage/unstage, commit, push/pull, branch, per-file diff over Viper.System.Exec); workspaces hold multiple roots; an integrated terminal runs a real shell over a new Viper.System.Pty pseudo-terminal runtime (ConPTY on Windows, posix_openpt/fork on POSIX); and BASIC editing gains the completion, diagnostics, hover, and document symbols Zia already had via a consolidated Viper.Basic.LanguageService (ADRs 0013–0016).
  • Agent-facing CLI (new). viper check, viper eval, and viper explain/--print-error-codes over a central diagnostic-code catalog, plus --dump-runtime-api/--dump-opcodes registry dumps; the LSP/MCP servers now carry the same structured diagnostics.
  • 2D drawing surface (new). Pixels gains bitmap-font text drawing and measurement (plain, scaled, centered/right-aligned) and Gradient2D adds normalized Sample/SampleRGBA with legacy-percent aliases — the runtime backing for a Viper Paint rebuilt around a registry-driven tool set with layers, blend modes, and an HSL picker.
  • Zia integer maps & header-optional modules (new). Map[Integer, T] lowers to the IntMap runtime (string-keyed Map unchanged) with declared key-type enforcement; source files may omit the module header (defaulting to Main); and the parser, lexer, and semantic checks tighten across precedence, diagnostics, and inheritance-aware visibility.
  • Runtime class names disambiguated. Colliding leaf names under Viper.* are made unique (Graphics.SceneSceneGraph, the Game.UI widgets that shadowed GUI ones→Hud*, Sound3DSpatialAudio3D) and duplicate Parse/Convert fold into Viper.Core.*, with old names kept as aliases and a test locking the no-collision invariant.
  • Windows and Linux builds back to green. Windows restores the BASIC-VM, installer, ViperIDE, and x86-64 suites and closes its D3D11 sign-off gaps; Linux returns to a full green suite — 1,670 passing.

By the Numbers

Metric v0.2.6 v0.2.7 Delta
Commits 191 +191
Source files 3,096 3,402 +306
Production SLOC 669K 762K +93K
Test SLOC 278K 304K +26K
Demo SLOC 192K 197K +5K

Counts via scripts/count_sloc.sh (production 761,859 / test 304,255 / demo 196,632 / source files 3,402); commits since the v0.2.6-dev tag (2026-06-01).


Graphics3D rendering

  • A sustained pass ends per-frame visible-triangle flicker: queue-order-independent occlusion history with covered-streak gating, camera-depth-fitted shadow cascades, per-camera LOD/impostor hysteresis, and conservative terrain-horizon culling.
  • Every backend (software/OpenGL/Metal/D3D11) validates draw-command index ranges and shares one depth-bias scale. D3D11 closes its sign-off gaps and routes uploads and screenshot readback through shared helpers that reject oversized, unaligned, or stale GPU state, and clamps post-FX scalar/enum inputs and effect-chain capacity before indexed passes; OpenGL drains GPU errors after every upload and bounds its texture/mesh caches by age and LRU.
  • The software backend rasterizes across a deterministic worker pool — parallel scanline fills that reproduce the single-threaded image bit-for-bit — so headless and CI renders stay reproducible while throughput scales with cores.
  • Shadow-casting spot lights join the shared directional shadow budget: a single perspective light view-projection drives all four shader languages, which perspective-divide spot coordinates and suppress contributions outside the cone while directional paths stay orthographic and cascaded.
  • Anisotropic filtering arrives as Material3D.Anisotropy (clamped 1–16, advertised via BackendSupports("anisotropy")), and Canvas3D exposes per-frame submission telemetry (DrawsSubmitted, SortPasses, BackendStateChanges) with stable radix/bucket sorts over reusable scratch. Opt-in backend counters add draw/dropped-draw, mesh-cache hit/miss, stream-upload, and fallback-bind totals plus the active presentation path, and a VIPER_OPENGL_PRESENT override compares the Linux GL direct, probe, and offscreen paths during triage.

3D assets, animation, and Canvas3D (new)

  • NodeAnimation3D/NodeAnimator3D play node, object, camera, and morph-weight clips, and SceneAsset/Assets3D can pull a single clip from an external file.
  • The FBX importer gains full model transforms (rotation order, pivots, Z-up), cubic curves, PBR texture-slot routing, and async loading; glTF accessor and skin-weight validation tightens.
  • New authoring helpers: DrawMeshWind foliage sway, DrawImage2D HUD blits, DrawMeshSkinned from an AnimController3D pose, native SetFullscreen/ToggleFullscreen (Game3D.Keys.F11), and Material3D depth-bias/ShadowMode.
  • Canvas3D adds BackendName and BackendFallback (true when init fell back to software), and a recoverable texture-fallback diagnostic records when a failed upload substitutes a placeholder, so a degraded frame is observable rather than silent.
  • Content loaders stop trapping on bad content: every 2D image and 3D model/scene loader returns null and records a thread-local last-error code/message (AssetDiagnostics3D.LastLoadError), reserving traps for null or invalid handles.
  • A shared rt_untrusted_count guard validates every element count read from a 3D asset against its backing bytes across the glTF, FBX, OBJ/STL, SceneGraph, and Game3D loaders, and new libFuzzer harnesses keep these parsers crash-free; the FBX importer parses ASCII doubles locale-independently, the glTF loader rejects unsafe accessor strides, and compound-collider and mesh-vertex growth became transactional so a failed resize leaves no half-built geometry.

Open-world streaming, navigation, and 3D safety

  • WorldStream3D cells load a binary sidecar into a resident-byte budget; NavMesh3D.Export/Import round-trip versioned VNAVMSH2 assets while still reading legacy VNAVMSH1; compressed TextureAsset3D uploads drain large mips across frames.
  • Non-finite interpolation, playback, and bone inputs across the animation stack clamp or revert to the bind pose; scene, transform, raycast, navigation, and physics entry points reject bad handles; stored references are class-checked so a reused slot is nulled rather than dereferenced.
  • Game3D async loads read worker-safe snapshots, drop stale publishes so a cancelled load can't overwrite current state, and finalize screenshot/render-target capture with no present side effect. The SceneGraph spatial index records a ~1,800× indexed-vs-flat cull speedup on a 10k-node fixture.
  • A retained Entity3D whose entity was despawned degrades predictably — neutral reads, no-op writes, a counted StaleEntityCalls touch — instead of trapping; genuinely invalid handles still trap.
  • Fallbacks that stay correct but shed fidelity are now observable: a process-wide Viper.Game3D.Diagnostics3D static exposes saturating counters (brute-force broadphase, clamped CCD, dropped animation events, evicted audio voices, navmesh-grid fallback, stale-entity touches) with a zero-omitting Summary(), and Physics3DWorld surfaces the same physics counts per world.
  • Physics3DWorld adds fixed-step controls (explicit timestep and substep budget) so the simulation advances deterministically and independently of render frame rate.

2D graphics and drawing (new)

  • Pixels gains a bitmap-font text surface — DrawText/DrawTextBg, scaled and centered/right-aligned variants, and TextWidth/TextHeight/TextScaledWidth measurement — so raster canvases can label themselves without a separate font path.
  • Gradient2D exposes normalized Sample/SampleRGBA over [0.0, 1.0] alongside SamplePct/SampleRGBAPct percent aliases, so existing integer-percent callers keep sampling the same stops as the public binding moves to Number.

Runtime hardening (fails closed)

  • A cppcheck-driven audit makes every recoverable rt_trap return a safe sentinel and release its locals across core, text, crypto, network, OOP, process, media decoders, and input helpers — and routes unrecoverable entropy/DRBG failures through a non-returning rt_abort, so no path proceeds with predictable key material.
  • Viper.Collections.F64Buffer and Viper.Collections.I64Buffer add packed numeric buffers with slice/copy, scalar math, element-wise add, dot, min/max, and List/Seq conversion coverage.
  • Viper.System.Shutdown adds a poll-based graceful shutdown bitmask so Ctrl-C/SIGTERM can be consumed by long-running loops before they become interrupt traps.
  • Viper.Time.TimeZone adds deterministic embedded IANA-zone lookup for UTC, Tokyo, New York, and Sydney, with DateTime.ToZone and DateTime.FormatInZone covering fixed offsets plus northern and southern DST transitions without host zoneinfo dependencies.
  • Game runtime content caps soften: Physics2D bodies/contacts/joints, quadtree result/pair buffers, ScreenFX slots, and in-game UI text/table/dropdown/modal storage now grow from documented default reservations instead of stopping at fixed internal arrays.
  • BigInt gains checked size arithmetic and full arbitrary-width two's-complement bitwise/shift semantics; heap-header validation is now active in release builds (not just debug), realloc routes through a registry-safe move path, heap and pool allocation validate payload headers under the registry lock, and the pool freelist takes a short spinlock so a concurrent pop never reads a stale next pointer.
  • Text-format parsers fail closed and reach further: CSV/JSON preserve parse-failure state through trap recovery, HTML/XML grow traversal stacks under overflow checks, Markdown normalizes entity-obfuscated URL schemes, and TOML extends to escapes, inline tables, and arrays of tables.
  • RSA verification goes constant-time; HTTP/2 framing, empty-body suppression, the WSS accept-vs-Stop race, and retry jitter tighten. Temp-file, archive, and savedata names draw their random suffixes from one centralized rt_entropy_platform_random_u64 (POSIX and Windows) and fail closed when secure entropy is unavailable; runtime-facing randomness is seeded from the RNG and counters rather than object addresses or fixed seeds; and the GIF and Theora/OGV decoders roll back per-frame so a corrupt packet leaves decoder state intact.
  • The sweep continues into output, process, and teardown paths: string-builder append checks across the command-line, path, date/number, relative-time, text-direction, SaveData/action-binding JSON, TOML, and XML formatters return clean sentinels instead of partial output; process launch moves to wide CreateProcess on Windows and posix_spawn with close-on-exec pipes on POSIX (draining captured output while waiting, never mutating process-wide SIGPIPE); TLS handshake/application secrets and AES-GCM scratch are wiped on teardown; and HTTP/HTTPS/WSS worker pools size from the runtime CPU count with thread-pool backpressure and capped active connections.

IL, codegen, and the native linker

  • Debug-only IL-builder invariants — name uniqueness, operand and block-parameter bounds, branch-argument counts — promote to release-mode validation, and a new verifier dataflow catches double-release and use-after-release across the CFG.
  • The EH resumetok becomes a linear handler-provenance capability (ADR 0005): exception dispatch is its sole producer, and new resume_token_mismatch/handler_invalid_entry/resume_token_escape diagnostics reject forged or stale tokens at verify time. Native EH lowering seeds each handler with its post-dispatch stack so a trap inside a catch/finally resolves to a concrete outer frame.
  • The IL error and numeric specs are promoted to active normative status, with EH metadata synced to ADR 0005 and a CTest guard preventing trap-kind drift.
  • A VM-neutral ScalarOps kernel now backs the tree-walking VM and both bytecode engines, so one IL module yields identical values and trap kinds across every execution mode (bytecode format bumped to v3). Function::blocks/BasicBlock::instructions move to a stable-address StableList with interned Symbol handles so references survive insertion and erasure.
  • Shared AllocaRoots helpers make alias analysis conservative for unknown calls, ConstFold/SCCP/Peephole normalize integer folds to fixed result widths, and CheckOpt shares one checked-range implementation with the builder — now demoting proven-safe overflow-checked i64 arithmetic to plain ops.
  • Selection, encoding, Win64 unwind, and AArch64 relocations surface diagnostics instead of asserting — atop the shared frame-layout fix that closes the O1 miscompiles — and the native linker hardens its four object readers, relocation ordering, trampoline-island growth, symbol resolution, and PE-image writing with checked count arithmetic and validated section bounds. Two optimizer correctness fixes accompany the linker work: the inliner now infers escaped continuation-block parameter types the way the verifier does — ending the Void-typed iadd.ovf results that produced branch-argument/parameter mismatches — and loop rotation reconstructs SSA by threading body-used header parameters through the guard and latch edges, retiring the centipede/chess/crackman -O0 demo carve-outs.
  • Codegen performance. AArch64 unlocks all sixteen argument registers via clobber-aware eviction and collapses N block reloads to one resident home; x86-64 eliminates duplicated end-of-block spill stores, models memory dependences precisely, and stops treating LEA as a barrier. Six correctness fixes accompany the work.
  • VM↔native determinism gate, and writable globals natively. A byte-diffing differential runner over the shared IL corpus (viper -run versus codegen … -run-native) surfaced four native-codegen divergences from the tree-walking VM, now all fixed — including mutable scalar globals, which had no writable data section: the Mach-O, ELF, and COFF object writers now emit a .data/__data section, so gaddr on a global i64 @g = 41 resolves intra-object on both the x86-64 and AArch64 native paths.

Bytecode VM and support libraries

  • The bytecode VM validates memory ranges and indirect callees before dereference, traps instead of asserting on bad branch/switch targets, and bounds runaway programs via BytecodeVM.setMaxInstructions and a signal-safe interrupt.
  • Game3D loop helpers (run/runFixed/overlay variants) now accept script function references from both the tree-walking and bytecode VMs, not only raw native pointers — the bytecode VM invokes these callbacks re-entrantly while a native call is suspended, so script-defined loops drive the engine under either VM.
  • The Viper.Threads parallel surface joins them: Parallel.For/Parallel.Invoke/Pool.Submit dispatch their callbacks synchronously on the calling thread under either VM (bytecode extern handlers registered, an e2e IL regression covering tree-walker, bytecode-switch, and bytecode-threaded dispatch), while sequence-callback forms trap with explicit diagnostics instead of falling through to native dispatch. A latent teardown crash is closed by draining the shared default pool before runtime-context teardown — workers unbind while their owning context is still alive — and gate, barrier, and reader-writer-lock finalization stay safe when waiters outlive the owning runtime object.
  • Sound gains an audio-mixer diagnostics surface (render calls, partial writes, xruns, recoveries, unrecovered failures) and a reworked ALSA backend with explicit hw/sw PCM configuration and transient wait/recovery; WASAPI shutdown joins its worker thread under a diagnostic timeout, music-stream teardown waits for in-flight refills without blocking indefinitely, and pause/resume/recovery failures surface through the backend stats; attach-state synchronizes under the context lock, and event-queue overflow drops transient motion events before close/key-up/focus-lost; glyph caches, file dialogs, and the code editor gain overflow guards.

GUI refined-depth visual pass

  • A shared anti-aliased vg_draw core — rounded rectangles, discs, lines, soft shadows, gradients, deterministic fixed-point coverage — plus new radius/elevation/gradient/focus/motion theme tokens route buttons, inputs, dropdowns, menus, dialogs, tooltips, scrollbars, tabs, lists, and the file tree through one rounded, elevated style.
  • ViperIDE draws vector toolbar icons in place of Unicode glyphs, a titled GUI.GroupBox card and GUI.Label.SetWordWrap rebuild its settings panel, and gated hover/press/focus motion plus wheel-scrollable dialog content finish the pass.

ViperIDE — editor, debugging, workbench, and build feedback (new)

  • The code editor gains real syntax highlighting (ADR 0007): widened CodeEditor token colors over a stable syntax-token enum, overridable function/operator/bracket classes, and Viper/IL highlighters with .il files routed to the Viper one — plus toggleable indentation guides (CodeEditor.Set/GetShowIndentGuides) and tab hit-testing (TabBar.GetTabIndexAt), all added as registry-only runtime surface.
  • A compiler-driven semantic overlay (ADR 0008) layers classified colors over the lexical pass: a background Zia Tokens job feeds CodeEditor.AddSemanticToken/ClearSemanticTokens, debounced off the keystroke path and cleared on every document change so stale tokens never linger.
  • Right-click context menus arrive for the editor and the tab bar — close/copy/reveal plus the standard edit commands routed through the existing handlers (DocumentManager.GetDocument backs indexed menu actions) — and formatting reaches both languages, with the Zia formatter now ignoring braces inside strings and block comments and a new BASIC formatter handling whole-document and range formatting.
  • A debug adapter replaces v0.2.6's non-executing placeholder: viper run --debug-adapter drives pause, continue, step in/over/out, source breakpoints, call stacks, locals, and a current-line gutter marker over newline-delimited JSON, stops on unhandled traps before they unwind, and terminates without blocking the frame — force-killing the adapter only after a grace window. A watch/evaluate extension (ADR 0009) resolves a name against the current stop's frame snapshot — side-effect-free, returning ok:false for an unresolved name — so an editor Evaluate command can inspect a selected expression or the identifier under the cursor while paused, the foundation for hover-to-inspect.
  • The CodeEditor runtime gains read-only previews and an atomic gutter click (ADR 0011): preview, diagnostic, and binary buffers reject edits in the shared widget rather than in IDE command code, and breakpoint handling consumes one {clicked, line, slot} snapshot instead of racing three getters. Workspace.FileIndex.Status (ADR 0010) returns a metadata fingerprint so the IDE catches nested project-tree changes a non-recursive watcher misses, and the project tree is demand-loaded with a FileIndex-backed Quick Open cache.
  • Editor responsiveness and save safety tighten: semantic queries pump the workspace index to readiness before answering, hover/signature/inlay/symbol/search refreshes yield past a per-frame budget, Save As writes through a same-directory temp-and-move, external-change detection compares size and modified time, and an opt-out "save all before build/debug" default keeps project builds seeing fresh dependencies.
  • ViperIDE adds persistent UI zoom (GUI.App.SetUiScale), millisecond build-duration and error/warning status that auto-opens Problems on failure, and absolute-path resolution of the viper compiler before each build.
  • An activity bar restructures the shell's left edge into an always-visible icon strip beside a swappable view stack — the file Explorer plus a new Source Control view — sitting outside the editor split so dragging the splitter never shrinks it. Workspaces now hold a primary project plus extra roots, with AllRoots() and longest-prefix OwningProject(path) making tree population, the Quick-Open cache, and per-root ignore patterns root-aware; an Add Folder to Workspace command adds roots without closing the current project.
  • A git Source Control view drives git -C <repo> through Viper.System.Exec — status, per-file unified diff, stage/unstage and stage-all, commit, push, pull, branch, and switch — capturing reads and running writes through separate calls so exit codes stay reliable.
  • An integrated terminal runs a real shell in a toggleable bottom panel — an ANSI-aware OutputPane, command input, Run/Stop, and a View > Terminal entry — over a new Viper.System.Pty pseudo-terminal runtime: a single merged ANSI stream with window resize, distinct from the pipe-based Process, built on posix_openpt/fork/setsid/execvp on POSIX and dynamically-resolved ConPTY on Windows 10 1809+ (ViperDOS unsupported; ADR 0016). The session reroots in the active project, survives restart, resizes from panel geometry, reports process exit, and exposes bounded Pty.LastError() diagnostics for each unsupported-platform or setup failure.
  • BASIC editing gains the completion, diagnostics, hover, and document symbols ViperIDE already offered Zia, via a synchronous in-process bridge over parseAndAnalyzeBasic with weak runtime stubs that keep the runtime library frontend-free. It ships as a single Viper.Basic.LanguageService — consolidated from two leaf-colliding classes to hold the runtime's leaf-name-uniqueness invariant (ADR 0014) — with go-to-definition, references, rename, and signature help held back until BASIC grows a project index. A companion editor-input surface (ADR 0013) adds triple-click events and shared CodeEditor word/line selection so interpreted and native callers observe identical mouse semantics, and themes runtime-created context menus.
  • An IDE-facing GUI round (ADRs 0019, 0021–0024) adds two general-purpose widgets — a GUI.Grid auto-sizing tabular cell model and a caret-anchored GUI.PopupList with filtering, navigation, and consume-on-read acceptance — alongside OutputPane cell/text metrics, FloatingPanel.CenterInParent, App logical-unit conversion, CodeEditor.InsertAndPlaceCursor, and Viper.Text.Char identifier predicates; ViperIDE adopts them for PTY terminal sizing, logical-unit overlay centering, and identifier-keystroke classification, retiring the hand-rolled equivalents. A new generation dimension on Viper.Threads.Scheduler (ScheduleGen/IsDueGen, ADR 0020) tags each debounced entry with the document revision that queued it, so a superseded diagnostics, completion, or hover pass is discarded the moment a newer revision arrives.

Frontends, language servers, and CLI

  • BASIC arrays move to inclusive upper bounds with overflow-checked row-major indexing and multidimensional REDIM/LBOUND/UBOUND, over a case-insensitive symbol table that preserves type suffixes and retain-before-release string/object reassignment; overflow-aware numeric, line-label, and SELECT CASE parsing and numbered DIM fields inside CLASS bodies round out the pass. Zia restores circular and self binds by treating an in-progress bind as a known dependency rather than a fatal V1000.
  • Zia gains Map[Integer, T] over the integer-keyed IntMap runtime (string-keyed Map unchanged), enforcing declared key types and routing map literals, indexing, methods, optionals, and for-in iteration through the right helpers; source files may now omit the module header, defaulting to Main.
  • The Zia parser and lexer tighten: CR/CRLF normalization, ranged diagnostics for malformed literals and unterminated strings/comments, capped numeric-literal exponents, overflow-rejected fixed-array counts, bounded lookahead, error recovery across a missing enum-variant comma and untyped lambdas, and corrected precedence for shifts, bitwise operators, coalescing, ranges, and ternaries. Semantic checks add namespace-alias and imported-symbol conflict detection, inheritance-aware private/field access, constrained-generic interface checks through base classes, scope-qualified definite initialization, underscore-prefixed unused parameters, and duplicate-local/bodyless-function rejection.
  • The Text/Time/IO surface closes documented edge cases (TextWrap at width ≤ 0, locale-independent Json.Format, embedded-NUL rejection in DateOnly/DateTime).
  • A new agent-facing CLI: viper check is a fast type-check/verify gate (exit 0/1/2), viper eval runs a snippet in one shot with JSON results, viper explain/--print-error-codes read a central diag_catalog, and --dump-runtime-api/--dump-opcodes emit registry inventories from the live binary; viper bench gains a default watchdog step budget so a non-terminating IL benchmark reports the budget and skips remaining strategies instead of hanging (--max-steps 0 still runs unbounded). The CLI surface itself is made consistent: --help, version, and dry-run output go to stdout with a zero exit; conflicting (--debug-vm with --debug-adapter), empty, or missing-input flags are rejected; -O3, an inline --max-steps= form, and uniform --name value/--name=value package options are accepted; and every version string is sourced from the build macros rather than literals.
  • The BASIC/Zia LSP/MCP servers compute UTF-16 ranges, enforce a strict initialize-before-use lifecycle, and route structured diagnostics (code, stage, range, help, fix-its) so did-you-mean corrections reach editor clients; zia-server LSP now also exposes ProjectIndex-backed definition/references/rename plus signature help, workspace symbols, and semantic tokens, while vbasic-server keeps those unsupported capabilities unadvertised until BASIC has an equivalent project-index layer; the CLI rejects mismatched run/build/ABI combinations behind atomic, descriptor-safe outputs.
  • Both language servers collapse onto one templated runner with stricter protocol auto-detection — a leading { selects MCP and Content-Length selects LSP, any other first byte is a reported error rather than a silent MCP fallback — both report the real toolchain version, and MCP returns structuredContent alongside text behind argument-closed tool schemas. ViperIDE now models wired editor commands separately from external language-server support, so a server-supported feature with no IDE adapter reads as disabled-with-reason rather than missing.

Runtime class-name disambiguation

  • No two runtime classes share a leaf name under Viper.* anymore: each collision is renamed unique — Graphics.SceneGraphics.SceneGraph, GUI.ClipboardGUI.ClipboardText, Workspace.WatcherWorkspace.WorkspaceWatcher, the Game.UI widgets that shadowed GUI ones→HudLabel/HudTextInput/HudSlider/HudDropdown/HudTooltip, and Sound3DSpatialAudio3D — with the old fully-qualified names kept working through RT_ALIAS and a leaf-name-collision check in the qualified-surface test locking the invariant.
  • Duplicate Viper.Parse and Viper.Convert classes collapse into the canonical Viper.Core.Parse/Viper.Core.Convert, with the public Viper.Parse/Viper.Convert names preserved as function aliases.

Project loading and packaging

  • Convention detection scans real BASIC/Zia tokens, rejects sources that escape the project root through symlinks, and gates install hooks behind explicit manifest opt-ins.
  • Package and archive writers stage through same-directory temp files so a failed write leaves no partial artifact, hash assets with SHA-256, and detect a staged binary's OS/architecture from its object header rather than the host; ZIP archives stamp a fixed date by default for byte-identical output.
  • The Windows toolchain installer becomes a native dialog wizard (license display, user-vs-machine scope) with a native ARM64 bootstrap; Linux gains a self-extracting, FUSE-less AppImage toolchain package; and macOS packaging adds a styled .dmg wrapping the .pkg.
  • Packaged applications (not just the toolchain) now ship as first-class AppImage, RPM, and DMG targets: Debian and RPM builders share one FHS layout, the macOS bundle stages once for both ZIP and DMG, and every artifact is verified after creation. The Linux package builder derives its X11/ALSA/C++-runtime dependencies from the staged binary's ELF64 DT_NEEDED entries rather than a hand-kept list, the AppImage embeds and validates a payload SHA-256 and extracts through a mktemp workspace, and Linux application and toolchain packages can be GPG-signed via dpkg-sig/rpmsign.

Windows and Linux builds

  • On Windows, NOMINMAX, extended MSVC atomic shims, a standard-VM bridge that no longer double-releases borrowed strings, and an 8-job MSVC parallelism cap restore the BASIC-VM, installer, ViperIDE, and x86-64 suites, while the D3D11 backend closes its sign-off gaps.
  • On Linux, restored OpenGL symbol loading, X11 backing-store sizing, ELF zero-fill/PT_LOAD grouping, native-import coverage (native-linked programs no longer pull strtoumax or quad-precision helpers as dynamic imports), and ARM regression fixes bring the full suite to 1,670 passing; Linux now defaults to the deterministic software backend for reproducible headless and CI renders, with the hardened OpenGL backend explicitly selectable. The Linux audio and graphics adapters serialize ALSA PCM operations, guard process-global X11 state (Xlib threading initialized before the first display open, validated atoms and display-scale parsing), bound clipboard transfers, and honor LC_MESSAGES before LANG for locale detection.

Tests

~25K new test SLOC. CTest resource locks now serialize tests that share generated codegen or VM-trace artifacts, keeping the suite parallel-safe. A new source-health audit, registered under the audit/tools CTest labels, tracks high-ownership subsystem metrics — runtime API-surface counts, duplication and unsupported-path markers, stub and fuzz-corpus coverage, packaging verification, and TODO debt — against baseline limits, giving reviewers a source-backed ledger.

  • 3D rendering, assets, and animation — spot-shadow coordinate and budget-ordering coverage, vegetation sway, versioned navmesh round-trip, FBX/node-animation import, D3D11 upload/readback-helper validation, fail-closed content-loader diagnostics, untrusted-count guard and parser fuzz harnesses, and Game3D.Diagnostics3D fallback coverage.
  • IL, codegen, and cross-engine — IL release-lifetime and alias-analysis precision, VM-vs-bytecode scalar-semantics equivalence, AArch64 register-allocation regressions, duplicate-spill-store elimination, inliner escaped-type and loop-rotation SSA regressions, Game3D script-callback parity across interpreted and native runs, and interpreted Parallel/Pool callback dispatch across the tree-walker, bytecode-switch, and bytecode-threaded paths.
  • Agent CLI and diagnostics — the agent_cli suite, the diagnostic-code catalog, and structured bridge/MCP/LSP diagnostic and hover coverage.
  • Runtime, frontends, and GUI — media/pixel decode and a deterministic pixel-hash baseline, BASIC parsing and a B-code-catalog drift guard, Text/Time/IO edge cases, Zia integer-map, lexer/parser-diagnostic, and inherited-initializer coverage, Pixels text-drawing and normalized-gradient suites, GUI overlay/font-propagation regressions, ViperIDE activity-bar/multi-root/git-SCM and PTY-terminal probes plus BASIC language-service completion/diagnostics/hover/symbol coverage, and Linux AppImage/RPM/DMG application-package verification alongside the Windows installer-wizard coverage.

Demos and docs tracked the work. Three demos grew: game3d-showcase gained F11 fullscreen, wind-swayed foliage, a render-to-image minimap, spot shadows, a renderer/audio counter HUD, and a procedural fallback forest with expanded tree/terrain/sky scenes; the paint app was rebuilt around a registry-driven tool set — an HSL color picker, menu bar, and select/gradient/curve/polygon/spray/text tools over layers with blend modes and opacity; and crackman gained a vector chomp-and-death animation, pulsing power pellets, score popups, a frightened-state vignette, a looping siren, and a board-clear celebration. On the docs side, the Graphics3D guides, man pages, and codemap now cover spot shadows, backend-fallback observability, streaming, navmesh export, the agent-facing CLI, and the canonical class names, and the Bible reference was refreshed against the current Zia/BASIC/runtime APIs — handwritten appendices give way to docs/basic-reference.md and viper --dump-runtime-api, with a new scripts/audit_bible_examples.py compile/run-checking its runnable code fences. Internally, the runtime's largest source files split into focused per-feature modules, the Zia editor/IntelliSense services moved into zia_editor_services, ViperIDE's orchestration split out of main.zia into focused helper modules under viperide/src with an architecture guide, and socket/entropy/file-dialog logic consolidated into rt_*_platform_{win,posix}.c adapters.