| id | 2606022123 |
|---|---|
| title | Catalog directive — accept `..` globs within project root |
| status | ✅ |
| summary | Let <?catalog?> accept `..` segments in glob patterns as long as the resolved pattern stays within the project root, matching <?include?>'s existing behavior. Unblocks cross-tree catalogs (e.g. a skill cataloging the architecture docs one level up the tree). |
| model | sonnet |
| depends-on |
Bring <?catalog?> glob acceptance in line with
<?include?>: .. segments are allowed as long
as the resolved pattern stays inside the project
root, unblocking cross-tree catalogs.
internal/rules/catalog/rule.go
rejects any glob containing a .. segment
outright. The companion <?include?> directive
(MDS021) accepts .. paths and only fails when
the resolved path escapes the project root (see
MDS021's README).
The asymmetry shows up in real use. The
solid-architecture skill
wants to catalog the architecture docs at
the architecture hub
and its siblings. The skill sits four levels
deep, so the glob would need a
../../../docs/... prefix, which today is
rejected. The skill ships a hand-maintained
reference-style link-def block as a workaround;
relaxing this rule retires that workaround.
- Allowing absolute glob paths. Project-root containment is the rule; absolute paths still reject.
- Allowing globs that resolve outside the
project root, even via
... - Loosening the
<?include?>directive — it already does the right thing.
Refactor validateGlob in
internal/rules/catalog/rule.go:
- Stop rejecting patterns wholesale on the
first
..segment. - After the existing absolute-path check, resolve the pattern against the marker file's directory and compare to the project root.
- Accept the pattern if it stays inside the project root.
- Reject with a new diagnostic
generated section directive glob escapes project rootwhen the pattern would resolve outside the project root.
A resolve helper already exists for MDS021. Either share it from the include rule or lift it into globpath. Have both directives call the shared helper.
- Add a test for a
../sibling/*.mdglob whose resolved path stays inside the project root (TestCatalog_DotDotGlobStaysInsideRoot). - Add a test for a glob whose resolve
escapes the project root and expects the new
diagnostic message
(
TestCatalog_DotDotGlobEscapesRoot). - Replace the
containsDotDotreject with a project-root containment check; the shared resolve helper now lives ininternal/globpathasResolveAgainstRoot(alongsideContainsDotDotSegment). Catalog defers there; the MDS021 helper can adopt it in a follow-up since its current path-escape check predates the helper. - Update the MDS019 catalog README to describe the new behavior and the escapes-root and missing-root diagnostics.
- Add
good/dotdot.mdandbad/dotdot.mdunderinternal/rules/MDS019-catalog/. The integration runner now pinsf.RootFS = f.FSfor MDS019 fixtures so ".." resolution mirrors a real project. - Add the
<?catalog?>block in the solid-architecture SKILL.md targeting../../../docs/development/architecture/*.mdwithrow: "[{slug}]: {filename}". Runningmdsmith fixregenerates the five slug-labeled link defs.
- Tests in
internal/rules/catalog/rule_test.gocover the accept and reject cases and pass. -
internal/rules/MDS019-catalog/README.mddocuments the new behavior and lists the escapes-root diagnostic. -
internal/rules/MDS019-catalog/good/andbad/each contain a new fixture for the new behavior. - All tests pass:
go test ./.... -
go tool golangci-lint runreports no issues. -
mdsmith check .passes. -
.claude/skills/solid-architecture/SKILL.mduses a<?catalog?>block for the architecture link defs and renders the five reference-style slug labels (audit,cross,go,hub,ts).