# 0039-edit-loop-helper (PT-BR) — Tradução
_Tradução automática do ADR original em inglês. Em caso de divergência, a versão EN prevalece._
# ADR-0039: edit-loop helper — N edições em 1 invocação
- **Status**: Aceito
- **Data**: 2026-06-17
- **Contexto**: Operator scripts that apply a batch of textual transformations to one file (rename an identifier in 7 places, swap import paths across a refatorar, sweep obsolete tipo aliases) currently invoke `edit` N times. Each invocation pays the full subprocess startup cost (clap parse, BLAKE3 read, `--expect-checksum` re-validação, write pipeline, envelope NDJSON emission) and re-enters the workspace jail. For 5 edits on a 50 KB file, the cumulative overhead is dominated by processo spawn (~15-30 ms × 5 = 75-150 ms) rather than the actual string matching (<5 ms total). The 2026-06-15 audit (ADR-0035) and the GAP-2026-012 closure that introduced `--partial` for multi-pair `edit` (ADR-0036) established that the multi-pair path inside one `edit` invocation is a verified, fuzz-tested code path with por-pair `pair_results` and the 9-strategy cascade. Extending that path to N pairs in a single invocation is mechanically trivial; the operator-visible benefit is N→1 processo boundary crossings. The G118 helper de resolução de caminho (ADR-0031) means the alvo file is resolved once against the workspace jail and reused; the G119 WAL política (ADR-0028) means the sidecar is either absent (padrão) or written once for the whole loop. The new sub-comando não change semantics: it is a thin stdin-driven wrapper around the existing por-pair `edit` engine, with the loop driven by NDJSON on stdin and the same `pair_results` envelope emitted on stdout (one NDJSON line por pair, plus a final summary line). The padrão `edit` behavior (all-or-nothing abort on first failed pair) is preserved unless `--partial` is passed, matching the contract ADR-0036 documented.
- **Decisão**: Add a new sub-comando `edit-loop` to v0.1.22 that accepts NDJSON on stdin in the form `{"old": "...", "new": "..."}` por line and aplica the pairs sequentially to a single alvo file, reusing the por-pair fuzzy cascade from `edit`. The sub-comando accepts the same alvo-file positional as `edit`, plus the same global flags (`--workspace`, `--expect-checksum`, `--preserve-timestamps`, `--line-ending`, `--partial`, `--fuzzy`). A new flag `--re-capture-checksum` (padrão `false`) controls whether the checksum is re-read after each pair (slower, safer for concorrente scripts) or only at the end (padrão; matches the single-`edit` behavior). The saída is NDJSON: one `pair_result` object por input line (in order), plus a final `summary` line with `pairs_total`, `pairs_matched`, `pairs_unmatched`, `bytes_before`, `bytes_after`, `checksum_before`, `checksum_after`, and `mtime_preserved`. The código de saída is 0 if all pairs matched (or `--partial` foi passed and at least one matched), 1 if zero pairs matched (NO_MATCHES), or 65 if any precondition failed (missing alvo, invalid NDJSON, `--expect-checksum` mismatch). The implementation lives in `src/commands/edit_loop.rs` and delegates to `commands::edit::run_pair` for each pair, sharing the same in-memory buffer for the alvo content to evita re-reading the file from disk N times.
- **Consequências**:
- **+** N edits collapse to 1 subprocess invocation. For a 5-pair batch on a small file, wall-clock drops from ~150 ms to ~35 ms. The actual saving scales with N and with processo spawn cost on the host (heavier on Windows devido a slower CreateProcess).
- **+** Single read of the alvo file from disk. The file content is loaded once at sub-comando start, mutated in memory, and written once at sub-comando end através de the existing atomic pipeline. No mid-loop race with another writer unless `--re-capture-checksum` is passed.
- **+** Pair ordering is deterministic: pairs são applied in stdin order, and the por-pair fuzzy cascade uses the post-previous-pair content as the search space. This matches the G117 contract (ADR-0026) and evita the "non-overlapping pair pre-validação" problem that would exige a separate pass over the file.
- **+** The `--partial` flag propagates the same semantics as multi-pair `edit` (ADR-0036): matched pairs são applied, unmatched são reported with `matched: false`, saída 0 if at least one pair matched, saída 1 if zero matched. Operators scripting a best-effort sweep can pass `--partial` once and consume the NDJSON stream.
- **+** The `--expect-checksum` flag is read once at sub-comando start, not por pair, matching the single-`edit` behavior. A concorrente writer that mutates the alvo between sub-comando start and atomic_write will trigger the standard state-drift envelope (saída 82) on the final write, not on intermediate states.
- **-** The entire alvo file is held in memory. The same `--max-filesize` global cap that protects `read` and `edit` protects `edit-loop`; a file that exceeds the cap is rejected with saída 65 before any pair is applied. This is the documented contract and matches the in-memory padrão of `edit --multi` (v0.1.15).
- **-** Pair interaction is not analyzed before the loop. If pair 3's `old` text foi already consumed by pair 1's `new` text, the cascade may match pair 1's saída as pair 3's input, producing a "successful" pair that the operator did not intend. The fix is operator discipline (order pairs so `old` texts são disjoint) or pre-validação através de a separate pass; the sub-comando não pre-validate.
- **-** Adding a sub-comando expands the help surface by one entry. The `edit` texto de help gains a cross-reference to `edit-loop` ("for N edits in one invocation, see `edit-loop`") and vice versa. The cross-reference is a 1-line addition to each help, not a new flag.
- **Justificativa**: The 2026-06-15 audit (ADR-0035) and the GAP-2026-012 closure (ADR-0036) established that the multi-pair `edit` path is the canonical answer to "I têm several text changes for one file" inside a single invocation. The remaining gap is the operator who scripts the same 5 `edit` calls in a `for` loop in a shell script: the por-invocation overhead is wasteful and the script is harder to read than a single NDJSON stream. `edit-loop` is the smallest command surface (one sub-comando, no new flags beyond `--re-capture-checksum`) that endereça the loop case without disturbing the single-pair or multi-pair paths. The padrão behavior matches the existing `edit --multi` semantics: read once, mutate in memory, write once. The `--partial` propagation is obrigatório by symmetry: an operator who passes `--partial` to multi-pair `edit` should get the same semantics in `edit-loop`, and the absence of `--partial` should preserve the all-or-nothing abort that ADR-0026 documented as the safer padrão. The `--re-capture-checksum` flag is the only new opt-in; it is off by padrão to match the existing `edit` behavior and to evita the I/O cost on the hot path. The in-memory buffer is the natural data structure (the por-pair cascade already operates on a `String` content), and the `--max-filesize` cap already protects against pathological inputs.
- **Alternativas consideradas**:
1. **Add a flag `--permite-sequential-drift` to `edit` that re-reads the file between pairs.** Rejected: mixes the loop case with the single-pair case, expands the `edit` help surface by a non-obvious flag, and forces every `edit` caller to reason about a mode they will never use. The sub-comando is the cleaner factoring.
2. **Add a flag `--loop <COUNT>` to `edit` that re-invokes the same pair N times.** Rejected: não match the operator mental model (N different pairs, not the same pair N times), and the syntax for N different pairs através de repeated `--old`/`--new` already exists inside a single `edit` call.
3. **Generalize `edit --multi` to accept NDJSON from a file através de `--multi-file <PATH>`.** Rejected: `--multi` already accepts NDJSON from stdin. The sub-comando is the right factoring because it changes the input source model (one file, many pairs over time) and the saída envelope model (por-pair result line plus summary) — both warrant a named sub-comando for discoverability.
4. **Defer to a separate `bulk-edit` tool that suporta multiple alvo files.** Out of escopo for v0.1.22: the audit identified the same-file N-pairs case as the immediate need. Multi-file batching is a v0.1.23+ concern that can layer on top of `edit-loop` (one subprocess por file, NDJSON manifest of `alvo + pairs`) without changing the single-file contract.
- **Gatilho para revisitar**: If operators report that the in-memory buffer is a bottleneck (files near the 1 GiB cap), revisit with a streaming variant that writes a tempfile after each pair (loses atomicity within the loop but permite larger files). If `--re-capture-checksum` proves necessary as the padrão rather than the opt-in (i.e. concorrente-write padrões dominate over single-script use), flip the padrão and document the I/O cost. If a future sub-comando (e.g. `replace-loop`, `transform-loop`) needs the same loop padrão, extract the NDJSON-stream-to-`run_pair` adapter into a shared helper rather than copy-pasting the stdin parser.
---
_Original em inglês: [`0039-edit-loop-helper.md`](0039-edit-loop-helper.md)_