Skip to content

How-to

Detect contradictions and track knowledge gaps

Use memory_check to find inconsistencies and memory_gap to log questions the memory couldn't answer.

Two intelligence-layer surfaces work together: check finds places where the memory disagrees with itself, and gap records questions it couldn’t answer well. This recipe shows how to use both.

Terminal window
quaid check people/alice --db ~/memory.db # one page
quaid check --all --db ~/memory.db # every page
quaid check --all --type assertion_conflict --db ~/memory.db # filter by contradiction type

check re-extracts the page’s assertions, then flags pairs of subject-predicate-object triples about the same (subject, predicate) whose objects differ while their valid_from / valid_until windows overlap. Detection is exact-match over the assertions table — it does not infer conflicts from arbitrary prose, timelines, or unstructured frontmatter.

Output is human-readable by default (each line starts with the contradiction id, e.g. #3 [a] ↔ [b]: …), JSON with --json. Materialized contradictions live in the contradictions table.

Assertions are populated three ways:

  1. A small frontmatter allowlist — the scalar fields is_a, works_at, and founded:

    ---
    title: Alice
    type: person
    works_at: River AI
    ---
  2. Parsed from a ## Assertions section in the body. Three sentence patterns are recognized: X works at Y, X is a Y, and X founded Y. Prose outside this section is never scanned.

  3. Mirrored from extracted-fact pages. Facts the conversation pipeline writes under extracted/ (kinds decision, preference, fact, action_item) are mirrored automatically as (type key, kind, summary) triples with asserted_by = 'extraction' — no ## Assertions heading needed. Superseded fact pages are skipped, so resolved history doesn’t conflict with current truth.

You can also insert rows into assertions directly (asserted_by = 'manual'); re-running check preserves manual rows.

Each contradiction has an id (shown by quaid check and memory_check). Resolve it with:

Terminal window
# Keep one page: the other page in the pair is superseded by it,
# and the contradiction is stamped resolved.
quaid check --resolve 3 --keep people/alice --db ~/memory.db
# Dismiss without superseding (e.g. false positive):
quaid check --resolve 3 --db ~/memory.db

Over MCP, pass resolve (and optionally keep) to memory_check:

Terminal window
quaid call memory_check '{"resolve":3,"keep":"people/alice"}' --db ~/memory.db

Resolution semantics:

  • Resolving stamps contradictions.resolved_at; resolved rows disappear from quaid check, memory_check, and the memory_stats contradiction count.
  • A resolved contradiction is a durable dismissal: the identical conflict (same pages, same description) is not re-raised on later checks. A materially different conflict (e.g. a new object value) is still detected as a new contradiction.
  • Superseding a page — via --keep, a supersedes: write, or the extraction pipeline — auto-resolves open contradictions touching the superseded page.

When neither side should win outright, fix the data instead:

  • Both true at different times? Add valid_until to the older assertion so the intervals don’t overlap.
  • Both true now, but seem to disagree? Edit the predicate; the contradiction was lexical, not semantic.

When a query returns weak results — or you anticipate one will — log it:

Terminal window
quaid call memory_gap '{"query":"who covers our European compliance?","context":"weekly briefing"}' --db ~/memory.db

By default this stores the hash of the query, plus the context, plus a default sensitivity = internal. The raw text is not persisted unless explicitly approved. See the Sensitivity contract.

Terminal window
quaid gaps --db ~/memory.db # unresolved (default)
quaid gaps --resolved --db ~/memory.db # include resolved
quaid gaps --limit 100 --db ~/memory.db

You add a page that answers the question, then either:

  1. Manually mark it resolved — set resolved_at and resolved_by_slug in knowledge_gaps directly.
  2. Use the research skill — the embedded skill has a documented workflow for ingesting new material in response to a gap and marking the gap resolved when novelty passes a threshold.

The skill is the recommended path; it keeps the gap → research → ingest → resolve loop legible.

  1. Daily: quaid stats shows unresolved gap counts; quaid gaps --limit 5 is the work queue.
  2. Weekly: quaid check --all to catch contradictions you’ve introduced.
  3. Monthly: quaid validate to catch link integrity issues. See Manage skills for an alerts skill that wires this into your day automatically.

Agents log gaps when their memory_query results don’t meet a confidence threshold. The hash-only default means the memory accumulates a privacy-safe ledger of “where can’t we answer well?” over time, even when individual queries are sensitive.

When an agent escalates a gap to external research (e.g. via the enrich skill), it must transition the sensitivity tier with explicit approval — see Sensitivity contract.