Skip to content

feat(v1.10): audit-log entries for manual-flag writes - #75

Merged
jameskhair-code merged 1 commit into
mainfrom
feat/v1.10-flag-audit
Jun 11, 2026
Merged

jameskhair-code merged 1 commit into
mainfrom
feat/v1.10-flag-audit

Conversation

@jameskhair-code

Copy link
Copy Markdown
Owner

Item 3 of the v1.10 preflight (docs/planning/v1.10-charter.md). Closes the one live correctness gap from the v1.9 known-limitations list: flag writes left no trail, and the campaign will generate thousands of them.

What changed

db.py — logging at the choke point. mark_mqg_complete and clear_mqg_flag now write one audit entry per book through the existing audit_log choke point, after the SQLite commit. Entry shape: field = the column, new_value = true (mark) / null (clear), source = "flag", step = "flag:<command>", no confidence. Putting it in the db methods (rather than the 11 call sites) means every current and future caller — including tags-review's per-book lock — is covered for free; callers pass their command name via a new audit_step keyword.

The flag: step namespace is load-bearing. The charter's design constraint was that neither audit reader confuses a flag event with an AI write — confirmed against both filters:

  • Calibration (load_audit_records, commands/audit.py:102) keeps only records with non-empty confidence AND source AND step. Flag entries carry no confidence → excluded.
  • Regrade staleness (find_stale_books, commands/regrade.py:56) filters on exact step name only (lcc-enrich etc.). A flag entry with a bare command-name step would have made a flagged book look freshly enriched and silently dropped it from regrade. flag:lcc-enrich ≠ lcc-enrich, so flag writes never refresh staleness.

Callers — all 11 sites across 8 commands pass their command name (clean-titles, comments-enrich ×2, enrich-identifiers ×2, lcc-enrich ×2, tags-enrich ×2, tags-review ×2, unflag-manual). Bulk marks write per-book entries deliberately (charter: history must be reconstructible per book; accept the volume).

Regrade marker ride-along. A flag write inside a regrade_audit context picks up the regrade marker at the choke point — harmless per the charter (both readers exclude the entry on other fields), and locked by a test.

Test isolation. New autouse conftest fixture redirects CALIBRE_TOOLKIT_AUDIT_LOG to tmp_path for every test — without it, the existing test_clear_mqg_flag.py db-level tests would now append to the real ~/.calibre-toolkit/audit.log on every suite run.

Verification

  • python -m pytest -q — 647 passed (8 new contract tests: per-book entry shape for mark and clear, bare-flag default, no entry on the unknown-column no-op/raise paths, calibration exclusion, regrade-staleness exclusion, regrade-marker ride-along).
  • Real-library flag → unflag loop: flagged one book (#mqg_identifiers_manual) through mark_mqg_complete, cleared it with the real unflag-manual id:=2 --auto-apply, and audit-log --book-id 2 shows both entries (flag:smoke, flag:unflag-manual). Library state net-unchanged (row deleted, back to undefined).

🤖 Generated with Claude Code

mark_mqg_complete and clear_mqg_flag write one audit entry per book
through the existing audit_log choke point: source="flag",
step="flag:<command>", new_value True (mark) / null (clear), no
confidence.

The "flag:" namespace is load-bearing: regrade staleness filters on
exact AI step names, so a bare command name would make a flagged book
look freshly enriched. No confidence keeps flag entries out of the
calibration pool. Both reader contracts are locked by tests, plus the
regrade-marker ride-along case.

New autouse conftest fixture redirects CALIBRE_TOOLKIT_AUDIT_LOG to
tmp_path so db-level tests stop short of the real audit log.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@jameskhair-code
jameskhair-code merged commit 7b5900e into main Jun 11, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant