Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
2215a4f
docs(wave-a): apply 12 P0 fixes from CDO synthesis
Copilot May 10, 2026
beacf07
docs(wave-b): foundation chapter (8 pages)
May 10, 2026
b38acd1
chore: untrack .docs-rewrite-plan/ (process metadata, not docs)
May 10, 2026
2f656ba
fix(docs): use ../sibling/ paths for slug-page cross-links
May 10, 2026
2092d21
docs(wave-c): consumer ramp (10 pages) + concepts SSOT fix
May 10, 2026
5f28658
docs(wave-d): producer ramp (10 pages) + CDO PASS polish
May 10, 2026
012f4ff
docs(wave-e): enterprise ramp (9 pages) + CDO fixes
May 10, 2026
0d0ee12
docs(wave-f): per-command CLI reference pages (24 commands)
May 10, 2026
b45ccdd
docs(wave-f): schema + top-level reference pages
May 10, 2026
56c5085
docs(wave-g): troubleshooting catalog + IDE integration hub
May 10, 2026
39d5740
docs(wave-i): persona-led sidebar + retire legacy guides + Astro polish
May 10, 2026
60ce789
docs: polish expressive-code rendering (themes, radius, shadow)
May 11, 2026
3a2c71a
feat(skills): add docs-sync per-PR advisory skill (issue scaffolding)
May 11, 2026
5126edc
feat(workflow): compile docs-sync.lock.yml (gh aw v0.71.5)
May 11, 2026
03aa3f4
feat(docs-sync): apply 4 eval-driven fixes from shadow run
May 11, 2026
bca675a
docs(sync): apply docs-sync panel for PR #1244 (apm update -> apm sel…
May 11, 2026
850e5f2
docs(landing+auth): proof-first landing, multi-host auth coverage
May 11, 2026
e660ec3
docs(landing): OS tabs for install, drop redundant MCP section
May 11, 2026
03e2d47
Merge main into docs/full-rewrite-persona-ramps
May 11, 2026
23ebe16
docs: fix stale getting-started/authentication links
May 11, 2026
82a675c
fix(ci): refresh apm-managed integration files; retarget policy help-…
May 11, 2026
c20ac5f
fix(ci): regenerate apm integration files with v0.13.0 path-resolution
May 11, 2026
72d388c
fix(docs): remove duplicate @astrojs/sitemap override blocking npm ci
May 11, 2026
1a663f5
Merge branch 'main' into docs/full-rewrite-persona-ramps
danielmeppiel May 11, 2026
264d907
docs(quickstart): hide apm run from main flow; flag as experimental
May 11, 2026
0dfdd4f
docs(compile): correct scope -- compile only handles instructions, no…
May 11, 2026
2f31ba6
docs(quickstart): move 'Looking for apm run?' note above the What nex…
May 11, 2026
285a9d2
docs(compile): clarify compile is optional for copilot, recommended f…
May 11, 2026
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
149 changes: 149 additions & 0 deletions .agents/skills/docs-impact-architect/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
---
name: docs-impact-architect
description: >-
Use this skill when the docs-impact-classifier returns a structural
verdict, signalling that the documentation TOC must change to
accommodate the PR. Proposes TOC deltas (new pages, moves,
merges) and emits new-page outline stubs that the doc-sync panel
later fleshes out. Holds the 3-promise narrative (consume /
produce / govern) and the persona ramps as hard constraints.
---

# docs-impact-architect

Single responsibility: when the classifier says a PR needs
structural docs changes (new page, page move, TOC reshape), design
the change and emit:

1. A precise TOC delta (added pages, moved pages, retired pages)
2. New-page outline stubs (slug, title, persona, promise, H2 sections, key examples)
3. The persona-ramp impact (which ramp gains/loses a stop)

You are NOT the writer (doc-writer owns prose). You are the **TOC
architect**. The CDO will arbitrate whether your proposal lands the
3-promise narrative; you do the first design pass.

## When to invoke

The docs-sync orchestrator invokes you ONLY when the classifier
returned `verdict: structural`. For `no_change` or `in_place` you
don't run.

## Inputs

- `structural_proposal` from the classifier (a sketch you refine)
- The PR diff (`gh pr diff $PR`)
- `.apm/docs-index.yml` (full corpus map)
- The PR description (for author-stated intent)

## Step 1: read the corpus map, not the corpus

Load `.apm/docs-index.yml` entirely. Inspect `chapters[]`, `pages[]`,
`promises[]`. This is your map. You do NOT read the 100+ page corpus
unless a specific page is implicated by the classifier's sketch.

## Step 2: classify the structural shape

Match the PR's surface change to one of these structural shapes:

| Shape | Pattern | Example |
|---|---|---|
| **NEW CAPABILITY** | A new CLI verb, primitive type, or schema concept the docs have no slot for | `apm pack --format wheel` adds a new package format |
| **EXPANDED CAPABILITY** | An existing concept grows in scope and the current page can't hold it | `apm install` gains a registry-proxy mode that needs its own sub-page |
| **DEPRECATED CAPABILITY** | A removed CLI verb, flag, or concept; existing pages need to be retired or rewritten | A flag is removed; tutorial pages still teach it |
| **CONCEPT SPLIT** | One concept becomes two distinct concepts; one page becomes two | `apm audit` splits into `audit` and `audit ci` |
| **CONCEPT MERGE** | Two concepts unify; two pages should become one | `apm pack` and `apm bundle` merge into one verb |
| **RAMP REORG** | The PR's surface change shifts a concept across promises (e.g. an enterprise feature becomes consumer-default) | Policy enforcement moves from enterprise to consumer default behaviour |

The structural shape drives the TOC delta shape.

## Step 3: design the TOC delta

For each new page proposed, fill in:

```yaml
new_page:
slug: docs/src/content/docs/<persona>/<topic>.md
title: "<short imperative title>"
persona: consumer | producer | enterprise | cross
promise: 1 | 2 | 3 | cross
parent_chapter: <existing chapter slug>
h2_sections:
- "## Why <topic>" # OPTIONAL -- skip unless concept is genuinely new
- "## How to <use>" # REQUIRED -- code first
- "## Reference" # OPTIONAL -- flag/option table
- "## Troubleshooting" # OPTIONAL -- only if known footguns
bridges:
incoming: # which existing pages should link TO this
- {from: <slug>, link_text: <suggested>}
outgoing: # which existing pages should this link FROM
- {to: <slug>, link_text: <suggested>}
ramp_impact: >-
one-paragraph description of how this changes the <persona>
ramp: which step it slots into, whether it adds a stop or
replaces an existing one
```

For each moved/retired page:

```yaml
moved_page:
from: <slug>
to: <slug>
redirect_rationale: <one-sentence>

retired_page:
slug: <slug>
reason: <one-sentence>
redirect_to: <slug> # MUST exist; orphaning pages breaks SEO
```

## Step 4: validate against the 3-promise narrative

Apply these hard rules. If any fails, redesign:

1. **Every page belongs to exactly one promise.** Cross-cutting pages (integrations, troubleshooting, reference) are explicitly marked `promise: cross`. If a new page straddles two promises, split it OR park it under `cross`.
2. **Consumer pages don't pre-teach producer concepts.** A consumer page may LINK to producer; it may not embed producer prose.
3. **Producer pages don't pre-teach enterprise concepts.** Same rule, one promise down.
4. **No page is orphaned from the TOC.** Every new page has a `parent_chapter` and at least one `incoming` bridge.
5. **No retired page lacks a `redirect_to`.** Search engines will index the old URL for months; the redirect is the SEO contract.

## Step 5: emit the architect report

Return JSON:

```json
{
"structural_shape": "NEW CAPABILITY" | "EXPANDED CAPABILITY" | "DEPRECATED CAPABILITY" | "CONCEPT SPLIT" | "CONCEPT MERGE" | "RAMP REORG",
"toc_delta": {
"new_pages": [...],
"moved_pages": [...],
"retired_pages": [...],
"chapter_changes": [...]
},
"promise_validation": {
"all_pages_single_promise": true | false,
"no_orphans": true | false,
"no_unredirected_retires": true | false,
"concerns": []
},
"downstream_in_place_pages": ["..."],
"rationale": "<2-3 sentence summary of why this structural delta and not alternatives>"
}
```

`downstream_in_place_pages[]` is the handoff to the localizer -- after
the architect approves the TOC, the localizer plans in-place edits
to existing pages that REFERENCE the new structure.

## Output contract

Return a SINGLE JSON document matching the schema in Step 5 as the
final message of your task. No prose around the JSON.

## Anti-patterns

- Inflating new-page counts to seem thorough. The minimal true delta wins.
- Skipping the promise-validation step. The CDO will catch it; better to self-catch.
- Designing a new chapter when an existing chapter has room. Always prefer extending over creating.
- Forgetting `redirect_to` on retired pages. SEO debt is the silent corpus killer.
154 changes: 154 additions & 0 deletions .agents/skills/docs-impact-classifier/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,154 @@
---
name: docs-impact-classifier
description: >-
Use this skill to classify the documentation impact of a pull
request diff, returning one of three verdicts -- no-change,
in-place edit, or structural change -- with bounded LLM cost.
Activate as a sibling skill of docs-sync; the orchestrator calls
this first, before any panel spawn, to keep cost floor at 1 LLM
call when no docs work is needed. Reads .apm/docs-index.yml as
the corpus map; never reads the full corpus.
---

# docs-impact-classifier

Single responsibility: given a PR diff and the `.apm/docs-index.yml`
corpus map, emit ONE classification verdict.

This skill is the cost gate for the entire docs-sync system. ~70% of
PRs should exit at verdict `no_change` with zero panel spawn.

## Architecture

This is a 3-layer funnel inside a single skill invocation:

- **L0 deterministic path gate** -- pure file-path matching, no LLM.
- **L1 symbol extraction + corpus grep** -- pure text processing, no LLM.
- **L2 LLM classifier** -- bounded ~8 KB context envelope, 1 call.

The skill returns the verdict from the earliest layer that can decide.

## Step 1: L0 deterministic path gate (no LLM)

Read `.apm/docs-index.yml` to load `no_impact_paths[]` and
`user_surface_paths[]`. Get the changed file list from the PR diff
(`gh pr diff --name-only`).

```
if every changed file matches no_impact_paths AND none match user_surface_paths:
return {verdict: "no_change", confidence: "high", source: "L0", scope_pages: []}
```

This handles:
- Test-only PRs (`tests/**`)
- CI workflow PRs (`.github/workflows/**`)
- Doc-only PRs (`docs/**`) -- out of scope, docs-sync doesn't review docs PRs
- Primitive-only PRs (`.apm/**`)
- Script and meta PRs

Expected hit rate: ~70% of PRs short-circuit here.

## Step 2: L1 symbol extraction + corpus grep (no LLM)

If L0 did not exit, extract user-observable symbols from the diff:

- **CLI command names** -- grep diff for `^@click.command`, `^@cli.command`, or any `apm <verb>` mention in added/removed lines.
- **Flag names** -- grep diff for `^@click.option`, `--[a-z-]+` patterns.
- **Public API symbols** -- added/removed `def <name>` in `src/apm_cli/__init__.py` or `src/apm_cli/api/**`.
- **Schema keys** -- added/removed keys in `apm.yml`, `apm.lock.yaml`, `apm-policy.yml` parsers.
- **Error strings** -- added/removed string literals in user-facing error paths (look for `_rich_error`, `click.echo`, `raise ... Error(`).

For each extracted symbol, consult `.apm/docs-index.yml#symbol_index`
to find the documented pages. Collect all hits into `candidate_pages[]`.

Also `grep -rn <symbol> docs/src/content/docs/` for symbols NOT in
the index (catches drift between index and corpus).

## Step 3: L2 LLM verdict (1 call, bounded context)

If L1 found zero candidate pages AND zero schema/CLI/flag changes:
return `{verdict: "no_change", confidence: "medium", source: "L1", scope_pages: []}`.

Otherwise, invoke the doc-analyser persona with EXACTLY this context
envelope (must fit in ~8 KB tokens):

- PR title + body (first 500 chars)
- Diff stats (`gh pr diff --stat` output)
- `.apm/docs-index.yml` (the whole file; it's ~8 KB seeded, may grow)
- L1 candidate pages with +/-5 lines of context per hit
- Path-classification summary from L0
- **`pr_doc_diff_paths[]`**: the list of paths under `docs/src/content/docs/**`
that the PR itself already modifies (drives the `in_place_resolved`
downgrade rule in "In-place-resolved detection" below).

Ask doc-analyser to return JSON matching this schema:

```json
{
"verdict": "no_change" | "in_place_resolved" | "in_place" | "structural",
"confidence": "low" | "medium" | "high",
"scope_pages": ["docs/src/content/docs/..."],
"structural_proposal": {
"new_pages": [{"slug": "...", "rationale": "..."}],
"moved_pages": [{"from": "...", "to": "..."}],
"toc_changes": "<one-paragraph>"
},
"reasoning": "<one-paragraph: what surface changed, what docs are affected, why this verdict>"
}
```

`structural_proposal` is populated only when verdict is `structural`.
`scope_pages` is populated for `in_place` and `structural` verdicts.

## Verdict semantics

| Verdict | Meaning | Panel size | Cost |
|---|---|---|---|
| `no_change` | No user-observable surface changed | 0 panel spawns | ~0-1 LLM call |
| `in_place_resolved` | Doc impact existed, but the PR's OWN diff already patches every page in `scope_pages` -- author already did the work | 0 panel spawns; skill emits NO advisory | ~1 LLM call |
| `in_place` | One to a few pages need a paragraph or section update; no new pages, no TOC change | N candidate pages x (doc-writer + python-architect) + editorial-owner + growth-hacker + CDO | ~6-12 LLM calls |
| `structural` | A new page is needed, OR an existing page should be split/merged, OR the TOC needs to change to fit a new concept | architect first (TOC delta), then in-place panel for affected pages | ~10-15 LLM calls |

## In-place-resolved detection (false-alarm killer)

BEFORE returning `in_place`, intersect your `scope_pages[]` with the
list of files the PR itself touches under `docs/**` (provided to you
by the orchestrator under `pr_doc_diff_paths[]`). If EVERY scope page
already appears in `pr_doc_diff_paths`, downgrade to `in_place_resolved`
and emit `reasoning` of the form "Author already patched <page list>".
This is the well-behaved-author path; the skill stays silent.

If only SOME scope pages are pre-patched, keep `in_place` and list the
REMAINING (unpatched) pages in `scope_pages[]`. Note the pre-patched
ones in `reasoning` for transparency.

## Rename / breaking-change heuristic (PR 1244 class)

When the L1 layer reports an ADDED public symbol that matches an
EXISTING public symbol's name in the corpus (e.g. PR adds `apm update`
but `apm update` already appears in 9 docs pages with different
semantics), this is a RENAME or BREAKING SEMANTIC CHANGE. Bias toward
`structural` (not `in_place`):
- the existing page describing the OLD semantics may need to SPLIT
into two pages (old verb under new name + new verb keeping old name)
- the TOC may need a NEW reference page for the renamed verb
- every passing mention in the corpus needs verification

Do NOT collapse a rename into `in_place` just because the affected
pages already exist. The shape of the work is structural even when no
new page is strictly required.

## Anti-patterns (verdict shape errors)

- Returning `in_place` with empty `scope_pages` -- invalid; orchestrator will reject.
- Returning `structural` without `structural_proposal` -- invalid.
- Returning `in_place` when EVERY scope page is in `pr_doc_diff_paths` -- should be `in_place_resolved`.
- Inflating `structural` to seem thorough -- the CDO will catch this. Return the minimal true verdict.
- Missing the rename heuristic above and emitting `in_place` for a verb-swap PR.
- Reading the corpus (the .md files themselves) at L2 -- context budget breach. You read the index, not the corpus.

## Output contract

Return a SINGLE JSON document matching the schema in Step 3 as the
final message of your task. No prose around the JSON. The
orchestrator parses your last message.
Loading
Loading