chore(template): clean-slate template snapshot from bb4a0c7
Curated, product-agnostic snapshot of the post-story-04 tree: demo content deleted, auth-only reference feature, web-next shell, all gates green. Product-specific docs, ADRs 027-029, PRDs/epics/archive, editor library traces, and product naming are curated out; generic template repairs (coverage provider devDeps, root test:coverage script, live lint fixes, root-only release-please) are kept. See TEMPLATE.md for provenance, curation list, and usage. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016j8z4VHjedXDTjEDNg7qHK
This commit is contained in:
52
.github/renovate.json
vendored
Normal file
52
.github/renovate.json
vendored
Normal file
@@ -0,0 +1,52 @@
|
||||
{
|
||||
"$schema": "https://docs.renovatebot.com/renovate-schema.json",
|
||||
"extends": [
|
||||
"config:base",
|
||||
"helpers:pinGitHubActionDigests",
|
||||
":separateMajorReleases",
|
||||
":automergeMinor",
|
||||
":automergePatch"
|
||||
],
|
||||
"dependencyDashboard": true,
|
||||
"dependencyDashboardLabels": ["renovate/dashboard"],
|
||||
"commitMessagePrefix": "chore(deps):",
|
||||
"major": {
|
||||
"commitMessagePrefix": "chore(deps-major):"
|
||||
},
|
||||
"packageRules": [
|
||||
{
|
||||
"groupName": "Sentry packages",
|
||||
"matchPackagePatterns": ["^@sentry/"],
|
||||
"schedule": ["on monday"],
|
||||
"automerge": false
|
||||
},
|
||||
{
|
||||
"groupName": "OpenTelemetry packages",
|
||||
"matchPackagePatterns": ["^@opentelemetry/"],
|
||||
"schedule": ["on monday"],
|
||||
"automerge": false
|
||||
},
|
||||
{
|
||||
"groupName": "tRPC packages",
|
||||
"matchPackagePatterns": ["^@trpc/"],
|
||||
"schedule": ["on monday"],
|
||||
"automerge": false
|
||||
},
|
||||
{
|
||||
"groupName": "Payload packages",
|
||||
"matchPackagePatterns": ["^payload"],
|
||||
"schedule": ["on monday"],
|
||||
"automerge": false
|
||||
},
|
||||
{
|
||||
"groupName": "Inversify packages",
|
||||
"matchPackagePatterns": ["^inversify"],
|
||||
"schedule": ["on monday"],
|
||||
"automerge": false
|
||||
}
|
||||
],
|
||||
"dockerfile": {
|
||||
"enabled": true,
|
||||
"fileMatch": ["^\\.sandcastle/Dockerfile$"]
|
||||
}
|
||||
}
|
||||
162
.github/workflows/ci.yml
vendored
Normal file
162
.github/workflows/ci.yml
vendored
Normal file
@@ -0,0 +1,162 @@
|
||||
# CI workflow — runs on every push to main and every pull request.
|
||||
#
|
||||
# TURBO_TOKEN / TURBO_TEAM: set these in your repository secrets/variables
|
||||
# to enable Turborepo remote caching. Without them the workflow still works,
|
||||
# just without the remote-cache speedup.
|
||||
#
|
||||
# PAYLOAD_SECRET: the value used here is a throwaway test secret. Do NOT
|
||||
# reuse it in production. Set a real secret for your deployed environments.
|
||||
|
||||
name: CI
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [main]
|
||||
pull_request:
|
||||
|
||||
env:
|
||||
TURBO_TOKEN: ${{ secrets.TURBO_TOKEN }}
|
||||
TURBO_TEAM: ${{ vars.TURBO_TEAM }}
|
||||
CI: true
|
||||
|
||||
jobs:
|
||||
validate:
|
||||
name: typecheck + lint + boundaries + test + build
|
||||
runs-on: ubuntu-latest
|
||||
services:
|
||||
postgres:
|
||||
image: postgres:16-alpine
|
||||
env:
|
||||
POSTGRES_PASSWORD: postgres
|
||||
POSTGRES_USER: postgres
|
||||
POSTGRES_DB: cms_test
|
||||
ports:
|
||||
- 5432:5432
|
||||
options: >-
|
||||
--health-cmd "pg_isready -U postgres"
|
||||
--health-interval 10s
|
||||
--health-timeout 5s
|
||||
--health-retries 5
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
# Full history so coverage:diff can resolve `origin/<base-ref>...HEAD`
|
||||
# against the PR's base branch (ADR-020 L1).
|
||||
fetch-depth: 0
|
||||
- uses: pnpm/action-setup@v4
|
||||
with:
|
||||
version: 9
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 22
|
||||
cache: pnpm
|
||||
- run: pnpm install --frozen-lockfile
|
||||
- name: Audit package signatures
|
||||
run: pnpm audit signatures --audit-level=high
|
||||
- name: Socket supply-chain scan
|
||||
if: github.event_name == 'pull_request'
|
||||
run: |
|
||||
if git diff --name-only origin/${{ github.base_ref }}...HEAD \
|
||||
| grep -qE '(^|/)package\.json$|(^|/)pnpm-lock\.yaml$'; then
|
||||
npx --yes socket-cli@latest scan .
|
||||
else
|
||||
echo "No package.json or pnpm-lock.yaml changes — skipping Socket scan."
|
||||
fi
|
||||
- run: pnpm typecheck
|
||||
- run: pnpm lint
|
||||
- run: pnpm conformance
|
||||
- name: Compliance manifest drift check
|
||||
run: |
|
||||
pnpm compliance:emit-all --check || {
|
||||
echo ""
|
||||
echo "Compliance artifacts are out of date."
|
||||
echo "Run \`pnpm compliance:emit-all\` locally and commit the updated files."
|
||||
exit 1
|
||||
}
|
||||
- name: Fallow whole-codebase analysis
|
||||
run: pnpm fallow --format annotations
|
||||
- run: pnpm turbo boundaries
|
||||
- name: Test with coverage
|
||||
env:
|
||||
DATABASE_URL: postgres://postgres:postgres@localhost:5432/cms_test
|
||||
PAYLOAD_SECRET: test-secret-do-not-use-in-prod
|
||||
run: pnpm test:coverage
|
||||
# L2 — merge per-package lcovs to coverage/lcov.info + emit
|
||||
# coverage/summary.json (ADR-020). Runs even on test failure so the
|
||||
# artifact still captures what was produced.
|
||||
- name: Coverage — aggregate (L2)
|
||||
if: always()
|
||||
run: pnpm coverage:aggregate
|
||||
# L1 — cover-the-diff gate. Only meaningful on PRs (push-to-main has
|
||||
# no base ref to diff against). Compares against the PR's base branch.
|
||||
- name: Coverage — diff (L1)
|
||||
if: github.event_name == 'pull_request'
|
||||
run: pnpm coverage:diff -- --base origin/${{ github.base_ref }}
|
||||
- run: pnpm build
|
||||
- uses: actions/upload-artifact@v4
|
||||
if: always()
|
||||
with:
|
||||
name: coverage
|
||||
path: |
|
||||
coverage/lcov.info
|
||||
coverage/summary.json
|
||||
**/coverage/lcov.info
|
||||
retention-days: 7
|
||||
|
||||
e2e:
|
||||
name: Playwright e2e
|
||||
needs: validate
|
||||
runs-on: ubuntu-latest
|
||||
services:
|
||||
postgres:
|
||||
image: postgres:16-alpine
|
||||
env:
|
||||
POSTGRES_PASSWORD: postgres
|
||||
POSTGRES_USER: postgres
|
||||
POSTGRES_DB: cms_test
|
||||
ports:
|
||||
- 5432:5432
|
||||
options: >-
|
||||
--health-cmd "pg_isready -U postgres"
|
||||
--health-interval 10s
|
||||
--health-timeout 5s
|
||||
--health-retries 5
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: pnpm/action-setup@v4
|
||||
with:
|
||||
version: 9
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 22
|
||||
cache: pnpm
|
||||
- run: pnpm install --frozen-lockfile
|
||||
- run: pnpm exec playwright install --with-deps chromium
|
||||
- name: Run e2e
|
||||
env:
|
||||
DATABASE_URL: postgres://postgres:postgres@localhost:5432/cms_test
|
||||
PAYLOAD_SECRET: test-secret-do-not-use-in-prod
|
||||
run: pnpm test:e2e
|
||||
|
||||
storybook:
|
||||
name: Storybook smoke tests + visual regression
|
||||
needs: validate
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: pnpm/action-setup@v4
|
||||
with:
|
||||
version: 9
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 22
|
||||
cache: pnpm
|
||||
- run: pnpm install --frozen-lockfile
|
||||
- run: pnpm exec playwright install --with-deps chromium
|
||||
- name: Build Storybook
|
||||
run: pnpm --filter @repo/storybook build:storybook
|
||||
- run: pnpm test:stories
|
||||
- name: Install Playwright browsers
|
||||
run: pnpm exec playwright install chromium --with-deps
|
||||
- name: Visual regression
|
||||
run: pnpm test:visual
|
||||
44
.github/workflows/codeql.yml
vendored
Normal file
44
.github/workflows/codeql.yml
vendored
Normal file
@@ -0,0 +1,44 @@
|
||||
# CodeQL static analysis — javascript-typescript.
|
||||
#
|
||||
# Runs on every push to main, every pull request, and weekly on Wednesday
|
||||
# at 02:00 UTC (staggered from the trace-revalidation cron on Monday 06:30).
|
||||
#
|
||||
# NOTE (consumers): CodeQL is free for public repositories and GitHub Free
|
||||
# plans. For *private* repositories it requires GitHub Advanced Security
|
||||
# (available on GitHub Enterprise Cloud/Server or as an add-on). If you are
|
||||
# using this template with a private repo and do not have Advanced Security
|
||||
# enabled, remove or disable this workflow — it will fail at the "Initialize
|
||||
# CodeQL" step with a licensing error.
|
||||
|
||||
name: CodeQL
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [main]
|
||||
pull_request:
|
||||
schedule:
|
||||
# 02:00 UTC every Wednesday
|
||||
- cron: "0 2 * * 3"
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
security-events: write
|
||||
|
||||
jobs:
|
||||
analyze:
|
||||
name: Analyze (javascript-typescript)
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 30
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Initialize CodeQL
|
||||
uses: github/codeql-action/init@v3
|
||||
with:
|
||||
languages: javascript-typescript
|
||||
# Uses the default query suite (security-and-quality). To restrict
|
||||
# to security-only queries, set:
|
||||
# queries: security-extended
|
||||
- name: Autobuild
|
||||
uses: github/codeql-action/autobuild@v3
|
||||
- name: Perform CodeQL Analysis
|
||||
uses: github/codeql-action/analyze@v3
|
||||
72
.github/workflows/coverage-snapshot.yml
vendored
Normal file
72
.github/workflows/coverage-snapshot.yml
vendored
Normal file
@@ -0,0 +1,72 @@
|
||||
# Coverage snapshot — commits coverage/summary.json back to main after each
|
||||
# merge so the trend history accumulates in `git log -- coverage/summary.json`
|
||||
# (ADR-020 L2). This is the only workflow that needs `contents: write`.
|
||||
#
|
||||
# Skipped if summary.json hasn't changed since the previous commit.
|
||||
|
||||
name: Coverage snapshot
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [main]
|
||||
|
||||
# Avoid two snapshot runs racing each other on rapid-fire merges.
|
||||
concurrency:
|
||||
group: coverage-snapshot
|
||||
cancel-in-progress: false
|
||||
|
||||
permissions:
|
||||
contents: write
|
||||
|
||||
jobs:
|
||||
snapshot:
|
||||
runs-on: ubuntu-latest
|
||||
services:
|
||||
postgres:
|
||||
image: postgres:16-alpine
|
||||
env:
|
||||
POSTGRES_PASSWORD: postgres
|
||||
POSTGRES_USER: postgres
|
||||
POSTGRES_DB: cms_test
|
||||
ports:
|
||||
- 5432:5432
|
||||
options: >-
|
||||
--health-cmd "pg_isready -U postgres"
|
||||
--health-interval 10s
|
||||
--health-timeout 5s
|
||||
--health-retries 5
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
# Token with write scope so we can push the snapshot back.
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
- uses: pnpm/action-setup@v4
|
||||
with:
|
||||
version: 9
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 22
|
||||
cache: pnpm
|
||||
- run: pnpm install --frozen-lockfile
|
||||
- name: Test with coverage
|
||||
env:
|
||||
DATABASE_URL: postgres://postgres:postgres@localhost:5432/cms_test
|
||||
PAYLOAD_SECRET: test-secret-do-not-use-in-prod
|
||||
run: pnpm test:coverage
|
||||
- name: Aggregate
|
||||
run: pnpm coverage:aggregate
|
||||
- name: Commit summary.json if changed
|
||||
run: |
|
||||
if git diff --quiet --exit-code coverage/summary.json; then
|
||||
echo "No summary.json change; skipping commit."
|
||||
exit 0
|
||||
fi
|
||||
git config user.name "github-actions[bot]"
|
||||
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
|
||||
git add coverage/summary.json
|
||||
git commit -m "chore(coverage): snapshot ${GITHUB_SHA::7}
|
||||
|
||||
Auto-generated by .github/workflows/coverage-snapshot.yml.
|
||||
|
||||
[skip ci]"
|
||||
git push origin HEAD:main
|
||||
110
.github/workflows/mutation-nightly.yml
vendored
Normal file
110
.github/workflows/mutation-nightly.yml
vendored
Normal file
@@ -0,0 +1,110 @@
|
||||
# Mutation testing (L3) — nightly run + on-demand. ADR-020.
|
||||
#
|
||||
# Stryker is slow (~minutes per feature) so it's NOT part of the default
|
||||
# CI loop. This workflow runs nightly (and on manual dispatch) across every
|
||||
# feature with a stryker.config.json, then uploads the HTML + JSON
|
||||
# mutation reports as artifacts.
|
||||
#
|
||||
# On a meaningful score drop (>5%) it opens a tracking issue.
|
||||
|
||||
name: Mutation testing (nightly)
|
||||
|
||||
on:
|
||||
schedule:
|
||||
# 02:30 UTC nightly
|
||||
- cron: "30 2 * * *"
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
filter:
|
||||
description: "Feature filter (e.g. @repo/auth). Empty = all features."
|
||||
required: false
|
||||
default: ""
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
issues: write
|
||||
|
||||
jobs:
|
||||
mutate:
|
||||
runs-on: ubuntu-latest
|
||||
services:
|
||||
postgres:
|
||||
image: postgres:16-alpine
|
||||
env:
|
||||
POSTGRES_PASSWORD: postgres
|
||||
POSTGRES_USER: postgres
|
||||
POSTGRES_DB: cms_test
|
||||
ports:
|
||||
- 5432:5432
|
||||
options: >-
|
||||
--health-cmd "pg_isready -U postgres"
|
||||
--health-interval 10s
|
||||
--health-timeout 5s
|
||||
--health-retries 5
|
||||
timeout-minutes: 60
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: pnpm/action-setup@v4
|
||||
with:
|
||||
version: 9
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 22
|
||||
cache: pnpm
|
||||
- run: pnpm install --frozen-lockfile
|
||||
- name: Run mutation testing
|
||||
env:
|
||||
DATABASE_URL: postgres://postgres:postgres@localhost:5432/cms_test
|
||||
PAYLOAD_SECRET: test-secret-do-not-use-in-prod
|
||||
run: |
|
||||
if [ -n "${{ inputs.filter }}" ]; then
|
||||
pnpm mutate -- --filter "${{ inputs.filter }}"
|
||||
else
|
||||
pnpm mutate
|
||||
fi
|
||||
continue-on-error: true
|
||||
- name: Upload mutation reports
|
||||
if: always()
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: mutation-reports
|
||||
path: packages/*/reports/mutation/
|
||||
retention-days: 30
|
||||
- name: Open tracking issue on >5% score drop
|
||||
if: failure()
|
||||
uses: actions/github-script@v7
|
||||
with:
|
||||
script: |
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
const reports = [];
|
||||
const pkgsDir = path.join(process.cwd(), 'packages');
|
||||
if (fs.existsSync(pkgsDir)) {
|
||||
for (const pkg of fs.readdirSync(pkgsDir)) {
|
||||
const json = path.join(pkgsDir, pkg, 'reports', 'mutation', 'mutation.json');
|
||||
if (fs.existsSync(json)) {
|
||||
try {
|
||||
const data = JSON.parse(fs.readFileSync(json, 'utf8'));
|
||||
const score = data.thresholds?.high && data.systemUnderTestMetrics?.metrics?.mutationScore;
|
||||
if (typeof score === 'number') {
|
||||
reports.push({ pkg, score: score.toFixed(2) });
|
||||
}
|
||||
} catch { /* skip */ }
|
||||
}
|
||||
}
|
||||
}
|
||||
if (reports.length === 0) return;
|
||||
const body = [
|
||||
'Nightly mutation testing run flagged failures. Latest scores:',
|
||||
'',
|
||||
...reports.map(r => `- **${r.pkg}**: ${r.score}%`),
|
||||
'',
|
||||
`Run: ${context.serverUrl}/${context.repo.owner}/${context.repo.repo}/actions/runs/${context.runId}`,
|
||||
].join('\n');
|
||||
await github.rest.issues.create({
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
title: `Mutation score drop — ${new Date().toISOString().slice(0, 10)}`,
|
||||
body,
|
||||
labels: ['mutation-testing', 'automated'],
|
||||
});
|
||||
83
.github/workflows/release-please.yml
vendored
Normal file
83
.github/workflows/release-please.yml
vendored
Normal file
@@ -0,0 +1,83 @@
|
||||
# Release Please — automated changelog + version bumps on merge to main.
|
||||
#
|
||||
# How it works:
|
||||
# 1. On every push to main, release-please scans conventional commits since
|
||||
# the last release tag.
|
||||
# 2. It opens (or updates) a single rolling "release PR" containing:
|
||||
# - the root package.json version bump
|
||||
# - new CHANGELOG.md entries grouped by section (Features / Bug Fixes
|
||||
# / Performance / Refactoring / Documentation / Reverts)
|
||||
# - updated .release-please-manifest.json
|
||||
# 3. Merging that PR triggers tag creation (`vN.N.N`) and GitHub release
|
||||
# notes.
|
||||
#
|
||||
# Single root version (template default): only the root package is tracked
|
||||
# and tags are plain `v*` (`include-component-in-tag: false`). Hybrid
|
||||
# per-feature versioning is a documented alternative — see ADR-021.
|
||||
#
|
||||
# Tracked package, manifest baseline, and changelog sections live in
|
||||
# `release-please-config.json` + `.release-please-manifest.json`.
|
||||
|
||||
name: Release Please
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [main]
|
||||
|
||||
permissions:
|
||||
contents: write
|
||||
pull-requests: write
|
||||
|
||||
# A second push to main while a release PR is open shouldn't fight with the
|
||||
# first invocation — release-please-action already updates the rolling PR
|
||||
# idempotently, but concurrency keeps the audit trail clean.
|
||||
concurrency:
|
||||
group: release-please
|
||||
cancel-in-progress: false
|
||||
|
||||
jobs:
|
||||
release-please:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: googleapis/release-please-action@v4
|
||||
id: release
|
||||
with:
|
||||
config-file: release-please-config.json
|
||||
manifest-file: .release-please-manifest.json
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
# The steps below run only when release-please actually cut a release.
|
||||
# pnpm dlx avoids adding @cyclonedx/cyclonedx-npm to the lockfile (CI-only
|
||||
# tool per ADR-022); SHA-pinned action follows ADR-023 §1 Renovate pattern.
|
||||
- uses: actions/checkout@v4
|
||||
if: ${{ steps.release.outputs.releases_created == 'true' }}
|
||||
|
||||
- uses: pnpm/action-setup@v4
|
||||
if: ${{ steps.release.outputs.releases_created == 'true' }}
|
||||
with:
|
||||
version: 9
|
||||
|
||||
- uses: actions/setup-node@v4
|
||||
if: ${{ steps.release.outputs.releases_created == 'true' }}
|
||||
with:
|
||||
node-version: 22
|
||||
cache: pnpm
|
||||
|
||||
- name: Install dependencies
|
||||
if: ${{ steps.release.outputs.releases_created == 'true' }}
|
||||
run: pnpm install --frozen-lockfile
|
||||
|
||||
- name: Generate CycloneDX SBOM
|
||||
if: ${{ steps.release.outputs.releases_created == 'true' }}
|
||||
run: >
|
||||
pnpm dlx @cyclonedx/cyclonedx-npm
|
||||
--output-file sbom-${{ steps.release.outputs.tag_name }}.cdx.json
|
||||
--output-format json
|
||||
--ignore-npm-errors
|
||||
|
||||
- name: Attach SBOM to GitHub release
|
||||
if: ${{ steps.release.outputs.releases_created == 'true' }}
|
||||
uses: softprops/action-gh-release@b4309332981a82ec1c5618f44dd2e27cc8bfbfda # v3.0.0
|
||||
with:
|
||||
tag_name: ${{ steps.release.outputs.tag_name }}
|
||||
files: sbom-${{ steps.release.outputs.tag_name }}.cdx.json
|
||||
28
.github/workflows/sentry-pii-guard.yml
vendored
Normal file
28
.github/workflows/sentry-pii-guard.yml
vendored
Normal file
@@ -0,0 +1,28 @@
|
||||
# R31 — block sendDefaultPii: true from ever landing.
|
||||
#
|
||||
# This is a defense-in-depth gate: the privacy posture is also enforced by
|
||||
# the centralized init helpers in core-shared/instrumentation/sentry/, but
|
||||
# this grep makes any drift impossible to merge.
|
||||
|
||||
name: Sentry PII guard (R31)
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
push:
|
||||
branches: [main]
|
||||
|
||||
jobs:
|
||||
pii-guard:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Verify sendDefaultPii is never true
|
||||
run: |
|
||||
if grep -RIn --include='*.ts' --include='*.tsx' --include='*.mjs' --include='*.cjs' --include='*.js' \
|
||||
--exclude-dir=node_modules --exclude-dir=.next --exclude-dir=dist --exclude-dir=.turbo \
|
||||
-E 'sendDefaultPii\s*:\s*true' \
|
||||
packages/ apps/; then
|
||||
echo "::error::R31 violation — sendDefaultPii: true is forbidden anywhere in the repo."
|
||||
exit 1
|
||||
fi
|
||||
echo "OK — no sendDefaultPii: true detected."
|
||||
38
.github/workflows/trace-revalidation-weekly.yml
vendored
Normal file
38
.github/workflows/trace-revalidation-weekly.yml
vendored
Normal file
@@ -0,0 +1,38 @@
|
||||
# Library trace revalidation — weekly run + on-demand. ADR-022.
|
||||
#
|
||||
# Walks every approved + pre-shipped trace in docs/library-decisions/,
|
||||
# re-runs each trace's verification-commands, classifies divergence as
|
||||
# soft (minor drift → rolling dashboard issue) or hard (re-evaluation
|
||||
# warranted → per-dep issue), and opens/updates/closes GitHub issues
|
||||
# accordingly. Runs in parallel to main — does NOT gate deployments.
|
||||
|
||||
name: Library trace revalidation (weekly)
|
||||
|
||||
on:
|
||||
schedule:
|
||||
# 06:30 UTC every Monday
|
||||
- cron: "30 6 * * 1"
|
||||
workflow_dispatch:
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
issues: write
|
||||
|
||||
jobs:
|
||||
revalidate:
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 30
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: pnpm/action-setup@v4
|
||||
with:
|
||||
version: 9
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 22
|
||||
cache: pnpm
|
||||
- run: pnpm install --frozen-lockfile
|
||||
- name: Revalidate library traces
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
run: node scripts/library-decisions/revalidate.mjs
|
||||
Reference in New Issue
Block a user