refactor: consolidate top-level layout into pkg/ + internal/#8
Merged
Conversation
Plan moves the four current top-level Go packages into pkg/ + internal/:
- pkg/{golist,depgraph,changeset} — public library API surface
- internal/project — cascade-specific build metadata (go's internal/
rule structurally enforces the private boundary)
Documents the maintainer-aesthetic call to use pkg/ despite the Go
FAQ's ambivalence (decision L-1), the disclosed amendment to the
high-level plan's "internal/ reserved for M5" reservation (L-8), and
the atomic-migration approach (L-5) — pre-v1.0's no-stability commit
makes the one-PR breakage acceptable.
Includes 19-row acceptance ledger covering each move's structural
verification (L-F1..L-F19); zero deferrals expected.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Moves four packages into the canonical pkg/ + internal/ split:
- pkg/{golist,depgraph,changeset} — the public library API surface
imported by external consumers via the repo's public module path.
- internal/project — cascade-specific build metadata; Go's internal/
rule structurally enforces that downstream consumers cannot import
this package.
- cmd/cascade stays at top-level per Go-canonical convention.
Result: top-level Go directories reduced from five (cmd/, golist/,
depgraph/, changeset/, project/) to three (cmd/, pkg/, internal/).
Mechanical changes:
- All git mv operations preserve history (verified via L-F18:
git log --follow finds prior M2/M3/M1.5 commits at the new paths).
- 9 import-path references updated across 6 files (cmd/cascade/*.go,
pkg/depgraph/*.go, pkg/golist/golist_test.go).
- VERSION symlink at repo root re-pointed from project/VERSION to
internal/project/VERSION; //go:embed VERSION inside version.go is
path-relative so survives the move automatically.
- Makefile VERSION_PKG and VERSION-file-read paths updated.
- scripts/coverage-check.sh PACKAGES array rewritten with new paths.
- README.md library import block, CLAUDE.md architecture section,
CONTRIBUTING.md coverage/versioning sections updated.
- Adds a third "Private support" subsection to CLAUDE.md
Architecture documenting internal/project and the Go internal/
visibility rule.
Disclosed amendment: the high-level plan (0001) reserved internal/
"for CLI-only glue that emerges in M5." This refactor brings
internal/ into use earlier — for project rather than M5 CLI glue.
Documented in the impl plan (0007) decision L-8.
Atomic migration (decision L-5): pre-v1.0's no-stability commit
makes the one-PR breakage of external import paths acceptable. No
backward-compat aliases or forwarding packages.
Documentary side of the milestone boundary:
- M3 design doc (0004) transitions docs/design/05-active → 06-final.
- M4 design doc (0005-cascade-m4-changeset-...md) lands in 05-active
for forward-looking changeset work that uses the new pkg/changeset
path.
- docs/design/index.md updated to reflect both.
All checks green: make check-all, race tests, lint clean (cold
cache), per-package coverage gate at 100% on pkg/golist,
pkg/depgraph, internal/project; pkg/changeset N/A (no implementation
yet). ./bin/cascade --version proves the ldflags chain still
threads through internal/project correctly post-move.
Spec/plan: docs/dev/0007-implementation-plan-package-layout-refactor-pkg-internal.md
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Walks L-F1..L-F19 row-by-row with grep-verifiable evidence; status: 19 done, 0 deferred, 0 no-op. Substrate section explicitly documents the minimal-citations posture appropriate for a pure refactor (no Go-guide chapters cited beyond the implicit internal/ visibility rule, with reasoning) so future contributors don't read the absence as compliance theatre. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
5 tasks
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
Layout refactor: top-level Go directories reduced from five (
cmd/,golist/,depgraph/,changeset/,project/) to three (cmd/,pkg/,internal/).pkg/{golist,depgraph,changeset}— public library API surface; importable by external consumers via the public module path.internal/project— cascade-specific build metadata; Go'sinternal/rule structurally enforces that downstream consumers cannot import this package.cmd/cascade— unchanged; stays at top-level per Go-canonical convention.Atomic migration (decision L-5): single PR moves all four packages and updates every import path in one go. No backward-compat aliases or forwarding packages — pre-v1.0's no-stability commit makes the one-shot breakage acceptable.
Disclosed amendment: the high-level plan (0001) reserved
internal/"for CLI-only glue that emerges in M5." This refactor bringsinternal/into use earlier — forprojectrather than M5 CLI glue. Documented in the impl plan (0007) decision L-8.Where
pkg/— newly created; receives the three public packages viagit mv(history preserved as similarity-detected renames).internal/— newly created; receivesprojectpackage.cmd/cascade/main.go,cmd/cascade/main_test.go— import path rewrites (/project→/internal/project).pkg/depgraph/*.go,pkg/depgraph/*_test.go,pkg/golist/golist_test.go— import path rewrites (/golist→/pkg/golist,/depgraph→/pkg/depgraph).Makefile—VERSION_PKGldflags target;VERSIONfile-read path.scripts/coverage-check.sh—PACKAGESarray updated to new paths plus a refreshed comment block.README.md— Library section'simportblock.CLAUDE.md— Architecture section rewritten for three layers (Pure core public / Private support module-internal / I/O shell); adds a one-paragraph subsection oninternal/project.CONTRIBUTING.md— Coverage and Versioning sections updated.VERSION(root symlink) — re-pointed fromproject/VERSIONtointernal/project/VERSION(rm+ln -s;git mvon symlinks is fragile).docs/design/05-active/0004-...m3-...md→docs/design/06-final/0004-...md— M3 design doc state transition (now-merged milestone moves to final).docs/design/05-active/0005-cascade-m4-changeset-...md— M4 design doc lands in 05-active for forward-looking changeset work that uses the newpkg/changesetpath.docs/design/index.md— reflects the above two state changes.docs/dev/0007-implementation-plan-...md— the implementation plan (the first commit on this branch).docs/dev/0008-implementation-retrospective-...md— the closing retrospective walking L-F1..L-F19 row-by-row.How to verify
Abridged ledger (full version in
docs/dev/0008-implementation-retrospective-package-layout-refactor-pkg-internal.md)pkg/golist/exists with all golist filespkg/depgraph/exists with M3 work.gofiles (depgraph.go, methods.go, doc.go, depgraph_test.go, helpers_test.go).pkg/changeset/exists with M1 stubinternal/project/exists with project files0.1.0) all present.golist/,depgraph/,changeset/,project/all gone.git grep -E '...(golist|depgraph|changeset|project)[^/]'returns empty.cmd/cascadeimports new internal pathcmd/cascade/main.go:12: "github.com/geomyidia/cascade/internal/project".VERSION_PKGpoints at internalVERSION_PKG := $(MODULE_PATH)/internal/project.coverage-check.shPACKAGES updatedpkg/count: 7 (3 in array + 4 in comment block); 4-entry array now referencespkg/{golist,depgraph,changeset}+internal/project.cascade/pkg/references in the import block.go build ./...succeedsmake buildclean locally; CI matrix evidence on this PR's check run.go test -race ./...passes-race -count=1.golangci-lint runclean0 issueswith cold-cache via OUT-1.gofmt -l .emptymake lintgofmt-check passes.go mod tidyis a no-oppkg/golist100%,pkg/depgraph100%,internal/project100%,pkg/changesetN/A (M1 stub).cascade 0.1.0 (build refactor/pkg-internal-layout@0bfaf63, ...)— Version from VERSION file, GitBranch+GitCommit+BuildDate from-X internal/project.*ldflags.git mvpreserved historypkg/golist/golist.go→ reaches5f80812 M2: golist adapter;pkg/depgraph/depgraph.go→5a309ba m3: implement depgraph package;internal/project/version.go→5897017and three earlier evolution commits;pkg/changeset/doc.go→55e66ce Land M1 repo scaffold.internal/visibility rule), with reasoning so future "no citations" entries aren't read as compliance theatre.Total rows: 19. Done: 19. Deferred: 0. No-op: 0. Iteration count: 1.
Notable findings
[^/]anchor was load-bearing. L-F6's verify (git grep -E '...[^/]') cleanly distinguishes "old top-level path" from "new pkg/-prefixed path" — without the anchor, a grep forcascade/golistalso matchescascade/pkg/golistand the verify lies. Documented in the retro's "What Worked" so future verify commands inherit the pattern.//go:embed VERSIONsurvived the move trivially because it's path-relative to the package directory. The program-level contract was never at risk; only the casual-reader root-level./VERSIONsymlink needed manual re-pointing.git mvproduced similarity-detected renames at 99–100% similarity with no special handling.git log --followtraces every file back to its original landing commit (M1, M1.5, M2, or M3 depending on the file). No split add+delete; blame is preserved.Checklist
make checkpasses locallyBreaking change?
Yes. External consumers' import paths break:
github.com/geomyidia/cascade/golist→github.com/geomyidia/cascade/pkg/golistgithub.com/geomyidia/cascade/depgraph→github.com/geomyidia/cascade/pkg/depgraphgithub.com/geomyidia/cascade/changeset→github.com/geomyidia/cascade/pkg/changesetgithub.com/geomyidia/cascade/project→ no longer importable externally (moved underinternal/, structurally enforced by the Go toolchain)Pre-v1.0 explicitly allows this; the README's Status section documents v0.x as no-stability. v1.0 commits to the
pkg/+internal/layout in perpetuity (or until a v2-directory rev). Worth re-checking the layout question one more time before the v0.1.0 → v1.0 jump.🤖 Generated with Claude Code