@@ -16,18 +16,14 @@ import {
1616 * A caller names ONE row here and gets its whole pipeline shape: which
1717 * ambiguity contract resolves the selector (`resolution`, the matrix row), and
1818 * which structural stages run around that resolution — occlusion, off-screen,
19- * hittable-ancestor promotion, and the poll budget. Those four stages used to
20- * be per-caller pipeline code, so "`is` never consults occlusion" was true only
21- * as an ABSENCE of code: nothing declared it and nothing could fail if a later
22- * edit added it. Here it is a value, and the stage runners below are the only
23- * door to each stage, so the value decides.
19+ * hittable-ancestor promotion, and the poll budget. The runners below are the
20+ * only door to each stage, so a row that skips one still says so as a value:
21+ * making `is` consult occlusion means editing this table, not adding a call.
2422 *
25- * Rule of this table, inherited from the #1649 review: a row may only declare
26- * what these runners enforce. Every field is read by the runner named in its
27- * doc comment, and every row — including the ones whose stages are skips — is
28- * driven through those runners in selector-pipeline-policy.test.ts, so flipping
29- * any cell changes an assertion. Do not add a column until its runner exists;
30- * an unconsumed column reads as truth while being free to drift.
23+ * A row may only declare what these runners enforce (#1649 review). Every row,
24+ * skips included, is driven through every runner in
25+ * selector-pipeline-policy.test.ts, so flipping any cell changes an assertion —
26+ * add a column only once a runner reads it.
3127 */
3228
3329/**
@@ -83,9 +79,9 @@ export type SelectorPollBudget = {
8379
8480/**
8581 * Consumed by `selectorPollBudget`, which `createWaitPolling` derives its
86- * deadline and sleep from. `'none'` is a real answer, not an omission: a row
87- * that resolves against one capture has no polling contract, and asking for
88- * its budget is a bug rather than a defaulting opportunity .
82+ * deadline and sleep from. `'none'` is an answer, not an omission: a row that
83+ * resolves against one capture has no polling contract, so asking for its
84+ * budget is a caller bug — never a place to default one in .
8985 */
9086export type SelectorPollStage = SelectorPollBudget | 'none' ;
9187
@@ -203,13 +199,13 @@ export function selectorPipelineCandidates(
203199
204200/**
205201 * Stage 2, post-resolution: promotion, then the occlusion verdict on what
206- * promotion produced — the order every acting caller ran by hand .
202+ * promotion produced.
207203 *
208- * `occluded` carries the node to NAME in the refusal, which is the promotion
209- * input when the match itself is covered (promotion declines to retarget away
210- * from a covered node) and the promotion output otherwise. The refusal shape
211- * stays with the caller: the same verdict is a thrown interaction error, a
212- * daemon response, or a diagnosis, and those are not interchangeable.
204+ * `occluded` carries the node to NAME in the refusal — the promotion input
205+ * when the match itself is covered (promotion declines to retarget away from a
206+ * covered node), the promotion output otherwise. The refusal SHAPE stays with
207+ * the caller: this verdict becomes a thrown interaction error, a daemon
208+ * response, or a diagnosis, and those are not interchangeable.
213209 */
214210export type SelectorPipelineTarget =
215211 | { kind : 'target' ; node : SnapshotNode }
0 commit comments