@se-studio/skills 1.5.8 → 1.5.11

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,17 @@
1
1
  # @se-studio/skills
2
2
 
3
+ ## 1.5.11
4
+
5
+ ### Patch Changes
6
+
7
+ - Document smoke/deploy failure playbook and refuse-customer-patches guardrails (agent-session Step 3b).
8
+
9
+ ## 1.5.10
10
+
11
+ ### Patch Changes
12
+
13
+ - Document lockfile sync enforcement (scripts, CI snippet, deps-update and smoke-test skill updates).
14
+
3
15
  ## 1.5.8
4
16
 
5
17
  ### Patch Changes
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@se-studio/skills",
3
- "version": "1.5.8",
3
+ "version": "1.5.11",
4
4
  "description": "SE Studio agent skills for marketing site development with Contentful CMS",
5
5
  "repository": {
6
6
  "type": "git",
@@ -22,6 +22,16 @@ Before non-trivial code, run the placement checklist (in the skill). Summary:
22
22
 
23
23
  If the checklist says **core**, stop and switch to core-first mode — do not patch `@se-studio` behaviour in this repo.
24
24
 
25
+ ### Deploy smoke failed?
26
+
27
+ Do **not** change `baseUrl`, discovery routes, or add `getRequestBaseUrl()` to unblock Vercel Deployment Checks. That fix belongs in `@se-studio/site-check` (core-first).
28
+
29
+ 1. Follow the smoke/deploy failure playbook in `se-core-product` — `packages/skills/references/agent-session/smoke-deploy-failure-playbook.md`
30
+ 2. Bump `@se-studio/site-check@2.9.4+` after npm publish (`discovery.urlOrigin: auto`)
31
+ 3. Customer-only: curate new URLs in `smoke.cases.json` when CMS routes go live — not package assertion hacks
32
+
33
+ Record `placement.decision` in `work/active/<feature>.yaml` before smoke/server-config commits aimed at deploy smoke.
34
+
25
35
  ### Core release order
26
36
 
27
37
  When work depends on a new `@se-studio/*` npm release:
@@ -19,6 +19,8 @@ placement:
19
19
  rationale: One-site hero layout tied to OM1 Figma
20
20
  extract_to_core: null # pending | null
21
21
  extract_rationale: null
22
+ # Required before smoke/server-config commits for deploy-smoke goals (agent-session Step 3b):
23
+ # smoke_edit: null # curated-urls | blocked-on-core | defer-extract
22
24
 
23
25
  blocked_on: null # e.g. "@se-studio/core-ui@2.1.0"
24
26
  cms_session: null # set to feature slug when doing parallel CMS edits
@@ -13,13 +13,7 @@
13
13
  "branch": "dev",
14
14
  "type": "core",
15
15
  "validate": "pnpm validate",
16
- "exampleApps": [
17
- "example-om1",
18
- "example-se2026",
19
- "example-brightline",
20
- "example-brightlifekids",
21
- "example-empty"
22
- ]
16
+ "exampleApps": ["example-empty", "cms-edit-host"]
23
17
  },
24
18
  {
25
19
  "key": "se2026",
@@ -0,0 +1,58 @@
1
+ # Refuse customer patches (site-first guardrails)
2
+
3
+ Agents in **site-first** mode must **refuse** customer-repo changes that belong in **`se-core-product`** (`@se-studio/*`), unless the user explicitly approves **`defer-extract`** in the manifest with `extract_to_core: pending` and a dated extraction plan.
4
+
5
+ Run this table **in addition to** the placement checklist (`site-workflows-agent-session` Step 3) when the task touches smoke, deploy checks, shared packages, or infra.
6
+
7
+ ## Refusal triggers
8
+
9
+ | Symptom, file, or request | Correct owner | Agent action (site-first) |
10
+ |---------------------------|---------------|---------------------------|
11
+ | Deploy / `smoke-test:live` failure after bumping `@se-studio/*` | **core** — fix package behaviour | **Stop.** Switch to core-first or set `blocked_on: "@se-studio/<pkg>@<version>"`. Customer only bumps after npm publish. |
12
+ | Discovery smoke (`llms.txt`, `markdown-index.txt`, `cms.txt`, `site-info.md`) origin mismatch on `*.vercel.app` | **core** — `@se-studio/site-check` (`discovery.urlOrigin`) | **Refuse** per-request origin hacks (`getRequestBaseUrl`, `headers()` for `baseUrl`). Bump `site-check@2.9.4+`. |
13
+ | Patching `@se-studio/site-check` expectations in app code | **core** `site-check` | **Refuse.** Open core PR + changeset. |
14
+ | Forking converter / link logic already in `contentful-rest-api` | **core** | **Refuse.** Fix converter or API in core. |
15
+ | `pnpm patch`, `patchedDependencies`, or overrides to fork `@se-studio/*` | **forbidden** | **Refuse** (see root `AGENTS.md`). |
16
+ | New smoke assertion that should apply to all marketing sites | **core** `site-check` | **Refuse** site-only assertion helpers; extend site-check. |
17
+ | `route-build-policy.json` change to hide a core regression (e.g. allow new `ƒ` on CMS routes) | **core** + site routing fix | **Refuse** policy-only workaround; fix why route went dynamic. |
18
+
19
+ ## Allowed customer-only smoke edits
20
+
21
+ | Change | When |
22
+ |--------|------|
23
+ | Add/remove **curated URLs** in `smoke.cases.json` | New CMS pages, article types, tags/people go live — follow `se-marketing-sites-smoke-test-setup` |
24
+ | Set `discovery` flags to `false` | Site-specific infra (e.g. CloudFront not routing discovery paths yet) |
25
+ | `cmsIntegrity.routing` mapping | Per-site URL calculators — not a package bug |
26
+ | Security **probe** cases (`category: probe`) | Site-specific hardening (see brightline reference) |
27
+
28
+ ## `defer-extract` (escape hatch)
29
+
30
+ Use only when the user **explicitly** accepts short-term customer code with a core extraction ticket:
31
+
32
+ 1. Manifest `placement.decision: defer-extract`
33
+ 2. `extract_to_core: pending` + `extract_rationale` (what moves to which package)
34
+ 3. Add `work/tracker.yaml` rollout or `attention` item if multi-site
35
+ 4. **Do not** merge to customer `develop` if it blocks other sites on a shared package fix
36
+
37
+ ## Manifest gate
38
+
39
+ Before committing customer changes to any of:
40
+
41
+ - `smoke.cases.json`, `route-build-policy.json`
42
+ - `src/lib/server-config.ts`, discovery route handlers (`llms.txt`, `markdown-index.txt`, …)
43
+ - `scripts/smoke-test-*.ts`, `.github/workflows/deployment-smoke.yml`
44
+
45
+ …when the **stated goal** is “fix deploy smoke” or “fix site-check failure”:
46
+
47
+ 1. Record `placement.decision` and `placement.rationale` in `work/active/<feature>.yaml`
48
+ 2. If decision is `core`: **do not commit customer workaround** — switch mode
49
+ 3. If decision is `customer`: user must confirm in chat (legitimate site-only URL curation)
50
+ 4. If decision is `defer-extract`: user must confirm extraction plan in chat
51
+
52
+ ## Emergency bypass (temporary only)
53
+
54
+ - `SMOKE_TEST_IGNORE=true` on a single deploy
55
+ - `workflow_dispatch` deployment smoke against a known-good URL
56
+ - Skip Vercel Deployment Check with **human** approval
57
+
58
+ Never treat emergency bypass as permission to land a permanent customer patch for `@se-studio/*` behaviour.
@@ -0,0 +1,80 @@
1
+ # Smoke / deploy failure playbook
2
+
3
+ When **local smoke**, **`smoke-test:live`**, or **Vercel Deployment Checks** fail, follow this sequence. Do **not** patch customer origin/URL logic to satisfy `@se-studio/site-check` assertions.
4
+
5
+ Full refusal rules: [`refuse-customer-patches.md`](./refuse-customer-patches.md).
6
+
7
+ ## 1. Classify the failure
8
+
9
+ Read the failing step and package:
10
+
11
+ | Failure mentions | Likely owner |
12
+ |------------------|--------------|
13
+ | `discovery`, `llms.txt`, `markdown-index.txt`, `urlOrigin`, canonical origin | `@se-studio/site-check` |
14
+ | `article link integrity`, `cmsIntegrity` | `@se-studio/site-check` + site `routing` config (customer OK) or `contentful-rest-api` (core) |
15
+ | `route-build-policy`, `mustBeSsgOrStatic`, `ƒ` on CMS route | Site introduced dynamic APIs — fix site routing/layout **or** core if shared helper caused it |
16
+ | HTML 404/500 on a **curated** smoke path | Site content/routing or CMS — usually **customer** |
17
+ | Lockfile / install on Vercel | Customer lockfile sync — see `lockfile-sync` reference, not site-check |
18
+
19
+ ## 2. If `@se-studio/*` behaviour is wrong → core-first
20
+
21
+ 1. Set manifest `mode: core-first` (or stop and ask user to switch).
22
+ 2. Fix in `packages/<pkg>/`, add **changeset**, run package tests.
23
+ 3. Push `dev` → wait for CI npm publish.
24
+ 4. Add/update `work/tracker.yaml` **rollout** for customer bumps.
25
+ 5. Set customer manifest `blocked_on: "@se-studio/<pkg>@<version>"` until npm confirms.
26
+
27
+ **Customer repo during wait:** only dependency bump via `pnpm update` — no `baseUrl` / origin / assertion hacks.
28
+
29
+ ## 3. If site content/routing is wrong → site-first
30
+
31
+ Examples: wrong slug in `smoke.cases.json`, page unpublished, new article type needs a case.
32
+
33
+ 1. Confirm placement `customer`.
34
+ 2. Refresh cases from production sitemap (`se-marketing-sites-smoke-test-setup` skill).
35
+ 3. Run `pnpm smoke-test:run` locally; `pnpm smoke-test:preview` against develop preview if needed.
36
+
37
+ ## 4. Discovery canonical origin (known anti-pattern)
38
+
39
+ **Symptom:** Deploy smoke hits `https://<project>-<hash>.vercel.app` but `llms.txt` / `markdown-index.txt` list `https://www.example.com/...` links. Smoke fails origin check.
40
+
41
+ **Wrong fix (refuse):**
42
+
43
+ - `getRequestBaseUrl()` from request headers in `server-config` or discovery routes
44
+ - Rewriting discovery output to match deployment host permanently
45
+
46
+ **Right fix:**
47
+
48
+ 1. Core: `@se-studio/site-check@2.9.4+` with `discovery.urlOrigin: auto` (default in smoke runner).
49
+ 2. Customer: `pnpm update @se-studio/site-check@2.9.4 -r`, keep canonical `baseUrl` in app config.
50
+ 3. Tracker rollout: `site-check-discovery-canonical` in `work/tracker.yaml`.
51
+
52
+ ## 5. Emergency unblock (human or agent with explicit approval)
53
+
54
+ | Action | Use when |
55
+ |--------|----------|
56
+ | `workflow_dispatch` deployment smoke | Re-test after core fix + customer bump |
57
+ | `SMOKE_TEST_IGNORE=true` | One-off deploy; document in manifest notes |
58
+ | Human approves blocked Deployment Check | Production promotion already reviewed |
59
+
60
+ Record what was bypassed and the real fix still required (core PR / npm bump).
61
+
62
+ ## 6. Validate before customer push
63
+
64
+ | Check | Command |
65
+ |-------|---------|
66
+ | Local HTTP smoke | `pnpm smoke-test:run` |
67
+ | Preview smoke | `pnpm smoke-test:preview` (develop URL + bypass token) |
68
+ | After core bump | `pnpm update @se-studio/site-check@<version> -r` then re-run smoke |
69
+ | Route policy | `pnpm validate:routes` when Contentful creds available in CI |
70
+
71
+ Deployment checks stay **HTTP-only** — never enable `cmsIntegrity` on Vercel live smoke.
72
+
73
+ ## 7. Handoff
74
+
75
+ Include in manifest / handoff:
76
+
77
+ - Root cause (core vs customer)
78
+ - Published package versions required
79
+ - Tracker rollout id
80
+ - Whether any emergency bypass was used
@@ -70,7 +70,7 @@ Invoke the skill with:
70
70
  **Example: merge only**
71
71
 
72
72
  ```bash
73
- cms-merge-guidelines --app-dir apps/example-om1
73
+ cms-merge-guidelines --app-dir apps/example-empty
74
74
  ```
75
75
 
76
76
  ---
@@ -51,7 +51,7 @@ or manually follow the steps below.
51
51
  ## Cursor agent task
52
52
 
53
53
  **Assign this task to a Cursor subagent.** Provide:
54
- - `apps/example-brightline/src/project/components/<TypeName>.tsx` (component source)
54
+ - `<app-dir>/src/project/components/<TypeName>.tsx` (e.g. `apps/example-empty` or a customer app path)
55
55
  - `generated/cms-discovery/field-list.json` (field metadata including enum values)
56
56
  - `generated/cms-discovery/theme-context.md` (palette + typography — authoritative colour names)
57
57
  - `scripts/guidelines/variant-proposal-prompt.md` (variant proposal instructions)
@@ -121,7 +121,7 @@ Example for Hero:
121
121
  ### 2 — Capture screenshots
122
122
 
123
123
  ```bash
124
- # From apps/example-brightline
124
+ # From the target app directory (e.g. apps/example-empty)
125
125
  node scripts/guidelines/capture-screenshots.mjs --variants /tmp/hero-variants.json
126
126
  ```
127
127
 
@@ -0,0 +1,54 @@
1
+ # Lockfile sync enforcement
2
+
3
+ Keep `pnpm-lock.yaml` aligned with every `package.json` and `pnpm-workspace.yaml` change.
4
+
5
+ ## Layers
6
+
7
+ | Layer | What it catches |
8
+ |-------|-----------------|
9
+ | **Pre-commit** | Manifest changed without staged lockfile; default frozen install drift |
10
+ | **CI validate** | Frozen install on integration branch (`develop` / `dev`) and PRs |
11
+ | **CI hoisted job** | cms-edit Vercel path (`--config.node-linker=hoisted`) — platform optional deps |
12
+ | **Vercel installCommand** | `--frozen-lockfile` on marketing sites; hoisted + frozen on cms-edit host |
13
+
14
+ ## Scripts (copy from se-core-product `scripts/`)
15
+
16
+ - `check-lockfile-sync.sh` — full (`default` + `hoisted`) or `--quick` (default only)
17
+ - `pre-commit-lockfile.sh` — wire into `.husky/pre-commit` before lint-staged
18
+
19
+ ## CI snippet
20
+
21
+ See [`validate-workflow-snippet.yml`](validate-workflow-snippet.yml). Customer monorepos should:
22
+
23
+ 1. Run validate on **`develop`** (or your integration branch), not only `main`.
24
+ 2. Add a parallel `lockfile-hoisted` job when `cms-edit/host/.npmrc` has `node-linker=hoisted`.
25
+
26
+ ## Vercel
27
+
28
+ | Project type | installCommand |
29
+ |--------------|----------------|
30
+ | Marketing app (monorepo root install) | `cd ../.. && pnpm install --frozen-lockfile` |
31
+ | cms-edit host | `cd ../.. && pnpm install --frozen-lockfile --config.node-linker=hoisted` |
32
+
33
+ ## After dependency changes
34
+
35
+ ```bash
36
+ pnpm install # repo root — never pnpm install -r for lockfile refresh
37
+ git add package.json pnpm-lock.yaml pnpm-workspace.yaml
38
+ ```
39
+
40
+ Use `pnpm install --no-frozen-lockfile` only when intentionally repairing the lockfile.
41
+
42
+ ## Rollout status (customer repos)
43
+
44
+ Apply the full stack when touching deps or CI in each repo:
45
+
46
+ | Repo | Pre-commit | CI develop/dev | CI hoisted | Vercel frozen (marketing) |
47
+ |------|------------|----------------|------------|---------------------------|
48
+ | brightline-sites | yes | yes | yes | yes |
49
+ | pedestal-sites | — | partial | — | no |
50
+ | om1-website | — | — | — | — |
51
+ | se-website-2026 | yes | yes | yes | yes |
52
+ | pointme | — | — | — | — |
53
+
54
+ Update this table as repos adopt the pattern.
@@ -0,0 +1,32 @@
1
+ # Append to .github/workflows/validate.yml (or equivalent CI workflow).
2
+ # Run on the integration branch (develop / dev), not only main.
3
+
4
+ on:
5
+ push:
6
+ branches: [main, develop] # or [main, dev] for se-core-product consumers
7
+ pull_request:
8
+
9
+ jobs:
10
+ validate:
11
+ runs-on: ubuntu-latest
12
+ steps:
13
+ - uses: actions/checkout@v4
14
+ - uses: pnpm/action-setup@v4
15
+ - uses: actions/setup-node@v4
16
+ with:
17
+ node-version: '24'
18
+ cache: pnpm
19
+ - run: pnpm install --frozen-lockfile
20
+ - run: pnpm validate
21
+
22
+ # Required when cms-edit/host (or apps/cms-edit-host) uses node-linker=hoisted.
23
+ lockfile-hoisted:
24
+ runs-on: ubuntu-latest
25
+ steps:
26
+ - uses: actions/checkout@v4
27
+ - uses: pnpm/action-setup@v4
28
+ - uses: actions/setup-node@v4
29
+ with:
30
+ node-version: '24'
31
+ cache: pnpm
32
+ - run: pnpm install --frozen-lockfile --config.node-linker=hoisted
@@ -48,7 +48,7 @@ Guidelines are only meaningful when the showcase is populated with realistic dat
48
48
 
49
49
  | Input | Description |
50
50
  |---|---|
51
- | **App directory** | Repo-relative path, e.g. `apps/example-om1` or `apps/example-se2026` |
51
+ | **App directory** | Repo-relative path, e.g. `apps/example-empty` in this monorepo, or an app path in a customer repo (see `docs/RELATED_PROJECTS.md`) |
52
52
  | **Mode** | `full` \| `single` \| `merge-only` |
53
53
  | **Type name** | Required for `single` mode — the exact type name from discovery, e.g. `"Hero"` or `"Cards Grid"` |
54
54
  | **Discovery URL** | `http://localhost:<PORT>/api/cms/discovery/` — `<PORT>` from the running dev server (`pnpm dev`) |
@@ -94,7 +94,7 @@ mkdir -p scripts
94
94
  cp node_modules/@se-studio/skills/skills/performance-audit/lighthouse.ts scripts/lighthouse.ts
95
95
  ```
96
96
 
97
- Or copy from `apps/example-se2026/scripts/lighthouse.ts` in the se-core-product monorepo if you have it available.
97
+ Or copy from a customer site repo if available (e.g. `se-website-2026/scripts/lighthouse.ts`). This monorepo only ships `apps/example-empty`.
98
98
 
99
99
  **Customise `PAGES` for the project** — edit the `PAGES` array near the top of the script. Choose representative pages: homepage, a list/index page, and a detail page. Use the sitemap to identify good candidates:
100
100
 
@@ -5,7 +5,7 @@ description: "Guide for the (cms-routes) route group and appShared pattern. Use
5
5
 
6
6
  # CMS Routes and appShared Pattern
7
7
 
8
- Reference apps: **example-se2026**, **example-brightline**, **example-om1**. (example-om1 uses `resources/`, `team/`, `topics/` instead of `articles/`, `people/`, `tags/`.)
8
+ Reference app: **example-empty** (this monorepo). Customer sites with fuller route sets: see `docs/RELATED_PROJECTS.md` (e.g. OM1 uses `resources/`, `team/`, `topics/` instead of `articles/`, `people/`, `tags/`).
9
9
 
10
10
  ## Route Group: (cms-routes)
11
11
 
@@ -7,7 +7,7 @@ description: "Guide for creating new Next.js App Router pages and dynamic routes
7
7
 
8
8
  This guide explains how to create new pages and handle routing in the SE Core Product Next.js framework. The system uses Next.js App Router with Contentful-driven dynamic routing.
9
9
 
10
- Reference apps: **example-se2026**, **example-brightline**, **example-om1**.
10
+ Reference app: **example-empty** (this monorepo). Customer implementations: see `docs/RELATED_PROJECTS.md`.
11
11
 
12
12
  ## Page Architecture
13
13
 
@@ -5,7 +5,7 @@ description: "Guide for the lib directory structure in SE Core Product CMS apps.
5
5
 
6
6
  # Lib Directory Structure
7
7
 
8
- Reference apps: **example-se2026**, **example-brightline**, **example-om1**.
8
+ Reference app: **example-empty** (this monorepo). Customer implementations: see `docs/RELATED_PROJECTS.md`.
9
9
 
10
10
  ## File Responsibilities
11
11
 
@@ -52,6 +52,8 @@ Example `package.json` entries:
52
52
  }
53
53
  ```
54
54
 
55
+ **Lockfile CI** — before deployment smoke, ensure `.github/workflows/validate.yml` runs `pnpm install --frozen-lockfile` on the integration branch (`develop` / `dev`) and PRs, plus a parallel `lockfile-hoisted` job when cms-edit uses `node-linker=hoisted`. Copy scripts and workflow snippet from [`references/lockfile-sync/`](../../references/lockfile-sync/README.md). Marketing `vercel.json` install commands must use `--frozen-lockfile`.
56
+
55
57
  **Vercel Deployment Check (live URL)** — GitHub Action on `vercel.deployment.ready` tests `client_payload.url` before production domains alias. Workflow must live on the repo **default branch**. Register the status `name` in Vercel → Settings → Build and Deployment → Deployment Checks.
56
58
 
57
59
  Filter on `client_payload.environment == 'production'` when Deployment Checks target production only. Vercel also dispatches for preview and custom environments (`preview`, `develop`, etc.); skip those to avoid duplicate CI runs. Use `workflow_dispatch` without an environment filter for manual smoke against any URL.
@@ -375,6 +377,24 @@ Commit `route-build-policy.json` beside `smoke.cases.json`. Start from `@se-stud
375
377
 
376
378
  **HubSpot bootstrap:** use `createHubSpotBootstrapScript()` with no args in root layout — not `headers()` + middleware pathname.
377
379
 
380
+ ## Deploy / live smoke failure playbook
381
+
382
+ When **`pnpm smoke-test:live`**, Vercel Deployment Checks, or preview smoke fail after a dependency bump, **do not** patch customer `baseUrl`/origin logic to satisfy `@se-studio/site-check`.
383
+
384
+ **Playbook:** [`packages/skills/references/agent-session/smoke-deploy-failure-playbook.md`](../../references/agent-session/smoke-deploy-failure-playbook.md)
385
+
386
+ **Refusal rules:** [`packages/skills/references/agent-session/refuse-customer-patches.md`](../../references/agent-session/refuse-customer-patches.md) (agent-session Step 3b)
387
+
388
+ Quick sequence:
389
+
390
+ 1. **Classify** — discovery/origin → `site-check`; broken slug → customer `smoke.cases.json`; new `ƒ` route → fix dynamic APIs.
391
+ 2. **Core-first** if package behaviour is wrong — changeset, push `dev`, tracker rollout, customer `blocked_on` until npm.
392
+ 3. **Customer-only** if curating URLs — refresh from sitemap; one case per **enabled** article-type segment.
393
+ 4. **Discovery canonical origin** — bump `site-check@2.9.4+`; never add `getRequestBaseUrl()` (tracker rollout `site-check-discovery-canonical`).
394
+ 5. **Emergency** — `SMOKE_TEST_IGNORE` or `workflow_dispatch` smoke; not a permanent site patch.
395
+
396
+ Record `placement.decision` in manifest before smoke/server-config commits aimed at unblocking deploy.
397
+
378
398
  ## Reference
379
399
 
380
400
  - HTTP + integrity example: `apps/example-empty/smoke.cases.json` and `scripts/smoke-test-run.ts` (monorepo).
@@ -78,6 +78,16 @@ If the user works only in a customer repo with no core checkout, still create/up
78
78
 
79
79
  **One feature = one manifest.** Do not append unrelated work to an existing manifest.
80
80
 
81
+ ### Cross-site tracker (`work/tracker.yaml`)
82
+
83
+ For work that spans repos (core npm rollouts, deployment gates, “bump on all sites”):
84
+
85
+ 1. Add or update a `rollouts` entry in `work/tracker.yaml` when a `@se-studio/*` release needs customer adoption
86
+ 2. Add `attention` items for human-only gates (blocked Vercel deploy, hosted MCP smoke, merge decisions)
87
+ 3. Run `pnpm work:tracker` from se-core-product to refresh `work/TRACKER.md`
88
+
89
+ Humans glance at **`work/TRACKER.md`** for the dashboard; agents edit `tracker.yaml` + manifests.
90
+
81
91
  ---
82
92
 
83
93
  ## Step 3 — Placement checklist (before non-trivial code)
@@ -105,6 +115,25 @@ Run before implementing anything beyond a one-line fix. Record results in manife
105
115
 
106
116
  **Core-first guard:** If checklist says `customer`, implement in customer repo (read-only probe in core example apps only if useful).
107
117
 
118
+ ### Step 3b — Refuse customer patches (mandatory)
119
+
120
+ After the placement checklist, run the **refusal table** when the task involves deploy smoke, `smoke.cases.json`, discovery routes, `server-config`, or “fix site-check / unblock Vercel.”
121
+
122
+ **Reference:** [`packages/skills/references/agent-session/refuse-customer-patches.md`](../../references/agent-session/refuse-customer-patches.md)
123
+
124
+ | If the fix would… | Agent must |
125
+ |-------------------|------------|
126
+ | Patch `@se-studio/*` behaviour in the customer repo | **Refuse** — core-first + changeset |
127
+ | Add `getRequestBaseUrl` or per-request origin for discovery smoke | **Refuse** — bump `@se-studio/site-check@2.9.4+` (`discovery.urlOrigin: auto`) |
128
+ | Change `route-build-policy.json` only to hide a new `ƒ` CMS route | **Refuse** — fix dynamic usage (Biome / layout) |
129
+ | Add curated URLs or site-only probe cases | **Allow** — placement `customer`; follow smoke-test skill |
130
+
131
+ **Deploy / live smoke failed?** Follow [`smoke-deploy-failure-playbook.md`](../../references/agent-session/smoke-deploy-failure-playbook.md) — classify failure → core vs customer → `blocked_on` if waiting on npm. Emergency: `SMOKE_TEST_IGNORE` or human Deployment Check approval — **not** permanent site hacks.
132
+
133
+ **Manifest gate:** Before committing customer changes to smoke config, discovery routes, or `server-config` for deploy-smoke goals, record `placement.decision` in `work/active/<feature>.yaml`. If `core`, do not commit customer workaround.
134
+
135
+ **`defer-extract`:** Only when the user explicitly approves in chat. Set `extract_to_core: pending` + rationale; add tracker rollout if multi-site.
136
+
108
137
  ---
109
138
 
110
139
  ## Step 4 — Git isolation
@@ -37,6 +37,8 @@ pnpm install --frozen-lockfile --config.node-linker=hoisted
37
37
 
38
38
  Run that locally **before push** whenever `package.json`, lockfile, or overrides change. A mismatch surfaces as `ERR_PNPM_OUTDATED_LOCKFILE` (manifest vs lockfile specifiers).
39
39
 
40
+ **Lockfile enforcement stack** — copy `scripts/check-lockfile-sync.sh` and `scripts/pre-commit-lockfile.sh` from se-core-product; wire pre-commit before lint-staged; add CI jobs from [`references/lockfile-sync/`](../../references/lockfile-sync/README.md). Marketing Vercel projects: `installCommand` must include `--frozen-lockfile`. Integration branch (`develop` / `dev`) must be in CI `push.branches`, not only `main`.
41
+
40
42
  ---
41
43
 
42
44
  ## Projects
@@ -234,6 +236,17 @@ After a successful update, you may add the patches check to the root `validate`
234
236
 
235
237
  This is optional follow-up — the skill workflow always runs the check regardless.
236
238
 
239
+ ## Optional: lockfile enforcement rollout
240
+
241
+ When updating deps in a customer repo, adopt the full lockfile stack if missing:
242
+
243
+ 1. Copy `scripts/check-lockfile-sync.sh` and `scripts/pre-commit-lockfile.sh` from se-core-product.
244
+ 2. Add `bash scripts/pre-commit-lockfile.sh` to `.husky/pre-commit` (before lint-staged).
245
+ 3. Extend `.github/workflows/validate.yml`: integration branch in `push.branches`, parallel `lockfile-hoisted` job when cms-edit uses hoisted linker.
246
+ 4. Set marketing `vercel.json` `installCommand` to `cd ../.. && pnpm install --frozen-lockfile`.
247
+
248
+ See [`references/lockfile-sync/README.md`](../../references/lockfile-sync/README.md) for the rollout table and workflow snippet.
249
+
237
250
  ---
238
251
 
239
252
  ## Troubleshooting