You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
As a Pair maintainer I want the release pipeline reduced to changeset-per-PR plus a two-workflow, dispatch-only model (version.yml → release.yml) with open-source changelogs So that releases are maintainer-controlled and reproducible, and exactly two workflow runs happen per release instead of a chain triggered by merges
Where: .github/workflows/{ci,version,release,tag-on-changeset-merge}.yml, .changeset/config.json, and the /pair-process-implement skill (changeset bump-type inference).
Epic Context
Parent Epic: none — standalone (maintainer decision, 2026-08-05). It was filed under #68, an epic of the frozen Knowledge Service initiative, while its subject belonged to #211 (release management), now closed: orphaned on both sides. It is real work and does not need an epic to exist. Status: Refined Priority: P1 (Should-Have) — the pipeline is the path every release takes Builds on: #148 / PR #333 (release scripts + tested determine-version, shipped)
Classification
risk:yellow · cost: green (not projected — Active: risk only)
Matrix — per dimension
Dimension
Tier
Source
Note
Service/domain criticality
green
Criticality Table
Touched deployables: packages/dev-tools (owns repo-wide CI gates + release-pipeline logic, incl. determine-version invoked by release.yml) and packages/knowledge-hub (dataset source of the pair-process-implement skill mirror) — both listed Low
Change/diff risk
yellow
story scope
Workflows + .changeset/config.json are shared CI/release infra touched on every PR. The skill change is a dataset↔mirror pair (change-risk.dataset-mirror-pairs override collapses it to one module), but the workflow/config changes remain separate, genuinely-shared modules — still "touches multiple modules or shared code"
Business impact
yellow
subdomain class
Integration & Process Standardization (Supporting) — distribution/release process. The newer Development Tooling Standards (Generic) subdomain covers lint/format/TypeScript/markdown/brand only, not release/CI, so it does not apply here
Security relevance
yellow
path heuristic
Touches release credentials: dropping the PAT in favour of GITHUB_TOKENreduces the permission surface, but any error in a release workflow's token wiring is a publishing-authority mistake
Coupling balance
green
subdomain volatility + integrations
No new cross-context integration
Tier = yellow (max rule). tier-resolution.default-artifact-downgrade checked and does not apply: Change/diff risk and Security relevance are yellow, and that override only downgrades to green when every present yellow is confined to Service/domain-criticality and/or Business-impact. Gate checks for 🟡: lint + type + build + unit.
Reclassified 2026-08-14 against corrected adoption inputs (tech/risk-matrix.md Criticality Table + tier-resolution.default-artifact-downgrade override, both added after this story's original refinement, 2026-08-05): Service/domain criticality moves from yellow (KB default) to green. Overall tier is unchanged at yellow — Change/diff risk and Security relevance remain genuinely observed, non-artifact yellows, so the new override does not fire.
Context
Split from #148: the tooling slice shipped (PR #333, #148 closed); this story carries the remaining pipeline rewrite.
State verified against the real workflows (2026-08-05)
The original AC set asked to "confirm each still applies". Confirmed, and half of them are already done — the story shrinks accordingly:
Original AC
Status today
Evidence
1. changeset-per-PR check in ci.yml, with escape-hatch label
⬜ still needed
ci.yml mentions .changeset twice, and both are the paths-ignore on its triggers — there is no check
version.yml triggers on push to main filtered to .changeset/**, not workflow_dispatch; .changeset/config.json uses the default @changesets/cli/changelog, not @changesets/changelog-github
3. release.yml dispatch-only
✅ already done
on: workflow_dispatch with a version input, no tag-push or release-event trigger
4. delete tag-on-changeset-merge.yml
⬜ still needed
the file is present
5. remove || echo fallbacks masking failures in ci.yml
✅ already done
zero occurrences
6. eliminate the PAT (GH_RELEASE_TOKEN)
🔄 consequence of 4
the token appears in exactly one file: tag-on-changeset-merge.yml. Deleting that workflow removes the PAT
7. /implement infers the bump type when creating the changeset
⬜ still needed
skill-layer change on pair-process-implement
So the work is: the missing CI check, making version.yml dispatch-only with proper changelogs, deleting one workflow (which retires the PAT), and one skill change.
Acceptance Criteria
Functional Requirements
Given-When-Then Format:
Given a pull request with no .changeset/*.md When CI runs Then the changeset check fails — unless the PR carries the documented escape-hatch label, in which case it passes with that reason visible
Given accumulated changesets on main Whenversion.yml is dispatched manually Then it bumps the fixed-group package versions atomically, syncs the root package.json, generates PR-linked, type-grouped CHANGELOGs, commits, and pushes the v{X.Y.Z} tag
Givenversion.yml When its triggers are inspected Then it is workflow_dispatch-only — a merge to main no longer starts a release chain by itself
Given a non-changeset PR merged to main When the merge completes Thenno release workflow runs, and a full release consists of exactly two runs (one version, one release)
Giventag-on-changeset-merge.yml deleted When the release path is exercised Then nothing depends on it, and GH_RELEASE_TOKEN is no longer referenced anywhere — cross-workflow triggering uses GITHUB_TOKEN
Given/pair-process-implement creating a changeset When it infers the bump type Then it derives patch/minor/major from the story type and commit convention, and states what it inferred so a wrong inference is visible before merge
Given the whole rewrite When the first release after it runs Then it is verified end to end on a real release (or a throwaway repo), because the only honest test of a release pipeline is a release
Business Rules
Releases are dispatched, never triggered by a merge. A merge accumulates intent (a changeset); a human decides when it ships.
Two runs per release, always — one version, one release. More runs means a chain nobody asked for.
Least privilege: GITHUB_TOKEN over a PAT. The PAT retires with the workflow that needs it.
A skipped changeset is explicit: the escape-hatch label is the only way past the check, and it leaves a trace.
An inferred bump type is stated, not assumed — the inference is a convenience, and a wrong one must be visible before it ships.
Edge Cases and Error Handling
PR that legitimately needs no changeset (docs-only, CI-only): the escape-hatch label, documented, with the reason on the PR.
Two dispatches of version.yml in a row: the second must be a no-op when no changesets remain, not an empty version bump.
Fixed-group drift: the group in .changeset/config.json lists seven packages; a new package added without joining the group would version independently. Assert the group matches the published set.
Dispatch of release.yml with a version that was never tagged: fail loudly rather than publishing something that does not exist.
Changeset written by hand with the wrong bump type: AC6's stated inference makes the mismatch visible; the human wins.
Test written first where testable: the changeset check (fixture PR payloads with and without a changeset, and with the label)
version.yml converted to workflow_dispatch-only
.changeset/config.json switched to @changesets/changelog-github (PR-linked, type-grouped)
tag-on-changeset-merge.yml deleted; no reference to GH_RELEASE_TOKEN remains anywhere
/pair-process-implement infers and states the bump type; dataset edited as source, mirror regenerated, skills:conformance green
Fixed-group assertion covering the published package set
One real release performed through the new pipeline, with the run count verified (exactly two)
DEVELOPMENT.md release section updated to the dispatch-only flow
🟡 gate checks green: lint + type + build + unit
Story Sizing and Sprint Readiness
Refined Story Points
Final Story Points: 5 (L) Confidence Level: Medium Sizing Justification: Four workflow/config changes plus a skill change — each small. The size comes from verification: a release pipeline is only honestly tested by releasing, so AC7 requires a real (or throwaway-repo) release, and a mistake here is felt as "we cannot publish". Two of the seven original criteria being already satisfied keeps this at 5 rather than 8.
Sprint Capacity Validation
Sprint Fit Assessment: Yes Development Time Estimate: ~0.75 day Testing Time Estimate: ~0.5 day, including the release run
Dependencies and Coordination
Story Dependencies
Prerequisite Stories: none — #148 / PR #333 already shipped the tooling this builds on Dependent Stories: none Shared Components: ci.yml → coordinates with #400 (adds a smoke job) and #416 (wires a check into the gate); pair-process-implement → mutex with any card touching that skill. Different lines of ci.yml, so sequencing is enough
Testing Methods: unit-testable parts (the changeset check) get fixture-driven tests; the pipeline itself is verified by performing a release — on a throwaway repository first if a real one is not due, which is the pattern github-implementation.md already uses for branch-protection work. Run count is the assertion that proves the chain is gone. Test Data Requirements: fixture PR payloads (with changeset, without, with label); a throwaway repo mirroring the fixed group.
Success Metrics
A merge to main starts nothing; a dispatch starts exactly two runs
Verification cut the scope roughly in half. Two criteria are already satisfied (release.yml dispatch-only, || echo removed) and one is a consequence of another (the PAT lives only in the workflow being deleted). Had this been implemented from the card as written, three of seven criteria would have been re-done or puzzled over.
AC7 is not ceremony: a release pipeline that has never released is untested, and the failure mode is discovered at the worst possible moment.
Team Concerns: three cards now touch ci.yml in the same period (#400, #416, this one). The lines differ, but the file does not — sequence them.
Technical Analysis
Implementation Approach
Technical Strategy: make release triggering explicit (dispatch-only), delete the merge-triggered workflow and the PAT with it, add the missing changeset check with a documented escape hatch, and switch the changelog generator to the PR-linked one.
pair-process-implement — bump-type inference, stated in output
DEVELOPMENT.md — release flow section
Data Flow: PR (+changeset) → merge accumulates → human dispatches version.yml → bump + changelog + tag → release.yml dispatched with that version → publish.
Integration Points: CI, the changeset toolchain, the implement skill, release credentials.
Design: not required
Technical Risks and Mitigation
Risk
Impact
Mitigation
Pipeline rewritten and never exercised
Discovered broken when a release is actually needed
AC7: a real or throwaway-repo release, with the two-run count asserted
PAT removed while something still needs it
Cross-workflow triggering silently stops working
AC5: assert no reference remains and the dispatch chain works in the verification release
Changeset check blocks legitimate PRs
Contributors reach for --no-verify or an unlabelled bypass
Documented escape-hatch label, visible on the PR
Fixed group drifts from the published set
A package versions independently and ships out of step
Assertion over the group vs the published packages
Bump-type inference wrong and silent
A breaking change ships as a patch
AC6: the inference is stated in the output, before merge
Summary: Add a ci.yml job that fails a PR carrying no .changeset/*.md file, unless the PR carries a documented escape-hatch label (e.g. no-changeset), in which case the job passes and the reason is visible on the PR.
Type: Feature Implementation
Description:ci.yml currently has no changeset check at all — its two .changeset mentions are only the paths-ignore on the push/pull_request triggers. This task adds the missing gate: a job that inspects the PR's changed files (or diff against origin/main) for .changeset/*.md, and short-circuits green when the PR has the escape-hatch label attached.
BLOCKING — surface before implementing:.pair/adoption/decision-log/2026-08-20-a-changeset-is-added-when-a-release-is-scheduled.md (dated after this story's last reclassification) adopts the opposite convention: a changeset is added by the release author when a release is scheduled, not per PR that changes behaviour. PRs #420/#424/#432/#437/#440 already merged with no changeset under that rule. Implementing AC1 literally (fail every PR without a changeset) would make the escape-hatch label the routine case for ordinary behaviour PRs, contradicting both the ADL and the story's own title ("changeset-per-PR"). Resolve this conflict — narrow the check's scope (e.g. only PRs that touch published packages AND declare a user-visible change in the description, or drop AC1 as superseded) — before writing the check, not after.
Acceptance Criteria:
Primary deliverable: a ci.yml job/step implementing the check + documented escape-hatch label (name and meaning recorded in RELEASE.md or CONTRIBUTING.md)
Quality standard: fixture-driven unit tests written first (failing), per the repo's Bug/Feature test-first convention
Integration requirement: runs on pull_request, does not fire on push/workflow_dispatch
Verification method: three fixture PR payloads — no changeset (red), no changeset + label (green, reason visible in log/summary), with changeset (green)
Technical Requirements:
Functionality: detect .changeset/*.md added/modified in the PR diff; detect the escape-hatch label via github.event.pull_request.labels
Performance: single fast job, no build/install beyond what's already cached
Security: no new token/permission needed (label + diff are both public PR metadata)
Compatibility: n/a
Implementation Approach:
Technical Design: a dedicated job (parallel to build/smoke), gated on github.event_name == 'pull_request', using git diff --name-only against the PR base or the GitHub API's changed-files list
Bounded Context & Modules: packages/dev-tools (if the check logic is factored into a testable script) or an inline ci.yml step for the label/diff check itself
Files to Modify/Create:
.github/workflows/ci.yml - add the changeset-check job
packages/dev-tools/src/** (or a scripts/workflows/ script) - if extracted for unit testability
Technical Standards References: .pair/knowledge/guidelines/testing/README.md (test-first); resolution of the ADL conflict above
Dependencies:
Technical: none new
Tasks: none (can start immediately, but land after conflict resolution)
Resolve the AC1/ADL-2026-08-20 conflict (see Blocking note) and record the resolution (ADL/comment on this story)
Write failing fixture tests for the check logic (no changeset / no changeset+label / with changeset)
Implement the check as a ci.yml job (or extracted script + thin CI step)
Document the escape-hatch label in RELEASE.md/CONTRIBUTING.md
Verify against a real PR without a changeset (should fail) and with the label (should pass)
Testing Strategy:
Unit Tests: fixture PR payloads (no changeset, no changeset + label, with changeset) if logic is extracted to a testable module
Integration Tests: a throwaway PR against a fork/branch exercising the real ci.yml job
Manual Testing: confirm the escape-hatch reason renders visibly in the PR (label + optionally a job-summary line)
Notes: Do not merge before the ADL conflict is resolved — implementing this as literally specified would fight the currently adopted release convention.
T-2: Rewrite version.yml — dispatch-only, direct commit + tag push, fixed-group drift assertion
Summary: Convert version.yml from its current push-to-main-on-.changeset/** trigger (which opens a release PR that a human merges, later tagged by tag-on-changeset-merge.yml) to a workflow_dispatch-only workflow that bumps the fixed group atomically, syncs root package.json, generates the changelog, commits directly, and pushes the v{X.Y.Z} tag itself — folding in the tagging responsibility that tag-on-changeset-merge.yml (deleted in T-4) currently owns.
Type: Feature Implementation
Description: Today's version.yml: trigger is push to main filtered on .changeset/** + workflow_dispatch; on a changeset it runs pnpm changeset version, syncs versions, commits chore: release v$CLI_VERSION, pushes a changeset-release/v{X}-{run} branch, and opens a PR via actions/github-script. A human merging that PR is what tag-on-changeset-merge.yml watches for to create the tag. This task removes the PR-and-merge step entirely: the workflow becomes workflow_dispatch-only, commits straight to main, and pushes the tag in the same run — so "two runs per release" (this + release.yml) holds with no intermediate human-merge step.
Acceptance Criteria:
Primary deliverable: version.yml with on: workflow_dispatch only (no push trigger); same run bumps, commits, and pushes the tag
Quality standard: idempotent — a second dispatch with no remaining changesets is a no-op (not an empty bump/tag)
Integration requirement: fixed-group bump stays atomic; a group-membership drift (new package added, not joined to the group) fails loudly
Verification method: dispatch against a branch/throwaway repo with 0 and >0 changesets; inspect the resulting commit + tag
Technical Requirements:
Functionality: pnpm changeset version + sync-version (existing script) + commit + git tag/git push --tags; skip cleanly when no changesets
Performance: single job, no new heavy steps
Security: keep using secrets.GITHUB_TOKEN (no PAT) for the push; needs contents: write (already granted)
Compatibility: same Node 20 / pnpm 10.15.0 pins as ci.yml/release.yml
Implementation Approach:
Technical Design: reuse the existing "Check for changeset files" + "Create version commits" steps; replace the branch+PR steps with a direct git push origin main and git tag v$CLI_VERSION && git push origin v$CLI_VERSION; add a fixed-group assertion step before the bump
Bounded Context & Modules: .github/workflows/version.yml; possibly packages/dev-tools for a testable "fixed-group matches published set" assertion script (reused by T-4's verification)
Tasks: none blocking start; T-4 (delete tag-on-changeset-merge.yml) should land together with or right after this, since this task is what makes that deletion safe
Add the fixed-group-vs-published-set assertion (see Open Question below on what "published set" means) as a pre-bump step
Remove the push trigger; keep workflow_dispatch
Replace the branch-creation + PR-creation steps with a direct commit to main + tag creation + push
Confirm the "no changesets" path is a true no-op (exits 0, no commit, no tag)
Dispatch against a throwaway repo/branch to confirm bump + changelog + commit + tag in one run
Testing Strategy:
Unit Tests: fixed-group assertion script, if extracted
Integration Tests: workflow dispatch dry-runs on a throwaway repo (paired with T-7)
Manual Testing: inspect the resulting commit and tag after a dispatch with real accumulated changesets
Notes:Open question — "published set" is ambiguous..changeset/config.json's fixed group lists 8 packages (@pair/pair-cli, @pair/brand, @pair/content-ops, @pair/knowledge-hub, @pair/eslint-config, @pair/prettier-config, @pair/website, @pair/ts-config), not the 7 the story text states. Of those 8, only @pair/pair-cli and @pair/eslint-config have private: false (i.e. are actually npm-publishable) — the other 6 are private: true. Confirm with the maintainer whether the assertion should cover (a) the 8-package fixed group as a monorepo-versioning invariant, or (b) the 2 actually-published packages, before writing the assertion.
T-3: Switch .changeset/config.json to @changesets/changelog-github
Summary: Replace the default "changelog": "@changesets/cli/changelog" entry in .changeset/config.json with @changesets/changelog-github, so generated CHANGELOGs link the originating PR and author per entry (type-grouping under Major/Minor/Patch headings is already the default Changesets behaviour, unaffected by this swap).
Type: Configuration
Description:.changeset/config.json currently uses the plain changelog generator (no PR links). @changesets/changelog-github needs adding as a dependency and configuring with the repo field (["@changesets/changelog-github", { "repo": "foomakers/pair" }]), and needs a GITHUB_TOKEN/GH_TOKEN with read access to PRs available in version.yml's environment at generation time (already has secrets.GITHUB_TOKEN).
Acceptance Criteria:
Primary deliverable: .changeset/config.json's changelog field set to ["@changesets/changelog-github", { "repo": "foomakers/pair" }]; package added to a relevant package.json's devDependencies
Quality standard: pnpm install succeeds; no lockfile drift beyond the new dependency
Integration requirement: version.yml's changeset-version step still runs cleanly with the new generator and existing GITHUB_TOKEN
Verification method: dispatch version.yml (or run pnpm changeset version locally with a token) against a changeset referencing a real merged PR and confirm the generated CHANGELOG entry links that PR
Performance: negligible — one extra GitHub API call per changeset at version time
Security: uses the existing GITHUB_TOKEN, no new secret
Compatibility: n/a
Implementation Approach:
Technical Design: config + dependency change only
Bounded Context & Modules: .changeset/config.json, root or packages/dev-tools devDependencies
Files to Modify/Create:
.changeset/config.json - swap changelog field
package.json (root, or wherever changesets deps live) - add @changesets/changelog-github
Technical Standards References: .pair/adoption/tech/tech-stack.md (Changesets already adopted; this task doesn't change the tool, only the changelog generator)
Summary: Delete .github/workflows/tag-on-changeset-merge.yml and confirm GH_RELEASE_TOKEN is referenced nowhere else in the repository — its only reference today is that workflow's "Create monorepo tag via REST API" step.
Type: Refactoring
Description: With T-2 making version.yml push its own tag directly, tag-on-changeset-merge.yml (which watches for a changeset-release/* PR merge and tags the merge commit via a PAT) becomes dead code. Deleting it retires the PAT per AC5/AC6's "consequence of AC4" relationship already noted in the story.
Acceptance Criteria:
Primary deliverable: .github/workflows/tag-on-changeset-merge.yml removed from the repo
Integration requirement: nothing else references this workflow (no workflow_call, no doc pointing users at merging a release PR)
Verification method: the grep above, plus a successful version.yml → release.yml dispatch chain (T-7) with no PAT anywhere in the run logs
Technical Requirements:
Functionality: n/a (deletion)
Performance: n/a
Security: removes a repo secret's last consumer — flag GH_RELEASE_TOKEN for removal from repo secrets once this merges (not part of this task's file changes, but note it for the maintainer)
Compatibility: n/a
Implementation Approach:
Technical Design: straightforward deletion, gated on T-2 having shipped (or shipping in the same PR)
Technical Standards References: story AC5/AC6, edge case "Fixed-group drift"
Dependencies:
Technical: T-2 must already push tags directly, or this deletion breaks tagging entirely
Tasks: T-2
Resource: repo-secret removal for GH_RELEASE_TOKEN is a maintainer action outside this task's scope, but should be tracked (e.g. a comment on this story or a follow-up)
Implementation Steps:
Confirm T-2's version.yml rewrite already pushes the tag directly (or land both in the same PR)
Delete tag-on-changeset-merge.yml
grep -r "GH_RELEASE_TOKEN" repo-wide to confirm zero remaining references
Note to the maintainer: remove the GH_RELEASE_TOKEN secret from repo settings (outside this task's file scope)
Testing Strategy:
Unit Tests: n/a
Integration Tests: T-7's end-to-end release run is the real test that nothing depended on the deleted workflow
Manual Testing: repo-wide grep for the token name
Notes: Land in the same PR as T-2 to avoid an interval where releases can't be tagged.
T-5: /pair-process-implement — infer and state changeset bump type
Priority: P1 | Estimated Hours: 4h | Bounded Context: Integration & Process Standardization (Development Collaboration for skill authorship, per the dataset/mirror split)
Summary: When /pair-process-implement's closing phase creates a changeset for a story's changes, infer the bump type (patch/minor/major) from the story type and commit convention, and state the inferred type in the skill's output so a wrong inference is visible before merge.
Type: Feature Implementation
Description: Today the pair-process-implement skill (dataset source: packages/knowledge-hub/dataset/.skills/process/implement/SKILL.md) contains no changeset-creation logic at all — this is net-new, not a modification of existing bump-inference code. Given AC5's ADL context (changesets are now added by the release author at release time, not per-PR — see T-1's blocking note), confirm with the maintainer whether this skill still creates a changeset per implemented story (as AC6 assumes) or whether AC6's scope changes to "the release author's workflow infers the bump type when batching changesets" instead.
Acceptance Criteria:
Primary deliverable: bump-type inference logic (patch/minor/major) added where changesets are authored, stating what was inferred and why (story type / commit convention signal)
Quality standard: dataset edited as source (packages/knowledge-hub/dataset/.skills/process/implement/SKILL.md), never the mirror directly; mirror regenerated; pnpm skills:conformance green
Integration requirement: inference is a suggestion surfaced to the human, not a silent write — a human can override before commit
Verification method: run the skill (or its dataset content review) against a fixture story of each type (bug fix → patch, feature → minor, breaking change → major) and confirm the stated inference matches
Technical Requirements:
Functionality: heuristic mapping story-type/commit-convention → bump type; output states the inference
Performance: n/a (authoring-time skill logic)
Security: n/a
Compatibility: n/a
Implementation Approach:
Technical Design: extend the implement skill's closing/PR-publish phase with a changeset-authoring step that derives and states the bump type
Bounded Context & Modules: packages/knowledge-hub/dataset/.skills/process/implement/SKILL.md (source); mirrored to .claude/skills/pair-process-implement/SKILL.md and the other 5 target directories
(generated) all mirror targets, via the existing distribution/regeneration tooling
Technical Standards References: .pair/adoption/tech/architecture.md § Skills Distribution (dataset-as-source, mirrors regenerated, never hand-edited)
Dependencies:
Technical: none new
Tasks: none — independent of T-1..T-4
Resource: mutex with any other card touching pair-process-implement (per this story's own Shared Components note)
Implementation Steps:
Confirm scope against the AC1/ADL-2026-08-20 conflict (does this skill still author a changeset per story, or does inference move to the release-author flow?)
Edit the dataset source SKILL.md to add the bump-type inference + stated-output step
Regenerate mirrors via the existing distribution tooling
Run pnpm skills:conformance and confirm green
Validate against one fixture story per bump type
Testing Strategy:
Unit Tests: n/a (skill content, not code) — conformance check is the automated gate
Integration Tests: pnpm skills:conformance
Manual Testing: dry-run the skill's changeset-authoring step against fixture stories of each type
Notes: Scope depends on resolving the same ADL conflict flagged in T-1 — do not implement in isolation from that resolution.
T-6: Update RELEASE.md (and DEVELOPMENT.md pointer) to the two-workflow dispatch-only flow
Summary: Rewrite RELEASE.md's "Overview" diagram, "Creating a Release" steps, and "Workflows" table to describe the new two-workflow (version.yml → release.yml) dispatch-only flow, removing all mention of the release PR and tag-on-changeset-merge.yml. DEVELOPMENT.md only points at RELEASE.md for the release process, so the substantive rewrite happens there.
Type: Documentation
Description:RELEASE.md currently documents the pre-story 4-workflow chain (pnpm changeset add → merge → version.yml opens a PR → merging that PR triggers tag-on-changeset-merge.yml → tag push triggers release.yml). This entire document needs rewriting to reflect: dispatch version.yml manually → it commits + tags directly on main → dispatch release.yml with that version. The DoD checklist item names DEVELOPMENT.md, but that file only links to RELEASE.md — the actual content to update lives there.
Acceptance Criteria:
Primary deliverable: RELEASE.md's Overview diagram, "Creating a Release" steps 2-4, and "Workflows" table rewritten for the two-workflow dispatch-only model; DEVELOPMENT.md's pointer sentence checked for accuracy
Quality standard: no references remain to a "version PR", "Tag workflow", or the release-PR merge step
Integration requirement: content matches the actual version.yml/release.yml behaviour after T-2/T-3/T-4 land
Verification method: manual read-through matched against the shipped workflow files
Technical Requirements:
Functionality: n/a (documentation)
Performance: n/a
Security: n/a
Compatibility: n/a
Implementation Approach:
Technical Design: rewrite in place
Bounded Context & Modules: repo root docs
Files to Modify/Create:
RELEASE.md - rewrite Overview, Creating a Release, Workflows table
DEVELOPMENT.md - verify its RELEASE.md pointer still reads correctly
Technical Standards References: none — plain docs, but must reflect the ADL 2026-08-20 changeset-timing convention too (step 1's "when" language is already correct there and should not regress)
Dependencies:
Technical: none
Tasks: T-2, T-3, T-4 must have landed (or be in final form) so the doc describes real behaviour, not the plan
Resource: none
Implementation Steps:
Rewrite the Overview ASCII diagram to two workflows
Rewrite "Creating a Release" steps 2-4 (dispatch version.yml, then dispatch release.yml — no PR-merge step)
Update the "Workflows" table (remove the tag-on-changeset-merge.yml row)
Cross-check against T-2/T-3/T-4's actual shipped files
Confirm DEVELOPMENT.md's pointer sentence still makes sense
Testing Strategy:
Unit Tests: n/a
Integration Tests: pnpm docs:staleness if it covers this file
Manual Testing: read-through against the real workflow YAML
Notes: None.
T-7: Perform and verify one real release through the new pipeline (exactly two runs)
Summary: Exercise the rewritten pipeline end to end — on a throwaway repo mirroring the fixed group if a real release isn't due, otherwise a real one — and verify exactly two workflow runs occur (one version, one release) with no PAT involved anywhere.
Type: Testing
Description: AC7 exists because a release pipeline is only honestly tested by releasing. This task dispatches version.yml, confirms the commit+tag land correctly, dispatches release.yml with that version, confirms the GitHub Release + artifacts are produced, and confirms the Actions run list shows exactly two runs for the release (no tag-on-changeset-merge.yml run, no extra build triggered by the version commit beyond what's expected).
Acceptance Criteria:
Primary deliverable: a completed release (real or throwaway-repo) through the new pipeline
Quality standard: exactly two workflow runs attributable to the release (version, release)
Integration requirement: release.yml dispatched with a version that was actually tagged by the preceding version.yml run succeeds; a version that was never tagged fails loudly (edge case check)
Verification method: Actions run history for the release window, cross-checked against the two expected runs
Technical Requirements:
Functionality: full pipeline correctness
Performance: n/a
Security: confirm no GH_RELEASE_TOKEN/PAT appears in any run's logs or permissions: block
Compatibility: n/a
Implementation Approach:
Technical Design: use a throwaway repo cloned with the fixed-group structure if no real release is due yet (pattern already used for branch-protection work per github-implementation.md); otherwise perform the real release
Bounded Context & Modules: GitHub Actions run history, version.yml, release.yml
Files to Modify/Create: none (verification task; may add notes to RELEASE.md if T-6 needs a correction discovered here)
Technical Standards References: story AC7, github-implementation.md's throwaway-repo pattern
Dependencies:
Technical: T-2, T-3, T-4 fully landed
Tasks: T-2, T-3, T-4 (and ideally T-6, so the doc matches what's verified)
Resource: dispatch permissions on the target repo (real or throwaway)
Implementation Steps:
Accumulate or write test changesets covering the fixed group
Dispatch version.yml; confirm commit + tag on main
Dispatch release.yml with the resulting version; confirm GitHub Release + artifacts
Count workflow runs in the Actions history for the window — must be exactly 2
Attempt release.yml dispatch with an untagged version — confirm it fails loudly (edge case)
Attempt a second version.yml dispatch with no remaining changesets — confirm no-op (edge case)
Testing Strategy:
Unit Tests: n/a
Integration Tests: this task is itself the integration test
Notes: This is the story's real proof of done — do not mark the story complete without this task's evidence recorded (run URLs/IDs) in the PR or a comment on this issue.
Story Statement
As a Pair maintainer
I want the release pipeline reduced to changeset-per-PR plus a two-workflow, dispatch-only model (
version.yml→release.yml) with open-source changelogsSo that releases are maintainer-controlled and reproducible, and exactly two workflow runs happen per release instead of a chain triggered by merges
Where:
.github/workflows/{ci,version,release,tag-on-changeset-merge}.yml,.changeset/config.json, and the/pair-process-implementskill (changeset bump-type inference).Epic Context
Parent Epic: none — standalone (maintainer decision, 2026-08-05). It was filed under #68, an epic of the frozen Knowledge Service initiative, while its subject belonged to #211 (release management), now closed: orphaned on both sides. It is real work and does not need an epic to exist.
Status: Refined
Priority: P1 (Should-Have) — the pipeline is the path every release takes
Builds on: #148 / PR #333 (release scripts + tested
determine-version, shipped)Classification
risk:yellow· cost: green (not projected —Active: riskonly)Matrix — per dimension
packages/dev-tools(owns repo-wide CI gates + release-pipeline logic, incl.determine-versioninvoked byrelease.yml) andpackages/knowledge-hub(dataset source of thepair-process-implementskill mirror) — both listed Low.changeset/config.jsonare shared CI/release infra touched on every PR. The skill change is a dataset↔mirror pair (change-risk.dataset-mirror-pairsoverride collapses it to one module), but the workflow/config changes remain separate, genuinely-shared modules — still "touches multiple modules or shared code"Integration & Process Standardization(Supporting) — distribution/release process. The newerDevelopment Tooling Standards(Generic) subdomain covers lint/format/TypeScript/markdown/brand only, not release/CI, so it does not apply hereGITHUB_TOKENreduces the permission surface, but any error in a release workflow's token wiring is a publishing-authority mistakeTier = yellow (max rule).
tier-resolution.default-artifact-downgradechecked and does not apply: Change/diff risk and Security relevance are yellow, and that override only downgrades to green when every present yellow is confined to Service/domain-criticality and/or Business-impact. Gate checks for 🟡: lint + type + build + unit.Reclassified 2026-08-14 against corrected adoption inputs (
tech/risk-matrix.mdCriticality Table +tier-resolution.default-artifact-downgradeoverride, both added after this story's original refinement, 2026-08-05): Service/domain criticality moves from yellow (KB default) to green. Overall tier is unchanged at yellow — Change/diff risk and Security relevance remain genuinely observed, non-artifact yellows, so the new override does not fire.Context
Split from #148: the tooling slice shipped (PR #333, #148 closed); this story carries the remaining pipeline rewrite.
State verified against the real workflows (2026-08-05)
The original AC set asked to "confirm each still applies". Confirmed, and half of them are already done — the story shrinks accordingly:
ci.yml, with escape-hatch labelci.ymlmentions.changesettwice, and both are thepaths-ignoreon its triggers — there is no checkversion.ymldispatch-only + PR-linked, type-grouped changelogsversion.ymltriggers onpushtomainfiltered to.changeset/**, notworkflow_dispatch;.changeset/config.jsonuses the default@changesets/cli/changelog, not@changesets/changelog-githubrelease.ymldispatch-onlyon: workflow_dispatchwith aversioninput, no tag-push or release-event triggertag-on-changeset-merge.yml|| echofallbacks masking failures inci.ymlGH_RELEASE_TOKEN)tag-on-changeset-merge.yml. Deleting that workflow removes the PAT/implementinfers the bump type when creating the changesetpair-process-implementSo the work is: the missing CI check, making
version.ymldispatch-only with proper changelogs, deleting one workflow (which retires the PAT), and one skill change.Acceptance Criteria
Functional Requirements
Given-When-Then Format:
Given a pull request with no
.changeset/*.mdWhen CI runs
Then the changeset check fails — unless the PR carries the documented escape-hatch label, in which case it passes with that reason visible
Given accumulated changesets on
mainWhen
version.ymlis dispatched manuallyThen it bumps the fixed-group package versions atomically, syncs the root
package.json, generates PR-linked, type-grouped CHANGELOGs, commits, and pushes thev{X.Y.Z}tagGiven
version.ymlWhen its triggers are inspected
Then it is
workflow_dispatch-only — a merge tomainno longer starts a release chain by itselfGiven a non-changeset PR merged to
mainWhen the merge completes
Then no release workflow runs, and a full release consists of exactly two runs (one version, one release)
Given
tag-on-changeset-merge.ymldeletedWhen the release path is exercised
Then nothing depends on it, and
GH_RELEASE_TOKENis no longer referenced anywhere — cross-workflow triggering usesGITHUB_TOKENGiven
/pair-process-implementcreating a changesetWhen it infers the bump type
Then it derives patch/minor/major from the story type and commit convention, and states what it inferred so a wrong inference is visible before merge
Given the whole rewrite
When the first release after it runs
Then it is verified end to end on a real release (or a throwaway repo), because the only honest test of a release pipeline is a release
Business Rules
version, onerelease. More runs means a chain nobody asked for.GITHUB_TOKENover a PAT. The PAT retires with the workflow that needs it.Edge Cases and Error Handling
version.ymlin a row: the second must be a no-op when no changesets remain, not an empty version bump..changeset/config.jsonlists seven packages; a new package added without joining the group would version independently. Assert the group matches the published set.release.ymlwith a version that was never tagged: fail loudly rather than publishing something that does not exist.Definition of Done Checklist
version.ymlconverted toworkflow_dispatch-only.changeset/config.jsonswitched to@changesets/changelog-github(PR-linked, type-grouped)tag-on-changeset-merge.ymldeleted; no reference toGH_RELEASE_TOKENremains anywhere/pair-process-implementinfers and states the bump type; dataset edited as source, mirror regenerated,skills:conformancegreenDEVELOPMENT.mdrelease section updated to the dispatch-only flowStory Sizing and Sprint Readiness
Refined Story Points
Final Story Points: 5 (L)
Confidence Level: Medium
Sizing Justification: Four workflow/config changes plus a skill change — each small. The size comes from verification: a release pipeline is only honestly tested by releasing, so AC7 requires a real (or throwaway-repo) release, and a mistake here is felt as "we cannot publish". Two of the seven original criteria being already satisfied keeps this at 5 rather than 8.
Sprint Capacity Validation
Sprint Fit Assessment: Yes
Development Time Estimate: ~0.75 day
Testing Time Estimate: ~0.5 day, including the release run
Dependencies and Coordination
Story Dependencies
Prerequisite Stories: none — #148 / PR #333 already shipped the tooling this builds on
Dependent Stories: none
Shared Components:
ci.yml→ coordinates with #400 (adds asmokejob) and #416 (wires a check into the gate);pair-process-implement→ mutex with any card touching that skill. Different lines ofci.yml, so sequencing is enoughExternal Dependencies
Related: #148 / PR #333 (tooling slice) · #211 (closed: the release-management epic this thematically belonged to) · #68 (former parent, frozen initiative) ·
@changesets/changelog-githubValidation and Testing Strategy
Acceptance Testing Approach
Testing Methods: unit-testable parts (the changeset check) get fixture-driven tests; the pipeline itself is verified by performing a release — on a throwaway repository first if a real one is not due, which is the pattern
github-implementation.mdalready uses for branch-protection work. Run count is the assertion that proves the chain is gone.Test Data Requirements: fixture PR payloads (with changeset, without, with label); a throwaway repo mirroring the fixed group.
Success Metrics
mainstarts nothing; a dispatch starts exactly two runsNotes and Additional Context
Refinement Session Insights (2026-08-05):
release.ymldispatch-only,|| echoremoved) and one is a consequence of another (the PAT lives only in the workflow being deleted). Had this been implemented from the card as written, three of seven criteria would have been re-done or puzzled over.Team Concerns: three cards now touch
ci.ymlin the same period (#400, #416, this one). The lines differ, but the file does not — sequence them.Technical Analysis
Implementation Approach
Technical Strategy: make release triggering explicit (dispatch-only), delete the merge-triggered workflow and the PAT with it, add the missing changeset check with a documented escape hatch, and switch the changelog generator to the PR-linked one.
Key Components:
ci.yml— changeset-per-PR check + escape-hatch labelversion.yml—workflow_dispatch-only, atomic fixed-group bump, tag pushrelease.yml— unchanged (already dispatch-only)tag-on-changeset-merge.yml— deleted (retiresGH_RELEASE_TOKEN).changeset/config.json—@changesets/changelog-githubpair-process-implement— bump-type inference, stated in outputDEVELOPMENT.md— release flow sectionData Flow: PR (+changeset) → merge accumulates → human dispatches
version.yml→ bump + changelog + tag →release.ymldispatched with that version → publish.Integration Points: CI, the changeset toolchain, the implement skill, release credentials.
Design: not required
Technical Risks and Mitigation
--no-verifyor an unlabelled bypassci.ymlTask Breakdown
ci.yml)version.yml—workflow_dispatch-only, direct commit + tag push, fixed-group drift assertion.changeset/config.jsonto@changesets/changelog-githubtag-on-changeset-merge.yml; remove allGH_RELEASE_TOKENreferences/pair-process-implement— infer and state changeset bump typeRELEASE.md(andDEVELOPMENT.mdpointer) to the two-workflow dispatch-only flowDependency Graph
AC Coverage
T-1: Changeset-per-PR CI check with escape-hatch label
Priority: P0 | Estimated Hours: 4h | Bounded Context: Integration & Process Standardization
Summary: Add a
ci.ymljob that fails a PR carrying no.changeset/*.mdfile, unless the PR carries a documented escape-hatch label (e.g.no-changeset), in which case the job passes and the reason is visible on the PR.Type: Feature Implementation
Description:
ci.ymlcurrently has no changeset check at all — its two.changesetmentions are only thepaths-ignoreon thepush/pull_requesttriggers. This task adds the missing gate: a job that inspects the PR's changed files (or diff againstorigin/main) for.changeset/*.md, and short-circuits green when the PR has the escape-hatch label attached.BLOCKING — surface before implementing:
.pair/adoption/decision-log/2026-08-20-a-changeset-is-added-when-a-release-is-scheduled.md(dated after this story's last reclassification) adopts the opposite convention: a changeset is added by the release author when a release is scheduled, not per PR that changes behaviour. PRs #420/#424/#432/#437/#440 already merged with no changeset under that rule. Implementing AC1 literally (fail every PR without a changeset) would make the escape-hatch label the routine case for ordinary behaviour PRs, contradicting both the ADL and the story's own title ("changeset-per-PR"). Resolve this conflict — narrow the check's scope (e.g. only PRs that touch published packages AND declare a user-visible change in the description, or drop AC1 as superseded) — before writing the check, not after.Acceptance Criteria:
ci.ymljob/step implementing the check + documented escape-hatch label (name and meaning recorded inRELEASE.mdorCONTRIBUTING.md)pull_request, does not fire onpush/workflow_dispatchTechnical Requirements:
.changeset/*.mdadded/modified in the PR diff; detect the escape-hatch label viagithub.event.pull_request.labelsImplementation Approach:
build/smoke), gated ongithub.event_name == 'pull_request', usinggit diff --name-onlyagainst the PR base or the GitHub API's changed-files listpackages/dev-tools(if the check logic is factored into a testable script) or an inlineci.ymlstep for the label/diff check itself.github/workflows/ci.yml- add the changeset-check jobpackages/dev-tools/src/**(or ascripts/workflows/script) - if extracted for unit testability.pair/knowledge/guidelines/testing/README.md(test-first); resolution of the ADL conflict aboveDependencies:
ci.ymlper this story's Dependencies section — sequence, don't parallel-mergeImplementation Steps:
ci.ymljob (or extracted script + thin CI step)RELEASE.md/CONTRIBUTING.mdTesting Strategy:
ci.ymljobNotes: Do not merge before the ADL conflict is resolved — implementing this as literally specified would fight the currently adopted release convention.
T-2: Rewrite
version.yml— dispatch-only, direct commit + tag push, fixed-group drift assertionPriority: P0 | Estimated Hours: 6h | Bounded Context: Integration & Process Standardization
Summary: Convert
version.ymlfrom its currentpush-to-main-on-.changeset/**trigger (which opens a release PR that a human merges, later tagged bytag-on-changeset-merge.yml) to aworkflow_dispatch-only workflow that bumps the fixed group atomically, syncs rootpackage.json, generates the changelog, commits directly, and pushes thev{X.Y.Z}tag itself — folding in the tagging responsibility thattag-on-changeset-merge.yml(deleted in T-4) currently owns.Type: Feature Implementation
Description: Today's
version.yml: trigger ispushtomainfiltered on.changeset/**+workflow_dispatch; on a changeset it runspnpm changeset version, syncs versions, commitschore: release v$CLI_VERSION, pushes achangeset-release/v{X}-{run}branch, and opens a PR viaactions/github-script. A human merging that PR is whattag-on-changeset-merge.ymlwatches for to create the tag. This task removes the PR-and-merge step entirely: the workflow becomesworkflow_dispatch-only, commits straight tomain, and pushes the tag in the same run — so "two runs per release" (this +release.yml) holds with no intermediate human-merge step.Acceptance Criteria:
version.ymlwithon: workflow_dispatchonly (nopushtrigger); same run bumps, commits, and pushes the tagTechnical Requirements:
pnpm changeset version+sync-version(existing script) + commit +git tag/git push --tags; skip cleanly when no changesetssecrets.GITHUB_TOKEN(no PAT) for the push; needscontents: write(already granted)ci.yml/release.ymlImplementation Approach:
git push origin mainandgit tag v$CLI_VERSION && git push origin v$CLI_VERSION; add a fixed-group assertion step before the bump.github/workflows/version.yml; possiblypackages/dev-toolsfor a testable "fixed-group matches published set" assertion script (reused by T-4's verification).github/workflows/version.yml- trigger + direct-commit-and-tag rewritepackages/dev-tools/src/**(optional) - fixed-group drift assertion, unit-testable.pair/adoption/tech/architecture.md§ Tooling Package Boundaries (dev-tools owns release-pipeline logic)Dependencies:
pnpm changeset version, existingsync-versionscripttag-on-changeset-merge.yml) should land together with or right after this, since this task is what makes that deletion safemainneedscontents: writealready present in the workflow'spermissions:blockImplementation Steps:
pushtrigger; keepworkflow_dispatchmain+ tag creation + pushTesting Strategy:
Notes: Open question — "published set" is ambiguous.
.changeset/config.json's fixed group lists 8 packages (@pair/pair-cli,@pair/brand,@pair/content-ops,@pair/knowledge-hub,@pair/eslint-config,@pair/prettier-config,@pair/website,@pair/ts-config), not the 7 the story text states. Of those 8, only@pair/pair-cliand@pair/eslint-confighaveprivate: false(i.e. are actually npm-publishable) — the other 6 areprivate: true. Confirm with the maintainer whether the assertion should cover (a) the 8-package fixed group as a monorepo-versioning invariant, or (b) the 2 actually-published packages, before writing the assertion.T-3: Switch
.changeset/config.jsonto@changesets/changelog-githubPriority: P1 | Estimated Hours: 2h | Bounded Context: Integration & Process Standardization
Summary: Replace the default
"changelog": "@changesets/cli/changelog"entry in.changeset/config.jsonwith@changesets/changelog-github, so generated CHANGELOGs link the originating PR and author per entry (type-grouping under Major/Minor/Patch headings is already the default Changesets behaviour, unaffected by this swap).Type: Configuration
Description:
.changeset/config.jsoncurrently uses the plain changelog generator (no PR links).@changesets/changelog-githubneeds adding as a dependency and configuring with therepofield (["@changesets/changelog-github", { "repo": "foomakers/pair" }]), and needs aGITHUB_TOKEN/GH_TOKENwith read access to PRs available inversion.yml's environment at generation time (already hassecrets.GITHUB_TOKEN).Acceptance Criteria:
.changeset/config.json'schangelogfield set to["@changesets/changelog-github", { "repo": "foomakers/pair" }]; package added to a relevantpackage.json's devDependenciespnpm installsucceeds; no lockfile drift beyond the new dependencyversion.yml's changeset-version step still runs cleanly with the new generator and existingGITHUB_TOKENversion.yml(or runpnpm changeset versionlocally with a token) against a changeset referencing a real merged PR and confirm the generated CHANGELOG entry links that PRTechnical Requirements:
GITHUB_TOKEN, no new secretImplementation Approach:
.changeset/config.json, root orpackages/dev-toolsdevDependencies.changeset/config.json- swapchangelogfieldpackage.json(root, or wherever changesets deps live) - add@changesets/changelog-github.pair/adoption/tech/tech-stack.md(Changesets already adopted; this task doesn't change the tool, only the changelog generator)Dependencies:
@changesets/changelog-githubnpm packageImplementation Steps:
pnpm add -D @changesets/changelog-githubat the appropriate workspace root.changeset/config.json'schangelogfield with therepooptionpnpm changeset versionlocally (with aGITHUB_TOKEN) against an existing changeset to confirm PR-linked outputversion.yml's environment provides a token with sufficient scopeTesting Strategy:
Notes: None.
T-4: Delete
tag-on-changeset-merge.yml; remove allGH_RELEASE_TOKENreferencesPriority: P0 | Estimated Hours: 2h | Bounded Context: Integration & Process Standardization
Summary: Delete
.github/workflows/tag-on-changeset-merge.ymland confirmGH_RELEASE_TOKENis referenced nowhere else in the repository — its only reference today is that workflow's "Create monorepo tag via REST API" step.Type: Refactoring
Description: With T-2 making
version.ymlpush its own tag directly,tag-on-changeset-merge.yml(which watches for achangeset-release/*PR merge and tags the merge commit via a PAT) becomes dead code. Deleting it retires the PAT per AC5/AC6's "consequence of AC4" relationship already noted in the story.Acceptance Criteria:
.github/workflows/tag-on-changeset-merge.ymlremoved from the repogrep -r GH_RELEASE_TOKEN(repo-wide, excluding.git) returns zero matchesworkflow_call, no doc pointing users at merging a release PR)version.yml→release.ymldispatch chain (T-7) with no PAT anywhere in the run logsTechnical Requirements:
GH_RELEASE_TOKENfor removal from repo secrets once this merges (not part of this task's file changes, but note it for the maintainer)Implementation Approach:
.github/workflows/.github/workflows/tag-on-changeset-merge.yml- deleteDependencies:
GH_RELEASE_TOKENis a maintainer action outside this task's scope, but should be tracked (e.g. a comment on this story or a follow-up)Implementation Steps:
version.ymlrewrite already pushes the tag directly (or land both in the same PR)tag-on-changeset-merge.ymlgrep -r "GH_RELEASE_TOKEN"repo-wide to confirm zero remaining referencesGH_RELEASE_TOKENsecret from repo settings (outside this task's file scope)Testing Strategy:
Notes: Land in the same PR as T-2 to avoid an interval where releases can't be tagged.
T-5:
/pair-process-implement— infer and state changeset bump typePriority: P1 | Estimated Hours: 4h | Bounded Context: Integration & Process Standardization (Development Collaboration for skill authorship, per the dataset/mirror split)
Summary: When
/pair-process-implement's closing phase creates a changeset for a story's changes, infer the bump type (patch/minor/major) from the story type and commit convention, and state the inferred type in the skill's output so a wrong inference is visible before merge.Type: Feature Implementation
Description: Today the
pair-process-implementskill (dataset source:packages/knowledge-hub/dataset/.skills/process/implement/SKILL.md) contains no changeset-creation logic at all — this is net-new, not a modification of existing bump-inference code. Given AC5's ADL context (changesets are now added by the release author at release time, not per-PR — see T-1's blocking note), confirm with the maintainer whether this skill still creates a changeset per implemented story (as AC6 assumes) or whether AC6's scope changes to "the release author's workflow infers the bump type when batching changesets" instead.Acceptance Criteria:
packages/knowledge-hub/dataset/.skills/process/implement/SKILL.md), never the mirror directly; mirror regenerated;pnpm skills:conformancegreenTechnical Requirements:
Implementation Approach:
packages/knowledge-hub/dataset/.skills/process/implement/SKILL.md(source); mirrored to.claude/skills/pair-process-implement/SKILL.mdand the other 5 target directoriespackages/knowledge-hub/dataset/.skills/process/implement/SKILL.md- add bump-type inference step.pair/adoption/tech/architecture.md§ Skills Distribution (dataset-as-source, mirrors regenerated, never hand-edited)Dependencies:
pair-process-implement(per this story's own Shared Components note)Implementation Steps:
pnpm skills:conformanceand confirm greenTesting Strategy:
pnpm skills:conformanceNotes: Scope depends on resolving the same ADL conflict flagged in T-1 — do not implement in isolation from that resolution.
T-6: Update
RELEASE.md(andDEVELOPMENT.mdpointer) to the two-workflow dispatch-only flowPriority: P1 | Estimated Hours: 2h | Bounded Context: Integration & Process Standardization
Summary: Rewrite
RELEASE.md's "Overview" diagram, "Creating a Release" steps, and "Workflows" table to describe the new two-workflow (version.yml→release.yml) dispatch-only flow, removing all mention of the release PR andtag-on-changeset-merge.yml.DEVELOPMENT.mdonly points atRELEASE.mdfor the release process, so the substantive rewrite happens there.Type: Documentation
Description:
RELEASE.mdcurrently documents the pre-story 4-workflow chain (pnpm changeset add→ merge →version.ymlopens a PR → merging that PR triggerstag-on-changeset-merge.yml→ tag push triggersrelease.yml). This entire document needs rewriting to reflect: dispatchversion.ymlmanually → it commits + tags directly onmain→ dispatchrelease.ymlwith that version. The DoD checklist item namesDEVELOPMENT.md, but that file only links toRELEASE.md— the actual content to update lives there.Acceptance Criteria:
RELEASE.md's Overview diagram, "Creating a Release" steps 2-4, and "Workflows" table rewritten for the two-workflow dispatch-only model;DEVELOPMENT.md's pointer sentence checked for accuracyversion.yml/release.ymlbehaviour after T-2/T-3/T-4 landTechnical Requirements:
Implementation Approach:
RELEASE.md- rewrite Overview, Creating a Release, Workflows tableDEVELOPMENT.md- verify itsRELEASE.mdpointer still reads correctlyDependencies:
Implementation Steps:
version.yml, then dispatchrelease.yml— no PR-merge step)tag-on-changeset-merge.ymlrow)DEVELOPMENT.md's pointer sentence still makes senseTesting Strategy:
pnpm docs:stalenessif it covers this fileNotes: None.
T-7: Perform and verify one real release through the new pipeline (exactly two runs)
Priority: P0 | Estimated Hours: 3h | Bounded Context: Integration & Process Standardization
Summary: Exercise the rewritten pipeline end to end — on a throwaway repo mirroring the fixed group if a real release isn't due, otherwise a real one — and verify exactly two workflow runs occur (one
version, onerelease) with no PAT involved anywhere.Type: Testing
Description: AC7 exists because a release pipeline is only honestly tested by releasing. This task dispatches
version.yml, confirms the commit+tag land correctly, dispatchesrelease.ymlwith that version, confirms the GitHub Release + artifacts are produced, and confirms the Actions run list shows exactly two runs for the release (notag-on-changeset-merge.ymlrun, no extrabuildtriggered by the version commit beyond what's expected).Acceptance Criteria:
version,release)release.ymldispatched with a version that was actually tagged by the precedingversion.ymlrun succeeds; a version that was never tagged fails loudly (edge case check)Technical Requirements:
GH_RELEASE_TOKEN/PAT appears in any run's logs orpermissions:blockImplementation Approach:
github-implementation.md); otherwise perform the real releaseversion.yml,release.ymlRELEASE.mdif T-6 needs a correction discovered here)github-implementation.md's throwaway-repo patternDependencies:
Implementation Steps:
version.yml; confirm commit + tag onmainrelease.ymlwith the resulting version; confirm GitHub Release + artifactsrelease.ymldispatch with an untagged version — confirm it fails loudly (edge case)version.ymldispatch with no remaining changesets — confirm no-op (edge case)Testing Strategy:
Notes: This is the story's real proof of done — do not mark the story complete without this task's evidence recorded (run URLs/IDs) in the PR or a comment on this issue.