Skip to content

feat(#77,#80): platform space-consistency invariant + P3 async error-context.drop lowering#810

Merged
avrabe merged 3 commits into
mainfrom
feat/49-platform-semantics
Jul 17, 2026
Merged

feat(#77,#80): platform space-consistency invariant + P3 async error-context.drop lowering#810
avrabe merged 3 commits into
mainfrom
feat/49-platform-semantics

Conversation

@avrabe

@avrabe avrabe commented Jul 17, 2026

Copy link
Copy Markdown
Contributor

Bounded v0.49 hub Lane 7 (BREADTH — platform semantics). Two sub-parts, each red-first and oracle-gated. Refs #77, #80.

Part A — #77: execution-space / memory-space consistency invariant

Gives the RAJA/Kokkos execution-space + memory-space choice a checked property, not a convention. New synth_memory::space model (ExecutionSpace × MemorySpace) with PlatformSpaces::validate() enforcing two consistency invariants:

  1. OS-mapping: a bare-metal execution space cannot use an OS-mapped (Linux-only) memory space; a hosted space cannot claim a physical on-silicon space (Flash/TCM/ExternalRAM). (the issue's own worked example.)
  2. FPU capability: an FP-requiring memory space cannot be hosted by an FPU-less core (Cortex-M0).

An inconsistent pairing is REJECTED with a machine reason naming the offending space (SpaceError).

Red-first evidence: 7 unit tests cover both directions of each invariant; neutering validate() to always-Ok fails 4 rejection tests.

Bounded scope: geometry (linmem/globals overlap, static-data addressing) is deliberately OUT — owned by synth_core::static_data_addr (VCR-VER-003, no file overlap with L2). This is a standalone model; wiring into live target selection is a named follow-up (disclosed in TP-009).

Part B — #80: P3 async intrinsic compilation (honest degradation)

Meld lowers P3 async components with RFC #46 host intrinsics under the pulseengine:async module. Synth's raw call lowering to a field-name BL already exists (#197 relocatable path); the missing piece is the semantic gate. New synth_core::async_intrinsics classifier, wired at the single CLI import-collection choke point (before instruction selection → both selector paths covered):

  • LOWERED: exactly error-context.drop — a pure scalar handle op (one i32 handle in, nothing out). It marshals as an ordinary AAPCS C call and compiles to a BL error-context.drop call site (UNDEF symbol the host linker resolves against kiln-builtins).
  • DECLINED by name with a machine reason: error-context.new / .debug-message (they carry a linmem message pointer — the SAME bounds-checked buffer class as stream, NOT scalar), stream, future, waitable-set/task (register save/restore across the scheduler yield). Unknown async intrinsics also decline.

The lowering decision is per op, not per family — lowering error-context.new as if scalar would silently miscompile its pointer argument (the exact bug #80 exists to prevent).

Gate evidence: 7 unit tests + 2 CLI end-to-end tests. The lowered op compiles to a relocatable ELF carrying error-context.drop in the symtab (executes-vs-reference ABI contract, checked via symtab not disasm); each of 5 declined-op fixtures FAILS the compile with the #80 reason.

Contract caveat: the pulseengine:async namespace and dotted resource.method field format are synth's assumed contract pending meld#94 — the gate does not fire until Meld's lowering confirms these strings. Pinned in one place citing RFC #46.

Frozen / gates

🤖 Generated with Claude Code

https://claude.ai/code/session_01YJK5LZZEkV5smCY1jKn18L

avrabe and others added 3 commits July 17, 2026 13:21
Formalize the RAJA/Kokkos execution-space + memory-space choice as a CHECKED
property, not a convention. New synth_memory::space model:

- ExecutionSpace (BareMetal{core} | Hosted) + CortexM core capability
- MemorySpace (Flash/SRAM/TCM/ExternalRAM/OsMapped backing, requires_fpu)
- PlatformSpaces::validate() enforces TWO consistency invariants:
  1. OS-mapping: bare-metal cannot use OS-mapped space; hosted cannot claim
     a physical on-silicon space
  2. FPU: an FP-requiring space cannot be hosted by an FPU-less core (M0)

Inconsistent pairings are REJECTED with a machine reason naming the offending
space (SpaceError). Red-first: 7 unit tests cover both directions of each
invariant; neutering validate() to always-Ok fails 4 rejection tests.

Geometry (linmem/globals overlap, static-data addressing) is OUT of scope —
owned by synth_core::static_data_addr (VCR-VER-003). This is a standalone
model; wiring into live target selection is a named follow-up.

rivet: TP-009 (system-req) + TP-VER-001 (sys-verification, verifies TP-009).

Implements: TP-009
Verifies: TP-VER-001

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YJK5LZZEkV5smCY1jKn18L
…ine the rest

Honest-degradation gate for RFC #46 P3 async host intrinsics (imported under
the pulseengine:async module by Meld's P3 lowering). New
synth_core::async_intrinsics classifier:

- LOWERED: error-context family (pure scalar handle ops — .new/.debug-message/
  .drop). These marshal as an ordinary AAPCS C call and flow through the
  existing relocatable field-name BL host-link path (#197), emitting an UNDEF
   symbol the host linker resolves against kiln-builtins.
- DECLINED by name with a machine reason: stream (needs bounds-checked buffer
  memory layout), future (readable/writable-end protocol), waitable-set/task
  (register save/restore across the scheduler yield). Unknown async intrinsics
  also decline rather than blindly BL an unspecified contract.

Wired at the single CLI import-collection choke point (before instruction
selection, so both selector paths get the gate). Non-async imports classify
NotAsync → byte-invisible (frozen fixtures unchanged; only pulseengine:async
fires the gate).

Gate evidence:
- synth-core async_intrinsics: 6 unit tests (classification of every family)
- synth-cli async_intrinsics_gate: 2 CLI e2e tests — error-context compiles to
  a relocatable ELF carrying  as the BL target symbol
  (executes-vs-reference ABI contract via ELF symtab); each declined family
  (stream/future/waitable-set/task) FAILS the compile with the #80 reason.
- frozen control_step 13/13 PASS (byte-invisible)
- CI oracle steps appended to ci.yml (#77 + #80)

rivet: KB-010 (system-req) + KB-VER-001 (sys-verification, verifies KB-010).

Implements: KB-010
Verifies: KB-VER-001

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YJK5LZZEkV5smCY1jKn18L
…drop

Two fixes:

1. WIRING (the prior commit lost these to an editor revert): re-add the
   `pub mod async_intrinsics;` decl in synth-core/lib.rs, the CLI import-gate
   in synth-cli/main.rs, the ci.yml oracle steps (#77 + #80), and the KB-010/
   KB-VER-001 rivet artifacts. Without the mod decl + CLI gate, the async
   classifier was dead code and no module actually declined — verified by
   re-running the CLI gate against a freshly-rebuilt binary.

2. SOUNDNESS (advisor review): lowering is now decided PER OP, not per family.
   error-context.new and error-context.debug-message carry a linmem message
   pointer (canonical ABI) — the SAME bounds-checked buffer class synth
   declines for stream — so lowering them as 'scalar' would silently
   miscompile the pointer arg. Only error-context.drop (one i32 handle in,
   nothing out) is lowered; LOWERED_FIELDS is exactly {error-context.drop}.
   The other error-context ops now decline with the buffer reason. New fixture
   async_error_context_new_declined.wat + CLI-gate case cover it.

Gate re-verified on a rebuilt binary: error-context.drop compiles (UNDEF
symbol in symtab); stream.read, error-context.new all exit 1 with the #80
reason. 7 unit + 2 CLI tests green; frozen control_step 13/13; claim 25/25;
rivet artifacts add 0 errors; fmt/clippy clean.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YJK5LZZEkV5smCY1jKn18L
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