Skip to content

v0.3.169 - Operator-Feedback Delivery Ledger + Batched Mark-Delivered

Choose a tag to compare

@mow-coding mow-coding released this 04 Jul 11:56

v0.3.169 - Operator-Feedback Delivery Ledger + Batched Mark-Delivered

v0.3.169 closes the v0.3.149 "Still Future: feedback status board" item. Operator
feedback records already carried a status field, but there was no read-only
board to aggregate delivery status and no way to commit a delivery boundary in one
action — the operator AI hand-edited each record's status through
operator-feedback-record --status, one record at a time, and lost track of "how
far did I deliver". Two commands ship together, both additive: no archive
migration, no id rewrite, no hash change.

Prime directives (unchanged)

Privacy — status and ids only. These commands aggregate and mutate delivery
STATUS metadata. They never read a feedback body and never echo feedback ref
values, title values, local absolute paths, tokens, or secrets. The record on
disk holds a feedback ref and title; both are deliberately projected out of
every ledger/mark-delivered result and receipt.

Truth — metadata lifecycle only, no external submission. delivered here
means "the operator marked it delivered", the same trust level as the existing
--status delivered. WOM performs no external submission and proves no human
receipt; external_submission_performed stays false.

What ships

  • Read-only delivery ledger (operator-feedback-ledger). Aliases
    feedback-ledger, feedback-board. Enumerates ops/feedback/*.yml via
    safe_archive_glob and, reading ONLY status + feedback id + safe timestamps,
    returns counts by status (draft/delivered/acknowledged/resolved/archived), a
    pending list of draft feedback ids, and the newest delivery-boundary
    timestamp among delivered records. It writes nothing and requires --dry-run.
    Malformed or non-mapping records are counted into an unreadable bucket and
    skipped so one half-written file never fails the whole board.

  • Approval-gated batched mark-delivered (operator-feedback-mark-delivered).
    Alias feedback-mark-delivered. In one action it marks every pending draft
    record as delivered, stamps delivered_at, sets reviewed_by, and refreshes
    updated_at. --dry-run previews which records would transition (by id and
    current->new status) and writes nothing. --approve (which requires a safe
    --reviewed-by) reads each record, PRESERVES every other field verbatim
    (feedback ref, title, related releases, resolved_in,
    body_managed_by_this_record, external_submission_performed), re-validates
    the mutated record against the shipped schema, writes the transition atomically
    per record, and writes a single delivery-boundary receipt under
    receipts/operator-feedback/delivery-batch.<timestamp>.<batch-digest>.json
    recording the ids, count, reviewer, and a per-batch content digest. The filename
    carries that digest (not the whole-second timestamp alone) so two batches
    committed within the same wall-clock second cannot collide and silently
    overwrite each other's audit receipt. --only <id> marks a single record.

    Three properties hold by construction:

    1. Draft-only. It transitions only draft -> delivered; acknowledged,
      resolved, and archived records are never touched (byte-identical after a run).
    2. Idempotent. Because it filters to draft before transitioning, a re-run
      once no drafts remain marks nothing new (delivered_count: 0, no records
      rewritten). A no-op approve also writes NO receipt — the delivery-boundary
      receipt is emitted only when at least one record actually transitioned, so
      empty zero-delivery boundary artifacts never accumulate.
    3. Fail-safe per record. A malformed/corrupt record in the target set is
      reported and skipped; it never aborts or half-writes records already
      validated.

Why mark-delivered does NOT reuse the record writer

operator-feedback-record rebuilds the record dict entirely from CLI arguments
and never merges the on-disk record. Routing mark-delivered through it would drop
feedback_ref/title/related_releases/resolved_in (there are no flags to
pass them) and break the shipped schema's 11-field required contract. Instead
mark-delivered reads the existing YAML, mutates only the delivery fields, and
re-validates against operator-feedback.schema.json before writing. A dedicated
test asserts the mutated record still conforms to the shipped schema — the release
gates do not run schema validation, so this guarantee is pinned by pytest.

Delivery-boundary honesty

Only records stamped by mark-delivered carry delivered_at. Records that reached
delivered through the older operator-feedback-record --status delivered path
have no delivered_at, so for those the ledger's boundary falls back to their
updated_at. The ledger reports delivery_boundary_stamped_count separately and
labels the boundary as the newest available delivery timestamp, not authoritative
proof of when — or whether — anything was delivered externally.

JSON-contract and schema additions (all additive)

  • operator-feedback.schema.json gains two OPTIONAL string properties,
    delivered_at and acknowledged_at (not added to required, so existing
    records still validate).
  • New schema wom-kit/schemas/operator-feedback-delivery-receipt.schema.json
    (wom-kit/operator-feedback-delivery-receipt/v0.1) for the batch receipt, with
    external_submission_performed: const false and delivery_is_metadata_only: const true.

Test honesty note

New tests use temp-dir fixtures copied from the fake-life archive and never touch a
real archive. They pin: the ledger aggregates counts + a pending list and does NOT
echo a seeded secret-ish feedback ref OR title; mark-delivered --dry-run previews
and writes nothing; --approve transitions only draft->delivered, stamps
delivered_at + reviewed_by, writes exactly one receipt, is idempotent (second
run no-ops AND writes no new receipt), and requires --reviewed-by; --only marks
a single record; seeded acknowledged and resolved records are byte-identical after a
run; the mutated record still conforms to the shipped schema; a malformed record is
reported as unreadable by the ledger and skipped by mark-delivered while the valid
draft still transitions and the return code stays sane; two batches committed in the
same wall-clock second keep two distinct receipts (per-batch digest in the filename);
a hand-authored record whose internal feedback_id is a secret-ish URL/token has that
id redacted to the safe file stem in the ledger pending list, the mark-delivered
output, and the receipt; and neither the mark-delivered result nor the on-disk batch
receipt contains the secret-ish ref or title.

Safety and scope

No archive migration. No id rewrite. No hash change. The ledger is read-only;
mark-delivered writes only status-metadata transitions and a receipt after
approval. delivered is a metadata stamp, never a claim of external submission.
All new commands are additive.

Upgrade

See UPGRADE.md. All changes are additive; no migration is required.