Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 16 additions & 3 deletions codewiki/src/be/updater/graph_diff.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,21 @@ def normalize_body(text: str | None) -> str:
return _WS.sub(" ", (text or "").strip())


def documented_source(node: Node) -> str:
"""The component's code with its doc comment in front, when the code does not already hold it.

Languages like Rust keep doc comments (`///`) above the item, outside ``source_code``. Without
them, a change that only documents behaviour would be invisible to the updater.
"""
code = node.source_code or ""
doc = (node.docstring or "").strip()
if doc and doc not in code:
return f"{doc}\n{code}"
return code


def body_hash(node: Node) -> str:
return hashlib.sha1(normalize_body(node.source_code).encode("utf-8")).hexdigest()
return hashlib.sha1(normalize_body(documented_source(node)).encode("utf-8")).hexdigest()


def signature(node: Node) -> dict[str, Any]:
Expand Down Expand Up @@ -78,8 +91,8 @@ def truncate_to_tokens(text: str, max_tokens: int) -> str:


def unified_body_diff(old: Node | None, new: Node | None, label: str) -> str:
old_lines = (old.source_code or "").splitlines(keepends=True) if old else []
new_lines = (new.source_code or "").splitlines(keepends=True) if new else []
old_lines = documented_source(old).splitlines(keepends=True) if old else []
new_lines = documented_source(new).splitlines(keepends=True) if new else []
diff = difflib.unified_diff(
old_lines, new_lines, fromfile=f"a/{label}", tofile=f"b/{label}", n=2
)
Expand Down
4 changes: 2 additions & 2 deletions codewiki/src/be/updater/prompts.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
from codewiki.src.be.dependency_analyzer.models.core import Node
from codewiki.src.be.prompt_template import _fence_language, _format_module_tree_str
from codewiki.src.be.updater.change_report import LeafReport
from codewiki.src.be.updater.graph_diff import GraphDiff
from codewiki.src.be.updater.graph_diff import GraphDiff, documented_source

VERDICT_VALUES = ("no-op", "patch", "rewrite")

Expand Down Expand Up @@ -292,7 +292,7 @@ def render_leaf_components(
node = graph.get(cid)
if node is None or cid not in changed or not node.source_code:
continue
code = node.source_code
code = documented_source(node)
if budget <= 0:
lines.append(f"\n(code of {cid} omitted for length; use read_code_components)")
continue
Expand Down
19 changes: 19 additions & 0 deletions tests/test_updater_graph_diff.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
CLASS_RENAMED,
DIFF_TRUNCATED_MARKER,
body_hash,
documented_source,
diff_graphs,
)
from codewiki.src.be.updater.options import UpdateOptions
Expand Down Expand Up @@ -83,3 +84,21 @@ def test_diff_truncation():
new = {"a.py::f": node("a.py::f", "function", big_new)}
d = diff_graphs(old, new, UpdateOptions(max_diff_tokens=50))
assert DIFF_TRUNCATED_MARKER in d.records["a.py::f"].diff


def test_doc_comment_only_change_is_a_body_change():
# Rust keeps `///` doc comments above the item, outside source_code.
code = "pub fn summarize(m: &Module) -> String {\n call(m)\n}\n"
a = node("src/llm.rs::summarize", "function", code)
b = node("src/llm.rs::summarize", "function", code)
b.docstring = "/// Sends only names and imports, with temperature 0 and at most 120 tokens."
d = diff_graphs({a.id: a}, {b.id: b})
assert d.body == {a.id}
assert "+/// Sends only names and imports, with temperature 0" in d.records[a.id].diff


def test_docstring_inside_source_is_not_counted_twice():
code = 'def g():\n """Return one."""\n return 1\n'
a = node("f.py::g", "function", code)
a.docstring = "Return one."
assert documented_source(a) == code
Loading