hunt commited on
Commit ·
e24f164
1
Parent(s): 7eaf400
Fix duckdb list-column binding and neo4j retry test; 164/164 tests passing
Browse files- HANDOFF.md +24 -0
- miranda-nodes/src/memory/duckdb_writer.rs +12 -6
- miranda-nodes/src/memory/neo4j_writer.rs +26 -7
- scripts/duckdb-init.sh +2 -2
HANDOFF.md
CHANGED
|
@@ -350,3 +350,27 @@ These are minimal compiling stubs, not final implementations. Once `cargo build
|
|
| 350 |
3. Begin replacing the 14 stub files' placeholder logic with real implementations per `wo-conversational-intelligence` and `wo-model-forge` design docs — starting with the two non-negotiable invariant modules: `autonomy_calibration.rs` and `partnership_tracker.rs`.
|
| 351 |
4. User's manual step still outstanding (needs interactive sudo, cannot be done via agent): CUPS purge commands provided earlier in session.
|
| 352 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 350 |
3. Begin replacing the 14 stub files' placeholder logic with real implementations per `wo-conversational-intelligence` and `wo-model-forge` design docs — starting with the two non-negotiable invariant modules: `autonomy_calibration.rs` and `partnership_tracker.rs`.
|
| 351 |
4. User's manual step still outstanding (needs interactive sudo, cannot be done via agent): CUPS purge commands provided earlier in session.
|
| 352 |
|
| 353 |
+
|
| 354 |
+
---
|
| 355 |
+
|
| 356 |
+
## Session Status Update — Sep 4, 2026, 10:15 CDT — ALL TESTS PASSING
|
| 357 |
+
|
| 358 |
+
### Verified via real test run: 164 passed, 0 failed, 2 ignored (`cargo test -p miranda-nodes`)
|
| 359 |
+
|
| 360 |
+
Two real bugs found and fixed after the build cleared:
|
| 361 |
+
|
| 362 |
+
1. **`duckdb_writer.rs`** — `duckdb-rs` 1.10505.0 does not support binding native `LIST` parameters (confirmed by tracing the panic to `ToSqlConversionFailure("binding List parameters is not yet supported")` in the driver source). Fixed by storing the `entities` and `mood_contexts` columns as JSON-encoded `VARCHAR` instead of DuckDB `VARCHAR[]`, serialized/deserialized with `serde_json`. Schema updated in both the test's inline schema and the real `scripts/duckdb-init.sh`.
|
| 363 |
+
2. **`neo4j_writer.rs`** — the `exhausts_retries_against_unreachable_host` test asserted `connect().await.is_err()`, but `neo4rs::Graph::new` pools connections lazily and does not fail at connect time against a closed port. Rewrote the test to actually exercise `write_conversation`'s retry loop (3 retries, 5ms backoff) and assert `Neo4jError::RetriesExhausted { attempts: 3, .. }` — this is the real behavior the module needs to guarantee per design.md's error-handling contract (JSONL log is source of truth if graph writes are exhausted).
|
| 364 |
+
|
| 365 |
+
Both fixes verified with real `cargo test` output, not code-review confidence.
|
| 366 |
+
|
| 367 |
+
### Verified test coverage includes
|
| 368 |
+
- Memory: mood classifier (latency + accuracy), neo4j writer (schema shape + real retry exhaustion), duckdb writer (real temp-DB round trip)
|
| 369 |
+
- Conversation: solver (SIMD blendshape/viseme DSP — 20+ tests covering additivity, attack/release timing, band selectivity, determinism, autonomic-channel isolation), viseme mapping, 60Hz dispatcher cadence
|
| 370 |
+
- Real-time verification: `tests/rt_verification.rs` — 60fps acceptance criteria against a real shared-memory bus, velocity clamping on frames read back from shm
|
| 371 |
+
|
| 372 |
+
### Next Steps
|
| 373 |
+
1. `cargo build --workspace` to confirm no other crate broke.
|
| 374 |
+
2. Begin real implementations for the 14 stub files (currently placeholders), starting with `autonomy_calibration.rs` and `partnership_tracker.rs` (the two non-negotiable invariant modules).
|
| 375 |
+
3. User's outstanding manual step: CUPS purge (needs interactive sudo, commands provided earlier).
|
| 376 |
+
|
miranda-nodes/src/memory/duckdb_writer.rs
CHANGED
|
@@ -12,7 +12,7 @@
|
|
| 12 |
//! rather than held open across awaits here.
|
| 13 |
|
| 14 |
use chrono::{DateTime, Utc};
|
| 15 |
-
use duckdb::{params, Connection
|
| 16 |
|
| 17 |
use super::entity_extractor::Entity;
|
| 18 |
use super::mood_classifier::MoodState;
|
|
@@ -56,7 +56,12 @@ impl DuckDbWriter {
|
|
| 56 |
let conn = self.connect()?;
|
| 57 |
|
| 58 |
let entity_names: Vec<String> = entities.iter().map(|e| e.entity_name.clone()).collect();
|
| 59 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 60 |
|
| 61 |
conn.execute(
|
| 62 |
"INSERT INTO events (event_id, timestamp, event_type, user_message, \
|
|
@@ -69,7 +74,7 @@ impl DuckDbWriter {
|
|
| 69 |
event_type,
|
| 70 |
user_message,
|
| 71 |
miranda_response,
|
| 72 |
-
|
| 73 |
mood_state.as_str(),
|
| 74 |
mood_state.color_hex(),
|
| 75 |
Option::<String>::None,
|
|
@@ -89,7 +94,8 @@ impl DuckDbWriter {
|
|
| 89 |
entity.entity_type.as_str(),
|
| 90 |
timestamp.to_rfc3339(),
|
| 91 |
timestamp.to_rfc3339(),
|
| 92 |
-
|
|
|
|
| 93 |
],
|
| 94 |
)?;
|
| 95 |
}
|
|
@@ -139,7 +145,7 @@ mod tests {
|
|
| 139 |
event_type VARCHAR NOT NULL,
|
| 140 |
user_message VARCHAR NOT NULL,
|
| 141 |
miranda_response VARCHAR NOT NULL,
|
| 142 |
-
entities VARCHAR
|
| 143 |
mood_state VARCHAR NOT NULL,
|
| 144 |
mood_rgb VARCHAR,
|
| 145 |
mood_hsl VARCHAR
|
|
@@ -150,7 +156,7 @@ mod tests {
|
|
| 150 |
first_mention TIMESTAMP NOT NULL,
|
| 151 |
last_mention TIMESTAMP NOT NULL,
|
| 152 |
mention_count INTEGER NOT NULL DEFAULT 1,
|
| 153 |
-
mood_contexts VARCHAR
|
| 154 |
PRIMARY KEY (entity_name, entity_type)
|
| 155 |
);",
|
| 156 |
)
|
|
|
|
| 12 |
//! rather than held open across awaits here.
|
| 13 |
|
| 14 |
use chrono::{DateTime, Utc};
|
| 15 |
+
use duckdb::{params, Connection};
|
| 16 |
|
| 17 |
use super::entity_extractor::Entity;
|
| 18 |
use super::mood_classifier::MoodState;
|
|
|
|
| 56 |
let conn = self.connect()?;
|
| 57 |
|
| 58 |
let entity_names: Vec<String> = entities.iter().map(|e| e.entity_name.clone()).collect();
|
| 59 |
+
// duckdb-rs does not yet support binding native LIST parameters
|
| 60 |
+
// (`ToSqlConversionFailure("binding List parameters is not yet
|
| 61 |
+
// supported")`), so list columns are stored as JSON-encoded
|
| 62 |
+
// VARCHAR instead of DuckDB VARCHAR[] and decoded on read.
|
| 63 |
+
let entity_names_json =
|
| 64 |
+
serde_json::to_string(&entity_names).unwrap_or_else(|_| "[]".to_string());
|
| 65 |
|
| 66 |
conn.execute(
|
| 67 |
"INSERT INTO events (event_id, timestamp, event_type, user_message, \
|
|
|
|
| 74 |
event_type,
|
| 75 |
user_message,
|
| 76 |
miranda_response,
|
| 77 |
+
entity_names_json,
|
| 78 |
mood_state.as_str(),
|
| 79 |
mood_state.color_hex(),
|
| 80 |
Option::<String>::None,
|
|
|
|
| 94 |
entity.entity_type.as_str(),
|
| 95 |
timestamp.to_rfc3339(),
|
| 96 |
timestamp.to_rfc3339(),
|
| 97 |
+
serde_json::to_string(&vec![mood_state.as_str().to_string()])
|
| 98 |
+
.unwrap_or_else(|_| "[]".to_string()),
|
| 99 |
],
|
| 100 |
)?;
|
| 101 |
}
|
|
|
|
| 145 |
event_type VARCHAR NOT NULL,
|
| 146 |
user_message VARCHAR NOT NULL,
|
| 147 |
miranda_response VARCHAR NOT NULL,
|
| 148 |
+
entities VARCHAR,
|
| 149 |
mood_state VARCHAR NOT NULL,
|
| 150 |
mood_rgb VARCHAR,
|
| 151 |
mood_hsl VARCHAR
|
|
|
|
| 156 |
first_mention TIMESTAMP NOT NULL,
|
| 157 |
last_mention TIMESTAMP NOT NULL,
|
| 158 |
mention_count INTEGER NOT NULL DEFAULT 1,
|
| 159 |
+
mood_contexts VARCHAR,
|
| 160 |
PRIMARY KEY (entity_name, entity_type)
|
| 161 |
);",
|
| 162 |
)
|
miranda-nodes/src/memory/neo4j_writer.rs
CHANGED
|
@@ -264,15 +264,34 @@ mod tests {
|
|
| 264 |
}
|
| 265 |
|
| 266 |
/// Real integration test exercising retry-with-backoff against a
|
| 267 |
-
/// deliberately unreachable Bolt address
|
| 268 |
-
///
|
|
|
|
|
|
|
|
|
|
| 269 |
/// silently succeeding.
|
| 270 |
#[tokio::test]
|
| 271 |
async fn exhausts_retries_against_unreachable_host() {
|
| 272 |
-
let
|
| 273 |
-
|
| 274 |
-
|
| 275 |
-
|
| 276 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 277 |
}
|
| 278 |
}
|
|
|
|
| 264 |
}
|
| 265 |
|
| 266 |
/// Real integration test exercising retry-with-backoff against a
|
| 267 |
+
/// deliberately unreachable Bolt address. `neo4rs::Graph::new` pools
|
| 268 |
+
/// connections lazily, so `connect()` itself succeeds even against a
|
| 269 |
+
/// closed port; the actual failure only surfaces once a query is
|
| 270 |
+
/// attempted. This verifies `write_conversation`'s retry loop runs to
|
| 271 |
+
/// `max_retries` and returns `RetriesExhausted` instead of hanging or
|
| 272 |
/// silently succeeding.
|
| 273 |
#[tokio::test]
|
| 274 |
async fn exhausts_retries_against_unreachable_host() {
|
| 275 |
+
let writer = Neo4jWriter::connect("bolt://127.0.0.1:1", "neo4j", "mirandamemory")
|
| 276 |
+
.await
|
| 277 |
+
.expect("Graph::new pools lazily and should not fail before a query is run")
|
| 278 |
+
.with_retry_policy(3, Duration::from_millis(5));
|
| 279 |
+
|
| 280 |
+
let entities: Vec<Entity> = Vec::new();
|
| 281 |
+
let record = ConversationRecord {
|
| 282 |
+
conversation_id: uuid::Uuid::new_v4(),
|
| 283 |
+
timestamp: Utc::now(),
|
| 284 |
+
user_message: "unreachable host test",
|
| 285 |
+
miranda_response: "n/a",
|
| 286 |
+
mood_state: MoodState::Curiosity,
|
| 287 |
+
intimacy_level: None,
|
| 288 |
+
entities: &entities,
|
| 289 |
+
};
|
| 290 |
+
|
| 291 |
+
let result = writer.write_conversation(&record).await;
|
| 292 |
+
match result {
|
| 293 |
+
Err(Neo4jError::RetriesExhausted { attempts, .. }) => assert_eq!(attempts, 3),
|
| 294 |
+
other => panic!("expected RetriesExhausted after 3 attempts, got {other:?}"),
|
| 295 |
+
}
|
| 296 |
}
|
| 297 |
}
|
scripts/duckdb-init.sh
CHANGED
|
@@ -27,7 +27,7 @@ CREATE TABLE IF NOT EXISTS events (
|
|
| 27 |
event_type VARCHAR NOT NULL,
|
| 28 |
user_message VARCHAR NOT NULL,
|
| 29 |
miranda_response VARCHAR NOT NULL,
|
| 30 |
-
entities VARCHAR
|
| 31 |
mood_state VARCHAR NOT NULL,
|
| 32 |
mood_rgb VARCHAR,
|
| 33 |
mood_hsl VARCHAR
|
|
@@ -39,7 +39,7 @@ CREATE TABLE IF NOT EXISTS entities (
|
|
| 39 |
first_mention TIMESTAMP NOT NULL,
|
| 40 |
last_mention TIMESTAMP NOT NULL,
|
| 41 |
mention_count INTEGER NOT NULL DEFAULT 1,
|
| 42 |
-
mood_contexts VARCHAR
|
| 43 |
PRIMARY KEY (entity_name, entity_type)
|
| 44 |
);
|
| 45 |
|
|
|
|
| 27 |
event_type VARCHAR NOT NULL,
|
| 28 |
user_message VARCHAR NOT NULL,
|
| 29 |
miranda_response VARCHAR NOT NULL,
|
| 30 |
+
entities VARCHAR,
|
| 31 |
mood_state VARCHAR NOT NULL,
|
| 32 |
mood_rgb VARCHAR,
|
| 33 |
mood_hsl VARCHAR
|
|
|
|
| 39 |
first_mention TIMESTAMP NOT NULL,
|
| 40 |
last_mention TIMESTAMP NOT NULL,
|
| 41 |
mention_count INTEGER NOT NULL DEFAULT 1,
|
| 42 |
+
mood_contexts VARCHAR,
|
| 43 |
PRIMARY KEY (entity_name, entity_type)
|
| 44 |
);
|
| 45 |
|