falsification CLI: mark wrong cached answers stale/failed
aborist [--shards-dir DIR] providence --falsify CACHE_KEY \
--state {failed,stale,quarantined} --reason "X" --by-actor NAME
Searches every shard for the cache_key (it lives in exactly one),
flips falsification_state on the providence_cache row, appends a row
to the falsifications log, and writes a 'falsify' audit event so the
chain captures the act with from_state/to_state/reason/by_actor.
Future cache lookups skip records whose state != 'live', so a
falsified answer never gets reused. The record itself is preserved
(history matters); only its admissibility changes.
Makefile target:
make falsify KEY=<hex> REASON='why' [STATE=failed]
Demo on the live shard cluster: marked the AMD/Pentium-4 conflation
answer as failed, verified state flipped + audit row recorded +
falsifications log captured fox as actor + the Barton-clock-vs-PR
explanation as reason. Re-asking the same question generated a fresh
cache_key (corpus state shifted between attempts) so a new LLM call
ran — exactly the v9.8 admissibility behavior: each (8-dim cache_key)
is independently live/failed.
66 tests still passing.
This commit is contained in:
parent
76446d4349
commit
1abe6d4adc
2 changed files with 124 additions and 2 deletions
4
Makefile
4
Makefile
|
|
@ -114,6 +114,10 @@ ACTIVITY_LIMIT ?= 10
|
|||
activity: bootstrap ## recent Q&A + freshly cached docs (agent timeline)
|
||||
$(ABORIST) --shards-dir $(SHARDS_DIR) activity --limit $(ACTIVITY_LIMIT)
|
||||
|
||||
falsify: bootstrap ## mark a cached answer wrong: make falsify KEY=hex REASON='why'
|
||||
@if [ -z "$(KEY)" ]; then echo "usage: make falsify KEY=<cache_key> REASON='why'" >&2; exit 2; fi
|
||||
$(ABORIST) --shards-dir $(SHARDS_DIR) providence --falsify $(KEY) --reason "$(REASON)"
|
||||
|
||||
# Multi-source RAG query against the shard cluster.
|
||||
# Usage: make query Q="What is anarcho-capitalism?"
|
||||
QUERY_TOP_K ?= 8
|
||||
|
|
|
|||
122
aborist/cli.py
122
aborist/cli.py
|
|
@ -4,6 +4,7 @@ from __future__ import annotations
|
|||
|
||||
import argparse
|
||||
import json
|
||||
import os
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
|
|
@ -323,8 +324,99 @@ def _cmd_query(args: argparse.Namespace) -> int:
|
|||
)
|
||||
|
||||
|
||||
def _falsify_cache_key(
|
||||
cache_key_value: str,
|
||||
*,
|
||||
state: str,
|
||||
reason: str,
|
||||
by_actor: str,
|
||||
shards_dir: Path | None,
|
||||
db_path: Path | None,
|
||||
) -> dict:
|
||||
"""Mark a providence_cache record as failed/stale/quarantined across shards.
|
||||
|
||||
Searches every shard for the cache_key (it lives in exactly one).
|
||||
Updates the row's falsification_state, appends a falsification log
|
||||
entry, and writes a 'falsify' audit event so the chain records the act.
|
||||
"""
|
||||
import time as _time
|
||||
|
||||
from aborist.store import append_audit, discover_shards, transaction
|
||||
|
||||
if state not in ("failed", "stale", "quarantined"):
|
||||
return {"status": "invalid_state", "value": state}
|
||||
|
||||
paths: list[Path] = (
|
||||
discover_shards(shards_dir) if shards_dir else [Path(db_path)]
|
||||
)
|
||||
|
||||
for sp in paths:
|
||||
c = connect(sp)
|
||||
try:
|
||||
row = c.execute(
|
||||
"SELECT cache_key, falsification_state FROM providence_cache "
|
||||
"WHERE cache_key = ?",
|
||||
(cache_key_value,),
|
||||
).fetchone()
|
||||
if row is None:
|
||||
continue
|
||||
now = int(_time.time())
|
||||
with transaction(c):
|
||||
event_hash = append_audit(
|
||||
c,
|
||||
event_type="falsify",
|
||||
subject_root=cache_key_value,
|
||||
body={
|
||||
"cache_key": cache_key_value,
|
||||
"from_state": row["falsification_state"],
|
||||
"to_state": state,
|
||||
"reason": reason,
|
||||
"by_actor": by_actor,
|
||||
},
|
||||
ts=now,
|
||||
)
|
||||
c.execute(
|
||||
"UPDATE providence_cache "
|
||||
"SET falsification_state = ?, audit_event_hash = ? "
|
||||
"WHERE cache_key = ?",
|
||||
(state, event_hash, cache_key_value),
|
||||
)
|
||||
c.execute(
|
||||
"INSERT INTO falsifications "
|
||||
"(cache_key, state, reason, by_actor, at, audit_event_hash) "
|
||||
"VALUES (?, ?, ?, ?, ?, ?)",
|
||||
(cache_key_value, state, reason, by_actor, now, event_hash),
|
||||
)
|
||||
return {
|
||||
"status": "falsified",
|
||||
"cache_key": cache_key_value,
|
||||
"shard": sp.name,
|
||||
"from_state": row["falsification_state"],
|
||||
"to_state": state,
|
||||
"reason": reason,
|
||||
"by_actor": by_actor,
|
||||
"audit_event_hash": event_hash,
|
||||
"ts": now,
|
||||
}
|
||||
finally:
|
||||
c.close()
|
||||
|
||||
return {"status": "not_found", "cache_key": cache_key_value}
|
||||
|
||||
|
||||
def _cmd_providence(args: argparse.Namespace) -> int:
|
||||
"""List providence_cache records for a document URI or source_root."""
|
||||
"""List providence_cache records or falsify one by cache_key."""
|
||||
if getattr(args, "falsify", None):
|
||||
result = _falsify_cache_key(
|
||||
args.falsify,
|
||||
state=args.state,
|
||||
reason=args.reason or "",
|
||||
by_actor=args.by_actor or os.environ.get("USER", "unknown"),
|
||||
shards_dir=Path(args.global_shards_dir) if args.global_shards_dir else None,
|
||||
db_path=Path(args.db) if args.db else None,
|
||||
)
|
||||
print(json.dumps(result, indent=2))
|
||||
return 0 if result.get("status") == "falsified" else 1
|
||||
conn = (
|
||||
connect_query(args.db, shards_dir=args.global_shards_dir)
|
||||
if args.global_shards_dir
|
||||
|
|
@ -978,11 +1070,37 @@ def build_parser() -> argparse.ArgumentParser:
|
|||
|
||||
prov_cmd = sub.add_parser(
|
||||
"providence",
|
||||
help="list providence_cache records",
|
||||
help="list or falsify providence_cache records",
|
||||
)
|
||||
prov_cmd.add_argument("--document-uri", dest="document_uri", default=None)
|
||||
prov_cmd.add_argument("--source-root", dest="source_root", default=None)
|
||||
prov_cmd.add_argument("--limit", type=int, default=20)
|
||||
prov_cmd.add_argument(
|
||||
"--falsify",
|
||||
default=None,
|
||||
metavar="CACHE_KEY",
|
||||
help=(
|
||||
"mark a providence_cache record as failed/stale/quarantined. "
|
||||
"Lookups will skip it. Audit chain records the act"
|
||||
),
|
||||
)
|
||||
prov_cmd.add_argument(
|
||||
"--state",
|
||||
default="failed",
|
||||
choices=["failed", "stale", "quarantined"],
|
||||
help="falsification state to set (default: failed)",
|
||||
)
|
||||
prov_cmd.add_argument(
|
||||
"--reason",
|
||||
default=None,
|
||||
help="reason text stored in falsifications log",
|
||||
)
|
||||
prov_cmd.add_argument(
|
||||
"--by-actor",
|
||||
dest="by_actor",
|
||||
default=None,
|
||||
help="who is falsifying (default: $USER)",
|
||||
)
|
||||
prov_cmd.set_defaults(func=_cmd_providence)
|
||||
|
||||
evict_cmd = sub.add_parser(
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue