<!-- source: openspec/changes/linear-as-agent-control-plane-openspec/verification.md -->

---
audience:
  - executor
---
# Verification — linear-agent-control-plane

## Spec alignment

Done means three capability specs in `openspec/current/` carry amendments that reflect the new managed artifacts. `openspec/current/ci-cd.md` must describe the two new workflow jobs (`sync-agent-guidance` and `sync-change-block`), their triggers, path filters, required secrets, and the hard-failure contract for missing RAP-id. `openspec/current/tooling.md` must document `@rapoport/openspec-linear-sync` as a private tool package: its CLI surface (`sync-guidance`, `sync-change`), exit-code contract, and the Handlebars template path. A new file `openspec/current/agent-guidance.md` must exist and describe the Agent Guidance artifact lifecycle: `docs/linear-agent-guidance.md` as canonical source, the five required sections, the 8 KB size gate, and CI as the sole writer to the Linear field.

At archive time the change-folder's `specs/` subfolder must contain diffs against all three files above. No amendments to `openspec/current/auth-session.md` or any product-domain spec are expected; the scope is purely infrastructure and tooling.

## Hallucination risks

- MUST appear: `tools/openspec-to-linear-sync/src/markers.ts` — the injector lives in its own module per the design contract; a diff that folds marker logic into `cli.ts` or `render.ts` violates the layout.
- MUST appear: `<!-- openspec:start` and `<!-- openspec:end -->` as literal strings in `tools/openspec-to-linear-sync/templates/change-block.md.hbs`.
- MUST appear: `LINEAR_API_KEY` referenced via `process.env.LINEAR_API_KEY` in `tools/openspec-to-linear-sync/src/linear.ts` — not hardcoded, not sourced from a config file.
- MUST appear: `paths: ['openspec/changes/**']` in `.github/workflows/openspec-linear-sync.yml` — the path filter is load-bearing; omitting it causes the job to run on every PR.
- MUST NOT appear: any `fs.writeFileSync` or file-mutation call inside `tools/openspec-to-linear-sync/` — the tool reads the repo and writes to Linear only; it must not modify local files.
- MUST NOT appear: `bidirectional` or any Linear webhook handler — bidirectional sync is explicitly out of scope; a diff introducing a webhook endpoint is scope drift.
- MUST NOT appear: `openspec/changes/` files modified by the sync tool at runtime — the tool is read-only with respect to the repo.
- MUST NOT appear: `@linear/sdk` imported in any `apps/` or `packages/` path — the SDK is a `tools/`-only dependency.

## Pattern references

- `tools/openspec-to-linear-sync/src/rap-id.ts` should mirror the shape of any existing single-responsibility extractor in `tools/` (e.g. a slug or id parser) — small module, one exported function, typed error thrown on failure, no side effects.
- `.github/workflows/openspec-linear-sync.yml` should mirror the structure of the nearest existing workflow in `.github/workflows/` that uses `pnpm --filter` — same `setup-node` / `pnpm install --filter` / run step sequence.
- `apps/studio/e2e/openspec-linear-sync.spec.ts` should mirror other fixture-driven e2e specs in `apps/studio/e2e/` — fixture data in a `__fixtures__/` subdirectory, `describe`/`it` blocks, no network calls in unit paths.
- `docs/linear-agent-guidance.md` front-matter (`version`, `last_synced`) should mirror the front-matter convention used in other `docs/` managed artifacts in the repo.

## Acceptance

- Done when: `[ -f docs/linear-agent-guidance.md ]`
- Done when: `grep -c '## Naming\|## OpenSpec\|## Acceptance\|## Workflow' docs/linear-agent-guidance.md` returns `4`
- Done when: `[ -f tools/openspec-to-linear-sync/templates/change-block.md.hbs ]`
- Done when: `grep -c 'openspec:start\|openspec:end' tools/openspec-to-linear-sync/templates/change-block.md.hbs` returns `2`
- Done when: `[ -f .github/workflows/openspec-linear-sync.yml ]`
- Done when: `grep -c 'openspec/changes/\*\*' .github/workflows/openspec-linear-sync.yml` returns `1`
- Done when: `pnpm --filter @rapoport/openspec-linear-sync build`
- Done when: `pnpm --filter @rapoport/openspec-linear-sync test`
- Reviewer confirms: a test PR with branch `pavel/rap-9999-smoke-test` touching a file under `openspec/changes/` causes the linked Linear issue description to contain exactly one `<!-- openspec:start -->…<!-- openspec:end -->` block within 60 s of the PR being opened, and a second push to the same PR replaces the block in-place with no duplicate.
- Reviewer confirms: a test PR with no RAP-id in title or branch produces a failed GitHub Actions check with a human-readable error message identifying the missing RAP-id as the cause.
- Done when: `pnpm --filter @rapoport/openspec-linear-sync build`
