feat(datastore): container manifests datastore (S12 Step 3)

Why

Step 3 of the OCI Local plan: the container_manifests datastore. Tests bake in regression guards for the two correctness issues from the closed OCI slice (!124 (closed)-!128 (closed)): annotations NULL Scan and JSONB INSERT encoding.

Spec: S12. Work item: #19 (closed).

What (non-obvious)

  • Raw SQL via qrm.DB.QueryContext, not jet. Plan-sanctioned: jet's typed builder doesn't expose the pgx text-format encoding path the JSONB INSERT fix requires.
  • New dep github.com/santhosh-tekuri/jsonschema/v6 for runtime annotations validation against the embedded schema. Loaded once at init, runs before every INSERT/UPDATE that writes the column.

Spec coverage

Per the plan's Step 3 slice: none at this step. The datastore methods underpin AC-7, AC-14, AC-15/16/17, AC-19/20. Handler steps 12, 14, 17 fill those rows.

LLM context

Design rationale:

  • Raw SQL not jet: jet routes through pgx's prepared-statement mode, which under QueryExecModeSimpleProtocol cannot encode []byte to JSONB (returns SQLSTATE 22P02). The nullableJSON helper returns string so the driver stringifies it as a JSON literal. Sibling stores (namespaces.go, repositories.go, blob_storage_attachments.go) use jet because they lack JSONB columns.
  • JSON Schema validation runs pre-INSERT (not as a DB CHECK) so the handler layer can map structured errors to spec error codes such as MANIFEST_INVALID at Steps 12-17.

Non-goals (deferred):

  • GC coordination, reachability events → S20
  • Counters, repositories.size_bytes → S22
  • Handler-layer error mapping → Steps 12-17

Merge request reports

Loading
Loading