galaxyproject / galaxyproject/foundry-pattern
Kind relationships: containment is the routing table's job, and the manifest under-reports it
- Dominant language
- Astro
- Stars
- 1
- Forks
- 0
- PR merge metrics
- No merged PRs in 30d
Description
> ⚠️ **Filed by Claude (AI assistant) on jmchilton's behalf** — written by Claude, not authored by them personally.
Split out of #15 (§G / question 4), which deferred this deliberately as *"the one item with no existing prose spec to transcribe, i.e. genuinely new design rather than capture."*
**That framing was measured before deferring, and two-thirds of it is wrong.** This issue starts from the measurement, not from §G's original paragraph.
§G listed four relationships: `cli-command` belongs to a `cli-tool`; `mold`s compose into a `pipeline`; a chapter belongs to a `book`; an experiment contains candidate `mold`s — *"nothing declares containment, so the catalog is 12 flat rows."*
## What is actually true
**`mold` → `pipeline` is already declared, richly.** `pipeline`'s frontmatter carries `phases[].mold` as a validated `[[wiki-link]]`, with `branches`, `chain`, `loop` and `fallthrough` — a whole composition graph. It is the best-declared relationship in either foundry, and it lives on the note rather than the kind because it **varies per note**, which is correct.
**The other three are containment, and containment is the directory.** None is data and none varies. All three are already decided by the collection routing table:
```ts
"cli-tools": { base: "content/cli", pattern: ["*/index.md"], kind: "cli-tool" },
"cli-commands": { base: "content/cli", pattern: ["*/*.md", "!*/index.md"], kind: "cli-command" },
```
**Containment is the complement of the companion relation, and the substrate already computes both sides.** `checkCompanions` walks a directory note's directory and tags each entry `note: true | false`. The `false` entries are companions. The `true` entries are contained notes — and that half is computed and thrown away.
**The one real gap is that the manifest under-reports.** `ManifestKind.locations` ships the collection *base* but not its *pattern*, so `cli-tool` and `cli-command` both read `content/cli`. A consumer can see two kinds share a directory and cannot tell which contains which. That, not an absent relationship declaration, is why the catalog is flat.
## The actual choice
1. **Derive** — carry each collection's pattern into `ManifestKind` beside `locations`; containment falls out of routing, nothing new is declared. The same "derived, not generated" move as #15's Phase 6.
2. **Declare** — a kind-level `contains` / `containedBy`. Most legible, needs no new manifest field, but becomes a **fourth** encoding of directory structure alongside the collection glob, the shape, and the companion list — and can disagree with all three. #15's whole thesis argues against it.
**Sequencing note:** option 1 is a manifest format change, so it wants to ride the version bump in the foundry-lib issue. Doing them separately means two coordinated releases across four repos instead of one. That was known and accepted when §G was deferred; it is the cost of this issue existing.
Contributor guide
No contributing guide indexed for this repository
Research direction
Start with the ManifestKind shape, the collection routing table, and checkCompanions, which already computes contained versus companion notes. Confirm how the manifest currently exposes collection locations, then resolve whether containment should be derived from routing patterns or declared at kind level; done requires an agreed design and coordinated manifest-format release plan.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- typescript
- Domain
- tooling
- Issue type
- Feature
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Quiet
- Clarity
- Needs clarification
- Newbie friendliness
- 30/100