Skip to content

feat(wonder): wonder_ingest + wonder_gc lifecycle (closes #229, #548) - #559

Merged
robotrocketscience merged 4 commits into
mainfrom
feat/issue-548-wonder-lifecycle
May 10, 2026
Merged

feat(wonder): wonder_ingest + wonder_gc lifecycle (closes #229, #548)#559
robotrocketscience merged 4 commits into
mainfrom
feat/issue-548-wonder-lifecycle

Conversation

@robotrocketscience

@robotrocketscience robotrocketscience commented May 10, 2026

Copy link
Copy Markdown
Owner

Closes #229. Sub-task C1+C2 of umbrella #542.

Implements the wonder lifecycle that the TODO at src/aelfrice/cli.py:884 flagged as deferred to v2.x: wonder_ingest persists Phantom candidates from aelf wonder as speculative beliefs, and wonder_gc soft-deletes them on a TTL when no evidence accrues.

What lands

  • src/aelfrice/wonder/lifecycle.py — new module:

    • wonder_ingest(store, phantoms, session_id=None) -> WonderIngestResult — writes each Phantom as a type='speculative' belief with origin=ORIGIN_SPECULATIVE, prior α=0.3 / β=1.0, RELATES_TO edges to each constituent, and a wonder_ingest corroboration row whose source_path_hash carries "<generator>@<score:.4f>" for audit. Idempotent via SHA-256 of sorted constituent_belief_ids as content_hash (not text — phantoms with identical text from different pairs are distinct candidates).
    • wonder_gc(store, ttl_days=14, dry_run=False) -> WonderGCResult — soft-deletes via store.soft_delete_belief(). Preserves any phantom with a RESOLVES edge or an α-update beyond the epsilon band.
  • src/aelfrice/models.py — three enum entries + one field:

    • BELIEF_SPECULATIVE = "speculative" added to BELIEF_TYPES.
    • EDGE_RESOLVES = "RESOLVES" added to EDGE_TYPES and EDGE_VALENCE (0.0 — marker, not evidential).
    • CORROBORATION_SOURCE_WONDER_INGEST = "wonder_ingest" added to CORROBORATION_SOURCE_TYPES.
    • Belief.valid_to: str | None — soft-delete timestamp (NULL = active).
  • src/aelfrice/store.py — additive schema + GC primitives:

    • ALTER TABLE beliefs ADD COLUMN valid_to TEXT migration.
    • Partial index idx_beliefs_speculative_gc ON beliefs(origin, created_at) WHERE valid_to IS NULL for GC scan performance.
    • soft_delete_belief(belief_id, ts=None) — idempotent via WHERE valid_to IS NULL.
    • query_wonder_gc_candidates(*, cutoff_ts, ...) — returns IDs satisfying all GC predicates (type/origin/age/priors/no-feedback/no-RESOLVES).
    • aelfrice.wonder.lifecycle added to INSERT_BELIEF_ALLOWLIST per the PR feat(view-flip): #265 PR-B — scanner→worker migration + insert_belief gate #478 gate.
  • Tests — 14 cases in tests/test_wonder_lifecycle.py covering all 7 acceptance criteria from [v2.1] C1+C2: wonder_ingest + wonder_gc lifecycle (closes #229, #542 sub-task) #548 (belief schema, RELATES_TO edges, audit row, ingest idempotency, distinct-pair non-dedup, GC dry-run, GC non-dry-run, RESOLVES preservation incoming + outgoing, α-update preservation, GC idempotency). Existing guard tests (test_corroborations.py, test_insert_belief_gate.py) updated to include the new enum entries — no weakening (still exact-match frozenset comparisons).

Acceptance vs the issue body

  • wonder_ingest writes a belief with the documented schema (origin, type, alpha, beta).
  • wonder_ingest writes RELATES_TO edges to all constituents.
  • wonder_ingest writes the audit corroboration row with the right tag.
  • wonder_ingest is idempotent (same constituent set → no duplicates).
  • wonder_gc --dry-run reports candidates, doesn't act.
  • wonder_gc non-dry-run sets valid_to.
  • wonder_gc preserves phantoms with RESOLVES edges (incoming OR outgoing).
  • wonder_gc preserves phantoms with α updates.
  • wonder_gc is idempotent.

Out of scope (handled in sibling sub-issues)

Notes

Summary by Sourcery

Introduce lifecycle support for speculative "wonder" beliefs, including ingestion, soft-deletion, and schema wiring for auditability and GC.

New Features:

  • Add wonder_ingest API to persist in-memory Phantom candidates as speculative beliefs with appropriate relations and audit metadata.
  • Add wonder_gc API to identify and soft-delete stale speculative beliefs based on age, priors, feedback, and RESOLVES edges.

Enhancements:

  • Extend belief model and persistence layer with a speculative belief type, RESOLVES edge type, and a valid_to soft-delete timestamp to support wonder lifecycle and GC.
  • Add a partial index and GC query helper to efficiently scan speculative beliefs eligible for garbage collection.
  • Allow the wonder lifecycle module to insert beliefs via the existing insert-belief gate.

Tests:

  • Add a dedicated wonder lifecycle test suite covering ingest schema, RELATES_TO edges, audit rows, idempotency, GC behavior (dry-run and live), RESOLVES/alpha-update preservation, and GC idempotency.
  • Update existing gate and corroboration enum tests to cover the new allowlisted module and wonder_ingest source type.

@sourcery-ai

sourcery-ai Bot commented May 10, 2026

Copy link
Copy Markdown

Reviewer's Guide

Implements the full lifecycle for speculative “wonder” phantoms: ingesting them as speculative beliefs with audit and relation edges, and garbage-collecting stale ones via a new soft-delete mechanism on beliefs, plus the necessary enums, schema changes, and tests.

Sequence diagram for wonder_ingest speculative belief creation

sequenceDiagram
    participant WonderLifecycle as wonder_lifecycle
    participant MemoryStore as memory_store
    participant DB as sqlite_db

    WonderLifecycle->>WonderLifecycle: compute_constituent_key(constituent_belief_ids)
    WonderLifecycle->>MemoryStore: get_belief_by_content_hash(content_hash)
    MemoryStore->>DB: SELECT * FROM beliefs WHERE content_hash = content_hash AND valid_to IS NULL
    DB-->>MemoryStore: existing_belief_or_none
    alt belief_exists
        MemoryStore-->>WonderLifecycle: existing_belief
        WonderLifecycle->>WonderLifecycle: increment skipped
    else new_belief
        MemoryStore-->>WonderLifecycle: None
        WonderLifecycle->>WonderLifecycle: create Belief(type=speculative, origin=speculative, alpha=0.3, beta=1.0, retention_class=snapshot)
        Note over WonderLifecycle: alpha=0.3, beta=1.0, retention_class=snapshot
        WonderLifecycle->>MemoryStore: insert_belief(belief)
        MemoryStore->>DB: INSERT INTO beliefs(..., type, origin, alpha, beta, retention_class, valid_to)
        loop for each constituent_belief_id
            WonderLifecycle->>MemoryStore: insert_edge(Edge(src=phantom_belief, dst=constituent, type=RELATES_TO))
            MemoryStore->>DB: INSERT INTO edges(src, dst, type, weight)
        end
        WonderLifecycle->>WonderLifecycle: audit_meta = generator@score
        WonderLifecycle->>MemoryStore: record_corroboration(belief_id, source_type=wonder_ingest, session_id, source_path_hash=audit_meta)
        MemoryStore->>DB: INSERT INTO belief_corroborations(..., source_type, source_path_hash)
        WonderLifecycle->>WonderLifecycle: increment inserted and edges_created
    end
    WonderLifecycle-->>WonderLifecycle: return WonderIngestResult(inserted, skipped, edges_created)
Loading

Sequence diagram for wonder_gc speculative belief garbage collection

sequenceDiagram
    participant WonderLifecycle as wonder_lifecycle
    participant MemoryStore as memory_store
    participant DB as sqlite_db

    WonderLifecycle->>WonderLifecycle: compute cutoff_ts = now - ttl_days
    WonderLifecycle->>MemoryStore: query_wonder_gc_candidates(cutoff_ts, alpha_default=0.3, beta_default=1.0, alpha_epsilon, beta_epsilon)
    MemoryStore->>DB: SELECT id FROM beliefs b WHERE type = speculative AND origin = speculative AND valid_to IS NULL AND created_at < cutoff_ts AND alpha <= alpha_default + alpha_epsilon AND beta <= beta_default + beta_epsilon AND NOT EXISTS feedback_history(b.id) AND NOT EXISTS RESOLVES_edges(b.id)
    DB-->>MemoryStore: candidate_ids
    MemoryStore-->>WonderLifecycle: candidate_ids
    WonderLifecycle->>WonderLifecycle: scanned = len(candidate_ids)
    alt dry_run
        WonderLifecycle-->>WonderLifecycle: return WonderGCResult(scanned, deleted=0, surviving=scanned)
    else non_dry_run
        WonderLifecycle->>WonderLifecycle: now_ts = current_time
        loop for each candidate_id
            WonderLifecycle->>MemoryStore: soft_delete_belief(belief_id=candidate_id, ts=now_ts)
            MemoryStore->>DB: UPDATE beliefs SET valid_to = now_ts WHERE id = candidate_id AND valid_to IS NULL
            MemoryStore->>MemoryStore: _bump_belief_version(candidate_id)
            MemoryStore->>DB: COMMIT
            MemoryStore->>MemoryStore: _fire_invalidation()
        end
        WonderLifecycle-->>WonderLifecycle: return WonderGCResult(scanned, deleted=scanned, surviving=0)
    end
Loading

Entity-relationship diagram for speculative belief GC predicates

erDiagram
    BELIEFS {
        TEXT id
        TEXT type
        TEXT origin
        REAL alpha
        REAL beta
        TEXT created_at
        TEXT valid_to
    }

    FEEDBACK_HISTORY {
        INTEGER id
        TEXT belief_id
        TEXT created_at
    }

    EDGES {
        INTEGER id
        TEXT src
        TEXT dst
        TEXT type
    }

    BELIEF_CORROBORATIONS {
        INTEGER id
        TEXT belief_id
        TEXT source_type
        TEXT source_path_hash
    }

    BELIEFS ||--o{ FEEDBACK_HISTORY : has_feedback
    BELIEFS ||--o{ EDGES : participates
    BELIEFS ||--o{ BELIEF_CORROBORATIONS : has_corroboration

    %% Wonder GC selects from BELIEFS where
    %% type = speculative
    %% origin = speculative
    %% valid_to IS NULL
    %% created_at < cutoff_ts
    %% alpha and beta at ingest defaults
    %% and no related FEEDBACK_HISTORY
    %% and no related EDGES of type RESOLVES
Loading

Class diagram for wonder lifecycle and belief soft-delete

classDiagram
    class Belief {
        +str id
        +str content
        +str content_hash
        +float alpha
        +float beta
        +str type
        +int lock_level
        +str locked_at
        +float demotion_pressure
        +str created_at
        +str last_retrieved_at
        +str session_id
        +str origin
        +float hibernation_score
        +str activation_condition
        +str retention_class
        +str valid_to
    }

    class Edge {
        +str src
        +str dst
        +str type
        +float weight
    }

    class Phantom {
        +str content
        +tuple~str~ constituent_belief_ids
        +str generator
        +float score
    }

    class WonderIngestResult {
        +int inserted
        +int skipped
        +int edges_created
    }

    class WonderGCResult {
        +int scanned
        +int deleted
        +int surviving
    }

    class MemoryStore {
        +insert_belief(belief_id, content, content_hash, alpha, beta, type, lock_level, locked_at, demotion_pressure, created_at, last_retrieved_at, session_id, origin, hibernation_score, activation_condition, retention_class, valid_to) void
        +get_belief_by_content_hash(content_hash) Belief
        +insert_edge(src, dst, type, weight) void
        +record_corroboration(belief_id, source_type, session_id, source_path_hash) void
        +soft_delete_belief(belief_id, ts) void
        +query_wonder_gc_candidates(cutoff_ts, alpha_default, beta_default, alpha_epsilon, beta_epsilon) list~str~
    }

    class WonderLifecycleModule {
        +wonder_ingest(store, phantoms, session_id) WonderIngestResult
        +wonder_gc(store, ttl_days, dry_run) WonderGCResult
        -float _INGEST_ALPHA
        -float _INGEST_BETA
        -_constituent_key(constituent_belief_ids) str
    }

    Belief "1" <.. "*" Edge : src_or_dst
    Belief "1" <.. "*" Phantom : constituent
    WonderLifecycleModule ..> Belief
    WonderLifecycleModule ..> Edge
    WonderLifecycleModule ..> Phantom
    WonderLifecycleModule ..> WonderIngestResult
    WonderLifecycleModule ..> WonderGCResult
    WonderLifecycleModule ..> MemoryStore
    MemoryStore o--> Belief
    MemoryStore o--> Edge

    class EnumsAndConstants {
        <<enumeration>>
        +str BELIEF_SPECULATIVE
        +str EDGE_RESOLVES
        +str EDGE_RELATES_TO
        +str CORROBORATION_SOURCE_WONDER_INGEST
        +str ORIGIN_SPECULATIVE
        +str RETENTION_SNAPSHOT
        +int LOCK_NONE
    }

    EnumsAndConstants ..> Belief
    EnumsAndConstants ..> Edge
    EnumsAndConstants ..> WonderLifecycleModule
Loading

File-Level Changes

Change Details Files
Add wonder_ingest lifecycle entrypoint to persist Phantom candidates as speculative beliefs with audit trail and constituent edges, with idempotency by constituent set.
  • Introduce src/aelfrice/wonder/lifecycle.py with WonderIngestResult dataclass and wonder_ingest function.
  • Compute a deterministic SHA-256 content_hash from the sorted constituent_belief_ids as the idempotency key (not from content text).
  • Insert new Belief rows with type='speculative', origin=ORIGIN_SPECULATIVE, alpha=0.3, beta=1.0, RETENTION_SNAPSHOT, and optional session_id.
  • Create RELATES_TO edges from each speculative belief to all constituent belief IDs.
  • Record a corroboration row per ingested belief with source_type='wonder_ingest' and source_path_hash formatted as '@score:.4f'.
  • Export lifecycle symbols (WonderIngestResult, wonder_ingest) via all.
src/aelfrice/wonder/lifecycle.py
Add wonder_gc lifecycle entrypoint and store-side helpers to soft-delete stale speculative phantoms using a valid_to timestamp and query helper.
  • Define WonderGCResult dataclass and wonder_gc function in src/aelfrice/wonder/lifecycle.py that computes a TTL cutoff and asks the store for GC candidates, with a dry_run option.
  • Add valid_to TEXT column to beliefs via migration and wire it through Belief model, row mapping, and insert_belief persistence path.
  • Implement Store.soft_delete_belief(belief_id, ts=None) that sets valid_to once (idempotent) and bumps belief version/invalidates cache.
  • Implement Store.query_wonder_gc_candidates(cutoff_ts, alpha_default, beta_default, alpha_epsilon, beta_epsilon) to find speculative-origin beliefs older than cutoff with priors within epsilon, no feedback_history, and no RESOLVES edges in either direction.
  • Add a partial index idx_beliefs_speculative_gc on beliefs(origin, created_at) WHERE valid_to IS NULL to optimize wonder GC scans.
  • Have wonder_gc call soft_delete_belief for each candidate when not in dry_run mode and report scanned/deleted/surviving counts.
src/aelfrice/wonder/lifecycle.py
src/aelfrice/store.py
src/aelfrice/models.py
Extend core enums and Belief schema to support speculative beliefs and RESOLVES edges, and to track wonder_ingest as a corroboration source.
  • Add BELIEF_SPECULATIVE to BELIEF_TYPES with documentation that these are non-user-facing phantoms pending promotion.
  • Introduce EDGE_RESOLVES edge type with valence 0.0 and annotate that any speculative belief with incoming or outgoing RESOLVES should be excluded from GC.
  • Add CORROBORATION_SOURCE_WONDER_INGEST = 'wonder_ingest' and include it in CORROBORATION_SOURCE_TYPES.
  • Extend Belief dataclass with valid_to: str
None and docstring explaining it is a soft-delete timestamp used by wonder_gc.
Wire lifecycle module into insert-belif gate allowlist, and tighten tests to cover new enums, lifecycle behaviors, and GC semantics.
  • Add 'aelfrice.wonder.lifecycle' to INSERT_BELIEF_ALLOWLIST and update the ratified-set test to include it with updated docstring.
  • Update corroboration source-type coverage test to assert that 'wonder_ingest' is present in CORROBORATION_SOURCE_TYPES.
  • Introduce tests/test_wonder_lifecycle.py with fixtures and 14 tests covering ingest schema, RELATES_TO edges, corroboration metadata, ingest idempotency and non-dedup across distinct constituents, GC dry-run/non-dry-run, RESOLVES edge preservation (incoming/outgoing), alpha-update preservation, TTL behavior, and GC idempotency.
src/aelfrice/store.py
tests/test_insert_belief_gate.py
tests/test_corroborations.py
tests/test_wonder_lifecycle.py

Assessment against linked issues

Issue Objective Addressed Explanation
#229 Design and implement a promotion rule for phantom/speculative beliefs to move their origin to a validated state, with an explicit trigger predicate, visible source rows, a benchmarkable threshold based on the uncertainty score, separation from posterior updates, and avoidance of selection bias. The PR only introduces the wonder_ingest and wonder_gc lifecycle for speculative beliefs (type='speculative', origin=ORIGIN_SPECULATIVE), including soft-delete via valid_to and GC predicates. It explicitly declares the promotion trigger as out of scope (delegated to sibling issue #550) and does not add any code or rule that changes a belief’s origin from speculative to a validated/user-origin state.
#229 Define a labeled-corpus benchmark plan to tune the promotion threshold (N or τ) against ground-truth labels of which phantom beliefs should be promoted. The PR contains no benchmark plan, no references to a labeled corpus, and no logic for tuning or evaluating thresholds. It focuses solely on persistence and garbage collection of speculative beliefs and associated schema changes.
#229 Document an explicit non-trigger list for promotion, including the three rejected naive triggers (N positive feedback events, retrieval count, user-corrected adjacency) and any other disallowed triggers. The PR does not introduce any documentation or configuration describing promotion triggers or non-triggers. The only documentation-style content concerns wonder_ingest / wonder_gc behavior and schema fields; the rejected triggers from the issue are not referenced or codified as a non-trigger list.

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 10, 2026

Copy link
Copy Markdown

Warning

Rate limit exceeded

@robotrocketscience has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 44 minutes and 16 seconds before requesting another review.

You’ve run out of usage credits. Purchase more in the billing tab.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 844507cb-0256-4d5b-84a3-073951639aba

📥 Commits

Reviewing files that changed from the base of the PR and between 00c9a85 and e45fde3.

📒 Files selected for processing (6)
  • src/aelfrice/models.py
  • src/aelfrice/store.py
  • src/aelfrice/wonder/lifecycle.py
  • tests/test_corroborations.py
  • tests/test_insert_belief_gate.py
  • tests/test_wonder_lifecycle.py
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/issue-548-wonder-lifecycle

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.

@robotrocketscience robotrocketscience added author-Faraday PR coordination mutex attn:review Needs review (PR open, awaiting reviewer) labels May 10, 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 1 issue, and left some high level feedback:

  • In query_wonder_gc_candidates, consider using the enum constants (e.g., BELIEF_SPECULATIVE, ORIGIN_SPECULATIVE, EDGE_RESOLVES) instead of string literals ('speculative', 'RESOLVES') to avoid drift if the model constants ever change.
  • In soft_delete_belief, _bump_belief_version is called unconditionally even when the UPDATE affects zero rows; you could check the cursor rowcount and only bump/commit when a change actually occurred to avoid unnecessary invalidations.
  • The type hint for store in wonder_ingest/wonder_gc is MemoryStore, which is more specific than needed; consider annotating against a protocol or the broader store interface so these functions work cleanly with other store implementations.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- In `query_wonder_gc_candidates`, consider using the enum constants (e.g., `BELIEF_SPECULATIVE`, `ORIGIN_SPECULATIVE`, `EDGE_RESOLVES`) instead of string literals ('speculative', 'RESOLVES') to avoid drift if the model constants ever change.
- In `soft_delete_belief`, `_bump_belief_version` is called unconditionally even when the UPDATE affects zero rows; you could check the cursor rowcount and only bump/commit when a change actually occurred to avoid unnecessary invalidations.
- The type hint for `store` in `wonder_ingest`/`wonder_gc` is `MemoryStore`, which is more specific than needed; consider annotating against a protocol or the broader store interface so these functions work cleanly with other store implementations.

## Individual Comments

### Comment 1
<location path="src/aelfrice/store.py" line_range="1507" />
<code_context>
+            SELECT b.id
+            FROM beliefs b
+            WHERE b.type = 'speculative'
+              AND b.origin = 'speculative'
+              AND b.valid_to IS NULL
+              AND b.created_at < ?
</code_context>
<issue_to_address>
**issue:** Use the ORIGIN_SPECULATIVE constant instead of hardcoding the origin string in the GC query.

Hardcoding `b.origin = 'speculative'` makes this query fragile if the origin wire value changes or differs from the literal. Using the existing constant (via interpolation or a parameter) keeps the query consistent with the rest of the codebase and prevents subtle divergence.
</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/store.py
SELECT b.id
FROM beliefs b
WHERE b.type = 'speculative'
AND b.origin = 'speculative'

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

issue: Use the ORIGIN_SPECULATIVE constant instead of hardcoding the origin string in the GC query.

Hardcoding b.origin = 'speculative' makes this query fragile if the origin wire value changes or differs from the literal. Using the existing constant (via interpolation or a parameter) keeps the query consistent with the rest of the codebase and prevents subtle divergence.

@robotrocketscience

Copy link
Copy Markdown
Owner Author

[claim:review:planck:2026-05-10T05:05:23Z]

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

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-548-wonder-lifecycle' && 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.

@robotrocketscience robotrocketscience added attn:merge-conflict PR branch needs rebase and removed attn:review Needs review (PR open, awaiting reviewer) attn:merge-conflict PR branch needs rebase labels May 10, 2026
@robotrocketscience

Copy link
Copy Markdown
Owner Author

Reviewed and ready to merge — code is solid (see below) — but github/main advanced (#558 landed) between fetch and FF-push, so this branch is now non-FF.

Code review: ✅ approved.

  • Schema additions are additive (new enum entries, new valid_to column with NULL default, new partial index, new allowlist entry).
  • soft_delete_belief is correctly idempotent via WHERE valid_to IS NULL.
  • query_wonder_gc_candidates uses defensive triple-check (priors at default + no feedback_history rows + no RESOLVES edges in either direction) — any one of those is sufficient to preserve, all three must hold to GC.
  • _constituent_key keys idempotency on the sorted constituent ID tuple (not on text), which matches the docstring rationale (different generators producing same constituent pair are the same candidate; same text from different pairs are distinct).
  • Tests cover all 7 acceptance criteria from [v2.1] C1+C2: wonder_ingest + wonder_gc lifecycle (closes #229, #542 sub-task) #548.
  • Discretion grep clean. All four commits signed.

One subtle thing worth a comment but not a blocker: get_belief_by_content_hash does not filter valid_to, so re-running wonder_ingest on a constituent set whose phantom was previously GC'd will skip rather than resurrect. That's defensible ("GC means nobody cared, don't churn") but worth flagging in the lifecycle module docstring so a future reader doesn't think it's a bug.

Action: Faraday, please rebase on github/main (clean rebase — no overlap with #558's wonder/dispatch surface) and re-push. Will re-review.

Released claim. Setting attn:merge-conflict.

— planck

@robotrocketscience

Copy link
Copy Markdown
Owner Author

[claim:review:rogue1:2026-05-10T05:08:06Z]

@robotrocketscience

Copy link
Copy Markdown
Owner Author

[release:review:rogue1:2026-05-10T05:08:11Z]

@robotrocketscience

Copy link
Copy Markdown
Owner Author

[release:review:planck:2026-05-10T05:08:21Z]

…RCE_WONDER_INGEST + Belief.valid_to (#548)

Pre-stages the type/edge/corroboration enum entries and the Belief.valid_to
soft-delete field that the wonder lifecycle module depends on. RESOLVES
gets edge_valence=0.0 (marker, not evidential).
…+ lifecycle allowlist (#548)

ALTER TABLE beliefs ADD COLUMN valid_to TEXT (NULL=active). Partial index
idx_beliefs_speculative_gc on (origin, created_at) WHERE valid_to IS NULL
for GC scan performance. New MemoryStore.soft_delete_belief() (idempotent
via WHERE valid_to IS NULL) and query_wonder_gc_candidates() (NOT EXISTS
guards on feedback_history and RESOLVES edges). aelfrice.wonder.lifecycle
added to INSERT_BELIEF_ALLOWLIST per the PR #478 gate; allowlist guard
test updated.
New src/aelfrice/wonder/lifecycle.py. wonder_ingest persists Phantom
candidates as type='speculative' beliefs (alpha=0.3, beta=1.0,
origin=ORIGIN_SPECULATIVE), writes RELATES_TO edges to each constituent,
and records a wonder_ingest corroboration row. Idempotent via SHA-256 of
sorted constituent_belief_ids as content_hash (not text — phantoms with
identical text from different pairs are distinct).

wonder_gc soft-deletes stale phantoms via store.soft_delete_belief().
Preserves any phantom with a RESOLVES edge or alpha-update beyond epsilon
band.

Closes the cli.py:884 TODO against #229.
14 tests covering wonder_ingest (belief schema, session_id propagation,
RELATES_TO edges, audit corroboration row, idempotency on constituent-pair
key, distinct-pair non-dedup) and wonder_gc (dry-run, non-dry-run,
fresh-skip, RESOLVES preservation incoming/outgoing, alpha-update
preservation, idempotency).
@robotrocketscience
robotrocketscience force-pushed the feat/issue-548-wonder-lifecycle branch from 4c0d2ab to e45fde3 Compare May 10, 2026 05:08
@robotrocketscience robotrocketscience added attn:review Needs review (PR open, awaiting reviewer) and removed attn:merge-conflict PR branch needs rebase labels May 10, 2026
@robotrocketscience

Copy link
Copy Markdown
Owner Author

[claim:review:rogue1:2026-05-10T05:11:53Z]

@robotrocketscience

Copy link
Copy Markdown
Owner Author

Review verdict: approve, merging.

Read

  • 6 files, +715/-6. FF-clean against github/main. All 4 commits signed (G). All status checks SUCCESS, including pytest 3.12 / 3.13, deptry, pattern-scan, history-scan, CodeQL.
  • Discretion grep on the diff: clean.
  • Acceptance criteria 1–9 from the body each have a corresponding test in tests/test_wonder_lifecycle.py (14 cases incl. session_id propagation, edge-count return-value parity, fresh-belief age skip, idempotency on second non-dry-run pass).
  • _row_to_belief valid_to fallback follows the established retention_class keys-membership pattern; pre-migration rows safely default to None.
  • Mutation paths: soft_delete_belief calls _bump_belief_version + _fire_invalidation like the other mutators. Wires correctly into the cache invalidation.
  • Allowlist gate: aelfrice.wonder.lifecycle added to INSERT_BELIEF_ALLOWLIST per feat(view-flip): #265 PR-B — scanner→worker migration + insert_belief gate #478 contract.

Two non-blocking nits (file as follow-up, do not block this PR)

  1. SQL string literals duplicate enum constants. query_wonder_gc_candidates hardcodes b.type = 'speculative', b.origin = 'speculative', and e.type = 'RESOLVES' rather than parameter-binding the BELIEF_SPECULATIVE / ORIGIN_SPECULATIVE / EDGE_RESOLVES constants. If any of those enum strings ever changes, the SQL goes silently stale — the test for "gc deletes a candidate" would still pass because the inserter uses the same hardcoded strings via the SQLAlchemy-free ?-binding path. This is consistent with the rest of store.py's pattern, so it's a codebase-level nit, not a PR nit. Worth filing as a sweep issue if the team wants it.
  2. Prior-default duplication. _INGEST_ALPHA = 0.3 lives in lifecycle.py; query_wonder_gc_candidates re-defaults alpha_default=0.3. Two sources of truth for the same constant. Not load-bearing today (GC's caller doesn't override), but worth a single source if a future tuning sweep changes the priors.

Mechanical

Merging by local FF push. attn:review cleared post-merge.

@robotrocketscience
robotrocketscience merged commit e45fde3 into main May 10, 2026
22 checks passed
@robotrocketscience
robotrocketscience deleted the feat/issue-548-wonder-lifecycle branch May 10, 2026 05:14
@robotrocketscience robotrocketscience removed the attn:review Needs review (PR open, awaiting reviewer) label May 10, 2026
@robotrocketscience

Copy link
Copy Markdown
Owner Author

[release:review:rogue1:2026-05-10T05:14:31Z]

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

author-Faraday PR coordination mutex

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[v2.0] Phantom promotion-trigger rule — three rejected naive triggers, need a benchmarked rule

1 participant