diff --git a/docs/architecture.md b/docs/architecture.md index e7793b6..32caada 100644 --- a/docs/architecture.md +++ b/docs/architecture.md @@ -108,32 +108,55 @@ compare_tool/ ## Data flow of one compare +Comparing two C files, end to end. A difference is a **real change unless a +filter can prove it is noise** — the shadow decides the truth, the raw diff +decides what you see, and three peeling steps (rename, autogen-name, reorder) +each remove only what they can justify. ARXML and A2L take the same two passes; +only the *shadow* — what each strips — differs. + ```mermaid -sequenceDiagram - participant F as Front end - participant S as scanner.scan - participant D as diff_engine.compare_pair - participant R as Renderer - - F->>S: old_root, new_root, exclude/include - S->>S: list_files() both sides, capture listing errors - loop each relative path - alt in both trees - S->>D: old_text, new_text, rel - D->>D: pass 1 — raw line diff - D->>D: pass 2 — shadow diff (+ rename map) - D->>D: label each raw hunk, then _status_of - D-->>S: {status, hunks, renames, notes} - else one side only - S->>S: added / deleted + semantic extras - else unreadable - S->>S: status 'error' — loud, never silent - end - end - S-->>F: {rel_path: result} - F->>R: the SAME dict, unfiltered +flowchart TD + START["scanner pairs a file by path"]:::io --> DISP{"present on…"} + DISP -- "new side only" --> ADD["added
(+ AUTOSAR/A2L extras)"]:::green + DISP -- "old side only" --> DEL["deleted"]:::green + DISP -- "could not read" --> ERR["error
loud, never silent"]:::red + DISP -- "both sides" --> EQ{"bytes identical?"} + + EQ -- "yes" --> IDENT["identical"]:::grey + EQ -- "no" --> EOL{"equal after newline
normalize?"} + EOL -- "yes" --> LEN["ignorable-only
line-endings / BOM"]:::grey + EOL -- "no" --> SHA["build the C shadow, both sides
strip // and /* */ comments · collapse whitespace
line count preserved"]:::step + + SHA --> P2["PASS 2 · diff the shadows
patience matcher (linediff.hunks)
→ candidate real hunks"]:::pass + P2 --> F1["peel · 1-to-1 rename map
verified by re-diff"]:::filter + F1 --> F2["peel · autogen-name noise
rtb_ · _DSTATE · tmp_N swaps"]:::filter + F2 --> F3["peel · safe reorder
dependence-preserving permutation"]:::filter + F3 --> REM{"candidate hunks
still left?"} + + REM -- "yes → real" --> MOV["detect moved blocks
delete ↔ insert, same content"]:::step + REM -- "no" --> P1 + MOV --> P1 + + P1["PASS 1 · diff the raw lines
label every hunk for display
real · moved · comment · rename · reorder · whitespace"]:::pass --> VER{"_status_of
one place decides"} + + VER -- "a real hunk survived pass 2" --> RC["real-change"]:::red + VER -- "only comment hunks" --> CMT["comment-only"]:::grey + VER -- "other noise only" --> IGN["ignorable-only"]:::grey + + classDef io fill:#eef2ff,stroke:#6366f1,color:#1e1b4b; + classDef step fill:#e0f2fe,stroke:#0284c7,color:#0c4a6e; + classDef pass fill:#dcfce7,stroke:#16a34a,color:#14532d; + classDef filter fill:#fef9c3,stroke:#ca8a04,color:#713f12; + classDef red fill:#fee2e2,stroke:#dc2626,color:#7f1d1d; + classDef grey fill:#f1f5f9,stroke:#94a3b8,color:#334155; + classDef green fill:#dcfce7,stroke:#16a34a,color:#14532d; ``` +The scanner drives the top branch — added / deleted / error / both — and hands +the renderers **one dict, unfiltered** (`{rel_path: result}`); the two-pass body +below the fold is `diff_engine.compare_pair`, and is the same for every text +file, C shown here. + ### The two passes `compare_pair` diffs the files twice. Both passes call the same matcher,