Skip to content

loco: the shared basin codebook — one FnIndex for a whole palette - #295

Merged
AdaWorldAPI merged 2 commits into
mainfrom
claude/medcare-rs-continue-ufsazd
Sep 1, 2026
Merged

loco: the shared basin codebook — one FnIndex for a whole palette#295
AdaWorldAPI merged 2 commits into
mainfrom
claude/medcare-rs-continue-ufsazd

Conversation

@AdaWorldAPI

Copy link
Copy Markdown
Owner

The measurement that decided the shape

The loco domain range 0x90..=0xFF is 112 function slots per vocabulary. ogar-ro mints 22 (0x90..=0xA5, read from the relation_palette! table, contiguous by design); recipe_vocab mints 34. A 144-entry relation palette therefore cannot be FnIndex bytes — 144 > 112, and no carving makes it fit.

So a large palette is not a set of functions. It is one function whose operand byte indexes a codebook.

The gap that blocked that

Two mechanisms each had one of the two properties a shared operand table needs, and neither had both:

index shape ownership
ConstantPool u8 1..=255 classid(4) + 12 V3 facet owned, per-function
ValueCodebook u8 id none — advisory {id, name} shared, basin-scoped

ValueCodebook's own contract is that the same call in sibling basins may resolve its operand against different codebooks — but it carries no table, so nothing could actually resolve. ConstantPool carries exactly the right table and is owned by ONE function, so a vocabulary-wide set held there would be copied into every function that names it.

crates/ogar-loco/src/basin.rs is the join: the pool's facet arithmetic under the codebook's ownership. ConstantPool::locate and ::slot_payload_offset are called, not reimplemented — pool.rs says the defects live in that arithmetic, so a second copy would be a second place for them to live.

Why this is not the shared-mutable sink pool refused

pool.rs rejects holding constants in the Inventory SoA because "Inventory is shared by every function, so a per-function pool living there is a shared-mutable sink with N writers." That objection is about mutability, not sharing — and it is answered structurally rather than by convention:

BasinCodebookBuilder is the only thing that can intern; seal() consumes it and yields a BasinCodebook with no &mut self method at all. One writer at mint time, zero afterwards. A body resolving an operand borrows &BasinCodebook and cannot reach a mutation it does not have.

The seam

BasinCodebooks::resolve_operand(vocab, call, i) asks the vocabulary which codebook the call's function declares, then resolves that byte against it. This is what makes Vocabulary::value_codebook load-bearing rather than advisory — before it, the declaration named a table nothing could reach.

What the entry classid buys

An entry is classid(4) + 12 — the V3 content-blind register — and the classid names the READING: 6×(u8:u8), 4×(u8:u8:u8), 3×(u8:u8:u8:u8) or 12×u8 over the same bytes. That is what makes an index into this table different in kind from an enum ordinal: a flat ordinal has no metric (nothing about 71 says it is near 72), whereas a quantizer code answers distance by table lookup.

No classid is minted here. As in pool, the classids stay PARAMETERS supplied by the caller, because minting a concept is an operator decision with a ledger entry.

Axis discipline

0x90 names three different things in this workspace, and this module touches two:

space width what 0x90 names
FnIndex (call codebook) u8 DOMAIN_FLOOR, first vocabulary-local opcode
ogar_vocab concept domain u16 hi byte 0x90XX, ROOT of the domain reference tree (0x90..=0x9D: Disease, Phenomenology, Lab, Imaging, Substance, Procedure, Form)
ValueCodebook::id u8 which codebook a basin plugged in

They never meet — loco's own concepts are 0x1701/0x1702 in Blocks, and this module mints none. But ogar_vocab's domain table already documents a live instance of the overlap (0x9E = has_phenotype in ogar-ro's predicate space, which ogar-ro does mint, as an opcode). The second commit states which axis every 0x9x in basin.rs is on, so a reader who knows 0x90XX as the reference-tree root does not read a health-domain claim into a sentence about function indices.

Tests — 8, each disable-verified

Two were vacuous on first writing and were caught by their own falsifiers:

  • Id-keyed resolution survived substituting "return the first book," because both basins listed the same table first. Rewritten to hold two tables in one basin with different bytes at index 1; the substitution now fails.
  • The capacity guard survived removal, because u8::try_from returns Full anyway — but without the guard the 256th entry is pushed before rejection. Same error value, corrupted state. Now asserts the table length is unchanged after a refusal; the substitution now fails.

The other six falsifiers failed as intended: dropping classid from entry identity, treating 0 as a real index, writing the payload over the classid, letting a duplicate codebook id shadow, and ignoring the vocabulary's declaration in resolve_operand.

Scope

Additive. ogar-loco stays vocabulary-agnostic — it owns the ABI, the shapes, the pool and now this table, and knows nothing about what any byte means. A thinking IR is a caller that plugs its vocabulary and codebooks in through the same seams; nothing in this module knows one exists.

Ledger: D-BASIN-CODEBOOK in docs/DISCOVERY-MAP.md (append-only, [G]/CODED).

Open underneath, unchanged

W-RO-5LaneShape (Pairs/Triples/Quads) and CascadeShape (G6D2/G4D3/G3D4) are bit-for-bit the same carving in two repos, deliberately duplicated because loco is zero-dep. A shared rail codebook is written in one and read in the other, which makes it the first thing genuinely blocked by that duplication rather than merely inconvenienced. Operator call, not this PR's.

Verification

  • cargo test -p ogar-loco — 63 passing (55 pre-existing + 8 new)
  • cargo clippy -p ogar-loco --all-targets --no-deps — clean
  • cargo check -p ogar-loco -p ogar-ro -p ogar-r2il --all-targets — clean

🤖 Generated with Claude Code


Generated by Claude Code

Measured first: the loco domain range 0x90..=0xFF is 112 function slots per
vocabulary (ogar-ro mints 22 from 0x90; recipe_vocab mints 34). A 144-entry
relation palette cannot be FnIndex bytes -- 144 > 112, and no carving makes it
fit. A large palette is therefore a VALUE table: one FnIndex for the whole
thing, with the operand byte indexing a codebook.

The gap that blocked that. Two mechanisms each had one of the two properties a
shared operand table needs:

  ConstantPool   u8 1..=255  classid(4)+12 V3 facet  OWNED, per-function
  ValueCodebook  u8 id       no shape (advisory)     SHARED, basin-scoped

ValueCodebook's contract is that the same call in sibling basins may resolve
its operand against different codebooks -- but it carries no table, so nothing
could actually resolve. ConstantPool carries exactly the right table and is
owned by one function, so a vocabulary-wide target set held there would be
copied into every function that names it.

crates/ogar-loco/src/basin.rs is the join: the pool's facet arithmetic under
the codebook's ownership. ConstantPool::locate and ::slot_payload_offset are
CALLED, not reimplemented -- pool.rs says the defects live in that arithmetic,
so a second copy would be a second place for them to live.

Why this is not the shared-mutable sink pool.rs refused: that objection is
about mutability, not sharing, and it is answered structurally rather than by
convention. BasinCodebookBuilder is the only thing that can intern; seal()
consumes it and yields a BasinCodebook with no &mut self method at all. One
writer at mint time, zero afterwards. Sharing an immutable table is not a sink.

BasinCodebooks::resolve_operand(vocab, call, i) is the seam that makes
Vocabulary::value_codebook load-bearing instead of advisory: it asks the
vocabulary which codebook the call's function declares, then resolves that
byte against it. Before this, the declaration named a table nothing could
reach.

What the entry classid buys: an entry is classid(4) + 12, the V3 content-blind
register, and the classid names the reading -- 6x(u8:u8), 4x(u8:u8:u8),
3x(u8:u8:u8:u8) or 12xu8 over the same bytes. That is what makes an index into
this table different in kind from an enum ordinal: a flat ordinal has no
metric, while a quantizer code answers distance by table lookup. Compiling
meaning into a codebook IS minting the entry classid.

No classid is minted here. As in pool, the classids stay PARAMETERS supplied
by the caller, because minting a concept is an operator decision with a ledger
entry. loco stays vocabulary-agnostic: it owns the ABI, the shapes, the pool
and now this table, and knows nothing about what any byte means. A thinking IR
is a caller that plugs its vocabulary and codebooks in through the same seams.

8 tests, each disable-verified rather than assumed. Two were VACUOUS on first
writing and were found by their own falsifier:

- id-keyed resolution passed while "return the first book" was substituted,
  because both basins listed the same table first. Strengthened to hold two
  tables in ONE basin with different bytes at index 1; the substitution now
  fails.
- the capacity guard passed while removed, because u8::try_from returns Full
  anyway -- but without the guard the 256th entry is PUSHED before rejection.
  Same error value, corrupted state. Strengthened to assert the table length
  is unchanged after a refusal; the substitution now fails.

The other six falsifiers all failed as intended: dropping classid from entry
identity, treating 0 as a real index, writing the payload over the classid,
letting a duplicate codebook id shadow, and ignoring the vocabulary's
declaration in resolve_operand.

Open underneath, unchanged: W-RO-5 (LaneShape and CascadeShape are bit-for-bit
the same carving in two repos). A shared rail codebook is written in one and
read in the other, which makes it the first thing actually blocked by that
duplication rather than merely annoyed by it.

cargo test -p ogar-loco: 63 passing (55 pre-existing + 8).
cargo clippy --all-targets --no-deps: clean.
…pt domain

Operator flag: 0x9x is now health domains. Checked, and there is no collision
-- but the hazard is real and the workspace already has a live instance of it.

Three address spaces carry overlapping numerals:

  FnIndex (call codebook)   u8           0x90 = DOMAIN_FLOOR, first
                                         vocabulary-local opcode
  ogar_vocab concept domain u16 hi byte  0x90XX = ROOT of the domain reference
                                         tree; 0x90..=0x9D is Disease,
                                         Phenomenology, Lab, Imaging,
                                         Substance, Procedure, Form
  ValueCodebook::id         u8           which codebook a basin plugged in

They never meet. loco's own concepts are 0x1701/0x1702 in the Blocks domain
and basin.rs mints none at all; its test classids are the deliberately invalid
0xDEAD_100x, and its test opcodes are FnIndex bytes. So the code is correct as
written.

What was wrong was the prose: basin.rs and the ledger entry both said 'the
domain range is 0x90..=0xFF' repeatedly without naming the axis, and a reader
who knows 0x90XX as the reference-tree root would read a health-domain claim
into a sentence about function indices.

ogar_vocab's own domain table already documents exactly this overlap one slot
along: '0x9E is NOT claimed: it is has_phenotype in ogar-ro's PREDICATE space,
a different axis that overlaps these numbers' -- and ogar-ro does mint 0x9E, as
an opcode. Both readings are correct on their own axis, which is precisely why
the axis has to be named rather than inferred.

basin.rs now carries the three-space table and states that every 0x9x below it
is an opcode byte. The DISCOVERY-MAP entry says the same inline.

No behaviour change. cargo test -p ogar-loco: 63 passing. clippy clean.
@cursor

cursor Bot commented Sep 1, 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_e26c6282-aafb-4f6b-8e30-90699bd85228)

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: dc94be7dc2

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +366 to +372
pub fn resolve_operand<V: Vocabulary>(
&self,
vocab: &V,
call: &Call,
which: usize,
) -> Option<&Constant> {
let declared = vocab.value_codebook(call.function)?;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Resolve operands from the validated vocabulary table

When a caller passes a raw Vocabulary—as this module's new test does—this method re-reads value_codebook from live, unvalidated trait methods. An implementation can override the composed method for shared-core functions or return changing domain_value_codebook answers, causing operands to resolve against a table different from the frozen semantics in CheckedVocabulary/VocabularyTable; the registry also retains only that frozen table. Require a checked vocabulary or perform the lookup directly against VocabularyTable, as the other downstream semantic traversals do.

Useful? React with 👍 / 👎.

@AdaWorldAPI
AdaWorldAPI merged commit ae781df into main Sep 1, 2026
2 checks passed
AdaWorldAPI pushed a commit that referenced this pull request Sep 2, 2026
Paired with the lance-graph semantic-family recovery (2026-09-02,
E-SIX-SEMANTIC-FAMILIES-MUST-NOT-IMPERSONATE-EACH-OTHER-1). The
register the 0x87..0x8B calls operated on aliased episodic loci,
qualia magnitude and population-basin geometry into one type.

Removed
- FnIndex BELNAP_JOIN / INFO_GAIN / SIGMA_TENSION / ACCUMULATE /
  STANCE_ENTROPY (0x87..0x8B), their arity and name rows; census
  re-pinned 101 -> 96. The slots return to reserved core (reserve,
  don't reclaim).
- crates/ogar-epistemic (the fixed 24-axis basis, concept 0x0334) and
  its workspace member line.

Kept
- TERNLOG 0x86: a generic 3-input mask combinator whose value byte is
  the truth table, independently justified by ndarray's ternlog.
- BasinCodebook (#295) untouched.

Ledger: D-EPISTEMIC-BAND-RETRACTED appended to docs/DISCOVERY-MAP.md.

Tests: ogar-loco 55 green; clippy -D warnings + fmt clean; workspace
metadata resolves without the removed member.

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