- Introduce new narrative probes for episode grammar, ensemble balance, and prose redundancy - Implement narrative presentation coverage tracking for better event visibility - Update harness scenarios to include new narrative ingestion and persistence tests - Refactor event emission to include narrative development IDs and presentations - Expand InterestCandidate to support narrative presentation models and roles
5.9 KiB
Event E2E suite (maintainable)
Goal: every catalog event is covered by automation that stays cheap when new ids are added.
Live accuracy roadmap: event-live-verification-plan.md.
Observe → confirm → emit: event-observation.md.
Tracks
| Track | Scenario | What it proves | How new events join |
|---|---|---|---|
| Inventory audits | nested in event_coverage |
Live library vs authored catalog | Add JSON row / live seed; audit fails until matched |
| A inject coverage | event_inject_coverage / ec30 |
Every camera-worthy id can register an interest key + label | Auto via EventCatalog.*.AuthoredIds |
| Live apply loop | event_live_apply_loop |
Happiness Signal + status gains via real apply | Auto loop; ledger id / id_drop / fail |
| Live relationship | event_live_relationship |
Vanilla setters/Beh + join negative; leave/family_removed/baby live fires |
Shared runner + ledger claims |
| Live pipelines | event_live_pipelines |
Traits/decisions/WorldLog/wars/eras/books/plots + libraries (worldLaw/item/subspecies_trait/power/gene/phenotype/meta traits); spell/biome best-effort unsupported; boat/combat best-effort | Auto loops + honest gaps |
| Live outcome smoke | event_live_outcome_smoke |
Short family + sample apply | Curated |
| Live coverage ledger | event_live_coverage |
Honest `none | feed |
| Semantic presentation | narrative_presentation_coverage |
Registry intake is typed; render uses no compatibility lookup or redundant phrase | Automatic through EventFeedUtil |
| Canonical narrative ingestion | narrative_canonical_ingestion |
Duplicate hooks create one event and one development for each durable family | Extend the recorder matrix |
Suite split (weight-aware)
| Gate | Includes | When |
|---|---|---|
event_suite |
audits + inject + apply loop + relationship + outcome smoke | Day-to-day event gate |
regression |
event_suite + event_live_pipelines (+ other product smokes) |
Full gate |
critical_smoke ×3 |
Spectator/settings/tip/exit | PR gate |
event_live_pipelines stays regression-only.
Flake budget is proven (--repeat 3 PASS); it remains heavier than day-to-day.
Idle quality (camera presentability)
See camera-presentability-plan.md.
| Check | Scenario / assert |
|---|---|
| Unpresentable Label rejected at Register | camera_presentability / presentability_probe |
No Watching: something interesting |
no_placeholder_tip |
| Focus survives max_cap | camera_presentability / has_focus |
| Ambient building falls are B-only | live patch + pipelines id_drop |
| Status-overlap onset without live status | status_overlap_camera / status_overlap_absent |
| Combat tip subject matches focus | combat_focus / tip_matches_focus |
| Combat dossier nametag matches focus | combat_focus / dossier_matches_focus |
| Combat 1v1 escalates to sided ensemble | combat_focus / combat_ensemble_escalate + tip_matches_any (Battle - / vs) |
| Cold combat clears fight tip | combat_focus / tip_not_contains fighting |
Live idle soak helper (Player.log window):
./scripts/soak-audit-player-log.sh 60
./scripts/soak-audit-player-log.sh --since-bytes "$(wc -c < ~/.config/unity3d/mkarpenko/WorldBox/Player.log)"
Coverage levels
Recorded in .harness/event-live-coverage.tsv (gitignored; regenerated each live run).
| Level | Meaning | Verified? |
|---|---|---|
none |
Inject only; no live fire this run | No |
feed |
Production feed entry with synthetic payload | Partial |
pipeline |
Vanilla fire proved the shared hook family; this id may not have fired | Partial |
id_drop |
Real fire; authored drop matched | Yes (accurate drop) |
id |
Real fire + expected note/interest | Yes |
unsupported |
No deterministic fire API; reason in notes |
Honest gap |
fail |
Unexpected miss/drop | Broken |
Inject / domain_feed never writes a live level other than leaving none.
Busy policy
Most feeds early-out on AgentHarness.Busy.
Live runners set ForceLiveEventFeeds (relationship also sets ForceRelationshipFeeds).
LiveFeedsAllowed = !Busy || ForceLiveEventFeeds || ForceRelationshipFeeds.
Ledger notes should record busy_bypass=ForceLiveEventFeeds (or the specific flag) when used.
Commands
./scripts/harness-run.sh event_inject_coverage
./scripts/harness-run.sh event_live_apply_loop
./scripts/harness-run.sh event_live_relationship
./scripts/harness-run.sh event_live_pipelines
./scripts/harness-run.sh event_suite
./scripts/harness-run.sh narrative_presentation_coverage
./scripts/harness-run.sh narrative_canonical_ingestion
./scripts/harness-run.sh regression
Artifacts (under IdleSpectator/.harness/, gitignored):
event-inject-coverage.tsv- inject wiringevent-live-coverage.tsv- source of truth for live proofevent-trigger-audit.tsv- design / call-site audit (not live proof)
Design rules
- Loop
AuthoredIds- no per-id harness steps for inject/apply/traits. - Inject ≠ live.
domain_feedis never live. ForceLiveEventFeeds/LiveFeedsAllowedbypass Busy during live runners only.- Coverage levels must not over-claim (see plan).
- Registry max-96: remove/clear during mass live loops so trim does not false-fail.
- Assert fails on
fail > 0; do not fail on cameranoneuntil a budget is explicitly tightened.
Code
EventInjectCoverageHarness,EventLiveApplyLoopHarness,EventLiveRelationshipHarness,EventLivePipelinesHarnessEventLiveCoverageLedger- Asserts:
event_inject_coverage,event_live_apply_loop,event_live_relationship,event_live_pipelines,event_live_coverage