Skip to content

refactor: consolidate top-level layout into pkg/ + internal/#8

Merged
oubiwann merged 3 commits into
mainfrom
refactor/pkg-internal-layout
May 7, 2026
Merged

refactor: consolidate top-level layout into pkg/ + internal/#8
oubiwann merged 3 commits into
mainfrom
refactor/pkg-internal-layout

Conversation

@oubiwann

@oubiwann oubiwann commented May 7, 2026

Copy link
Copy Markdown
Contributor

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's internal/ 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 brings internal/ into use earlier — for project rather than M5 CLI glue. Documented in the impl plan (0007) decision L-8.

Where

  • pkg/ — newly created; receives the three public packages via git mv (history preserved as similarity-detected renames).
  • internal/ — newly created; receives project package.
  • 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).
  • MakefileVERSION_PKG ldflags target; VERSION file-read path.
  • scripts/coverage-check.shPACKAGES array updated to new paths plus a refreshed comment block.
  • README.md — Library section's import block.
  • CLAUDE.md — Architecture section rewritten for three layers (Pure core public / Private support module-internal / I/O shell); adds a one-paragraph subsection on internal/project.
  • CONTRIBUTING.md — Coverage and Versioning sections updated.
  • VERSION (root symlink) — re-pointed from project/VERSION to internal/project/VERSION (rm + ln -s; git mv on symlinks is fragile).
  • docs/design/05-active/0004-...m3-...mddocs/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 new pkg/changeset path.
  • 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

make tidy           # confirm go.mod is still tidy (no-op)
make build          # produces ./bin/cascade
./bin/cascade --version   # L-F17: prints injected version metadata, ldflags chain still wired
make lint           # cold cache via OUT-1; should be 0 issues
make test           # go test -race -count=1 ./...
bash scripts/coverage-check.sh   # L-F16: per-package gate against new paths

# L-F18: history preservation across the four moves
git log --oneline --follow pkg/golist/golist.go | head -5
git log --oneline --follow pkg/depgraph/depgraph.go | head -3
git log --oneline --follow internal/project/version.go | head -5
git log --oneline --follow pkg/changeset/doc.go | head -3

# L-F6: no old paths remain anywhere
git grep -E 'github\.com/geomyidia/cascade/(golist|depgraph|changeset|project)[^/]' -- '*.go'

Abridged ledger (full version in docs/dev/0008-implementation-retrospective-package-layout-refactor-pkg-internal.md)

ID Criterion Status Evidence
L-F1 pkg/golist/ exists with all golist files done golist.go, parse.go, errors.go, doc.go, plus _test.go siblings + testdata/ all present at new path.
L-F2 pkg/depgraph/ exists with M3 work done 5 .go files (depgraph.go, methods.go, doc.go, depgraph_test.go, helpers_test.go).
L-F3 pkg/changeset/ exists with M1 stub done doc.go preserved.
L-F4 internal/project/ exists with project files done version.go, version_test.go, VERSION (0.1.0) all present.
L-F5 Old top-level dirs removed done golist/, depgraph/, changeset/, project/ all gone.
L-F6 No old-path imports remain done git grep -E '...(golist|depgraph|changeset|project)[^/]' returns empty.
L-F7 cmd/cascade imports new internal path done cmd/cascade/main.go:12: "github.com/geomyidia/cascade/internal/project".
L-F8 Makefile VERSION_PKG points at internal done VERSION_PKG := $(MODULE_PATH)/internal/project.
L-F9 coverage-check.sh PACKAGES updated done pkg/ count: 7 (3 in array + 4 in comment block); 4-entry array now references pkg/{golist,depgraph,changeset} + internal/project.
L-F10 README Library example uses new paths done 3 cascade/pkg/ references in the import block.
L-F11 go build ./... succeeds done make build clean locally; CI matrix evidence on this PR's check run.
L-F12 go test -race ./... passes done All four test-bearing packages pass under -race -count=1.
L-F13 golangci-lint run clean done 0 issues with cold-cache via OUT-1.
L-F14 gofmt -l . empty done make lint gofmt-check passes.
L-F15 go mod tidy is a no-op done No go.mod/go.sum diff after tidy. Module path unchanged.
L-F16 Per-package coverage gate at 100% done pkg/golist 100%, pkg/depgraph 100%, internal/project 100%, pkg/changeset N/A (M1 stub).
L-F17 Build + version chain works end-to-end done cascade 0.1.0 (build refactor/pkg-internal-layout@0bfaf63, ...) — Version from VERSION file, GitBranch+GitCommit+BuildDate from -X internal/project.* ldflags.
L-F18 git mv preserved history done All four packages: pkg/golist/golist.go → reaches 5f80812 M2: golist adapter; pkg/depgraph/depgraph.go5a309ba m3: implement depgraph package; internal/project/version.go5897017 and three earlier evolution commits; pkg/changeset/doc.go55e66ce Land M1 repo scaffold.
L-F19 Closing report names guides + IDs cited done Retrospective §"Substrate loaded at session start" — explicitly documents minimal-citations posture appropriate for a pure refactor (no Go-guide chapters loaded beyond implicit 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

  • The plan's [^/] 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 for cascade/golist also matches cascade/pkg/golist and the verify lies. Documented in the retro's "What Worked" so future verify commands inherit the pattern.
  • //go:embed VERSION survived 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 ./VERSION symlink needed manual re-pointing.
  • git mv produced similarity-detected renames at 99–100% similarity with no special handling. git log --follow traces 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.
  • OUT-1 (M3's lint-cache fix) confirmed cleanliness with high confidence on first invocation. Third milestone in a row OUT-1 has either caught an issue (M3) or confirmed cleanliness against a layout/build-system change (this refactor).

Checklist

  • make check passes locally
  • New/changed exported symbols have godoc comments (N/A: no API changes)
  • Tests added/updated for behavior changes (N/A: behaviour unchanged; existing tests follow the moved code)
  • No public-API breakage (or if there is, it's flagged below) — see Breaking change
  • If this PR closes a milestone ledger, each row's planned evidence text matches the criterion text (per M2 retro carry-forward)

Breaking change?

Yes. External consumers' import paths break:

  • github.com/geomyidia/cascade/golistgithub.com/geomyidia/cascade/pkg/golist
  • github.com/geomyidia/cascade/depgraphgithub.com/geomyidia/cascade/pkg/depgraph
  • github.com/geomyidia/cascade/changesetgithub.com/geomyidia/cascade/pkg/changeset
  • github.com/geomyidia/cascade/project → no longer importable externally (moved under internal/, 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

oubiwann and others added 3 commits May 7, 2026 01:49
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>
@oubiwann oubiwann merged commit f176e4f into main May 7, 2026
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant