# v2.0 spec: phantom promotion-trigger rule

Spec for issue [#229](https://github.com/robotrocketscience/aelfrice/issues/229). Substrate-cascade addendum to [`substrate_decision.md`](substrate_decision.md) (#196 ratified Option B). Companion to [`v2_wonder_consolidation.md`](v2_wonder_consolidation.md) (#228) — that issue specifies the strategy that generates phantoms; this issue specifies the rule that promotes them to `origin = user_validated`.

Status: spec, no implementation. **Recommendation included** for the rule shape; threshold tuning requires the labeled-corpus benchmark below.

## What's being decided

What rule moves a phantom belief (`origin = speculative`) to `origin = user_validated`. Three naive triggers were proposed in the lab and all three are rejected. v2.0 needs a real rule with explicit predicate, source rows, threshold, and audit-trail entry.

## The three rejected triggers (verbatim from issue body)

1. **Promote on N positive feedback events** — conflates posterior movement with discrete origin promotion; threshold has no benchmark.
2. **Promote on retrieval count** — re-uses `last_retrieved_at` / hook-tagged `valence=0.1` rows. Promotes purely because the user happens to ask similar questions. **Selection bias, not validation.**
3. **Promote on `user_corrected` adjacency** — "the agent corrected something nearby" is not the user acknowledging the original belief.

These are non-triggers. The v2.0 rule must not collapse to any of them.

## What the rule needs (the four constraints)

Per issue body § What a real promotion rule needs:

1. **Single source of truth.** The rule must be visible from the row(s) that trigger it. No hidden state-machine edges.
2. **Distinguish posterior movement from origin promotion.** Posteriors are continuous; origin is a discrete trust label. Promoting one off the other has to be deliberate, not incidental.
3. **Benchmarked threshold.** Any N or τ has to be tuned against a labeled corpus where "this belief should have been promoted" is ground truth.
4. **No selection bias.** Triggers driven by user query distribution must not promote.

## Recommendation: the explicit-acknowledgment rule

A phantom promotes when **and only when** the user explicitly acknowledges it via one of two surfaces:

### Surface A — explicit `aelf:validate <id>` slash command

A new slash command (and CLI / MCP equivalent) that takes a phantom belief ID and writes a `validation_event` row tagged `source = explicit_user`, `valence = +1.0`, `origin_change = speculative → user_validated`. The promotion happens *in the same atomic write*; there is no deferred state machine.

### Surface B — `aelf:lock <text>` matching a phantom's content

When a user locks a statement (`/aelf:lock`), the lock pipeline checks for any phantom belief whose `content_hash` matches OR whose normalized text exceeds Jaccard ≥ 0.9 against the lock target. Matched phantoms promote in the same transaction as the lock.

Both surfaces produce a row visible in `feedback_history` (Surface A) or the `locks` audit (Surface B) — single source of truth, satisfies constraint #1.

### Why this rule satisfies the four constraints

1. **Single source of truth.** Surface A writes a `validation_event`; Surface B writes a `lock_event`. Both rows carry the `origin_change` field. Inspector can ask "why did belief X promote?" and the answer is one row.
2. **Posterior vs origin separation.** Posterior continues to move on `apply_feedback` calls. Origin only changes on these two surfaces. Continuous and discrete separation preserved.
3. **Benchmarked threshold.** No threshold to tune. The rule is binary: either the user typed the validation/lock surface or they didn't. (See § Labeled-corpus benchmark below for the *recall* check.)
4. **No selection bias.** Neither surface fires on retrieval traffic, hook valence, or correction adjacency. The only path to promotion is explicit user typing.

## Labeled-corpus benchmark plan

Required by constraint #3 even though the rule has no tunable threshold — we need to verify that the rule has acceptable **recall** (validates phantoms users *would* validate if asked) and acceptable **precision** (doesn't validate phantoms users would reject).

### Corpus

Use the wonder-consolidation R0 synthetic corpus (200 atoms; campaign in #228) extended with:

- 50 phantoms generated by the winning strategy from #228.
- For each phantom, a human-labeled `should_promote: bool` ground truth, derived by showing the phantom alongside its constituent atoms to a labeler and asking "would you lock this if it surfaced?"

### Metrics

- **Recall:** of phantoms with `should_promote = true`, what fraction get promoted under simulated user behavior (50% lock-flow simulation, 50% explicit-validate simulation, 0% no-action simulation as a control). Target: ≥ 70%.
- **Precision:** of phantoms that promote under simulation, what fraction had `should_promote = true`. Target: ≥ 90%. Lower precision means the lock matcher (Surface B Jaccard ≥ 0.9) is too loose.
- **Selection-bias control:** verify that retrieval-frequency rank does not predict promotion under the rule. Pearson correlation between (retrieval count over 7d) and (promoted: bool) ≤ 0.2.

If precision falls below 90%, tighten Surface B Jaccard. If recall falls below 70%, broaden Surface B's normalization (lemmatization, stopword strip) before adding new surfaces.

## Decision asks

- [ ] **Confirm the rule shape.** Two-surface explicit acknowledgment, no count thresholds, no implicit triggers.
- [ ] **Confirm Surface B Jaccard threshold default = 0.9.** Tunable post-benchmark per § Labeled-corpus benchmark.
- [ ] **Confirm `aelf:validate` as the surface name.** Alternative: `aelf:promote`, `aelf:confirm`. Recommendation: `aelf:validate` matches existing semantics where `origin = user_validated` is the target state.
- [ ] **Confirm the benchmark gates v2.0 ship.** If precision < 90% or recall < 70% on R<final>, the rule does not ship; #229 stays open and the wonder line item ships without auto-promotion (phantoms remain `origin = speculative` indefinitely).
- [ ] **Confirm the explicit non-trigger list:** N-feedback, retrieval-count, user_corrected adjacency. Anything else surfaced during review gets added here, not silently allowed.

## Out of scope

- Phantom **generation** strategy (#228).
- Phantom **lifecycle** (`wonder_ingest`, `wonder_gc` TTL=14d) — separate v2.0 sub-issue.
- Demotion (`origin = user_validated → speculative`) — not currently planned; may surface if user-validated phantoms accumulate stale signals.
- Cross-project phantom federation — not applicable; phantoms are per-project.

## Provenance

Lab memory cited in issue body: `103307e54dc4ee70` (2026-04-28).
Companion: [v2_wonder_consolidation.md](v2_wonder_consolidation.md) (#228).
Substrate ratification: [substrate_decision.md](substrate_decision.md) (Option B). Substrate-compatible; no per-axis state involved.
