diff --git a/.planning/phases/32-seo-foundation/32-REVIEW-DISPOSITION.md b/.planning/phases/32-seo-foundation/32-REVIEW-DISPOSITION.md index d6729899..348b43c4 100644 --- a/.planning/phases/32-seo-foundation/32-REVIEW-DISPOSITION.md +++ b/.planning/phases/32-seo-foundation/32-REVIEW-DISPOSITION.md @@ -3,16 +3,275 @@ phase: 32 review: 32-REVIEW.md titles: json findings: -open: 0 -total: 0 -unparsed: 52 -recorded: 2026-10-27T13:31:36.596Z + - id: CR-01 + severity: critical + disposition: open + title: "[CR-A01] `required: true` on a form extension field makes every save of the host form fail (also for administrators who cannot see the extension)" + - id: CR-02 + severity: critical + disposition: open + title: "[CR-A02] Plugin field-type upload route ignores the extension's Permissions/Visible, so administrators without them can run its `Upload`" + - id: WR-01 + severity: warning + disposition: open + title: "[WR-A01] Admin writes that change or delete records fire no record event (hasMany link/unlink, deferred child unlink, deferred child commit)" + - id: WR-02 + severity: warning + disposition: open + title: "[WR-A02] `RecordSaved.Locale` is the admin's UI language or the raw `Accept-Language` header, not a content locale, and reorder reports something different" + - id: WR-03 + severity: warning + disposition: open + title: "[WR-A03] A failing extension `Load` (or plugin-type `Load`) after a successful save rolls back the whole save" + - id: WR-04 + severity: warning + disposition: open + title: "[WR-A04] Journal API writes can commit changes (including a slug) and fire no RecordSaved" + - id: WR-05 + severity: warning + disposition: open + title: "[WR-A05] Journal `postSavedEvent` reports `Old: nil` for a translated `content_html` that existed, because the body is mutated between the snapshot and the event" + - id: WR-06 + severity: warning + disposition: open + title: "[WR-A06] Tags auto-created by the Journal post API fire no RecordSaved although `journal-tag` is now a content type" + - id: WR-07 + severity: warning + disposition: open + title: "[WR-A07] `Hide` leaves the owner's relation-manager and partial endpoints of a hidden field reachable" + - id: IN-01 + severity: info + disposition: open + title: "[IN-A01] Dead check in `BindWritableFields`" + - id: IN-02 + severity: info + disposition: open + title: "[IN-A02] Scoped API tokens never see an extension that declares no Permissions, and their posted values are dropped silently" + - id: IN-03 + severity: info + disposition: open + title: "[IN-A03] `resolveExtensionLocales` wraps a nil error" + - id: IN-04 + severity: info + disposition: open + title: "[IN-A04] `tab: default` on an extension field is refused although `default` names the default tab elsewhere" + - id: IN-05 + severity: info + disposition: open + title: "[IN-A05] Journal `requestLocale` drops the region, so translated slugs in region-coded locales never match" + - id: IN-06 + severity: info + disposition: open + title: "[IN-A06] The extension's client assets are served to every administrator of the host form" + - id: CR-03 + severity: critical + disposition: open + title: "[CR-B01] Exact redirects with a trailing slash or upper-case query characters never match at runtime" + - id: WR-08 + severity: warning + disposition: open + title: "[WR-B01] A query-specific exact redirect is silently shadowed by the path-only rule" + - id: WR-09 + severity: warning + disposition: open + title: "[WR-B02] `AddressChanged` writes redirects without validation or the loop simulation" + - id: WR-10 + severity: warning + disposition: open + title: "[WR-B03] The save-time loop check races with concurrent writes" + - id: WR-11 + severity: warning + disposition: open + title: "[WR-B04] Undo is not idempotent under concurrent requests" + - id: WR-12 + severity: warning + disposition: open + title: "[WR-B05] Public resolve and 404 report answer 500 for NUL or invalid UTF-8 paths" + - id: WR-13 + severity: warning + disposition: open + title: "[WR-B06] The runtime cycle log grows without bound and is keyed by attacker-controlled URLs" + - id: WR-14 + severity: warning + disposition: open + title: "[WR-B07] Export with a large `page` panics the handler" + - id: WR-15 + severity: warning + disposition: open + title: "[WR-B08] Public throttle buckets key on the SSR server's IP, capping the whole site" + - id: WR-16 + severity: warning + disposition: open + title: "[WR-B09] Social image values bypass validation on every non-admin write path" + - id: WR-17 + severity: warning + disposition: open + title: "[WR-B10] Invalid redirect status, match or query values are silently coerced on API, MCP and import" + - id: WR-18 + severity: warning + disposition: open + title: "[WR-B11] `set_url_seo`, batch `set_seo` and the records import accept any locale" + - id: WR-19 + severity: warning + disposition: open + title: "[WR-B12] Entry generation overwrites `entry.URL`, which can swallow an address change and its 301" + - id: IN-07 + severity: info + disposition: open + title: "[IN-B01] The `regexCache` / `globCache` maps are never evicted" + - id: IN-08 + severity: info + disposition: open + title: "[IN-B02] CSV `unescapeCell` changes legitimate values that start with an apostrophe" + - id: IN-09 + severity: info + disposition: open + title: "[IN-B03] The transfer token has no expiry or user binding, and the fallback key is per process" + - id: IN-10 + severity: info + disposition: open + title: "[IN-B04] Uniqueness checks swallow query errors inside the save transaction" + - id: IN-11 + severity: info + disposition: open + title: "[IN-B05] `RenderTemplate` trims separators that belong to the content" + - id: IN-12 + severity: info + disposition: open + title: "[IN-B06] Body caps do not account for JSON escaping" + - id: IN-13 + severity: info + disposition: open + title: "[IN-B07] `/robots.txt` serves allow-all without the noindex header when the service is nil, even outside production" + - id: IN-14 + severity: info + disposition: open + title: "[IN-B08] Self canonical and `url` are built from the decoded path" + - id: CR-04 + severity: critical + disposition: open + title: "[CR-C01] The SERP preview and the robots.txt tester deadlock: their first action is dropped by the host and `inflight` is never cleared" + - id: WR-20 + severity: warning + disposition: open + title: "[WR-C01] The social image preview accepts `/\\host/...`, so the admin can load an image from an attacker's host" + - id: WR-21 + severity: warning + disposition: open + title: "[WR-C02] The CSV export/import round trip changes cells that already start with an apostrophe followed by a formula character" + - id: WR-22 + severity: warning + disposition: open + title: "[WR-C03] The 404 \"Open/Resolved\" filter and the redirect \"Chains\" filter disagree with the runtime matcher" + - id: WR-23 + severity: warning + disposition: open + title: "[WR-C04] The URL rule address is uncapped but sits in a btree UNIQUE index, so long values return 500 instead of 422" + - id: WR-24 + severity: warning + disposition: open + title: "[WR-C05] The robots element's grammar drifts from the Go grammar, and an unparseable value is silently wiped on the next edit" + - id: WR-25 + severity: warning + disposition: open + title: "[WR-C06] The element tests never exercise the host protocol; the tester and the image element have no tests" + - id: IN-15 + severity: info + disposition: open + title: "[IN-C01] The regex length refusal puts an untranslated English phrase into the Polish UI" + - id: IN-16 + severity: info + disposition: open + title: "[IN-C02] A migration comment is stale" + - id: IN-17 + severity: info + disposition: open + title: "[IN-C03] The SERP preview's template rendering is not single-pass like the Go renderer" + - id: IN-18 + severity: info + disposition: open + title: "[IN-C04] `plural()` can throw on an unusual `ui-locale`" + - id: IN-19 + severity: info + disposition: open + title: "[IN-C05] Two test names do not describe what they assert" + - id: IN-20 + severity: info + disposition: open + title: "[IN-C06] The inner controls' accessible name is the machine field name" + - id: IN-21 + severity: info + disposition: open + title: "[IN-C07] The README test instructions skip the vitest suite, and the test script hides an empty run" + - id: IN-22 + severity: info + disposition: open + title: "[IN-C08] Three partials are maintained twice" + - id: IN-23 + severity: info + disposition: open + title: "[IN-C09] The `disabled` branches in the widget elements are dead, and would be broken if reached" +open: 52 +total: 52 +recorded: 2026-10-27T13:31:50.257Z --- # Phase 32: Code Review Disposition | Finding | Severity | Disposition | Source | |---------|----------|-------------|--------| +| CR-01 | critical | open | - | +| CR-02 | critical | open | - | +| WR-01 | warning | open | - | +| WR-02 | warning | open | - | +| WR-03 | warning | open | - | +| WR-04 | warning | open | - | +| WR-05 | warning | open | - | +| WR-06 | warning | open | - | +| WR-07 | warning | open | - | +| IN-01 | info | open | - | +| IN-02 | info | open | - | +| IN-03 | info | open | - | +| IN-04 | info | open | - | +| IN-05 | info | open | - | +| IN-06 | info | open | - | +| CR-03 | critical | open | - | +| WR-08 | warning | open | - | +| WR-09 | warning | open | - | +| WR-10 | warning | open | - | +| WR-11 | warning | open | - | +| WR-12 | warning | open | - | +| WR-13 | warning | open | - | +| WR-14 | warning | open | - | +| WR-15 | warning | open | - | +| WR-16 | warning | open | - | +| WR-17 | warning | open | - | +| WR-18 | warning | open | - | +| WR-19 | warning | open | - | +| IN-07 | info | open | - | +| IN-08 | info | open | - | +| IN-09 | info | open | - | +| IN-10 | info | open | - | +| IN-11 | info | open | - | +| IN-12 | info | open | - | +| IN-13 | info | open | - | +| IN-14 | info | open | - | +| CR-04 | critical | open | - | +| WR-20 | warning | open | - | +| WR-21 | warning | open | - | +| WR-22 | warning | open | - | +| WR-23 | warning | open | - | +| WR-24 | warning | open | - | +| WR-25 | warning | open | - | +| IN-15 | info | open | - | +| IN-16 | info | open | - | +| IN-17 | info | open | - | +| IN-18 | info | open | - | +| IN-19 | info | open | - | +| IN-20 | info | open | - | +| IN-21 | info | open | - | +| IN-22 | info | open | - | +| IN-23 | info | open | - | Dispositions: `open` (recorded, not yet triaged), `fixed`, `skipped`, `deferred`. Set `deferred` by hand and put the reason in the Source cell; both are preserved. A `|` in the reason is kept as prose and escaped on the next run.