Skip to content

ogar-blockly: everything is a call — (function : value), shape-carved - #236

Merged
AdaWorldAPI merged 2 commits into
mainfrom
claude/rust-scratch-abi-soa-gsamge
Aug 4, 2026
Merged

ogar-blockly: everything is a call — (function : value), shape-carved#236
AdaWorldAPI merged 2 commits into
mainfrom
claude/rust-scratch-abi-soa-gsamge

Conversation

@AdaWorldAPI

Copy link
Copy Markdown
Owner

Operator-ruled rework of the function body from a flat opcode stream to the V3 indexed reading: every 12-byte lane is 6 × (u8:u8) rails indexed against a label codebook, and the unit is a Call = function : value.

There is no opcode/function distinction

ADD is function 0x40; a user-defined block is another index in the same <256 codebook; invoking either is the same bytes. PaletteOpFnIndex. The Inventory SoA turns out to be the label codebook those indices resolve against — which is why labels stay out of payloads (slot purity §2) while one byte still names anything in scope.

Three earlier defects/claims retire in place

1 — The "nesting gap" is withdrawn. The prior correction recorded the absence of a stream delimiter as a real defect. That was an artifact of treating the body as self-delimiting bytecode. Nesting is by reference — a function index names another function's node — exactly as SB3 nests via block ids. No END, no jump offset, no need.

2 — The operand gap (codex P1 on #235) closes. The value byte is the immediate (WAIT:10); computed arguments use a stack discipline ((NUMBER:5)(NUMBER:3)(ADD:_)); wide literals spend the value byte as a constant-pool index (pool = named follow-up).

3 — Arity is a classid property. LaneShape (mirroring CascadeShape G6D2/G4D3/G3D4) carves the same 360 bytes three ways:

shape carving per call calls / node
Pairs 6 × (u8:u8) fn : val 180
Triples 4 × (u8:u8:u8) fn : val : val 120
Quads 3 × (u8:u8:u8:u8) fn : val ×3 90

A function needing more immediates picks a wider carving, never a wider field. The shape comes from the classid, uniform per body — read_from_value_slab(shape, slab) takes it as a parameter because it is never in the slab.

Narrowing is loud

BodyError::ValueBeyondShape refuses a call the shape would truncate instead of dropping a byte. Length recovery is call-level, per shape — the byte-level rposition regression is caught in every shape.

Both guards verified by breaking them: the truncation guard fails the suite with two immediates must not fit Pairs; the len regression with Quads: trailing bare call lost.

The retired edge-block design is stripped

Slot 1 is documented reserved-zeroed with the retirement named (operator-deprecated this session), so the shape cannot be re-learned from this crate. Relations ride the payload rails as indexed calls.

Also recorded in the ledger

  • Literal over grammar (operator ruling): A = B + C lines are a projection over the pair stream, never the storage format — preserving positional addressing, the SIMD sweep, and single-pass lowering into rash's Input tree.
  • Baby-steps roadmap (operator-set): ABI-shaped Blockly/Scratch first; later a PowerAutomate-shaped low-code editor; both Mario-editor ergonomics over ClassView : WideFieldMask projections.

Gates

  • cargo test -p ogar-blockly — 16 pass, 0 failed (2 falsifier break-runs verified)
  • cargo clippy -p ogar-blockly --all-targets -- -D warnings — clean
  • cargo fmt -p ogar-blockly -- --check — clean
  • cargo check --workspace --all-targets — clean; workspace tests clean
  • examples/density.rs — re-runnable layout/density accounting per shape

An adversarial review fleet (4 finder lenses → per-finding refutation) is running over this diff; any confirmed finding lands as a follow-up commit on this PR.

Ledger

docs/DISCOVERY-MAP.mdD-BLOCKS-PALETTE correction 2 (append-only; retirements named in place).


Generated by Claude Code

Operator-ruled rework of the function body from a flat opcode
stream to the V3 indexed reading: every 12-byte lane is 6x(u8:u8)
rails indexed against a label codebook, and the unit is a Call --
function index : value byte(s).

There is no opcode/function distinction any more. ADD is function
0x40, a user block is another index in the same <256 codebook, and
invoking either is the same bytes. PaletteOp is renamed FnIndex;
the Inventory SoA is the label codebook those indices resolve
against, which is why labels stay out of payloads (slot purity)
while one byte still names anything in scope.

Three earlier defects/claims retire in place:

- The "nesting gap" is withdrawn. It was an artifact of treating
  the body as self-delimiting bytecode. Nesting is by reference --
  a function index names another function's node -- exactly as SB3
  nests via block ids. No END marker, no jump offset, no need.
- The operand gap (codex P1 on #235) closes. The value byte is the
  immediate (WAIT:10, REPEAT:4); computed arguments use a stack
  discipline ((NUMBER:5)(NUMBER:3)(ADD:_)); wide literals spend the
  value byte as a constant-pool index (pool is a named follow-up).
- Arity is a classid property, not an encoding trick. LaneShape
  (mirroring CascadeShape G6D2/G4D3/G3D4) carves the same 360 bytes
  as 180 pairs / 120 triples / 90 quads. A function needing more
  immediates picks a wider carving, never a wider field.

Narrowing is loud: BodyError::ValueBeyondShape refuses a call the
shape would truncate instead of dropping a byte. Length recovery is
call-level, per shape -- the byte-level rposition regression is
caught by test in every shape. Both guards were verified by
breaking them: the truncation guard fails the suite with "two
immediates must not fit Pairs", the len regression with "Quads:
trailing bare call lost".

The retired edge-block design (12 in-family + 4 out-of-family) is
stripped from this crate's docs; slot 1 is documented reserved-
zeroed with the retirement named, so the deprecated shape cannot be
re-learned from here. Relations ride the payload rails as indexed
calls.

Also recorded in the ledger: the operator's literal-over-grammar
ruling (grammar lines like A = B + C are a projection over the pair
stream, never the storage format) and the baby-steps roadmap --
ABI-shaped Blockly/Scratch first, later a PowerAutomate-shaped
low-code editor, both Mario-editor ergonomics over
ClassView : WideFieldMask projections.

Ledger: docs/DISCOVERY-MAP.md D-BLOCKS-PALETTE (correction 2).

Gates: 16 tests pass (2 falsifier break-runs verified), fmt clean,
clippy -D warnings clean, workspace check + tests clean.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011DN5odWu4eisdevH9bPWyz
@cursor

cursor Bot commented Aug 4, 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_751ef3ad-9cb0-49e1-a9b1-2463afdd8ee0)

Adversarial review of 450fe91 (4 finder lenses, per-finding
refutation): 7 raw findings, 3 confirmed, 4 refuted. The confirmed
three collapse to two distinct defects, both doc-level, both real
falsehoods about the public surface:

- VALUE_SLAB_LEN's doc still linked [OPS_PER_FUNCTION], a constant
  this rework renamed to BODY_BYTES -- a dangling intra-doc link
  that also carried the retired "360 of them are operations"
  framing, contradicting the crate's own "no opcode distinct from
  a function call". Now links BODY_BYTES and says call payload
  (180/120/90 calls per LaneShape).
- The crate doc's stack example wrote (CONST:5)(CONST:3)(ADD:0),
  but FnIndex::CONST does not exist -- the numeric literal is
  NUMBER (0x46), which the test for this exact example already
  used. Worse, a near-miss FnIndex::CONSTANT (0x5C) exists and
  means a named math constant, so a reader searching CONST would
  land on wrong bytes. Now (NUMBER:5)(NUMBER:3)(ADD:0).

Deliberately NOT changed: the earlier D-BLOCKS-PALETTE ledger text
that names OPS_PER_FUNCTION. That entry is append-only history and
accurately described the crate as it stood when written; correction
2 supersedes it in place.

Gate added to the routine: RUSTDOCFLAGS="-D
rustdoc::broken_intra_doc_links" cargo doc -- the check that
catches this class (clippy does not). Clean, alongside 16 tests,
fmt, clippy -D warnings.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011DN5odWu4eisdevH9bPWyz
@AdaWorldAPI
AdaWorldAPI marked this pull request as ready for review August 4, 2026 17:24
@AdaWorldAPI
AdaWorldAPI merged commit 2e7bab9 into main Aug 4, 2026
1 check passed
AdaWorldAPI pushed a commit that referenced this pull request Aug 4, 2026
Docs-only. Turns the session's rulings into a durable plan and
records the a2ui-rs wiring as a ledger entry.

docs/BLOCK-EDITOR-PLAN.md sequences W0-W5 with gates, five open
decisions, and five falsifiers. It opens by naming what is LOCKED
so a future session cannot re-derive it: the 0x17XX domain, the
plug-and-play producer posture, the provenance fence, one content
classid, (function:value) calls, arity-by-classid via LaneShape,
nesting by reference, loud narrowing, literal-over-grammar, and the
retired edge block. Every one is shipped code with tests (#234,
#235, #236), not intention.

The headline finding for the a2ui wiring is that most of it already
exists. Charter C1.6 says a click IS a navigates_to/ActionInvocation
edge, and a2ui-server already ships receive_action -> KlickwegEdge
-> lower_action_fire -> ActionInvocation as pure compile-time value
construction (#209, warden COMPILE-TIME-CLEAN, 34 tests). Placing a
block, connecting two blocks and clicking a placed block are each a
click by ordinal address, so each is already a Klickweg edge. Edit
telemetry and harvested-app telemetry unify in one closed predicate
set with NO new predicate -- the Predicate enum is count-locked at
79 and extending it is a gated ontology change, not a consequence of
this arc.

Nesting maps 1:1: the ObjectSlot "A3 Klickwege brick" recursion
desktop -> window -> region -> widget becomes canvas -> script ->
block -> input, which a2ui-wasm::resolve_nested walks unchanged.

The gaps are recorded as measured, not assumed. Interaction-to-edge
and nested addressing exist. A palette of pickables, 2-D placement
(Skin::Form and Skin::Flow are both 1-D list renderers) and
multi-facet body ingest (a2ui-wasm implements one 12-byte facet; a
body is thirty) are absent -- none charter-forbidden, but the editor
tier is a real build rather than wiring. Drag/connect is the one T2
pressure point: local drag state is fine, the result must travel as
an address-carried write.

Open decision D2 proposes that "place tile at slot N" rides
ActionInvoke{ordinal: PLACE, args:[N, fn]} rather than a third
FrameKind: args is explicitly ClassView/ActionDef-carved, so it is
an address-carried write, and a third kind would widen a
deliberately closed vocabulary.

Roadmap order is operator-set: ABI-shaped Blockly/Scratch first,
Klickwege wiring second, PowerAutomate-shaped skin third -- both
skins Mario-editor ergonomics over ClassView : WideFieldMask, which
is T1 applied at editor scale. The W1 falsifier is unchanged from
the first turn of the arc: a drag produces zero SoA writes, an
operand change exactly one.

Ledger: docs/DISCOVERY-MAP.md D-BLOCKS-KLICKWEGE, graded [H] (PLAN)
-- the W0 substrate it builds on is [G]/CODED, the wiring is unbuilt.

Gates: docs-only; 16 ogar-blockly tests and workspace check
re-verified unchanged.

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