Преглед изворни кода

HANDOFF.md: add Phase 13 plan (Focus filter + reset)

Plan-only commit. The Phase 13 entry in §9 Upcoming describes a task-list
"Focus" control (pick a sprint worker → only tasks where that worker
has non-zero assignment remain, plus any sw column that is zero across
every visible task collapses away) and a Reset button that clears
search / prio / owner / focus / manually-hidden columns in one click.
Pure client-side JS + view; no schema, route, controller, or audit
changes. §12 resume prompt updated so a fresh session sees Phase 13 as
scheduled.

No code changes.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
achiappa пре 2 недеља
родитељ
комит
e23cfac9da
1 измењених фајлова са 129 додато и 8 уклоњено
  1. 129 8
      HANDOFF.md

+ 129 - 8
HANDOFF.md

@@ -272,8 +272,127 @@ with a `BOOTSTRAP_ADMIN` audit row.
 
 ### Upcoming
 
-Nothing scheduled. The next time real work lands, follow the maintenance
-rule (§14) and add the entry here.
+- [ ] **Phase 13 — "Focus" filter in the task list**
+
+      **Problem.** With more than a handful of workers on a sprint, the
+      task list is wide and noisy for someone who only cares about what
+      *they* (or one specific teammate) are on the hook for. Today you
+      can filter by owner, but "owner" is not the same as "has time
+      assigned" — a task owned by Alice can still have Bob doing 3 days
+      of the work. Scanning a 12-worker grid for Bob's non-zero cells is
+      exactly what the computer should do.
+
+      **Goal.** Add a **Focus** control to the task-list toolbar. Pick
+      one sprint worker; the list then shows only tasks where that
+      worker's assignment is > 0, and any worker column that is zero for
+      every remaining visible task collapses away. A **Reset filters**
+      button next to it clears the search, priority filter, owner
+      multi-select, focus worker, and any manually-hidden columns in one
+      click. All state is purely client-side — no API changes.
+
+      **Scope (plan).**
+
+      1. **Toolbar (`views/sprints/show.php`).**
+         - Between the existing `[data-owner-filter-root]` and
+           `[data-columns-root]`, insert a `[data-focus-filter-root]`
+           block: a `<select data-focus-select>` with `<option value="">
+           All workers</option>` + one `<option value="{sw_id}">{name}
+           </option>` per sprint worker. Styled to match the other
+           toolbar controls.
+         - At the far left of the toolbar row, add a
+           `<button data-reset-filters>` (subtle, border-only, "Reset"
+           label). Visible only when any filter is active (managed by
+           the same logic that computes filter state below).
+         - No schema or controller changes — this is pure view + JS.
+
+      2. **JS filter state (`public/assets/js/sprint-planner.js`).**
+         - New localStorage key: `sp:{sprintId}:focusWorker`, string
+           value (sw_id or "").
+         - Hydrate on boot, reflect into `<select data-focus-select>`.
+         - On `change`: persist, then call `applyFilters()`.
+         - `applyFilters()` grows a fourth AND clause: if focus is set
+           and the row's `[data-assign][data-sw-id="{focus}"]` input has
+           value ≤ 0, hide the row. Use the same zero-tolerance the
+           capacity math uses (`Number(v) > 0`, not `!== 0`, so 0.0 is
+           treated as empty).
+
+      3. **Derived column auto-hide (new function,
+         `applyFocusColumnVisibility()`).**
+         - Called at the end of `applyFilters()` when focus is active.
+         - For each sprint worker's column `sw-{id}`:
+           - If any visible task row has `[data-assign][data-sw-id="{id}"]`
+             > 0 → keep the column as-is (respect the user's manual
+             visibility from the Columns dropdown).
+           - Otherwise → add a transient CSS class `focus-auto-hidden`
+             to every `[data-col="sw-{id}"]` cell/header (don't touch
+             the user's `hiddenCols` set, so turning focus off restores
+             their pick).
+         - When focus is cleared, strip every `.focus-auto-hidden` and
+           let `applyColumnVisibility()` re-run.
+         - Define `.focus-auto-hidden { display: none; }` in
+           `assets/css/input.css` (one line; Tailwind's `@layer
+           utilities` section, or inline in the view — former keeps the
+           vendored CSS path consistent).
+
+      4. **Reset button.**
+         - On click: clear `[data-task-search]`, reset
+           `[data-prio-filter]` to `""`, empty `ownerFilterSet` (and
+           persist), clear `focusWorker` (and persist), and empty
+           `hiddenCols` (and persist), then call the existing update
+           functions (`updateOwnerFilterUi`, `applyColumnVisibility`,
+           `applyFilters`). One code path, no reloads.
+         - Visibility rule: show the button when any of
+           `{search, prio, ownerFilterSet.size, focusWorker,
+           hiddenCols.size}` is non-empty. Re-evaluate after every
+           filter change.
+
+      5. **Edge cases / behaviour.**
+         - **Focus + owner + search all active** → AND. The existing
+           `applyFilters` ordering is fine; focus is just another
+           predicate per row.
+         - **Focused worker has no assigned tasks** → row list is empty,
+           every sw column is all-zero, so every sw column collapses.
+           The existing `[data-task-empty-filter]` banner covers the
+           empty-rows case — test that it shows, not the "No tasks yet"
+           banner.
+         - **New task created while focus is on** → `buildTaskRow` adds
+           a row with zero assignments, so the focus filter will hide
+           it immediately. Acceptable (user can clear focus to see it),
+           but a small UX surprise — call it out in the commit message.
+         - **Worker removed from sprint** → the reorder-then-reload
+           (§10) already covers this; focus just reads from the refreshed
+           DOM.
+         - **Archived sprints** → read-only, but the focus/reset
+           controls are pure UI, so they still work for viewers.
+
+      6. **Tests.** No new PHPUnit — this phase is 100% client-side JS
+         over existing HTML. Manual acceptance:
+           (a) pick a worker with assignments → only their tasks show
+               and only columns with non-zero cells for those tasks
+               remain;
+           (b) pick a worker with no assignments → empty-filter banner,
+               all sw columns collapsed;
+           (c) stack with search + prio + owner filters → all four AND;
+           (d) hit Reset → everything clears, Reset button vanishes.
+         Add these to [ACCEPTANCE.md](ACCEPTANCE.md) in the same commit
+         so the §10 manual walkthrough stays truthful.
+
+      **Out of scope.**
+      - Server-side enforcement of the filter. The API does not gate
+        which tasks a user can see — sprint membership already grants
+        read access to the whole sprint, and focus is a personal lens
+        over that.
+      - Multi-worker focus. Sticking to one worker at a time keeps the
+        UI + column-collapse rule simple. Multi-focus would muddy "what
+        counts as a relevant column" and nobody has asked for it.
+      - Persisting the Reset click as an audit event. Pure UI state, no
+        data mutation, no audit row.
+
+      **Spec alignment.**
+      - §3 / §4 / §5: unchanged — no schema or domain changes.
+      - §6 Routes: unchanged — no new endpoints.
+      - §7 Audit: unchanged — no mutations.
+      - §11: phpunit count stays 88 (no new tests).
 
 ## 10. Residual known gaps / deferred items
 
@@ -330,12 +449,14 @@ vendor/bin/phpunit
 Tell Claude:
 
 > Working on `/Users/achiappa/Development/claude_code_private/sprint_planer_web`.
-> Read `HANDOFF.md`, the git log, and `ACCEPTANCE.md`. All 12 phases are
-> shipped (see §9). There is no scheduled coding work. The only
-> outstanding items are in §10 (mostly a manual acceptance walkthrough
-> in the running container). If I ask for new work, follow the
-> maintenance rule in §14 — commit code, then commit a HANDOFF.md
-> update separately.
+> Read `HANDOFF.md`, the git log, and `ACCEPTANCE.md`. Phases 1–12 are
+> shipped (see §9); Phase 13 ("Focus" filter + reset in the task list)
+> is planned but not implemented — the scope is in §9 under Upcoming.
+> Other outstanding items are in §10 (mostly a manual acceptance
+> walkthrough in the running container). If I ask you to work Phase 13,
+> follow the maintenance rule in §14 — commit code, then commit a
+> HANDOFF.md update separately that moves the entry from Upcoming →
+> Shipped with its SHA.
 
 Claude should verify what's described here against actual repo state
 before acting — nothing here is load-bearing once it grows stale.