Skip to content

feat(parser): wasm parser-module loader, hardening, and authoring target (0.23.0) — postponed - #173

Draft
facontidavide wants to merge 2 commits into
mainfrom
feat/parser-extensibility-1b
Draft

feat(parser): wasm parser-module loader, hardening, and authoring target (0.23.0) — postponed#173
facontidavide wants to merge 2 commits into
mainfrom
feat/parser-extensibility-1b

Conversation

@facontidavide

@facontidavide facontidavide commented Aug 8, 2026

Copy link
Copy Markdown
Contributor

SDK PR 1b of the parser-extensibility v4 architecture (spec, PlotJuggler/pj-official-plugins#272) — stacked on #172 (feat/parser-extensibility-1a). A second loader for the already-frozen ABI: wasmer execution, hardening, budgets, and the wasm authoring target. Merge #172 first; this PR then retargets to main. Per maintainer decision the stack carries a single version increment: this PR keeps VERSION at 0.22.0 and folds its changelog into the 0.22.0 entry (no 0.23.0).

Exit-criterion prototype findings (spec §13 gate)

  • The pinned libwasmer.a (7.0.1, static) declares but does not export wasm_module_share/obtain — the loader uses engine-owned module reuse: one compilation, store-per-bound-instance, isolated state verified.
  • No creator-thread affinity observed; calls are sequential-only, host-serialized (documented in the loader header — per-store executors remain PR-2 host work).
  • The lib exports the full wasmer_metering_* C API but no interrupt/epoch/deadline surface — execution limits are enforceable instruction metering (fresh allowance per guest call), not a wall-clock watchdog that couldn't fire.

Surface

Area Contents
Loader Validation before instantiation: manifest section (shared codec, exactly one), reactor enforced (_initialize; start/_start rejected), export names and signatures audited via the shared pj_base wasm inspector, empty frozen import allow-list (a parser module may import nothing)
Runtime Metered store-per-instance execution; linear-memory base re-acquired at every point of use, overflow-safe bounds; splices resolve against the original host payload; shared fault taxonomy + strike tracker with quarantine replay
Caps & budgets Artifacts must declare a linear-memory maximum (default cap 256 MiB, engine-enforced at runtime); session budgets (modules / artifact size / claims / instances / aggregate declared memory) gate admission with DECLINE, no mutation on rejection
Adversarial fixtures Unreachable trap, metered infinite loop, memory-growth bomb, admission limits, quarantine replay → repeat-disable, plus the load-rejection matrix
Authoring pj-wasm-embed-manifest installed CLI (embed/verify); pj_add_parser_module(... TARGETS native wasm) builds both artifacts from one source with a post-link audit — dogfooded on the toy module
Packaging wasmer required only by the plugin_host component; plugin_sdk consumers stay wasmer-free. PJ_WASMER_ROOT gate with graceful skip; CI installs wasmer 7.0.1 and runs the wasmer-labeled tests

Verification

  • 79/79 Debug+ASAN with both toolchain roots (wasi-sdk 27 + wasmer 7.0.1); graceful-skip verified for each root independently
  • Installed-package consumer produced native + wasm artifacts from one source
  • Process: milestone reviews with independent re-verification (1b-M1, 1b-M2), a simplification pass, and one error-path leak fix (metering middleware adapter failure) before squashing

🤖 Generated with Claude Code

@facontidavide
facontidavide force-pushed the feat/parser-extensibility-1b branch from 8dfaa32 to 6bc55f6 Compare August 9, 2026 09:11
@facontidavide
facontidavide force-pushed the feat/parser-extensibility-1a branch from ad01f03 to babd073 Compare August 9, 2026 09:18
@facontidavide
facontidavide force-pushed the feat/parser-extensibility-1b branch from 6bc55f6 to d02344d Compare August 9, 2026 09:21
@facontidavide facontidavide changed the title feat(parser): wasm parser-module loader, hardening, and authoring target (0.23.0) feat(parser): wasm parser-module loader, hardening, and authoring target Aug 9, 2026
@facontidavide
facontidavide force-pushed the feat/parser-extensibility-1b branch 2 times, most recently from 0279ed5 to 21f11b7 Compare August 9, 2026 09:42
@facontidavide
facontidavide marked this pull request as draft August 9, 2026 10:05
@facontidavide
facontidavide force-pushed the feat/parser-extensibility-1a branch from babd073 to 4e42f8b Compare August 9, 2026 11:03
@facontidavide
facontidavide force-pushed the feat/parser-extensibility-1b branch from 21f11b7 to 93931f0 Compare August 9, 2026 11:03
@facontidavide
facontidavide marked this pull request as ready for review August 9, 2026 11:03
…0.22.0)

SDK core of the parser-extensibility v4 architecture (spec: pj-official-plugins
PR #272) — the complete wasmer-free surface, with the dual-target module ABI
frozen here:

- pj.parser_route_claims.v1 extension: exact handler-table route claims
  (scalar/object, exact-only match), auto-implemented by
  MessageParserPluginBase from its handler table; delivery via
  get_plugin_extension, zero layout changes
- pj.parser_functional.v2: object sink gains accept_object_spliced (one
  splice per object, input-space offsets, frozen per-type eligibility table
  in builtin_object_abi.h); frozen error-kind constants; v1 byte-identical
- parser_module_abi.h: frozen pj_module_* export ABI (u64 module-space
  tokens, token-0 creation-error channel, 512-byte error buffer) +
  bounds-checked little-endian codecs for BindingInfo / parse-input /
  output-descriptor blocks
- host claim catalog + route resolver: §4 admission matrix (priority bounds,
  wildcard/object rules, encoding registry, duplicate identity, provenance
  never from manifests), module-manifest ingestion, synthesized plugin claim
  ids (wildcard:<encoding>, handler:<encoding>:<type>), §5 selection
  (pin fail-closed → exact > wildcard → provenance tier → priority →
  identity tie-break) with split per-route probe caches and selection traces
- native module loader (dlopen RTLD_LOCAL|RTLD_NOW, per-handle export
  resolution, session never-unload) + module runtime over the codecs with
  splice eligibility/bounds validation and the fault-vs-data-error strike
  tracker (3 strikes → quarantine → recreate; repeat → session disable)
- authoring kit pj_base/include/pj_base/parser_module/: header-only,
  C++17, wasi-clean (own Status/Expected/arena; -fno-exceptions capable);
  CdrReader + CdrFieldLocator (XCDR1 traversal plans, depth caps, bounds),
  ProtoReader + ProtoFieldLocator, checked time normalization, canonical-wire
  ObjectWriter (PointCloud/Image + splice path), pj::FunctionalParser +
  PJ_FUNCTIONAL_PARSER macro, pj_add_parser_module() native target
- wasm manifest custom-section codec (shared embed/read; 1b's tooling wraps
  it) + static wasm ABI conformance: wasi-sdk 27 reactor build of the same
  toy module, binary-format audit of export names/signatures, reactor model,
  and single manifest section — no wasmer, gated on PJ_WASI_SDK_ROOT, wired
  into linux CI

Tests: 75/75 Debug+ASAN (74 with the wasm gate skipped), incl. layout
sentinels, golden byte fixtures, adversarial loader/runtime fixtures, and a
kit-authored module E2E (load → admit → bind → full + spliced PointCloud).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@facontidavide
facontidavide force-pushed the feat/parser-extensibility-1a branch from 4e42f8b to 08503f7 Compare August 9, 2026 11:34
@facontidavide
facontidavide force-pushed the feat/parser-extensibility-1b branch from 93931f0 to f977260 Compare August 9, 2026 11:34
…get (0.23.0)

SDK PR 1b of the parser-extensibility v4 architecture (spec: pj-official-plugins
PR #272), stacked on the core PR: a second loader for the already-frozen
module ABI — wasmer execution, hardening, and the wasm authoring target.
Ships as its own 0.23.0 release: the core PR lands first as 0.22.0 and this
one follows, so an SDK with the wasm loader is distinguishable from one
without it.

- wasmer 7.0.1 statically linked (pinned; required only by the plugin_host
  component — plugin_sdk consumers stay wasmer-free). Exit-criterion prototype
  findings encoded in the loader contract: the pinned static lib exports no
  wasm_module_share/obtain symbols (engine-owned module reuse: one compilation,
  store-per-bound-instance with isolated state) and no creator-thread affinity
  exists — calls are sequential-only, host-serialized. Pin re-evaluated against
  7.2.1: no C-API gains, WASI-syscall CVEs unreachable under the empty import
  allow-list, and 7.2 drops x86_64-darwin (rationale in ARCHITECTURE.md)
- wasm loader: validation before any instantiation — manifest custom section
  via the shared codec (exactly one), reactor model enforced (_initialize
  required, start section/_start rejected), operational export set verified
  by name AND signature through the shared pj_base wasm inspector, and a
  frozen EMPTY import allow-list (a parser module may import nothing)
- execution runtime: metered store-per-instance calls (the pinned lib exports
  the wasmer_metering_* C API but no interrupt/epoch/deadline surface, so
  limits are enforceable instruction metering — fresh point allowance per
  guest call, exhaustion = distinct contract violation), linear-memory base
  re-acquired at every point of use with overflow-safe bounds, splices
  resolved against the original host payload, shared fault taxonomy + strike
  tracker with quarantine replay
- memory caps at validation: artifacts must declare a linear-memory maximum
  (default cap 256 MiB); the engine enforces it at runtime. Aggregate session
  budgets (modules, artifact size, claims, active instances, declared memory)
  gate admission with DECLINE and mutate nothing on rejection
- adversarial fixtures: unreachable trap, metered infinite loop, memory-growth
  bomb, admission limits, quarantine replay — plus the M1 rejection matrix
- pj-wasm-embed-manifest installed CLI (embed/verify) wrapping the shared
  section codec; pj_add_parser_module(... TARGETS native wasm) builds both
  artifacts from one source with post-link audit, dogfooded on the toy module
- fix: release the metering middleware on the adapter-failure path
- VERSION 0.23.0, CHANGELOG entry, CI wasmer job (metering-symbol check)

Tests: 79/79 Debug+ASAN with both toolchain roots; graceful skip verified for
each root independently.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@facontidavide
facontidavide marked this pull request as draft August 9, 2026 14:28
@facontidavide
facontidavide force-pushed the feat/parser-extensibility-1b branch from f977260 to 878cb93 Compare August 9, 2026 14:28
@facontidavide facontidavide changed the title feat(parser): wasm parser-module loader, hardening, and authoring target feat(parser): wasm parser-module loader, hardening, and authoring target (0.23.0) — postponed Aug 9, 2026
@facontidavide

Copy link
Copy Markdown
Contributor Author

Postponed — the core PR (#172) merges first on its own as 0.22.0.

This was the explicit rationale for splitting the SDK work in two: 1b is a second loader for an ABI that #172 already freezes, so deferring wasm delays wasm, never the architecture. Nothing here blocks #172, and #172 ships a complete native module story on its own.

State of this branch while it waits:

  • VERSION restored to 0.23.0 with its own CHANGELOG section (the single-bump arrangement only made sense when the two merged back to back).
  • Rebased on the current feat/parser-extensibility-1a; 80/80 with both toolchains (wasi-sdk 27 + wasmer 7.0.1), all review findings fixed.
  • After feat(parser): extensible parser routing + functional parser modules (0.22.0) #172 merges this needs a rebase onto main and a retarget; then it is ready for review as-is.

🤖 Generated with Claude Code

@facontidavide
facontidavide force-pushed the feat/parser-extensibility-1a branch from 08503f7 to 3501581 Compare August 9, 2026 14:41
@facontidavide

Copy link
Copy Markdown
Contributor Author

Note for revival: feat/parser-extensibility-1a has since been amended (docs + skills synchronized, VERSION made a CMake configure dependency), so this branch now trails it.

When picking this back up, after #172 merges: rebase onto main, then expect doc conflicts in parser_module/README.md, pj_plugins/CLAUDE.md, and pj_plugins/docs/ARCHITECTURE.md#172 rewrote those to describe the native-only 0.22.0 surface, so this PR's wasm sections need re-applying on top of that new baseline rather than merged blindly. The wasm authoring reference (.claude/skills/plotjuggler-plugin/references/parser-module.md) also currently documents native-only targets and will need its wasm section.

Deliberately not rebased now to avoid resolving those conflicts twice.

🤖 Generated with Claude Code

@facontidavide
facontidavide force-pushed the feat/parser-extensibility-1a branch from 3501581 to 817130e Compare August 9, 2026 14:49
Base automatically changed from feat/parser-extensibility-1a to main August 9, 2026 14:57
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant