feat(wonder): wonder_ingest + wonder_gc lifecycle (closes #229, #548) - #559
Conversation
Reviewer's GuideImplements 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 creationsequenceDiagram
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)
Sequence diagram for wonder_gc speculative belief garbage collectionsequenceDiagram
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
Entity-relationship diagram for speculative belief GC predicateserDiagram
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
Class diagram for wonder lifecycle and belief soft-deleteclassDiagram
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
File-Level Changes
Assessment against linked issues
Possibly linked issues
Tips and commandsInteracting with Sourcery
Customizing Your ExperienceAccess your dashboard to:
Getting Help
|
|
Warning Rate limit exceeded
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 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 configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (6)
✨ Finishing Touches🧪 Generate unit tests (beta)
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. Comment |
There was a problem hiding this comment.
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_versionis 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
storeinwonder_ingest/wonder_gcisMemoryStore, 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>Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.
| SELECT b.id | ||
| FROM beliefs b | ||
| WHERE b.type = 'speculative' | ||
| AND b.origin = 'speculative' |
There was a problem hiding this comment.
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.
|
[claim:review:planck:2026-05-10T05:05:23Z] |
|
This PR is now behind Auto-rebase was removed because the bot has no signing key; rebasing as the bot strips author signatures and the |
|
Reviewed and ready to merge — code is solid (see below) — but Code review: ✅ approved.
One subtle thing worth a comment but not a blocker: Action: Faraday, please rebase on Released claim. Setting — planck |
|
[claim:review:rogue1:2026-05-10T05:08:06Z] |
|
[release:review:rogue1:2026-05-10T05:08:11Z] |
|
[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).
4c0d2ab to
e45fde3
Compare
|
[claim:review:rogue1:2026-05-10T05:11:53Z] |
|
Review verdict: approve, merging. Read
Two non-blocking nits (file as follow-up, do not block this PR)
MechanicalMerging by local FF push. |
|
[release:review:rogue1:2026-05-10T05:14:31Z] |
Closes #229. Sub-task C1+C2 of umbrella #542.
Implements the wonder lifecycle that the TODO at
src/aelfrice/cli.py:884flagged as deferred to v2.x:wonder_ingestpersistsPhantomcandidates fromaelf wonderas speculative beliefs, andwonder_gcsoft-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 eachPhantomas atype='speculative'belief withorigin=ORIGIN_SPECULATIVE, prior α=0.3 / β=1.0,RELATES_TOedges to each constituent, and awonder_ingestcorroboration row whosesource_path_hashcarries"<generator>@<score:.4f>"for audit. Idempotent via SHA-256 of sortedconstituent_belief_idsascontent_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 viastore.soft_delete_belief(). Preserves any phantom with aRESOLVESedge or an α-update beyond the epsilon band.src/aelfrice/models.py— three enum entries + one field:BELIEF_SPECULATIVE = "speculative"added toBELIEF_TYPES.EDGE_RESOLVES = "RESOLVES"added toEDGE_TYPESandEDGE_VALENCE(0.0 — marker, not evidential).CORROBORATION_SOURCE_WONDER_INGEST = "wonder_ingest"added toCORROBORATION_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 TEXTmigration.idx_beliefs_speculative_gc ON beliefs(origin, created_at) WHERE valid_to IS NULLfor GC scan performance.soft_delete_belief(belief_id, ts=None)— idempotent viaWHERE 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.lifecycleadded toINSERT_BELIEF_ALLOWLISTper the PR feat(view-flip): #265 PR-B — scanner→worker migration + insert_belief gate #478 gate.Tests — 14 cases in
tests/test_wonder_lifecycle.pycovering 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_ingestwrites a belief with the documented schema (origin, type, alpha, beta).wonder_ingestwrites RELATES_TO edges to all constituents.wonder_ingestwrites the audit corroboration row with the right tag.wonder_ingestis idempotent (same constituent set → no duplicates).wonder_gc --dry-runreports candidates, doesn't act.wonder_gcnon-dry-run setsvalid_to.wonder_gcpreserves phantoms withRESOLVESedges (incoming OR outgoing).wonder_gcpreserves phantoms with α updates.wonder_gcis idempotent.Out of scope (handled in sibling sub-issues)
aelf wonder --persist,aelf wonder gc) — sibling [v2.1] C3: aelf wonder --persist + gc CLI surface (#542 sub-task) #549 (C3).aelf confirm) — sibling [v2.1] C4: phantom promotion trigger (#542 sub-task) #550 (C4), depends on this PR.wonder_ingest) — sibling [v2.1] E4: skill layer integration — subagent dispatch → wonder_ingest (#542 sub-task) #552 (E4), depends on this PR.Notes
audit_logtable exists today (and per [phantom-prereqs T2] Implicit retrieval-driven feedback — sweeper + grace window #191/feat: deferred-feedback sweeper — implicit retrieval-driven posterior signal (#191) #256 implementation,feedback_historyis the live audit surface for posterior updates). Usedbelief_corroborationswithsource_type='wonder_ingest'for the audit row — consistent with how the v1.5.0 corroboration design treats re-assertion events as first-class signals.github/main(v2.0.1 → v2.1.0). All commits in this branch land on top of currentgithub/maindirectly; no version-rollback noise included.Summary by Sourcery
Introduce lifecycle support for speculative "wonder" beliefs, including ingestion, soft-deletion, and schema wiring for auditability and GC.
New Features:
Enhancements:
Tests: