Skip to content

feat: kb.timeline — chronological trajectory view of an entity's claims and relations #313

Description

@plind-junior

the KB already knows what it knows about an entity, but it has no way to show how that knowledge accrued over time. kb.read_entity returns the entity and its current claims as a flat set; kb.neighbors (#184) expands graph adjacency at a point in time; kb.trace (#197) walks the provenance DAG to explain how one artifact derives from another. none of these answers "what did the KB learn about this entity, in what order?" — a trajectory. the raw material is already on disk: Claim carries created_at / updated_at / last_confirmed_at, Relation carries created_at / updated_at, and decision time is recoverable from the decided_at field on decided/ records and the append-only audit.log.jsonl. this issue asks for a read-only method that orders an entity's approved claims, relations, and decisions along that time axis.

proposed surface

a new read-only method kb.timeline and its CLI mirror vouch timeline.

  • input: entity_id (required); optional since / until iso-8601 bounds; optional order in {effective, decided} (default effective — orders by created_at / last_confirmed_at; decided orders by the decided_at recovered from decided/ + the audit log); optional types filter (e.g. decision,fact); optional limit.
  • output: an ordered list of entries, each {when, kind, id, summary, status} where kind is claim | relation and when is the chosen timestamp. status reflects the artifact's current ClaimStatus for claims (a superseded claim still appears, flagged); Relation has no status field, so status is null for relation entries. the shape stays close to kb.neighbors for surface consistency.
  • CLI: vouch timeline <entity-id> [--order decided] [--since 2026-01-01] [--until ...] [--types decision,fact] [--limit N], human table by default, --json for the machine shape.

only approved durable artifacts are read; pending proposals never appear.

review gate & scope

this is a pure read — no propose_*, no kb.approve, no mutation. it does not create or edit knowledge, so there are no gate implications: it is a viewport over already-reviewed artifacts, exactly like kb.read_entity and kb.neighbors. the timestamp reconstruction reads decided/ and audit.log.jsonl only; it never edits either. all timestamp/ordering logic lives in the read path (a new helper alongside the other read methods), not in storage.py, which stays pure I/O. everything runs against the local .vouch/ — no network, no external service.

per the per-tool convention, kb.timeline attaches the _meta.vouch_salience sidebar inline (via salience.attach_salience, as kb_context does) rather than relying on any global decorator.

being a new kb.* method, it must touch the four registration sites or test_capabilities will fail:

  • MCP tool in src/vouch/server.py (@mcp.tool() kb_timeline)
  • JSONL handler in src/vouch/jsonl_server.py (_h_timeline + HANDLERS["kb.timeline"])
  • METHODS list in src/vouch/capabilities.py
  • CLI command in src/vouch/cli.py

plus a test under tests/test_timeline.py.

relationship to adjacent issues

distinct from #197 (kb.trace): that walks the provenance DAG to explain derivation — which source or claim an artifact descended from; timeline orders an entity's own artifacts along a time axis (one is causal, one is chronological). distinct from #184 (kb.neighbors): that expands graph adjacency, not chronology. distinct from #232 (visibility-aware kb.audit): timeline reads the audit log only to recover decided_at for ordering, it is not an audit-query surface.

acceptance criteria

  • kb.timeline returns an entity's approved claims and relations ordered by the chosen time axis, most-recent-last (or documented direction)
  • order=effective uses artifact timestamps; order=decided reconstructs decision time from decided/ + audit.log.jsonl without editing either
  • since / until / types / limit filters apply as documented
  • superseded and archived claims still appear, flagged by current ClaimStatus; relation entries carry status = null; pending proposals never appear
  • the method is read-only: no proposal, no approval, no write path is reachable from it
  • _meta.vouch_salience is attached inline per the per-tool convention
  • registered at all four sites; test_capabilities passes
  • vouch timeline CLI mirrors the method with human + --json output
  • tests/test_timeline.py covers ordering, both order modes, the filters, and the superseded-still-visible case
  • make check green (pytest, mypy, ruff)

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or requestretrievalcontext, search, synthesis, and evaluationsize: M200-499 changed non-doc lines

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions