Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .agents/skills/skill-lifecycle/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ A skill surfaces at a trigger moment. A rule that binds every action all the tim
Packaging keeps one topic in one authoritative place while the skill makes it surface automatically. It has three shapes, and each pairing states which it uses:

- **Moved content.** The law-doc section keeps a summary and the skill holds the full rules (`git-commit-conventions`, `comment-and-doc-style`, `pr-review-conduct`). The section ends with the standard pointer sentence: packaged as the named skill at `.agents/skills/<name>/SKILL.md` in the hub, not a repo-relative link since that path is hub-local and not carried into every fleet repo, read the skill for the full rules.
- **Kept authority.** The source doc keeps the full rules and the skill is the summary that routes to them (`audit-a-repo` over `AUDIT.md`, `workflow-ci-contract` over `WORKFLOW.md` outside section 4). The skill states per topic which doc section owns it.
- **Included content.** The doc keeps the full rules and the skill needs them whole to work in isolation, so it carries the section as a generated include rather than as a summary or a copy, declared with the region markers "The Pipeline" above describes and keyed on the doc's section (`agent-conduct` over the three `GOVERNANCE.md` sections it surfaces, `workflow-ci-contract` over `WORKFLOW.md` section 4). The doc side states the shape with one sentence naming the skill that includes the section, and the skill side is the region itself. A section carried this way is read outside its own document, so it names a sibling section by document and heading rather than as above or below, and it links to no file by a relative path, since the path would resolve against the skill's directory rather than the doc's. The doc wins by construction, since `scripts/build_dist.py` writes the region from it and its `--check` reports a region that differs from it as stale.
- **Kept authority.** The source doc keeps the full rules and the skill is the summary that routes to them (`audit-a-repo` over `AUDIT.md`, `workflow-ci-contract` over `WORKFLOW.md` outside sections 3, 4, and 5). The skill states per topic which doc section owns it.
- **Included content.** The doc keeps the full rules and the skill needs them whole to work in isolation, so it carries the section as a generated include rather than as a summary or a copy, declared with the region markers "The Pipeline" above describes and keyed on the doc's section (`agent-conduct` over the three `GOVERNANCE.md` sections it surfaces, `workflow-ci-contract` over `WORKFLOW.md` sections 3, 4, and 5). The doc side states the shape with one sentence naming the skill that includes the section, and the skill side is the region itself. A section carried this way is read outside its own document, so it names a sibling section by document and heading rather than as above or below, and it links to no file by a relative path, since the path would resolve against the skill's directory rather than the doc's. The doc wins by construction, since `scripts/build_dist.py` writes the region from it and its `--check` reports a region that differs from it as stale.

In every shape the doc is the authority when the two are found to disagree, the moved-content shape included: the doc's summary says what the rule is, and the skill's full text is what gets corrected. A deliberate change to a packaged rule is not such a disagreement. It lands where the full text lives, and in the same change the author either edits the other side's summary to match, since a summary has no mechanical check, or regenerates the include, which has one. A rule stated fully in both places by hand is the drift this pattern exists to prevent, and an include is the one full second statement that cannot drift undetected.
20 changes: 6 additions & 14 deletions .agents/skills/workflow-ci-contract/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,31 +8,23 @@ description: >-

## Why This Exists

`WORKFLOW.md` is the fleet's CI/CD behavioral contract. This skill is that contract's surface, so an agent editing workflow YAML has the contract in view. It carries the summary, with the contract's section 4 carried whole as a generated include and the test methodology indexed in `references/`. `WORKFLOW.md`'s own canonical-scope note says which of it and `GOVERNANCE.md` is authoritative where the two overlap.
`WORKFLOW.md` is the fleet's CI/CD behavioral contract. This skill is that contract's surface, so an agent editing workflow YAML has the contract in view. It carries the summary, and `WORKFLOW.md` sections 3, 4, and 5 are each carried whole in `references/` as a generated include. `WORKFLOW.md`'s own canonical-scope note says which of it and `GOVERNANCE.md` is authoritative where the two overlap.

## How the Contract Is Read

- **Outcomes, not bytes.** A workflow is judged against `WORKFLOW.md` section 4's expected inputs and outputs, never against a snippet byte for byte, per `GOVERNANCE.md` "Foundational Principles".
- **Applicability.** A guarantee governing a construct the repo does not contain is N/A: recorded, excluded from the verdict, never a defect. A source-only pipeline is mostly N/A and that is fine.
- **Applicability.** A guarantee, or a 5A check or 5B scenario from `WORKFLOW.md` section 5, governing a construct the repo does not contain is N/A: recorded, excluded from the verdict, never a defect. A source-only pipeline is mostly N/A and that is fine.
- **Operational is binary.** Every applicable guarantee holds, or the workflow is not operational. A single applicable input-output mismatch is a defect regardless of how clean the YAML looks.
- **Reached, not carried.** A standard workflow whose job graph is identical across repos of a type is reached as a hub-hosted `workflow_call` task, per `GOVERNANCE.md` "Hub-Hosted Tooling". The repo's own surface is the caller stub, pinned to a hub release commit, and a composite-action hook at `.github/actions/<hook>` for what is its own. A hub task reaches its own actions and sibling tasks through `$/`, which resolves at that pinned commit. The merge-bot is the first, and `docs/reusable-workflows.md` in the hub carries the model, the hook contract, and the phase each workflow migrates in. Until a workflow's phase ships, its copy is graded as below.
- **Two layers.** Orchestration (the PR entry workflow, publisher, version and release jobs) is generic and standard at the job level. Build leaves (the `build-<target>` tasks) are repo-owned. Inputs like `github`/`dockerhub`/`expect_release_assets` live on the orchestrator, a leaf receives `ref`/`branch`/`smoke` and whatever else its target needs, a derived `push` among them where that leaf pushes, so assert each input in the layer that declares it. A package target declares no push input on either layer, its push living in a separate `publish-<target>` job in the repo's own publisher. What a repo curates is the list of targets, and adding or dropping one edits the whole surface together: the `enable_<target>` input, the `build-<target>` job and its `github-release` and `build-docker` `needs:` entries, the `changes` paths-filter entry and output, the `smoke-build` enable-forward, and a package target's `publish-<target>` job (D6.4).
- **Reached, not carried.** A standard workflow whose job graph is identical across repos of a type is reached as a hub-hosted `workflow_call` task, per `GOVERNANCE.md` "Hub-Hosted Tooling". The repo's own surface is the caller stub, pinned to a hub release commit, and a composite-action hook at `.github/actions/<hook>` for what is its own. A hub task reaches its own actions and sibling tasks through `$/`, which resolves at that pinned commit. The merge-bot is the first, and `docs/reusable-workflows.md` in the hub carries the model, the hook contract, and the stage each workflow migrates in. Until a workflow's stage ships, its copy is graded against the same contract.
- **Two layers.** The pipeline splits into an orchestrator layer and a build-leaf layer, defined in `WORKFLOW.md` section 3's `Two Layers: Orchestration vs Build` and carried in `references/architecture.md`, while `WORKFLOW.md` section 1's `Two layers when auditing` maps which layer declares which input. When a check names an input, assert it in the layer that declares it.

## Style Rules

`GOVERNANCE.md` "Workflow YAML Conventions" keeps the style rules, and the `comment-and-doc-style` Skill keeps the line-ending policy, reached from `GOVERNANCE.md` "Documentation Style Conventions" under "Line Endings". Read both before editing a workflow or a composite action.

## The Core Behavioral Spine
## The Contract Text

- **PRs validate fast and never publish**: a paths-filter smoke-builds only changed targets, the caller's own job reaching the reusable validator, or the replacement it points its aggregator at, always runs, and one required aggregator gates the merge, running under `if: always()` so a failed or skipped dependency cannot skip the gate itself, treating skipped smoke as pass and blocking on failure or cancelled. Smoke does a full compile/lint/test but pushes nothing and uploads nothing, every `upload-artifact` gated on smoke being false, which is `!inputs.smoke` at the workflow layer and `inputs.smoke != 'true'` in a composite action, whose inputs are strings.
- **A human merge never auto-publishes**, per `GOVERNANCE.md` "Release Model": a `plan` job decides once and every job gates on it. Publishes come from a code-affecting bot push to `main`, a manual dispatch of `main` or `develop`, or the main-only weekly Docker schedule, while a publisher whose only trigger is `workflow_dispatch` (`releaseTrigger: dispatch-only`) reaches the dispatch alone, its bot-push and schedule paths never firing, which covers a source-only repo and an operational repo alike. Each run builds the one trigger branch, the default branch a clean `X.Y.Z`, anything else a prerelease `X.Y.Z-g<sha>`, with NBGV owning the patch from git height. The gate's branch literal, the `prerelease` expression, and `version.json`'s `publicReleaseRefSpec` each name the repo's actual default branch, and a divergence among the three is a defect. The release tags the built commit's SHA (`GitCommitId`), never a branch name.
- **Validate at entry**: `GOVERNANCE.md` "Workflow YAML Conventions" keeps the rule. The release gate that applies it checks branch-versus-prerelease in both directions, strips `+buildmetadata`, and on smoke skips the check while the job still succeeds.
- **The seam contract**: a target contributes a release file by uploading `release-asset-<branch>-<target>`, and the release job collects by `pattern:` plus `merge-multiple:`, never `artifact-ids:`, canonical even for a single target. A caller with no file target passes `expect_release_assets: false`, which covers a Docker-only, a PyPI-only, and a source-only repo, while a NuGet-only caller keeps the default `true`, its leaf uploading a `release-asset-*` that carries the package.
- **Artifacts are an intra-run handoff**: `GOVERNANCE.md` "Workflow YAML Conventions" keeps the consume-then-delete rule, the condition that gates the delete, and the blanket-delete ban. D5 in `references/d-guarantees.md` states the outputs a pipeline shows for them.
- **No-op republish**: an unchanged version re-pushes nothing, the release-create step skips when the tag exists and is refreshed only on a dispatch, registries dedupe server-side (`--skip-duplicate`, `skip-existing: true`), and Docker alone always re-pushes by design.
- **A build failure blocks every publish target**: `github-release` needs every build and guards with `!failure() && !cancelled()` as the terminal registry pusher (Docker) does, and a package target's separate `publish-<target>` job `needs:` the release-task call, so no build failure ships anything partial. A failed package push is outside that, since it runs after the release is cut.

`references/d-guarantees.md` carries `WORKFLOW.md` section 4 whole as a generated include, so a guarantee's exact wording is one read away. `references/test-methodology.md` indexes `WORKFLOW.md` section 5's audit, trace, and probe procedure, and the sweep itself is run from section 5, which carries the whole core list, the per-type addenda, and the scenario table.
`references/architecture.md`, `references/d-guarantees.md`, and `references/test-methodology.md` carry `WORKFLOW.md` sections 3, 4, and 5 whole, each as a generated include, so the pipeline's architecture, a guarantee's exact wording, and the audit-trace-probe procedure are each one read away rather than restated in full here. A defect in an include region is fixed in `WORKFLOW.md` and regenerated, never edited in this skill, per the `skill-lifecycle` Skill. `WORKFLOW.md` keeps sections 1, 2, and 6 itself, the applicability rule, the style-rule pointer, and the per-project-type walkthroughs that say which items go N/A per type, so read those there.

## After Any Workflow Edit

Expand Down
Loading