docs(workflow-learnings): correct the "bounded" heuristic — a clock-shaped dep is not a fast one (#3012)
The severity heuristic I wrote in #2998 sorted dependencies **by name**, and #3007 is the counterexample. ## What I got wrong I classified `lifecycleDates` as *bounded* because its dep list contains `lifecycleNowMs`, and deferred it in #3001 with the line *"any wrong answer there survives only until the next update."* That value is driven by a **local-midnight boundary timer** — one tick per card per day. So a finished card shows no completion date for up to **twenty-four hours**. @gsxdsm found it after I'd written it off. `nowMs`, `Ticker` and `lastFetchTimeMs` span a live 30-second ticker, a per-fetch stamp, and a daily boundary. Sorting them by name puts a day-long defect in the same bucket as a 30-second one. ## The sharper half A card in a **completion lane doesn't subscribe to the shared live ticker at all** — that's exactly what the ticker's eligibility check is for, and what #2996 fixed. So the "fast" dependency that would have rescued this population is the one thing that population never receives. The corrected question is: **which dependencies refresh *for this population*** — not which ones appear in the list. Two of my three severity calls in that sweep leaned on a dep that the affected cards structurally never get. ## Why this is worth a PR rather than a quiet edit The doc is what the next person triages against. #3001 explicitly told them the four "bounded" sites were deprioritised **by design** — on reasoning that was wrong for at least one of them. Leaving that in place means someone defers a day-long defect on my say-so. Docs only. No code, no baselines. Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -293,10 +293,23 @@ Found: the blocker fan-out map (empty trait index, permanent), the card's live e
|
||||
|
||||
**Two properties decide severity, and both are checkable by reading the dependency list:**
|
||||
|
||||
1. **Does any dependency refresh quickly?** A live clock, `allTasks`, a task identity — any of these
|
||||
rebuilds the closure on the next update, so the wrong answer is a bounded window rather than
|
||||
permanent. The near-duplicate chip keys on `allTasks` and self-heals on the next task refresh; the
|
||||
time indicator keys on `task.column`, which never changes, so it never recovers.
|
||||
1. **Does any dependency refresh quickly?** `allTasks` or a task identity rebuilds the closure on the
|
||||
next update, so the wrong answer is a bounded window rather than permanent. The near-duplicate
|
||||
chip keys on `allTasks` and self-heals on the next task refresh; the time indicator keys on
|
||||
`task.column`, which never changes, so it never recovers.
|
||||
|
||||
**A CLOCK-SHAPED DEPENDENCY IS NOT AUTOMATICALLY A FAST ONE — read its cadence, not its name.**
|
||||
I classified `lifecycleDates` as bounded on the strength of a `lifecycleNowMs` dependency and
|
||||
deferred it. That value is driven by a LOCAL-MIDNIGHT boundary timer, one tick per card per day,
|
||||
so a finished card shows no completion date for up to twenty-four hours. The operator found it
|
||||
after I had written it off. `nowMs`, `Ticker` and `lastFetchTimeMs` span a live 30-second ticker,
|
||||
a per-fetch stamp and a daily boundary; sorting them by name puts a day-long defect in the same
|
||||
bucket as a 30-second one.
|
||||
|
||||
The interaction is worth keeping too: a card in a completion lane does not subscribe to the shared
|
||||
live ticker at all (that is what the ticker's own eligibility check is for), so the "fast"
|
||||
dependency that would have rescued it is the one thing it never receives. Ask which dependencies
|
||||
refresh FOR THIS POPULATION, not which ones exist in the list.
|
||||
2. **Is the value covered TRANSITIVELY?** A dependency that itself lists the flags gets a new
|
||||
identity when they arrive, which propagates. `TaskCard`'s context-menu memo omits all three role
|
||||
flags and is nonetheless correct, because it depends on `taskActionMenuModel.actions` and that
|
||||
|
||||
Reference in New Issue
Block a user