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
1 change: 1 addition & 0 deletions docs/COMMANDS.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ DB resolves from `$AELFRICE_DB`, then `<git-common-dir>/aelfrice/memory.db` when
| `search <query> [--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 <statement>` | 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 <belief_id>` | Drop a user-lock without changing origin. Idempotent. Writes a `lock:unlock` audit row. |
| `delete <belief_id> [--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 <belief_id>` | 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. |
Expand Down
152 changes: 152 additions & 0 deletions src/aelfrice/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@
EDGE_SUPERSEDES,
EDGE_SUPPORTS,
INGEST_SOURCE_CLI_REMEMBER,
LOCK_NONE,
LOCK_USER,
ORIGIN_USER_STATED,
ORIGIN_USER_VALIDATED,
Expand Down Expand Up @@ -1278,6 +1279,116 @@ 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:
Comment thread
sourcery-ai[bot] marked this conversation as resolved.
return True
ab = alpha + beta
if ab > 0 and ab >= args.min_alpha_beta and (alpha / ab) >= args.min_posterior:
return True
return False
Comment thread
coderabbitai[bot] marked this conversation as resolved.


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]
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

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 != LOCK_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 > 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]
"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 != LOCK_NONE: # type: ignore[attr-defined]
parts.append("LOCK")
if corr >= args.min_corroboration:
parts.append(f"CORR={corr}")
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}")
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 != LOCK_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)
Expand Down Expand Up @@ -3493,6 +3604,47 @@ 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; 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; 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,
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",
Expand Down
18 changes: 18 additions & 0 deletions src/aelfrice/slash_commands/core.md
Original file line number Diff line number Diff line change
@@ -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
---
<objective>
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.
</objective>

<process>
Run: `uv run aelf core $ARGUMENTS`
Display the output verbatim. Do not add commentary.
</process>
Loading
Loading