Phase 5 — Hardening #15
Loading…
Reference in a new issue
No description provided.
Delete branch "refs/pull/15/head"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Summary
WUMING_MAX_DIFF_LINESenv var; posts plain PR comment and exits early if diff exceeds the limit (0 = disabled)truncate_large_hunks()replaces hunks > 300 lines with a single stub line before sending to agentslen(diff_text) // 4per agent call via structured loggerwith_retry()helper inretry.py; applied toForgejoClientand all three backendslog.pywithJSONFormatter+setup_logging(); allprint()calls replaced"quote"field added to agent JSON schema; diff searched by text to resolve position before falling back to LLM-supplied line numberCloses #14
Test plan
uv run ruff format --check .uv run ruff check .uv run ty check .uv run complexipy .uv run tryke test(192 tests passing)src/wuming/diff.pyline 7No action needed: each
Hunk'snew_startis parsed directly from the@@ -old +new,count @@diff header by_DiffParser, not computed incrementally from previous hunks. Truncatinghunk.linesto a single stub has no effect on any subsequent hunk'snew_start. Bothbuild_position_mapandfind_line_by_quoteuse each hunk'snew_startas an independent starting point.src/wuming/diff.pyline 29No action needed:
len(hunk.lines)counts every line in the raw diff hunk (context, additions, deletions), which is the right signal — it shows the agent how many diff lines it would have had to read. Showing only added lines would understate the size of the change. The stub is informational and has no effect on correctness.src/wuming/diff.pyline 67No action needed: a PR diff contains at most one entry per file path. Once the loop finds
file_diff.path == pathand exhausts all its hunks without a match, there is nothing further to search. The earlyreturn Noneis intentional.src/wuming/retry.pyline 45No action needed: the
assert last_exception is not Noneis only reachable after all attempts are exhausted (at least one exception was caught), solast_exceptionis guaranteed set at that point. The assert exists to narrow the type fromBaseException | NonetoBaseExceptionfor the type checker.src/wuming/retry.pyline 50The docstring has an off-by-one error. The code uses
base_delay * 2 ** attemptwhereattemptis 0-indexed, giving delays ofbase_delay * 1,base_delay * 2,base_delay * 4for the 2nd, 3rd, 4th attempts — that is the intended behaviour. The docstring incorrectly statesbase_delay * 2 ** (k - 2)(which would give 0.5x on the second attempt); it should readbase_delay * 2 ** (k - 1). Will fix the docstring.src/wuming/main.pyline 44No action needed — same reasoning as the
diff.pycomment above.hunk.new_startis parsed from the@@ ... +N,M @@diff header and is independent of all other hunks.truncate_large_hunksonly replaceshunk.lines; it never modifiesnew_start.build_position_mapproduces correct file-line keys for every hunk regardless of truncation.src/wuming/main.pyline 87No action needed: if both the quote lookup and the fallback line number miss the diff,
line_for_lookup not in position_maps.get(path, {})isTrueand the comment is dropped with a warning. A bad agent line number therefore never produces a mis-anchored comment — it produces no comment. The quote mechanism improves resolution when it works; the validation gate handles the rest.src/wuming/agents/base.pyline 65No action needed: the guard
if raw_quote is not Noneon the preceding line meansstr(raw_quote)is only called whenraw_quoteholds a real value. JSONnulldeserialises to PythonNone, which the guard catches, producingquote = Noneon the else branch.src/wuming/backends/anthropic.pyline 25No action needed:
payload,system, anduserare constructed once before_attemptis defined and are never mutated between retry calls.systemanduserare immutable strings;payloadis a dict built once and passed as a JSON body without modification. The closure is safe across all retry attempts.src/wuming/forgejo.pyline 63No action needed: default-argument binding is the standard Python idiom for capturing a loop variable in a closure. The type annotation
rid: intmakes the intent explicit.functools.partialwould add an import for no readability gain in a 3-line helper.src/wuming/forgejo.pyline 63No action needed:
riddoes not shadow the built-inid. They are different names — Python'sidis a standalone builtin;rid(review id) is a separate identifier with no relationship to it.tests/test_log.pyline 83No action needed:
JSONFormatter.format()usesstrftime("%Y-%m-%dT%H:%M:%S")which never emits fractional seconds. The regex in the test intentionally matches only what the formatter actually produces.CLAUDE.mdline 5No action needed: the comment sits on the
config_agent.pyline of the project layout table, not onretry.py.retry.pyappears two lines later with its own annotation. The layout is correct.CLAUDE.mdline 14Will fix: updating the wording to 'posts a plain PR comment and exits' in the
WUMING_MAX_DIFF_LINESentry in CLAUDE.md, matching the README phrasing.README.mdline 5No action needed: README.md uses a dedicated Default column showing the raw value (
0), with the meaning in the Description column. CLAUDE.md is an inline reference where0 = disabledgives the meaning in one place without a separate column. Both are accurate for their context.