// Package arch holds quarry's structural assertions. This test enforces the
// ops-seam rule from docs/rfcs/0001-quarry-forge.md ยง9: only internal/ops
// may import the data planes. It runs `go list` over the module, so it needs
// no dependencies and cannot drift from the real build graph.
package arch
import (
"encoding/json"
"os/exec"
"strings"
"testing"
)
// dataPlanePrefixes are import-path prefixes only internal/ops may reach.
// Grow this list as data planes land (SQLite driver, forge OLTP, the zit
// subprocess wrapper). The zero state still verifies the mechanism.
var dataPlanePrefixes = []string{
"github.com/ncruces/go-sqlite3",
"craftdesign.group/quarry/internal/zitcli",
"craftdesign.group/quarry/internal/oltp",
}
// allowedImporters may import data-plane packages directly.
var allowedImporters = []string{
"craftdesign.group/quarry/internal/ops",
"craftdesign.group/quarry/internal/zitcli",
"craftdesign.group/quarry/internal/oltp",
}
type pkg struct {
ImportPath string
Imports []string
Deps []string
}
func TestOnlyOpsImportsDataPlanes(t *testing.T) {
out, err := exec.Command("go", "list", "-json", "./...").Output()
if err != nil {
t.Fatalf("go list: %v", err)
}
dec := json.NewDecoder(strings.NewReader(string(out)))
for dec.More() {
var p pkg
if err := dec.Decode(&p); err != nil {
t.Fatal(err)
}
if isAllowed(p.ImportPath) {
continue
}
for _, imp := range p.Imports {
for _, plane := range dataPlanePrefixes {
if strings.HasPrefix(imp, plane) {
t.Errorf("%s imports data plane %s directly; route through internal/ops", p.ImportPath, imp)
}
}
}
}
}
func isAllowed(path string) bool {
for _, a := range allowedImporters {
if path == a || strings.HasPrefix(path, a+"/") {
return true
}
}
return false
}