m3: depgraph (reverse-dep closure)#7
Merged
Merged
Conversation
The algorithmic heart of cascade: pure-data graph construction over []golist.Package values, with reverse-transitive closure traversal under the imports relation. Build merges Imports + TestImports + XTestImports into each node's outgoing edges so changes to a tested dep correctly invalidate the consuming package. RevDepClosure is a BFS over reverse edges with a visited set; output is sorted lexicographically. Seeds not present in the graph are silently skipped (per resolved Q3). Methods take uniform *Graph receivers (per TD-09 / IM-04 receiver consistency). Surface: Build, Graph, Stats, plus Has / DirectImports / DirectImporters / RevDepClosure / Stats methods. Stats is computed once at Build time and cached on the Graph (per resolved M3-1, the user override of the spec's deferral lean). Coverage at 100% statement coverage on depgraph; the dead dedup branch in the existing in-progress sortAndDedup helper is removed (reverse map is dedup-by-construction, forward map is pre-dedup'd by mergeImports), keeping the gate honest rather than masking it with test contortions. Closing report walks F-1..F-20 row-by-row with grep-verifiable evidence; substrate (guides loaded, pattern IDs cited) recorded per F-19. Adds OUT-1 fix to Makefile (fresh lint cache per invocation) which surfaced an unused-parameter issue on its first run, exactly the M1/M2 carry-forward failure mode it exists to prevent. Adds CC self-check checklist line to PR template per the M2 retro carry- forward — the protocol gets installed in the artifact contributors actually see. Spec: docs/design/05-active/0004-cascade-m3-depgraph-reverse-dep-closure.md Plan: docs/dev/0005-m3-implementation-plan-depgraph-reverse-dep-closure.md Closing report: docs/dev/0006-m3-implementation-retrospective.md Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Records 835b4b0 as the closing commit for M3 work. Convention matches M2's retrospective (0004-m2-implementation-retrospective.md) where the closing-commit SHA is concrete and the merge OID is filled in post-merge. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
M3 — the
depgraphpackage: pure-data import-graph construction and reverse-transitive closure traversal over[]golist.Package. Edges mergeImports + TestImports + XTestImportsper node;RevDepClosureis BFS over reverse edges with a visited set, output sorted lexicographically. Five exported methods (Has,DirectImports,DirectImporters,RevDepClosure,Stats); uniform*Graphreceivers;Statspre-computed atBuildtime.Two carry-forwards land alongside the milestone: a Makefile lint-cache fix (OUT-1, the M1/M2 retro carry-forward) and a CC self-check checklist line in the PR template.
Where
depgraph/—depgraph.go(Graph, Build, mergeImports, sortValues, computeStats),methods.go(Stats type + the five methods),depgraph_test.go+helpers_test.go(public-API tests inpackage depgraph_testper TE-43).Makefile—LINT_CACHE_DIR := $(shell mktemp -d ...)exported into thelintrecipe viaGOLANGCI_LINT_CACHE. Fresh cache per invocation; ~5–10s overhead. Earned its keep on first run (caught an unused-parameter issue local would have shipped)..github/PULL_REQUEST_TEMPLATE.md— adds a single ledger-row evidence-vs-criterion checklist line. Promoted from the impl plan's §Risks mitigation to deliverable so the protocol gets installed in the artifact contributors actually see.docs/dev/0006-m3-implementation-retrospective.md— closing report. Walks F-1..F-20 row-by-row with grep-verifiable evidence; substrate loaded + pattern IDs cited per F-19.How to verify
Abridged ledger (full version in
docs/dev/0006-m3-implementation-retrospective.md)depgraph/doc.goexists with package commenthead -3grep matches^// Package depgraph.Graphtype opaque (no exported fields)go docoutputstype Graph struct {followed by// Has unexported fields.; no exported field lines.Buildsignature matches specfunc Build(pkgs []golist.Package) *Graph— exact match.RevDepClosuremethod signaturefunc (g *Graph) RevDepClosure(seeds []string) []string— exact match.DirectImportsmethod signaturefunc (g *Graph) DirectImports(path string) []string— exact match.DirectImportersmethod signaturefunc (g *Graph) DirectImporters(path string) []string— exact match.Hasmethod signaturefunc (g *Graph) Has(path string) bool— exact match.TestRevDepClosure_StandardTopologiescases passsort.StringsAreSorted(got)so non-determinism would fail in the subtest, not just under -count.ok github.com/geomyidia/cascade/depgraph 0.150s. Six sub-cases cover the spec's exact expected closures.Imports=[i,shared] + TestImports=[t,shared] + XTestImports=[xt]produces deduplicatedDirectImports(p) = [i, shared, t, xt].DirectImports/DirectImporters/Hascorrect-count=10clean; sort assertion inline in every subtest.ok: github.com/geomyidia/cascade/depgraph coverage 100% >= 100%. Dead-branch dedup loop insortAndDedupremoved (reverse map is dedup-by-construction); gate honest, not masked.*Graph; race detector clean; identical output across all goroutines.go doc ./depgraphrenders cleanlyStats()+ TestStats (M3-1)Statsstruct exported with documented fields; method returns by value (cached at Build). TestStats covers four cases including edges-to-absent-nodes.Total rows: 20. Done: 20. Deferred: 0. No-op: 0. Iteration count: 1.
Notable findings
make lintimmediately surfaced a reviveunused-parameterissue in the goroutine fan-out — exactly the M1/M2 carry-forward failure mode it exists to prevent. Without OUT-1, this would have been the third consecutive milestone where local lint passed and CI failed for the same class of issue.sortAndDeduphad an unreachable dedup loop; the reverse map is dedup-by-construction (each(src, dst)pair appends once). Removed rather than worked around. Pattern: pure-data packages with strict coverage gates expose dead defensive code at the right time.*Graphreceivers) is honored regardless. Documented in the retrospective's substrate section.Checklist
make checkpasses locallyBreaking change?
No. M3 introduces a new package; no existing surface changes.
🤖 Generated with Claude Code