Prose that keeps pace with the merge stream.
A scheduled trigger fires once a day. It reads every PR merged since the last successful run, picks out the changes that move API surface, and lands a rolling editor-review PR pointing — by file, line, and originating PR — at the documents that no longer match the code.
It flags. It does not rewrite. An editor owns the prose; the routine owns the diff.
Six steps, deterministic from window to worklist.
Resolve scan window
Anchored to created_at of the last successful run; widened back to the open editor-PR's recorded window so the flagging merges stay in scope.
List merged PRs
Every PR merged inside the window, fetched through the gh CLI on the workflow's authenticated token.
API-surface only
Touches under scripts/, portal/, or apps/ in .py / .ts / .tsx / .js / .mjs / .cjs / .sh. Tests and build noise excluded.
Path + symbol drift
Path drift: file modified, removed, or renamed (tracked by old path). Symbol drift: def / class / export removed or renamed, distinctive identifiers only.
Match against docs
Every signal grep'd against every Markdown file under docs/ (excluding _generated/ and _shared/). Exact path match; gated symbol match.
One rolling PR
Refreshes the automation/docs-api-drift branch in place. Opens draft so the merge button is gated behind an editor's explicit "ready for review".
Every flag carries its receipt.
What the editor sees, in order.
- The document. One H3 per stale file, never bundled.
- The signal. Either
pathorsymbol, with the verb that landed it (modified · removed · renamed). - The provenance. The originating PR number plus its title — one click away from the diff.
- The line citations. Exact line numbers in the doc, not section headings — so the editor opens the file and lands on the cursor.
- What's absent. No prose suggestion, no rewrite, no "consider updating" — the routine is allergic to writing for the editor.
Conservative by design, complete by contract.
Nothing slips between runs.
The lower bound is the last successful run, not a fixed 24 hours. When an editor-review PR is already open, the window stretches back to the report window it recorded — so an aging merge never escapes review.
Two signals, both noise-gated.
Path drift is exact and effectively false-positive-free. Symbol drift only chases distinctive identifiers — past a minimum length, off the stopword list, snake- or camel-cased. build, parse, index never reach the docs scan.
One PR. Never a sibling.
The deliverable is a single PR on automation/docs-api-drift, refreshed in place. An incomplete scan exits non-zero and leaves the PR untouched — the next run rescans the window instead of advancing past unpublished drift.
What can go wrong, and how it lands.
| Condition | Disposition | Effect on the editor PR |
|---|---|---|
| Window exceeds the configured cap | exit non-zero | PR untouched; next run rescans the same window. |
gh error while reading a PR's file list |
exit non-zero | PR untouched; not recorded as the last successful run. |
| Lookup of the open editor PR fails | exit non-zero | No close, no refresh, no advance of the window. |
| Scan completes; drift found | open or refresh PR (draft) | Worklist replaces the previous report on the same branch. |
| Scan completes; no drift in widened window | close PR, delete branch | Editor's inbox returns to silent. |
| Editor merges the worklist itself | gated by draft status | Requires affirmative "ready for review" — guard added after the PR #1094 single-click failure mode. |
The contract, the walkthrough, the source.
This brief is the surface. The contract is the truth.
The Markdown editor contract is the canonical specification of the routine's behavior. The walkthrough page expands every cell of the worklist. The workflow file is what actually runs at 06:17 UTC.