|
| 1 | +# cypher-kanban-ast-unification-v1 — Cypher IS the kanban-board AST; the GUID-keyed substrate IS the graph; four subsystems collapse to one |
| 2 | + |
| 3 | +> **Status:** PLAN (pre-5+3-council). Captures the unification from |
| 4 | +> `E-GUID-IS-THE-GRAPH` + `E-CYPHER-IS-THE-KANBAN-AST` before it dilutes, |
| 5 | +> and sequences the q2-rewire wiring. **datafusion stays the default query |
| 6 | +> engine; the SurrealQL lowering rides the `lite-unified` gate (#540, |
| 7 | +> default-OFF) — process, not switch.** |
| 8 | +
|
| 9 | +## The thesis (one AST, four sides) |
| 10 | + |
| 11 | +A kanban board is a graph. The GUID is the key. Therefore Cypher — the AST for |
| 12 | +graph patterns — is the board's native query/mutation language, and the planner |
| 13 | +already shares **one IR/AST** across all four sides: |
| 14 | + |
| 15 | +| Side | Surface | Already shipped | |
| 16 | +|---|---|---| |
| 17 | +| **Query language** | Cypher / Gremlin / SPARQL / GQL → one IR | planner `strategy/{cypher,gremlin,sparql,gql}_parse.rs` | |
| 18 | +| **Adapter / egress** | SurrealQL AST (`DEFINE`/traversal) | `ExecTarget::SurrealQl` + `ogar-adapter-surrealql`; odoo ontology traversal = existence proof | |
| 19 | +| **Planner layer** | thinking-styles + MUL over the IR | planner `thinking/` (12 styles, NARS, sigma chain), `mul/` | |
| 20 | +| **Board** | kanban phases the cards move through | `kanban::{KanbanColumn, ExecTarget}` | |
| 21 | + |
| 22 | +Board ⇄ graph mapping (no new types): |
| 23 | +- **card → GUID node** (`NodeGuid` key; `classid→ClassView`, `local_key`=family++identity) |
| 24 | +- **column / phase → state** (a `Column` node via `:IN` edge, or a `classid`/property) |
| 25 | +- **move → edge rewrite** (`(c)-[:IN]->(Doing)` ⇒ `(c)-[:IN]->(Done)`) |
| 26 | +- **dependency / blocks → edge**; **WIP limit → a Cypher `count` guard**; **swimlane → basin/label** |
| 27 | +- **`KanbanColumn::can_transition_to` → the graph schema** (which edges are legal) |
| 28 | + |
| 29 | +The `KanbanColumn` cognitive cycle is the *mailbox* instantiation; an odoo project |
| 30 | +board / woa work-order board / q2 case board are *domain* instantiations — |
| 31 | +**same AST, same substrate, different `classid` + edge schema.** |
| 32 | + |
| 33 | +## What's already true (no work) |
| 34 | + |
| 35 | +- **The substrate is the graph** (`E-GUID-IS-THE-GRAPH`): node = `NodeGuid` key, |
| 36 | + edge = `EdgeBlock` slot (byte → neighbor `local_key`) or `CausalEdge64`, |
| 37 | + traversal = prefix-route + slot-deref, zero value decode. |
| 38 | +- **Cypher parses** (core nom parser, 44 tests: node + relationship patterns, |
| 39 | + var-length `*1..2`, WHERE/RETURN/etc). |
| 40 | +- **The polyglot front-ends → one IR**; **thinking-styles + MUL** plan over it; |
| 41 | + **`ExecTarget::SurrealQl`** is the egress. |
| 42 | +- **odoo ontology traversal already runs through the SurrealQL AST adapter** — |
| 43 | + the existence proof that Cypher/ontology-over-SurrealQL works. |
| 44 | + |
| 45 | +## The gap (what this plan wires) — additive, layout-preserving |
| 46 | + |
| 47 | +### Inc 0 — `Backend::MailboxSoa` router variant |
| 48 | +`graph_router::Backend` gains a `MailboxSoa` variant whose scan: |
| 49 | +- resolves **key → row** via `NodeGuid::{from_guid_prefix, local_key}` (no guid |
| 50 | + value-column — the key IS the address), |
| 51 | +- follows edges by **`EdgeBlock` slot deref** (byte → neighbor `local_key`) and/or |
| 52 | + `MailboxSoaView::edges_raw` (`CausalEdge64`), |
| 53 | +- a Cypher `MATCH (n:Label)` lowers to a **classid prefix route**; `(a)-[r]->(b)` |
| 54 | + to an **edge-slot deref** — both zero-value-decode. |
| 55 | +Additive to the existing 3-backend router (DataFusion / Blasgraph / Palette); no |
| 56 | +`NodeRow`/stride/`ENVELOPE_LAYOUT_VERSION` change. |
| 57 | + |
| 58 | +### Inc 1 — Cypher → SurrealQL lowering behind `lite-unified` (default-OFF) |
| 59 | +The board's mutations/queries lower to SurrealQL (`ExecTarget::SurrealQl`) **only |
| 60 | +under `lite-unified`**; datafusion stays the default. This is the egress side of |
| 61 | +the AST, gated per the #540 process-not-switch invariant. |
| 62 | + |
| 63 | +### Inc 2 — kanban-board-as-Cypher over the GUID substrate |
| 64 | +Express board ops as Cypher patterns dispatched through the planner with |
| 65 | +thinking-styles/MUL: a move = a Cypher edge-rewrite → IR → style/MUL plan → |
| 66 | +`ExecTarget`; a query (cards-in-column / blocked / WIP-count) = a Cypher `MATCH`. |
| 67 | +The transition-legality (`KanbanColumn::can_transition_to`) is the schema guard. |
| 68 | + |
| 69 | +### Inc 3 — q2 consumer wiring (the rewire) |
| 70 | +q2 (Palantir-Gotham/neo4j-aspiring) cases = a **domain `classid` + edge schema** |
| 71 | +over the same substrate + AST. q2 depends on lance-graph as the hot path (NOT a |
| 72 | +substitute — `.claude/rules/architectural-compliance.md`); its board/case |
| 73 | +traversal is Cypher over `Backend::MailboxSoa`. |
| 74 | + |
| 75 | +## Falsification gates |
| 76 | + |
| 77 | +- **F1 (router):** a Cypher `MATCH (n:Label)` over `Backend::MailboxSoa` returns |
| 78 | + the same node set as the DataFusion backend on the same data (backend parity). |
| 79 | +- **F2 (zero-decode):** a 1-hop traversal touches only key + `EdgeBlock` bytes, |
| 80 | + never the 480 B value slab (assert via a value-access counter / borrow check). |
| 81 | +- **F3 (board legality):** an illegal kanban move (`!can_transition_to`) is |
| 82 | + rejected at plan time, not after the edge rewrite. |
| 83 | +- **F4 (gate isolation):** with `lite-unified` OFF, behaviour is byte-identical to |
| 84 | + today (datafusion path); the SurrealQL lowering is unreachable. |
| 85 | +- **F5 (no new layer):** the unification adds ONE router variant + ONE lowering |
| 86 | + path behind a flag — no new node/edge type, no second object model, no |
| 87 | + kanban-as-traversal type. |
| 88 | + |
| 89 | +## Scope guards (truth-architect) |
| 90 | + |
| 91 | +- "Cypher is the kanban AST" = Cypher is the **surface** that lowers to the shared |
| 92 | + IR/SurrealQL AST — NOT a claim the nom parser emits SurrealQL today (it lowers |
| 93 | + to DataFusion; SurrealQL lowering is Inc 1 behind `lite-unified`). |
| 94 | +- **datafusion is NOT deprecated** (#540). The router gains a backend; it does not |
| 95 | + lose one. |
| 96 | +- No measured-perf claim without a bench (F1 is a correctness/parity gate, not a |
| 97 | + speed gate). |
| 98 | +- The mailbox-`KanbanColumn` lifecycle and a domain board are the SAME structure; |
| 99 | + do NOT fork a second kanban type per domain — vary `classid` + edge schema. |
| 100 | + |
| 101 | +## Cross-refs |
| 102 | +`E-GUID-IS-THE-GRAPH`, `E-CYPHER-IS-THE-KANBAN-AST`, `E-AR-DO-WIRING` |
| 103 | +(ontology→DO consumers), `lite-unified-surrealql-lance-v1` (#540 gate), |
| 104 | +`canonical_node::{NodeGuid, EdgeBlock, NodeRow}`, `soa_view::MailboxSoaView`, |
| 105 | +`kanban::{KanbanColumn, ExecTarget}`, planner `thinking/` + |
| 106 | +`strategy/cypher_parse.rs`, `graph_router::Backend`, |
| 107 | +`.claude/rules/architectural-compliance.md` (q2 must consume, not substitute). |
0 commit comments