3. Reading a Diff
In most tools, “what changed in the architecture last week?” is a hard question. Diagrams aren’t comparable; PowerPoint slides have no diff. ArchLang’s text source means git already knows — but raw git diff shows you removed and added lines, not architectural deltas. Renaming a module and changing nothing else looks, in a text diff, like deleting everything that mentions the old name and adding everything that mentions the new one.
ArchLang’s diff is structural. It knows that a module with the same stable ID and a different name is a rename, not a delete-plus-add. It tells you so explicitly. This chapter walks through one such diff, still using only bare language.
The before state
Section titled “The before state”The payments system from a few weeks ago:
module #m4k29p Payments { aspect team: "Payments" "Core payment processing."
aspect { domain: "Payments" zone: "PCI" }
interface authorize { "Authorize a transaction" } interface capture { "Capture an authorized amount" } interface refund { "Issue a refund" }}
module #x7t1qd Ledger { aspect team: "Finance" "Financial record keeping."
aspect { domain: "Finance" zone: "Internal" }
interface record { "Record a financial event" }}
module #b0w83r LegacyBilling { aspect team: "Payments" "Old billing module slated for removal."
interface charge { "Legacy charge endpoint" }}
module #u5e7af Customer { "End user initiating payments."}
process #z2j6vm BasicPayment { Customer > Payments.authorize Payments > Ledger.record}Notice the #m4k29p, #x7t1qd, etc. prefixes. Those are stable IDs, minted by the formatter the first time the file was saved (see Chapter 13). They are deliberately opaque — random characters that encode no name, type, or meaning — and they never change. That is the whole point: the ID stays fixed even when the module is renamed, re-scoped, or moved, so the diff engine can recognize that “the module formerly known as Payments” is the same module after a rename. (Don’t read anything into the characters; a meaningful ID is a bug, because anything meaningful eventually goes stale and tempts you to edit it.)
The after state
Section titled “The after state”A few weeks later the same files look like this:
module #m4k29p PaymentsService { aspect team: "Payments" "Core payment processing."
aspect { domain: "Payments" zone: "PCI" criticality: "High" }
interface authorize { "Authorize a transaction" } interface capture { "Capture an authorized amount" } interface refund { "Issue a refund" } interface void { "Void an unsettled authorization" }}
module #x7t1qd Ledger { aspect team: "Finance" "Financial record keeping."
aspect { domain: "Finance" zone: "Internal" }
interface record { "Record a financial event" } interface auditLog { "Append immutable audit entry" }}
module #h9n42c FraudCheck { aspect team: "Risk" "Real-time fraud screening."
aspect { domain: "Risk" zone: "Internal" }
interface screen { "Score a transaction for fraud" }}
module #u5e7af Customer { "End user initiating payments."}
process #z2j6vm BasicPayment { Customer > PaymentsService.authorize PaymentsService > FraudCheck.screen PaymentsService > Ledger.record}The text diff would tell you that Payments is gone, PaymentsService is new, a chunk of lines moved around, and several aspects were touched. Useful for code review of the file itself, useless as a description of how the architecture changed.
The structural diff
Section titled “The structural diff”Open both versions in the viewer’s diff mode (the hosted viewer accepts two directories side-by-side). You see this:
- Renamed:
Payments→PaymentsService(same#m4k29p). - Added aspect:
criticality: "High"onPaymentsService. - Added interface:
PaymentsService.void. - Added interface:
Ledger.auditLog. - Added module:
FraudCheck(#h9n42c). - Removed module:
LegacyBilling(#b0w83r). - Modified process:
BasicPayment— one step inserted (PaymentsService > FraudCheck.screen).
Each item is anchored to a node in the diagram. Renamed nodes appear in their post-rename position, marked as renamed; added nodes glow green; removed nodes glow red and dim out; modified processes highlight the inserted or removed steps.
How the rename was detected
Section titled “How the rename was detected”Payments and PaymentsService share the stable ID #m4k29p. That’s how the diff knows. Stable IDs are anchored to modules and types, not to names. You can rename a module freely and the diff stays useful.
What about the new interface PaymentsService.void? Interfaces don’t have stable IDs (see Chapter 13). Their identity is their dot-path inside the enclosing module. The diff engine uses heuristics on contract shape (type, fields, description) and name similarity to detect interface renames; everything else falls back to add-plus-remove. In this example void is genuinely new, so the diff shows it as added.
Why not give everything a stable ID? Because the cost is permanent visual noise in source files. IDs on modules buy something concrete (cross-file references survive rename). IDs on every interface inside every module would clutter source without adding much — interfaces rarely get renamed independently of their module, and when they do, the heuristic catches the common cases.
Why this matters for review
Section titled “Why this matters for review”A pull-request author opens the diff view. The reviewer sees:
FraudCheckis new. Question: who owns it, where does it run, what data does it touch?BasicPaymentnow routes throughFraudCheck.screen. Question: is that step blocking? What’s the SLA?LegacyBillingis gone. Question: are any external systems still calling it?
Those questions are about the architecture, not about the file. The diff view surfaces them directly. The same review against a raw git diff would bury them under noise.
Summary
Section titled “Summary”- Stable IDs (
#m4k29p) are opaque and permanent; they anchor module identity across renames. - The diff is structural: rename, add, remove, modify — not line-level.
- Interfaces use heuristics (contract shape + name similarity), not IDs.
- The viewer’s diff mode renders deltas directly on the diagram.
- Chapter 14 returns to diffs in depth once we’ve covered everything they can show.
What’s next
Section titled “What’s next”Chapter 4: Modules → — the first primitive, in detail.