Skip to content

Storage abstraction: per-artifact Protocols with entry-point discovery (blocker for #391) #394

Description

@mlieberman85

Summary

Prerequisite feature for #391 (datastore backend for project metadata) and its future siblings (attestation datastore, report datastore, audit-cache datastore). Landed as its own feature so the abstraction can be reviewed on its own merits and land ahead of any specific backend.

Design conversation on 2026-08-23 (chat log; not yet in a spec) landed on:

  • darnit-core stays filesystem-only (Constitution I unchanged, storage claim in CLAUDE.md unchanged).
  • Alternative storage backends land as plugins behind per-artifact Protocols, mirroring feature 027's QuestionResolver pattern.
  • Discovery via Python entry points (darnit.stores.<kind>).
  • Backend selection in TOML ([stores.<kind>] backend = "...").

Scope

Protocols (four, one per artifact class):

  • ProjectStateStore -- read/write .project/project.yaml, maintainers.yaml, extensions.
  • AttestationStore -- persist feature-025 attestation bundles.
  • ReportStore -- persist audit reports (Markdown, JSON, SARIF).
  • AuditCacheStore -- persist per-audit-run cache.

Contracts each Protocol MUST document:

  • Sync vs async surface.
  • Batched vs per-item write semantics.
  • Transactional vs eventually-consistent.
  • What a "failed write" means to the caller (WARN? ERROR? exception?).

Per-artifact granularity chosen (over "one Store Protocol with method families per backend") so .project/ can stay YAML-on-disk while attestations go to a database, and so each artifact class can migrate independently.

Core deliverables:

  • Four Protocol classes with @runtime_checkable decoration (per feature 027 convention).
  • Filesystem-backed default implementation for each, shipped in darnit-core. Existing paths (.project/, .darnit/attestations/, .darnit/reports/, .darnit/cache/) become the default backend's on-disk layout.
  • Entry-point discovery machinery: register under darnit.stores.project, darnit.stores.attestation, darnit.stores.report, darnit.stores.cache.
  • TOML surface on FrameworkConfig ([stores.<kind>] backend = "<name>") with schema validation.
  • Zero behavior change for any consumer that doesn't set [stores.*] -- filesystem default is transparent.

Non-goals for v0

Constitution alignment

  • I. Plugin Separation: the Protocols and filesystem defaults live in darnit-core; alternative backends are plugin packages that never touch core.
  • III. TOML-First: backend selection is a TOML surface, no Python-code escape hatch.
  • V. Sieve Pipeline Integrity: sieve handlers do not touch stores directly; store operations happen at audit-boundary composition, keeping the pipeline's PASS/FAIL/WARN/ERROR contract intact.

Related

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions