From 3d724c4d0eaedbc2efa3660bd63b967ecac4d07b Mon Sep 17 00:00:00 2001 From: rrs <276464689+robotrocketscience@users.noreply.github.com> Date: Wed, 6 May 2026 15:19:16 -0700 Subject: [PATCH 01/11] feat(cli): add aelf core subcommand (#439) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Implements _cmd_core with _qualifies_core and _emit_core helpers. Composition over list_locked_beliefs(), list_belief_ids(), and get_belief() — no new store method. Subparser registered after p_locked with --locked-only/--no-locked as a mutually exclusive group. Spec: docs/feature-aelf-core.md. --- src/aelfrice/cli.py | 148 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 148 insertions(+) diff --git a/src/aelfrice/cli.py b/src/aelfrice/cli.py index 0a63d1579..48b3ab87d 100644 --- a/src/aelfrice/cli.py +++ b/src/aelfrice/cli.py @@ -1278,6 +1278,115 @@ def _cmd_confirm(args: argparse.Namespace, out: object) -> int: return 0 +_CORE_MIN_CORROBORATION: int = 2 +_CORE_MIN_POSTERIOR: float = 2.0 / 3.0 +_CORE_MIN_ALPHA_BETA: int = 4 + + +def _qualifies_core(b: object, args: argparse.Namespace) -> bool: + """Return True if belief b meets any non-lock core signal.""" + alpha: float = b.alpha # type: ignore[attr-defined] + beta: float = b.beta # type: ignore[attr-defined] + corr: int = b.corroboration_count # type: ignore[attr-defined] + if corr >= args.min_corroboration: + return True + ab = alpha + beta + if ab >= args.min_alpha_beta and (alpha / ab) >= args.min_posterior: + return True + return False + + +def _emit_core( + locked: list[object], + candidates: list[object], + args: argparse.Namespace, + out: object, +) -> None: + seen: set[str] = {b.id for b in locked} # type: ignore[attr-defined] + unlocked = [b for b in candidates if b.id not in seen] # type: ignore[attr-defined] + + def _posterior(b: object) -> float: + a: float = b.alpha # type: ignore[attr-defined] + bb: float = b.beta # type: ignore[attr-defined] + return a / (a + bb) + + unlocked.sort(key=lambda b: (-_posterior(b), b.id)) # type: ignore[attr-defined] + results = list(locked) + unlocked + + if args.limit is not None: + results = results[: args.limit] + + if not results: + print("no core beliefs", file=out) # type: ignore[arg-type] + return + + if args.json: + rows = [] + for b in results: + signals: list[str] = [] + if b.lock_level != "none": # type: ignore[attr-defined] + signals.append("lock") + if b.corroboration_count >= args.min_corroboration: # type: ignore[attr-defined] + signals.append("corroboration") + alpha: float = b.alpha # type: ignore[attr-defined] + beta: float = b.beta # type: ignore[attr-defined] + ab = alpha + beta + if ab >= args.min_alpha_beta and (alpha / ab) >= args.min_posterior: + signals.append("posterior") + rows.append({ + "id": b.id, # type: ignore[attr-defined] + "content": b.content, # type: ignore[attr-defined] + "lock_level": b.lock_level, # type: ignore[attr-defined] + "alpha": alpha, + "beta": beta, + "posterior_mean": round(alpha / ab, 3) if ab else 0.0, + "corroboration_count": b.corroboration_count, # type: ignore[attr-defined] + "signals": sorted(set(signals)), + }) + print(json.dumps(rows, indent=2), file=out) # type: ignore[arg-type] + return + + for b in results: + alpha = b.alpha # type: ignore[attr-defined] + beta = b.beta # type: ignore[attr-defined] + corr = b.corroboration_count # type: ignore[attr-defined] + ab = alpha + beta + parts: list[str] = [] + if b.lock_level != "none": # type: ignore[attr-defined] + parts.append("LOCK") + if corr >= args.min_corroboration: + parts.append(f"CORR={corr}") + if ab >= args.min_alpha_beta and (alpha / ab) >= args.min_posterior: + parts.append(f"α={alpha:.1f}") + parts.append(f"β={beta:.1f}") + parts.append(f"μ={alpha / ab:.3f}") + tag = f" [{','.join(parts)}]" if parts else "" + print(f"{b.id}{tag}: {b.content}", file=out) # type: ignore[arg-type, attr-defined] + + +def _cmd_core(args: argparse.Namespace, out: object) -> int: + """Surface load-bearing beliefs: locked ∪ corroborated ∪ high-posterior. + + Spec: docs/feature-aelf-core.md. No new store method — composition over + list_locked_beliefs(), list_belief_ids(), and get_belief(). + """ + store = _open_store() + try: + locked: list[object] = [] if args.no_locked else store.list_locked_beliefs() + candidates: list[object] = [] + if not args.locked_only: + for bid in store.list_belief_ids(): + b = store.get_belief(bid) + if b is None or b.lock_level != "none": + continue + if _qualifies_core(b, args): + candidates.append(b) + finally: + store.close() + _emit_core(locked, candidates, args, out) + return 0 + + def _cmd_promote(args: argparse.Namespace, out: object) -> int: """Promote agent_inferred -> user_validated. Alias of `aelf validate`.""" return _cmd_validate(args, out) @@ -3493,6 +3602,45 @@ def build_parser(*, show_advanced: bool = False) -> argparse.ArgumentParser: ) p_locked.set_defaults(func=_cmd_locked) + # Read-only lens: load-bearing beliefs (locked ∪ corroborated ∪ high-posterior). + p_core = sub.add_parser( + "core", + help="surface load-bearing beliefs: locked ∪ corroborated ∪ high-posterior", + ) + p_core.add_argument( + "--json", action="store_true", dest="json", + help="emit JSON list instead of text", + ) + p_core.add_argument( + "--limit", type=int, default=None, metavar="N", + help="cap result count after filtering/sort", + ) + p_core.add_argument( + "--min-corroboration", type=int, default=_CORE_MIN_CORROBORATION, + metavar="N", + help="corroboration_count threshold (default 2; 0 disables)", + ) + p_core.add_argument( + "--min-posterior", type=float, default=_CORE_MIN_POSTERIOR, + metavar="FLOAT", + help="posterior-mean threshold (default 2/3; 0.0 disables)", + ) + p_core.add_argument( + "--min-alpha-beta", type=int, default=_CORE_MIN_ALPHA_BETA, + metavar="N", + help="α+β co-gate for posterior signal (default 4)", + ) + _core_excl = p_core.add_mutually_exclusive_group() + _core_excl.add_argument( + "--locked-only", action="store_true", + help="return only the locked subset", + ) + _core_excl.add_argument( + "--no-locked", action="store_true", + help="suppress locked beliefs (surface corroboration/posterior only)", + ) + p_core.set_defaults(func=_cmd_core) + # Hidden: belief lifecycle inverse of `lock` / `validate`. Power-user. p_demote = sub.add_parser( "demote", From 610645ff4849bf570aa8abb65f241bcef51232da Mon Sep 17 00:00:00 2001 From: rrs <276464689+robotrocketscience@users.noreply.github.com> Date: Wed, 6 May 2026 15:21:12 -0700 Subject: [PATCH 02/11] test(cli): unit tests for aelf core (#439) --- tests/test_cli_core.py | 283 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 283 insertions(+) create mode 100644 tests/test_cli_core.py diff --git a/tests/test_cli_core.py b/tests/test_cli_core.py new file mode 100644 index 000000000..e7ac929e8 --- /dev/null +++ b/tests/test_cli_core.py @@ -0,0 +1,283 @@ +"""Tests for `aelf core` CLI subcommand (#439). + +Five-belief fixture matrix per spec (docs/feature-aelf-core.md): + b-locked lock=user alpha=1 beta=1 corr=0 → yes (LOCK) + b-corr lock=none alpha=1 beta=1 corr=3 → yes (CORR) + b-posterior lock=none alpha=4 beta=1 corr=0 → yes (μ=0.8, α+β=5) + b-thin-post lock=none alpha=2 beta=1 corr=0 → no (μ=0.667 but α+β=3) + b-prior lock=none alpha=1 beta=1 corr=0 → no + +Tests cover all 8 spec scenarios. +""" +from __future__ import annotations + +import io +import json +from pathlib import Path + +import pytest + +from aelfrice.cli import main +from aelfrice.models import ( + BELIEF_FACTUAL, + CORROBORATION_SOURCE_CLI_REMEMBER, + LOCK_NONE, + LOCK_USER, + ORIGIN_AGENT_INFERRED, + Belief, +) +from aelfrice.store import MemoryStore + + +@pytest.fixture(autouse=True) +def isolated_db(tmp_path: Path, monkeypatch: pytest.MonkeyPatch) -> Path: + p = tmp_path / "aelf.db" + monkeypatch.setenv("AELFRICE_DB", str(p)) + return p + + +def _run(*argv: str) -> tuple[int, str]: + buf = io.StringIO() + code = main(argv=list(argv), out=buf) + return code, buf.getvalue() + + +def _make_belief( + bid: str, + content: str, + lock_level: str = LOCK_NONE, + alpha: float = 1.0, + beta: float = 1.0, +) -> Belief: + return Belief( + id=bid, + content=content, + content_hash="hash_" + bid[:6], + alpha=alpha, + beta=beta, + type=BELIEF_FACTUAL, + lock_level=lock_level, + locked_at="2026-05-06T00:00:00Z" if lock_level != LOCK_NONE else None, + demotion_pressure=0, + created_at="2026-05-06T00:00:00Z", + last_retrieved_at=None, + origin=ORIGIN_AGENT_INFERRED, + ) + + +def _seed_store(db: Path) -> dict[str, Belief]: + beliefs = { + "b-locked": _make_belief("b0locked0000000000", "locked ground truth", lock_level=LOCK_USER), + "b-corr": _make_belief("b0corr00000000000a", "independently corroborated"), + "b-posterior": _make_belief("b0posterior000000a", "strong posterior", alpha=4.0, beta=1.0), + "b-thin": _make_belief("b0thinpost000000aa", "thin posterior", alpha=2.0, beta=1.0), + "b-prior": _make_belief("b0prior000000000aa", "flat prior"), + } + s = MemoryStore(str(db)) + try: + for b in beliefs.values(): + s.insert_belief(b) + # b-corr: record 3 corroboration rows via the public API + for _ in range(3): + s.record_corroboration( + beliefs["b-corr"].id, + source_type=CORROBORATION_SOURCE_CLI_REMEMBER, + ) + finally: + s.close() + return beliefs + + +# --- scenario 1: default text output ----------------------------------------- + + +def test_core_default_includes_locked(isolated_db: Path) -> None: + b = _seed_store(isolated_db) + code, out = _run("core") + assert code == 0 + assert b["b-locked"].id in out + + +def test_core_default_includes_corroborated(isolated_db: Path) -> None: + b = _seed_store(isolated_db) + code, out = _run("core") + assert code == 0 + assert b["b-corr"].id in out + + +def test_core_default_includes_posterior(isolated_db: Path) -> None: + b = _seed_store(isolated_db) + code, out = _run("core") + assert code == 0 + assert b["b-posterior"].id in out + + +def test_core_default_excludes_thin_posterior(isolated_db: Path) -> None: + b = _seed_store(isolated_db) + _, out = _run("core") + assert b["b-thin"].id not in out + + +def test_core_default_excludes_flat_prior(isolated_db: Path) -> None: + b = _seed_store(isolated_db) + _, out = _run("core") + assert b["b-prior"].id not in out + + +def test_core_tag_block_lock(isolated_db: Path) -> None: + b = _seed_store(isolated_db) + _, out = _run("core") + assert f"{b['b-locked'].id} [LOCK]" in out + + +def test_core_tag_block_corr(isolated_db: Path) -> None: + b = _seed_store(isolated_db) + _, out = _run("core") + assert "CORR=3" in out + + +def test_core_tag_block_posterior(isolated_db: Path) -> None: + b = _seed_store(isolated_db) + _, out = _run("core") + assert "μ=0.800" in out + + +# --- scenario 2: --json round-trip ------------------------------------------- + + +def test_core_json_parses(isolated_db: Path) -> None: + _seed_store(isolated_db) + _, out = _run("core", "--json") + rows = json.loads(out) + assert isinstance(rows, list) + + +def test_core_json_signals_lock(isolated_db: Path) -> None: + b = _seed_store(isolated_db) + _, out = _run("core", "--json") + rows = json.loads(out) + locked_row = next(r for r in rows if r["id"] == b["b-locked"].id) + assert "lock" in locked_row["signals"] + + +def test_core_json_signals_corroboration(isolated_db: Path) -> None: + b = _seed_store(isolated_db) + _, out = _run("core", "--json") + rows = json.loads(out) + corr_row = next(r for r in rows if r["id"] == b["b-corr"].id) + assert "corroboration" in corr_row["signals"] + + +def test_core_json_signals_posterior(isolated_db: Path) -> None: + b = _seed_store(isolated_db) + _, out = _run("core", "--json") + rows = json.loads(out) + post_row = next(r for r in rows if r["id"] == b["b-posterior"].id) + assert "posterior" in post_row["signals"] + + +def test_core_json_signals_nonempty(isolated_db: Path) -> None: + _seed_store(isolated_db) + _, out = _run("core", "--json") + rows = json.loads(out) + for row in rows: + assert len(row["signals"]) >= 1 + + +# --- scenario 3: --locked-only ----------------------------------------------- + + +def test_core_locked_only_exits_zero(isolated_db: Path) -> None: + _seed_store(isolated_db) + code, _ = _run("core", "--locked-only") + assert code == 0 + + +def test_core_locked_only_returns_locked(isolated_db: Path) -> None: + b = _seed_store(isolated_db) + _, out = _run("core", "--locked-only") + assert b["b-locked"].id in out + + +def test_core_locked_only_excludes_corr(isolated_db: Path) -> None: + b = _seed_store(isolated_db) + _, out = _run("core", "--locked-only") + assert b["b-corr"].id not in out + + +def test_core_locked_only_excludes_posterior(isolated_db: Path) -> None: + b = _seed_store(isolated_db) + _, out = _run("core", "--locked-only") + assert b["b-posterior"].id not in out + + +# --- scenario 4: --no-locked ------------------------------------------------- + + +def test_core_no_locked_suppresses_locked(isolated_db: Path) -> None: + b = _seed_store(isolated_db) + _, out = _run("core", "--no-locked") + assert b["b-locked"].id not in out + + +def test_core_no_locked_includes_corr(isolated_db: Path) -> None: + b = _seed_store(isolated_db) + _, out = _run("core", "--no-locked") + assert b["b-corr"].id in out + + +def test_core_no_locked_includes_posterior(isolated_db: Path) -> None: + b = _seed_store(isolated_db) + _, out = _run("core", "--no-locked") + assert b["b-posterior"].id in out + + +# --- scenario 5: mutual exclusion exit 2 ------------------------------------- + + +def test_core_locked_only_and_no_locked_exit_two( + isolated_db: Path, capsys: pytest.CaptureFixture[str] +) -> None: + with pytest.raises(SystemExit) as exc: + _run("core", "--locked-only", "--no-locked") + assert exc.value.code == 2 + + +# --- scenario 6: --limit 1 returns locked first ------------------------------ + + +def test_core_limit_one_returns_locked(isolated_db: Path) -> None: + b = _seed_store(isolated_db) + _, out = _run("core", "--limit", "1") + assert b["b-locked"].id in out + assert b["b-corr"].id not in out + assert b["b-posterior"].id not in out + + +# --- scenario 7: empty store prints sentinel ---------------------------------- + + +def test_core_empty_store_exits_zero(isolated_db: Path) -> None: + code, _ = _run("core") + assert code == 0 + + +def test_core_empty_store_message(isolated_db: Path) -> None: + _, out = _run("core") + assert out.strip() == "no core beliefs" + + +# --- scenario 8: threshold flags --------------------------------------------- + + +def test_core_min_corroboration_raised_drops_corr(isolated_db: Path) -> None: + b = _seed_store(isolated_db) + _, out = _run("core", "--min-corroboration", "4") + assert b["b-corr"].id not in out + + +def test_core_disabled_posterior_and_corr_includes_all_nonprior(isolated_db: Path) -> None: + """--min-posterior 0.0 --min-alpha-beta 0 includes b-thin (μ=0.667, α+β=3).""" + b = _seed_store(isolated_db) + _, out = _run("core", "--min-posterior", "0.0", "--min-alpha-beta", "0") + assert b["b-thin"].id in out From 6824e7f9c410742be51f280f40a0c7175fdb1c2d Mon Sep 17 00:00:00 2001 From: rrs <276464689+robotrocketscience@users.noreply.github.com> Date: Wed, 6 May 2026 15:21:24 -0700 Subject: [PATCH 03/11] feat(slash_commands): add /aelf:core (#439) --- src/aelfrice/slash_commands/core.md | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100644 src/aelfrice/slash_commands/core.md diff --git a/src/aelfrice/slash_commands/core.md b/src/aelfrice/slash_commands/core.md new file mode 100644 index 000000000..e2081dec8 --- /dev/null +++ b/src/aelfrice/slash_commands/core.md @@ -0,0 +1,18 @@ +--- +name: aelf:core +description: Surface load-bearing beliefs — locked ∪ corroborated (≥2 sources) ∪ high-posterior (μ ≥ 2/3, α+β ≥ 4). Read-only. +argument-hint: Optional flags, e.g. --json or --locked-only +allowed-tools: + - Bash +--- + +List the beliefs that anchor the store: any belief that is user-locked, +independently corroborated from at least two sources, or has a strong +multi-event positive posterior. This is the operator's first-look lens +when checking whether the store foundation is healthy. + + + +Run: `uv run aelf core $ARGUMENTS` +Display the output verbatim. Do not add commentary. + From 31181c8b904c158d8717e904fe28c2d829599811 Mon Sep 17 00:00:00 2001 From: rrs <276464689+robotrocketscience@users.noreply.github.com> Date: Wed, 6 May 2026 15:21:39 -0700 Subject: [PATCH 04/11] test(slash_commands): add core to EXPECTED_COMMANDS (#439) --- tests/test_slash_commands.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/test_slash_commands.py b/tests/test_slash_commands.py index 2c429293c..f6d2a1951 100644 --- a/tests/test_slash_commands.py +++ b/tests/test_slash_commands.py @@ -49,6 +49,8 @@ # test_slash_commands_match_visible_cli_subcommands both enforce the # slash file exists and matches the CLI surface. "delete", + # v2.0 (#439) — load-bearing belief lens (locked ∪ corroborated ∪ high-posterior). + "core", ) From 39bd8f950756237bf12dfd1977d8e074e1175e03 Mon Sep 17 00:00:00 2001 From: rrs <276464689+robotrocketscience@users.noreply.github.com> Date: Wed, 6 May 2026 15:21:51 -0700 Subject: [PATCH 05/11] docs(COMMANDS): add aelf core to command reference (#439) --- docs/COMMANDS.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/COMMANDS.md b/docs/COMMANDS.md index c0449806b..1179d42b0 100644 --- a/docs/COMMANDS.md +++ b/docs/COMMANDS.md @@ -18,6 +18,7 @@ DB resolves from `$AELFRICE_DB`, then `/aelfrice/memory.db` when | `search [--budget N]` | L0 locked + L2.5 entity-index (v1.3+) + L1 FTS5 BM25, token-budgeted (default 2,400 at v1.3+, 2,000 prior). L2.5 default-on; disable via `[retrieval] entity_index_enabled = false` in `.aelfrice.toml` or `AELFRICE_ENTITY_INDEX=0` in the env. Distinguishes "store empty" from "no match". | | `lock ` | Insert at `(α, β) = (9.0, 0.5)` with `lock_level=user`. Idempotent — re-lock upgrades existing. | | `locked [--pressured]` | List locks. With `--pressured`, only those with `demotion_pressure > 0`. | +| `core [--json] [--limit N] [--min-corroboration N] [--min-posterior FLOAT] [--min-alpha-beta N] [--locked-only] [--no-locked]` | (v2.0+, #439) Surface load-bearing beliefs: locked ∪ {corroboration ≥ 2} ∪ {posterior ≥ 2/3 with α+β ≥ 4}. Read-only. | | `unlock ` | Drop a user-lock without changing origin. Idempotent. Writes a `lock:unlock` audit row. | | `delete [--yes] [--force]` | Hard-delete a belief: removes the belief row, FTS entry, edges (src and dst), and entity index rows. Writes one audit row to `feedback_history` (valence=-1.0, source=`user_deleted`) before the cascade so the forensic record survives. Confirmation prompt by default — prints belief content and requires the user to type the first 8 characters of the id; `--yes` skips the prompt. Refuses locked (`lock_level=user`) beliefs without `--force`; with `--force` the audit source becomes `user_deleted_force`. Exit 0 on success; exit 1 on not-found, locked-without-force, or prompt mismatch. | | `demote ` | Drop a user lock (one tier per call: lock first, then user_validated). Delegates to `unlock` for the lock-drop path so an audit row is always written. | From b186c9417e0f9d77613b7872b00747ce54b706b5 Mon Sep 17 00:00:00 2001 From: rrs <276464689+robotrocketscience@users.noreply.github.com> Date: Wed, 6 May 2026 18:52:43 -0700 Subject: [PATCH 06/11] =?UTF-8?q?fix(cli):=20guard=20=5Fposterior=20agains?= =?UTF-8?q?t=20=CE=B1+=CE=B2=3D=3D0=20(#439)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Sort path in _emit_core dereferences alpha/(alpha+beta) on every belief; a malformed belief with alpha=beta=0 would raise ZeroDivisionError and crash 'aelf core'. The JSON path already guarded this case (line 1342: 'round(alpha / ab, 3) if ab else 0.0'); the sort path didn't. Mirror the same fallback (μ=0.0 when α+β==0) in the inner _posterior helper. Add a regression test (test_core_zero_alpha_beta_does_not_crash) that constructs a Belief with alpha=beta=0 and asserts 'aelf core' returns 0 without raising. Found by Sourcery review on PR #463. --- src/aelfrice/cli.py | 3 ++- tests/test_cli_core.py | 25 +++++++++++++++++++++++++ 2 files changed, 27 insertions(+), 1 deletion(-) diff --git a/src/aelfrice/cli.py b/src/aelfrice/cli.py index 48b3ab87d..a1389ae2f 100644 --- a/src/aelfrice/cli.py +++ b/src/aelfrice/cli.py @@ -1308,7 +1308,8 @@ def _emit_core( def _posterior(b: object) -> float: a: float = b.alpha # type: ignore[attr-defined] bb: float = b.beta # type: ignore[attr-defined] - return a / (a + bb) + ab = a + bb + return a / ab if ab > 0 else 0.0 unlocked.sort(key=lambda b: (-_posterior(b), b.id)) # type: ignore[attr-defined] results = list(locked) + unlocked diff --git a/tests/test_cli_core.py b/tests/test_cli_core.py index e7ac929e8..68e8e1392 100644 --- a/tests/test_cli_core.py +++ b/tests/test_cli_core.py @@ -281,3 +281,28 @@ def test_core_disabled_posterior_and_corr_includes_all_nonprior(isolated_db: Pat b = _seed_store(isolated_db) _, out = _run("core", "--min-posterior", "0.0", "--min-alpha-beta", "0") assert b["b-thin"].id in out + + +# --- scenario 9: defensive — α+β==0 must not crash sort ---------------------- + + +def test_core_zero_alpha_beta_does_not_crash(isolated_db: Path) -> None: + """Belief with alpha=beta=0 must not raise ZeroDivisionError in sort path.""" + s = MemoryStore(str(isolated_db)) + try: + s.insert_belief( + _make_belief("b0zeroab0000000000", "zero ab edge case", alpha=0.0, beta=0.0), + ) + s.insert_belief( + _make_belief( + "b0postlive00000000", + "live posterior", + alpha=4.0, + beta=1.0, + ), + ) + finally: + s.close() + code, out = _run("core") + assert code == 0 + assert "b0postlive00000000" in out From da00bf5a4d3a96accb145b018706edc4fd2947b7 Mon Sep 17 00:00:00 2001 From: rrs <276464689+robotrocketscience@users.noreply.github.com> Date: Wed, 6 May 2026 18:53:04 -0700 Subject: [PATCH 07/11] docs(cli): clarify aelf core threshold-flag help text (#439) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Sourcery flagged a semantics mismatch: help text said '0 disables' but the implementation reads as 'threshold = 0 admits any non-negative value'. Existing test test_core_disabled_posterior_and_corr_includes_all_nonprior asserts b-thin (posterior-only candidate) is included with --min-posterior 0.0 --min-alpha-beta 0, which only holds under the lowering reading — so the implementation is intentional and the test pins it; only the help text was misleading. Reword help to 'lower to widen lens — 0 admits …' so the documented behavior matches code + existing test. No semantics change. Spec memo (docs/feature-aelf-core.md, PR #456) flag table also says '0 disables'; that is a separate doc-edit follow-up — not flipped here to keep this PR focused on the Sourcery findings. --- src/aelfrice/cli.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/aelfrice/cli.py b/src/aelfrice/cli.py index a1389ae2f..080e18672 100644 --- a/src/aelfrice/cli.py +++ b/src/aelfrice/cli.py @@ -3619,12 +3619,14 @@ def build_parser(*, show_advanced: bool = False) -> argparse.ArgumentParser: p_core.add_argument( "--min-corroboration", type=int, default=_CORE_MIN_CORROBORATION, metavar="N", - help="corroboration_count threshold (default 2; 0 disables)", + help="corroboration_count threshold (default 2; lower to widen " + "lens — 0 admits any non-negative count)", ) p_core.add_argument( "--min-posterior", type=float, default=_CORE_MIN_POSTERIOR, metavar="FLOAT", - help="posterior-mean threshold (default 2/3; 0.0 disables)", + help="posterior-mean threshold (default 2/3; lower to widen " + "lens — 0.0 admits any belief that passes --min-alpha-beta)", ) p_core.add_argument( "--min-alpha-beta", type=int, default=_CORE_MIN_ALPHA_BETA, From 134ce97385f55c58c3b820e2ec86c504c4f10d81 Mon Sep 17 00:00:00 2001 From: rrs <276464689+robotrocketscience@users.noreply.github.com> Date: Wed, 6 May 2026 18:53:21 -0700 Subject: [PATCH 08/11] test(cli_core): assert non-core beliefs absent from --json output (#439) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Sourcery noted that test_core_default_includes_* asserts b-thin and b-prior are excluded from default text output, but test_core_json_parses only checked structure — the JSON path could silently regress and emit non-core rows without the test catching it. Mirror the text-mode exclusion assertion: at default thresholds, the JSON row set must not contain b-thin or b-prior ids. --- tests/test_cli_core.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/tests/test_cli_core.py b/tests/test_cli_core.py index 68e8e1392..71df3c94b 100644 --- a/tests/test_cli_core.py +++ b/tests/test_cli_core.py @@ -146,10 +146,16 @@ def test_core_tag_block_posterior(isolated_db: Path) -> None: def test_core_json_parses(isolated_db: Path) -> None: - _seed_store(isolated_db) + b = _seed_store(isolated_db) _, out = _run("core", "--json") rows = json.loads(out) assert isinstance(rows, list) + # JSON output must apply the same core-filter as text mode: + # b-thin (μ=0.667, α+β=3) and b-prior (μ=0.5, α+β=2) are excluded + # at default thresholds. + row_ids = {row["id"] for row in rows} + assert b["b-thin"].id not in row_ids + assert b["b-prior"].id not in row_ids def test_core_json_signals_lock(isolated_db: Path) -> None: From d03d159cf95b0112876c28c98a3e7d882168c9b2 Mon Sep 17 00:00:00 2001 From: rrs <276464689+robotrocketscience@users.noreply.github.com> Date: Thu, 7 May 2026 20:59:39 -0700 Subject: [PATCH 09/11] refactor(cli): use LOCK_NONE constant in aelf core (#439) Replace three hardcoded "none" string literals in _emit_core / _cmd_core with the LOCK_NONE constant from aelfrice.models, matching the existing LOCK_USER usage pattern elsewhere in cli.py. Sourcery nit; no behavior change. --- src/aelfrice/cli.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/aelfrice/cli.py b/src/aelfrice/cli.py index 080e18672..7aed9c017 100644 --- a/src/aelfrice/cli.py +++ b/src/aelfrice/cli.py @@ -65,6 +65,7 @@ EDGE_SUPERSEDES, EDGE_SUPPORTS, INGEST_SOURCE_CLI_REMEMBER, + LOCK_NONE, LOCK_USER, ORIGIN_USER_STATED, ORIGIN_USER_VALIDATED, @@ -1325,7 +1326,7 @@ def _posterior(b: object) -> float: rows = [] for b in results: signals: list[str] = [] - if b.lock_level != "none": # type: ignore[attr-defined] + if b.lock_level != LOCK_NONE: # type: ignore[attr-defined] signals.append("lock") if b.corroboration_count >= args.min_corroboration: # type: ignore[attr-defined] signals.append("corroboration") @@ -1353,7 +1354,7 @@ def _posterior(b: object) -> float: corr = b.corroboration_count # type: ignore[attr-defined] ab = alpha + beta parts: list[str] = [] - if b.lock_level != "none": # type: ignore[attr-defined] + if b.lock_level != LOCK_NONE: # type: ignore[attr-defined] parts.append("LOCK") if corr >= args.min_corroboration: parts.append(f"CORR={corr}") @@ -1378,7 +1379,7 @@ def _cmd_core(args: argparse.Namespace, out: object) -> int: if not args.locked_only: for bid in store.list_belief_ids(): b = store.get_belief(bid) - if b is None or b.lock_level != "none": + if b is None or b.lock_level != LOCK_NONE: continue if _qualifies_core(b, args): candidates.append(b) From a60db1d10703c6593d84e4ca41eb8d9d92987363 Mon Sep 17 00:00:00 2001 From: rrs <276464689+robotrocketscience@users.noreply.github.com> Date: Thu, 7 May 2026 21:00:09 -0700 Subject: [PATCH 10/11] fix(cli): guard alpha/ab division when ab==0 in aelf core (#439) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Three sites in _qualifies_core / _emit_core (JSON + text paths) performed alpha/ab guarded only by `ab >= args.min_alpha_beta`. With `--min-alpha-beta 0` (a documented valid value: 'admits any belief that passes --min-alpha-beta'), a belief with α+β==0 satisfies the gate and the division raises ZeroDivisionError. The `_posterior` inner function already had the `ab > 0` guard from #439; its three siblings did not. Add the same guard to all three sites. New regression test `test_core_zero_alpha_beta_with_min_ab_zero_does_not_crash` exercises the unguarded path explicitly — the existing `test_core_zero_alpha_beta_does_not_crash` only covered the sort path because default `min_alpha_beta=4` short-circuits before the division. Refs CodeRabbit + Sourcery review on #463. --- src/aelfrice/cli.py | 6 +++--- tests/test_cli_core.py | 20 ++++++++++++++++++++ 2 files changed, 23 insertions(+), 3 deletions(-) diff --git a/src/aelfrice/cli.py b/src/aelfrice/cli.py index 7aed9c017..8901d093d 100644 --- a/src/aelfrice/cli.py +++ b/src/aelfrice/cli.py @@ -1292,7 +1292,7 @@ def _qualifies_core(b: object, args: argparse.Namespace) -> bool: if corr >= args.min_corroboration: return True ab = alpha + beta - if ab >= args.min_alpha_beta and (alpha / ab) >= args.min_posterior: + if ab > 0 and ab >= args.min_alpha_beta and (alpha / ab) >= args.min_posterior: return True return False @@ -1333,7 +1333,7 @@ def _posterior(b: object) -> float: alpha: float = b.alpha # type: ignore[attr-defined] beta: float = b.beta # type: ignore[attr-defined] ab = alpha + beta - if ab >= args.min_alpha_beta and (alpha / ab) >= args.min_posterior: + if ab > 0 and ab >= args.min_alpha_beta and (alpha / ab) >= args.min_posterior: signals.append("posterior") rows.append({ "id": b.id, # type: ignore[attr-defined] @@ -1358,7 +1358,7 @@ def _posterior(b: object) -> float: parts.append("LOCK") if corr >= args.min_corroboration: parts.append(f"CORR={corr}") - if ab >= args.min_alpha_beta and (alpha / ab) >= args.min_posterior: + if ab > 0 and ab >= args.min_alpha_beta and (alpha / ab) >= args.min_posterior: parts.append(f"α={alpha:.1f}") parts.append(f"β={beta:.1f}") parts.append(f"μ={alpha / ab:.3f}") diff --git a/tests/test_cli_core.py b/tests/test_cli_core.py index 71df3c94b..d282af3a3 100644 --- a/tests/test_cli_core.py +++ b/tests/test_cli_core.py @@ -312,3 +312,23 @@ def test_core_zero_alpha_beta_does_not_crash(isolated_db: Path) -> None: code, out = _run("core") assert code == 0 assert "b0postlive00000000" in out + + +def test_core_zero_alpha_beta_with_min_ab_zero_does_not_crash( + isolated_db: Path, +) -> None: + """`--min-alpha-beta 0` must not enable the alpha/ab division on an α+β==0 belief. + + The default test above passes only because `min_alpha_beta=4` short-circuits + the qualify check before the division. This variant exercises the actual + unguarded sites at the JSON and text emission paths. + """ + s = MemoryStore(str(isolated_db)) + try: + s.insert_belief( + _make_belief("b0zeroab0000000000", "zero ab edge case", alpha=0.0, beta=0.0), + ) + finally: + s.close() + code, _ = _run("core", "--min-alpha-beta", "0") + assert code == 0 From a89bd81d3f852a3656dd969df718e5bce13f2c58 Mon Sep 17 00:00:00 2001 From: rrs <276464689+robotrocketscience@users.noreply.github.com> Date: Thu, 7 May 2026 21:00:22 -0700 Subject: [PATCH 11/11] test(cli_core): drop CodeQL-flagged unused b assignments (#439) `test_core_tag_block_corr` and `test_core_tag_block_posterior` assigned `b = _seed_store(isolated_db)` but never referenced `b`; the assertions match raw substrings in stdout. Replace with bare `_seed_store(isolated_db)` calls to clear the CodeQL py/unused-local-variable warnings. --- tests/test_cli_core.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/test_cli_core.py b/tests/test_cli_core.py index d282af3a3..2360ca48d 100644 --- a/tests/test_cli_core.py +++ b/tests/test_cli_core.py @@ -131,13 +131,13 @@ def test_core_tag_block_lock(isolated_db: Path) -> None: def test_core_tag_block_corr(isolated_db: Path) -> None: - b = _seed_store(isolated_db) + _seed_store(isolated_db) _, out = _run("core") assert "CORR=3" in out def test_core_tag_block_posterior(isolated_db: Path) -> None: - b = _seed_store(isolated_db) + _seed_store(isolated_db) _, out = _run("core") assert "μ=0.800" in out