Repository navigation
fix(replace): keep run-mode substitutes unique across the run - #394
Conversation
In run mode a substitute emitted for one key is never emitted for another key later in the run, placeholders are numbered across the run, and a key's established run-wide substitute wins over another key's new proposal. Record mode is unchanged. 🤖 Generated with Claude Code Co-Authored-By: Claude <noreply@anthropic.com> Signed-off-by: Aaron Gonzales <aagonzales@nvidia.com>
[Medium impact] The PR appears safe to merge; the earlier copying issue is fixed and no new actionable issues were found. SummaryRun mode now reserves emitted substitutes across records, numbers placeholders across the run, and gives established mappings priority over new proposals.
Reviews (2) · Last reviewed commit: "perf(replace): check run-wide substitute..." · Reviewed by Greptile |
| placeholders[entry["label"]] += 1 | ||
| taken = originals | proposed.keys() | emitted.keys() | ||
| used += 1 | ||
| protected = originals | proposed.keys() | emitted.keys() | taken.keys() |
There was a problem hiding this comment.
Placeholders repeatedly copy earlier substitutes
Each placeholder copies every earlier substitute through | taken.keys(). For distinct names that repeatedly receive the same proposal, almost every record needs a placeholder. Doubling such a run can roughly quadruple this copying work.
Check each candidate against taken separately instead of copying it into protected.
Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!
…aceholder Signed-off-by: Aaron Gonzales <aagonzales@nvidia.com>
Verdict: approve. The change does what the PR describes: run-wide uniqueness of substitutes, an established mapping wins, record mode unchanged, deterministic output, and linear time. None of the findings below needed to block the merge. They are follow-ups. VerificationEach item was checked with direct calls to
Findings
Interaction with other PRs#333 and #379 do not interact with this change. Both target |
With
Substitute(consistency="run"), two different values no longer receive the same substitute anywhere in the run, and a value that already has a run-wide substitute keeps it. Before this change, each record checked collisions only against itself. As a result, "Alice" in one record and "Carl" in a later record could both become "Maya", and a join on substitutes could merge two people. The docs recommend run mode for exactly that join.Behaviour (run mode only)
[SUBSTITUTE_FIRST_NAME_1]names one value only.consistency="record"output is unchanged. The Rewrite path uses record mode and is unaffected.The run-mode join recommendation in
docs/concepts/replace.mdstays, because the uniqueness it needs now holds; one sentence there states the guarantee. The fold's docstring describes the run-mode rules.Review focus
collisiontest case changes its run-mode expectation: record 2 keepsAcme->Novafrom record 1, andInitechfalls back to a placeholder. The old expectation pinned the precedence this PR reverses.Testing
tests/engine/test_llm_replace_workflow.py: 3 failed, 22 passed before this change; 25 passed after. The failing cases are the flippedcollisioncase, a newcross-keycase (one value in record 1 and a different value in record 2 propose the same substitute), and the property test's run case, which now asserts that each substitute maps to one value across all 300 random records. Before this change, the property test fails on a placeholder token shared by several values.🤖 Generated with Claude Code