Skip to content

feat(cli): aelf core subcommand (#439) - #463

Merged
robotrocketscience merged 11 commits into
mainfrom
feat/issue-439-aelf-core-impl
May 8, 2026
Merged

feat(cli): aelf core subcommand (#439)#463
robotrocketscience merged 11 commits into
mainfrom
feat/issue-439-aelf-core-impl

Conversation

@yoshi280

@yoshi280 yoshi280 commented May 6, 2026

Copy link
Copy Markdown
Collaborator

Closes #439.

Implements aelf core per the merged spec memo (docs/feature-aelf-core.md,
PR #456). Surfaces the load-bearing subset of the belief store: locked ∪
{corroboration ≥ 2} ∪ {posterior ≥ 2/3 with α+β ≥ 4}. Read-only.

What's in here

  • _cmd_core + _qualifies_core + _emit_core in src/aelfrice/cli.py
    (composition over list_locked_beliefs / list_belief_ids / get_belief
    — no new store method, per spec § "Why no new store method").
  • Subparser registration with add_mutually_exclusive_group() for
    --locked-only / --no-locked (argparse handles exit 2 on conflict).
  • tests/test_cli_core.py — 26 unit tests against the spec's 5-belief
    fixture matrix; covers all 8 spec test scenarios (default text, JSON
    round-trip + signals list, --locked-only, --no-locked, mutual
    exclusion, --limit, empty store, threshold flags).
  • src/aelfrice/slash_commands/core.md (mirrors unlock.md).
  • core added to EXPECTED_COMMANDS in tests/test_slash_commands.py.
  • docs/COMMANDS.md row inserted between locked and unlock.

Notable spec calls

  • _emit_core recomputes signal attribution per row from the threshold
    args so the JSON signals list and the text tag block both reflect the
    current gates, not just whether the belief survived _qualifies_core.
  • Locked subset sort delegated to list_locked_beliefs (already
    ORDER BY locked_at DESC, id ASC — matches spec).
  • Tests seed corroboration via the public record_corroboration API
    rather than direct SQL.

Out of scope (deferred per spec)

  • PageRank weighting — graph-centrality signal needs a persisted PageRank
    pass first.
  • Hibernation-aware filter.
  • aelf core --explain <id>.

Test plan

  • uv run pytest tests/test_cli_core.py tests/test_slash_commands.py — 136 passed.
  • uv run aelf core --help — argparse registration works.
  • AELFRICE_DB=/tmp/empty.db uv run aelf coreno core beliefs, exit 0.
  • Discretion grep (sonnet|opus|claude|setr|kulili|gylf|toug|...) on
    the diff vs github/main — clean.

Summary by Sourcery

Add a new read-only core CLI subcommand and corresponding slash command to surface load-bearing beliefs based on lock status, corroboration, and posterior thresholds.

New Features:

  • Introduce aelf core CLI command to list load-bearing beliefs with JSON and text output modes, result limiting, and configurable corroboration/posterior thresholds.
  • Expose core as a slash command endpoint that runs the new CLI and returns its output verbatim.

Enhancements:

  • Document the new core command and its flags in the main commands reference alongside existing belief-management commands.

Tests:

  • Add a dedicated test suite for aelf core covering default behavior, JSON output, locking filters, mutual exclusion of flags, limiting, empty-store handling, and threshold configuration.
  • Extend slash command surface tests to include the new core command so the CLI and slash command interfaces stay in sync.

Summary by CodeRabbit

  • New Features

    • Added aelf core command to surface load-bearing beliefs with locking, corroboration, and posterior/alpha-beta thresholds; supports --locked-only/--no-locked, threshold flags, --limit, and JSON or human-readable output.
  • Documentation

    • Added CLI command reference entry and a slash-command definition for aelf:core.
  • Tests

    • Added comprehensive tests covering output formats, threshold behavior, locking modes, ordering/limits, and edge cases.

@sourcery-ai

sourcery-ai Bot commented May 6, 2026

Copy link
Copy Markdown

Reviewer's Guide

Implements the new read-only aelf core CLI subcommand that surfaces "load-bearing" beliefs (locked, sufficiently corroborated, or high-posterior), wires it into argparse, docs, and slash-commands, and adds a focused test suite validating behavior and thresholds against the spec fixture matrix.

Sequence diagram for the new aelf core CLI command

sequenceDiagram
  actor User
  participant Shell
  participant AelfCLI
  participant Argparse
  participant CoreCommand
  participant Store
  participant Qualifier
  participant Emitter

  User->>Shell: run aelf core [flags]
  Shell->>AelfCLI: invoke main()
  AelfCLI->>Argparse: parse arguments
  Argparse->>CoreCommand: _cmd_core(args, out)

  CoreCommand->>Store: _open_store()

  alt args.no_locked
    CoreCommand->>CoreCommand: locked = []
  else not args.no_locked
    CoreCommand->>Store: list_locked_beliefs()
    Store-->>CoreCommand: locked list
  end

  alt not args.locked_only
    CoreCommand->>Store: list_belief_ids()
    Store-->>CoreCommand: belief_ids
    loop each belief_id
      CoreCommand->>Store: get_belief(belief_id)
      Store-->>CoreCommand: belief or None
      alt belief is not None and belief.lock_level == none
        CoreCommand->>Qualifier: _qualifies_core(belief, args)
        Qualifier-->>CoreCommand: qualifies bool
        alt qualifies
          CoreCommand->>CoreCommand: append belief to candidates
        end
      end
    end
  end

  CoreCommand->>Store: close()

  CoreCommand->>Emitter: _emit_core(locked, candidates, args, out)
  Emitter-->>CoreCommand: print formatted results

  CoreCommand-->>Argparse: return 0
  Argparse-->>AelfCLI: exit code 0
  AelfCLI-->>Shell: process exit
Loading

Updated class diagram for the aelf core command and related types

classDiagram

  class Belief {
    +str id
    +str content
    +str lock_level
    +float alpha
    +float beta
    +int corroboration_count
  }

  class BeliefStore {
    +list~Belief~ list_locked_beliefs()
    +list~str~ list_belief_ids()
    +Belief get_belief(belief_id)
    +void close()
  }

  class CoreArgs {
    +bool json
    +int limit
    +int min_corroboration
    +float min_posterior
    +int min_alpha_beta
    +bool locked_only
    +bool no_locked
  }

  class AelfCoreCommand {
    +int _CORE_MIN_CORROBORATION
    +float _CORE_MIN_POSTERIOR
    +int _CORE_MIN_ALPHA_BETA
    +bool _qualifies_core(b, args)
    +void _emit_core(locked, candidates, args, out)
    +int _cmd_core(args, out)
  }

  AelfCoreCommand --> BeliefStore : uses
  AelfCoreCommand --> Belief : filters_formats
  AelfCoreCommand --> CoreArgs : reads_thresholds
Loading

File-Level Changes

Change Details Files
Add core-belief selection, formatting, and CLI plumbing for the new aelf core subcommand.
  • Introduce core-threshold constants and _qualifies_core helper to encapsulate corroboration/posterior gating logic based on CLI arguments.
  • Implement _emit_core to merge locked and qualifying unlocked beliefs, sort by posterior for unlocked entries, apply optional limit, and render either tagged text or JSON with recomputed signals and posterior stats per belief.
  • Implement _cmd_core to fetch locked beliefs and qualifying unlocked candidates from the store using existing list/get methods, then delegate output to _emit_core while honoring --locked-only and --no-locked flags.
  • Register the core subparser in build_parser with JSON/limit/threshold flags and a mutually exclusive group for --locked-only vs --no-locked, defaulting its handler to _cmd_core.
  • Ensure empty result sets print the sentinel message no core beliefs and exit with status 0.
src/aelfrice/cli.py
Document and expose the core command via slash-commands and top-level command docs.
  • Create src/aelfrice/slash_commands/core.md describing the aelf core slash command, its purpose, and how to invoke it via uv run aelf core with arbitrary arguments, mirroring the style of other command docs.
  • Add core to the EXPECTED_COMMANDS list so slash-command tests enforce that the slash surface matches the CLI.
  • Add a core row to docs/COMMANDS.md documenting flags and the load-bearing belief semantics and versioning of the new command.
src/aelfrice/slash_commands/core.md
tests/test_slash_commands.py
docs/COMMANDS.md
Add unit tests for aelf core behavior across spec scenarios using a five-belief fixture matrix.
  • Introduce tests/test_cli_core.py with helpers to create beliefs and seed a MemoryStore, including corroboration via the public record_corroboration API.
  • Test default text output inclusion/exclusion of locked, corroborated, posterior, thin-posterior, and prior-only beliefs, plus tag-block formatting (LOCK, CORR, posterior stats).
  • Test JSON output shape and that signals includes the appropriate markers for lock, corroboration, and posterior for each belief and is never empty for returned beliefs.
  • Validate --locked-only, --no-locked, and their mutual exclusion (exit code 2 via argparse) along with --limit ordering preference for locked beliefs.
  • Cover edge cases for an empty store (sentinel message, exit 0) and threshold overrides, including raising --min-corroboration and disabling posterior/α+β gates to include otherwise excluded beliefs.
tests/test_cli_core.py

Assessment against linked issues

Issue Objective Addressed Explanation
#439 Implement the aelf core CLI subcommand that surfaces the load-bearing subset of beliefs (locked ∪ sufficiently corroborated ∪ sufficiently high-posterior) with an appropriate definition of "core" and read-only behavior, analogous in spirit to aelf locked.
#439 Provide unit tests for the aelf core CLI subcommand against fixture stores to validate selection criteria, output behavior (text/JSON), flags, and edge cases.
#439 Document the aelf core command in the documentation, including docs/COMMANDS.md and integration with the slash-commands docs surface.

Possibly linked issues


Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

@coderabbitai

coderabbitai Bot commented May 6, 2026

Copy link
Copy Markdown

Review Change Stack

Caution

Review failed

The pull request is closed.

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 9f8e16f0-ef7b-4615-b435-481083bf2125

📥 Commits

Reviewing files that changed from the base of the PR and between 5f6f0f2 and a89bd81.

📒 Files selected for processing (5)
  • docs/COMMANDS.md
  • src/aelfrice/cli.py
  • src/aelfrice/slash_commands/core.md
  • tests/test_cli_core.py
  • tests/test_slash_commands.py

📝 Walkthrough

Walkthrough

This PR implements the aelf core CLI subcommand (v2.0+, #439) to surface load-bearing beliefs by combining locked beliefs with corroborated and high-posterior candidates. Includes command wiring, qualification and emit helpers, docs/slash metadata, and integration tests.

Changes

Core CLI Command Implementation

Layer / File(s) Summary
Constants & Thresholds
src/aelfrice/cli.py
Added _CORE_MIN_CORROBORATION, _CORE_MIN_POSTERIOR, _CORE_MIN_ALPHA_BETA module constants.
Qualification & Filtering
src/aelfrice/cli.py
Introduced _qualifies_core(...) to decide eligibility based on corroboration or posterior+alpha-beta gating.
Output Formatting
src/aelfrice/cli.py
Added _emit_core(...) to merge locked and qualifying non-locked beliefs, dedupe, sort (posterior desc, id tiebreak), apply --limit, and emit text or JSON with signals metadata; prints no core beliefs when empty.
Command Handler & Parser Wiring
src/aelfrice/cli.py, docs/COMMANDS.md
Added _cmd_core(...) and extended build_parser() to register core with flags --json, --limit, --min-corroboration, --min-posterior, --min-alpha-beta, and mutually exclusive --locked-only / --no-locked; inserted docs row.
Slash Command Definition
src/aelfrice/slash_commands/core.md
Created aelf:core markdown with frontmatter, <objective> criteria, and <process> invoking uv run aelf core $ARGUMENTS.
Integration Tests — Helpers
tests/test_cli_core.py
Added DB-isolation fixture, CLI runner helper, belief factory, and store seeding helpers.
Integration Tests — Behavior
tests/test_cli_core.py
Added tests for default filtering, tagging, JSON output, --locked-only/--no-locked, mutual-exclusion, --limit, empty-store sentinel, threshold flags, and alpha=beta=0 defensive case.
Slash Commands Manifest
tests/test_slash_commands.py
Updated EXPECTED_COMMANDS to include core, enabling validation of src/aelfrice/slash_commands/core.md.

Sequence Diagram

sequenceDiagram
    actor User
    participant CLI as aelf core
    participant Store as Belief Store
    participant Filter as Filtering Logic
    participant Output as Output Formatter

    User->>CLI: aelf core [--flags]
    CLI->>Store: Load beliefs
    Store-->>CLI: Belief set
    CLI->>Filter: Build locked subset
    Filter-->>CLI: Locked beliefs
    CLI->>Filter: Compute candidates by corroboration/posterior
    Filter-->>CLI: Unlocked candidates
    CLI->>CLI: Merge & deduplicate
    CLI->>CLI: Sort by posterior + tiebreak
    CLI->>Output: Format (text or JSON)
    Output-->>CLI: Formatted output
    CLI-->>User: Display results
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

Suggested labels

attn:review, docs

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 18.42% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The PR title 'feat(cli): aelf core subcommand (#439)' accurately and concisely summarizes the main change—adding a new CLI subcommand.
Description check ✅ Passed The PR description comprehensively covers summary, linked issues, type of change, verification steps, test plan, and notes for reviewer, aligning with the template.
Linked Issues check ✅ Passed All coding requirements from issue #439 are met: spec-compliant load-bearing belief definition, JSON/text output modes, CLI flags, unit tests, and documentation updates.
Out of Scope Changes check ✅ Passed All changes directly implement the #439 specification: CLI subcommand, tests, documentation, and slash command—no out-of-scope modifications detected.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/issue-439-aelf-core-impl

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 Microsoft Presidio Analyzer (2.2.362)
docs/COMMANDS.md

Microsoft Presidio Analyzer failed to scan this file


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@yoshi280 yoshi280 added the attn:review Needs review (PR open, awaiting reviewer) label May 6, 2026

@sourcery-ai sourcery-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey - I've found 3 issues, and left some high level feedback:

  • In both _posterior and the JSON/text signal recomputation paths, alpha / (alpha + beta) can divide by zero if a belief ever has alpha + beta == 0; consider guarding against this (e.g., skip posterior or treat μ as 0.0) to avoid a hard crash on malformed or edge-case beliefs.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- In both `_posterior` and the JSON/text signal recomputation paths, `alpha / (alpha + beta)` can divide by zero if a belief ever has `alpha + beta == 0`; consider guarding against this (e.g., skip posterior or treat μ as 0.0) to avoid a hard crash on malformed or edge-case beliefs.

## Individual Comments

### Comment 1
<location path="src/aelfrice/cli.py" line_range="1308-1311" />
<code_context>
+    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]
</code_context>
<issue_to_address>
**issue:** Guard `_posterior` against a zero α+β to avoid a potential ZeroDivisionError.

Beliefs with α=β=0 (i.e., a + bb == 0) will cause a ZeroDivisionError here. Since you already special-case `ab == 0` when computing `posterior_mean`, consider doing the same in `_posterior` (e.g., return 0.0 or another defined default when `a + bb == 0`) so sorting cannot crash on such entries.
</issue_to_address>

### Comment 2
<location path="src/aelfrice/cli.py" line_range="1291" />
<code_context>
+    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
</code_context>
<issue_to_address>
**issue (bug_risk):** `--min-corroboration` "0 disables" semantics don’t match the current check.

`_qualifies_core` checks `if corr >= args.min_corroboration`, so `0` actually enables the signal for all beliefs (`corr >= 0` is always true). If `0` is meant to disable this gate, you likely want something like `if args.min_corroboration and corr >= args.min_corroboration:` (and the same logic wherever you add the `"corroboration"` signal). Otherwise, please update the help text to match the current behavior.
</issue_to_address>

### Comment 3
<location path="tests/test_cli_core.py" line_range="148-152" />
<code_context>
+def test_core_json_parses(isolated_db: Path) -> None:
</code_context>
<issue_to_address>
**suggestion (testing):** Align JSON scenario coverage with the default text scenario by asserting that non-core beliefs are excluded from JSON output as well.

In the text tests we assert that `b-thin` and `b-prior` are excluded from `aelf core` output. Here, the JSON tests only verify structure and the presence of `signals`. Please also assert that `b-thin` and `b-prior` ids are absent from the JSON rows under default thresholds, so both output modes enforce the same core-filter semantics.

```suggestion
def test_core_json_parses(isolated_db: Path) -> None:
    b = _seed_store(isolated_db)
    _, out = _run("core", "--json")
    rows = json.loads(out)
    assert isinstance(rows, list)

    # core filter should exclude non-core beliefs in JSON mode as well
    thin_id = b["b-thin"].id
    prior_id = b["b-prior"].id
    row_ids = {row["id"] for row in rows}

    assert thin_id not in row_ids
    assert prior_id not in row_ids
```
</issue_to_address>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

Comment thread src/aelfrice/cli.py Outdated
Comment thread src/aelfrice/cli.py
Comment thread tests/test_cli_core.py
Comment on lines +148 to +152
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)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

suggestion (testing): Align JSON scenario coverage with the default text scenario by asserting that non-core beliefs are excluded from JSON output as well.

In the text tests we assert that b-thin and b-prior are excluded from aelf core output. Here, the JSON tests only verify structure and the presence of signals. Please also assert that b-thin and b-prior ids are absent from the JSON rows under default thresholds, so both output modes enforce the same core-filter semantics.

Suggested change
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_parses(isolated_db: Path) -> None:
b = _seed_store(isolated_db)
_, out = _run("core", "--json")
rows = json.loads(out)
assert isinstance(rows, list)
# core filter should exclude non-core beliefs in JSON mode as well
thin_id = b["b-thin"].id
prior_id = b["b-prior"].id
row_ids = {row["id"] for row in rows}
assert thin_id not in row_ids
assert prior_id not in row_ids

Comment thread tests/test_cli_core.py Fixed
Comment thread tests/test_cli_core.py Fixed
@github-actions github-actions Bot added the attn:merge-conflict PR branch needs rebase label May 6, 2026
@github-actions

github-actions Bot commented May 6, 2026

Copy link
Copy Markdown

This PR is now behind main. Rebase locally so your commit signatures stay intact:

git fetch origin && git checkout 'feat/issue-439-aelf-core-impl' && git rebase origin/main
# resolve conflicts if any, then
git push --force-with-lease

Auto-rebase was removed because the bot has no signing key; rebasing as the bot strips author signatures and the required_signatures rule on main then blocks the merge. See #341.

@yoshi280

yoshi280 commented May 7, 2026

Copy link
Copy Markdown
Collaborator Author

[claim:review:setr:2026-05-07T00:20:09Z]

@yoshi280

yoshi280 commented May 7, 2026

Copy link
Copy Markdown
Collaborator Author

[claim:review:Gylf:2026-05-07T00:20:32Z]

@yoshi280

yoshi280 commented May 7, 2026

Copy link
Copy Markdown
Collaborator Author

[release:review:Gylf:2026-05-07T00:20:37Z]

@yoshi280

yoshi280 commented May 7, 2026

Copy link
Copy Markdown
Collaborator Author

[claim:review:Toug:2026-05-07T00:22:14Z]

@yoshi280

yoshi280 commented May 7, 2026

Copy link
Copy Markdown
Collaborator Author

[release:review:Toug:2026-05-07T00:22:18Z]

@yoshi280

yoshi280 commented May 7, 2026

Copy link
Copy Markdown
Collaborator Author

Review

Reviewed at HEAD 926b9d3. Approving on substance — needs rebase against main before FF-merge.

Substance — LGTM:

  • _cmd_core composition over list_locked_beliefs / list_belief_ids / get_belief matches the spec memo (docs/feature-aelf-core.md); no new store method added, as intended.
  • Default thresholds (min_corroboration=2, min_posterior=2/3, min_alpha_beta=4) line up with the slash-command description in src/aelfrice/slash_commands/core.md.
  • Mutually-exclusive --locked-only / --no-locked group is correct — reduces over the two suppression knobs.
  • Posterior co-gate (α+β ≥ N) prevents thin-prior beliefs at α=2 β=1 from leaking in (matches b-thin-post in the test fixture).
  • Test matrix (tests/test_cli_core.py) covers all 8 spec scenarios against the 5-belief fixture; spec-test-impl alignment is tight.
  • Slash command registered in EXPECTED_COMMANDS; docs/COMMANDS.md entry added.

CI: all required checks green at HEAD.

Discretion grep: clean.

Signatures: all 5 commits show G against gpg.ssh.allowedSignersFile.

Required change — rebase only:

  • Branch is 3 commits behind github/main (PR [v2.x] replay-soak cron blocked by branch ruleset — gate streak stuck at 0, blocks #264 #461: replay-soak status branch reshuffle). I tested the rebase locally — it replays cleanly, no actual conflicts. The attn:merge-conflict label is correct as "needs rebase," not "has conflict text."
  • After git rebase github/main && git push --force-with-lease github, this is FF-merge ready. I'll drop attn:review so this leaves the review queue; flip it back on after the rebase and a session will pick up the merge.

Releasing review claim.

@yoshi280 yoshi280 removed the attn:review Needs review (PR open, awaiting reviewer) label May 7, 2026
@yoshi280

yoshi280 commented May 7, 2026

Copy link
Copy Markdown
Collaborator Author

[release:review:setr:2026-05-07T00:23:54Z]

robotrocketscience added a commit that referenced this pull request May 7, 2026
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.
@robotrocketscience
robotrocketscience force-pushed the feat/issue-439-aelf-core-impl branch from 926b9d3 to 8077883 Compare May 7, 2026 01:53

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

♻️ Duplicate comments (1)
tests/test_cli_core.py (1)

133-136: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Unused variable b (CodeQL flagged at lines 134 and 140)

_seed_store is called for its side effects (populating the DB); the returned dict is never used in either test. Replace both assignments with bare calls.

🔧 Proposed fix
 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

Also applies to: 139-143

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/test_cli_core.py` around lines 133 - 136, The test assigns the return
value of _seed_store to an unused variable b in test_core_tag_block_corr (and
the similar test around lines 139-143); remove the unused assignment and call
_seed_store(isolated_db) as a bare call so the DB is populated for side effects
only, leaving the rest of the test (calls to _run("core") and assertions)
unchanged.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/aelfrice/cli.py`:
- Around line 1286-1296: The division by ab (alpha+beta) in multiple places can
raise ZeroDivisionError when ab == 0 and --min-alpha-beta is 0; update the three
sites that compute (alpha / ab) to guard the division the same way _posterior
does by requiring ab > 0 (in addition to the existing threshold check) —
specifically modify the conditional in _qualifies_core and both places inside
_emit_core (JSON and text emission paths) to include ab > 0 before performing
alpha/ab so the division never occurs when ab == 0; also consider adding a
regression test that calls the existing zero-ab belief test with
--min-alpha-beta 0.

---

Duplicate comments:
In `@tests/test_cli_core.py`:
- Around line 133-136: The test assigns the return value of _seed_store to an
unused variable b in test_core_tag_block_corr (and the similar test around lines
139-143); remove the unused assignment and call _seed_store(isolated_db) as a
bare call so the DB is populated for side effects only, leaving the rest of the
test (calls to _run("core") and assertions) unchanged.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 770622e2-15d9-42ad-b64b-85121984c1a6

📥 Commits

Reviewing files that changed from the base of the PR and between 7f880ca and 8077883.

📒 Files selected for processing (5)
  • docs/COMMANDS.md
  • src/aelfrice/cli.py
  • src/aelfrice/slash_commands/core.md
  • tests/test_cli_core.py
  • tests/test_slash_commands.py

Comment thread src/aelfrice/cli.py
@yoshi280 yoshi280 added attn:review Needs review (PR open, awaiting reviewer) and removed attn:merge-conflict PR branch needs rebase labels May 7, 2026
@yoshi280

yoshi280 commented May 7, 2026

Copy link
Copy Markdown
Collaborator Author

[claim:review:Kulili:2026-05-07T18:47:28Z]

@github-actions github-actions Bot added the attn:merge-conflict PR branch needs rebase label May 7, 2026
@github-actions

github-actions Bot commented May 7, 2026

Copy link
Copy Markdown

This PR is now behind main. Rebase locally so your commit signatures stay intact:

git fetch origin && git checkout 'feat/issue-439-aelf-core-impl' && git rebase origin/main
# resolve conflicts if any, then
git push --force-with-lease

Auto-rebase was removed because the bot has no signing key; rebasing as the bot strips author signatures and the required_signatures rule on main then blocks the merge. See #341.

@yoshi280

yoshi280 commented May 7, 2026

Copy link
Copy Markdown
Collaborator Author

[claim:review:Gylf:2026-05-07T18:49:09Z]

@yoshi280

yoshi280 commented May 7, 2026

Copy link
Copy Markdown
Collaborator Author

Review verdict — Kulili

Spec conformance (docs/feature-aelf-core.md, merged in #456): ✅

  • Definition of "core" (locked ∪ corroboration ≥ 2 ∪ posterior ≥ 2/3 with α+β ≥ 4) implemented in _qualifies_core exactly as spec'd.
  • Defaults: MIN_CORROBORATION=2, MIN_POSTERIOR=2/3, MIN_ALPHA_BETA=4 — match.
  • All seven flags present with correct semantics; --locked-only / --no-locked mutual exclusion via add_mutually_exclusive_group() (argparse exit 2 — matches spec).
  • Sort: locked first (delegated to list_locked_beliefs, already ORDER BY locked_at DESC, id ASC); non-locked by posterior_mean DESC, id ASC tiebreak.
  • Composition over list_locked_beliefs / list_belief_ids / get_belief — no new store method, per spec § "Why no new store method".
  • Tag-block format ([LOCK,CORR=N,α=F.F,β=F.F,μ=0.NNN]) matches spec example.

Code quality: ✅

  • _posterior guards α+β==0 (commit fa86868); explicit zero-AB regression test.
  • 26 unit tests cover the 5-belief fixture matrix and all 8 spec scenarios.
  • JSON output applies the same filter as text mode (verified by test_core_json_parses excluding b-thin/b-prior).
  • signals list per row uses sorted(set(...)) — deterministic.

Discretion grep (sonnet|opus|claude|setr|kulili|gylf|toug|parallel.session|...): clean.

CI: all green (pytest 3.12/3.13, CodeQL, Sourcery, CodeRabbit, Staging Gate full suite, deptry, vulture, typos).

Commits: all signed (G); 8 atomic commits, conventional-commit prefixes correct.


Blockers (not author-fixable)

  1. attn:decisions-needed on [v2.0] aelf core CLI — research-line surface, sibling of aelf unlock #439 not cleared. Per Toug's 01:49 comment on the issue, the spec-memo merge (PR docs(feature-aelf-core): spec memo for #439 #456 at 21:01:25Z 2026-05-06) preceded this flag by ~4h, and Toug explicitly deferred clearance to the operator: "Not removing attn:decisions-needed unilaterally — operator should clear it once they've confirmed PR feat(cli): aelf core subcommand (#439) #463 follows the merged spec." This PR follows the merged spec verbatim — operator needs to clear aelf-flag.sh 439 none (or equivalent) to authorize merge.

  2. Branch needs rebase. git merge-base --is-ancestor github/main pr-463 → REBASE-NEEDED. mergeStateStatus=BLOCKED, mergeable=MERGEABLE. Author rebase + force-push (or maintainer rebase-merge after flag clearance).

Recommended path

Once operator clears attn:decisions-needed:

git fetch github main feat/issue-439-aelf-core-impl
git rebase github/main feat/issue-439-aelf-core-impl  # in author's worktree
# verify all commits still G after rebase
git push github feat/issue-439-aelf-core-impl --force-with-lease
# CI re-runs; reviewer (not author) FF-merges per protocol rule 6

No diff-level changes requested. Releasing review claim.

@yoshi280

yoshi280 commented May 7, 2026

Copy link
Copy Markdown
Collaborator Author

[release:review:Kulili:2026-05-07T18:49:50Z]

@yoshi280

yoshi280 commented May 7, 2026

Copy link
Copy Markdown
Collaborator Author

Review: approve in substance, blocked on rebase.

Substance — pass

Implementation matches docs/feature-aelf-core.md end-to-end:

  • _qualifies_core gates on corroboration_count >= MIN_CORROBORATION OR (α+β >= MIN_ALPHA_BETA AND α/(α+β) >= MIN_POSTERIOR) — matches §"Definition of core" exactly. Defaults are 2 / 4 / 0.6666.
  • _emit_core dedupes locked from candidates (seen set on b.id), sorts non-locked by (-posterior, id), applies --limit after sort. Locked ordering delegates to list_locked_beliefs (already ORDER BY locked_at DESC, id ASC per §"Output — text").
  • _emit_core recomputes signal attribution per row from the threshold args, so the JSON signals list and the text tag block reflect the current gates rather than just whether the belief survived _qualifies_core — matches the spec's contract that signals is "exactly the signals that put this belief in the result."
  • Composition over list_locked_beliefs / list_belief_ids / get_belief. No new store method, per §"Why no new store method (v2.0)".
  • Mutual exclusion via add_mutually_exclusive_group() — argparse exit 2 path matches §"Mutual exclusion in argparse".
  • α+β=0 is guarded in _emit_core._posterior (returns 0.0) — covered by test_core_zero_alpha_beta_does_not_crash.

tests/test_cli_core.py covers all 8 spec test scenarios in §"Test plan" plus extras (per-row tag-block presence, JSON signals nonemptiness, threshold-disable cases). 27 tests, all green in CI.

Surface

  • 8 atomic signed commits (all G).
  • docs/COMMANDS.md row inserted in the spec'd position between locked and unlock.
  • src/aelfrice/slash_commands/core.md mirrors unlock.md. core added to EXPECTED_COMMANDS.
  • Discretion grep on the diff: clean.
  • All required CI checks: pass (pytest 3.12 / 3.13, pattern-scan, history-scan, secrets-scan, deptry, vulture, CodeQL, commit-msg-prefix, pr-title-prefix, pr-body-issue-link, release-docs-check).

Blocker — rebase needed

attn:merge-conflict label is set; the branch is no longer fast-forward over main after #466 merged at 18:47 UTC. git merge-tree shows the auto-merge resolves cleanly (no text conflicts), so a plain rebase on github/main should produce the same tree.

Per branch protection / two-repo workflow rule 6, merge requires a signed FF push. Cannot be done by reviewer — author rebase + force-push of the branch is the path. Once rebased and CI re-passes, this is ready to ship.

Releasing the review claim so another session can land it after rebase.

@yoshi280

yoshi280 commented May 7, 2026

Copy link
Copy Markdown
Collaborator Author

[release:review:Gylf:2026-05-07T18:51:54Z]

@yoshi280 yoshi280 removed the attn:review Needs review (PR open, awaiting reviewer) label May 7, 2026
@yoshi280 yoshi280 added attn:merge-conflict PR branch needs rebase and removed attn:merge-conflict PR branch needs rebase labels May 7, 2026
@github-actions github-actions Bot added the attn:merge-conflict PR branch needs rebase label May 7, 2026
@github-actions

github-actions Bot commented May 7, 2026

Copy link
Copy Markdown

This PR is now behind main. Rebase locally so your commit signatures stay intact:

git fetch origin && git checkout 'feat/issue-439-aelf-core-impl' && git rebase origin/main
# resolve conflicts if any, then
git push --force-with-lease

Auto-rebase was removed because the bot has no signing key; rebasing as the bot strips author signatures and the required_signatures rule on main then blocks the merge. See #341.

@yoshi280

yoshi280 commented May 7, 2026

Copy link
Copy Markdown
Collaborator Author

[claim:review:Toug:2026-05-07T21:31:33Z]

robotrocketscience added a commit that referenced this pull request May 7, 2026
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.
@robotrocketscience
robotrocketscience force-pushed the feat/issue-439-aelf-core-impl branch from 8077883 to 5f6f0f2 Compare May 7, 2026 21:33
@yoshi280 yoshi280 removed the attn:merge-conflict PR branch needs rebase label May 7, 2026

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

♻️ Duplicate comments (3)
tests/test_cli_core.py (2)

133-136: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Unused variable b (also Line 140).

b = _seed_store(isolated_db) is assigned but never referenced; the assertions check raw string matches in out. Both variables can be dropped.

🔧 Proposed fix
 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
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/test_cli_core.py` around lines 133 - 136, The test
test_core_tag_block_corr assigns an unused variable b from
_seed_store(isolated_db); remove the unnecessary assignment (either drop the
call entirely if seeding is not needed, or invoke _seed_store(isolated_db)
without assigning its return value to b if you need its side effects). Do the
same for the other unused b assignment referenced on Line 140 so both tests no
longer assign unused variables; keep the rest of the assertions (the
_run("core") and "CORR=3" checks) unchanged.

292-314: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

test_core_zero_alpha_beta_does_not_crash does not cover the unguarded alpha / ab path.

The test runs with default thresholds (min_alpha_beta=4), so the zero-ab belief is short-circuited by ab >= 4 before any division is attempted. The ZeroDivisionError at Lines 1294, 1335, and 1360 of cli.py (when --min-alpha-beta 0 is passed with an α+β == 0 belief) is still unreachable by this test.

A companion variant like the following would provide the regression coverage:

def test_core_zero_alpha_beta_with_min_ab_zero_does_not_crash(isolated_db: Path) -> None:
    s = MemoryStore(str(isolated_db))
    try:
        s.insert_belief(_make_belief("b0zeroab0000000000", "zero ab", alpha=0.0, beta=0.0))
    finally:
        s.close()
    code, _ = _run("core", "--min-alpha-beta", "0")
    assert code == 0
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/test_cli_core.py` around lines 292 - 314, Add a companion test that
actually exercises the unguarded division path by running the CLI with
min-alpha-beta set to 0: create a new test function (e.g.
test_core_zero_alpha_beta_with_min_ab_zero_does_not_crash) that uses MemoryStore
and _make_belief to insert a belief with alpha=0.0 and beta=0.0, closes the
store, calls _run("core", "--min-alpha-beta", "0"), and asserts the exit code is
0; this ensures the code paths in cli.py that compute alpha/ab (referenced by
the current test and the _run invocation) do not raise ZeroDivisionError.
src/aelfrice/cli.py (1)

1294-1294: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

ZeroDivisionError when --min-alpha-beta 0 with an α+β == 0 belief — three sites still unguarded.

Lines 1294, 1335, and 1360 all compute alpha / ab guarded only by ab >= args.min_alpha_beta. When --min-alpha-beta 0 is passed, 0 >= 0 is True and the division executes. The _posterior inner function at Line 1312 already has the ab > 0 guard; the three sibling expressions need the same treatment.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/aelfrice/cli.py` at line 1294, The condition that computes posterior
proportion (alpha / ab) is vulnerable to ZeroDivisionError when ab == 0 and
args.min_alpha_beta == 0; update the three places that currently check "ab >=
args.min_alpha_beta and (alpha / ab) >= args.min_posterior" (and the two other
sibling expressions that perform alpha / ab) to require ab > 0 before performing
the division—i.e., change the guard to "ab > 0 and ab >= args.min_alpha_beta and
(alpha / ab) >= args.min_posterior" (or equivalent short-circuit ordering) so
the division is only executed when ab > 0; mirror the same ab > 0 guard used in
the existing _posterior inner function to ensure consistent behavior.
🧹 Nitpick comments (2)
src/aelfrice/cli.py (2)

1328-1328: ⚡ Quick win

Use LOCK_NONE constant instead of the hardcoded string "none" (Lines 1328, 1356, 1381).

LOCK_NONE is not currently imported in cli.py (only LOCK_USER is). Three new comparisons use the raw string literal, which silently diverges if the model constant ever changes.

♻️ Proposed fix

Add LOCK_NONE to the existing aelfrice.models import block:

 from aelfrice.models import (
     CORROBORATION_SOURCE_CLI_REMEMBER,
     ...
+    LOCK_NONE,
     LOCK_USER,
     ...
 )

Then replace the three hardcoded comparisons:

-            if b.lock_level != "none":  # type: ignore[attr-defined]
+            if b.lock_level != LOCK_NONE:  # type: ignore[attr-defined]

(apply identically at Lines 1328, 1356, and 1381)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/aelfrice/cli.py` at line 1328, Import the LOCK_NONE constant from
aelfrice.models alongside the existing LOCK_USER import, and replace the three
occurrences that compare against the hardcoded string ("none")—e.g., expressions
like b.lock_level != "none"—with comparisons against LOCK_NONE (e.g.,
b.lock_level != LOCK_NONE) so the code uses the canonical constant; the
replacements appear near the uses of variable b.lock_level and should be applied
identically at each occurrence.

1379-1384: ⚖️ Poor tradeoff

N+1 store round-trips in _cmd_core for large belief stores.

list_belief_ids() + get_belief(bid) per ID is O(N) SQLite lookups. For large stores this could be noticeably slow on the hot loop. The pattern is consistent with _wonder_pick_seed, and the spec explicitly forbids a new store method, but a future list_beliefs_with_lock_none() API would cut this to one query.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/aelfrice/cli.py` around lines 1379 - 1384, The loop in _cmd_core does N+1
store round-trips by calling store.list_belief_ids() then store.get_belief(bid)
for each id; add a new store method list_beliefs_with_lock_none() (or a
single-query iterator that yields full belief objects with lock_level == "none")
and replace the loop in _cmd_core (and the similar loop in _wonder_pick_seed) to
iterate over those belief objects and apply _qualifies_core(b, args) to build
candidates, eliminating per-id get_belief calls.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Duplicate comments:
In `@src/aelfrice/cli.py`:
- Line 1294: The condition that computes posterior proportion (alpha / ab) is
vulnerable to ZeroDivisionError when ab == 0 and args.min_alpha_beta == 0;
update the three places that currently check "ab >= args.min_alpha_beta and
(alpha / ab) >= args.min_posterior" (and the two other sibling expressions that
perform alpha / ab) to require ab > 0 before performing the division—i.e.,
change the guard to "ab > 0 and ab >= args.min_alpha_beta and (alpha / ab) >=
args.min_posterior" (or equivalent short-circuit ordering) so the division is
only executed when ab > 0; mirror the same ab > 0 guard used in the existing
_posterior inner function to ensure consistent behavior.

In `@tests/test_cli_core.py`:
- Around line 133-136: The test test_core_tag_block_corr assigns an unused
variable b from _seed_store(isolated_db); remove the unnecessary assignment
(either drop the call entirely if seeding is not needed, or invoke
_seed_store(isolated_db) without assigning its return value to b if you need its
side effects). Do the same for the other unused b assignment referenced on Line
140 so both tests no longer assign unused variables; keep the rest of the
assertions (the _run("core") and "CORR=3" checks) unchanged.
- Around line 292-314: Add a companion test that actually exercises the
unguarded division path by running the CLI with min-alpha-beta set to 0: create
a new test function (e.g.
test_core_zero_alpha_beta_with_min_ab_zero_does_not_crash) that uses MemoryStore
and _make_belief to insert a belief with alpha=0.0 and beta=0.0, closes the
store, calls _run("core", "--min-alpha-beta", "0"), and asserts the exit code is
0; this ensures the code paths in cli.py that compute alpha/ab (referenced by
the current test and the _run invocation) do not raise ZeroDivisionError.

---

Nitpick comments:
In `@src/aelfrice/cli.py`:
- Line 1328: Import the LOCK_NONE constant from aelfrice.models alongside the
existing LOCK_USER import, and replace the three occurrences that compare
against the hardcoded string ("none")—e.g., expressions like b.lock_level !=
"none"—with comparisons against LOCK_NONE (e.g., b.lock_level != LOCK_NONE) so
the code uses the canonical constant; the replacements appear near the uses of
variable b.lock_level and should be applied identically at each occurrence.
- Around line 1379-1384: The loop in _cmd_core does N+1 store round-trips by
calling store.list_belief_ids() then store.get_belief(bid) for each id; add a
new store method list_beliefs_with_lock_none() (or a single-query iterator that
yields full belief objects with lock_level == "none") and replace the loop in
_cmd_core (and the similar loop in _wonder_pick_seed) to iterate over those
belief objects and apply _qualifies_core(b, args) to build candidates,
eliminating per-id get_belief calls.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 8c7c53e7-3506-40b4-a592-8e033cb49e5a

📥 Commits

Reviewing files that changed from the base of the PR and between 8077883 and 5f6f0f2.

📒 Files selected for processing (5)
  • docs/COMMANDS.md
  • src/aelfrice/cli.py
  • src/aelfrice/slash_commands/core.md
  • tests/test_cli_core.py
  • tests/test_slash_commands.py
🚧 Files skipped from review as they are similar to previous changes (2)
  • src/aelfrice/slash_commands/core.md
  • docs/COMMANDS.md

robotrocketscience added a commit that referenced this pull request May 7, 2026
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.
@robotrocketscience
robotrocketscience force-pushed the feat/issue-439-aelf-core-impl branch from 5f6f0f2 to 74b0219 Compare May 7, 2026 21:37
@yoshi280

yoshi280 commented May 7, 2026

Copy link
Copy Markdown
Collaborator Author

[release:review:Toug:2026-05-07T21:37:29Z]

@github-actions github-actions Bot added the attn:merge-conflict PR branch needs rebase label May 8, 2026
@github-actions

github-actions Bot commented May 8, 2026

Copy link
Copy Markdown

This PR is now behind main. Rebase locally so your commit signatures stay intact:

git fetch origin && git checkout 'feat/issue-439-aelf-core-impl' && git rebase origin/main
# resolve conflicts if any, then
git push --force-with-lease

Auto-rebase was removed because the bot has no signing key; rebasing as the bot strips author signatures and the required_signatures rule on main then blocks the merge. See #341.

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.
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.
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.
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.
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.
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.
`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.
@robotrocketscience
robotrocketscience force-pushed the feat/issue-439-aelf-core-impl branch from 74b0219 to a89bd81 Compare May 8, 2026 04:00
@robotrocketscience
robotrocketscience merged commit a89bd81 into main May 8, 2026
19 of 20 checks passed
@robotrocketscience
robotrocketscience deleted the feat/issue-439-aelf-core-impl branch May 8, 2026 04:03
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

attn:merge-conflict PR branch needs rebase

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[v2.0] aelf core CLI — research-line surface, sibling of aelf unlock

3 participants