m4: changeset (changed-files-to-packages mapping)#9
Merged
Conversation
The bridge between cascade's two algorithmic primitives: golist (M2)
produces []golist.Package; depgraph (M3) walks reverse-edge closures
from a seed set. changeset.Resolve turns "these files changed" (git
diff --name-only output) into "these packages are the seeds" — the
input of g.RevDepClosure.
Surface: one exported function (Resolve), one option type (Option),
one option constructor (WithModuleRoot). Algorithm: build dirMap from
pkg.Dir → ImportPath, walk changedFiles, parent-dir lookup, sorted
dedupe via map[string]struct{}; O(P+F).
Disclosed amendments to the spec (carried in the closing retro):
- F-2 signature: spec said positional moduleRoot string; user override
during plan-mode review (Q1) chose functional option pattern.
- Q2: empty/unset moduleRoot triggers os.Getwd fallback. Tests pass
WithModuleRoot explicitly to bypass the io. The single io edge is
hooked through an internal getCwd function-variable seam, mirroring
M2's runGoList pattern (pkg/golist/seam_test.go's withSeam idiom is
reused as withCwdSeam in pkg/changeset/seam_test.go).
- doc.go updated from "All operations are pure — no io" to a
description that names the os.Getwd fallback and the seam-based
testability story. F-1's verify (the // Package changeset line) is
preserved.
Coverage at 100% statement coverage on pkg/changeset, joining
pkg/golist, pkg/depgraph, and internal/project at the same gate. Each
table-driven subtest also asserts sort.StringsAreSorted(got) inline so
non-determinism would surface in the failing subtest, not just as a
-count=10 flake (M3's What-Worked carry-forward).
Spec/plan: docs/dev/0009-implementation-plan-changed-files-to-packages-mapping.md
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Walks F-1..F-14 row-by-row with grep-verifiable evidence. 14 done, 0 deferred, 0 no-op. Documents three disclosed amendments to the spec (Q1 functional-option signature, Q2 os.Getwd fallback with seam, doc.go content update) so the spec's next ODM promotion picks them up. Substrate section enumerates pattern IDs cited during implementation (AP-29/30/36/40/44/52, API-42, IM-01, TD-09/17, TE-01..08/15/43, DC-01/02). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Captures the three disclosed amendments from the M4 retrospective (0010) into the active spec at docs/design/05-active/0005-... so the spec stays the source-of-truth for downstream consumers and CDC review: - Public API surface: Resolve signature reflects the functional- option pattern (Q1 user override). Adds Option type definition and WithModuleRoot constructor as a sibling subsection. Updates Resolve godoc to describe opts, the os.Getwd fallback (Q2), and the IgnoredGoFiles mapping rule (Q5 confirmed). - Decided: bullets updated. moduleRoot via WithModuleRoot, not positional; the seam pattern (getCwd) for the io edge is named. - F-2 ledger row's verify command updated to grep for the functional-option signature. - Open questions section retitled "Open questions (resolved)" with each Q1-Q6 marked **Resolved:** plus the resolution chosen (or spec lean confirmed). Q1 and Q2 record the user override explicitly. - Risks & mitigations: adds an entry for the single io edge from os.Getwd fallback, naming the seam pattern as the mitigation and M2's runGoList as the precedent. - Frontmatter version 1.0 → 1.1. The implementation already matches this amended spec; this commit just brings the spec text in line with what shipped. Nothing in the ledger's done-ness shifts: F-1..F-14 closed in 75617a2 and f78dcb9 remain done. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The previous spec-amendment commit (9e92a95) bumped the frontmatter version from 1.0 to 1.1 but didn't document what changed in-doc. Adding a Version History table at the bottom of the spec capturing: - 1.0 baseline (positional Resolve, no exported types, no io) - 1.1 amendments (Option + WithModuleRoot, os.Getwd fallback with getCwd seam, IgnoredGoFiles mapping rule, F-2 verify command, resolved open questions, risks-section addition) Per spec-keeping discipline (assets/ai/AI-ENGINEERING-METHODOLOGY.md §"Anti-degradation practices"): a version bump without a documented change is silent drift; the table makes the diff visible to future readers and to CDC. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
CDC pass run against m4/changeset-mapping head 75617a2 + retro fix-up f78dcb9. Replaces the "Pending..." placeholder in the §"CDC review notes" section with the full independent-verification report: - Direct re-reads on F-1 (doc.go), F-2 (Resolve signature), F-9 (removed-file lookup is purely lexical), F-12 (imports list + zero go.mod requires), F-14 (substrate enumeration). - CC-attested-via-CI rows (F-3..F-8, F-10, F-11, F-13) accepted on the strength of CI green + local-run evidence in the row walk. - Specifically verified the options pattern (config struct, WithModuleRoot setting both moduleRoot + moduleRootSet, the meaningful "not set vs explicitly empty" distinction the flag enables) and the seam-based pure-testing path (every test call site in changeset_test.go passes WithModuleRoot; TestResolve_DefaultUsesGetCwd + TestResolve_GetCwdErrorTolerated exercise both getCwd branches via withCwdSeam). CDC findings: zero softpedals, zero silent drops, row count 14-declared / 14-closed. Closure recommendation: M4 is mergeable. Three engineering observations carried forward into the retros' What-Worked corpus: (a) the moduleRootSet flag as an API-design pattern (option zero value semantically meaningful); (b) the plan-mode AskUserQuestion round-trip surfacing design-affecting decisions before code is written; (c) the external+internal two-file test convention now established across pkg/golist and pkg/changeset. Forward-looking note: the active M4 spec's F-2 verify text references the original positional moduleRoot signature; the in-PR amendment commit (9e92a95) already updates this to the functional-option form, so the spec is in-sync at v1.1. 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
M4 — the
pkg/changesetpackage: pure-data mapping fromgit diff --name-onlyoutput to the import paths of the packages those files belong to. Bridges cascade's two algorithmic primitives —golist(M2) produces[]golist.Package;depgraph(M3) walks reverse-edge closures from a seed set;changeset.Resolveturns "these files changed" into "these packages are the seeds forg.RevDepClosure."Surface: one exported function (
Resolve), one option type (Option), one option constructor (WithModuleRoot). Three exported names total. Algorithm: builddirMap[pkg.Dir]→pkg.ImportPathonce; for each.gofile inchangedFiles, takefilepath.Dir(filepath.Clean(absPath))and look up; sorted-deduped output. O(P + F).Where
pkg/changeset/changeset.go—Option,WithModuleRoot,config,getCwdseam,Resolve. Single file; ~140 lines including comments.pkg/changeset/changeset_test.go— public-API tests (package changeset_test); 16 StandardCases + HandTraceable's 7 sub-cases + PathNormalisation's 5 cases + IgnoredGoFiles + PackagesWithEmptyFieldsSkipped + EmptyFilePathSkipped.pkg/changeset/seam_test.go— internal-package tests (package changeset) for thegetCwdseam; covers the os.Getwd success and error branches without depending on the real test cwd.pkg/changeset/helpers_test.go— sharedstringSlicesEqualhelper.pkg/changeset/doc.go— M1 stub updated to reflect the io-edge fallback (the// Package changesetline is preserved per F-1).docs/design/05-active/0005-cascade-m4-changeset-changed-files-to-packages-mapping.md— spec amended in-PR (1.0 → 1.1) so the spec stays the source-of-truth at merge. Version History section added at the bottom; spec amendments commit message (9e92a95) and Version History commit message (e17a730) name the diff.docs/dev/0009-implementation-plan-changed-files-to-packages-mapping.md— implementation plan (committed by maintainer to local main ased64e14before branch cut).docs/dev/0010-implementation-retrospective-m4-changeset.md— closing retrospective walking F-1..F-14 row-by-row.How to verify
Disclosed amendments to the spec (folded back into 0005-...md @ v1.1)
Three amendments resolved in plan-mode review with the maintainer; all three folded into the active spec in this PR (commits
9e92a95+e17a730) so the spec stays the source-of-truth at merge.func Resolve(changedFiles []string, pkgs []golist.Package, moduleRoot string) []string(positional). User overrode to functional option:func Resolve(changedFiles []string, pkgs []golist.Package, opts ...Option) []stringwithWithModuleRoot(string) Option. TheOptiontype is the only knob in v0.x; future-proofs forWithIgnorePatternetc. and lets tests opt out of the io fallback (Q2) by passingWithModuleRootexplicitly.os.Getwdfallback (Q2). Spec leaned "skip relative paths when moduleRoot is empty." User chose: whenWithModuleRootis not supplied, fall back toos.Getwdat call time. The single io edge is hooked through an internal function-variable seam (getCwd = os.Getwd), structurally identical to M2'srunGoListseam. Tests inseam_test.go(package changesetinternal) replacegetCwdto drive the success/error branches; production tests passWithModuleRootexplicitly to bypass the io.doc.gocontent updated. M1 stub said "All operations are pure — no io." That is no longer accurate after Q2. Updated to describe the io edge plus the seam-based testability story. F-1's verify (the// Package changesetcomment line) is preserved.The implementation already matches the amended spec; the spec commit just brings the spec text in line with what shipped.
Abridged ledger (full version in
docs/dev/0010-implementation-retrospective-m4-changeset.md)pkg/changeset/doc.goexists with package comment// Package changesetline); content body amended (disclosed).Resolvesignature matches specfunc Resolve(changedFiles []string, pkgs []golist.Package, opts ...Option) []string— exact match to amended spec v1.1.TestResolve_StandardCasesrows passsort.StringsAreSorted(got)inline../, interior./,..traversal, absolute-with-extra-separators._test.gofiles map to the package, not to_test--- PASS: TestResolve_StandardCases/_test.go_in_pkga.--- PASS: TestResolve_StandardCases/mixed_go_and_non_go.--- PASS: TestResolve_StandardCases/Go_file_outside_any_package.--- PASS: TestResolve_StandardCases/removed_Go_file_in_pkga— purely lexical lookup, noos.Stat.-count=10clean; sort assertion inline in every subtest.ok: github.com/geomyidia/cascade/pkg/changeset coverage 100% >= 100%. All four cascade packages now at 100% (golist, depgraph, changeset, internal/project).pkg/golistgo list -m all | wc -l= 1. Imports:os,path/filepath,sort,stringsfrom stdlib, pluspkg/golistfrom own module.go docrenders cleanlyResolve,Option,WithModuleRoot— every exported name with DC-01 / DC-02-compliant doc comments.Total rows: 14. Done: 14. Deferred: 0. No-op: 0. Iteration count: 1.
Notable findings
getCwd = os.Getwd+withCwdSeamhelper is structurally identical to M2'srunGoList+withSeam. Pattern is now mature; M5+ packages with io edges should reach for it by default.make check-allafter writing tests caught a gofmt issue (struct-literal trailing-comment alignment) before CI would have. Pattern is battle-tested across M3, refactor, and M4.golist.Run → depgraph.Build → changeset.Resolve → g.RevDepClosure— each call's output type matches the next call's input shape. M5's CLI wires this directly.Checklist
make checkpasses locallyBreaking change?
No for cascade's CLI users. No for library consumers — this PR adds a new exported package; no existing surface is removed or renamed. The package-layout refactor (PR #8) was the breaking-change milestone for the v0.x window.
🤖 Generated with Claude Code