11 KiB
NEO-109 — Implementation plan
Story reference
| Field | Value |
|---|---|
| Key | NEO-109 |
| Title | E5M3-10: Slice 3 encounter telemetry hook sites |
| Linear | https://linear.app/neon-sprawl/issue/NEO-109/e5m3-10-slice-3-encounter-telemetry-hook-sites |
| Module | E5.M3 — EncounterAndRewardTables · Epic 5 Slice 3 · backlog E5M3-10 |
| Branch | NEO-109-slice-3-encounter-telemetry-hook-sites |
| Blocked by | NEO-106 — combat wiring (Done on main); NEO-107 — event record (Done on main) |
| Pattern | NEO-49 / NEO-64 — comment-only engine anchors; NEO-84 — reserved encounter_start in Slice 1 combat |
| Blocks | None — client capstone NEO-110 / NEO-111 do not depend on telemetry |
| Client counterpart | None — server-only comments; player-visible HUD is NEO-110 |
Kickoff clarifications
| Topic | Question | Agent recommendation | Answer |
|---|---|---|---|
reward_attribution shape |
Once per completion vs per grant vs skip? | Once per successful completion — batch payload after all grants + completion mark commit; item_created remains at inventory layer (NEO-56). |
Adopted — once per completion |
encounter_complete anchor |
Single engine anchor vs dual wiring + ops? | EncounterCompletionOperations.TryCompleteAndGrant only — remove duplicate in EncounterCombatWiring (NEO-49 / NEO-64 precedent). |
Adopted — completion ops only |
| Manual QA doc | docs/manual-qa/NEO-109.md? |
Yes (NEO-64 pattern). | Adopted — skip (NEO-108 server-only precedent per user) |
encounter_complete_denied |
Keep deny hook on Deny? |
Keep — already landed from NEO-105 review; NEO-56 deny precedent; not in epic vocabulary but comments-only. | Adopted (implicit — no change) |
| Runtime behavior | Comments-only vs dev ILogger? |
Comments-only — TODO(E9.M1); no production logging (NEO-49 precedent). |
Adopted (repo precedent; not asked) |
Goal, scope, and out-of-scope
Goal: Document and place comment-only hook sites on the server-authoritative encounter funnel for Epic 5 Slice 3 product telemetry encounter_start, encounter_complete, and reward_attribution, plus consolidate anchors so E9.M1 wiring has one documented surface per event.
In scope (from Linear + E5M3-10):
TODO(E9.M1)markers at encounter start, completion commit, and once reward attribution on successful grant batch.server/README.mdencounter telemetry subsection; epic Slice 3 vocabulary cross-link.- Normalize partial NEO-109 stubs from NEO-104/105/106 into full NEO-64-style comment blocks (event name, payload fields, no ingest).
- Update NEO-84 reserved
encounter_startpointer inCombatOperationsto E5.M3 anchor (comments only). - E5M3 backlog + alignment register + module snapshot when implementation completes.
Out of scope (from Linear + backlog):
- Production ingest, dashboards (E9.M1).
ILogger/ metrics / dev-only log lines.- Godot client, Bruno changes, API/wire contract changes.
docs/manual-qa/NEO-109.md(kickoff: skip).- Duplicate hook comments in
AbilityCastApiorEncounterCombatWiringforencounter_complete/reward_attribution.
Acceptance criteria checklist
- Hook names match epic_05 Slice 3 vocabulary (
encounter_complete, reward attribution /reward_attribution). - No runtime behavior change beyond comments.
Implementation reconciliation (shipped)
encounter_start: full comment block inEncounterProgressOperations.TryActivateOnFirstEngagement; NEO-84CombatOperationsreserved pointer updated.encounter_complete+reward_attribution: full comment blocks inEncounterCompletionOperations.TryCompleteAndGrantafter event record; duplicate removed fromEncounterCombatWiring(delegate pointer only).encounter_complete_denied: retained onDeny.- Docs:
server/README.mdencounter telemetry subsection; E5.M3 module snapshot; alignment register; module dependency register; E5M3-10 backlog landed note.
Technical approach
Current state (on main)
Partial NEO-109 tags already exist from precursor stories:
| Event | File | Status |
|---|---|---|
encounter_start |
EncounterProgressOperations.TryActivateOnFirstEngagement |
Stub present — expand to full block |
encounter_complete |
EncounterCompletionOperations success path |
Thin TODO — expand; remove EncounterCombatWiring duplicate |
encounter_complete_denied |
EncounterCompletionOperations.Deny |
Block present — keep |
reward_attribution |
— | Missing — add on completion success path |
Hook sites (after implementation)
-
encounter_start—EncounterProgressOperations.TryActivateOnFirstEngagement, immediately beforeprogressStore.TryActivatewhen activation will proceed (not when already started/completed/no encounter):- Comment block: future E9.M1 event
encounter_start. TODO(E9.M1): catalog emit— once per player+encounter on first activation.- Payload:
playerId,encounterId,npcInstanceId(engagement target), optionalrequiredNpcInstanceIdscount. - NEO-84: update class-level reserved comment in
CombatOperationsto point here (Slice 3 landed).
- Comment block: future E9.M1 event
-
encounter_complete—EncounterCompletionOperations.TryCompleteAndGrant, afterTryMarkCompleted+TryRecordsucceed (authoritative commit):- Replace thin TODO with full block naming
encounter_complete. - Payload:
playerId,encounterId,rewardTableId,completedAt,idempotencyKey,grantedItemssummary fromEncounterCompleteEvent. - Remove duplicate hook block at end of
EncounterCombatWiring.TryProcessCastOutcome(wiring only calls completion ops).
- Replace thin TODO with full block naming
-
reward_attribution— same success path, once per completion (kickoff decision):- Comment block naming
reward_attribution(snake_case catalog name; epic prose “reward attribution”). TODO(E9.M1): catalog emit— once when reward table grants commit for encounter completion.- Payload:
playerId,encounterId,rewardTableId,grantedItems[](batch fromEncounterGrantApplied/ event store snapshot). - Note in comment: inventory layer still emits
item_createdper stack viaPlayerInventoryOperations(NEO-56);reward_attributionis encounter-scoped attribution for E7.M2 / loot analytics.
- Comment block naming
-
encounter_complete_denied— keep existingDenyblock (reasonCodefromEncounterCompletionReasonCodes). -
Cross-references:
EncounterCompletionResult/EncounterCompleteEventxml summaries → telemetry anchors inEncounterCompletionOperations.EncounterProgressOperationsclass summary →encounter_startanchor.server/README.md: new Encounter telemetry hooks (NEO-109) subsection (after NEO-108 or NEO-106 block) listing all three epic events + deny +CombatOperationsreserved pointer.E5_M3_EncounterAndRewardTables.md,documentation_and_implementation_alignment.md,module_dependency_register.md,E5M3-prototype-backlog.md: E5M3-10 landed note when complete.
NEO-56 / NEO-64 analogy
| Layer | Inventory / gather | Encounter Slice 3 |
|---|---|---|
| Low-level item mutation | item_created (NEO-56) |
Same on each TryAddStack during grants |
| Orchestration / funnel | resource_gathered (NEO-64) |
encounter_complete + reward_attribution (NEO-109) at completion commit |
| Engagement | — | encounter_start at first activation |
Files to add
None.
Files to modify
| Path | Rationale |
|---|---|
server/NeonSprawl.Server/Game/Encounters/EncounterCompletionOperations.cs |
Expand encounter_complete block; add reward_attribution once on success; keep encounter_complete_denied on Deny. |
server/NeonSprawl.Server/Game/Encounters/EncounterCombatWiring.cs |
Remove duplicate encounter_complete hook; one-line pointer to EncounterCompletionOperations. |
server/NeonSprawl.Server/Game/Encounters/EncounterProgressOperations.cs |
Expand encounter_start block to NEO-64 style; class summary cross-ref. |
server/NeonSprawl.Server/Game/Encounters/EncounterCompletionResult.cs |
Xml summary → telemetry hook anchor (no behavior change). |
server/NeonSprawl.Server/Game/Encounters/EncounterCompleteEvent.cs |
Xml summary → completion + attribution hook anchor (no behavior change). |
server/NeonSprawl.Server/Game/Combat/CombatOperations.cs |
Update reserved encounter_start comment → E5.M3 EncounterProgressOperations anchor. |
server/README.md |
NEO-109 encounter telemetry hooks subsection; fix NEO-104 vs NEO-109 label on encounter_start in NEO-106 table if needed. |
docs/decomposition/modules/E5_M3_EncounterAndRewardTables.md |
NEO-109 telemetry hooks landed line. |
docs/decomposition/modules/documentation_and_implementation_alignment.md |
E5.M3 row: NEO-109 hook sites. |
docs/decomposition/modules/module_dependency_register.md |
E5.M3 note — E5M3-10 complete when landed. |
docs/plans/E5M3-prototype-backlog.md |
E5M3-10 acceptance checkboxes + landed note when complete. |
Tests
| Test file | What it covers |
|---|---|
| (none added or changed) | Comments-only; no behavior or wire contract change. Regression: dotnet test NeonSprawl.sln (existing EncounterCompletionOperationsTests, EncounterProgressOperationsTests, cast integration tests unchanged). |
Manual verification (no checklist doc): grep NEO-109 / encounter_complete / reward_attribution / encounter_start under server/NeonSprawl.Server/Game/Encounters/; confirm EncounterCombatWiring has no encounter_complete emit comment; confirm no new ILogger or ingest calls.
Open questions / risks
| Question / risk | Agent recommendation | Status |
|---|---|---|
Overlap with NEO-56 item_created |
Keep both — item_created per stack; reward_attribution once per encounter completion for attribution context. |
adopted (kickoff) |
encounter_complete_denied not in epic list |
Keep deny hook — NEO-56 precedent; zero runtime cost. | adopted |
| Precursor partial stubs | Treat as draft; NEO-109 normalizes style and removes wiring duplicate. | adopted |
None blocking.