Problem / why
A manifest may declare a nested components: block under schema_version 1 (or with
schema_version omitted). The parser must accept that block (each component owning paths,
tag_prefix, triggers, builds, deploys, and an optional environments subset) and load
it into the same component-major in-memory model F1 introduced. A manifest with no components:
block continues to parse exactly as today, as the single implicit default component.
Scope
This PR does:
- Accept a
components: block in internal/config/parse.go and route it to a component parse
path that reads the nested block into the component-major model (the declared components ARE
the components; no synthesized default). This is gated on schema_version being omitted or
1, NOT on a version bump.
- Add a component validator (
internal/config/validate_components.go or equivalent): each
component has a distinct tag_prefix, a safe name, non-empty paths, and at least one build
or deploy. A component's environments, if present, must be a subset of the global ladder.
- Update
internal/schema/manifest.schema.json to describe the component-major
config.components, state.components.<name>.<env>, and latest_release.components.<name>,
all under schema_version 1.
- Keep a manifest with no
components: block on its existing parse and validate path,
unchanged, loading as the single default component.
This PR does NOT:
- Implement per-component version math (V2) or per-component file generation (F4 / V3).
- Implement the env-subset behavior (X1) beyond validating the field shape.
- Change the single-component path.
Files / areas touched
internal/config/parse.go - component parse routing.
internal/config/validate_components.go - component validation.
internal/config/types.go - the ComponentConfig shape (its full field set is exercised in
V1; here, enough to parse and validate).
internal/schema/manifest.schema.json - component-major shape under schema_version 1.
Tests and coverage required
- Unit tests: a two-component manifest parses and validates into the component-major model.
- Validation tests: duplicate
tag_prefix rejected; missing prefix rejected; unsafe name or
empty paths rejected; a component env subset that escapes the global ladder rejected.
- A test that a manifest with no
components: block still parses and validates exactly as
before (no regression).
Acceptance criteria
- A manifest with a nested
components: block under schema_version 1 parses into the
component-major model.
- The component validator enforces distinct prefixes, safe names, non-empty paths, and a valid
env subset.
- The single-component path is unaffected.
Dependencies
Blocked by F1 (needs the component-major in-memory model to parse into).
Problem / why
A manifest may declare a nested
components:block underschema_version 1(or withschema_versionomitted). The parser must accept that block (each component owningpaths,tag_prefix,triggers,builds,deploys, and an optionalenvironmentssubset) and loadit into the same component-major in-memory model F1 introduced. A manifest with no
components:block continues to parse exactly as today, as the single implicit
defaultcomponent.Scope
This PR does:
components:block ininternal/config/parse.goand route it to a component parsepath that reads the nested block into the component-major model (the declared components ARE
the components; no synthesized default). This is gated on
schema_versionbeing omitted or1, NOT on a version bump.internal/config/validate_components.goor equivalent): eachcomponent has a distinct
tag_prefix, a safe name, non-emptypaths, and at least one buildor deploy. A component's
environments, if present, must be a subset of the global ladder.internal/schema/manifest.schema.jsonto describe the component-majorconfig.components,state.components.<name>.<env>, andlatest_release.components.<name>,all under
schema_version 1.components:block on its existing parse and validate path,unchanged, loading as the single
defaultcomponent.This PR does NOT:
Files / areas touched
internal/config/parse.go- component parse routing.internal/config/validate_components.go- component validation.internal/config/types.go- theComponentConfigshape (its full field set is exercised inV1; here, enough to parse and validate).
internal/schema/manifest.schema.json- component-major shape under schema_version 1.Tests and coverage required
tag_prefixrejected; missing prefix rejected; unsafe name orempty
pathsrejected; a component env subset that escapes the global ladder rejected.components:block still parses and validates exactly asbefore (no regression).
Acceptance criteria
components:block under schema_version 1 parses into thecomponent-major model.
env subset.
Dependencies
Blocked by F1 (needs the component-major in-memory model to parse into).