Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions CHANGELOG/v4.md

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion docs/concepts/PHILOSOPHY.md
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,7 @@ The 2,400-token retrieval-API default is a calibrated choice, not an arbitrary o

The v1 surface is small. Feedback-driven belief mutation goes through `apply_feedback`, and every lock through one path. When the system misbehaves, there is one place to look.

Being precise about `(α, β)`, since the aspiration and the code have drifted apart before ([#1168](https://github.com/robotrocketscience/aelfrice/issues/1168)): `apply_feedback` is the *primary* writer, not the only one. Three other paths write it, each deliberately and each leaving an audit trail — `deferred_feedback.sweep_deferred_feedback` (the implicit retrieval lane, with its own smaller epsilon and grace window), `clamp_ghosts.clamp_ghost_alpha` (a one-shot migration clamp), and the consolidation dedup pass (which sums existing evidence when collapsing a duplicate group rather than adding new evidence). The invariants that matter hold across all of them: a user lock is a floor no passive signal moves, a federated peer's belief is read-only locally, and every posterior move that is not a merge writes a `feedback_history` row. The posterior write itself is a single atomic SQL increment inside one `BEGIN IMMEDIATE` transaction with its audit row, so concurrent writers cannot lose each other's evidence and the log cannot disagree with the projection.
Being precise about `(α, β)`, since the aspiration and the code have drifted apart before ([#1168](https://github.com/robotrocketscience/aelfrice/issues/1168)): `apply_feedback` is the *primary* writer, not the only one. Two other paths write it, each deliberately and each leaving an audit trail — `clamp_ghosts.clamp_ghost_alpha` (a one-shot migration clamp) and the consolidation dedup pass (which sums existing evidence when collapsing a duplicate group rather than adding new evidence). A third used to: `deferred_feedback.sweep_deferred_feedback`, the implicit retrieval lane, which [#1162](https://github.com/robotrocketscience/aelfrice/issues/1162) made audit-only. It had no counterweight — `scoring.decay` has no production caller — so exposure alone walked a frequently-retrieved belief's posterior upward without bound, and it contradicted [#1086](https://github.com/robotrocketscience/aelfrice/issues/1086), which had already decided that exposure is not evidence. The invariants that matter hold across all of them: a user lock is a floor no passive signal moves, a federated peer's belief is read-only locally, and every posterior move that is not a merge writes a `feedback_history` row. The posterior write itself is a single atomic SQL increment inside one `BEGIN IMMEDIATE` transaction with its audit row, so concurrent writers cannot lose each other's evidence and the log cannot disagree with the projection.

The earlier research line had a much bigger surface — twenty-nine MCP tools, `wonder`, `reason`, snapshot/diff. It delivered value but also delivered ambiguity. The rebuild started narrow on purpose; v1.x–v3.x have reintroduced breadth (15 MCP tools at v3.3, plus `/aelf:wonder` / `/aelf:reason` / `/aelf:graph` slash surfaces), each addition gated on evidence — a benchmark, an experiment, a clear case where the existing operations don't suffice.

Expand Down
2 changes: 1 addition & 1 deletion docs/user/COMMANDS.md
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ DB resolves from `$AELFRICE_DB`, then `<git-common-dir>/aelfrice/memory.db` when
| `bench [--top-k N]` | Run the deterministic 16-belief × 16-query benchmark. Prints a JSON `BenchmarkReport`. |
| `bench all --out PATH [--canonical] [--adapters CSV] [--smoke]` | (v2.0+, #437) Reproducibility harness — subprocess each academic-suite adapter (mab, locomo, longmemeval, structmemeval, amabench) at the canonical headline cut and merge into one schema-v2 JSON. `--canonical` asserts the run matches `CANONICAL_INVOCATIONS` (full benchmarks per the 2026-05-06 ratification) and refuses if the cut differs. `--smoke` runs the small SMOKE_INVOCATIONS subset. `--adapters` filters; combined with `--canonical` this refuses (cut mismatch). Returns 0 ok / 1 any error / 2 any skipped_data_missing. |
| `tail [--since DUR] [--filter key=value]... [--no-blob] [--no-follow]` | (v1.6+) Live-tail the per-turn hook audit log at `<git-common-dir>/aelfrice/hook_audit.jsonl`. Per fire: a header line (time, hook, tokens, latency, `L0×N L1×M`) plus one indented snippet line per injected belief. `--no-blob` suppresses snippet bodies; `--no-follow` dumps and exits; `--filter` matches fields like `hook=user_prompt_submit` / `lane=L0` (repeatable). See [hook-injection-audit.md](../design/hook-injection-audit.md). |
| `sweep-feedback` | (v1.6+) Run the deferred-feedback sweeper once (#191). Enqueue-on-retrieve is default-on, but the queue has no automatic consumer — this verb is the manual one-shot pass that applies `+ε` (default 0.05) α per enqueued exposure past its grace window. Note this is a *separate*, legacy exposure-as-evidence path: the primary hook retrieval path is audit-only by default since #1086 (see `AELFRICE_EXPOSURE_UPDATES_POSTERIOR`), and #1091 flagged this sweep for the same treatment. |
| `sweep-feedback` | (v1.6+) **Audit** the deferred-feedback queue (#191). Reports how many exposures past their grace window *would* have received `+ε` (default 0.05) α, and what that would total — and changes nothing. #1162 gave this sweep the treatment #1091 flagged it for, so both exposure-as-evidence paths are now audit-only and agree; enqueue-on-retrieve is opt-in in the same change. Because nothing is consumed the numbers are repeatable rather than draining to zero on the first run. `--gc` deletes the banked `enqueued` rows the sweep can no longer act on and reports the count; it is the one destructive action and never implicit. |
| `eval [--corpus PATH]` | Run the relevance-calibration harness (P@K / ROC-AUC / Spearman ρ) on a synthetic corpus. Prints the calibration block; exit 0 on success. |
| `clamp-ghosts [--threshold F] [--target F] [--apply] [--limit N]` | **Hidden / advanced.** One-shot repair tool for stores migrated from pre-v1.0 schemas. Identifies belief rows whose α is inflated above prior yet have zero `feedback_history` and zero `belief_corroborations` entries (audit-trail-less ghosts; α floor `--threshold`, default 4.0). `--target` (default 4.0, must be ≤ threshold) is the α value clamped down to; `--limit` caps rows per call. Default dry-run; `--apply` writes the UPDATE plus a negative-valence `feedback_history` row inside one transaction so the clamp is reversible and idempotent. |
| `scan-derivation --reference PATH [--threshold F] [--n N] [PATH ...]` | (v3.0+, [#681](https://github.com/robotrocketscience/aelfrice/issues/681)) N-gram Jaccard similarity gate against a reference document. Reads each PATH (or stdin via `-` / no args), prints `MATCH [score] label: excerpt` or `clean [score] label`, exits 0 (all clean) / 1 (one or more matched) / 2 (reference unreadable). Designed to drop into a git pre-commit / pre-push hook. Defaults: 3-gram windows, threshold 0.6. |
Expand Down
67 changes: 56 additions & 11 deletions src/aelfrice/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -7051,12 +7051,19 @@ def _print_doctor_session_ring(out: object) -> None:


def _cmd_sweep_feedback(args: argparse.Namespace, out: object) -> int:
"""Process the deferred-feedback queue (#191).
"""Audit the deferred-feedback queue (#191, audit-only since #1162).

Applies +epsilon to the alpha of each belief whose retrieval-
exposure row has cleared its grace window without a contradicting
explicit-feedback event. Cancels rows where an explicit signal
landed within the grace window. Idempotent.
Reports how many rows would have received `+epsilon` under the
pre-#1162 sweeper and what that would have totalled, and mutates
nothing — no alpha, no feedback_history, no queue status. Because
it consumes nothing the numbers are repeatable rather than
draining to zero on the first run.

`--gc` is the one destructive action here and it is never implicit:
it deletes the banked `status='enqueued'` rows the audit just
reported on — exactly those, so the report cannot describe less
than the deletion — and prints the count. Rows past `--limit` are
left alone and called out separately.

Exits 0 unless `--strict` is passed and an exception escapes.
Without `--strict`, errors are logged to stderr and the command
Expand All @@ -7081,13 +7088,23 @@ def _cmd_sweep_feedback(args: argparse.Namespace, out: object) -> int:
limit = int(args.limit) if args.limit is not None else 10_000

store = _open_store()
purged: int | None = None
try:
result = sweep_deferred_feedback(
store,
grace_seconds=grace,
epsilon=eps,
limit=limit,
)
# After the audit, and scoped to exactly the rows it classified.
# Deleting every enqueued row instead would give the destructive
# verb wider scope than the report justifying it: on a six-figure
# queue the audit describes the first `limit` rows and the purge
# would remove all of them.
if getattr(args, "gc", False):
purged = store.purge_enqueued_deferred_feedback(
result.audited_row_ids
)
except Exception as exc: # noqa: BLE001 - cron-safe by default
print(f"aelf sweep-feedback: {exc}", file=sys.stderr)
if getattr(args, "strict", False):
Expand All @@ -7100,14 +7117,31 @@ def _cmd_sweep_feedback(args: argparse.Namespace, out: object) -> int:
pass

print(
f"sweep-feedback: applied={result.applied} "
f"cancelled={result.cancelled} "
f"skipped_no_belief={result.skipped_no_belief} "
f"sweep-feedback (audit-only, no alpha changed): "
f"would_apply={result.would_apply} "
f"would_cancel={result.would_cancel} "
f"would_skip_no_belief={result.would_skip_no_belief} "
f"would_skip_locked={result.would_skip_locked} "
f"would_skip_foreign={result.would_skip_foreign} "
f"pending_in_grace={result.pending_unmet_grace} "
f"pending_beyond_limit={result.pending_beyond_limit} "
f"alpha_withheld={result.alpha_withheld:.4f} "
f"epsilon={result.epsilon_used} "
f"grace_seconds={result.grace_seconds_used}",
file=out, # type: ignore[arg-type]
)
if purged is not None:
print(
f"sweep-feedback: --gc deleted {purged} banked enqueued row(s)",
file=out, # type: ignore[arg-type]
)
if result.pending_beyond_limit:
print(
f"sweep-feedback: {result.pending_beyond_limit} eligible row(s) "
f"past --limit ({limit}) were neither reported on above nor "
"collected; re-run, or raise --limit to widen both together",
file=out, # type: ignore[arg-type]
)
return 0


Expand Down Expand Up @@ -8950,9 +8984,9 @@ def _positive_int(s: str) -> int:
p_sweep_feedback = sub.add_parser(
"sweep-feedback",
help=(
"process deferred retrieval-exposure feedback queue (#191): "
"apply +epsilon to beliefs whose grace window elapsed without "
"a contradicting explicit signal"
"audit the deferred retrieval-exposure feedback queue (#191): "
"report what the pre-#1162 sweeper would have applied. Changes "
"no belief; pass --gc to drop the banked rows"
),
)
p_sweep_feedback.add_argument(
Expand Down Expand Up @@ -8980,6 +9014,17 @@ def _positive_int(s: str) -> int:
"--strict", action="store_true",
help="exit non-zero on any exception (default: log + exit 0 for cron)",
)
p_sweep_feedback.add_argument(
"--gc", action="store_true",
help=(
"delete the banked status='enqueued' rows this run reported "
"on (#1162). The audit-only sweeper cannot act on these, so "
"they are a record rather than pending work. Scoped to the "
"audited rows, so --limit bounds the deletion and the report "
"together; leaves 'applied' and 'cancelled' rows — the trail "
"of sweeps that did run — alone. Idempotent"
),
)
p_sweep_feedback.set_defaults(func=_cmd_sweep_feedback)

# Hidden: one-shot maintenance for pre-migration ghost-α rows
Expand Down
Loading
Loading