@se-studio/skills 1.4.1 → 1.4.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,21 @@
1
1
  # @se-studio/skills
2
2
 
3
+ ## 1.4.3
4
+
5
+ ### Patch Changes
6
+
7
+ - Document SSG guardrails (Biome, route-build-policy, validate-build-routes) in se-marketing-sites-smoke-test-setup skill.
8
+
9
+ ## 1.4.2
10
+
11
+ ### Patch Changes
12
+
13
+ - Add flat navigation assembly via `getNavigation` in `createAppHelpers` — menus resolve without Contentful include depth. Registry and link-index fetchers stay package-internal so apps cannot call them directly.
14
+
15
+ Flat-nav caches use collection tags (`FLAT_NAV_CACHE_TAGS`, including `tagType` and `link`) for webhook invalidation, with `FLAT_NAV_TIME_REVALIDATE_SECONDS` (3600) as an ISR fallback when webhooks miss.
16
+
17
+ Fix flat-nav Contentful fetches for spaces with differing content models (e.g. OM1): registry and link-wrapper fetches omit `select`; tagType bulk link fetches request golden `fields.slug` and fall back to minimal fields when absent. Unresolved nav targets log under `LOG_CMS`.
18
+
3
19
  ## 1.4.1
4
20
 
5
21
  ### Patch Changes
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@se-studio/skills",
3
- "version": "1.4.1",
3
+ "version": "1.4.3",
4
4
  "description": "SE Studio agent skills for marketing site development with Contentful CMS",
5
5
  "repository": {
6
6
  "type": "git",
@@ -270,8 +270,67 @@ Remove legacy `smoke-test:validate-links`, `smoke-test-preload.cjs`, and bespoke
270
270
  3. Update `@se-studio/site-check` to `^2.6.1` when adopting integrity; otherwise `^2.1.2` minimum.
271
271
  4. Follow workflow above to create `smoke.cases.json`.
272
272
 
273
+ ## SSG guardrails (all marketing sites)
274
+
275
+ Prevent `DYNAMIC_SERVER_USAGE` / production 500s on on-demand SSG routes (`●` in `next build`). Three layers — lint, build policy, production smoke.
276
+
277
+ ### 1. Biome — ban dynamic request APIs in SSG surfaces
278
+
279
+ Copy the override block from `@se-studio/site-check/templates/biome-ssg-guardrails.override.json` into the app `biome.json` `overrides` array.
280
+
281
+ Restricts request-time Next.js APIs in:
282
+
283
+ - `src/app/layout.tsx`
284
+ - `src/app/(cms-routes)/**`
285
+ - `src/project/**`
286
+
287
+ Banned: `next/headers` (headers, cookies, draftMode), `connection` from `next/server`, `unstable_noStore` from `next/cache`. `unstable_cache` and other `next/cache` exports remain allowed.
288
+
289
+ Dynamic by design (no restriction): `(cms-dev)`, `preview`, `api`, `middleware.ts`.
290
+
291
+ Lint is necessary but not sufficient — route policy + production smoke still required.
292
+
293
+ Runs on every `pnpm check` / `pnpm validate`.
294
+
295
+ ### 2. Build route policy — no surprise `ƒ` on CMS segment routes
296
+
297
+ Requires `@se-studio/site-check` **^2.7.0**.
298
+
299
+ Commit `route-build-policy.json` beside `smoke.cases.json`. Start from `@se-studio/site-check/templates/route-build-policy.example.json` and adjust route segments to match the app.
300
+
301
+ ```json
302
+ {
303
+ "allowedDynamic": ["/", "/articles", "/tags", "/people", "/_not-found"],
304
+ "mustBeSsgOrStatic": [
305
+ "/[level1]",
306
+ "/[level1]/[...slugs]",
307
+ "/articles/[articleType]",
308
+ "/articles/[articleType]/[...slugs]"
309
+ ]
310
+ }
311
+ ```
312
+
313
+ - `mustBeSsgOrStatic` — must be `●` or `○` in `next build`, never `ƒ`.
314
+ - `allowedDynamic` — documents known `ƒ` routes; fail if a new `ƒ` appears without updating the policy.
315
+
316
+ **Scripts:**
317
+
318
+ ```json
319
+ "validate:routes": "validate-build-routes",
320
+ "validate": "pnpm check && pnpm type-check && pnpm validate:routes"
321
+ ```
322
+
323
+ `validate-build-routes` runs `pnpm build` and compares the Route (app) table to the policy. `smoke-test-one` also validates after build when `route-build-policy.json` exists (`SMOKE_TEST_VALIDATE_ROUTES=false` to skip).
324
+
325
+ ### 3. Production smoke (runtime safety net)
326
+
327
+ `pnpm smoke-test:cache` / `smoke-test:deploy-check` catches breakage lint/policy miss. Keep mandatory in CI / Vercel build gates.
328
+
329
+ **HubSpot bootstrap:** use `createHubSpotBootstrapScript()` with no args in root layout — not `headers()` + middleware pathname.
330
+
273
331
  ## Reference
274
332
 
275
333
  - HTTP + integrity example: `apps/example-empty/smoke.cases.json` and `scripts/smoke-test-run.ts` (monorepo).
276
- - Package API: `runStaticSmokeTest`, `runStaticSmokeTestWithIntegrity`, `runPreviewStaticSmokeTest`, `auditCacheLogs` from `@se-studio/site-check/smoke-test`.
334
+ - SSG guardrails reference app: `apps/example-empty/route-build-policy.json` and `biome.json` overrides.
335
+ - Package API: `runStaticSmokeTest`, `runStaticSmokeTestWithIntegrity`, `runPreviewStaticSmokeTest`, `auditCacheLogs`, `validateBuildRoutesFromBuildOutput` from `@se-studio/site-check/smoke-test`.
277
336
  - CMS integrity types: `@se-studio/site-check/cms-integrity`.
@@ -75,6 +75,7 @@ The secret is passed as a **request header** (`REVALIDATION_SECRET`), not a quer
75
75
  * 5. Updates .env.local with the new secret
76
76
  */
77
77
 
78
+ import { REVALIDATION_WEBHOOK_ENTRY_CONTENT_TYPES } from '@se-studio/contentful-rest-api';
78
79
  import { createClient } from 'contentful-management';
79
80
  import { randomBytes } from 'node:crypto';
80
81
  import { spawnSync } from 'node:child_process';
@@ -149,13 +150,8 @@ const WEBHOOK_NAME = 'Vercel Revalidation';
149
150
  const ASSET_WEBHOOK_NAME = 'Vercel Revalidation (Assets)';
150
151
  const PREVIEW_WEBHOOK_NAME = 'Vercel Revalidation (Preview)';
151
152
 
152
- const ENTRY_CONTENT_TYPES = [
153
- 'article', 'articleType', 'banner', 'customType', 'location',
154
- 'navigation', 'page', 'pageVariant', 'person', 'tag', 'template',
155
- ];
156
-
157
153
  const contentTypeFilter = {
158
- in: [{ doc: 'sys.contentType.sys.id' }, ENTRY_CONTENT_TYPES],
154
+ in: [{ doc: 'sys.contentType.sys.id' }, [...REVALIDATION_WEBHOOK_ENTRY_CONTENT_TYPES]],
159
155
  };
160
156
 
161
157
  async function main(): Promise<void> {
@@ -0,0 +1,134 @@
1
+ ---
2
+ name: vercel-logs-audit
3
+ description: "Pull and triage Vercel error logs across SE Studio marketing sites (develop + production). Use when checking production errors, monitoring Vercel runtime issues, or running incremental log audits."
4
+ ---
5
+
6
+ # Vercel logs audit
7
+
8
+ Cross-project error monitoring for the 7 marketing sites in `docs/vercel-logs/projects.registry.json`.
9
+
10
+ **Requires:** Vercel CLI (`vercel`), authenticated via `vercel login` or `VERCEL_TOKEN` in `.env.local`.
11
+
12
+ **Output:** Generated under `docs/vercel-logs/` — **do not commit** except `projects.registry.json` and `README.md`.
13
+
14
+ ---
15
+
16
+ ## Quick start
17
+
18
+ From repo root:
19
+
20
+ ```bash
21
+ # Full pipeline: pull → filter → analyze
22
+ pnpm vercel-logs
23
+
24
+ # Subset
25
+ pnpm vercel-logs --sites se2026,brightline --envs develop
26
+
27
+ # Re-backfill 7 days (resets checkpoints for selected targets)
28
+ pnpm vercel-logs --full
29
+
30
+ # Plan fetches without calling Vercel
31
+ pnpm vercel-logs:pull --dry-run
32
+ ```
33
+
34
+ Individual steps:
35
+
36
+ ```bash
37
+ pnpm vercel-logs:pull
38
+ pnpm vercel-logs:filter
39
+ pnpm vercel-logs:analyze
40
+ ```
41
+
42
+ ---
43
+
44
+ ## Incremental behaviour
45
+
46
+ | Run | Window |
47
+ |-----|--------|
48
+ | First run (no `state.json`) | Last **7 days** per site × environment |
49
+ | Subsequent runs | Since last checkpoint minus 5-minute overlap |
50
+ | `--full` | Clears checkpoints and re-backfills 7 days |
51
+ | `--since 2d` | Override start time for selected pull |
52
+
53
+ Checkpoints live in `docs/vercel-logs/state.json` (gitignored).
54
+
55
+ If a pull hits the Vercel log limit, the checkpoint is set to the **oldest fetched timestamp** (not `now`) so the next run can backfill older entries.
56
+
57
+ ---
58
+
59
+ ## Pipeline steps
60
+
61
+ | Step | Input | Output |
62
+ |------|-------|--------|
63
+ | `pull` | Vercel CLI | `raw/<runId>/.../logs.jsonl` (raw JSON) |
64
+ | `filter` | Raw JSONL + manifests | `errors/<runId>.jsonl` (normalized) |
65
+ | `analyze` | Filtered JSONL | `reports/<runId>-summary.md` |
66
+
67
+ ---
68
+
69
+ ## Teams and projects
70
+
71
+ The registry maps each site to a Vercel project and team scope:
72
+
73
+ | Team | Sites |
74
+ |------|-------|
75
+ | `se-studio` | se2026, om1, pedestal, headwater |
76
+ | `brightline` | brightline, brightlifekids |
77
+ | `engineeringpointmes-projects` | pointme |
78
+
79
+ Your Vercel account must have access to all three teams. Verify with `vercel whoami`.
80
+
81
+ ---
82
+
83
+ ## Reading results
84
+
85
+ After `pnpm vercel-logs:analyze`, open:
86
+
87
+ `docs/vercel-logs/reports/<runId>-summary.md`
88
+
89
+ Triage in this order:
90
+
91
+ 1. **By site × environment** — which deploy surface is failing?
92
+ 2. **Top messages** — group identical errors (often one root cause)
93
+ 3. **Status codes** — 5xx vs application-level errors
94
+ 4. **Sample paths** — affected routes
95
+ 5. **Changes since previous run** — new regressions
96
+
97
+ Filtered entries: `docs/vercel-logs/errors/<runId>.jsonl`
98
+
99
+ Exit code **2** from analyze means errors were found (useful for future CI).
100
+
101
+ ---
102
+
103
+ ## What counts as an error
104
+
105
+ Pull uses two CLI passes per target:
106
+
107
+ - Log level `error` or `fatal`
108
+ - HTTP status `500`–`508`
109
+
110
+ Filter normalizes raw JSON and keeps entries matching:
111
+
112
+ - Log level `error` or `fatal`
113
+ - HTTP status `5xx`
114
+
115
+ Optional: `pnpm vercel-logs:filter --include-warnings`
116
+
117
+ ---
118
+
119
+ ## Troubleshooting
120
+
121
+ | Problem | Fix |
122
+ |---------|-----|
123
+ | `vercel logs failed` / auth error | `vercel login` or set `VERCEL_TOKEN` |
124
+ | Wrong team / project not found | Check `team` in `projects.registry.json`; use `vercel projects ls --scope <team>` |
125
+ | No targets matched | Check `--sites` / `--envs` keys match registry `key` fields |
126
+ | Empty report after errors expected | Widen with `--full` or `--since 7d`; confirm develop uses `--branch develop` |
127
+
128
+ ---
129
+
130
+ ## Maintenance
131
+
132
+ - Registry: `docs/vercel-logs/projects.registry.json`
133
+ - Scripts: `scripts/vercel-logs/`
134
+ - Tests: `pnpm vercel-logs:test`