56 lines
2.7 KiB
Markdown
56 lines
2.7 KiB
Markdown
# Event observation (observe → confirm → emit)
|
|
|
|
IdleSpectator learns about the game through Harmony sensors.
|
|
|
|
Those sensors must not treat AI noise as catalog truth.
|
|
|
|
## Pipeline
|
|
|
|
```text
|
|
Patch (Observe) → EventOutcome (Confirm) → Feed Emit (EventReason + catalog)
|
|
```
|
|
|
|
| Layer | Responsibility | Lives in |
|
|
|-------|----------------|----------|
|
|
| Observe | Thin Harmony Prefix/Postfix; snapshot before when needed | `Events/Patches/*` |
|
|
| Confirm | Did the semantic claim happen? | `Events/EventOutcome.cs` |
|
|
| Bridge | Drop unconfirmed with `InterestDropLog`; else run emit | `Events/EventObservation.cs` |
|
|
| Emit | Catalog dials, keys, `EventReason` labels | `Events/Feeds/*` |
|
|
|
|
## Rules
|
|
|
|
1. **Never** treat `BehResult.Continue` as success by itself.
|
|
2. Prefer **state setters** when they exist (`setLover`, `setParent*`, `newFamily`, `setFamily`, `addNewStatusEffect`).
|
|
3. Beh hooks need **before/after** confirmation (`EventOutcome.GainedFamily`, `StillSeekingLover`, …).
|
|
4. Unconfirmed attempts log `outcome_unconfirmed` via `InterestDropLog` (not silent).
|
|
5. New catalog events must name their confirm predicate (or setter) in the audit TSV `game_call_site` / `fix_action`.
|
|
|
|
## Example (family join)
|
|
|
|
Vanilla `BehFamilyGroupJoin` returns Continue even when no nearby family exists.
|
|
|
|
Confirm with `GainedFamily(before, actor)` before Emit `family_group_join`.
|
|
|
|
Negative harness: Beh Continue with no family gain must log `outcome_unconfirmed` and must not register `rel:family_group_join`.
|
|
|
|
## Adding an event
|
|
|
|
For every new camera-worthy catalog id, record three things up front:
|
|
|
|
| Field | Meaning | Example |
|
|
|-------|---------|---------|
|
|
| **Confirm predicate** | `EventOutcome` helper, or “setter is the transition” | `GainedFamily`, `setLover(null)` |
|
|
| **Fire API** | Vanilla call the live harness will invoke | `BehFamilyGroupLeave.execute`, `Actor.addTrait` |
|
|
| **Expected live level** | Honest target after the runner claims | `id`, `id_drop`, `pipeline` (`shared=`…), or `unsupported` |
|
|
|
|
Then implement:
|
|
|
|
1. Find the real game call site (setter or Beh).
|
|
2. Add/extend an `EventOutcome` predicate if Beh Continue is ambiguous.
|
|
3. Patch calls `EventObservation.Confirm` / `ConfirmAfter` then the domain feed.
|
|
4. Mark the audit row with the confirm rule (`event-trigger-audit.tsv` = design/call-site only).
|
|
5. Harness: live path asserts key **or** authored drop; assert absence / `outcome_unconfirmed` when the outcome fails.
|
|
6. Do **not** call `domain_feed` / inject and label it live.
|
|
7. Live proof lands in `.harness/event-live-coverage.tsv` via `EventLiveCoverageLedger.Claim` - that file is the source of truth for live levels, not the audit TSV.
|
|
|
|
See [`event-live-verification-plan.md`](event-live-verification-plan.md) for claiming rules and suite wiring.
|