docs(12): record post-research decisions and validation strategy
This commit is contained in:
@@ -91,6 +91,16 @@ Repo: `fonoteka.go`. Framework changes in `summercms.go` only where a gap is fou
|
||||
- Which errors per route need a recording and which a Go test with bodies from PHP source, where recording a case is impractical (e.g. a mid-transaction race). Recording is the default.
|
||||
- Plan count and split, subject to the plan-count checkpoint, "unit tests are the last plan" and the security-review agent (this phase touches authorization and public tokens).
|
||||
|
||||
### Post-research decisions (2026-10-02, confirmed at the plan-count checkpoint)
|
||||
- **D-19:** Supersedes D-16 point 3. `meta.total`/`last_page` mirror Scout v10.25.0 `Builder::getTotalCount`: re-fetch up to `min(found, 1000)` ids from the engine and count them in SQL with the same access gating. The total is therefore re-gated and capped at 1000; stale/foreign ids still shorten the page. The D-18 leak test also asserts the total never counts a leaked row.
|
||||
- **D-20:** `GET realtime/channels` (`{"data":{"collection":"collection:<id>"}}`) is ported in this phase. `me/context` returns only its recorded flags (AI, org, Discogs, currency) and no channel. API-01 and success criterion 1 are reworded at plan time.
|
||||
- **D-21:** Error bodies are reproduced as PHP serves them in production (`APP_DEBUG=false`), including Winter HTML error pages where PHP throws `HttpException` (switch, household, invitations, accept). The existing accept 410 fixture is re-recorded under `APP_DEBUG=false`; the invitation `ValidationException` envelopes are recorded.
|
||||
- **D-22:** Photo and attachment URLs match PHP (`/storage/app/uploads/public/<partition>/<disk>`). The Go attach URL prefix is fixed in this phase, restoring P5 D-16.
|
||||
- **D-23:** The raw invitation token in River job args is encrypted with the app key and decrypted only inside the mail job. Amends D-13: the raw token never appears in plain text in `river_job.args`, logs or `summer_jobs.metadata`.
|
||||
- **D-24:** The image guard accepts webp as PHP does. `golang.org/x/image` is bumped to v0.46.0 and its webp decoder registered (named here as the phase decision that authorises the dependency bump).
|
||||
- **D-25:** The site-admin check in `me/context` reads user groups. User groups (`users_groups` and the groups relation) are added to the Go user plugin as an **additive, non-breaking** change; its existing contract is unchanged. The user signed off on this core-plugin change on 2026-10-02.
|
||||
- **D-26:** Research-found bugs fixed in this phase: the token group applies exactly one `inv.scope:read|write` per route as PHP does (not `read` at group level), and deleting a collection removes its albums one by one so each album gets its Typesense removal and `deleted` broadcast, as PHP does.
|
||||
|
||||
</decisions>
|
||||
|
||||
<canonical_refs>
|
||||
|
||||
@@ -0,0 +1,82 @@
|
||||
---
|
||||
phase: "12"
|
||||
slug: "p-ytarium-api-collections-and-albums"
|
||||
# status lifecycle: draft (seeded by plan-phase) → validated (set by validate-phase §6)
|
||||
# audit-milestone §5.5 distinguishes NOT-VALIDATED (draft) from PARTIAL (validated + nyquist_compliant: false) (#2117)
|
||||
status: draft
|
||||
nyquist_compliant: false
|
||||
wave_0_complete: false
|
||||
created: "2026-10-02"
|
||||
---
|
||||
|
||||
# Phase 12 — Validation Strategy
|
||||
|
||||
> Per-phase validation contract for feedback sampling during execution.
|
||||
|
||||
---
|
||||
|
||||
## Test Infrastructure
|
||||
|
||||
| Property | Value |
|
||||
|----------|-------|
|
||||
| **Framework** | Go `testing` (+ testify assert/require, Go fuzzing), testcontainers Postgres |
|
||||
| **Config file** | none (`parity/parity_test.go` TestMain starts Postgres) |
|
||||
| **Quick run command** | `cd fonoteka.go && go test ./plugins/golem15/fonoteka/... -short -count=1` |
|
||||
| **Full suite command** | `cd fonoteka.go && go vet ./... && go test ./... -count=1`, plus `cd summercms.go && go vet ./... && go test ./... -count=1` for framework changes |
|
||||
| **Parity command** | `cd fonoteka.go && go test ./parity -run 'TestParityCorpus|TestBroadcastGoldens|TestNuxtFlow' -count=1` |
|
||||
| **Estimated runtime** | ~180 seconds (full suite, both repos, with containers) |
|
||||
|
||||
---
|
||||
|
||||
## Sampling Rate
|
||||
|
||||
- **After every task commit:** quick run command plus `go vet` in the touched repo
|
||||
- **After every plan wave:** full suite in both repos plus the parity command
|
||||
- **Before `/gsd-verify-work`:** full suite green in both repos; parity corpus with the new routes flipped to `ported` and passing; `check_corpus.go --require-recorded --check-secrets` green; `go test ./cmd/summer -run TestDocsTree` green
|
||||
- **Max feedback latency:** 60 seconds (quick run)
|
||||
|
||||
---
|
||||
|
||||
## Per-Task Verification Map
|
||||
|
||||
Seeded from RESEARCH.md by requirement; task IDs are filled in once PLAN.md files exist.
|
||||
|
||||
| Task ID | Plan | Wave | Requirement | Threat Ref | Secure Behavior | Test Type | Automated Command | File Exists | Status |
|
||||
|---------|------|------|-------------|------------|-----------------|-----------|-------------------|-------------|--------|
|
||||
| TBD | 01 | 1 | framework | — | beachcomber `found`/weights, tide multipart + URL mask, Laravel-semantics validator + catalogs, attach URL export | unit | `cd summercms.go && go test ./modules/... -count=1` | ❌ W0 | ⬜ pending |
|
||||
| TBD | 02 | 2 | API-01 | T-12-01, T-12-03, T-12-04, T-12-05 | Collections, switch, me/context, realtime/channels, share replays; token pin and narrowing | parity + integration | `go test ./parity -run TestParityCorpus/.*collection` | ❌ W0 | ⬜ pending |
|
||||
| TBD | 03 | 3 | API-01 | T-12-06, T-12-07 | Invite mail enqueued in tx, absent on rollback; token encrypted in job args, never logged | integration + parity flow | `go test ./parity -run TestNuxtFlow/nuxt-collections` | ❌ W0 | ⬜ pending |
|
||||
| TBD | 04 | 4 | API-02 | T-12-02, T-12-09, T-12-10, T-12-11 | Album CRUD, rating, photos, bulk, stats/value/missing/sync, search, lookups; upload guard; SSRF guard | parity + integration | `go test ./parity -run 'TestParityCorpus/.*albums|TestBroadcastGoldens'` | ❌ W0 | ⬜ pending |
|
||||
| TBD | 05 | 5 | API-01, API-02 | T-12-01..T-12-11 | D-18 leak test (5 cases + total), request-DTO fuzz, route-table single-scope test | security + fuzz + unit | `go test ./plugins/golem15/fonoteka/... -run 'TestSearchLeak|TestRouteTable|FuzzWriteEndpoints' -count=1` | ❌ W0 | ⬜ pending |
|
||||
|
||||
*Status: ⬜ pending · ✅ green · ❌ red · ⚠️ flaky*
|
||||
|
||||
---
|
||||
|
||||
## Wave 0 Requirements
|
||||
|
||||
- [ ] Re-record the HttpException cases under `APP_DEBUG=false` (accept 410, switch 404, household/members 404, invitations 404, token 404) — D-21
|
||||
- [ ] tide request `body_file` (multipart) + `url`/`thumb_url` disk-name normalizer + publication date masking (framework)
|
||||
- [ ] Seed hooks or flows for a second user and an outsider (reuse `id:outsider` from Phase 11)
|
||||
- [ ] Fake `beachcomber` engine with scripted ids and `found` for D-18/D-19
|
||||
|
||||
---
|
||||
|
||||
## Manual-Only Verifications
|
||||
|
||||
| Behavior | Requirement | Why Manual | Test Instructions |
|
||||
|----------|-------------|------------|-------------------|
|
||||
| Recording new PHP fixtures against the isolated PHP instance | API-01, API-02 | Needs the running PHP reference instance and capture tooling | Follow the Phase 2 `tide` capture rules (private 0600 vars, no live tokens in git), then run `check_corpus.go --require-recorded --check-secrets` |
|
||||
|
||||
---
|
||||
|
||||
## Validation Sign-Off
|
||||
|
||||
- [ ] All tasks have `<automated>` verify or Wave 0 dependencies
|
||||
- [ ] Sampling continuity: no 3 consecutive tasks without automated verify
|
||||
- [ ] Wave 0 covers all MISSING references
|
||||
- [ ] No watch-mode flags
|
||||
- [ ] Feedback latency < 60s
|
||||
- [ ] `nyquist_compliant: true` set in frontmatter
|
||||
|
||||
**Approval:** pending
|
||||
Reference in New Issue
Block a user