From dd948120ffa735f08593a3d7af738883e129c1c9 Mon Sep 17 00:00:00 2001 From: VinPropane Date: Sat, 25 Apr 2026 19:52:45 -0400 Subject: [PATCH] NEO-27: add implementation plan for Slice 3 telemetry hook sites --- docs/plans/NEO-27-implementation-plan.md | 78 ++++++++++++++++++++++++ 1 file changed, 78 insertions(+) create mode 100644 docs/plans/NEO-27-implementation-plan.md diff --git a/docs/plans/NEO-27-implementation-plan.md b/docs/plans/NEO-27-implementation-plan.md new file mode 100644 index 0000000..fb1e338 --- /dev/null +++ b/docs/plans/NEO-27-implementation-plan.md @@ -0,0 +1,78 @@ +# NEO-27 — Implementation plan + +## Story reference + +| Field | Value | +|--------|--------| +| **Key** | NEO-27 | +| **Title** | E1.M3: Slice 3 telemetry hook sites (`target_changed`, …) | +| **Linear** | [NEO-27](https://linear.app/neon-sprawl/issue/NEO-27/e1m3-slice-3-telemetry-hook-sites-target-changed) | +| **Slug** | E1M3-05 | +| **Git branch** | `NEO-27-e1m3-slice-3-telemetry-hook-sites` | +| **Parent context** | [Epic 1 — Core Player Runtime](https://linear.app/neon-sprawl/project/epic-1-core-player-runtime-client-controls-character-loop-66bd590cd016) · [E1M3 prototype backlog](E1M3-prototype-backlog.md) | +| **Decomposition** | [Epic 1 Slice 3 — telemetry hooks](../decomposition/epics/epic_01_core_player_runtime.md#epic-1-slice-3); [E1.M3 — InteractionAndTargetingLayer](../decomposition/modules/E1_M3_InteractionAndTargetingLayer.md) | + +## Goal, scope, and out-of-scope + +**Goal:** Establish **documented hook sites** for Epic 1 Slice 3 product telemetry names: **`target_changed`** (wired to real selection transitions), plus **reserved** (no-op / comment-only) sites for **`ability_cast_requested`** and **`ability_cast_denied`** until [E1.M4](../decomposition/modules/E1_M4_AbilityInputScaffold.md) + [E5.M1](../decomposition/modules/E5_M1_CombatRulesEngine.md). All real ingest waits on **`TODO(E9.M1)`** per [E9.M1 — TelemetryEventSchema](../decomposition/modules/E9_M1_TelemetryEventSchema.md). + +**In scope** + +- **Event names** in code or doc comments matching [epic Slice 3](../decomposition/epics/epic_01_core_player_runtime.md#epic-1-slice-3) (`target_changed`, `ability_cast_requested`, `ability_cast_denied`). +- **`TODO(E9.M1)`** at each hook site until a catalog exists. +- **Optional dev logging** when a flag is enabled (reuse or extend the NEO-26 `log_selection_events` pattern on the client; optional `ILogger` / `Debug.WriteLine` guard on server only if we add a clearly dev-gated path—prefer comments + single optional trace line consistent with repo norms). +- **`documentation_and_implementation_alignment.md`:** extend the **E1.M3** snapshot row to mention NEO-27 hook sites (per Linear acceptance; NEO-23 is already on `main`). + +**Out of scope** + +- Production ingest, dashboards, OpenTelemetry. +- Changing `TargetState` / HTTP contracts (NEO-23). +- Implementing real ability cast requests (E1.M4). + +## Acceptance criteria checklist + +- [ ] **Documented event names** in-repo matching Slice 3: `target_changed`, `ability_cast_requested`, `ability_cast_denied` (latter two may be comment-only reserves). +- [ ] **`TODO(E9.M1)`** at each hook site referencing schema work. +- [ ] **Optional dev logging** for `target_changed` when a documented flag is on (or explicitly documented that an existing flag covers it, with log line including the product event name). +- [ ] **`documentation_and_implementation_alignment.md`** E1.M3 row updated for NEO-27. + +## Technical approach + +1. **`target_changed` (client)** — Canonical prototype mirror: when **`TargetSelectionClient`** emits **`selection_event`** (NEO-26), the product telemetry name is **`target_changed`** (same transition: normalized `lockedTargetId` change, with `cause` / `sequence` carrying intent). Add a short class-level or method-level note on **`_maybe_emit_selection_event`** linking **`selection_event`** → **`target_changed`**. Optionally prefix dev **`print`** (when `log_selection_events` is true) with a literal `target_changed` token so grep and QA are unambiguous. + +2. **`target_changed` (server)** — Authoritative lock id transitions occur in **`InMemoryPlayerTargetLockStore.ApplySet`** / **`ApplyClear`** when the stored lock id actually changes (sequence bumps). Add **`//` / `///` comments** (and `TODO(E9.M1)`) at those mutation success paths as the **server-side hook site** for `target_changed`. Rationale: single choke point; HTTP handlers stay thin. + +3. **`ability_cast_requested` / `ability_cast_denied` (reserve)** — No hotbar or cast route exists yet. Add a compact **comment block** in **`client/scripts/main.gd`** (or the first file E1.M4 will extend for input, if we prefer—**Decision:** `main.gd` next to other prototype wiring) listing the two event names and pointing to E1.M4 / E5.M1 + E9.M1. Optionally mirror a one-line reserve in **`TargetingApi.cs`** near denial responses noting that **`ability_cast_denied`** (with `reasonCode`) will attach to a **future cast POST**, not the current target-select deny path—avoids confusion with selection denials. + +4. **Docs alignment** — Append to the E1.M3 **Snapshot** cell: NEO-27 documents Slice 3 telemetry hook sites; link this plan. + +## Files to add + +**None** — hook sites are comments / optional log text on existing modules (unless we later extract a shared `TelemetryHooks` static class; out of scope for this slice). + +## Files to modify + +| Path | Rationale | +|------|-----------| +| `client/scripts/target_selection_client.gd` | Document `target_changed` ↔ `selection_event`; optional dev log prefix; `TODO(E9.M1)`. | +| `server/NeonSprawl.Server/Game/Targeting/InMemoryPlayerTargetLockStore.cs` | Server authoritative `target_changed` hook site on lock id transitions. | +| `client/scripts/main.gd` | Reserved comment block for `ability_cast_requested` / `ability_cast_denied` (E1.M4 + E5.M1). | +| `server/NeonSprawl.Server/Game/Targeting/TargetingApi.cs` | Optional one-line reserve clarifying cast denials vs target-select denials (avoids mis-mapping event names). | +| `client/README.md` | Short “Slice 3 telemetry (NEO-27)” pointer next to SelectionEvent section. | +| `docs/decomposition/modules/documentation_and_implementation_alignment.md` | E1.M3 snapshot: NEO-27 telemetry hook sites landed (per team rule). | +| `docs/decomposition/modules/E1_M3_InteractionAndTargetingLayer.md` | Optional one-line under telemetry: code hook pointers (`target_selection_client.gd`, lock store)—only if the module table still says hooks are TODO-only; keep register alignment. | + +## Tests + +| File | Action | +|------|--------| +| `client/test/selection_event_client_test.gd` | **Change only if** new observable behavior is added (e.g. new export or signal). If implementation is comments + optional `print` format only, **no test change** — manual QA: enable `log_selection_events`, tab/clear, confirm output contains `target_changed`. | + +**Server:** No new tests required for comment-only / dev-trace placeholders unless we introduce a testable abstraction (out of scope). + +## Open questions / risks + +- **Linear `blockedBy` NEO-24:** Relation may still show in Linear; **tab-target path is on `main`**, so implementation is unblocked in-repo. Remove or complete the Linear dependency when convenient. +- **Ability reserve file:** If you prefer a dedicated `ability_input_placeholder.gd` for E1.M4 instead of `main.gd`, say so before implementation; plan defaults to **`main.gd`** to avoid extra nodes until E1.M4. + +**None** otherwise.