Skip to content

Commit 46ad59b

Browse files
committed
v3 session stack: REFACTOR not bridge. P2 takes P3 AST directly. No adapter layer.
1 parent 5f18f8f commit 46ad59b

1 file changed

Lines changed: 126 additions & 134 deletions

File tree

.claude/TONIGHT_SESSION_STACK.md

Lines changed: 126 additions & 134 deletions
Original file line numberDiff line numberDiff line change
@@ -1,205 +1,197 @@
1-
# TONIGHT_SESSION_STACK.md (v2CORRECTED)
1+
# TONIGHT_SESSION_STACK.md (v3REFACTOR, NOT BRIDGE)
22

3-
## ⚠ CORRECTION FROM v1
4-
5-
**v1 said delete lance_parser (P3, 5532 lines). WRONG.**
6-
lance_parser IS the production Cypher parser. It's a correctly adapted
7-
port of lance-graph's nom parser with proper ladybug-rs error type integration.
8-
The "divergence" in semantic.rs is correct QueryError adaptation, not drift.
9-
10-
**Session 1 now deletes ONLY P1 (cypher.rs, 1560 lines).**
3+
## 4 Hours. No Bridges. No Adapters. Refactor Properly.
114

125
---
136

14-
## ⚠ REPO FOCUS RULES
7+
## SESSION 1: Kill P1, Refactor P2 to Consume P3 AST Directly [REPO: ladybug-rs]
158

9+
**Read COMPLETELY before writing:**
1610
```
17-
EVERY TASK IS TAGGED WITH A REPO.
18-
DO NOT touch files in a different repo than the current tag.
19-
When switching repos: STOP. Read that repo's CLAUDE.md FIRST.
20-
21-
Current repo names (DO NOT RENAME ANYTHING TONIGHT):
22-
ladybug-rs ← main surgery target
23-
rustynum ← READ ONLY from ladybug-rs sessions
11+
src/query/lance_parser/ast.rs (532 lines — the AST types)
12+
src/cypher_bridge.rs (897 lines — the executor)
13+
src/query/cypher.rs (1560 lines — the thing being deleted)
14+
src/bin/server.rs lines 1621-1655 (the /cypher endpoint)
2415
```
2516

26-
---
27-
28-
## SESSION 1: Delete P1 Only [REPO: ladybug-rs]
17+
**The refactor:**
2918

30-
**Read first:** `CLAUDE.md`, `src/query/cypher.rs` (skim — understand what's being removed)
19+
P2's `execute_cypher()` takes `&[CypherOp]`. CypherOp is a flat enum with 5 variants
20+
(MergeNode, CreateNode, CreateEdge, SetProperty, MatchReturn).
3121

32-
```
33-
1. Save CTE generator FIRST:
34-
cp src/query/cypher.rs /tmp/cypher_backup.rs
35-
Extract lines 1253-1361 → src/query/cte_builder.rs
36-
(Recursive CTE for variable-length paths — UNIQUE, neither P3 nor P5 has it)
37-
38-
2. Delete src/query/cypher.rs
39-
40-
3. Update src/query/mod.rs:
41-
Remove: pub mod cypher;
42-
Remove: pub use cypher::{CypherParser, CypherQuery, CypherTranspiler, cypher_to_sql};
43-
44-
4. Fix broken references:
45-
server.rs:1625 calls cypher_to_sql — this will break. COMMENT IT OUT for now:
46-
// TODO: wire lance_parser + cypher_bridge (session 2)
47-
http_error(501, "cypher_not_implemented", "being rewired", format)
22+
P3's parser produces `lance_parser::ast::CypherQuery` with rich tree types
23+
(ReadingClause, MatchClause, GraphPattern, NodePattern, PathPattern, etc.).
4824

49-
hybrid.rs:20 imports CypherParser — comment out or remove usage
25+
**DO NOT create an ast_bridge.rs. Rewrite cypher_bridge.rs to take P3 types directly:**
5026

51-
5. cargo check --no-default-features --features "simd"
27+
```rust
28+
// BEFORE (current cypher_bridge.rs):
29+
pub fn execute_cypher(bs: &mut BindSpace, ops: &[CypherOp]) -> Result<CypherResult, String>
5230

53-
6. Rename in src/learning/cam_ops.rs:
54-
CypherOp → CypherInstruction
55-
Update all references within src/learning/
56-
57-
7. cargo check again
31+
// AFTER (refactored):
32+
pub fn execute_cypher(bs: &mut BindSpace, query: &lance_parser::ast::CypherQuery) -> Result<CypherResult, String>
5833
```
5934

60-
**-1560 lines deleted. lance_parser UNTOUCHED.**
35+
The internal `CypherOp` enum DISAPPEARS. The execute functions work directly on the AST:
6136

62-
**Commit:** `chore: delete P1 cypher.rs (hand-rolled transpiler) — rescue CTE builder`
37+
```rust
38+
// BEFORE:
39+
CypherOp::MergeNode { labels, properties } => execute_merge_node(bs, labels, properties, &mut result)?
6340

64-
---
41+
// AFTER:
42+
for clause in &query.reading_clauses {
43+
match clause {
44+
ReadingClause::Match(m) => execute_match(bs, m, &query.where_clause, &query.return_clause, &mut result)?,
45+
ReadingClause::Unwind(u) => execute_unwind(bs, u, &mut result)?,
46+
}
47+
}
48+
// CREATE/MERGE/SET handled from query.update_clauses (or however P3 structures writes)
49+
```
6550

66-
## SESSION 2: Build AST→CypherOp Bridge + Wire Server [REPO: ladybug-rs]
51+
Keep P2's execution LOGIC (find_node_by_label_and_name, evaluate_where, MERGE semantics).
52+
Replace P2's TYPES (CypherOp, NodeRef, WhereClause, CypherValue) with P3's types.
53+
Delete P2's parse_cypher() (P3's parse_cypher_query replaces it).
54+
Keep P2's execute_* functions, rewrite their signatures to take P3 AST nodes.
6755

68-
**Read first:**
69-
- `src/query/lance_parser/ast.rs` (the AST types P3 produces)
70-
- `src/cypher_bridge.rs` (the CypherOp types P2 consumes)
56+
**Steps:**
7157

7258
```
73-
1. Create src/query/ast_bridge.rs (~100-150 lines):
74-
Convert lance_parser AST → cypher_bridge CypherOp
75-
76-
use crate::query::lance_parser::ast::{CypherQuery as ParsedQuery, ...};
77-
use crate::cypher_bridge::{CypherOp, NodeRef, CypherValue};
78-
79-
pub fn ast_to_ops(parsed: &ParsedQuery) -> Result<Vec<CypherOp>, String> {
80-
// Walk the AST, produce CypherOp list
81-
// MATCH clause → CypherOp::MatchReturn
82-
// CREATE clause → CypherOp::CreateNode / CreateEdge
83-
// MERGE → CypherOp::MergeNode
84-
// SET → CypherOp::SetProperty
85-
}
59+
1. Delete src/query/cypher.rs
60+
- Save lines 1253-1361 to src/query/cte_builder.rs first
61+
- Remove from query/mod.rs
8662
87-
2. Wire server.rs /cypher endpoint:
88-
Replace the commented-out TODO from session 1:
63+
2. Rewrite src/cypher_bridge.rs:
64+
- Remove: CypherOp enum, NodeRef enum, WhereClause enum, CypherValue enum
65+
- Remove: parse_cypher() function
66+
- Change: execute_cypher signature to take &CypherQuery (P3 type)
67+
- Change: execute_merge_node to take &NodePattern (P3 type)
68+
- Change: execute_create_edge to take &PathPattern (P3 type)
69+
- Change: execute_match_return to take &MatchClause + &WhereClause (P3 types)
70+
- Change: evaluate_where to take &BooleanExpression (P3 type)
71+
- Keep: CypherResult (it's the output format, not input)
72+
- Keep: find_node_by_label_and_name (working scan logic)
73+
- Keep: MERGE upsert semantics
8974
75+
Map P3's PropertyValue → to the value types execute_* needs
76+
Map P3's BooleanExpression → to what evaluate_where checks
77+
This is INLINE refactoring, not a bridge module.
78+
79+
3. Wire server.rs:
9080
use ladybug::query::lance_parser::parse_cypher_query;
91-
use ladybug::query::ast_bridge::ast_to_ops;
9281
use ladybug::cypher_bridge::execute_cypher;
9382
9483
match parse_cypher_query(&query) {
95-
Ok(parsed) => {
96-
// Validate via semantic analyzer (P3 has this!)
97-
match ast_to_ops(&parsed) {
98-
Ok(ops) => {
99-
let bs = db.cog_redis.bind_space_mut();
100-
match execute_cypher(bs, &ops) {
101-
Ok(result) => serialize result as JSON
102-
Err(e) => http_error(500, ...)
103-
}
104-
}
105-
Err(e) => http_error(400, "ast_conversion", &e, format)
106-
}
84+
Ok(ast) => match execute_cypher(&mut bs, &ast) {
85+
Ok(result) => serialize
86+
Err(e) => error
10787
}
108-
Err(e) => http_error(400, "cypher_parse", &e.to_string(), format)
88+
Err(e) => parse error
10989
}
11090
111-
3. cargo check
112-
4. Test: curl /cypher with MERGE → node created
113-
5. Test: curl /cypher with MATCH → results returned
114-
```
91+
4. Rename cam_ops CypherOp → CypherInstruction
11592
116-
**~150 lines new. Full parse→validate→execute pipeline working.**
93+
5. cargo check --no-default-features --features "simd"
94+
```
11795

118-
**Commit:** `feat: wire lance_parser → ast_bridgecypher_bridge → server.rs /cypher`
96+
**Exit gate:** `/cypher` endpoint calls P3 parserrefactored P2 executor. Zero bridge types.
11997

12098
---
12199

122-
## SESSION 3: Unlock spo.rs [REPO: ladybug-rs]
100+
## SESSION 2: Unlock spo.rs Properly [REPO: ladybug-rs]
123101

124-
**Read first:** `src/spo/spo.rs` (ENTIRE FILE, 1568 lines. No skimming.)
102+
**Read COMPLETELY:** `src/spo/spo.rs` (all 1568 lines, every function, every type)
125103

126104
```
127-
1. src/spo/mod.rs: change `mod spo;` → `pub(crate) mod spo;`
105+
1. src/spo/mod.rs: `mod spo` → `pub(crate) mod spo`
106+
107+
2. In spo.rs itself: make key types pub(crate)
108+
pub(crate) struct SPOCrystal
109+
pub(crate) struct OrthogonalCodebook
110+
pub(crate) fn bundle()
111+
pub(crate) fn bundle_weighted()
112+
Keep private: internal helpers, Fingerprint (use core::Fingerprint instead)
113+
114+
3. Add to core/fingerprint.rs:
115+
pub fn project_out(&self, other: &Fingerprint) -> Fingerprint
116+
pub fn dot_bipolar(&self, other: &Fingerprint) -> i64
117+
(Port from spo.rs, adapt to core::Fingerprint layout)
118+
119+
4. In spo.rs: replace internal Fingerprint usage with core::Fingerprint
120+
where signatures cross module boundary.
121+
Keep internal Fingerprint for private functions if easier —
122+
but crystal_api RETURNS core::Fingerprint.
128123
129-
2. Add to core/fingerprint.rs:
130-
project_out() — Gram-Schmidt from spo.rs lines 116-140
131-
dot_bipolar() — from spo.rs lines 109-115
124+
5. Create src/spo/crystal_api.rs — NOT a facade. Direct re-export + helpers:
125+
pub use super::spo::{SPOCrystal, OrthogonalCodebook};
132126
133-
3. Create src/spo/crystal_api.rs (~200 lines):
134-
Public facade wrapping private SPOCrystal.
127+
Plus convenience constructors that use core types:
128+
pub fn new_crystal() -> SPOCrystal
129+
pub fn encode_and_insert(crystal: &mut SPOCrystal, s: &str, p: &str, o: &str)
130+
pub fn query_object(crystal: &SPOCrystal, s: &str, p: &str) -> Vec<QueryHit>
135131
136-
4. Add to src/spo/mod.rs: pub mod crystal_api;
132+
These are THIN — they call spo.rs methods directly, not wrap them.
137133
138-
5. cargo check
134+
6. cargo check
139135
```
140136

141-
**Commit:** `feat: unlock spo.rs — pub(crate), crystal_api facade, project_out`
137+
**Exit gate:** `use crate::spo::crystal_api::SPOCrystal` works from server.rs.
142138

143139
---
144140

145-
## SESSION 4: Wire Crystal to Cypher Bridge [REPO: ladybug-rs]
141+
## SESSION 3: Wire Crystal Into Cypher Execute [REPO: ladybug-rs]
146142

147-
**Read:** `src/cypher_bridge.rs` lines 370-420, `src/spo/crystal_api.rs`
143+
**Read:** refactored cypher_bridge.rs (from session 1) + crystal_api.rs (from session 2)
148144

149145
```
150-
1. Add CrystalQuery to server DatabaseState
151-
2. In cypher_bridge execute_match: try crystal_api first, fall back to nodes_iter
152-
3. cargo check
153-
```
154-
155-
**Commit:** `feat: MATCH queries use SPO Crystal O(25) lookup with nodes_iter fallback`
146+
1. Add SPOCrystal to DatabaseState in server.rs
156147
157-
---
148+
2. In cypher_bridge execute_match (the read path):
149+
REPLACE bs.nodes_iter() full scan
150+
WITH crystal.resonate_spo() for queries that have S and/or P
151+
152+
KEEP nodes_iter as fallback for label-only queries without SPO terms
153+
154+
This is refactoring execute_match, not adding a layer.
158155
159-
## SESSION 5: CI Triage [REPO: ladybug-rs, then rustynum if needed]
156+
3. In cypher_bridge execute_merge/create:
157+
AFTER writing to BindSpace, ALSO insert into SPOCrystal
158+
Both stores get the data. Crystal is the fast index.
159+
BindSpace is the source of truth.
160160
161-
```
162-
⚠ REPO SWITCH possible. Read each CLAUDE.md before touching.
163-
Focus: get cargo check green, not cargo test (tests can wait).
161+
4. cargo check + test with curl
164162
```
165163

164+
**Exit gate:** MATCH with subject+predicate hits Crystal (O(25)), not scan (O(N)).
165+
166166
---
167167

168-
## SESSION 6: Close Stale PRs [REPO: ladybug-rs]
168+
## SESSION 4: CI + Stale PRs [REPO: ladybug-rs, maybe rustynum]
169169

170170
```
171-
Close #11-#33, #54 with "superceded by main"
172-
Evaluate #168, #169 against merged #170
173-
Target: open PRs ≤ 5
174-
```
171+
1. cargo check --all-features (or closest working feature set)
172+
Fix what breaks. Don't add features.
175173
176-
---
177-
178-
## SESSION 7 (STRETCH): Harvest lance-graph truth.rs [REPO: ladybug-rs]
174+
2. Close PRs #11-#33, #54
175+
Evaluate #168, #169 against #170
179176
180-
```
181-
READ lance-graph truth.rs (175 lines).
182-
MERGE into ladybug-rs graph/spo/.
183-
ADD walk_chain_forward from lance-graph store.rs.
177+
3. If rustynum CI blocks ladybug-rs:
178+
⚠ SWITCH REPO — read rustynum CLAUDE.md first
179+
Fix the minimum needed for cargo check to pass
184180
```
185181

186182
---
187183

188-
## SESSION ORDER
184+
## TIMING
189185

190186
```
191-
SESSION WHAT EST. TIME PRIORITY
192-
1 Delete P1 only 20-30 min P0
193-
2 Bridge P3→P2 + server 45-60 min P0
194-
3 Unlock spo.rs 45-60 min P0
195-
4 Crystal → Cypher 30-45 min P1
196-
5 CI triage 30-60 min P1
197-
6 Close stale PRs 15 min P2
198-
7 Harvest truth.rs 30 min P2 (stretch)
187+
SESSION EST. PRIORITY
188+
1 90 min P0 (the big refactor)
189+
2 60 min P0
190+
3 45 min P1
191+
4 30 min P2
192+
TOTAL ~4 hours
199193
```
200194

201-
**Minimum tonight:** Sessions 1-3 (delete P1, bridge P3→P2, unlock spo.rs).
202-
203195
---
204196

205-
*"Read first. All of it. Then decide."*
197+
*"No bridges. No adapters. No facades. Refactor the types. Inline the logic."*

0 commit comments

Comments
 (0)