diff --git a/docs/coding-agent/lessons.md b/docs/coding-agent/lessons.md index 9f129db..a17a931 100644 --- a/docs/coding-agent/lessons.md +++ b/docs/coding-agent/lessons.md @@ -21,6 +21,28 @@ Purpose: ## Entries +## 2026-07-04 - Evidence Greps Must Match The Syntactic Class Being Ruled Out [tags: validation, grep-evidence] + +Context: +- Plan: lint-suppression cleanup +- Task/Wave: Task_1 acceptance check +- Roles involved: Worker | Orchestrator + +Symptom: +- Both the Orchestrator's inventory grep and the Worker's done-evidence grep for module-wide allows matched only single-lint forms (`allow(dead_code)`), missing two combined-form sites (`#![allow(dead_code, unused_imports)]`) — the task was reported done with its acceptance criterion unmet. + +Root cause: +- The regex encoded the expected spelling of the attribute, not the syntactic class being ruled out. + +Fix applied: +- Addendum cleaned the two missed files; completion evidence switched to `rg '^#!\[allow' src -n`, which matches every module-wide allow regardless of lint list. + +Prevention: +- When acceptance is "no X remains", the evidence grep must match the broadest syntactic form of X (then narrower greps may summarize permitted exceptions). Encode the class, not the expected spelling. + +Evidence: +- Task_1 report grep showed clean; Orchestrator's independent broad grep found embedded.rs/shared.rs; addendum report + corrected grep confirm only the two permitted files remain. + ## 2026-07-04 - Verify Skip-Gating Predicate Branches Against What The Producer Actually Emits [tags: validation, review] Context: diff --git a/docs/coding-agent/plans/completed/lint-suppression-cleanup-plan.md b/docs/coding-agent/plans/completed/lint-suppression-cleanup-plan.md new file mode 100644 index 0000000..485fe84 --- /dev/null +++ b/docs/coding-agent/plans/completed/lint-suppression-cleanup-plan.md @@ -0,0 +1,104 @@ +# Plan: Remove or justify blanket lint suppressions + +- status: done (Reviewer APPROVED 2026-07-04, zero findings) +- generated: 2026-07-04 +- last_updated: 2026-07-04 +- work_type: code + +## Goal + +- Eliminate module-wide `#![allow(unused_imports)]` and `#![allow(dead_code)]` suppressions so the compiler can see rot again; every surviving allow is item-level with a rationale comment (per repo lessons "Explain Temporary Suppressions" and "Prefer Root-Cause Fixes Over Symptom Patches"). + +## Definition of Done + +- No module-wide (`#![allow(...)]`) lint suppressions remain in `src/` except where a documented structural reason survives review (expected: `test_support.rs`, possibly `reconciliation.rs`). +- Every remaining `#[allow(dead_code)]`/`#[allow(unused_imports)]` is item-level and carries a rationale + removal-condition comment. +- Genuinely dead code is deleted; unused imports removed. +- `cargo fmt --check`, `cargo check`, `cargo clippy --all-targets -- -D warnings`, `cargo test --no-run`, `cargo test` all pass. + +## Scope / Non-goals + +- Scope: the 26 inventoried suppression sites (2 unused_imports module-wide, 12 dead_code module-wide, 12 item/statement-level) and the code they hide. +- Non-goals: behavior changes; API additions; restructuring (the reorg is done); deleting roadmap-intended API surface. + +## Context (workspace) + +- Research: Task_9 review + post-completion architecture audit flagged these as rot-masking debt (debt items #8, #11-adjacent in the completed reorg plan's register). Inventory grep run 2026-07-04 (26 sites). Research dispatch waived: inventory is mechanical and prior audit context is fresh. +- Key judgment rule: ports/, models/, api DTO families contain deliberately pre-built surface for roadmap phases — for items unused today but API-shaped (pub(crate) types, trait methods, builders), NARROW the allow to the item with a rationale, do not delete. Delete only provably dead internals (private helpers with no callers, stale imports). +- Known-special sites: `src/test_support.rs` (shared fakes: different tests use different subsets — module-wide allow is structurally justified, keep with comment); `src/usecases/reconciliation.rs` (internal seam pending a governance surface per its own comments — narrow or keep with explicit rationale); `src/policy/graph_expansion.rs:20` (audit explicitly wants this narrowed). + +## Open Questions (max 3) + +- None. + +## Assumptions + +- A1: The compiler/clippy under `-D warnings` is the arbiter for what each removal exposes; the worker iterates per file. +- A2: Local full `cargo test` is currently viable (machine stall condition cleared 2026-07-04). + +## Tasks + +### Task_1: Remove/narrow all blanket suppressions and clean exposed rot +- type: impl +- owns: + - src/** (suppression attributes, unused imports, dead private code, rationale comments only — no logic changes) +- depends_on: [] +- description: | + For each inventoried site: remove the module-wide allow; run cargo clippy --all-targets -- -D warnings; + triage each exposed warning: (a) delete unused imports; (b) delete provably dead PRIVATE code; + (c) for API-shaped or roadmap-intended items, add item-level #[allow(dead_code)] with a one-line + rationale + removal condition; (d) for test_support.rs (and reconciliation.rs if narrowing is + impractical) keep a module-wide allow with an explanatory comment. Report per-site outcomes + (removed / narrowed / kept-with-comment, and lines of dead code deleted). +- acceptance: + - Zero undocumented module-wide allows in src/ + - All surviving allows are item-level (or documented module-level exceptions) with rationale comments + - No logic/behavior changes; test counts unchanged or reduced only by deleted dead test helpers +- validation: + - kind: command + required: true + owner: worker + detail: "cargo fmt --check && cargo check && cargo clippy --all-targets -- -D warnings && cargo test --no-run && cargo test" + +### Task_2: Independent review +- type: review +- owns: [] +- depends_on: [Task_1] +- description: | + Reviewer verifies: no deleted item was roadmap-intended API surface (spot-check deletions against + ports/models/api families); surviving allows have honest rationales; validation evidence complete. +- acceptance: + - Reviewer status APPROVED +- validation: + - kind: review + required: true + owner: reviewer + detail: "Diff review vs acceptance criteria + deletion-safety spot check" + +## Task Waves (explicit parallel dispatch sets) + +- Wave 1: [Task_1] +- Wave 2: [Task_2] + +## Rollback / Safety + +- Single-purpose branch refactor/lint-suppression-cleanup off merged main; pure-cleanup commit, trivially revertible. + +## Progress Log (append-only) + +- 2026-07-04: Plan drafted from suppression inventory (26 sites) + reorg audit debt register. +- 2026-07-04 Wave 1 completed: [Task_1 + addendum] (codex worker via agmsg) + - Summary: all module-wide suppressions removed except the two documented exceptions (test_support.rs shared fakes, reconciliation.rs dormant governance seam, both with rationale + removal conditions); API-shaped dormant seams narrowed to item-level allows with rationale/removal comments; unused imports cleaned; 19 lines of provably dead private helpers deleted (embedded.rs insert_quads/remove_quads, shared.rs graph_object_ref). Inventory gap: two combined-form allows (embedded.rs, shared.rs) were missed by both the plan inventory grep and the worker's done-evidence grep — caught by Orchestrator broad grep, fixed via addendum; lesson recorded. + - Validation evidence: fmt --check / check / clippy --all-targets -D warnings / test --no-run / FULL cargo test all pass twice (main pass + addendum): 338 lib + 25 integration passed, 0 failed, 3 ignored live smokes. Orchestrator independent broad grep + clippy pass. + - Notes: one attempted Qdrant constant deletion was self-reverted when all-target clippy showed test ownership — deletion-safety rule worked. +- 2026-07-04 Wave 2 completed: [Task_2] + - Reviewer verdict: APPROVED, zero findings. Independently confirmed: the three deleted helpers have zero callers on main (including tests) and no roadmap/doc references; only the two sanctioned module-wide allows remain (tests/ also clean); cfg_attr(not(test), allow(dead_code)) correctly applied to test-asserted items; diff contains no logic changes; fmt/clippy/test --no-run/test --lib pass independently. + - Non-blocking next-touch note: candidate_record.rs "test fixtures use selectively" allows could adopt the self-policing cfg_attr(not(test)) form. + +## Decision Log (append-only; re-plans and major discoveries) + +- 2026-07-04 Decision: Deletion-safety rule — API-shaped/roadmap-intended items get narrowed allows with rationale, never deletion; only provably dead private internals are removed. + +## Notes + +- Risks: deleting something a service-gated integration path uses (mitigated: full cargo test now runs locally); allow removal cascading into large diffs in ports/models (mitigated: narrowing is always available). diff --git a/src/adapters.rs b/src/adapters.rs index 9be68db..20ff3e3 100644 --- a/src/adapters.rs +++ b/src/adapters.rs @@ -1,14 +1,18 @@ -#![allow(unused_imports)] - pub(crate) mod openai; pub(crate) mod oxigraph; pub(crate) mod qdrant; pub(crate) mod stats; pub(crate) use openai::OpenAIEmbeddingProvider; +// Composition modes may select either graph adapter; remove when both are referenced in every target. +#[allow(unused_imports)] pub(crate) use oxigraph::{OxigraphGraphAuthorityStore, OxigraphHttpGraphAuthorityStore}; pub(crate) use qdrant::QdrantVectorCandidateStore; +// Stats adapters are selected by composition/tests in different target sets; remove when target use converges. +#[allow(unused_imports)] pub(crate) use stats::{InMemoryRetrievalStatsStore, SqliteRetrievalStatsStore}; #[cfg(test)] +// Unit tests share this adapter through the barrel selectively; remove when tests import stats:: directly. +#[allow(unused_imports)] pub(crate) use stats::noop_retrieval_stats_store; diff --git a/src/adapters/oxigraph/embedded.rs b/src/adapters/oxigraph/embedded.rs index 1ce0a71..99a6d60 100644 --- a/src/adapters/oxigraph/embedded.rs +++ b/src/adapters/oxigraph/embedded.rs @@ -1,37 +1,29 @@ -#![allow(dead_code, unused_imports)] - use std::collections::{HashMap, HashSet}; use std::fs; use std::path::Path; -use std::sync::{Mutex, MutexGuard}; +use std::sync::Mutex; use async_trait::async_trait; -use chrono::{DateTime, Utc}; -use oxigraph::model::{GraphName, Literal, NamedNode, NamedOrBlankNode, Quad, Term}; +use oxigraph::model::{GraphName, NamedNode, Quad}; +#[cfg(test)] +use oxigraph::model::{Literal, NamedOrBlankNode, Term}; use oxigraph::store::Store; -use serde::{de::DeserializeOwned, Deserialize}; -use crate::api::types::{ - graph_uri, DerivedMemory, Entity, Episode, MemoryId, MemoryLink, MemoryObject, MemoryThread, - ObjectType, Observation, RelationType, -}; +use crate::api::types::{graph_uri, DerivedMemory, MemoryLink, MemoryObject, ObjectType}; use crate::errors::CustomError; use crate::policy::graph_expansion::{ bounded_expansion, derived_memories_by_provenance, derived_memories_by_thread, }; -use crate::policy::graph_expansion::{ - bounded_incident_link_refs, graph_expansion_bounded_error, BoundedExpansionLinkRef, -}; use crate::ports::graph_authority::{ GraphAuthorityStore, GraphDerivedMemoryProvenanceQuery, GraphDerivedMemoryThreadQuery, - GraphExpansion, GraphExpansionBoundedFailure, GraphExpansionBoundedFailureReason, - GraphExpansionQuery, GraphObjectQuery, GraphObjectRef, + GraphExpansion, GraphExpansionQuery, GraphObjectQuery, GraphObjectRef, }; -use super::rdf_mapping::{rdf_triples_for_link, rdf_triples_for_object, RdfObject, RdfTriple}; +#[cfg(test)] +use super::rdf_mapping::RdfObject; +use super::rdf_mapping::{rdf_triples_for_link, rdf_triples_for_object, RdfTriple}; use super::shared::*; -use super::sparql_selectors::{SparqlGraphSelectors, SparqlLinkRef}; -use super::vocabulary as vocab; +use super::sparql_selectors::SparqlGraphSelectors; pub(crate) struct OxigraphGraphAuthorityStore { pub(crate) store: Store, @@ -67,10 +59,14 @@ impl OxigraphGraphAuthorityStore { }) } + // Embedded adapter tests assert graph mutation counts; remove when tests assert via graph queries only. + #[cfg_attr(not(test), allow(dead_code))] pub(crate) fn triple_count(&self) -> Result { Ok(self.store.iter().count()) } + // Embedded adapter tests simulate graph corruption directly; remove when those tests use public writes only. + #[cfg_attr(not(test), allow(dead_code))] pub(crate) fn replace_triples( &self, owner_graph_uri: String, @@ -112,20 +108,6 @@ impl OxigraphGraphAuthorityStore { Ok(()) } - fn insert_quads(&self, quads: &[Quad]) -> Result<(), CustomError> { - for quad in quads { - self.store.insert(quad).map_err(oxigraph_error)?; - } - Ok(()) - } - - fn remove_quads(&self, quads: &[Quad]) -> Result<(), CustomError> { - for quad in quads { - self.store.remove(quad).map_err(oxigraph_error)?; - } - Ok(()) - } - fn quads_in_graph(&self, owner_graph_uri: &str) -> Result, CustomError> { let graph_name = GraphName::NamedNode(NamedNode::new(owner_graph_uri)?); self.store diff --git a/src/adapters/oxigraph/http.rs b/src/adapters/oxigraph/http.rs index 54f38a9..5016ffd 100644 --- a/src/adapters/oxigraph/http.rs +++ b/src/adapters/oxigraph/http.rs @@ -1,36 +1,24 @@ -#![allow(unused_imports)] - -use std::collections::{HashMap, HashSet}; -use std::fs; -use std::path::Path; -use std::sync::{Mutex, MutexGuard}; +use std::collections::HashSet; use async_trait::async_trait; -use chrono::{DateTime, Utc}; -use oxigraph::model::{GraphName, Literal, NamedNode, NamedOrBlankNode, Quad, Term}; +use oxigraph::model::Quad; use oxigraph::store::Store; -use serde::{de::DeserializeOwned, Deserialize}; use crate::api::types::{ - graph_uri, DerivedMemory, Entity, Episode, MemoryId, MemoryLink, MemoryObject, MemoryThread, - ObjectType, Observation, RelationType, + graph_uri, DerivedMemory, MemoryId, MemoryLink, MemoryObject, ObjectType, RelationType, }; use crate::errors::CustomError; use crate::policy::graph_expansion::{ bounded_expansion, derived_memories_by_provenance, derived_memories_by_thread, }; -use crate::policy::graph_expansion::{ - bounded_incident_link_refs, graph_expansion_bounded_error, BoundedExpansionLinkRef, -}; +use crate::policy::graph_expansion::{bounded_incident_link_refs, BoundedExpansionLinkRef}; use crate::ports::graph_authority::{ GraphAuthorityStore, GraphDerivedMemoryProvenanceQuery, GraphDerivedMemoryThreadQuery, - GraphExpansion, GraphExpansionBoundedFailure, GraphExpansionBoundedFailureReason, - GraphExpansionQuery, GraphObjectQuery, GraphObjectRef, + GraphExpansion, GraphExpansionQuery, GraphObjectQuery, GraphObjectRef, }; -use super::rdf_mapping::{rdf_triples_for_link, rdf_triples_for_object, RdfObject, RdfTriple}; +use super::rdf_mapping::{rdf_triples_for_link, rdf_triples_for_object}; use super::shared::*; -use super::sparql_selectors::{SparqlGraphSelectors, SparqlLinkRef}; use super::vocabulary as vocab; pub(crate) struct OxigraphHttpGraphAuthorityStore { diff --git a/src/adapters/oxigraph/rdf_mapping.rs b/src/adapters/oxigraph/rdf_mapping.rs index 18d3c87..ba8aba8 100644 --- a/src/adapters/oxigraph/rdf_mapping.rs +++ b/src/adapters/oxigraph/rdf_mapping.rs @@ -1,7 +1,5 @@ // RDF mapping surface. Public domain objects stay independent from // Oxigraph types. -#![allow(dead_code)] - use chrono::{DateTime, SecondsFormat, Utc}; use serde::Serialize; diff --git a/src/adapters/oxigraph/shared.rs b/src/adapters/oxigraph/shared.rs index 5d4d48c..ff12dcb 100644 --- a/src/adapters/oxigraph/shared.rs +++ b/src/adapters/oxigraph/shared.rs @@ -1,11 +1,6 @@ -#![allow(dead_code, unused_imports)] - use std::collections::{HashMap, HashSet}; -use std::fs; -use std::path::Path; use std::sync::{Mutex, MutexGuard}; -use async_trait::async_trait; use chrono::{DateTime, Utc}; use oxigraph::model::{GraphName, Literal, NamedNode, NamedOrBlankNode, Quad, Term}; use oxigraph::store::Store; @@ -16,19 +11,15 @@ use crate::api::types::{ ObjectType, Observation, RelationType, }; use crate::errors::CustomError; -use crate::policy::graph_expansion::{ - bounded_expansion, derived_memories_by_provenance, derived_memories_by_thread, -}; use crate::policy::graph_expansion::{ bounded_incident_link_refs, graph_expansion_bounded_error, BoundedExpansionLinkRef, }; use crate::ports::graph_authority::{ - GraphAuthorityStore, GraphDerivedMemoryProvenanceQuery, GraphDerivedMemoryThreadQuery, - GraphExpansion, GraphExpansionBoundedFailure, GraphExpansionBoundedFailureReason, - GraphExpansionQuery, GraphObjectQuery, GraphObjectRef, + GraphExpansionBoundedFailure, GraphExpansionBoundedFailureReason, GraphExpansionQuery, + GraphObjectQuery, GraphObjectRef, }; -use super::rdf_mapping::{rdf_triples_for_link, rdf_triples_for_object, RdfObject, RdfTriple}; +use super::rdf_mapping::{RdfObject, RdfTriple}; use super::sparql_selectors::{SparqlGraphSelectors, SparqlLinkRef}; use super::vocabulary as vocab; impl BoundedExpansionLinkRef for SparqlLinkRef { @@ -412,6 +403,8 @@ pub(super) struct SparqlBinding { #[serde(rename = "type")] kind: String, pub(super) value: String, + // SPARQL JSON includes datatype metadata for literals; remove if parsing no longer preserves literal metadata. + #[allow(dead_code)] datatype: Option, } @@ -965,11 +958,6 @@ pub(super) fn bounded_graph_visible_refs( }) } -pub(super) fn graph_object_ref(object: &MemoryObject) -> GraphObjectRef { - let (object_id, object_type) = object_identity(object); - GraphObjectRef::new(object_id, object_type) -} - pub(super) fn quad_for_triple( owner_graph_uri: &str, triple: &RdfTriple, diff --git a/src/adapters/oxigraph/sparql_selectors.rs b/src/adapters/oxigraph/sparql_selectors.rs index 07fc97d..e972e14 100644 --- a/src/adapters/oxigraph/sparql_selectors.rs +++ b/src/adapters/oxigraph/sparql_selectors.rs @@ -1,7 +1,5 @@ // Internal SPARQL selectors for the embedded Oxigraph authority. These helpers // return backend-neutral IDs/refs; canonical object hydration reads RDF state. -#![allow(dead_code)] - use std::collections::HashSet; use oxigraph::model::Term; @@ -32,6 +30,8 @@ pub(crate) struct SparqlLinkRef { } #[derive(Debug, Clone, Copy, PartialEq, Eq)] +// Lifecycle predicate metadata is reserved for governance diagnostics; remove if lifecycle SPARQL inspection is retired. +#[allow(dead_code)] pub(crate) struct LifecycleCurrentnessPredicates { pub(crate) retention_state: &'static str, pub(crate) is_current: &'static str, @@ -160,6 +160,8 @@ impl<'a> SparqlGraphSelectors<'a> { ) } + // Entity-scoped derived-memory selectors are reserved for governance diagnostics; remove if that surface drops entity filters. + #[allow(dead_code)] pub(crate) fn select_derived_memories_by_entity( &self, entity_ids: &[MemoryId], @@ -181,6 +183,8 @@ impl<'a> SparqlGraphSelectors<'a> { ) } + // Lifecycle predicate metadata is reserved for governance diagnostics; remove if lifecycle SPARQL inspection is retired. + #[allow(dead_code)] pub(crate) const fn lifecycle_currentness_predicates() -> LifecycleCurrentnessPredicates { LifecycleCurrentnessPredicates { retention_state: vocab::RETENTION_STATE, @@ -191,6 +195,8 @@ impl<'a> SparqlGraphSelectors<'a> { } } + // Supersession selectors are reserved for governance diagnostics; remove if lifecycle reconciliation stops using SPARQL. + #[allow(dead_code)] pub(crate) fn select_superseded_derived_memory_ids( &self, ) -> Result, CustomError> { diff --git a/src/adapters/oxigraph/tests.rs b/src/adapters/oxigraph/tests.rs index 320fc70..f8adb17 100644 --- a/src/adapters/oxigraph/tests.rs +++ b/src/adapters/oxigraph/tests.rs @@ -4,17 +4,13 @@ mod tests { use super::super::embedded::*; use super::super::http::*; - use super::super::rdf_mapping::{ - rdf_triples_for_link, rdf_triples_for_object, RdfObject, RdfTriple, - }; + use super::super::rdf_mapping::{rdf_triples_for_object, RdfObject, RdfTriple}; use super::super::shared::*; use super::super::sparql_selectors::SparqlGraphSelectors; use super::super::vocabulary as vocab; - use super::super::*; use crate::api::types::{ graph_uri, ContextPackSection, LifecycleFilterAction, LifecycleFilterReason, MemoryId, - MemoryLink, MemoryObject, ObjectType, RelationType, RetentionState, RetrievalContext, - ThreadStatus, + MemoryObject, ObjectType, RelationType, RetentionState, RetrievalContext, ThreadStatus, }; use crate::models::vector::{ EmbeddingInput, VectorCandidateMatch, VectorCandidateSearch, VectorRecordEmbedding, diff --git a/src/adapters/oxigraph/vocabulary.rs b/src/adapters/oxigraph/vocabulary.rs index a7b1b65..227d0a6 100644 --- a/src/adapters/oxigraph/vocabulary.rs +++ b/src/adapters/oxigraph/vocabulary.rs @@ -54,6 +54,8 @@ pub(crate) const TO: &str = "urn:cmem:vocab:to"; pub(crate) const TO_TYPE: &str = "urn:cmem:vocab:toType"; pub(crate) const RELATION: &str = "urn:cmem:vocab:relation"; pub(crate) const RATIONALE: &str = "urn:cmem:vocab:rationale"; +// Supersession vocabulary is reserved for lifecycle diagnostics; remove if supersedes relations are retired. +#[allow(dead_code)] pub(crate) const RELATION_SUPERSEDES: &str = "urn:cmem:relation:supersedes"; pub(crate) fn relation_predicate(name: &str) -> String { diff --git a/src/adapters/qdrant/payload.rs b/src/adapters/qdrant/payload.rs index 823cb1c..81a9b86 100644 --- a/src/adapters/qdrant/payload.rs +++ b/src/adapters/qdrant/payload.rs @@ -1,7 +1,5 @@ // Qdrant payload mapping. These fields are denormalized candidate // recall/filter hints, not graph authority. -#![allow(dead_code)] - use chrono::{DateTime, SecondsFormat, Utc}; use qdrant_client::qdrant::FieldType; use serde::Serialize; @@ -10,9 +8,6 @@ use crate::domain::schema::require_current_schema_version; use crate::errors::CustomError; use crate::models::vector::{VectorRecord, VectorSurface}; -pub(crate) const GRAPH_AUTHORITY_NOTE: &str = - "Qdrant relationship ID fields are denormalized filter hints only; GraphAuthorityStore remains authoritative for relationships, provenance, lifecycle, currentness, and graph expansion."; - pub(crate) const OBJECT_ID_FIELD: &str = "object_id"; pub(crate) const GRAPH_URI_FIELD: &str = "graph_uri"; pub(crate) const OBJECT_TYPE_FIELD: &str = "object_type"; @@ -21,8 +16,6 @@ pub(crate) const DERIVED_TYPE_FIELD: &str = "derived_type"; pub(crate) const ENTITY_TYPE_FIELD: &str = "entity_type"; pub(crate) const THREAD_STATUS_FIELD: &str = "thread_status"; pub(crate) const SCHEMA_VERSION_FIELD: &str = "schema_version"; -pub(crate) const EMBEDDING_TEXT_FIELD: &str = "embedding_text"; -pub(crate) const CONTENT_TEXT_FIELD: &str = "content_text"; pub(crate) const SURFACE_FIELD: &str = "surface"; pub(crate) const RETENTION_STATE_FIELD: &str = "retention_state"; pub(crate) const IS_CURRENT_FIELD: &str = "is_current"; @@ -48,6 +41,17 @@ pub(crate) const CONFIDENCE_FIELD: &str = "confidence"; pub(crate) const STABILITY_FIELD: &str = "stability"; pub(crate) const RAW_REF_FIELD: &str = "raw_ref"; +// Graph-authority boundary note is asserted by all-target tests; remove when Qdrant owns graph truth. +#[cfg_attr(not(test), allow(dead_code))] +pub(crate) const GRAPH_AUTHORITY_NOTE: &str = + "Qdrant relationship ID fields are denormalized filter hints only; GraphAuthorityStore remains authoritative for relationships, provenance, lifecycle, currentness, and graph expansion."; +// Payload text keys are asserted by all-target tests; remove when payload no longer stores embedded/content text. +#[cfg_attr(not(test), allow(dead_code))] +pub(crate) const EMBEDDING_TEXT_FIELD: &str = "embedding_text"; +// Payload text keys are asserted by all-target tests; remove when payload no longer stores embedded/content text. +#[cfg_attr(not(test), allow(dead_code))] +pub(crate) const CONTENT_TEXT_FIELD: &str = "content_text"; + #[derive(Debug, Clone, PartialEq, Eq)] pub(crate) struct QdrantPayloadIndexField { pub(crate) name: &'static str, diff --git a/src/adapters/qdrant/store.rs b/src/adapters/qdrant/store.rs index 54b5c09..ade23cf 100644 --- a/src/adapters/qdrant/store.rs +++ b/src/adapters/qdrant/store.rs @@ -1,8 +1,6 @@ // Qdrant candidate-store adapter. Qdrant provides vector recall and // payload prefiltering; Oxigraph remains authoritative for graph/lifecycle // truth. -#![allow(dead_code)] - use std::{collections::HashMap, time::Duration}; use async_trait::async_trait; @@ -571,6 +569,8 @@ fn scored_point_to_match(point: ScoredPoint) -> Result Result { @@ -637,6 +637,8 @@ fn payload_string( } } +// Diagnostic payload parsing is dormant until reconciliation is wired; remove with list_candidate_diagnostics. +#[allow(dead_code)] fn optional_payload_string( payload: &HashMap, field: &str, @@ -647,6 +649,8 @@ fn optional_payload_string( } } +// Diagnostic payload parsing is dormant until reconciliation is wired; remove with list_candidate_diagnostics. +#[allow(dead_code)] fn optional_payload_bool( payload: &HashMap, field: &str, @@ -671,6 +675,8 @@ fn object_type_name(object_type: ObjectType) -> &'static str { } } +// Diagnostic sort order is dormant until reconciliation is wired; remove with list_candidate_diagnostics. +#[allow(dead_code)] fn object_type_rank(object_type: ObjectType) -> u8 { match object_type { ObjectType::Episode => 0, @@ -726,6 +732,8 @@ fn parse_object_type(value: String) -> Result { } } +// Diagnostic payload parsing is dormant until reconciliation is wired; remove with list_candidate_diagnostics. +#[allow(dead_code)] fn parse_retention_state(value: String) -> Result { match value.as_str() { "active" => Ok(crate::api::types::RetentionState::Active), diff --git a/src/adapters/stats/sqlite.rs b/src/adapters/stats/sqlite.rs index b551cd4..920b8ea 100644 --- a/src/adapters/stats/sqlite.rs +++ b/src/adapters/stats/sqlite.rs @@ -484,7 +484,6 @@ fn set_meta_value( Ok(()) } -#[allow(dead_code)] fn meta_value(connection: &Connection, key: &str) -> Result, CustomError> { connection .query_row( diff --git a/src/models/vector.rs b/src/models/vector.rs index e3757fa..2a15a83 100644 --- a/src/models/vector.rs +++ b/src/models/vector.rs @@ -4,6 +4,7 @@ mod record; // Provider-neutral vector model surface. Adapters, pipelines, and test // support intentionally consume different subsets of these helpers. +// Candidate query builders are used by adapter/test subsets; remove when all callers import concrete modules. #[allow(unused_imports)] pub(crate) use candidate_record::{ default_vector_candidate_object_types, EmbeddingInput, VectorCandidateFilters, @@ -11,6 +12,7 @@ pub(crate) use candidate_record::{ VectorTimeField, VectorTimeRangeFilter, }; pub(crate) use embedding_model::EmbeddingModel; +// Diagnostic/vector-record helpers are used by adapter/test subsets; remove when all callers import concrete modules. #[allow(unused_imports)] pub(crate) use record::{ VectorCandidateDiagnosticRecord, VectorPayloadHints, VectorRecord, VectorRecordEmbedding, diff --git a/src/models/vector/candidate_record.rs b/src/models/vector/candidate_record.rs index abdb5c7..b22aa44 100644 --- a/src/models/vector/candidate_record.rs +++ b/src/models/vector/candidate_record.rs @@ -1,7 +1,5 @@ // Vector candidate query surface. Some filters are exercised by live // adapters while deterministic tests use narrower subsets. -#![allow(dead_code)] - use chrono::{DateTime, Utc}; use crate::api::types::{default_retrieval_object_types, MemoryId, ObjectType, RetentionState}; @@ -42,6 +40,8 @@ impl EmbeddingInput { } #[derive(Debug, Clone, PartialEq)] +// Test fakes and diagnostics use candidate records selectively; remove when all vector stores expose diagnostics. +#[allow(dead_code)] pub(crate) struct VectorCandidateRecord { pub(crate) object_id: MemoryId, pub(crate) object_type: ObjectType, @@ -54,6 +54,8 @@ pub(crate) struct VectorCandidateRecord { } impl VectorCandidateRecord { + // Deterministic fakes build candidate records directly; remove when fakes use VectorRecord only. + #[allow(dead_code)] pub(crate) fn new( object_id: MemoryId, object_type: ObjectType, @@ -72,6 +74,8 @@ impl VectorCandidateRecord { } } + // Payload-filter fixtures use explicit hints; remove when fixture construction moves to VectorRecord. + #[allow(dead_code)] pub(crate) fn with_filter_hints( mut self, retention_state: Option, @@ -110,6 +114,8 @@ impl VectorCandidateSearch { self } + // Default recall scope is a convenience for tests and future callers; remove if all callers pass explicit types. + #[allow(dead_code)] pub(crate) fn with_default_object_types(mut self) -> Self { self.object_types = default_vector_candidate_object_types(); self @@ -121,6 +127,8 @@ impl VectorCandidateSearch { } } +// Default recall scope is retained for query-builder callers; remove if query builders stop exposing defaults. +#[allow(dead_code)] pub(crate) fn default_vector_candidate_object_types() -> Vec { default_retrieval_object_types() } @@ -141,11 +149,15 @@ impl VectorCandidateFilters { Self::default() } + // Lifecycle prefilter builders are used by adapter and fixture subsets; remove when all callers build filters directly. + #[allow(dead_code)] pub(crate) fn with_retention_states(mut self, retention_states: Vec) -> Self { self.retention_states = retention_states; self } + // Lifecycle prefilter builders are used by adapter and fixture subsets; remove when all callers build filters directly. + #[allow(dead_code)] pub(crate) fn current_only(mut self) -> Self { self.is_current = Some(true); self.is_superseded = Some(false); @@ -156,21 +168,29 @@ impl VectorCandidateFilters { self.is_current.is_some() || self.is_superseded.is_some() } + // Relationship prefilter builders are used by adapter and fixture subsets; remove when all callers build filters directly. + #[allow(dead_code)] pub(crate) fn with_thread_ids(mut self, thread_ids: Vec) -> Self { self.thread_ids = thread_ids; self } + // Relationship prefilter builders are used by adapter and fixture subsets; remove when all callers build filters directly. + #[allow(dead_code)] pub(crate) fn with_entity_ids(mut self, entity_ids: Vec) -> Self { self.entity_ids = entity_ids; self } + // Relationship prefilter builders are used by adapter and fixture subsets; remove when all callers build filters directly. + #[allow(dead_code)] pub(crate) fn with_episode_ids(mut self, episode_ids: Vec) -> Self { self.episode_ids = episode_ids; self } + // Time prefilter builders are used by adapter and fixture subsets; remove when all callers build filters directly. + #[allow(dead_code)] pub(crate) fn with_time_range(mut self, time_range: VectorTimeRangeFilter) -> Self { self.time_ranges.push(time_range); self @@ -185,6 +205,8 @@ pub(crate) struct VectorTimeRangeFilter { } impl VectorTimeRangeFilter { + // Time prefilter builders are used by adapter and fixture subsets; remove when all callers build ranges directly. + #[allow(dead_code)] pub(crate) fn new( field: VectorTimeField, after: Option>, @@ -199,6 +221,8 @@ impl VectorTimeRangeFilter { } #[derive(Debug, Clone, Copy, PartialEq, Eq)] +// The query model reserves all payload time fields; remove variants only with matching payload/index changes. +#[allow(dead_code)] pub(crate) enum VectorTimeField { Created, Updated, diff --git a/src/models/vector/record.rs b/src/models/vector/record.rs index f485b75..a7f2106 100644 --- a/src/models/vector/record.rs +++ b/src/models/vector/record.rs @@ -1,7 +1,5 @@ // Provider-neutral vector record surface. Payload hints remain // denormalized recall/filter hints; graph state stays authoritative. -#![allow(dead_code)] - use chrono::{DateTime, Utc}; use crate::api::types::{ @@ -18,6 +16,8 @@ pub(crate) struct VectorRecordEmbedding<'a> { } #[derive(Debug, Clone, PartialEq)] +// Diagnostic records back the vector-store diagnostics port; remove when that port is retired or called in production. +#[allow(dead_code)] pub(crate) struct VectorCandidateDiagnosticRecord { pub(crate) object_id: MemoryId, pub(crate) object_type: ObjectType, @@ -30,6 +30,8 @@ pub(crate) struct VectorCandidateDiagnosticRecord { } impl VectorCandidateDiagnosticRecord { + // Diagnostic adapters convert full records for tests/admin reads; remove when diagnostics no longer use VectorRecord. + #[allow(dead_code)] pub(crate) fn from_vector_record(record: &VectorRecord) -> Self { Self { object_id: record.object_id, @@ -52,6 +54,8 @@ impl<'a> VectorRecordEmbedding<'a> { Self { record, embedding } } + // Deterministic fakes use this conversion path; remove when fakes store VectorRecord directly. + #[allow(dead_code)] pub(crate) fn to_candidate_record(self) -> VectorCandidateRecord { self.record.to_candidate_record(self.embedding.to_vec()) } @@ -149,6 +153,8 @@ impl VectorRecord { ) } + // Diagnostic/fake stores need candidate conversion; remove when vector stores no longer expose candidate diagnostics. + #[allow(dead_code)] pub(crate) fn to_candidate_record(&self, embedding: Vec) -> VectorCandidateRecord { VectorCandidateRecord::new(self.object_id, self.object_type, self.surface, embedding) .with_filter_hints( diff --git a/src/policy.rs b/src/policy.rs index 3714618..d1393fa 100644 --- a/src/policy.rs +++ b/src/policy.rs @@ -5,6 +5,7 @@ pub(crate) mod embedding_surface; pub(crate) mod graph_expansion; pub(crate) mod retrieval_selectivity; +// Surface builders are intentionally available as a policy family; remove when callers import concrete modules. #[allow(unused_imports)] pub(crate) use embedding_surface::{ derived_memory_vector_record, entity_vector_record, episode_vector_record, diff --git a/src/policy/embedding_surface.rs b/src/policy/embedding_surface.rs index 862cd15..8f61f8d 100644 --- a/src/policy/embedding_surface.rs +++ b/src/policy/embedding_surface.rs @@ -1,7 +1,5 @@ // Embedding-surface builders for graph objects that participate in vector // candidate recall. -#![allow(dead_code)] - use crate::api::types::{ graph_uri, DerivedMemory, Entity, Episode, MemoryObject, MemoryThread, ObjectType, Observation, }; diff --git a/src/policy/graph_expansion.rs b/src/policy/graph_expansion.rs index fc176fb..f075c73 100644 --- a/src/policy/graph_expansion.rs +++ b/src/policy/graph_expansion.rs @@ -17,8 +17,6 @@ // (`apply_fanout_limits_by_pair`, `bounded_hub_retention_limit`), filters // (`relation_allowed`, `object_type_allowed`), and bounded-failure error // construction (`graph_expansion_bounded_error`). -#![allow(dead_code)] - use std::collections::{HashSet, VecDeque}; use crate::api::types::{ @@ -223,6 +221,8 @@ fn provenance_linked_derived_memory_id( } } +// Node-set expansion is reserved for diagnostics/tests; remove if callers never need object IDs only. +#[allow(dead_code)] pub(crate) fn bounded_expansion_node_set( query: &GraphExpansionQuery, root_exists: bool, diff --git a/src/ports/embedder.rs b/src/ports/embedder.rs index b779f1d..d8d1617 100644 --- a/src/ports/embedder.rs +++ b/src/ports/embedder.rs @@ -1,7 +1,5 @@ // Provider-neutral embedding boundary used by remember, retrieve, and // lifecycle vector maintenance. -#![allow(dead_code)] - use async_trait::async_trait; use crate::errors::CustomError; diff --git a/src/ports/graph_authority.rs b/src/ports/graph_authority.rs index 08c24e8..5776b6b 100644 --- a/src/ports/graph_authority.rs +++ b/src/ports/graph_authority.rs @@ -2,8 +2,6 @@ // The bounded-expansion algorithm lives in crate::policy::graph_expansion. // Oxigraph service mode is the application default; embedded and fake stores // keep tests and explicit fixture runs deterministic. -#![allow(dead_code)] - use async_trait::async_trait; use crate::api::types::{ @@ -67,6 +65,8 @@ impl GraphDerivedMemoryProvenanceQuery { self } + // Provenance queries reserve limit support for governance diagnostics; remove if that surface drops limits. + #[allow(dead_code)] pub(crate) fn with_limit(mut self, limit: usize) -> Self { self.limit = Some(limit); self @@ -90,6 +90,8 @@ impl GraphDerivedMemoryThreadQuery { self } + // Thread queries reserve limit support for governance diagnostics; remove if that surface drops limits. + #[allow(dead_code)] pub(crate) fn with_limit(mut self, limit: usize) -> Self { self.limit = Some(limit); self @@ -97,6 +99,8 @@ impl GraphDerivedMemoryThreadQuery { } impl GraphObjectQuery { + // Diagnostics and fakes need ID-only graph lookup; remove when all callers use typed refs. + #[allow(dead_code)] pub(crate) fn by_ids(object_ids: Vec) -> Self { Self { object_refs: Vec::new(), @@ -285,6 +289,8 @@ pub(crate) struct GraphExpansion { } impl GraphExpansion { + // Tests and future diagnostics need a minimal expansion constructor; remove when from_plan covers all callers. + #[allow(dead_code)] pub(crate) fn new(objects: Vec, links: Vec) -> Self { Self { objects, @@ -344,6 +350,8 @@ pub(crate) trait GraphAuthorityStore: Send + Sync { query: &GraphExpansionQuery, ) -> Result; + // Governance reconciliation is dormant; remove when diagnostic object listing is no longer part of the port. + #[allow(dead_code)] async fn list_diagnostic_objects(&self) -> Result, CustomError>; async fn list_diagnostic_links(&self) -> Result, CustomError>; diff --git a/src/ports/retrieval_stats.rs b/src/ports/retrieval_stats.rs index d2db099..639199c 100644 --- a/src/ports/retrieval_stats.rs +++ b/src/ports/retrieval_stats.rs @@ -8,7 +8,6 @@ use crate::api::types::{ }; use crate::errors::CustomError; -#[allow(dead_code)] #[async_trait] pub(crate) trait RetrievalStatsStore: Send + Sync { async fn record_edges(&self, edges: &[RetrievalStatsEdge]) -> Result<(), CustomError>; @@ -34,6 +33,8 @@ pub(crate) trait RetrievalStatsStore: Send + Sync { async fn mark_unhealthy(&self, message: String) -> Result<(), CustomError>; async fn record_rejected_low_information_link(&self) -> Result<(), CustomError>; + // Admin diagnostics are dormant until the governance surface lands; remove when a caller reads this count. + #[allow(dead_code)] async fn rejected_low_information_link_count(&self) -> Result; } @@ -65,6 +66,7 @@ pub(crate) struct RetrievalStatsObjectState { pub(crate) observed_at: DateTime, } +// Counter keys are a typed stats boundary for future diagnostics; remove when counter reads become public or delete with the counter API. #[allow(dead_code)] #[derive(Debug, Clone, PartialEq, Eq, Hash)] pub(crate) struct RetrievalStatsCounterKey { @@ -73,6 +75,7 @@ pub(crate) struct RetrievalStatsCounterKey { pub(crate) object_type: ObjectType, } +// Counter snapshots are a typed stats boundary for future diagnostics; remove when counter reads become public or delete with the counter API. #[allow(dead_code)] #[derive(Debug, Default, Clone, Copy, PartialEq, Eq)] pub(crate) struct RetrievalStatsCounter { @@ -123,6 +126,7 @@ pub(crate) async fn record_stats_after_write( } } +// Reconciliation diagnostics need raw edge derivation; remove once reconciliation is wired to record_stats_after_write only. #[allow(dead_code)] pub(crate) fn retrieval_stats_edges( objects: &[MemoryObject], diff --git a/src/ports/source_reference.rs b/src/ports/source_reference.rs index ddd4a03..8200223 100644 --- a/src/ports/source_reference.rs +++ b/src/ports/source_reference.rs @@ -1,19 +1,21 @@ // Source-reference boundary. Current graph/vector storage keeps source // references as opaque pointers; caller-owned source storage stays outside // Character Memory core. -#![allow(dead_code)] - use async_trait::async_trait; use crate::errors::CustomError; #[derive(Debug, Clone, PartialEq, Eq)] +// Source resolution is a future boundary; remove if caller-owned source storage is dropped. +#[allow(dead_code)] pub(crate) struct ResolvedSourceReference { pub(crate) reference: String, pub(crate) resolved_text: String, } impl ResolvedSourceReference { + // Source resolver fixtures use this constructor; remove if source resolution is dropped. + #[allow(dead_code)] pub(crate) fn new(reference: impl Into, resolved_text: impl Into) -> Self { Self { reference: reference.into(), @@ -23,6 +25,8 @@ impl ResolvedSourceReference { } #[async_trait] +// Source resolution is a future boundary; remove if caller-owned source storage is dropped. +#[allow(dead_code)] pub(crate) trait SourceReferenceResolver: Send + Sync { async fn resolve( &self, diff --git a/src/ports/vector_candidate.rs b/src/ports/vector_candidate.rs index 3f1d4f5..de54500 100644 --- a/src/ports/vector_candidate.rs +++ b/src/ports/vector_candidate.rs @@ -1,7 +1,5 @@ // Vector candidate recall contract. Qdrant is the default adapter, while // tests use deterministic fake stores. -#![allow(dead_code)] - use async_trait::async_trait; use crate::api::types::MemoryId; @@ -23,6 +21,8 @@ pub(crate) trait VectorCandidateStore: Send + Sync { query: &VectorCandidateSearch, ) -> Result, CustomError>; + // Reconciliation diagnostics are dormant; remove when vector candidate diagnostics are retired. + #[allow(dead_code)] async fn list_candidate_diagnostics( &self, ) -> Result, CustomError>; diff --git a/src/test_support.rs b/src/test_support.rs index 66c5780..ad35b6b 100644 --- a/src/test_support.rs +++ b/src/test_support.rs @@ -1,5 +1,7 @@ // Deterministic test harness shared by pipeline, adapter, and facade // tests. +// Shared fakes and fixtures are intentionally broader than any single test module; +// remove this module-level allow once the harness is split by fixture family. #![allow(dead_code)] use std::collections::HashSet; diff --git a/src/usecases/reconciliation.rs b/src/usecases/reconciliation.rs index 07c4cc4..c25f8a6 100644 --- a/src/usecases/reconciliation.rs +++ b/src/usecases/reconciliation.rs @@ -1,3 +1,5 @@ +// Reconciliation is an admin/governance seam that is intentionally dormant in the +// public facade; remove this module-level allow once a governance surface calls it. #![allow(dead_code)] use std::collections::{HashMap, HashSet};