Adds CodeQL static analysis on push to main, pull_request, and weekly
on Wednesday 02:00 UTC (staggered from trace-revalidation Monday cron).
Uses the default security-and-quality query suite. Includes a consumer
note that private repos require GitHub Advanced Security.
Adds .github/workflows/trace-revalidation-weekly.yml to run the library
trace revalidation script on a weekly Monday cron (06:30 UTC) and on
workflow_dispatch. Permissions scoped to issues:write + contents:read
only — no contents:write, workflow does not auto-edit traces.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Adds .github/renovate.json extending config:base,
helpers:pinGitHubActionDigests, :separateMajorReleases, :automergeMinor,
and :automergePatch. Groups Sentry, OpenTelemetry, tRPC, Payload, and
Inversify into weekly per-cluster PRs to reduce noise. Enables Dockerfile
manager for .sandcastle/Dockerfile. Sets dependencyDashboard:true for a
single Renovate-managed tracking issue. Uses chore(deps): / chore(deps-major):
commit prefixes so release-please bump rules apply cleanly.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Adds a supply-chain scan step that runs `socket-cli` against the
lockfile on PRs that touch package.json or pnpm-lock.yaml. The step
is gated behind a git-diff paths check so it only fires when dependency
files change. The repo-root .socket.json (critical → error) causes the
step to exit non-zero on any critical finding, blocking the PR.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Closes the user's ask: versioning + a changelog generated on merging
to main, building on the just-mandated Conventional Commits substrate
(CLAUDE.md Key Conventions).
Architecture: ADR-021. Cookbook: docs/guides/releasing.md.
Initial state — six tracked packages at v0.1.0:
- . -> template-vertical (tag: template-v...)
- packages/auth -> @repo/auth (tag: auth-v...)
- packages/blog -> @repo/blog (tag: blog-v...)
- packages/media -> @repo/media (tag: media-v...)
- packages/marketing-pages -> @repo/marketing-pages (tag: marketing-pages-v...)
- packages/navigation -> @repo/navigation (tag: navigation-v...)
Core packages, tooling, and apps are NOT independently versioned
(ADR-021 rationale: core bumps cascade; apps aren't consumables;
surfacing them would create noise without information).
Configuration:
- release-please-config.json - 6 tracked packages, hybrid scope,
pre-1.0 conservative bump policy
(feat: -> patch, feat!: -> minor),
conventional-commit type mapping
- .release-please-manifest.json - baseline 0.1.0 for all 6 packages
- .github/workflows/release-please.yml - googleapis/release-please-
action@v4 on push to main,
concurrency-gated, write
permissions for the rolling PR
Workflow: on every push to main, release-please scans commits since
the last release tag PER PACKAGE (using commit-path, not the
conventional-commit scope), updates a single rolling release PR with
version bumps + per-package CHANGELOG entries. Merging that PR cuts
per-package tags + GitHub releases.
CHANGELOG files seeded at v0.1.0 baseline:
- CHANGELOG.md (root)
- packages/<feature>/CHANGELOG.md (5 features)
Subsequent versions are appended by release-please from commit
history. Do not edit manually.
Visibility surfaces updated (every agent entry point):
- CLAUDE.md Read First + new "Versioning is hybrid" Key Conventions
bullet (with bump policy summary)
- AGENTS.md preamble - new "Releases:" callout alongside Commits
- docs/glossary.md - new Releasing section with 8 terms (Conventional
Commits, release-please, Hybrid versioning, Tag prefix, Rolling
release PR, Bump targeting, Pre-1.0 bump policy, Release-As trailer,
CHANGELOG.md)
- docs/README.md - guides tree updated with releasing.md
- .claude/hooks/session-start.sh - one-line release reminder
- .claude/hooks/prompt-context.sh - new keyword group for
release/version/bump/semver/tag prompts
Package.json version bumps:
- root: name "template" -> "template-vertical", version "0.1.0"
- packages/auth, blog, media, marketing-pages, navigation: "0.0.0" -> "0.1.0"
Root rename rationale: release-please tags use the package-name + the
component prefix; "template-vertical" matches the repo identity (and
the user's question preview).
First release-please PR after this lands will sweep all subsequent
post-baseline commits into 0.1.1 / 0.2.0 bumps as appropriate.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Lands L3 of the agent-first coverage architecture (ADR-020) — the
mutation-testing layer. Stryker on entities + use-cases (the pure
business-logic surface) catches the third dimension of test quality:
tests that exist + execute the code but assert nothing.
Deps (root devDependencies):
- @stryker-mutator/core ^8.7.0
- @stryker-mutator/vitest-runner ^8.7.0
Shared base: packages/core-testing/stryker.base.json
- testRunner: vitest (uses each feature's vitest.config.ts)
- mutate: src/entities/** + src/application/use-cases/** (excludes
tests, factories, contracts)
- thresholds: high 90 / low 80 / break 80
- reporters: progress + html + json (reports/mutation/{index.html,
mutation.json})
- incremental mode enabled, concurrency 4, timeout 10s
- exposed via @repo/core-testing/stryker.base.json subpath export
Per-feature config: packages/auth/stryker.config.json
- 4-line file that extends the shared base
- Proof-of-concept; other features get a config when L0 unification
closes their existing test gaps
Driver: scripts/coverage/mutate.mjs (zero-dep Node ESM)
- discoverStrykerConfigs: walks packages/* and apps/* for
stryker.config.json
- Supports --filter <name>, --since <ref> (incremental), --json
- Runs Stryker per-feature via node_modules/.bin/stryker run
- Surfaces per-package pass/fail summary; exits 1 on any failure
- Tests: scripts/coverage/mutate.test.mjs (3 tests, all green)
CI: .github/workflows/mutation-nightly.yml
- Cron at 02:30 UTC + workflow_dispatch with filter input
- Uploads reports/mutation/** as artifact (30-day retention)
- On failure, opens a tracking issue labelled mutation-testing
- permissions: contents: read, issues: write
- 60-min timeout (Stryker is slow by design)
Generator: turbo gen feature now scaffolds stryker.config.json from
turbo/generators/templates/feature/stryker.config.json.hbs — new
features ship mutation-ready out of the box.
Guide: docs/guides/coverage.md L3 section fleshed out with run
syntax, config shape, base config inventory, CI behavior, and a
"what you're looking for" primer on mutation scores.
Lockfile churn: pnpm regenerated the lockfile for the new deps;
~5K-line net reduction is collateral (pnpm version drift) but
mechanical.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Two-workflow split per ADR-020:
.github/workflows/ci.yml (existing, extended):
- checkout now uses fetch-depth: 0 so coverage:diff can resolve
origin/<base-ref>...HEAD against the PR's base branch
- new step "Coverage — aggregate (L2)" runs after the test step
(with `if: always()` so the artifact still captures partial state
on test failures)
- new step "Coverage — diff (L1)" runs only on pull_request events,
diffing against origin/${{ github.base_ref }}
- artifact upload extended to include the aggregated
coverage/lcov.info and coverage/summary.json alongside the
per-package files
.github/workflows/coverage-snapshot.yml (new):
- dedicated workflow with `permissions: contents: write` so it can
commit the aggregated coverage/summary.json back to main after
each merge — the committed trend store (ADR-020 L2)
- runs full test + aggregate, then commits summary.json only if it
actually changed (commit body marked [skip ci] so the snapshot
doesn't recurse into itself)
- concurrency: coverage-snapshot ensures only one snapshot at a time
This closes the CI side of the coverage architecture. PRs now fail
fast when changed lines are uncovered, and main's trend history
accumulates automatically.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Adds two flat-config blocks to core-eslint/base.js: (1) repo-wide
no-restricted-imports for @sentry/* with the R40 message, (2) an
allowlist override for the only paths permitted to import the Sentry
SDK directly — core-shared/instrumentation/sentry/**, the bind-sentry
DI files, the no-sentry test guards, and apps' instrumentation* /
next.config / vite.config / sentry.*.config files. Patterns use
**/-prefix so they match whether ESLint runs from the repo root or
from inside a sub-package.
Also adds the standard `argsIgnorePattern: "^_"` config (used
throughout the repo) and a Node-globals override for *.mjs/*.cjs/*.js
and *.config.{ts,tsx} so withSentryConfig in next.config.mjs lints
clean. Required adding `globals` as a core-eslint dep.
Adds .github/workflows/sentry-pii-guard.yml — a lightweight CI step
that fails any PR introducing `sendDefaultPii: true` (R31). Excludes
node_modules / dist / .next / .turbo from the grep so vendored SDK
JSDoc examples don't false-positive.
Pre-existing lint nits cleared as part of getting `pnpm lint` green:
- core-testing define-contract-suite.test.ts: void the unused
receivedTracer (mirrors the next test's pattern)
- marketing-pages bind-dev-seed.ts: drop unused MockSiteSettingsRepository
import
- marketing-pages get-site-settings.use-case.ts: drop the now-redundant
eslint-disable for `_input`
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Runs typecheck + lint + boundaries + test (with coverage) + build
on every push to main and every PR. Postgres service for tests that
need DB. Playwright e2e and Storybook smoke tests gated on validate
job passing. Coverage uploaded as artifact (lcov format) for downstream
tools (Codecov, etc.) — wiring left to template users.
Spec: §6.11