Skip to content

feat(module-ci): apply output types before modules - #17

Merged
anujhydrabadi merged 1 commit into
masterfrom
feat/apply-output-types
Sep 15, 2026
Merged

anujhydrabadi merged 1 commit into
masterfrom
feat/apply-output-types

Conversation

@anujhydrabadi

Copy link
Copy Markdown
Contributor

Why

A modules repository now carries two trees: the modules at modules/{intent}/{flavor}/{version}/ and the output types they exchange at outputs/{namespace}/{name}.yaml. CI had no step for the second.

The ordering is forced, not chosen. A module names its output type by reference, and the control plane refuses a module upload whose type it does not already hold (Output @ns/name not found). So the action applies output types first, in both preview and publish mode.

Preview ≠ publish, for a real reason

An output type is global and unversioned: the control plane keys it on name + namespace alone — no stage, no version — and a write replaces it for every module and every environment at once. There is no slot to hold a proposed change and nothing to roll back to.

Mode Output types
preview (PR) raptor create output-type -f FILE --if-absent. A type the control plane has never seen is created — zero consumers, so the write is safe, and it is the only way a PR that adds a module and its new type can validate its own module. An existing type is only reported in the PR comment.
publish (push) Full apply. raptor still refuses a removal or retype while some module uses the type, and names those modules.
cleanup (PR closed) Nothing.

Never deletes. Removing a file from outputs/ leaves the type in place. Two reasons: a delete on PR-close would break every module reading it with no preview slot to restore from, and a type carries no provenance fields, so there is no ownership check like the one module cleanup relies on. The README says so and points at raptor module delete-output-type.

Changes

  • New steps Detect target output type definitions and Apply output types, placed before both the preview and publish module steps.
  • New input apply-output-types (default true) for a repo whose types are managed elsewhere.
  • all-modules: true now also sweeps every definition under outputs/.
  • A deleted file is deliberately not a target ([ -f "$f" ] || continue).
  • The PR comment is assembled in the upsert step instead of the module step: a PR can touch output types only, modules only, or both, and the <!-- facets-module-ci:preview --> marker must appear exactly once in the final body. The upsert condition widened to dirs != '' || output_files != '', so a types-only PR still gets a comment.
  • READMEs updated with the layout, the mode table and the never-deletes rule.

Testing

Not run against a live repository. action.yml parses as YAML, every embedded script passes bash -n, and the three new/changed scripts are shellcheck clean at --severity=warning.

Safe to merge before any repository has an outputs/ tree: the detection step finds nothing and every new step no-ops.

Merge order

This is second of three, and must not be tagged v1 until raptor ships:

  1. Facets-cloud/raptor #442merge and tag a release. This action calls create output-type -f DIR --if-absent; an older raptor rejects both, and control-plane-bootstrapped repos pin module-ci-action@v1.
  2. This PR → merge, then move the v1 alias.
  3. Facets-cloud/control-plane — export output types in the modules-repo bootstrap and sync. It must land last: the moment it ships, bootstrap and sync start writing outputs/ trees whose CI needs both of the above already live.

🤖 Generated with Claude Code

A modules repository now carries the output types its modules exchange, at
outputs/{namespace}/{name}.yaml. CI had no step for them.

The order is not a preference. A module names its output type by reference and
the control plane refuses a module upload whose type it does not already hold
("Output @ns/name not found"), so the types are applied first in both preview
and publish mode.

Preview and publish are not the same operation at different strengths, because
an output type is global and unversioned: the control plane keys it on name and
namespace alone, with no stage and no version, and a write replaces it for
every module at once. There is no slot to hold a proposed change and nothing to
roll back to.

- preview (pull request): `raptor create output-type -f FILE --if-absent`. A
  type the control plane has never seen is created — it has no consumers, so
  the write is safe, and it is the only way a pull request that adds a module
  together with its new type can validate its own module. A type that already
  exists is only reported in the PR comment.
- publish (push): the full apply. raptor still refuses a removal or a retype
  while some module uses the type.
- cleanup (PR close): nothing. CI never deletes an output type — there is no
  preview slot to restore one from, and a type carries no provenance, so there
  is no ownership check like the module cleanup relies on.

The PR comment is now assembled in the upsert step rather than in the module
step, because a pull request can touch output types only, modules only, or
both, and the marker must appear exactly once in the final body.

New input `apply-output-types` (default true) turns the whole thing off for a
repository whose types are managed elsewhere.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@anujhydrabadi
anujhydrabadi merged commit 344c855 into master Sep 15, 2026
1 check passed
@anujhydrabadi
anujhydrabadi deleted the feat/apply-output-types branch September 15, 2026 12:11
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant