Files
pbakaus_impeccable/tests/framework-fixtures/README.md
T
Paul BakausandClaude Opus 4.7 d5480caee3 feat(live): CSP detection + consent-gated patch flow at first-time setup
Real-world tests (EAC Next turborepo) confirmed that CSP is the common
blocker for live mode. Adds setup-time detection with a one-time user
consent flow — the patch becomes a permanent, dev-guarded entry in the
user's own config, not a transient add/remove.

## Changes

- New detect-csp.mjs helper: grep-based classifier returning
  { shape, signals }. Shape is one of:
    - "shared-helper" (monorepo CSP helper with additional*Src arrays)
    - "inline-headers" (literal CSP string in headers())
    - "middleware" (response.headers.set in middleware.ts; detect-only v1)
    - "meta-tag" (<meta http-equiv>; detect-only v1)
    - null (no CSP)
  Max depth 6, skips node_modules / build / cache dirs, 64KB per file.

- cspChecked boolean on config.json. First-run setup runs detection;
  subsequent runs skip. Users re-trigger by deleting the flag.
  Validator accepts it.

- Skill live.md gains:
    - CSP detection step in first-time setup (gated by cspChecked)
    - Consent-prompt template (so every agent phrases it the same way)
    - Shape 1 patch template: append `...__impeccableLiveDev` to
      additionalScriptSrc/additionalConnectSrc in the app's config
    - Shape 2 patch template: two-point edit — declare a dev-only
      variable, interpolate into script-src and connect-src in the
      CSP literal string
    - Troubleshooting note for "said no but now live doesn't work"

## Fixtures

- nextjs-turborepo/: Turborepo shape (shared CSP helper with
  additionalScriptSrc options). Sanitized from a real monorepo so the
  patch mechanics get tested against realistic layering. Includes
  expected-after-patch.ts for human/agent review.

- nextjs-inline-csp/: app-level next.config.js with a literal CSP
  string. Includes expected-after-patch.js showing the Shape 2 edit.

## Tests

Framework-fixture harness extended with a detect-csp shape-classification
assertion per fixture. 42 tests across 7 fixtures pass. Clean fixtures
(vite-react, nextjs-app, astro, sveltekit, multipage-with-generator)
correctly return shape: null.

## Deliberately not doing

- No patches[] array, no marker-based rollback, no add/remove lifecycle.
  The patch is a permanent dev-guarded config line — the same kind of
  edit a user would make themselves.
- No base URL rewriting or proxy mechanism. Script tag still points at
  localhost:8400; CSP permits it once patched. No browser-side changes.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-21 23:41:11 -07:00

54 lines
2.4 KiB
Markdown

# Framework fixtures
Representative project shapes for exercising live mode against different framework conventions. Each fixture is a small directory tree that the test harness copies into a temp git repo, then drives `live-inject.mjs`, `live-wrap.mjs`, `live-accept.mjs`, and `is-generated.mjs` against.
## Layout
```
<fixture>/
files/ project tree the test copies into tmp
gitignore.txt becomes .gitignore in tmp (so we can commit the real files here)
fixture.json config + expected results the test consumes
```
`fixture.json` schema:
```json
{
"name": "human-readable label",
"config": { ...contents for live-inject.mjs config.json ... },
"sourceFiles": ["paths that is-generated should classify as source (false)"],
"generatedFiles": ["paths that is-generated should classify as generated (true)"],
"wrapCases": [
{
"name": "description",
"args": { "classes": "...", "tag": "...", "elementId": "..." },
"expectedFile": "where wrap should land (relative to fixture root)",
"expectsError": "optional error code, e.g. element_not_in_source"
}
],
"csp": {
"shape": "shared-helper | inline-headers | middleware | meta-tag | null",
"signals": ["diagnostic hints — paths where CSP was detected"],
"patchTarget": "which file the agent should modify",
"expectedAfter": "filename of the reference post-patch output inside this fixture"
}
}
```
The `expectedAfter` file lives alongside `fixture.json` (not inside `files/`) and is a human/agent-review reference — tests don't auto-apply the patch.
## Current fixtures
| Fixture | Shape |
|---|---|
| `vite-react/` | Tracked `index.html` shell + `src/App.jsx`. Inject into the shell. |
| `nextjs-app/` | `app/layout.tsx` as JSX inject target (commentSyntax `jsx`). |
| `astro/` | `src/layouts/Layout.astro` as inject target. HTML comments. |
| `sveltekit/` | `src/app.html` shell + `src/routes/+page.svelte`. |
| `multipage-with-generator/` | `src/` tracked, `dist/` gitignored. Exercises the is-generated guard and `element_not_in_source` fallback. |
| `nextjs-turborepo/` | Monorepo with shared CSP helper (`createBaseNextConfig`). Exercises CSP shape 1 (shared-helper). |
| `nextjs-inline-csp/` | App-level `next.config.js` with a literal CSP string. Exercises CSP shape 2 (inline-headers). |
Add new fixtures by cloning a directory, swapping files, and updating `fixture.json`.