You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Commit 35ff81f
Browse filesBrowse the repository at this point in the historyBrowse files
fix(replay): unify the id-uniqueness predicate across both writer sites (#1269 review)
Address the maintainer review on #1272:
1. ONE shared uniqueness predicate. The two demotion sites were counting
id matches with DIFFERENT semantics — `demoteNonUniqueId` via
`filterIdentitySet` (NFC + 256-byte cap, and a broken-parent-walk
exclusion), `selectableId` via a raw `normalizeSelectorText` scan (trim,
no NFC/cap, no exclusion) — so the identity tuple and the selector chain
could disagree and half-demote (id gone from one, kept in the other).
Extract `idMatchCountInTree(nodes, id)` in target-identity-node.ts,
counting over the canonical `readNodeLocalIdentity` id the replay
verifier keys on, with no ancestry/parent-walk exclusion. Both
`demoteNonUniqueId` and `selectableId` now call it. Corrects the
inaccurate "vacuously-true / plain id scan" comment.
Cross-invariant test (build.test.ts): for the same node+tree,
evidence.id === undefined iff the built chain has no id= clause — across
demoted, unique, and a non-NFC (decomposed vs precomposed) edge case.
Verified it fails under the old raw-scan and passes under the unified
predicate.
2. End-to-end reorder proof (session-replay-target-classification.test.ts):
record against a tree whose rows share android:id/title, then classify
against a DIFFERENT replay tree where the shared-id rows reorder — the
demoted role+label identity rebinds the correct row (verified,
matchCount 1) while `id="android:id/title"` resolves ambiguously (null).
This pins the FDR 1.0 -> 0 mechanism, not just record-time demotion.
3. Removed the conflated "20/20 clean" live-number comment from the unit
test; it now states the mechanism (role+label selectivity) instead.
Behavior for the already-clean unique-id path is unchanged: for ordinary
ascii ids the canonical count equals the old raw count. The only outcomes
that change are the edge cases the old split mishandled (non-NFC, broken
parent walk) — where demotion is the correct result. The kept clause still
emits the chain's own normalizeSelectorText id string, so unique ids lead
the chain exactly as before.
0 commit comments