Skip to content

ogar-loco: hoist the vocabulary-agnostic call ABI out of ogar-blockly - #239

Merged
AdaWorldAPI merged 1 commit into
mainfrom
claude/rust-scratch-abi-soa-gsamge
Aug 5, 2026
Merged

ogar-loco: hoist the vocabulary-agnostic call ABI out of ogar-blockly#239
AdaWorldAPI merged 1 commit into
mainfrom
claude/rust-scratch-abi-soa-gsamge

Conversation

@AdaWorldAPI

Copy link
Copy Markdown
Owner

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 from ogar-blockly (bytes, semantics, tests unchanged).
    • DOMAIN_FLOOR generalizes DEVICE_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'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.
    • 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 palette-typed (references_are_resolvable / branches_of are vocabulary-parameterized).
  • 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.

What is deliberately NOT here (the wiring side)

Recorded in docs/BLOCK-EDITOR-PLAN.md § W6:

  1. The template vocabulary crate — gated on lance-graph's rung-2 144-verb unification (O7: the two shipped 144-vocabularies diverge; an ordinal-pinned codebook forces that ruling) and its concept-domain mint.
  2. The flow vocabulary crate (Power Automate) + the structured PARALLEL/JOIN / try-catch-shaped control mints its runAfter semantics need.
  3. The blockly-rs flip off its local node/flow/program/pool copies — a scheduled obligation, not an aspiration; until it lands, ogar-loco's copies are the canonical ones for any second vocabulary.
  4. Every concept mint (M1–M3 unchanged, plus the template/flow domains).

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 the density example — all green, scoped -p ogar-loco -p ogar-blockly.
  • Back-compat is proven from inside: 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

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.
@cursor

cursor Bot commented Aug 5, 2026

Copy link
Copy Markdown

Bugbot couldn't run - usage limit reached

Bugbot 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
AdaWorldAPI marked this pull request as ready for review August 5, 2026 12:33
@AdaWorldAPI
AdaWorldAPI merged commit 04f2d42 into main Aug 5, 2026
2 checks passed
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.
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.

2 participants