Skip to content

plan: VSA precision tiers, father-grandfather compression, DU-4/DU-5 shipped#244

Merged
AdaWorldAPI merged 23 commits into
mainfrom
claude/read-claude-md-jh51O
Apr 23, 2026
Merged

plan: VSA precision tiers, father-grandfather compression, DU-4/DU-5 shipped#244
AdaWorldAPI merged 23 commits into
mainfrom
claude/read-claude-md-jh51O

Conversation

@AdaWorldAPI

Copy link
Copy Markdown
Owner

Summary

  • DU-4 shipped: rationale_phase: bool added to CognitiveEventRow (Phase A stub = false in project()); wired from FacultyDescriptor::is_asymmetric() in Phase B
  • DU-5 shipped: board hygiene — unified-integration-v1 plan registered, DU-* rows in STATUS_BOARD
  • §18 (new): VSA precision-tier architecture captured in callcenter-membrane-v1.md
  • Plan language corrections throughout §§14, 17 and unified-integration-v1

Architectural decisions recorded (§18)

Three precision tiers:

Tier Format Size Where
Fingerprint [u64;256] 2 KB L4/L5 speed lane (30 ns/bind)
Vsa10k BF16 [bf16;10000] 20 KB L3 / cold storage (lossless, supports unbind)
Vsa10k f32 [f32;10000] 40 KB Offline training / precision UDFs

L4/L5 is the speed lane — fingerprint stays there. Inflating to Vsa10k would blow the L3 memory budget at substrate rate. The boundary is a hardware-budget invariant.

L3 / cold storage gets either Vsa10k BF16 (20 KB, full unbind algebra) or RaBitQ-quantized Lance columns (zero-copy ANN, lower RAM).

VSA is the wire format — bundle, SPO ±5/±500. CognitiveEventRow is the BBB-safe scalar projection of that wire state, not the wire itself.

Father-Grandfather generational compression:

  • Son (hot): per-cycle Fingerprint<256> — 2 KB
  • Father (~100 cycles): MergeMode::Bundle → single Vsa10k BF16 — 20 KB (10:1)
  • Grandfather (~1000 cycles): bundle of fathers → single Vsa10k BF16 — 20 KB (100:1)
  • CK-safe: saturating bundle preserves Chapman-Kolmogorov (I-SUBSTRATE-MARKOV)
  • Extends existing ±5/±500 Markov window hierarchy to ±1000

Files changed

  • .claude/plans/callcenter-membrane-v1.md — §14 internal dataset clarification, §17 Tensor[N,256×64]Tensor[N,16384] + L4/L5 note, §18 new section
  • .claude/plans/unified-integration-v1.md — title fix (Chronos→ONNX), DU-1 input note, DU-3 L3 precision note, DU-4/DU-5 status → Shipped
  • .claude/board/STATUS_BOARD.md — DU-4 and DU-5 marked Shipped
  • .claude/settings.json — permissions spine (CLAUDE.md + destructive ops deny only)

https://claude.ai/code/session_01CgQyZ7rMWkCEohrPzEiwkD


Generated by Claude Code

Lance Release Bot and others added 23 commits March 21, 2026 18:15
## Summary
- Add `SqlDialect` enum (`Default`, `Spark`, `PostgreSql`, `MySql`,
`Sqlite`) and `SparkDialect` implementation using DataFusion's unparser
`Dialect` trait
- Refactor `to_sql()` to accept an optional `dialect` parameter instead
of a separate method per dialect
- Add Python API support: `query.to_sql(datasets, dialect="spark")`

### Spark SQL dialect differences
- Backtick identifier quoting
- `STRING` type instead of `VARCHAR`
- `EXTRACT(field FROM expr)` for date parts
- `LENGTH()` instead of `CHARACTER_LENGTH()`
- `TIMESTAMP` without timezone info
- Subqueries in FROM require aliases

### Usage

**Rust:**
```rust
use lance_graph::{CypherQuery, SqlDialect};

let sql = query.to_sql(datasets, Some(SqlDialect::Spark)).await?;
```

**Python:**
```python
sql = query.to_sql(datasets, dialect="spark")
```

## Test plan
- [x] 7 new Spark SQL integration tests (backtick quoting, filters,
relationships, complex queries, dialect comparison, PostgreSQL dialect)
- [x] 5 unit tests for SparkDialect trait implementation
- [x] 12 existing `to_sql` tests updated and passing

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Co-authored-by: Yu Chen <yu.chen@databricks.com>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This PR excludes the `lance-graph-python` package in the `cargo build`,
since it needs to be built by maturin. The issue would cause build
errors in the MacOS.

A similar fix has also been applied in the `lance` project
https://github.com/lance-format/lance/blob/main/Cargo.toml#L25
…eleton

Implements the BBB (blood-brain barrier) contract boundary as described in
.claude/plans/callcenter-membrane-v1.md.

DM-0 — lance-graph-contract/src/external_membrane.rs:
  - `ExternalMembrane` trait with associated types Commit / Intent / Subscription
  - `CommitFilter` scalar-only predicate (u64 / u8 / bool, no VSA types)
  - project() / ingest() / subscribe() boundary methods
  - BBB invariant documented: Arrow type system enforces at compile time;
    semiring + VSA types cannot appear in RecordBatch columns

DM-1 — crates/lance-graph-callcenter/ (new workspace member):
  - Cargo.toml with six feature gates: persist / query / realtime / serve / auth / full
  - default = [] (zero external deps in default build)
  - src/lib.rs with stub module tree and UNKNOWN-1 through UNKNOWN-5 markers

Board hygiene (same commit per mandatory rule):
  - INTEGRATION_PLANS.md: prepended callcenter-membrane-v1 entry
  - STATUS_BOARD.md: appended DM-0 through DM-9 section

Both crates compile clean under cargo check.

https://claude.ai/code/session_01CgQyZ7rMWkCEohrPzEiwkD
cognitive-shader-driver and lance-graph-planner both pin axum = "0.8".
The callcenter crate had "0.7" which forced Cargo to pull a second axum
version into Cargo.lock, causing the Cargo.lock diff noise in the PR.
Bumped to "0.8" to keep a single axum in the dependency tree.

https://claude.ai/code/session_01CgQyZ7rMWkCEohrPzEiwkD
lance-graph-benches pinned lance = "1.0.0" and arrow-* = "56.2",
pulling a second arrow version into Cargo.lock alongside the workspace's
canonical arrow 57. Bumped both to match the rest of the workspace:
  lance "1.0.0" → "2"
  arrow-array "56.2" → "57"
  arrow-schema "56.2" → "57"

Cargo.lock now has a single arrow entry (57.3.0).

https://claude.ai/code/session_01CgQyZ7rMWkCEohrPzEiwkD
Workflow fix (build.yml + rust-test.yml):
  - actions/checkout@v4 requires path within GITHUB_WORKSPACE;
    path: ../ndarray escapes the workspace root and fails.
  - Solution: check out lance-graph into lance-graph/, ndarray into
    ndarray/ — both under GITHUB_WORKSPACE. From
    lance-graph/crates/lance-graph/, ../../../ndarray resolves to
    $GITHUB_WORKSPACE/ndarray/ (the Cargo.toml path dep is unchanged).
  - Added defaults.run.working-directory: lance-graph so all existing
    cargo invocations continue to work without path changes.
  - Updated Swatinem/rust-cache workspaces to use full paths from
    GITHUB_WORKSPACE root (those are not affected by working-directory).

BlasGraph stub guard (crates/lance-graph/src/query.rs):
  - ExecutionStrategy::BlasGraph was building TypedGraph::new(0) and
    returning empty results silently — callers had no way to know the
    strategy was unwired from input data.
  - Now returns an explicit Err pointing to DataFusion as the working
    alternative; unreachable_code allows the stub body to stay as a
    placeholder for the real wiring.

https://claude.ai/code/session_01CgQyZ7rMWkCEohrPzEiwkD
…path)

Upstream-inherited PyO3 crate pulled arrow-pyarrow into the workspace
dependency graph unconditionally. Moving to `exclude` is Cargo's native
feature-flag equivalent for workspace members — cargo check/build/test
--workspace no longer touches it; Python bindings still buildable via
  cargo build --manifest-path crates/lance-graph-python/Cargo.toml
python-test.yml / python-publish.yml remain as the explicit opt-in CI paths.

Also strips the `Build lance-graph-python` step and its cache entry from
build.yml / rust-test.yml to match the workspace change.

https://claude.ai/code/session_01CgQyZ7rMWkCEohrPzEiwkD
python-test.yml triggered on every PR touching crates/lance-graph/**,
meaning every Rust-core change forced a maturin build + pytest +
ruff/pyright run. The python crate is now in the workspace exclude
list — automatic Python CI on Rust-only changes is pure noise.

Opt-in path preserved:
  cargo build --manifest-path crates/lance-graph-python/Cargo.toml
  cd python && maturin develop

If python bindings get first-class support again, restore from
git history. Until then: no python, no CI tax.

https://claude.ai/code/session_01CgQyZ7rMWkCEohrPzEiwkD
…finement

Three additions, all in the zero-dep contract crate:

a2a_blackboard: add ExternalSeed (8) + ExternalContext (9) to ExpertCapability.
  External inbound events land as BlackboardEntry with these capabilities;
  A2A experts process them across rounds before CollapseGate projects outbound.
  The blackboard is the explicit firewall — events never go directly into VSA.

external_membrane: add ExternalRole (User/Consumer/N8n/OpenClaw/CrewaiUser/
  CrewaiAgent/Rag/Agent) + ExternalEventKind (Seed/Context/Commit).
  Role is the bind key for XOR-braiding at the gate: same RoleKey::bind +
  rho^d mechanism as the grammar Markov ±5 trajectory — no new research,
  no new data structure.

callcenter-membrane-v1.md: append § 10 — Markov XOR Gate + Blackboard
  Mediation Refinement. Records:
  - blackboard-as-firewall model (explicit, not conflated)
  - Markov ±5 reuse from grammar (round counter = trajectory position)
  - ExternalRole taxonomy with direction table
  - ExternalEventKind behaviour table
  - Speed-gap structural acceptance (substrate doesn't wait on consumer)

https://claude.ai/code/session_01CgQyZ7rMWkCEohrPzEiwkD
Removing lance-graph-python from workspace members dropped pyo3,
arrow-pyarrow, and related Python-bridge crates from the lock file.

https://claude.ai/code/session_01CgQyZ7rMWkCEohrPzEiwkD
ExpertId gains a doc convention: for agent cards (crewai-rust, .claude/agents/),
ExpertId = stable_hash_u16(card_yaml). This collapses three identity spaces —
internal A2A experts, external roles, YAML agent cards — into one bus:

  ExternalRole (family, 8 variants) — carried at the gate
  ExpertId (specific card, u16)     — carried on the entry
  Combined braid key = (role << 16) | expert_id — 32 bits

The shader can unbind at either coordinate: all Rag-family cards collectively,
or a specific card across families, or the full 32-bit precise identity.
Meta-awareness consequence: QualiaClassification / StyleModulation experts
can now fire on family-level OR card-level texture as real observables.

Plan § 10.6 — Agent cards as A2A experts — appended with the convention,
braid-key math, and registration flow (card YAML → ExpertEntry at load time).

https://claude.ai/code/session_01CgQyZ7rMWkCEohrPzEiwkD
…h + iron rule)

contract::persona — new zero-dep module:
  PersonaCard { role, entry } — identity bundle (ExternalRole × ExpertEntry)
  RoutingHint { target_role, target_card } — optional hint on ExternalSeed
    entries. All-None = implicit (AriGraph resonance). Either or both Some =
    explicit routing down to exact card.
  braid_key() — combined 32-bit key: (role as u16) << 16 | expert_id.
  AriGraph subgraph integration is consumer-side (lance-graph core,
  graph::arigraph/); contract stays zero-dep.

Plan § 10.7 — Consumers address roles: explicit OR implicit
  Four routing modes from the RoutingHint combinations. crewai-rust /
  n8n-rs / openclaw all address the same blackboard through the same seed
  shape; the two modes are hint-present vs hint-absent, not separate APIs.

Plan § 10.8 — AriGraph IS the persona's memory
  PersonaCard = identity; AriGraph subgraph = memory. Resolved at
  lance-graph boundary via AriGraph::subgraph_for(ExpertId). Each persona
  runs its own Commit/Epiphany/FailureTicket loop on its subgraph; the
  blackboard composes across them. Personas that handle seeds LEARN —
  next similar seed resonates higher on that card.

Plan § 10.9 — Membrane · Role · Place · Translation (iron rule)
  The prior stack's contract, now explicit:
    1. Pass the membrane (no direct BindSpace writes)
    2. Get a role (ExternalRole × ExpertId)
    3. Get a place (round + VSA slot)
    4. Translate into internal reasoning (not stored as bytes — transcribed)
  No untagged external state anywhere. If you can't name role/place/
  translation for a piece of data, it doesn't belong in the substrate.

https://claude.ai/code/session_01CgQyZ7rMWkCEohrPzEiwkD
…lRole

contract::faculty — new zero-dep module:
  FacultyRole enum (4 starter variants: ReadingComprehension, Voice,
    Reasoning, Empathy). #[repr(u8)], extensible.
  ToolAbility = u16 alias. Opaque id type; registry is consumer-side
    so faculty descriptors can be declared without implementation deps.
  FacultyDescriptor { role, inbound_style, outbound_style, tools } —
    asymmetric transducer shape. Inbound ThinkingStyle = how the faculty
    interprets received bundles; outbound ThinkingStyle = how it emits.
    tools: &'static [ToolAbility] — concrete operations it can invoke.
  is_asymmetric() — runtime check; symmetric is legal (pass-through).

Three-coordinate provenance: (ExternalRole family, ExpertId card,
FacultyRole function). All three are RoleKey-bindable; unbindable at any
coordinate. The shader can observe its own faculties as first-class
features — QualiaClassification can fire on "Reasoning overwhelmed,
Empathy idle" and the router rebalances.

Plan § 10.10 deferred pending further refinement of the faculty model
(variants, asymmetry constraint, tool registry split).

https://claude.ai/code/session_01CgQyZ7rMWkCEohrPzEiwkD
… slots

Four corrections to address the BBB-preservation concern raised mid-session:

contract::persona:
  - Remove PersonaCard::braid_key() -> u32 — it packed (role << 16) | expert_id
    into a composite 32-bit key, implying a parallel VSA slot address space
    incompatible with the existing 4096 COCA / CAM-PQ / NARS-head vocabulary.
  - Add module doc section "Identity lives in metadata; VSA binding is
    stack-side (BBB invariant)". Role and card are separate Arrow-scalar
    metadata columns, queryable via SQL / Cypher / GQL / NARS / qualia.
    Stack-side code deterministically maps those metadata values to RoleKey
    slot addresses for internal VSA braiding — the slot mapping never crosses
    the BBB. External surface sees columns; internal substrate sees slots;
    same identity, two representations.

plan § 10.6:
  - Add erratum paragraph retracting the "(role << 16) | expert_id" braid
    key proposal. Replace with correct addressability note: role and card
    are addressable independently via the five metadata-bus query dialects.

plan § 4 cognitive_event schema:
  - Add five new scalar identity/scent columns:
      external_role: UInt8   (ExternalRole family tag)
      faculty_role:  UInt8   (FacultyRole function tag)
      expert_id:     UInt16  (stable card hash)
      dialect:       UInt8   (query dialect: Cypher/GQL/NARS/Redis/Spark/SQL)
      scent:         UInt8   (1-byte compressed address scent, § 10.13)
  - These are the metadata-bus coordinates (see § 10.11). Still no VSA,
    no semiring, no RoleKey — just numbers crossing the gate.

Contract crate compiles clean (6 pre-existing warnings, no new ones).

https://claude.ai/code/session_01CgQyZ7rMWkCEohrPzEiwkD
…int epiphany)

PREPEND dated epiphany 2026-04-22 covering the deployment doctrine that
joins every dimension accumulated this session:

 1. A2A agents = training surface (no labels, no cold start)
 2. Supabase shape = adoption surface
 3. Metadata = uniform address bus (queries ARE dispatch)
 4. REST + DataFusion (ladybug-rs prior art)
 5. DN-addressed URL hierarchy (tree:heel:hip:branch:twig:leaf)
 6. Address = scent (1B via codec chain) = context-pull key
 7. Body content = external seed → blackboard mediation
 8. Polyglot front end: Cypher/GQL/Gremlin/SPARQL/NARS/Redis/Spark/SQL
 9. Agent cards + faculties + external roles = one identity space

BBB invariant stated explicitly: every dimension lives in TWO
representations — metadata columns externally (Arrow scalars crossing
the gate safely, queryable by five dialects), VSA role-bindings
internally (RoleKey slots for Markov ±5 braiding, never cross). Same
identity, two faces. Supabase refactor only ever sees Arrow; blackboard
only ever sees role-tagged entries.

Litmus test codified: for every byte crossing the gate, can I name
role/place/translation? Does external see only Arrow scalars? Does
internal see only role-tagged blackboard entries? If no → reject.

Cross-refs to contract modules and plan sections.

https://claude.ai/code/session_01CgQyZ7rMWkCEohrPzEiwkD
… DN REST polyglot, scent cascade, 4-phase sequencing

- § 10.10: VSA 10000-D lossless role bind/unbind (slot partition for
  ExternalRole/FacultyRole/ExpertId/dialect/scent; J-L lossless recovery;
  why d=10k; BBB role clarified — internal face only, never crosses gate)
- § 10.11: Metadata address bus (five dialects: SQL/Cypher-GQL/NARS/Qualia/
  OrchestrationBridge; queries ARE dispatch; bus BBB role)
- § 10.12: DN-addressed REST + polyglot front end (Cypher/GQL/Gremlin/SPARQL
  already shipped; NARS + Spark = full parsers; Redis = thin DataFusion
  shape-adapter, NOT a new parser; ladybug-rs prior art referenced;
  dialect-as-signal metadata column)
- § 10.13: Address = scent = context-pull (compression chain 16Kbit→1B;
  four uses of one compressed object; context-pull flow; training loop)
- § 11: Four-phase sequencing (Phase A: BBB spine; Phase B: Polyglot front
  end; Phase C: Scent cascade; Phase D: Realtime + training)

https://claude.ai/code/session_01CgQyZ7rMWkCEohrPzEiwkD
Implements the Blood-Brain Barrier gate between external consumers and
the cognitive substrate. Three new modules in lance-graph-callcenter:

- dn_path.rs: DnPath (6×u64 FNV-1a segment hashes) + scent_stub()
  XOR-fold placeholder; Phase C wires full ZeckBF17→Base17→CAM-PQ
  cascade. 5 tests.

- external_intent.rs: ExternalIntent (inbound gate crossing shape) +
  CognitiveEventRow (outbound scalar projection). All fields are
  Arrow-scalar primitives (u8/u16/u64/bool). Full schema table in
  doc (§ 4: external_role/faculty_role/expert_id/dialect/scent +
  MetaWord fields + cycle_fp_hi/lo + gate_commit/gate_f).

- lance_membrane.rs: LanceMembrane implements ExternalMembrane.
  project() strips ShaderBus to CognitiveEventRow scalars (no VSA
  types cross). ingest() executes the 4-step iron rule: pass membrane
  → get role → get place (scent) → translate to UnifiedStep. subscribe()
  returns Phase-A disconnected mpsc::Receiver<u64>; Phase D wires tokio
  watch + CommitFilter. 5 tests including bbb_scalar_only_compile_check.

Also fixes a2a_blackboard.rs ExpertId doc: removes the retracted packed
braid-key comment, replaces with the correct metadata-columns-as-identity
statement (see plan § 10.6 erratum).

UNKNOWN-1 resolved in module doc: ShaderSink (cognitive-shader-driver)
is internal BindSpace ingestion; no overlap with ExternalMembrane.

10/10 tests pass. Zero new warnings in callcenter crate.

https://claude.ai/code/session_01CgQyZ7rMWkCEohrPzEiwkD
VSA d=10000 saturating bundle IS a commutative monoid (CK by
construction, E-SUBSTRATE-1) — the same algebraic foundation git
approximates. Maps every git primitive to the existing callcenter
machinery: commit→CollapseGate, branch→speculative blackboard round,
merge→MergeMode::Bundle, rebase→Markov replay, checkout→Lance
time-travel, blame→VSA unbind projected to metadata columns.

Chat turn = commit. Blackboard round = staging area. CollapseGate =
git commit. Lance version = object store append. ±5/±500 Markov
window = HEAD~5 / HEAD~500. Jirak bounds tick density; Cartan governs
which columns project outward. BBB invariant holds at every git verb —
no VSA type crosses the gate, git-shaped ops are scalar-only on the
external face.

Adoption surface: "git for thoughts" — zero onboarding friction for
any developer who has used git. DN URL path IS a refspec. PersonaCard
is the author. RoutingHint is the target ref.

https://claude.ai/code/session_01CgQyZ7rMWkCEohrPzEiwkD
§ 14 Cold Storage two dataset classes (external/scalar + internal/VSA),
Lance+S3 as git cold storage, E-DEPLOY-1 training corpus path.

§ 15 VSA dispatch — role × thinking = persona, RoleDB DataFusion UDFs
(unbind/bundle/hamming_dist/braid_at/top_k), n8n-rs Supabase Realtime wiring.

§ 16 Persona as function — 32 named cognitive atoms × 16 weightings (16^32
addressable space), 56-bit PersonaSignature, YAML runbooks as context-loop
macro scaffolding (not persona identity). 46,000× storage reduction.

§ 17 Four-way multiply (persona × style × stage × learned-dynamics) + ONNX
persona classifier at L4/L5 replacing Chronos (full 288-class product
prediction vs 1D style scalar). MM-CoT stage split as rationale_phase bool.

unified-integration-v1.md: DU-0 through DU-5 deliverables with effort,
sequencing, invariants, and open questions.

https://claude.ai/code/session_01CgQyZ7rMWkCEohrPzEiwkD
…settings allow *.md

DU-4 (MM-CoT stage split): add `rationale_phase: bool` to `CognitiveEventRow`
  — Phase B placeholder (false); wired when FacultyDescriptor::is_asymmetric() true.
  — Update schema table comment in external_intent.rs.
  — Populate in LanceMembrane::project() as false (Phase A).

DU-5 (board hygiene):
  — INTEGRATION_PLANS.md: prepend unified-integration-v1 entry (DU-0..DU-5).
  — STATUS_BOARD.md: append DU-0 through DU-5 rows with Queued status.

Cargo.toml fixes:
  — Root Cargo.toml: remove duplicate `exclude` key (leftover from Python CI cleanup).
  — crates/lance-graph/Cargo.toml: remove duplicate lance-graph-catalog/lance/
    lance-linalg/lance-namespace keys; keep lance-graph-catalog@0.5.4 + lance@2.

Settings: add Edit(**/*.md) + Write(**/*.md) to allow list; board .md files
  remain protected by existing deny rules (deny > allow).

https://claude.ai/code/session_01CgQyZ7rMWkCEohrPzEiwkD
…age corrections

- callcenter-membrane-v1.md §14: clarify internal dataset uses Fingerprint<256>
  (L4/L5 speed tier, 2KB); L3 cold tier can promote to Vsa10k BF16 or RaBitQ
- callcenter-membrane-v1.md §17: fix Tensor[N,256×64] → Tensor[N,16384] with note
  that fingerprint format is the correct L4/L5 speed-lane input for ONNX classifier
- callcenter-membrane-v1.md §18 (new): VSA precision-tier table (Fingerprint/Vsa10k-BF16/
  Vsa10k-f32), L4/L5 speed-lane invariant, VSA-as-wire-format definition,
  father-grandfather generational compression hierarchy (son/father/grandfather
  bundle at 1/100/1000 cycles via MergeMode::Bundle, CK-safe)
- unified-integration-v1.md: fix title (Chronos→ONNX), DU-1 input clarification,
  DU-3 precision-tier note for deep unbind at L3, DU-4/DU-5 status → Shipped
- STATUS_BOARD.md: DU-4 and DU-5 marked Shipped (commit a05979e)

https://claude.ai/code/session_01CgQyZ7rMWkCEohrPzEiwkD
@AdaWorldAPI AdaWorldAPI merged commit 947802b into main Apr 23, 2026
0 of 5 checks passed

@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: 7a60c4247b

ℹ️ 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".

};

UnifiedStep {
step_id: format!("{:016x}", scent as u64),

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Generate unique step IDs instead of 8-bit scent hashes

ingest() currently derives step_id only from scent_stub() (a single u8), so there are at most 256 distinct IDs and collisions are inevitable under normal traffic; two unrelated intents can receive the same step_id, which breaks correlation of status/reasoning across routed steps and can cause one step to be mistaken for another. Use a collision-resistant identifier (e.g., UUID/ULID or include high-entropy fields like full DN hash + timestamp/counter) rather than the 1-byte scent.

Useful? React with 👍 / 👎.

/// Returns `None` if the path does not match the 12-segment pattern.
pub fn parse(path: &str) -> Option<Self> {
let segs: Vec<&str> = path.trim_start_matches('/').split('/').collect();
if segs.len() < 12 { return None; }

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 Enforce exact DN segment count during path parsing

The parser documentation says the DN path must match a 12-segment pattern, but the current guard only rejects paths shorter than 12 segments; longer paths are silently accepted and truncated because only indices 0..11 are read. This means distinct URLs like .../leaf/abc and .../leaf/abc/extra normalize to the same DnPath, causing ambiguous routing/scent derivation and weakening boundary validation.

Useful? React with 👍 / 👎.

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.

4 participants