feat: phantom promotion-opportunity detector (#1132) - #1134
Conversation
Read-only detector for phantoms (origin='speculative') that have crossed a cross-session corroboration threshold: origin='speculative' AND live (valid_to IS NULL) AND corr>=N AND distinct-sessions>=M AND no inbound CONTRADICTS, ordered by created_at. The inverse population of find_promotable_snapshots; NULL sessions excluded from the distinct count (same rationale). Does not promote -- under #229 a phantom's origin advances only through explicit user acknowledgment; this feeds the promotion- opportunity note that surfaces the candidate for that act.
Add promotion_fires (per-session note budget) and promotion_dedup (belief-ids already surfaced) to the session ring, independent of the #980 generation budget so the two opportunity lanes bound their notes separately. record_promotion_fire / read_promotion_state mirror the phantom equivalents; _normalize_for_session seeds + coerces the new fields (default for pre-#1132 rings, no migration). Direct unit tests cover the normalize round-trip, the counter/dedup contract, and lane independence.
…1132) The promotion-side mirror of the #980 generation detector. When the opt-in [phantom_promotion] lane is on, each UserPromptSubmit turn surfaces phantoms that have crossed the corroboration threshold as an <aelfrice-phantom-promotion-opportunity> note naming the candidate and its aelf validate / lock surface. Note-not-write: origin promotion stays the explicit user act #229 mandates (a corroboration count is a non-trigger for the write); this lane only decides WHEN to prompt, never promotes autonomously. Closes the #1125-census gap -- phantoms were never promoted because nothing surfaced a corroborated one for the explicit act, not because promotion is broken. New pure aelfrice.phantom_promotion_opportunity module: config (env > kwarg > TOML > default-off, mirroring [phantom_generation]), the store-backed detector, a per-session budget+dedup orchestrator, and an XML-escaped note. Wired as a fail-soft UserPromptSubmit lane parallel to #980. Default-off; no clock, network, or LLM (#605-clean).
Document the [phantom_promotion] TOML section (enabled / max_fires_per_session / min_corroborations / min_sessions) in CONFIG.md as the promotion-side mirror of [phantom_generation]. Add [Unreleased] entries: the Q2 detector (Added) and the Q1 retention-promotion speculative-exclusion fix (Fixed).
Reviewer's GuideAdds an opt-in, fail-soft phantom promotion-opportunity detector and wiring: a store-level query to find corroborated speculative beliefs, a promotion lane in the UserPromptSubmit hook, and per-session budget/dedup state in the session ring, plus documentation and tests. Sequence diagram for phantom promotion-opportunity lane in UserPromptSubmitsequenceDiagram
actor User
participant Hook as user_prompt_submit
participant Promo as _maybe_phantom_promotion_block
participant Config as load_phantom_promotion_config
participant Store as MemoryStore
participant Eval as evaluate_promotion_opportunities
User->>Hook: submit prompt
Hook->>Promo: _maybe_phantom_promotion_block(session_id, cwd, stderr)
Promo->>Config: load_phantom_promotion_config(start=cwd)
Config-->>Promo: PhantomPromotionConfig
Promo->>Promo: [config.enabled?]
alt promotion disabled or in memory store
Promo-->>Hook: ""
else promotion enabled
Promo->>Store: MemoryStore(db_path)
Promo->>Eval: evaluate_promotion_opportunities(store, session_id, config, stderr)
Eval-->>Promo: opportunities
Promo->>Store: close()
Promo-->>Hook: format_promotion_note(opportunities)
Hook->>User: write promotion note block
end
File-Level Changes
Assessment against linked issues
Possibly linked issues
Tips and commandsInteracting with Sourcery
Customizing Your ExperienceAccess your dashboard to:
Getting Help
|
|
Warning Review limit reached
Next review available in: 34 minutes Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available. How can I continue?After more reviews become available, a review can be triggered using the To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews. How do review limits work?CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability. For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window. Please refer docs for additional details. Review details⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (9)
✨ 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 |
PR-size soft capThis PR is over the advisory size threshold:
Bigger PRs collide with more open work, which under the parallel-session workflow tends to produce repeated This is advisory only — nothing is blocked. If the size is intentional (large refactor, module removal, generated code), apply the |
There was a problem hiding this comment.
Hey - I've left some high level feedback:
- In
load_phantom_promotion_config, you callshould_trigger_phantom_promotion(start=...)which re-parses.aelfrice.tomlvia_read_section; consider passing the already-read section into the flag resolver or factoring out the env/TOML parsing so the file is only read once per call. - In
format_promotion_note, you passopp.topicthrough_note_topic, which internally calls_truncateagain even thoughtopicwas already truncated when building thePromotionOpportunity; you can simplify by assumingtopicis already bounded and only escaping here.
Prompt for AI Agents
Please address the comments from this code review:
## Overall Comments
- In `load_phantom_promotion_config`, you call `should_trigger_phantom_promotion(start=...)` which re-parses `.aelfrice.toml` via `_read_section`; consider passing the already-read section into the flag resolver or factoring out the env/TOML parsing so the file is only read once per call.
- In `format_promotion_note`, you pass `opp.topic` through `_note_topic`, which internally calls `_truncate` again even though `topic` was already truncated when building the `PromotionOpportunity`; you can simplify by assuming `topic` is already bounded and only escaping here.Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.
The typos CI check reads 'opps' as a misspelling of 'oops'. Spell out the local variable in the detect test.
|
merge-train: blocked required check(s) failed: The |
- load_phantom_promotion_config resolves 'enabled' from the already-read TOML section via a shared _resolve_enabled helper, instead of re-reading the file through should_trigger_phantom_promotion (one file read per call). - _note_topic escapes only; the topic is already whitespace-collapsed and length-bounded by _truncate when the PromotionOpportunity is built, so the double truncation is dropped.
|
@sourcery-ai review |
|
Sorry @robotrocketscience, you have reached your weekly rate limit of 500000 diff characters. Please try again later or upgrade to continue using Sourcery |
|
Merged via local FF-push (the sanctioned wedged-bot fallback), not the merge-train. Rationale: the merge-train treats |
What
Builds the phantom promotion-opportunity detector — the promotion-side
mirror of the #980 phantom-generation detector. Closes #1132 (Q2; Q1, the
retention-promotion speculative-exclusion fix, shipped in #1133).
When the opt-in
[phantom_promotion]lane is enabled, eachUserPromptSubmitturn checks whether any phantom (
origin='speculative') has crossed across-session corroboration threshold and, if so, appends a small
<aelfrice-phantom-promotion-opportunity>note naming the candidate(s) andtheir
aelf validate <id>/aelf locksurface.Why
The #1125 census found phantoms are essentially never promoted (0 across
seven real stores) — but not because promotion is broken. Origin promotion is,
by the ratified #229 rule, an explicit user act (
aelf validate/ lock);a corroboration count is an explicit non-trigger for that write. The gap is
that nothing ever surfaces a corroborated phantom for the user to act on, so
the explicit act is never initiated.
This detector closes that gap the only way #229 permits — by surfacing, not
writing. It preserves "the only path to promotion is explicit user typing"
while fixing "nothing prompts the typing." Origin promotion stays exactly where
#229 put it; this lane only decides when to prompt, and never promotes
autonomously (the note says so explicitly).
Design
Modeled 1:1 on the #980 generation detector so the two lanes are consistent:
store.find_promotable_phantoms:origin='speculative'ANDlive (
valid_to IS NULL) ANDcorr >= min_corroborationsANDdistinct-sessions >= min_sessionsAND no inbound CONTRADICTS, ordered bycreated_at. Deterministic; the inverse population offind_promotable_snapshots.aelfrice.phantom_promotion_opportunity: configresolution (env
AELFRICE_PHANTOM_PROMOTION> kwarg > TOML[phantom_promotion]> default-off), a per-session budget + belief-id deduporchestrator, and an XML-escaped note builder.
session_ringgainspromotion_fires/promotion_dedup,independent of the Phantom belief lifecycle audit + trigger-driven generation in normal turns #980 generation budget so the two lanes bound notes
separately (default for pre-R&D: phantom promotion — origin path is 0-by-design (#229); retention path reaches speculative rows on a count trigger #1132 rings, no migration).
UserPromptSubmitlane parallel to Phantom belief lifecycle audit + trigger-driven generation in normal turns #980; default-offpath returns before opening the store.
Named
phantom_promotion_opportunity(not_trigger) to avoid colliding withthe #550 "phantom promotion trigger" (the explicit Surface A/B origin-flip),
which is a different concept.
No clock, no network, no LLM (#605-clean).
Threshold
Defaults mirror the retention-promotion rule (
belief_retention_class.md§4):≥3 corroborations across ≥2 distinct sessions. All knobs
(
max_fires_per_session,min_corroborations,min_sessions) are TOML-tunable.Tests
test_phantom_promotion_opportunity.py— store predicate (threshold,sessions, NULL-session exclusion, non-speculative exclusion, CONTRADICTS
exclusion, GC'd exclusion, ordering, cap, configurable threshold); config
resolution (default-off, env, TOML knobs + wrong-type fallback); detect + note
(incl. an escaping test that a hostile phantom containing the close tag /
markup cannot break the data boundary); orchestrator budget / dedup / disabled
/ no-session guards.
test_hook_phantom_promotion_wiring.py— end-to-endUserPromptSubmit:default-off silence, fires when enabled, second-turn dedup, below-threshold
silence.
test_session_ring_promotion.py— normalize round-trip, counter/dedupcontract, empty-key rejection, lane independence from Phantom belief lifecycle audit + trigger-driven generation in normal turns #980.
103 tests pass across the phantom / session-ring / hook / promotion suites,
including the pre-existing #980 and #550 tests (no regressions).
Config
Default-off; a fresh install is unaffected.
docs/user/CONFIG.mddocuments the[phantom_promotion]section.Summary by Sourcery
Add an opt-in phantom promotion-opportunity detector that surfaces highly corroborated speculative beliefs to users during prompt submission, without performing promotion itself.
New Features:
<aelfrice-phantom-promotion-opportunity>note on qualifyingUserPromptSubmitturns when enabled via[phantom_promotion]config.find_promotable_phantomsquery to identify live speculative beliefs that meet configurable corroboration and session thresholds for promotion consideration.Enhancements:
[phantom_promotion]configuration section, including enablement and tunable thresholds, and record the feature in the v4 changelog.Tests:
UserPromptSubmitwiring to ensure fail-soft, default-off behaviour.