From 1f017cd9b0de29e312f89d45574c836bb67370c6 Mon Sep 17 00:00:00 2001 From: SinachPat Date: Sat, 15 Aug 2026 14:06:45 +0100 Subject: [PATCH] docs: add decision records, changelog, and repo index links --- AGENTS.md | 2 + CHANGELOG.md | 53 +++++++++++++++++++ README.md | 2 + .../0001-mvp-scope-content-loop-first.md | 31 +++++++++++ docs/decisions/0002-phase-zero-spikes-gate.md | 29 ++++++++++ docs/decisions/0003-pairing-code-direction.md | 27 ++++++++++ .../0004-plugin-install-allowlist.md | 29 ++++++++++ .../decisions/0005-golden-harness-fixtures.md | 29 ++++++++++ docs/decisions/0006-builder-detection.md | 29 ++++++++++ docs/decisions/0007-media-proxy-not-copy.md | 26 +++++++++ .../0008-empty-packages-not-stubs.md | 26 +++++++++ docs/decisions/0009-repo-rename.md | 26 +++++++++ docs/decisions/README.md | 31 +++++++++++ 13 files changed, 340 insertions(+) create mode 100644 CHANGELOG.md create mode 100644 docs/decisions/0001-mvp-scope-content-loop-first.md create mode 100644 docs/decisions/0002-phase-zero-spikes-gate.md create mode 100644 docs/decisions/0003-pairing-code-direction.md create mode 100644 docs/decisions/0004-plugin-install-allowlist.md create mode 100644 docs/decisions/0005-golden-harness-fixtures.md create mode 100644 docs/decisions/0006-builder-detection.md create mode 100644 docs/decisions/0007-media-proxy-not-copy.md create mode 100644 docs/decisions/0008-empty-packages-not-stubs.md create mode 100644 docs/decisions/0009-repo-rename.md create mode 100644 docs/decisions/README.md diff --git a/AGENTS.md b/AGENTS.md index 344b7df..eb46f6a 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -15,8 +15,10 @@ plugin/ WordPress plugin (PHP) — empty until Phase 0 gate infrastructure/ Docker images, warm pool, GC, deploy scripts e2e/ Playwright + e2e/golden/ harness spikes/ Phase 0 written results — gate before product code +docs/decisions/ Architecture Decision Records (0001–…) PRD.md Product requirements (v2.0 — non-technical-first) IMPLEMENTATION.md TDD build guide with 8-sprint Phase 1 plan +CHANGELOG.md Keep-a-Changelog log of changes ``` ## Skill routing — use the precheck first diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..c570d00 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,53 @@ +# Changelog + +All notable changes to this project are documented here. This file follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/) and the project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). + +The project is pre-1.0. Versions below `1.0.0` are internal milestones, not public releases. + +## [Unreleased] + +### Added + +- **Monorepo workspace** — `pnpm` workspace (`api`, `web`, `e2e`), root `package.json` / `pnpm-workspace.yaml` / `tsconfig.base.json`, and a PHP `plugin` package (`composer.json`). Empty packages by design (see [ADR 8](docs/decisions/0008-empty-packages-not-stubs.md)). +- **Phase 0 spike records** under `spikes/`: + - `pairing-threat-model.md` — pairing protocol: 8+ char code, 5-min TTL, 5-attempt lockout, HMAC, scoped `read`/`deploy` tokens, threat table T1–T10. + - `plugin-catalog.md` — 40-slug install allowlist + detect-only list; no `wp plugin install `. + - `builder-detect.md` — builder detection rules + plugin `site-info` API sketch. + - `mirror-timing.md` — synthetic 2GB mirror/proxy timing result. + - `golden-task.md` — golden harness status (live Grok pending key). + - `phase-0-harness.md` — batch writeup with open questions. +- **Golden-task harness** under `e2e/golden/` — 20 prompts × 2 site fixtures (`gutenberg-business`, `elementor-restaurant`), apply-then-assert scorer, offline runner, live Grok client, and 21 passing Vitest tests. +- **Builder detection** — `detectBuilder()` (elementor / beaver / divi / gutenberg / classic) from theme + plugin slugs + post meta + content. +- **Subset + media proxy** — `exportDbSubset()` (content tables only, secret redaction) and `mediaProxyTarget()` / `stageReplacement()` (origin proxy, copy-on-replace). +- **Mirror timing runner** — `run-mirror-timing.ts` with a real 2GB `dd` baseline; result: slice p50/p95 ≈ 0.003/0.010 ms, 0 upload bytes copied. +- **Documentation** — ADR set under `docs/decisions/` (0001–0009), this changelog, and `.env.example`. + +### Changed + +- **Repository identity** — renamed from `originmain` to `wursor`; description set to the product tagline; stale homepage cleared; topics `wordpress`, `ai`, `agent` added (see [ADR 9](docs/decisions/0009-repo-rename.md)). +- **PRD / IMPLEMENTATION** — expanded risk register (R1–R14 with mitigations and sprint ownership), media-proxy and capability-tier decisions locked, pairing and warm-pool details corrected. +- **README / AGENTS.md** — repo layout and Phase 0 gate documented; status updated to reflect the workspace existing while product code remains gated. +- **`.gitignore`** — added coverage/report/build artifacts and the large-export fixture path. + +### Removed + +- Nothing removed from the current product; the prior `originmain` codebase was removed earlier in `702ce4e`. + +### Security + +- Pairing threat model and plugin install allowlist formalize the two highest-risk boundaries (live-site backdoor, arbitrary plugin install). See [ADR 3](docs/decisions/0003-pairing-code-direction.md) and [ADR 4](docs/decisions/0004-plugin-install-allowlist.md). + +## [0.1.0] - 2026-08-15 + +First tracked Wursor artifact set. + +### Added + +- pstack-style engineering rigor skill family (`.agents/skills/`) and `AGENTS.md` routing (`0dae13c`). +- Wursor v2.0 PRD and IMPLEMENTATION guide — non-technical-first pivot (`dfb3c93`). + +## [0.0.0] - 2026-08-13 + +### Added + +- Initial Wursor PRD after removing the prior Originmain codebase (`702ce4e`). diff --git a/README.md b/README.md index 1bc6c84..ddb4c2a 100644 --- a/README.md +++ b/README.md @@ -11,6 +11,8 @@ Just describe what you want. Wursor does the rest. - Full product spec: [PRD.md](./PRD.md) - Build guide (TDD, sprints, CI): [IMPLEMENTATION.md](./IMPLEMENTATION.md) - Phase 0 gate: [spikes/README.md](./spikes/README.md) +- Decisions: [docs/decisions/](./docs/decisions/) +- Changelog: [CHANGELOG.md](./CHANGELOG.md) ## What it does diff --git a/docs/decisions/0001-mvp-scope-content-loop-first.md b/docs/decisions/0001-mvp-scope-content-loop-first.md new file mode 100644 index 0000000..f9b1056 --- /dev/null +++ b/docs/decisions/0001-mvp-scope-content-loop-first.md @@ -0,0 +1,31 @@ +# 1. MVP is the content-change loop, not the full P0 feature list + +- **Status:** Accepted +- **Date:** 2026-08-15 + +## Context + +PRD §7.1 lists plugin-install and site-build playbooks as P0 ("launch-blocking"), but IMPLEMENTATION.md schedules them into Phase 2 (Sprints 9–10). The two documents disagreed on what "P0" meant. + +## Decision + +The MVP is the Phase 1 exit criterion only: a new user signs up, pairs a WordPress site, types "change the homepage heading", sees the change in a sandbox preview, and approves — in under five minutes. + +Plugin-install, site-build, design picker, and multi-step workflows are explicitly deferred to Phase 2. + +### Options considered + +- Ship the full PRD P0 (plugin install + site build in the first release). +- Thin vertical slice even smaller than Phase 1 (fixture-only, deploy stubbed). +- **Chosen:** Phase 1 exit only. + +### Rejected + +- Full P0 — a plugin-install playbook requires the catalog, reputation gate, and egress watch (ADR 4) that are not built; shipping them prematurely reintroduces R2. +- Thinner slice — deploy/rollback is the product's trust guarantee (R3); stubbing it hides the one thing that can break a live site. + +## Consequences + +- Clear, single exit test: `e2e/phase1-exit-criteria.test.ts`. +- PRD §7.1 will be annotated to move plugin/site-build out of P0 (doc-sync follow-up). +- Fewer parallel workstreams; content + deploy are the critical path. diff --git a/docs/decisions/0002-phase-zero-spikes-gate.md b/docs/decisions/0002-phase-zero-spikes-gate.md new file mode 100644 index 0000000..2c86ae5 --- /dev/null +++ b/docs/decisions/0002-phase-zero-spikes-gate.md @@ -0,0 +1,29 @@ +# 2. Phase 0 spikes gate the scaffold + +- **Status:** Accepted +- **Date:** 2026-08-15 + +## Context + +IMPLEMENTATION.md says "Do not start the web-app scaffold until the four boxes have a written result." The four spikes were golden-task harness, builder detection, pairing threat model, and large-site mirror timing — plus a plugin catalog. + +## Decision + +Treat the spikes as a hard gate. Product code (`web/` chat, playbooks, deploy) does not start until each spike has a written, verifiable result in the repo. Fixtures and throwaway scripts are allowed during the gate. + +### Options considered + +- Honor the gate. +- Spike in parallel with Sprint 1. +- Skip spikes and start the scaffold. + +### Rejected + +- Parallel — spike results change the architecture (e.g. mirror slice, pairing direction); building Sprint 1 against unverified assumptions means rework. +- Skip — the spikes exist precisely because an unvalidated assumption can kill the 5-minute exit or the live-site safety guarantee. + +## Consequences + +- Phase 0 exit is reviewable: five written spike notes, three with executable proofs. +- The scaffold exists only as empty packages (ADR 8), not product code. +- The remaining gate item is a live Grok score (see `spikes/golden-task.md`). diff --git a/docs/decisions/0003-pairing-code-direction.md b/docs/decisions/0003-pairing-code-direction.md new file mode 100644 index 0000000..4053b62 --- /dev/null +++ b/docs/decisions/0003-pairing-code-direction.md @@ -0,0 +1,27 @@ +# 3. Wursor generates the pairing code, not the plugin + +- **Status:** Accepted +- **Date:** 2026-08-15 + +## Context + +The IMPLEMENTATION.md Sprint 2 sketch had `Wursor_Auth::generate_pairing_code()` run on the plugin (TV-style pairing). PRD §7.1.4 says the user "copies a code from the Wursor web app" — the code must be bound to the signed-in account before the site is known. The plugin is a privileged backdoor (files, DB, WP-CLI) to the live site (R9). + +## Decision + +Wursor generates the pairing code bound to the account; the user pastes it into the plugin; the plugin redeems it with its `site_url`; Wursor issues scoped `read`/`deploy` tokens plus an HMAC secret. Full protocol in `spikes/pairing-threat-model.md`. + +### Options considered + +- Plugin-local generate/redeem (the sketch). +- Wursor-generated, pasted into the plugin. + +### Rejected + +- Plugin-local — cannot bind the code to an account before the site is known; a 6-char code with no TTL/lockout/HMAC is site ownership via a leaked URL. + +## Consequences + +- 8+ char code, 5-min TTL, 5-attempt lockout, one redeem, HMAC, hashed scoped tokens are the Sprint 2 test spec. +- The `generate_pairing_code` sketch in IMPLEMENTATION.md is wrong and will be corrected during Sprint 2. +- The threat model (T1–T10) is the audit trail for this boundary. diff --git a/docs/decisions/0004-plugin-install-allowlist.md b/docs/decisions/0004-plugin-install-allowlist.md new file mode 100644 index 0000000..93c6f43 --- /dev/null +++ b/docs/decisions/0004-plugin-install-allowlist.md @@ -0,0 +1,29 @@ +# 4. Plugin install is a 40-slug allowlist, fail-closed + +- **Status:** Accepted +- **Date:** 2026-08-15 + +## Context + +wordpress.org is not a reviewed-safe catalog. A malicious plugin looks fine in preview and only phones home after deploy. The agent will eventually install plugins, but must not be able to in the MVP either (R2). + +## Decision + +The agent may install only from a written ~40-slug allowlist (`spikes/plugin-catalog.md`), and only via `wp plugin install `. No URLs, no zips, no premium marketplaces. Unknown slug → refuse. A detect-only list (Wordfence, Jetpack, cache suites) is never installed. + +### Options considered + +- Open wordpress.org search. +- Written allowlist now; reputation/egress gate later (Sprint 9). +- No wall until the install playbook exists. + +### Rejected + +- Open search — reintroduces R2. +- No wall until later — the MVP agent could still `wp plugin install ` unless the tool schema forbids it from day one. + +## Consequences + +- Sprint 3 `tool-schemas.ts` must forbid `wp plugin install http` and unknown slugs even though no install playbook ships in MVP. +- Reputation gate, zip SHA, and egress watch on first activate are Sprint 9 scope, already specced. +- Catalog changes are PRs, not prompt edits. diff --git a/docs/decisions/0005-golden-harness-fixtures.md b/docs/decisions/0005-golden-harness-fixtures.md new file mode 100644 index 0000000..2a20290 --- /dev/null +++ b/docs/decisions/0005-golden-harness-fixtures.md @@ -0,0 +1,29 @@ +# 5. Golden harness scores slot-fill tool calls against JSON fixtures + +- **Status:** Accepted +- **Date:** 2026-08-15 + +## Context + +R7: can we score a model on WordPress tasks without vibes? A live WordPress sandbox was not available on the development machine (no Docker), and a live Grok key was not set. The harness still had to exist and produce a scoreable path. + +## Decision + +Twenty prompts across two JSON site fixtures (`gutenberg-business`, `elementor-restaurant`). Each prompt has a hard assertion (`preview_text`, `option`, or `screenshot`). A tool call is applied to the fixture and the assertion is checked. `run-golden.ts` scores the 20 expected traces offline and, when `XAI_API_KEY` is set, sends `gb-01` to `api.x.ai`. + +### Options considered + +- Docker WordPress fixtures + Playwright. +- JSON fixtures + slot-fill apply-then-assert. +- Defer the harness until Docker exists. + +### Rejected + +- Docker now — unavailable in this environment; blocks progress for a reason that does not change the assertion design. +- Defer — ships nothing; the assertion types and prompt file survive the swap to a real runner. + +## Consequences + +- WordPress work is modeled as slot-fill (`page`, `old`, `new`) + a deterministic write, which is how playbooks will actually execute. +- `applyTool` is the seam that gets replaced by a REST / `wp post update` runner when sandboxes exist. +- Unit tests stay offline (TDD rule: no network in unit tests). A live Grok score is the outstanding gate item. diff --git a/docs/decisions/0006-builder-detection.md b/docs/decisions/0006-builder-detection.md new file mode 100644 index 0000000..182a4af --- /dev/null +++ b/docs/decisions/0006-builder-detection.md @@ -0,0 +1,29 @@ +# 6. Builder detection uses slugs + post meta with a priority order + +- **Status:** Accepted +- **Date:** 2026-08-15 + +## Context + +WordPress pages live in different stores: Gutenberg in `post_content` block markup, Elementor in `_elementor_data` post meta, Classic as raw HTML. Editing the wrong store means the preview does not change and we do not know why (R6, R13). + +## Decision + +`detectBuilder()` returns `elementor | beaver | divi | gutenberg | classic` from theme + active plugin slugs + post meta + content. Priority: elementor (slug + `_elementor_edit_mode`/`_elementor_data`) → beaver (`_fl_builder_data`) → divi (theme + `_et_pb_use_builder`) → gutenberg (`