--- name: apm-spec-guardian description: >- Use this skill to run a four-panel adversarial advisory review on any pull request that touches the OpenAPM specification artifact (docs/src/content/docs/specs/openapm-*.md), its inline / sidecar JSON Schemas (docs/src/content/docs/specs/schemas/*.schema.json), or the conformance fixture seed (tests/fixtures/spec-conformance/**). The panel fans out to four spec-ecosystem reviewers (swagger-openapi-editor, oci-distribution-editor, pkgmgr-registry-contract-editor, w3c-tag-architect), each running in its own agent thread, and a spec-editor synthesizer that produces a fold-now / defer-v0.1.1 / defer-v0.2 / reject list plus a ship decision keyed off a 1..10 shocked_meter scale. The orchestrator is the sole writer to the PR: ONE consolidated comment, no verdict labels, no merge gating. The panel is advisory -- it surfaces findings, prioritizes folds, and renders a ship recommendation that the maintainer weighs. --- # APM Spec Guardian -- Four-Panel Advisory Review for OpenAPM This skill institutionalizes the two-round adversarial spec review that produced OpenAPM v0.1 by hand. The panel is FAN-OUT + SYNTHESIZER. Each panelist runs in its own agent thread (via the `task` tool) and returns JSON matching `assets/panelist-return-schema.json`. The orchestrator schema-validates each return, hands all returns to the `spec-editor-synthesizer` (also a task thread, returns JSON matching `assets/synthesizer-return-schema.json`), runs the linter checklist in `assets/linter-checklist.md`, then renders ONE comment from `assets/comment-template.md`. This skill is ADVISORY by design. It does not compute a binary verdict, it does not apply verdict labels, and it does not gate merge. The panel surfaces findings; the maintainer ships. ## Activation scope This skill activates ONLY when the PR diff touches at least one of: - `docs/src/content/docs/specs/openapm-*.md` (the normative spec artifact, current and future versions) - `docs/src/content/docs/specs/schemas/*.schema.json` (sidecar JSON Schemas, if/when the inline Appendix-A schemas are extracted to files) - `tests/fixtures/spec-conformance/**` (the conformance fixture seed) Edits to any OTHER documentation page MUST NOT trigger this skill. The maintainer's general `docs-sync` skill covers those. ## Architecture invariants - **Advisory regime, not gate regime.** There is no `APPROVE` / `REJECT`, no `spec-approved` / `spec-rejected` label, no deterministic verdict computation. The synthesizer returns a `ship_decision` (`fold_and_ship` / `needs_revision` / `next_brief`); this is prose for the human reviewer, never auto-applied as a label or status check. - **Ship-meter floor.** `ship_decision: fold_and_ship` REQUIRES `shocked_meter_avg >= 7.0`. Below 7.0 the synthesizer MUST emit `needs_revision` (single drafter pass on the existing artifact) or `next_brief` (another round of panel review with a new brief). The floor is advisory wording in the comment, not a status check. - **Blocker veto.** If ANY panelist returns `new_blocking_findings[].length > 0`, the synthesizer MUST emit `ship_decision: next_brief` regardless of the shocked_meter_avg. A blocking finding from one panel is not outweighed by three panels rating the artifact 9/10. - **Single-writer interlock.** Only the orchestrator writes to the PR: exactly one `add-comment` call and one `remove-labels` call. The `remove-labels` call sweeps `spec-review` (trigger idempotency). NO `add-labels` call -- there are no verdict labels. Panelist subagents and the synthesizer subagent return JSON only and MUST NOT call any `gh` write command, post comments, apply labels, or touch PR state. - **Single-emission discipline.** Exactly one comment per panel run, rendered from `assets/comment-template.md` after all subagents return and the linter checklist runs. - **ASCII-only artifact.** Every byte the skill writes (the comment, the synthesizer prose, any rendered fold instruction) MUST be within printable ASCII (U+0020 - U+007E). The skill inherits the repo encoding rule from `.github/instructions/encoding.instructions.md` (if present) and additionally enforces it on the spec artifact via linter check 1. - **No-vendor-foundation language ban.** The spec artifact MUST NOT contain "CNCF", "Linux Foundation", "Sandbox", "Incubation", "W3C Process", or "IETF RFC stream". The persona prompts MAY reference these as pedigree (a panelist's credibility comes from having edited OpenAPI; that does not put OpenAPI's foundation affiliation in the spec text). Linter check 2 greps the artifact for the forbidden token list AFTER any fold. ## Agent roster | Agent | Role | Always active? | |-------|------|----------------| | [Swagger / OpenAPI Editor](../../agents/spec-swagger-editor.agent.md) | Interface-contract discipline (schemas, $ref hygiene, oneOf discriminators, conformance enumeration) | Yes | | [OCI Distribution Editor](../../agents/spec-oci-editor.agent.md) | Registry-HTTP rigor (hash envelopes, mirror tolerance, fail-closed extraction, supply-chain threat model) | Yes | | [Package-Manager Registry-Contract Editor](../../agents/spec-pkgmgr-editor.agent.md) | Dependency-resolution rigor (semver dialect pinning, lockfile determinism, transitive conflict policy, reserved-slot defensive MUSTs) | Yes | | [W3C TAG Architect](../../agents/spec-tag-architect.agent.md) | Web-platform integration / architecture (extensibility, layering, fingerprinting, machine-readable contract surface) | Yes | | [Spec Editor Synthesizer](../../agents/spec-editor-synthesizer.agent.md) | Same hand that drafted; aggregates panel returns, computes shocked_meter_avg, clusters convergent themes, produces fold-now / defer / reject lists and ship_decision | Yes | The roster is invariant for the v0.1 lineage. Changing it requires bumping the skill version. ## Topology ``` apm-spec-guardian SKILL (orchestrator thread) | +------ Wave 0: scope decision (orchestrator-internal) ------+ | classify diff: | | - editorial-only (tiny patch, single section, no schema | | change, no fixture add) -> skip Wave 3, run Wave 5 | | linter only, render lightweight comment | | - editorial-patch (default for PR-trigger) | | -> skip Wave 1+2, start at Wave 3 | | - new-version (operator opt-in via PR body marker | | `apm-spec-guardian: new-version`) | | -> run Wave 1 + 2 + 3 + 4 + 5 | +------------------------------------------------------------+ | IF new-version mode: run Wave 1 + Wave 2 first | Wave 1 (optional, new-version only): task -> spec-editor-synthesizer acting as ASSESSOR -- reads issue context + corpus + produces SPEC_BRIEF_v0 (session-state artifact) Wave 2 (optional, new-version only): task -> spec-editor-synthesizer acting as DRAFTER -- produces SPEC_DRAFT_v0 from SPEC_BRIEF_v0 | Wave 3: FAN-OUT via task tool (4 panelists in parallel) +------+------+--------+------+ v v v v swagger oci pkgmgr tag (each returns JSON per assets/panelist-return-schema.json) | v <-- S4 schema-validate per return v <-- on malformed: re-spawn that panelist v (max 2 attempts; then placeholder) v Wave 4: task -> spec-editor-synthesizer - aggregates findings across 4 panels - computes shocked_meter_avg - resolves dissent - clusters into convergent themes - emits fold_now[] + defer_v0_1_1[] + defer_v0_2[] + reject[] - emits ship_decision honoring ship-meter floor + blocker veto - returns assets/synthesizer-return-schema.json | v <-- S4 schema-validate v Wave 5: LINTER (mechanical, from assets/linter-checklist.md) - 11 checks; each MUST pass - failures append to ship_prose as advisory notes - linter does NOT change ship_decision; it informs the human reviewer | Wave 6: orchestrator (sole writer) | | v v add-comment remove-labels (max:1) [spec-review] (trigger idempotency reset) ``` ## Wave 0 -- scope decision The orchestrator classifies the diff before spawning any panelist. Decision rules, in order: 1. **New-version mode.** If the PR body contains the literal marker line `apm-spec-guardian: new-version`, OR the diff creates a new `docs/src/content/docs/specs/openapm-*.md` file (not an edit to an existing one), classify as `new-version`. Run Waves 1 -> 2 -> 3 -> 4 -> 5 -> 6. 2. **Editorial-only mode.** If ALL of the following hold: - the diff added < 50 lines AND removed < 50 lines total across all in-scope paths, - no JSON Schema file was added, removed, or had its top-level `properties` keys changed, - no fixture file was added or removed (existing fixture content edits are OK), - no anchor of the form `