Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ The goal is a trustworthy substrate for coding agents that can:
- **Candidate claim workflow** — episodic events can produce staged claims that are promoted or rejected explicitly.
- **Observation continuity surfaces** — episodic events can produce privacy-checked, source-backed observations that are recallable by ID, summarized by compaction, and coverage-accounted across full session event ranges.
- **Continuity reliability controls** — coverage accounting, deterministic `catch-up`, gap warnings in summaries, destructive prune operations blocked when gaps remain, prune markers preserved in logs, and audit-aware observation recall.
- **MCP/OAuth server** — `aver-server` exposes memory tools over Streamable HTTP MCP behind a local OAuth-style token flow, including the ADR-0008 five-tool surface with validated recall/write/event/extraction-trigger parameters, observation projection tools, explicit unsupported-scope errors, persisted confidence overrides, and recall subgraphs with confidence floors.
- **MCP/OAuth server** — `aver-server` exposes memory tools over Streamable HTTP MCP behind a local OAuth-style token flow, including the ADR-0008 five-tool surface with validated recall/write/event/extraction-trigger parameters, observation projection tools, ADR-0021/0022 scoped memory parameters and connection defaults, persisted confidence overrides, and recall subgraphs with confidence floors.
- **Evaluation harnesses** — fixture evaluation plus a BEAM100K runner using local Ollama for embeddings, answer generation, and judging.

## Quick Start
Expand Down Expand Up @@ -219,6 +219,8 @@ MCP currently exposes 18 tools through a progressive discovery card so agents ke

Aver's MCP guide is intentionally proactive but selective: agents should recall first, then record durable user-shared preferences, project facts, and long-lived working context even when the user does not say "remember this" explicitly. Identity details should be recorded only when they are necessary, user-shared, and not sensitive personal data. When durability is uncertain, agents should prefer `record_event` over `remember_claim`, and they must not store secrets, credentials, sensitive personal data, transient chat, or facts they cannot explain with provenance.

Scope is a first-class memory dimension. Write tools such as `remember_claim`, `add_triple`, `record_event`, `record_observation`, and `propose_candidate_claim` accept an optional `scope`; when omitted through MCP, the request's ADR-0022 resolved scope applies, falling back to `global` for clients that send no scope signal. Read tools (`recall`, `expand`) accept `scope` plus `scope_walk`: use `ancestors` for normal project memory, `exact` for isolation, `descendants` for subtree audits, and `any` only for intentional cross-scope search. Vector chunks do not carry their own scope; they attach to a claim and inherit the claim's effective scope.

CLI-only continuity and maintenance surfaces (`catch-up`, `compaction-summary`) are implemented in `aver-cli`; MCP exposes `record_observation`, `assemble_compaction_summary`, and the observation audit tools above, while claim-maintenance tasks stay available through the four advanced tools when agents explicitly need them.

Adapter boundaries are explicit in `aver-server` via the `adapters` module (`Pi`, `ClaudeCode`, `CodexOpenAi`, `OpenCode`, `Mcp`, `JsonlCliHarness`) so host runtimes can be added without leaking host-specific logic into `aver-core`.
Expand Down
2 changes: 2 additions & 0 deletions autoresearch.jsonl
Original file line number Diff line number Diff line change
Expand Up @@ -565,3 +565,5 @@
{"run":536,"commit":"74552c9","metric":807,"metrics":{"tests_green":807,"tests_total":807,"milestone_index":9,"loc_core":6951,"commit_count_total":600,"memory_error_rate":0,"unsupported_claim_rate":0,"mean_precision_at_k":1,"mean_recall_at_k":1,"beam_questions":0,"beam_rubric_checks":0,"beam_abstention_pct":0,"beam_contradiction_resolution_pct":0,"beam_event_ordering_pct":0,"beam_information_extraction_pct":0,"beam_instruction_following_pct":0,"beam_knowledge_update_pct":0,"beam_multi_session_reasoning_pct":0,"beam_preference_following_pct":0,"beam_summarization_pct":0,"beam_temporal_reasoning_pct":0},"status":"keep","description":"Reject non-positive predicate closure children","timestamp":1779052727528,"segment":28,"confidence":6.3538461538461535,"asi":{"hypothesis":"Predicate closure child_id links should reject non-positive values so predicate ontology transitive-closure rows get precise diagnostics before foreign-key handling.","red_evidence":"`cargo test -q -p aver-core --test migrations predicate_closure_child_id_must_be_positive` failed for the intended reason after using the seeded `uses` predicate type: child_id=0 produced a generic foreign-key error.","green_evidence":"Targeted predicate closure child-id test passed; full migrations test passed with 110 tests; `./autoresearch.sh` passed with checks green and metrics tests_green=807 tests_total=807.","implementation_notes":"Added migration `0115_predicate_closure_child_id_positive_checks.sql` with insert/update triggers rejecting predicate_closure.child_id <= 0.","anti_overfit_note":"This is a general predicate ontology closure integrity invariant and does not use benchmark expected outputs or labels."}}
{"run":537,"commit":"74fbeab","metric":808,"metrics":{"tests_green":808,"tests_total":808,"milestone_index":9,"loc_core":6951,"commit_count_total":601,"memory_error_rate":0,"unsupported_claim_rate":0,"mean_precision_at_k":1,"mean_recall_at_k":1,"beam_questions":0,"beam_rubric_checks":0,"beam_abstention_pct":0,"beam_contradiction_resolution_pct":0,"beam_event_ordering_pct":0,"beam_information_extraction_pct":0,"beam_instruction_following_pct":0,"beam_knowledge_update_pct":0,"beam_multi_session_reasoning_pct":0,"beam_preference_following_pct":0,"beam_summarization_pct":0,"beam_temporal_reasoning_pct":0},"status":"keep","description":"Reject non-positive predicate closure ancestors","timestamp":1779052824413,"segment":28,"confidence":6.369230769230769,"asi":{"hypothesis":"Predicate closure ancestor_id links should reject non-positive values so predicate ontology transitive-closure rows get precise diagnostics before foreign-key handling.","red_evidence":"`cargo test -q -p aver-core --test migrations predicate_closure_ancestor_id_must_be_positive` failed because ancestor_id=0 produced a generic foreign-key error.","green_evidence":"Targeted predicate closure ancestor-id test passed; full migrations test passed with 111 tests; `./autoresearch.sh` passed with checks green and metrics tests_green=808 tests_total=808.","implementation_notes":"Added migration `0116_predicate_closure_ancestor_id_positive_checks.sql` with insert/update triggers rejecting predicate_closure.ancestor_id <= 0.","anti_overfit_note":"This is a general predicate ontology closure integrity invariant and does not use benchmark expected outputs or labels."}}
{"run":538,"commit":"5547e6f","metric":809,"metrics":{"tests_green":809,"tests_total":809,"milestone_index":9,"loc_core":6951,"commit_count_total":602,"memory_error_rate":0,"unsupported_claim_rate":0,"mean_precision_at_k":1,"mean_recall_at_k":1,"beam_questions":0,"beam_rubric_checks":0,"beam_abstention_pct":0,"beam_contradiction_resolution_pct":0,"beam_event_ordering_pct":0,"beam_information_extraction_pct":0,"beam_instruction_following_pct":0,"beam_knowledge_update_pct":0,"beam_multi_session_reasoning_pct":0,"beam_preference_following_pct":0,"beam_summarization_pct":0,"beam_temporal_reasoning_pct":0},"status":"keep","description":"Reject blank predicate alias notes","timestamp":1779052989417,"segment":28,"confidence":6.384615384615385,"asi":{"hypothesis":"Predicate alias notes are optional, but when present they should be nonblank so alias provenance remains meaningful and auditable.","red_evidence":"`cargo test -q -p aver-core --test migrations predicate_alias_note_must_not_be_blank_when_set` failed because direct SQL accepted a whitespace-only note.","green_evidence":"Targeted predicate alias note test passed; full migrations test passed with 112 tests; `./autoresearch.sh` passed with checks green and metrics tests_green=809 tests_total=809.","implementation_notes":"Added migration `0117_predicate_alias_note_nonblank_checks.sql` with insert/update triggers rejecting non-null trimmed-empty predicate_alias.note values.","anti_overfit_note":"This is a general predicate alias auditability invariant and does not use benchmark expected outputs or labels."}}
{"run":539,"commit":"54da71f","metric":810,"metrics":{"tests_green":810,"tests_total":810,"milestone_index":9,"loc_core":6951,"commit_count_total":603,"memory_error_rate":0,"unsupported_claim_rate":0,"mean_precision_at_k":1,"mean_recall_at_k":1,"beam_questions":0,"beam_rubric_checks":0,"beam_abstention_pct":0,"beam_contradiction_resolution_pct":0,"beam_event_ordering_pct":0,"beam_information_extraction_pct":0,"beam_instruction_following_pct":0,"beam_knowledge_update_pct":0,"beam_multi_session_reasoning_pct":0,"beam_preference_following_pct":0,"beam_summarization_pct":0,"beam_temporal_reasoning_pct":0},"status":"keep","description":"Reject self-parent ontology extensions","timestamp":1779053189044,"segment":28,"confidence":6.351145038167939,"asi":{"hypothesis":"Ontology extension audit rows should reject self-parenting predicate relationships so the extension log cannot encode a cyclic immediate parent edge.","red_evidence":"`cargo test -q -p aver-core --test migrations ontology_extension_parent_must_not_self_reference` failed because direct SQL accepted predicate='uses' with parent='uses'.","green_evidence":"Targeted ontology extension self-parent test passed; full migrations test passed with 113 tests; `./autoresearch.sh` passed with checks green and metrics tests_green=810 tests_total=810.","implementation_notes":"Added migration `0118_ontology_extension_parent_not_self_checks.sql` with insert/update triggers rejecting ontology_extension_log rows where parent equals predicate.","anti_overfit_note":"This is a general ontology hierarchy audit invariant and does not use benchmark expected outputs or labels."}}
{"run":540,"commit":"54da71f","metric":471,"metrics":{"tests_green":471,"tests_total":472,"milestone_index":9,"loc_core":6951,"commit_count_total":604,"memory_error_rate":0,"unsupported_claim_rate":0,"mean_precision_at_k":0,"mean_recall_at_k":0,"beam_questions":0,"beam_rubric_checks":0,"beam_abstention_pct":0,"beam_contradiction_resolution_pct":0,"beam_event_ordering_pct":0,"beam_information_extraction_pct":0,"beam_instruction_following_pct":0,"beam_knowledge_update_pct":0,"beam_multi_session_reasoning_pct":0,"beam_preference_following_pct":0,"beam_summarization_pct":0,"beam_temporal_reasoning_pct":0},"status":"crash","description":"Predicate type created_via trigger broke legacy migration replay","timestamp":1779053310404,"segment":28,"confidence":6.4,"asi":{"hypothesis":"Predicate type created_via should reject blank creation-source strings for auditability.","rollback_reason":"`./autoresearch.sh` failed because vector_index migration replay hit `error in trigger predicate_type_created_via_nonblank_insert after drop column: no such column: NEW.created_via`; older migration replay paths may temporarily lack the audit column, so this trigger placement is unsafe.","next_action_hint":"Do not retry a trigger that references predicate_types.created_via without first understanding the legacy vector_index replay/drop-column path; prefer a different invariant on stable columns or a migration-safe implementation.","error_details":"crates/aver-core/tests/vector_index.rs migration_backfills_existing_vector_chunks_rows failed after targeted migrations tests passed.","anti_overfit_note":"The attempted invariant was general auditability, not benchmark-specific, but implementation violated migration replay compatibility."}}
1 change: 1 addition & 0 deletions crates/aver-server/src/mcp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -500,6 +500,7 @@ fn mcp_tool_instructions() -> String {
"Default active set: {}. ",
"Decision policy: recall before answering when durable memory may matter; remember_claim only for explicit stable long-term facts; record_event for useful raw history; record_observation and assemble_compaction_summary for source-backed continuity. ",
"Self-healing writes: predicates are strict, but unknown-predicate errors include fuzzy/semantic suggestions, accepted aliases, and a retry hint; retry with a suggested predicate rather than inventing new predicates or silently rewriting claims. Use `relates_to` as the safest generic fallback when no precise predicate fits. ",
"Scope policy: pass `scope` only for an explicit per-call override; otherwise the request's resolved scope applies. For scoped reads, use `scope_walk=ancestors` for normal project memory, `exact` for isolation, `descendants` for subtree audits, and `any` only for cross-scope search. ",
"Proactive memory policy: record durable user-shared preferences, project facts, and long-lived working context even without a direct remember command; only record identity details when they are necessary, user-shared, and not sensitive personal data; prefer record_event over remember_claim when durability is uncertain. Avoid storing secrets, credentials, sensitive personal data, transient chat, or facts you cannot explain with provenance. ",
"Default workflows: recall existing memory before answering or updating; record_event -> should_extract_memories -> propose_candidate_claim/list_candidate_claims -> promote_candidate_claim or reject_candidate_claim for event-to-claim promotion; record_observation -> recall_observation or observation_coverage -> assemble_compaction_summary for continuity and compaction. ",
"Graph navigation tools available: {}. Progressively load graph navigation tools only after recall returns an entity or you already know an anchor: expand; use add_triple instead of remember_claim only when confidence/source control is required. ",
Expand Down
2 changes: 1 addition & 1 deletion crates/aver-server/src/scope_resolution.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ impl ResolvedScope {
}

/// Validate a scope candidate without going through sqlite. Mirrors the
/// `[A-Za-z0-9_/-]` charset enforced by migration 0084.
/// `[A-Za-z0-9_/-]` charset enforced by migration 0085.
fn validate(scope: &str, source: &'static str) -> anyhow::Result<()> {
if scope.trim().is_empty() {
anyhow::bail!("{source}: scope must not be blank");
Expand Down
6 changes: 6 additions & 0 deletions crates/aver-server/tests/mcp_instructions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,12 @@ fn mcp_instructions_are_a_progressive_discovery_card() {
assert!(instructions.contains(
"unknown-predicate errors include fuzzy/semantic suggestions, accepted aliases, and a retry hint"
));
assert!(instructions.contains(
"Scope policy: pass `scope` only for an explicit per-call override; otherwise the request's resolved scope applies."
));
assert!(instructions.contains(
"For scoped reads, use `scope_walk=ancestors` for normal project memory, `exact` for isolation, `descendants` for subtree audits, and `any` only for cross-scope search."
));
assert!(instructions.contains(
"Progressively load graph navigation tools only after recall returns an entity or you already know an anchor: expand; use add_triple instead of remember_claim only when confidence/source control is required."
));
Expand Down
33 changes: 18 additions & 15 deletions doc/adr/0021-scope-as-first-class-memory-dimension.md
Original file line number Diff line number Diff line change
Expand Up @@ -75,24 +75,26 @@ the existing two ACTIVE claims valid.

### Schema change

A new migration `migrations/00NN_scope_column.sql` adds:
Migration `migrations/0085_scope_column.sql` adds:

```sql
ALTER TABLE claims ADD COLUMN scope TEXT NOT NULL DEFAULT 'global';
ALTER TABLE events ADD COLUMN scope TEXT NOT NULL DEFAULT 'global';
ALTER TABLE observations ADD COLUMN scope TEXT NOT NULL DEFAULT 'global';

CREATE INDEX claims_scope ON claims(scope);
CREATE INDEX events_scope ON events(scope);
CREATE INDEX observations_scope ON observations(scope);
ALTER TABLE claims ADD COLUMN scope TEXT NOT NULL DEFAULT 'global';
ALTER TABLE episodic_events ADD COLUMN scope TEXT NOT NULL DEFAULT 'global';
ALTER TABLE observations ADD COLUMN scope TEXT NOT NULL DEFAULT 'global';
ALTER TABLE candidate_claims ADD COLUMN scope TEXT NOT NULL DEFAULT 'global';

CREATE INDEX claims_scope ON claims(scope);
CREATE INDEX episodic_events_scope ON episodic_events(scope);
CREATE INDEX observations_scope ON observations(scope);
CREATE INDEX candidate_claims_scope ON candidate_claims(scope);
```

Triggers analogous to `claims_agent_id_*_insert/update`
(`migrations/0060`–`0061`) enforce `scope` non-blank and a charset of
`[A-Za-z0-9_/-]` (note the `/` — paths are first-class).

The candidate-claim staging table inherits a `scope` column on the same
migration so candidates carry the writer's intended scope through promotion.
The candidate-claim staging table carries the writer's intended scope through
promotion.
Comment on lines +78 to +97

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🗄️ Data Integrity & Integration | 🟡 Minor | ⚡ Quick win

Correct the index count in the consequences section.

This migration creates four scope indexes, including candidate_claims_scope, but the ADR still describes the cost as “three indexes.” Update that statement so the schema contract is internally consistent.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@doc/adr/0021-scope-as-first-class-memory-dimension.md` around lines 78 - 97,
Update the consequences section of the ADR to state that the migration adds four
scope indexes, including candidate_claims_scope, instead of three. Keep the
surrounding cost discussion unchanged.


### Path convention

Expand Down Expand Up @@ -129,11 +131,12 @@ this one.

### Write-path semantics

`add_triple`, `remember_claim`, `record_event`, `record_observation`,
`propose_candidate_claim`, and `add_vector_chunk` accept an optional `scope`.
When omitted: `'global'` (preserves today's behavior). `promote_candidate_claim`
copies the candidate's `scope` onto the durable claim; it is not a separate
parameter on promote.
`add_triple`, `remember_claim`, `record_event`, `record_observation`, and
`propose_candidate_claim` accept an optional `scope`. When omitted: `'global'`
(preserves today's behavior). `promote_candidate_claim` copies the candidate's
`scope` onto the durable claim; it is not a separate parameter on promote.
`add_vector_chunk` does not accept a separate scope because vector chunks attach
to a claim and inherit the claim's effective scope.

### Migration

Expand Down
Loading
Loading