Docs Feature Drift Check workflow (PatterAI/Patter)
The Docs Feature Drift Check workflow from PatterAI/Patter, explained and optimized by Latchkey.
CI health: C - fair
Point runs-on at Latchkey and get caching, job timeouts, self-healing for flaky steps, and up to 58% lower cost, applied automatically.
What it does
This is the Docs Feature Drift Check workflow from the PatterAI/Patter repository, a real project running GitHub Actions. It is shown here with attribution under its MIT license.
Below, Latchkey shows a faster, safer version produced by its optimization engine.
The workflow
name: Docs Feature Drift Check
# Daily consistency check between:
# - the canonical feature inventory (patter_sdk_features.xlsx, stored in the
# patter-assets sibling repo)
# - the Mintlify documentation under docs/
# - the public SDK surface (libraries/python/getpatter/__init__.py + libraries/typescript/src/index.ts)
#
# Opens or updates a single issue labelled `docs-drift` listing every mismatch.
# If there is nothing to report, closes the issue (if open).
on:
schedule:
# 03:00 UTC every day
- cron: '0 3 * * *'
workflow_dispatch: {}
permissions:
contents: read
issues: write
jobs:
drift-check:
runs-on: ubuntu-latest
steps:
- name: Checkout Patter repo
uses: actions/checkout@v5
- name: Checkout patter-assets (private, xlsx lives here)
uses: actions/checkout@v5
with:
repository: PatterAI/patter-assets
token: ${{ secrets.PATTER_ASSETS_TOKEN }}
path: patter-assets
# Soft-fail if the repo/secret isn't configured yet: the job falls
# back to a file path check and emits a warning.
continue-on-error: true
- name: Set up Python
uses: actions/setup-python@v6
with:
python-version: '3.12'
- name: Install deps
run: pip install openpyxl==3.1.5
- name: Run drift check
id: drift
run: |
python scripts/check_feature_docs_drift.py \
--xlsx patter-assets/patter_sdk_features.xlsx \
--docs docs/ \
--py-init libraries/python/getpatter/__init__.py \
--ts-index libraries/typescript/src/index.ts \
--output drift-report.md
continue-on-error: true
- name: Open or update docs-drift issue
if: steps.drift.outcome == 'failure'
uses: actions/github-script@v8
with:
script: |
const fs = require('fs');
const body = fs.readFileSync('drift-report.md', 'utf8');
const { data: issues } = await github.rest.issues.listForRepo({
owner: context.repo.owner,
repo: context.repo.repo,
labels: 'docs-drift',
state: 'open',
});
if (issues.length > 0) {
await github.rest.issues.update({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: issues[0].number,
body,
});
} else {
await github.rest.issues.create({
owner: context.repo.owner,
repo: context.repo.repo,
title: 'docs-drift: feature inventory ↔ docs mismatch',
body,
labels: ['docs-drift', 'documentation'],
});
}
- name: Close docs-drift issue if clean
if: steps.drift.outcome == 'success'
uses: actions/github-script@v8
with:
script: |
const { data: issues } = await github.rest.issues.listForRepo({
owner: context.repo.owner,
repo: context.repo.repo,
labels: 'docs-drift',
state: 'open',
});
for (const issue of issues) {
await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: issue.number,
body: 'Drift resolved - closing automatically.',
});
await github.rest.issues.update({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: issue.number,
state: 'closed',
});
}
The same workflow, on Latchkey
Estimated ~20% faster on cache hits, plus fewer wasted runs and a safer supply chain. Added and changed lines are highlighted.
name: Docs Feature Drift Check # Daily consistency check between: # - the canonical feature inventory (patter_sdk_features.xlsx, stored in the # patter-assets sibling repo) # - the Mintlify documentation under docs/ # - the public SDK surface (libraries/python/getpatter/__init__.py + libraries/typescript/src/index.ts) # # Opens or updates a single issue labelled `docs-drift` listing every mismatch. # If there is nothing to report, closes the issue (if open). on: schedule: # 03:00 UTC every day - cron: '0 3 * * *' workflow_dispatch: {} permissions: contents: read issues: write jobs: drift-check: timeout-minutes: 30 runs-on: latchkey-small steps: - name: Checkout Patter repo uses: actions/checkout@v5 - name: Checkout patter-assets (private, xlsx lives here) uses: actions/checkout@v5 with: repository: PatterAI/patter-assets token: ${{ secrets.PATTER_ASSETS_TOKEN }} path: patter-assets # Soft-fail if the repo/secret isn't configured yet: the job falls # back to a file path check and emits a warning. continue-on-error: true - name: Set up Python uses: actions/setup-python@v6 with: cache: 'pip' python-version: '3.12' - name: Install deps run: pip install openpyxl==3.1.5 - name: Run drift check id: drift run: | python scripts/check_feature_docs_drift.py \ --xlsx patter-assets/patter_sdk_features.xlsx \ --docs docs/ \ --py-init libraries/python/getpatter/__init__.py \ --ts-index libraries/typescript/src/index.ts \ --output drift-report.md continue-on-error: true - name: Open or update docs-drift issue if: steps.drift.outcome == 'failure' uses: actions/github-script@v8 with: script: | const fs = require('fs'); const body = fs.readFileSync('drift-report.md', 'utf8'); const { data: issues } = await github.rest.issues.listForRepo({ owner: context.repo.owner, repo: context.repo.repo, labels: 'docs-drift', state: 'open', }); if (issues.length > 0) { await github.rest.issues.update({ owner: context.repo.owner, repo: context.repo.repo, issue_number: issues[0].number, body, }); } else { await github.rest.issues.create({ owner: context.repo.owner, repo: context.repo.repo, title: 'docs-drift: feature inventory ↔ docs mismatch', body, labels: ['docs-drift', 'documentation'], }); } - name: Close docs-drift issue if clean if: steps.drift.outcome == 'success' uses: actions/github-script@v8 with: script: | const { data: issues } = await github.rest.issues.listForRepo({ owner: context.repo.owner, repo: context.repo.repo, labels: 'docs-drift', state: 'open', }); for (const issue of issues) { await github.rest.issues.createComment({ owner: context.repo.owner, repo: context.repo.repo, issue_number: issue.number, body: 'Drift resolved - closing automatically.', }); await github.rest.issues.update({ owner: context.repo.owner, repo: context.repo.repo, issue_number: issue.number, state: 'closed', }); }
What changed
- Run on Latchkey managed runners with one line (
runs-on), which apply the fixes below automatically and self-heal transient failures. This example useslatchkey-small; pick the runner size that fits the job. - Cache dependency installs on the setup step so they are served from cache.
- Add a job timeout so a hung step cannot burn hours of runner time.
What Latchkey heals here
This workflow has steps that commonly fail on transient issues (network, registries, flaky browsers). On Latchkey managed runners they are detected, retried, and self-healed instead of failing your build:
- Dependency installs
This workflow runs 1 job per trigger. On Latchkey the same minutes cost up to 58% less than GitHub-hosted, with zero queue time.