feat(#77,#80): platform space-consistency invariant + P3 async error-context.drop lowering#810
Merged
Merged
Conversation
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
This was referenced Jul 17, 2026
Closed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
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::spacemodel (ExecutionSpace×MemorySpace) withPlatformSpaces::validate()enforcing two consistency invariants: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-Okfails 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:asyncmodule. Synth's raw call lowering to a field-nameBLalready exists (#197 relocatable path); the missing piece is the semantic gate. Newsynth_core::async_intrinsicsclassifier, wired at the single CLI import-collection choke point (before instruction selection → both selector paths covered):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 aBL error-context.dropcall site (UNDEF symbol the host linker resolves against kiln-builtins).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.newas 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.dropin the symtab (executes-vs-reference ABI contract, checked via symtab not disasm); each of 5 declined-op fixtures FAILS the compile with the#80reason.Contract caveat: the
pulseengine:asyncnamespace and dottedresource.methodfield 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
control_step13/13 PASS (byte-invisible — the async gate fires only on thepulseengine:asyncnamespace; non-async modules are untouched).flight_algoanchor unaffected by the same argument (import-free module, binary proven unchanged by control_step).cargo build -p synth-cli --features riscvclean; touched-crate + synth-cli tests green; clippy -D; fmt.claim_check.py25/25.sys-verificationcarry averifieslink;rivet validateadds 0 errors vs baseline (52/52).bazel test //coq:verify_proofsnot run (nothing to verify there).🤖 Generated with Claude Code
https://claude.ai/code/session_01YJK5LZZEkV5smCY1jKn18L