Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion .claude/board/ISSUES.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@

## 2026-06-22 — ISS-CONTRACT-APP-PREFIX-MIRROR — `contract::ogar_codebook` lacks the OGAR#97 `APP_PREFIX` / `render_classid_for` mirror, so membrane consumers must hand-stamp the hi-u16 render prefix

**Status:** Open · Owner: lance-graph-contract · Surfaced by: `.claude/knowledge/ogar-consumer-preflight.md` (the consumer spellbook).
**Status:** RESOLVED 2026-06-22 (`claude/contract-app-prefix-mirror`) · Owner: lance-graph-contract · Surfaced by: `.claude/knowledge/ogar-consumer-preflight.md` (the consumer spellbook).

**Resolution:** `contract::ogar_codebook` now mirrors the hi-u16 APP-prefix layer — `AppPrefix` (the OGAR#95 §2 allocation table as typed data: `0x0001` OpenProject / `0x0002` Odoo / `0x0003` WoA / `0x0004` SMB / `0x0005` Healthcare / `0x0007` Redmine), `render_classid` + `render_classid_for_concept` (compose), `classid_app_prefix` + `classid_concept` (decompose). A membrane consumer (BBB-safe) now pulls BOTH halves from one source — no hand-stamped `0x000N`. Wire-compat parity test `app_prefixes_match_ogar_allocation_table` pins the prefixes against OGAR `PortSpec::APP_PREFIX`; `render_classid_composes_decomposes_and_preserves_the_concept_half` pins the `0x0005_0901` MedCare-patient worked example. Mirrors OGAR#97 (`ogar_vocab::app`), following the OGAR#98 `canonical_concept_name` precedent.

`contract::ogar_codebook` mirrors `canonical_concept_id` / `canonical_concept_name` (the lo-u16 concept pull, BBB-safe for membrane consumers woa-rs / medcare-rs / smb-office-rs) but does NOT mirror OGAR#97's `PortSpec::APP_PREFIX` + `render_classid_for` (the hi-u16 render composition: `render_classid = APP << 16 | concept`, OGAR#95 §2). A membrane consumer (BBB-barrier: contract/ontology/callcenter only — `lance_graph_ogar` forbidden) can therefore pull the shared concept but must re-derive the app prefix from the OGAR#95 allocation table by hand. Per Core-First the consumer MUST NOT hard-code `0x000N`. **Fix:** mirror the app-prefix table + a `render_classid` helper into `contract::ogar_codebook` (the `canonical_concept_name` reverse-map mirror, OGAR#98, is the precedent) so the membrane stamps from one source. Interim: the spellbook's Q5 says "stamp from the allocation table." Cross-ref: `.claude/knowledge/ogar-consumer-preflight.md` § "A Core gap this spellbook surfaces"; OGAR#95/#97/#98.

Expand Down
6 changes: 6 additions & 0 deletions .claude/board/LATEST_STATE.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,12 @@

---

## 2026-06-22 — IN PR (`claude/contract-app-prefix-mirror`) — `contract::ogar_codebook` APP-prefix (hi-u16) mirror — closes `ISS-CONTRACT-APP-PREFIX-MIRROR`

Membrane consumers can now pull BOTH halves of a render `classid` BBB-safely from `lance_graph_contract::ogar_codebook` — no hand-stamped `0x000N`. **NEW:** `AppPrefix` enum (the OGAR#95 §2 allocation table as typed data — `Core 0x0000` / OpenProject `0x0001` / Odoo `0x0002` / WoA `0x0003` / SMB `0x0004` / Healthcare `0x0005` / Redmine `0x0007`) with `prefix()` / `from_prefix()` / `render(concept)`; free fns `render_classid(prefix, concept)`, `render_classid_for_concept(AppPrefix, &str)`, `classid_app_prefix(classid)`, `classid_concept(classid)` — the wire-compat mirror of OGAR#97 `ogar_vocab::app` (`render_classid_for::<P>` / `app_of` / `concept_of`), **no `ogar-vocab` dependency**. Two parity tests: `app_prefixes_match_ogar_allocation_table` (pins the 6 prefixes vs OGAR `PortSpec::APP_PREFIX`) + `render_classid_composes_decomposes_and_preserves_the_concept_half` (pins the `0x0005_0901` MedCare-patient worked example, and that the render lens never perturbs the lo-u16 concept RBAC keys on). Follows the OGAR#98 `canonical_concept_name` mirror precedent. Closes the gap the #591 consumer spellbook surfaced. Contract lib **+2 tests** / +1 doctest; `cargo fmt -p lance-graph-contract --check` clean; `clippy -p lance-graph-contract --all-targets -D warnings` clean (also `--features guid-v2-tail`). (Incidental: the crate-wide `cargo fmt` pass also corrected pre-existing struct-literal/line-width drift in `content_store.rs` — same crate, no behavior change.) Refs: PR (this branch), ISSUES `ISS-CONTRACT-APP-PREFIX-MIRROR` (RESOLVED), `.claude/knowledge/ogar-consumer-preflight.md` § Core-gap (CLOSED), OGAR#97/#98.

---

## 2026-06-20 — golden-image (symbiont) harness shipped to `main`; lance-7 lockstep unified end-to-end

`crates/symbiont/` (workspace-`exclude`d) compiles+links the FULL stack into ONE binary — lance-graph + lance7/lancedb0.30 + ndarray + ractor + surrealdb(kv-lance) + OGAR. **Verified green** (real git-deps build, `CARGO_EXIT=0`, 4.3 MB binary runs): unified `lance 7.0.0 / lance-index 7.0.0 / lancedb 0.30.0 / datafusion 53.1.0 / arrow 58` — no lance-6/7 split. It is a **living integration harness** (`Dockerfile` + portable git-deps `Cargo.toml`) that tracks each fork's canonical branch (`master`/`main`), **NOT** a frozen snapshot; every per-session `jirak` branch is stale (HEAD ⊂ main/master, 0 unique commits). **`TD-SURREALDB-KVLANCE-LANCE7` PAID** — surrealdb `main` carries the lance-7 bump. PR #555 adds the 5+3 council `INTEGRATION_PLAN.md` (loose-end ledger → the Spain-grid acceptance gate). **Honest state:** linked into one binary; the *runtime edges* between the five crates are still pending integration (Grid→NodeRow bridge, kanban loop). Battle-test plan (probes A1–E3) queued behind the singleton-BindSpace → SoA switch. Refs: PR_ARC #555, EPIPHANIES `E-GOLDEN-IMAGE-IS-A-LIVING-HARNESS`, AGENT_LOG 2026-06-20.
Expand Down
38 changes: 25 additions & 13 deletions .claude/knowledge/ogar-consumer-preflight.md
Original file line number Diff line number Diff line change
Expand Up @@ -112,8 +112,10 @@ One signature is suspicious; a local codebook copy alone is the trap.
2. **Pull the classid** — pure function, no registry:
- spine: `lance_graph_ogar::WoaPort::class_id(name) -> Option<u16>`
- membrane (BBB): `lance_graph_contract::ogar_codebook::canonical_concept_id(name)`
3. **Stamp the app prefix + delete the old surface.** Render id =
`APP << 16 | cid`; authorize on the shared `cid` (lo u16). Then delete: the
3. **Stamp the app prefix + delete the old surface.** Compose the render id —
membrane (BBB): `ogar_codebook::render_classid_for_concept(AppPrefix::X, name)`
or `AppPrefix::X.render(cid)`; spine: `render_classid_for::<XPort>(cid)`. Both
are `APP << 16 | cid`; authorize on the shared `cid` (lo u16). Then delete: the
`*Bridge` import, any `OntologyRegistry` field, and every local codebook
copy. Your diff touches only your crate; the spine is byte-for-byte unchanged.

Expand All @@ -133,17 +135,27 @@ repo; the classid pull is a pure function call.
These three are the migration backlog. The terminal `bridges/` deletion in the
spine is gated on all three reaching 0.

## A Core gap this spellbook surfaces (honest — flag, don't paper)

`contract::ogar_codebook` mirrors `canonical_concept_id` / `canonical_concept_name`
(the lo-u16 pull, BBB-safe) but does **not** yet mirror OGAR#97's
`PortSpec::APP_PREFIX` / `render_classid_for` (the hi-u16 render composition). So
a **membrane** consumer can pull the shared concept but must hand-stamp the app
prefix from the OGAR#95 allocation table — a small re-derivation a
`contract::ogar_codebook::APP_PREFIX` mirror would remove. Per Core-First the
consumer must NOT hard-code `0x000N`; file the contract mirror (the
`canonical_concept_name` precedent is OGAR#98) rather than minting a local
prefix const. Tracked: `ISS-CONTRACT-APP-PREFIX-MIRROR`.
## A Core gap this spellbook surfaced — now CLOSED

> **Resolved 2026-06-22** (`claude/contract-app-prefix-mirror`, closes
> `ISS-CONTRACT-APP-PREFIX-MIRROR`). `contract::ogar_codebook` now mirrors the
> hi-u16 APP-prefix layer alongside the lo-u16 concept layer: `AppPrefix` (the
> OGAR#95 §2 allocation table as typed data — `0x0001` OpenProject … `0x0005`
> Healthcare … `0x0007` Redmine), `render_classid` / `render_classid_for_concept`
> (compose), `classid_app_prefix` / `classid_concept` (decompose). A **membrane**
> consumer now pulls BOTH halves BBB-safely —
> `render_classid_for_concept(AppPrefix::Healthcare, "patient")` → `Some(0x0005_0901)`,
> no hand-stamped `0x000N`. Wire-compat parity tests pin the prefixes against OGAR
> `PortSpec::APP_PREFIX`. Mirrors OGAR#97 `ogar_vocab::app`, following the OGAR#98
> `canonical_concept_name` precedent.

Original gap (kept for the record — honest, flag don't paper):
`contract::ogar_codebook` mirrored the lo-u16 concept pull (`canonical_concept_id`)
but not OGAR#97's `PortSpec::APP_PREFIX` / `render_classid_for` (the hi-u16 render
composition), so a **membrane** consumer could pull the shared concept yet had to
hand-stamp the app prefix from the OGAR#95 allocation table. Per Core-First the
fix was to mirror it into the contract (the `canonical_concept_name` precedent is
OGAR#98), never to mint a local prefix const.

## When this doc fires + trigger phrases

Expand Down
17 changes: 14 additions & 3 deletions crates/lance-graph-contract/src/content_store.rs
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,11 @@ impl SourceSpan {
/// New span; `end` is clamped to be `>= start`.
#[must_use]
pub fn new(content: ContentId, start: u32, end: u32) -> Self {
Self { content, start, end: end.max(start) }
Self {
content,
start,
end: end.max(start),
}
}

/// Span length in bytes. Saturating: a malformed span (`end < start`, only
Expand Down Expand Up @@ -226,7 +230,10 @@ mod tests {
fn out_of_bounds_and_missing_fail() {
let mut s = MemStore::default();
let id = s.put_str("short");
assert_eq!(s.resolve_span(SourceSpan::new(id, 0, 999)), Err(ContentError::SpanOutOfBounds));
assert_eq!(
s.resolve_span(SourceSpan::new(id, 0, 999)),
Err(ContentError::SpanOutOfBounds)
);
assert_eq!(
s.resolve_span(SourceSpan::new(ContentId(123), 0, 1)),
Err(ContentError::NotFound)
Expand All @@ -245,7 +252,11 @@ mod tests {
fn malformed_span_len_saturates_not_panics() {
// Public fields let a consumer build end < start, bypassing new()'s clamp.
// len() must saturate to 0 (consistent with is_empty), never panic/wrap.
let bad = SourceSpan { content: ContentId(7), start: 13, end: 0 };
let bad = SourceSpan {
content: ContentId(7),
start: 13,
end: 0,
};
assert_eq!(bad.len(), 0);
assert!(bad.is_empty());
assert!(!bad.is_cited());
Expand Down
5 changes: 3 additions & 2 deletions crates/lance-graph-contract/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -142,8 +142,9 @@ pub use episodic_edges::{EdgeRef, EpisodicEdges64};
pub use head2head::{CompetitionOutcome, Head2Head, WinnerCriterion};
pub use kanban::{ExecTarget, KanbanColumn, KanbanMove, RubiconTransitionError};
pub use ogar_codebook::{
canonical_concept_domain, canonical_concept_id, classid_concept_domain, source_domain_concept,
ConceptDomain, LabelDTO, CODEBOOK,
canonical_concept_domain, canonical_concept_id, classid_app_prefix, classid_concept,
classid_concept_domain, render_classid, render_classid_for_concept, source_domain_concept,
AppPrefix, ConceptDomain, LabelDTO, CODEBOOK,
};
pub use scheduler::{DatasetVersion, NextPhaseScheduler, VersionScheduler};
pub use soa_graph::{
Expand Down
Loading
Loading