Skip to content

fix(masters): normalize whitespace around a non-empty Metrika counter id - #810

Merged
axisrow merged 2 commits into
mainfrom
ao/direct-cli-88/fix-metrika-counter-identity-whitespace
Aug 7, 2026
Merged

fix(masters): normalize whitespace around a non-empty Metrika counter id#810
axisrow merged 2 commits into
mainfrom
ao/direct-cli-88/fix-metrika-counter-identity-whitespace

Conversation

@axisrow

@axisrow axisrow commented Aug 7, 2026

Copy link
Copy Markdown
Owner

Summary

_metrika_counter_identity (direct_cli/browser/masters.py, added in PR #801) extracts the numeric counter id shared by the suggestion-text and read-back tag-display formats so _verify_saved can compare them for equality. The non-empty branch returned the identity unstripped:

identity = first_line.rsplit(" • ", 1)[1]
return identity if identity.strip() else text

If a real (non-empty) id has surrounding whitespace on one side but not the other — e.g. read-back "domain • 12345 \n30 целей" (trailing space before the newline) vs. suggestion "label • domain/path • 12345" (no trailing space) — the two identities ("12345 " vs "12345") wouldn't compare equal, and _verify_saved's Counter comparison would report a false save-mismatch even though the add actually succeeded.

Fix

identity = first_line.rsplit(" • ", 1)[1].strip()
return identity if identity else text

The existing empty/whitespace-only fallback behavior (PR #808's guard: return the original text unchanged when there's no real id after the last " • " separator) is unchanged — only the non-empty branch now normalizes whitespace.

Testing

  • Added test_strips_trailing_whitespace_around_a_real_id, test_strips_leading_whitespace_around_a_real_id, and test_suggestion_and_whitespace_padded_tag_display_share_identity (the exact scenario from the issue: suggestion text with no padding vs. read-back tag-display text with incidental whitespace, both must normalize to the same identity) to TestMetrikaCounterIdentity in tests/test_masters.py.
  • pytest tests/test_masters.py -k MetrikaCounterIdentity — 10 passed
  • pytest tests/test_masters.py — 843 passed
  • Full offline suite pytest — 3492 passed, 23 skipped, no regressions
  • black/flake8 clean on all changed files

Closes #809

🤖 Generated with Claude Code

_metrika_counter_identity extracts the numeric counter id shared by the
suggestion-text and read-back tag-display formats so _verify_saved can
compare them for equality. The non-empty branch returned the identity
unstripped, so an id with incidental surrounding whitespace on one side
but not the other (e.g. read-back "...12345 \n30 целей" vs. suggestion
"...12345") would not compare equal, producing a false save-mismatch
even though the add actually succeeded.

Closes #809

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XPPspf5omgkZJpq6uk6yAR
@axisrow

axisrow commented Aug 7, 2026

Copy link
Copy Markdown
Owner Author

🔍 Local review (cycle 1) — round 564e95fe-cb4c-4e02-8413-a38e69742e36

Reviewed locally (/review + Codex companion), no bots pinged.

Verdict Reviewer Finding Location
SKIP (clean) claude Claude /review found no issues across 7 independent angles: correctness, removed-behavior, cross-caller impact, reuse, simplification/efficiency, altitude, and CLAUDE.md conventions.
codex Codex companion review could not be programmatically parsed by its own JSON extractor on two automated attempts (prose preceded the JSON verdict block); the raw transcript was manually inspected and accepted by explicit user direction as an exception to the normal automated-parse path.
FIX codex Codex flagged (low confidence, 0.35) that stripping whitespace around a non-empty identity token also collapses distinct non-numeric malformed tokens that differ only by surrounding whitespace, partially narrowing the docstring-documented "malformed inputs must not silently match" invariant beyond the intended numeric-id case. direct_cli/browser/masters.py:5339-5343
Applied Restricted the whitespace-stripping normalization to tokens that are genuinely numeric (.isdigit()); non-numeric tokens now fall back to the original unstripped text, fully restoring the invariant for malformed input while keeping the fix for real numeric counter ids. direct_cli/browser/masters.py

Cycle 1/3.

Cycle-review finding (Codex, round 2, PR #810): stripping whitespace
around a non-empty identity token also collapsed distinct non-numeric
malformed tokens that differ only by surrounding whitespace (e.g.
"Label A •  foo " vs "Label B • foo "), narrowing the docstring's
documented 'malformed inputs must not silently match' invariant beyond
the intended numeric-id case.

Restrict the stripping normalization to tokens that are genuinely
numeric (.isdigit()) -- real counter ids are numeric per the original
live recon. A stripped non-numeric token now falls back to the
unstripped original text, fully restoring the invariant for malformed
input while keeping the #809 fix for real numeric counter ids.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XPPspf5omgkZJpq6uk6yAR
@axisrow

axisrow commented Aug 7, 2026

Copy link
Copy Markdown
Owner Author

🔍 Local review (cycle 2) — round 4243714e-0aac-4d6c-ac75-1e225fe32aef

Reviewed locally (/review + Codex companion), no bots pinged.

Verdict Reviewer Finding Location
SKIP claude Claude /review flagged (non-blocking, altitude/design observation, not a bug) that the function has accreted three sequential defensive branches across three issues, suggesting a future single-regex rewrite might be more maintainable. direct_cli/browser/masters.py:5307
— (clean) codex Manually reviewed Codex companion output (again unparseable by its own JSON extractor due to leading prose) approved the fix with no findings, independently re-verifying the #809 fix, the malformed-token guard, and a non-ASCII isdigit() edge case as non-material.

No FIX verdicts this round — reason to defer the design observation: the three guards each protect a distinct, tested, narrow scenario (empty token, whitespace padding, non-numeric malformed token); a regex rewrite risks silently changing behavior for one of the 12 existing regression tests without a corresponding maintainability win, and the current code passes cycle-review round 2 clean on correctness. Left as-is.

Cycle 2/3 — clean round, no FIX.

@axisrow

axisrow commented Aug 7, 2026

Copy link
Copy Markdown
Owner Author

📋 Review summary — all cycles

Cycle Reviewer Finding Verdict Resolution
1 (issue #809, pre-PR) Codex found an unstripped whitespace edge case where a real numeric counter id with padding on one side but not the other would fail Counter-based save verification despite the add succeeding. FIX Fixed in e773a1e (original PR commit)
1 codex Codex found stripping whitespace broadly (not restricted to numeric tokens) would collapse distinct non-numeric malformed inputs that differ only by surrounding whitespace, narrowing an existing safety invariant. FIX Fixed in 1ba7c44 (.isdigit() guard)
2 claude Claude noted the function has accumulated three sequential defensive branches across three issues and floated a future single-regex rewrite as more maintainable; not a bug. SKIP Left as-is — see round-2 PR comment for rationale

Totals: 2 FIX (both resolved), 1 SKIP, 0 UNVERIFIED. Codex companion output was manually inspected both rounds due to a JSON-parse gap in the companion tool itself (prose preceding the JSON verdict block); accepted by explicit user direction as noted in this PR's round-1 comment.

@axisrow
axisrow merged commit 6bc0cea into main Aug 7, 2026
6 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

masters: _metrika_counter_identity doesn't normalize surrounding whitespace around a non-empty id

1 participant