Structured default_setup entries so setup inputs can't be forgotten
- Dominant language
- Python
- Stars
- 60
- Forks
- 18
- Avg merge
- 1d 16h
- Merged PRs (30d)
- 38
Description
**From Claude** (Anthropic's Claude Code), prompted by @petebachant while reviewing #1579.
Split out of the first TODO in #1579, which proposed:
```yaml
environments:
compilation:
kind: system
default_setup:
- kind: source
path: scripts/setup.sh
```
## The problem
#1579 ships `default_setup` as `list[str]` alongside a separate `inputs`
list. Nothing ties them together, so this is silently irreproducible:
```yaml
default_setup:
- source scripts/setup.sh
inputs: [] # forgotten
```
`scripts/setup.sh` changes, the stage was built against the old toolchain,
and `calkit status` shows nothing stale because no declared dependency
moved. The failure is silent, which is the worst shape for it.
## Proposal
Widen the field to a union rather than replacing the string form:
```python
default_setup: list[str | SetupSource] | None
```
`{kind: source, path: scripts/setup.sh}` makes the dependency implicit in
the declaration -- you can't say what to source without saying what it
depends on -- so there is no separate `inputs` discipline to forget.
Keeping plain strings matters because `module load cuda` has no input and
shouldn't be forced into an object. `Stage.inputs` is already
`list[str | PathInput | InputsFromStageOutputs]`, so a union matches how
the codebase already handles this.
This is backwards compatible with what #1579 ships, so nothing there has
to change first.
`inputs` would stay for the residue -- a setup command that reads a config
file without sourcing it -- but most projects would stop writing it.
## Not proposed: detecting inputs from the command
#1579 also floated parsing paths out of the setup commands. @petebachant's
own read was that it is "more implicit and potentially could fail," which
matches the comment already in `calkit/pipeline.py`:
> Declared rather than parsed out of the commands, since a shell command
> doesn't reliably say which of its words is a path.
Concretely it breaks on `source $SETUP_DIR/setup.sh` (the path isn't in
the text), `. scripts/setup.sh` (the dot form), and `source ~/.bashrc` (a
real path that correctly isn't a project input). A missed input is
*silent*, so detection that is 95% right reintroduces exactly the bug it
was meant to fix, except now with users trusting it.
The structured form gets the benefit that made auto-detection attractive
(no second list to maintain) without that risk.
Contributor guide
Research direction
Start in calkit/pipeline.py and trace the existing default_setup and Stage.inputs declarations. Check how setup entries are parsed and validated, then verify that both strings and SetupSource entries remain supported and that a source entry carries its path dependency without a separate inputs declaration.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- python
- Domain
- tooling
- Issue type
- Feature
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 58/100