Add core CI workflows and Dependabot configuration#1
Conversation
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
julianken-bot
left a comment
There was a problem hiding this comment.
Verdict: APPROVE
Verification ledger:
- YAML syntax: all 4 files validated (Python yaml.safe_load)
pnpm lint: FAILS (22 errors, 46 warnings) -- pre-existing on mainpnpm tsc --noEmit: FAILS (10+ type errors) -- pre-existing on mainpnpm test:unit:coverage: FAILS (9/115 tests) -- pre-existing on main- Scripts referenced by workflows (
lint,tsc,build,test:unit:coverage): all exist in package.json - Dependabot groups: cross-checked against package.json dependencies -- correct matches
- Concurrency groups and timeouts: present on all workflows
- Frozen lockfile: used in all install steps
Findings (1):
- IMPORTANT: CI will be red on main immediately after merge (details inline on ci-lint.yml:28)
Bottom line: The workflow definitions themselves are correct and well-structured -- concurrency groups, cancel-in-progress, timeouts, frozen lockfile, and artifact uploads are all properly configured. The Dependabot grouping is sensible. The one concern is that main currently has pre-existing lint, type, and test failures, so these workflows will report red from their first run. This is not a defect in the PR, but it is worth sequencing the fix before or alongside this merge.
Approving because the CI definitions are sound. The pre-existing failures are a separate concern that should be addressed in a companion PR.
Reviewed by @julianken-bot (opus) against the 12-rule anti-slop rubric. R8 second pass completed; no additional findings.
| node-version: 20 | ||
| cache: 'pnpm' | ||
| - run: pnpm install --frozen-lockfile | ||
| - run: pnpm lint |
There was a problem hiding this comment.
IMPORTANT: These three CI workflows will fail immediately when this PR merges to main. I verified locally:
pnpm lint: 22 errors, 46 warnings (exit code 1)pnpm tsc --noEmit: 10+ TS2345/TS2322 errors intests/unit/lib/types/branded.test.tspnpm test:unit:coverage: 9 test failures across 5 files
The failures are all pre-existing on main (introduced in the initial commit), so they are not defects in this PR's workflow definitions. However, adding CI that starts red on main means the first CI run after merge will be a failure, and the branch protection signal (if/when enabled) will be broken from day one.
Consider either (a) fixing the pre-existing lint/type/test errors in a preceding or companion PR before merging this, or (b) accepting the red CI as a known state and fixing it in the next PR. Option (a) is strongly preferred -- green-on-merge is the standard CI invariant.
Payload CMS connects to postgres at build time via postgresAdapter. A dummy DATABASE_URL without a real service would cause connection-refused. Mirrors the postgres service config from e2e-tests.yml. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
next build runs generateRouteStaticParams which queries the database for dynamic routes like [slug]. The postgres service container alone isn't enough — migrations must run first to create the schema. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Addresses julianken-bot review finding #1 (integration gap) and #2 (docs anchor rot). Unit tests cover the validator in isolation; this test file asserts (a) payload.config.ts still names all three required env vars on failure — a future refactor that trims the list will fail this test — and (b) the docs anchor the error message points at still exists. Per bot review on PR #76.
…environment (#76) * fix(env): fail loudly on missing required env vars at module-load Replaces three ad-hoc env reads in payload.config.ts with a single reusable validator (src/lib/env/required-env.ts) that collects ALL missing vars in one Error rather than stopping at the first. Two of those reads previously used `process.env.FOO || ''` and silently defaulted to empty string, masking the real failure behind cryptic Postgres/Payload errors downstream. Adds NEXT_PUBLIC_SERVER_URL to CI workflows (ci-build, bundle-size, e2e-tests) that previously relied on the silent empty-string default. Documents required Preview env vars in docs/deployment.md#preview-environment — the docs anchor referenced by the validator's error message. The one-time `vercel env add PAYLOAD_SECRET preview` action happens post-merge and is tracked in the linked issue. Fixes #73 Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * test: add integration + docs-anchor guards for env preflight Addresses julianken-bot review finding #1 (integration gap) and #2 (docs anchor rot). Unit tests cover the validator in isolation; this test file asserts (a) payload.config.ts still names all three required env vars on failure — a future refactor that trims the list will fail this test — and (b) the docs anchor the error message points at still exists. Per bot review on PR #76. --------- Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…tern Detects modified pattern files via `git diff --name-only origin/main...HEAD` and requires that every authored pattern (non-empty oneLineSummary or implementationSketch) has a CHANGELOG entry dated >= today. Two checks: 1. Touched-and-authored patterns must have a CHANGELOG entry >= today. (Empty stubs are skipped — they're scaffolding, not editorial content.) 2. Every CHANGELOG entry's slug must exist in PATTERNS (active OR archived). Catches typos and removed patterns silently invalidating the audit trail. On main itself (no upstream diff) check #1 becomes a no-op. The script falls through `origin/main` → `upstream/main` → `main` to handle clones without an upstream remote. Refs #154 Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…rences, check-affiliate-links, lint-changelog) + workflow (#166) * feat(adp): typecheck-sketches.ts compiles every implementationSketch Compiles every Pattern's implementationSketch through `tsc --noEmit` with flags tuned for snippet-mode TypeScript (`--ignoreConfig --types node --skipLibCheck --lib es2022,dom --module esnext --target es2022 --moduleResolution bundler --strict`). Spike-log lessons applied: - Inject `export {}` automatically when a snippet has no top-level import or export, so top-level await doesn't trip TS1375. - Capture both stdout AND stderr from the tsc subprocess (diagnostics split across both depending on the failure). - Skip patterns whose `sdkAvailability` is `python-only` or `no-sdk` for compilation, but require a "pseudocode" banner so readers aren't misled. Wires into pnpm lint via a later commit. Refs #154 Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * feat(adp): validate-references.ts with Crossref + OpenAlex fallback Verifies that every paper Reference resolves to a real publication by DOI. This is the teeth on the catalog's citation-rigor claim. Critical: arXiv preprint DOIs (`10.48550/arXiv.*`) are NOT indexed by Crossref — Reflexion, Self-Refine, CRITIC and others all return 404 there. The script falls back to OpenAlex on Crossref 404 or network error, hitting `https://api.openalex.org/works/doi:{doi}` (the DOI is NOT URL-encoded inside the `doi:` prefix). Validation: title fuzzy-match (lowercased, accents and punctuation stripped), year exact, first-author surname (after splitting on comma / " and ", trimming " et al."). Politeness: - User-Agent identifies us with `mailto:juliankennon@gmail.com` (Crossref's polite-pool requirement). - 100 ms throttle between requests. - 3-attempt retry with exponential backoff for 5xx. Cache: short-circuits via references.lock.json when a DOI's title / year / surname still match. Lockfile is normalised to pretty-printed JSON for diff-friendliness; the script no-op-skips writing if content is unchanged. Refs #154 Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * feat(adp): check-affiliate-links.ts rejects affiliate query params Refuses to ship Reference URLs / realWorldExample sourceUrls / readerGotcha sourceUrls that carry affiliate or tracking query parameters. Editorial principle: zero affiliate links anywhere in the catalog. Detects (case-insensitive): - Classic: tag, ref, aff, linkCode, via, partner, affiliate, affid, aff_id, partnerid, utm_source_aff - Commission Junction: clickid, cjevent - Impact Radius: irclickid - AWIN / ShareASale: awc, afftrack, sscid - Amazon variants: ascsubtag, linkId, pf_rd_*, pd_rd_* (prefix match) - Mailchimp: mc_cid, mc_eid Plus: hard-rejects known URL-shortener domains (bit.ly, lnkd.in, t.co, buff.ly, goo.gl, tinyurl.com, ow.ly, rebrand.ly) — a shortener can hide an affiliate redirect, and HEAD-unwrapping every link is more failure surface than the rule is worth. Refs #154 Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * feat(adp): lint-changelog.ts requires CHANGELOG entry per touched pattern Detects modified pattern files via `git diff --name-only origin/main...HEAD` and requires that every authored pattern (non-empty oneLineSummary or implementationSketch) has a CHANGELOG entry dated >= today. Two checks: 1. Touched-and-authored patterns must have a CHANGELOG entry >= today. (Empty stubs are skipped — they're scaffolding, not editorial content.) 2. Every CHANGELOG entry's slug must exist in PATTERNS (active OR archived). Catches typos and removed patterns silently invalidating the audit trail. On main itself (no upstream diff) check #1 becomes a no-op. The script falls through `origin/main` → `upstream/main` → `main` to handle clones without an upstream remote. Refs #154 Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * feat(adp): check-pattern-overlap.ts manual editorial tool Surfaces pairs of patterns whose summaries / when-to-use bullets overlap heavily — a smell that the field-of-thought boundary may not be sharp. Runs Jaccard token overlap (with stop words removed) across every active pair and prints any pair above a threshold (default 0.55). NOT wired into pnpm lint and NOT run in CI. Editor runs it on demand when adding a new pattern or restructuring layers. Always exits 0 — the output is informational, not a gate. Usage: tsx scripts/check-pattern-overlap.ts [--threshold=0.55] Refs #154 Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * feat(adp): check-pattern-links.ts walks every external URL Walks every external URL in the catalog (References, realWorldExamples, readerGotcha sources) and reports broken links. Designed to be polite to upstream services: - Per-host concurrency = 1 with a 1-3 second jittered delay between same-host requests. Fanning out 5 in parallel against arXiv hits Cloudflare's rate limiter. - HEAD first, then GET with `Range: bytes=0-0` if the host returns 403 / 405 / 501 (Springer / IEEE / JSTOR are the usual offenders). - Identifying User-Agent (mailto: for Crossref polite-pool eligibility, general courtesy for everyone else; default undici UA gets 403 from many CDNs). Output: structured progress on stderr, JSON summary on stdout. Always exits 0 — the workflow consumes the JSON to file/dedupe issues. We do not fail the lint chain on transient outages. Standalone tool + weekly GitHub Actions workflow (separate commit). NOT wired into pnpm lint. Refs #154 Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * feat(adp): weekly broken-link workflow with issue de-duplication Weekly run (Mondays 14:00 UTC, off-peak for arXiv/IEEE) of scripts/check-pattern-links.ts plus search-or-create issue filing so a multi-week outage doesn't open dozens of identical issues. - permissions: { contents: read, issues: write } (default GITHUB_TOKEN doesn't grant issues:write). - pnpm setup via pnpm/action-setup@v4 + actions/setup-node@v6 with cache: 'pnpm' and pnpm install --frozen-lockfile. - Labels new issues as ['agentic-design-patterns', 'broken-link']. - For each broken URL: search open issues with the broken-link label and matching title; comment on the existing one if found, else create a new. - Uploads link-results.json as a 30-day artifact for forensics. Refs #154 Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * feat(adp): wire pnpm lint:adp + add negative-test fixture runner - Wires `lint` to run `eslint && pnpm run lint:adp`. - `lint:adp` runs the four CI guardrails in order: typecheck-sketches → validate-references → check-affiliate-links → lint-changelog. The two manual tools (check-pattern-overlap, check-pattern-links) are intentionally excluded. - Adds scripts/__fixtures__/run-negative-tests.ts — a manual fixture runner that verifies each guardrail rejects what it should: * Fabricated DOI 10.48550/arXiv.9999.99999 → validate-references exits 1 * URL with ?tag=detachednode-20 → check-affiliate-links exits 1 * Snippet with top-level await + no exports → typecheck-sketches injects `export {}` and compiles cleanly Plus a network-shape sanity probe: real arXiv DOI 10.48550/arXiv.2303.11366 resolves via the OpenAlex fallback (Crossref returns 404 for it). Closes #154 Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
Add core CI workflows and Dependabot configuration
…environment (#76) * fix(env): fail loudly on missing required env vars at module-load Replaces three ad-hoc env reads in payload.config.ts with a single reusable validator (src/lib/env/required-env.ts) that collects ALL missing vars in one Error rather than stopping at the first. Two of those reads previously used `process.env.FOO || ''` and silently defaulted to empty string, masking the real failure behind cryptic Postgres/Payload errors downstream. Adds NEXT_PUBLIC_SERVER_URL to CI workflows (ci-build, bundle-size, e2e-tests) that previously relied on the silent empty-string default. Documents required Preview env vars in docs/deployment.md#preview-environment — the docs anchor referenced by the validator's error message. The one-time `vercel env add PAYLOAD_SECRET preview` action happens post-merge and is tracked in the linked issue. Fixes #73 Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * test: add integration + docs-anchor guards for env preflight Addresses julianken-bot review finding #1 (integration gap) and #2 (docs anchor rot). Unit tests cover the validator in isolation; this test file asserts (a) payload.config.ts still names all three required env vars on failure — a future refactor that trims the list will fail this test — and (b) the docs anchor the error message points at still exists. Per bot review on PR #76. --------- Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…rences, check-affiliate-links, lint-changelog) + workflow (#166) * feat(adp): typecheck-sketches.ts compiles every implementationSketch Compiles every Pattern's implementationSketch through `tsc --noEmit` with flags tuned for snippet-mode TypeScript (`--ignoreConfig --types node --skipLibCheck --lib es2022,dom --module esnext --target es2022 --moduleResolution bundler --strict`). Spike-log lessons applied: - Inject `export {}` automatically when a snippet has no top-level import or export, so top-level await doesn't trip TS1375. - Capture both stdout AND stderr from the tsc subprocess (diagnostics split across both depending on the failure). - Skip patterns whose `sdkAvailability` is `python-only` or `no-sdk` for compilation, but require a "pseudocode" banner so readers aren't misled. Wires into pnpm lint via a later commit. Refs #154 Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * feat(adp): validate-references.ts with Crossref + OpenAlex fallback Verifies that every paper Reference resolves to a real publication by DOI. This is the teeth on the catalog's citation-rigor claim. Critical: arXiv preprint DOIs (`10.48550/arXiv.*`) are NOT indexed by Crossref — Reflexion, Self-Refine, CRITIC and others all return 404 there. The script falls back to OpenAlex on Crossref 404 or network error, hitting `https://api.openalex.org/works/doi:{doi}` (the DOI is NOT URL-encoded inside the `doi:` prefix). Validation: title fuzzy-match (lowercased, accents and punctuation stripped), year exact, first-author surname (after splitting on comma / " and ", trimming " et al."). Politeness: - User-Agent identifies us with `mailto:juliankennon@gmail.com` (Crossref's polite-pool requirement). - 100 ms throttle between requests. - 3-attempt retry with exponential backoff for 5xx. Cache: short-circuits via references.lock.json when a DOI's title / year / surname still match. Lockfile is normalised to pretty-printed JSON for diff-friendliness; the script no-op-skips writing if content is unchanged. Refs #154 Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * feat(adp): check-affiliate-links.ts rejects affiliate query params Refuses to ship Reference URLs / realWorldExample sourceUrls / readerGotcha sourceUrls that carry affiliate or tracking query parameters. Editorial principle: zero affiliate links anywhere in the catalog. Detects (case-insensitive): - Classic: tag, ref, aff, linkCode, via, partner, affiliate, affid, aff_id, partnerid, utm_source_aff - Commission Junction: clickid, cjevent - Impact Radius: irclickid - AWIN / ShareASale: awc, afftrack, sscid - Amazon variants: ascsubtag, linkId, pf_rd_*, pd_rd_* (prefix match) - Mailchimp: mc_cid, mc_eid Plus: hard-rejects known URL-shortener domains (bit.ly, lnkd.in, t.co, buff.ly, goo.gl, tinyurl.com, ow.ly, rebrand.ly) — a shortener can hide an affiliate redirect, and HEAD-unwrapping every link is more failure surface than the rule is worth. Refs #154 Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * feat(adp): lint-changelog.ts requires CHANGELOG entry per touched pattern Detects modified pattern files via `git diff --name-only origin/main...HEAD` and requires that every authored pattern (non-empty oneLineSummary or implementationSketch) has a CHANGELOG entry dated >= today. Two checks: 1. Touched-and-authored patterns must have a CHANGELOG entry >= today. (Empty stubs are skipped — they're scaffolding, not editorial content.) 2. Every CHANGELOG entry's slug must exist in PATTERNS (active OR archived). Catches typos and removed patterns silently invalidating the audit trail. On main itself (no upstream diff) check #1 becomes a no-op. The script falls through `origin/main` → `upstream/main` → `main` to handle clones without an upstream remote. Refs #154 Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * feat(adp): check-pattern-overlap.ts manual editorial tool Surfaces pairs of patterns whose summaries / when-to-use bullets overlap heavily — a smell that the field-of-thought boundary may not be sharp. Runs Jaccard token overlap (with stop words removed) across every active pair and prints any pair above a threshold (default 0.55). NOT wired into pnpm lint and NOT run in CI. Editor runs it on demand when adding a new pattern or restructuring layers. Always exits 0 — the output is informational, not a gate. Usage: tsx scripts/check-pattern-overlap.ts [--threshold=0.55] Refs #154 Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * feat(adp): check-pattern-links.ts walks every external URL Walks every external URL in the catalog (References, realWorldExamples, readerGotcha sources) and reports broken links. Designed to be polite to upstream services: - Per-host concurrency = 1 with a 1-3 second jittered delay between same-host requests. Fanning out 5 in parallel against arXiv hits Cloudflare's rate limiter. - HEAD first, then GET with `Range: bytes=0-0` if the host returns 403 / 405 / 501 (Springer / IEEE / JSTOR are the usual offenders). - Identifying User-Agent (mailto: for Crossref polite-pool eligibility, general courtesy for everyone else; default undici UA gets 403 from many CDNs). Output: structured progress on stderr, JSON summary on stdout. Always exits 0 — the workflow consumes the JSON to file/dedupe issues. We do not fail the lint chain on transient outages. Standalone tool + weekly GitHub Actions workflow (separate commit). NOT wired into pnpm lint. Refs #154 Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * feat(adp): weekly broken-link workflow with issue de-duplication Weekly run (Mondays 14:00 UTC, off-peak for arXiv/IEEE) of scripts/check-pattern-links.ts plus search-or-create issue filing so a multi-week outage doesn't open dozens of identical issues. - permissions: { contents: read, issues: write } (default GITHUB_TOKEN doesn't grant issues:write). - pnpm setup via pnpm/action-setup@v4 + actions/setup-node@v6 with cache: 'pnpm' and pnpm install --frozen-lockfile. - Labels new issues as ['agentic-design-patterns', 'broken-link']. - For each broken URL: search open issues with the broken-link label and matching title; comment on the existing one if found, else create a new. - Uploads link-results.json as a 30-day artifact for forensics. Refs #154 Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * feat(adp): wire pnpm lint:adp + add negative-test fixture runner - Wires `lint` to run `eslint && pnpm run lint:adp`. - `lint:adp` runs the four CI guardrails in order: typecheck-sketches → validate-references → check-affiliate-links → lint-changelog. The two manual tools (check-pattern-overlap, check-pattern-links) are intentionally excluded. - Adds scripts/__fixtures__/run-negative-tests.ts — a manual fixture runner that verifies each guardrail rejects what it should: * Fabricated DOI 10.48550/arXiv.9999.99999 → validate-references exits 1 * URL with ?tag=detachednode-20 → check-affiliate-links exits 1 * Snippet with top-level await + no exports → typecheck-sketches injects `export {}` and compiles cleanly Plus a network-shape sanity probe: real arXiv DOI 10.48550/arXiv.2303.11366 resolves via the OpenAlex fallback (Crossref returns 404 for it). Closes #154 Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Summary
tsc --noEmit) as two parallel jobs on push/PR to mainAll workflows use pnpm 9, Node 20, frozen lockfile installs, concurrency groups with cancel-in-progress, and reasonable timeouts.
Test plan
🤖 Generated with Claude Code