ogar-loco: hoist the vocabulary-agnostic call ABI out of ogar-blockly - #239
Merged
Conversation
Operator direction: elixir-shaped templates are a rails-shaped semantic over classid index, 256:256 — not much different than blockly, just a different vocabulary — and the surface must be reusable for any further frontend (Power-Automate-style flows are next in line). So the surface splits: ogar-loco carries everything that is the same no matter what the bytes MEAN; a vocabulary crate per domain carries the meanings. ogar-loco (new, zero-dep): - FnIndex / Call / LaneShape / FunctionBody / call_in_slab + layout constants + budgets, moved verbatim from ogar-blockly — bytes, semantics, and tests unchanged. - DOMAIN_FLOOR generalizes DEVICE_FAMILY_FLOOR: below the floor is the shared computational core, byte-stable across every vocabulary; at or above is the classid-selected vocabulary's own range. - vocabulary::shared_core — the core's stack_arity / body_refs / branches / min_shape tables defined ONCE (transcribed from the proven blockly-rs tables: the two-quantity split + expression arities). Uncovered shared-core bytes (WAIT, STOP, RETURN, ...) refuse everywhere; coverage grows here, for everyone. - trait Vocabulary + vocabulary::conformance::check — the seam a sibling codebook implements, and the mechanical no-drift gate every vocabulary crate must run. Both failure modes verified able to fire: a drifted ADD arity and a truncating min_shape are caught by name. - node / pool / program hoisted from blockly-abi, generalized where they were palette-typed (references_are_resolvable and branches_of are vocabulary-parameterized), tests ported. ogar-blockly becomes the Blockly/Scratch vocabulary crate over the core: re-exports the old surface unchanged (the palette census test now doubles as the re-export completeness proof; blockly-rs compiles with zero changes), keeps BlockConcept / SoaSplit / BLOCKS_DOMAIN, and adds BlocklyVocabulary — domain hooks empty-and-refusing until the device families mint, because that range is reserved, not allocated. Deliberately NOT taken here (recorded in the plan's W6 section): the template and flow vocabulary crates (gated on the rung-2 144-verb unification and on operator mints), the blockly-rs flip off its local copies (a scheduled obligation, not an aspiration), and every concept mint (M1-M3 unchanged). Gates: fmt, clippy -D warnings, tests (36 loco + 7 blockly), rustdoc -D warnings, density example — all green.
Bugbot couldn't run - usage limit reachedBugbot is counted against Cursor usage for this user or team, and this run hit a usage or spend limit. A user or team admin can review and increase usage limits in the Cursor dashboard. (requestId: serverGenReqId_b4cd93b9-4244-4789-b568-89038f511d9e) |
AdaWorldAPI
marked this pull request as ready for review
August 5, 2026 12:33
AdaWorldAPI
pushed a commit
that referenced
this pull request
Aug 5, 2026
…the permanent floor External review of #239 surfaced the panic edge: Program traversal indexed call.values[slot] with slot driven by v.body_refs(), so an unvalidated vocabulary claiming more than three references panicked. Conformance would have rejected that vocabulary, but nothing forced conformance to have run before traversal. - conformance::validate(v) -> CheckedVocabulary<V>: the proof-carrying wrapper, constructible only through validation. references_are_resolvable and branches_of now require it, turning the test-time convention into a type. The wrapper delegates ALL Vocabulary methods (composed included -- conformance validated the composed answers, so re-deriving from the hooks could answer differently than what was validated). - Fixing the edge surfaced a second defect: the default min_shape mapped everything >=2 refs to Triples, wrongly rejecting a LEGAL three-reference domain function (three refs fit Quads exactly). Fixed in the trait default and in shared_core, pinned two-sided: the three-ref vocabulary conforms and defaults to Quads; the hostile 200-ref vocabulary is refused by validate even with a Quads override (no shape holds more than three value bytes). - DOMAIN_FLOOR declared PERMANENT stored-byte ABI: 0x00..=0x8F universal forever, 0x90..=0xFF vocabulary-local forever. Moving the floor would silently reinterpret persisted programs, so it is documented as permanent and pinned by a const assert whose message names why the 'fix' would be wrong. Gates: fmt, clippy -D warnings, tests (38 loco + 7 blockly), rustdoc -D warnings -- all green.
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.
What
The skeleton for the reusable low-code surface, per the operator direction: "Elixir should become just a rails-shaped semantic over classid index, 256:256. Not much different than blockly, just different vocabulary. It should be a reusable surface for any other purposes." Named next consumers: lance-graph's elixir-shaped compiled templates, then Power-Automate-style flows.
The surface splits in two — this PR builds the shared half and leaves the customizations to the wiring side:
crates/ogar-loco(new, zero-dep) — everything that is the same no matter what the bytes mean:FnIndex/Call/LaneShape/FunctionBody/call_in_slab+ layout constants + budgets, moved verbatim fromogar-blockly(bytes, semantics, tests unchanged).DOMAIN_FLOORgeneralizesDEVICE_FAMILY_FLOOR: below the floor is the shared computational core, byte-stable across every vocabulary; at/above is the classid-selected vocabulary's own range.vocabulary::shared_core— the core'sstack_arity/body_refs/branches/min_shapetables defined once (transcribed from the proven blockly-rs tables: the two-quantity split + expression arities). Uncovered shared-core bytes (WAIT, STOP, RETURN, …) refuse everywhere.trait Vocabulary+vocabulary::conformance::check— the seam a sibling codebook implements, and the mechanical no-drift gate every vocabulary crate must run. Both failure modes verified able to fire: a drifted ADD arity and a truncatingmin_shapeare caught by name.node/pool/programhoisted from blockly-abi, generalized where palette-typed (references_are_resolvable/branches_ofare vocabulary-parameterized).ogar-blocklybecomes the Blockly/Scratch vocabulary crate over the core: re-exports the old surface unchanged (the palette census test now doubles as the re-export completeness proof; blockly-rs compiles with zero changes), keepsBlockConcept/SoaSplit/BLOCKS_DOMAIN, and addsBlocklyVocabulary— domain hooks empty-and-refusing until the device families mint, because that range is reserved, not allocated.What is deliberately NOT here (the wiring side)
Recorded in
docs/BLOCK-EDITOR-PLAN.md§ W6:runAftersemantics need.node/flow/program/poolcopies — a scheduled obligation, not an aspiration; until it lands, ogar-loco's copies are the canonical ones for any second vocabulary.Gates
cargo fmt --check,cargo clippy --all-targets --all-features -- -D warnings,cargo test --all-features(36 ogar-loco + 7 ogar-blockly),RUSTDOCFLAGS="-D warnings" cargo doc --no-deps, and thedensityexample — all green, scoped-p ogar-loco -p ogar-blockly.ogar-blockly's census test compiles every named palette constant through the re-export path, exactly as downstream consumers do.🤖 Generated with Claude Code
https://claude.ai/code/session_011DN5odWu4eisdevH9bPWyz
Generated by Claude Code