Files
WP-LIT-MCP/docs/superpowers/notes/2026-09-27-etappe-3b-rulings.md
T

112 lines
19 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Etappe 3b – Entscheidungen (Rulings), Befunde und offene Punkte
Aus dem SDD-Ledger übernommen, 2026-09-27. Security-Audit: 2026-09-27-etappe-3b-security-audit.md. Abnahme: 2026-09-27-etappe-3b-abnahme.md.
## Offen für spätere Etappen
- Etappe U: Revisionen von Theme-Builder-Layouts und Bibliothekseinträgen über MCP wiederherstellen (jetzt nur restore_url zum WordPress-Revisionsbildschirm, Audit L3); Oracle über Vorfilter/next_cursor von replace-text (Q13); Race beim Anhängen von Vorlagen; try/catch um Divi-Aufrufe; tree_rev-Race; DNS-Pinning; Build-Hygiene.
- Etappe 4: Presets können Lottie-Quelle/Interactions tragen – Preset-Schreiben braucht dieselben Builder-Sperren.
- Bewusst belassen: {{field:}} im Body-Layout warnt nur (Anzeige-Parität mit Divi, Audit I1); Bestätigung ist nicht an den Probelauf gebunden (wie 3a, Audit I3); gemeinsamer confirm-Helfer verworfen (Q17 M4).
## Ledger
Spec: docs/superpowers/specs/2026-09-25-wp-lit-mcp-design.md; decisions: docs/superpowers/notes/2026-09-27-etappe-3-entscheidungen-entwurf.md (§5 user answers binding, F1: TB templates disabled by default + explicit activation tool); rulings 1a/1b/2a/2b/3a in docs/superpowers/notes/.
Branch: etappe-3 (base 0edb474; 3a merged to main 4f05388), in place. Pods 3.3.9.2 activated locally by user permission (2026-09-27), no pods defined yet.
Process rules carried over: opus reviewers for security-relevant tasks; controller verifies live with benign probes if reviewer agents stop; smoke guard; commits by explicit path; final review + security audit + one fix wave (breaker after round 2).
## Pre-flight rulings
Pre-flight (opus): 1 Critical, 6 Important, 16 Minor, 7 Info; all anchors match once; full tables in preflight.md (B1–B23).
- Ruling Q1 (B1, Critical): 3b fixtures use their own pod `lit_fixture_person` („[Fixture] Personen“) that no smoke deletes; wp-basis-smoke's shared lit_person stays as is — cost if wrong: none
- Ruling Q2 (B2): extract GlobalEdits' backup + confirm-merge into a shared helper; live TB layout edits reuse it (backup when revisions off, P9 refusals) — cost if wrong: none
- Ruling Q3 (B3): lit/tb-assign leaves omitted exclude_from unchanged; dry run shows both lists (before/after) — cost if wrong: none
- Ruling Q4 (B4): TemplateBuildTest uses assertPartials — cost if wrong: none
- Ruling Q5 (B5, USER-APPROVED 2026-09-27): Task 1 Step 8 may enable the fixture template briefly, conditions limited to exactly one „[Fixture]“ person, disabled again in the same step (try/finally), verified off afterwards; Step 6 does not change Divi's post-type setting — cost if wrong: momentary visible change on one fixture URL
- Ruling Q6 (B6): tb-smoke creates/deletes its own temporary pod, never touches lit_person or lit_fixture_person — cost if wrong: none
- Ruling Q7 (B7): UsageMatcher::referencesAny() refuses any global reference in every spelling Divi renders; used by lit/library-make-global and lit/library-save scope global (no self-reference, no nested refs in shortcode text) — cost if wrong: none
- Ruling Q8 (B8–B21 minors): adopt as proposed in preflight.md (template live = attached+enabled regardless of post status; layouts must be published before reattach/activate; tb-list hides IDs of templates the user can't edit; test/count/doc fixes; smoke library-id check via jq) — cost if wrong: small
- Ruling Q9 (B22 / plan open point): live-visible TB edits use dry run + confirm (with Q2 backup), not refusal — matches F2 — cost if wrong: none
- Ruling Q10 (B23 / plan open point): author conditions require list_users — only admins hold Divi's theme_builder right by default — cost if wrong: editors with theme_builder can't set author conditions
## Progress
- Task 1: dispatched (opus, BASE 0edb474; Q1 own pod, Q5 user-approved brief activation)
- Task 1: done (c615522; fixtures: pod lit_fixture_person 2381, persons 2385/2386, body layout 2391, template 2394 disabled, global header 1061; brief activation only for Erika, off again; live site unchanged). Finding 10: stale TB editor save detaches our template silently + marks unused (7-day trash) → confirms plan mitigation (detached/reattach). Finding 12: Divi dialog writes Pods fields as post_meta_key + select_meta_key "custom_meta_<key>" (empty meta_key); plugin writes custom_meta_<key>; choice shows stored value; relation shows raw ID
- Ruling Q11: Task 11 (Pods field check) and any usage/field detection recognize both forms (custom_meta_<key> and post_meta_key/select_meta_key); S29/S30 meta-key rules already cover both on write — cost if wrong: missed warnings
- Ruling Q12: Task 1 (fixtures/test data only) verified by controller from report + commit instead of a separate review; fixtures are re-checked by later task reviews — cost if wrong: none
- Task 1: complete (0edb474..c615522)
- Tasks 2–3: dispatched (opus, BASE c615522, one commit each)
- Tasks 2–3: implementer done (06f1379 P10 PostIdParser + type-exact post_link_url; c7ce924 P13 revealsIds + replace-text skipped_nodes ID-oracle fix; 1923 tests); concern: replace-text prefilter/next_cursor partial oracle → U (Ruling Q13)
- Tasks 2–3: review (opus): both Approved, live-verified (P10 nothing widened; P13 no ID in any path, digit oracle fixed, nur lesen reveals). Important (pre-existing): {{link:<library ID>}} type oracle ("Unbekannter Name post_link_url_et_pb_layout" vs "gibt es nicht")
- Ruling Q14: WpLinkTargets treats et_pb_layout (and any post type without a Divi post_link_url option, incl. internal _-types) as not found → uniform message; minors: merge stacked docblocks WordPressIntegration.php:52-56, DiviTextSearch withoutLibraryIds doc (hides more for undecodable opaque openers) — fix round 1 now — cost if wrong: none
- Ruling Q13 (confirmed): replace-text prefilter/next_cursor oracle deferred to U, documented as parity with WordPress' own content search
- Tasks 2–3: fix round 1 (Q14; 82ef69a; 1926 tests): WpLinkTargets linkable = Divi's et_builder_get_public_post_types() minus attachment/_-types/et_pb_layout; identical answers library vs missing ID (test); DiviTextSearch strips IDs only in global nodes — verified by controller against report/tests
- Tasks 2, 3: complete (c615522..82ef69a)
- Task 4: dispatched (opus, BASE 82ef69a; wp_die guard, ThemeBuilderAccess, Q8 minors)
- Task 4: implementer done (d04a508; 1958 tests); helpers for T7/T9/T10: ThemeBuilderAccess::canEditTemplate(), layoutsRefusal(); attach race → U
- Task 4: review (opus): Approved; wp_die guard live-verified (CLI/AJAX/JSON, nested, no output/status leak, handlers restored, nothing written); ThemeBuilderAccess = Divi's save gate; P12 no oracle; isLive matches Divi
- Ruling Q15: ThemeBuilderAccess::canUse additionally requires edit_theme_options (Divi's TB admin page gate) — never laxer than Divi's UI — cost if wrong: roles with theme_builder but without edit_theme_options can't use TB tools
- Ruling Q16 (T4 minors): T10 must be able to deactivate an attached+enabled template that sits in the trash (raw lookup for the off-switch, fail-safe); docblock note on third-party wp_die inside hooks; canEditTemplate docblock (IDs from Divi's list); dedupe GlobalUsages::THEME_BUILDER_TYPES/DiviSaver cache clear/compat row → final wave
- Task 4: fix round 1 (Q15 + docblocks) dispatched
- Task 4: fix round 1 (Q15; 4ff1c1e; 1959 tests) — verified by controller
- Task 4: complete (82ef69a..4ff1c1e)
- Task 5: dispatched (opus, BASE 4ff1c1e; Q2 shared backup/confirm helper, Q9, Q8)
- Task 5: implementer done (b1dd35a; 1980 tests; smoke ok); VisibleEdits shared helper (GlobalEdits/ThemeBuilderEdits/DiviWriter); TB layouts get Divi flags (as Divi writes); T11 adds ?DynamicFields after VisibleEdits param
- Task 5: review (opus): Approved; live: 9 write paths on live layout → confirm_required/merged confirm/replace-text refused, confirmed save with revision, backup when revisions off; access P12 no oracle; post-content body-only on all paths; GlobalEdits byte-identical after Q2
- Ruling Q17 (T5 minors): M1 GlobalUsages P8a TB rows reuse ThemeBuilderAccess::canUse (not only theme_builder) → final wave (security, must); M2 confirm description mentions live TB layouts → T16; M3 library-path P9/P14 wording test → final wave; M4 optional VisibleEdits::confirmed → final wave
- Task 5: complete (4ff1c1e..b1dd35a)
- Tasks 6–7: dispatched (opus, BASE b1dd35a, one commit each; Q10, Q8, group wiring)
- Tasks 6–7: implementer done (ac69fdf TemplateConditions: 34 Divi IDs, 27 round-trip live, assign_term for terms, list_users for authors, uniform missing/unreadable; 54922a9 tb-list + group live: nur lesen blocks TB writes, disabled → not_found; 1998 tests)
- Tasks 6–7: review (opus): both Approved; live: 34 Divi condition IDs covered by construction, parsing safe, uniform missing/unreadable, tb-list leaks nothing, detached shown, group matrix verified, never enabled a template
- Ruling Q18: ThemeBuilderAccess::template() answers not_found (identical to missing) for templates the user can't edit (canEditTemplate), consistent with tb-list (Q8/B11) — implement in T8 (first caller) incl. test; minors → final wave: DETACHED_LIMIT applied after edit filter + truncation note, invalid id message, role-slug regex doc
- Tasks 6, 7: complete (b1dd35a..54922a9)
- Task 8: dispatched (opus, BASE 54922a9; F1, Q4, Q8, Q18, rollback reuse)
- Task 8: implementer done (42b9b38; 2020 tests; live create: disabled+attached, tb-list shows, fixture page byte-identical, cleanup complete); controller deleted 3 leftover change-log rows of the live check (1248–1250)
- Task 8: review (opus): never-enabled verified on all paths incl. forced read-back; rollback per step live; unsaved-editor detection = Divi's hasDraft; rights live. Important: post inserted by Divi before it fails (throw inside store_template/insert_layout after wp_insert_post) not tracked → orphan published et_template (disabled/detached, no visible effect); minors: orphan layout_type term relationships after delete, partial() names deleted IDs, refuse() loses details, default template editability
- Ruling Q19: while guarded() runs, record IDs of posts inserted of the expected types (wp_insert_post action) and hand them over (exception subclass carrying IDs) so TemplateBuild rolls them back; undo() also removes layout_type term relationships; partial() lists only IDs whose delete failed; refuse() keeps all failure details; defaultTemplate() respects canEditTemplate — fix round 1 — cost if wrong: none
- Task 8: fix round 1 (Q19; 2827fd4; 2030 tests; live wp_die-in-hook on template and layout save → write_failed, nothing left) — verified by controller; residual (throw between DB insert and first cache clean) documented, accepted
- Task 8: complete (54922a9..2827fd4)
- Tasks 9–10: dispatched (opus, BASE 2827fd4, one commit each; Q3, Q9, Q8, Q16, Q18)
- Tasks 9–10: implementer done (0975b2f tb-assign; 64fc439 tb-activate; 2056 tests; live on temp draft only, visible site unchanged, cleanup verified)
- Ruling Q20: the off-switch (tb-activate enabled:false) is exempt from the unsaved-editor refusal (E7) — reducing visibility must always be possible; result warns that saving an open Theme Builder editor may restore its own state — cost if wrong: a stale editor may re-enable (warned)
- Tasks 9–10: review (opus): spec ✅ both; live: no path makes a template visible except confirmed activate (reattach disables first), Q3/Q9 dry runs, Q16 trash off-switch no oracle, rights, change log; visible site unchanged at every step; changes requested: overlap lists leak uneditable live templates (Q8/B11), Q20 not yet implemented
- Ruling Q21: one shared ThemeBuilderAccess::editableLiveTemplates() used by tb-list, tb-assign and tb-activate dry runs; uneditable live templates only as a count („weitere aktive Vorlagen ohne Berechtigung“); Q20 implemented (off-switch skips draft refusal + warning); minors: dedupe overlaps vs possible_overlaps, reattach records previous enabled state in previous/log, stricter exclude_from null handling, live from $after->isLive() — fix round 1
- Tasks 9–10: first fix-round implementer stopped by user mid-way; user said 'weiter' → fresh opus implementer continues from uncommitted partial work (Q20, Q21, minors)
- Tasks 9–10: fix round 1 (Q20, Q21, minors; a31d434; 2068 tests); tb-list hidden_live count; re-review running
- Tasks 9–10: re-review clean (Q21 no leak, counts only; Q20 live with a real Divi draft; minors fixed)
- Ruling Q22 (must, final wave): ThemeBuilderEdits::showing()/listing() use editableLiveTemplates() (count for hidden) — same leak class as Q21, in layout-edit confirm details — cost if wrong: none
- Tasks 9, 10: complete (2827fd4..a31d434)
- Task 11: dispatched (opus, BASE a31d434; Q11 both forms, Q21 pattern)
- Task 11: implementer done (6be2e65; 2084 tests; live read-only on 2391); DynamicFields::metaKeyOf reads both forms (Q11), choice/relation notes, editable templates only, dry run shows field warnings
- Ruling Q23: the plan's review checkpoint after Task 11 is covered by per-task reviews + the final whole-branch review (every task so far reviewed with live checks) — no separate checkpoint review — cost if wrong: late discovery of cross-task drift (final review)
- Task 11: review (sonnet): Approved; metaKeyOf matches Divi's DynamicContentOptionPostMetaKey branch for branch, live fixture 2391 unchanged, no leak, named-arg wiring correct
- Task 11: complete (a31d434..6be2e65)
- Tasks 12–13: dispatched (opus, BASE 6be2e65, one commit each; bounded, no leaks, cheap write-time warning)
- Tasks 12–13: implementer done (f82964f find-similar: caps 200 posts/200 matches/5000 nodes, batch loads; 4f70886 write-time warning: ≤200 library sections cached per request; 2102 tests; smoke ok)
- Tasks 12–13: review (sonnet): both Approved; live find-similar as admin + temp author: no oracle (P12 forbidden for foreign reference), pagination exact, excluded types uniform; minors → final wave: excluded-type message names "" type; multi-type own-posts restriction documented
- Tasks 12, 13: complete (6be2e65..4f70886)
- Tasks 14–15: dispatched (opus, BASE 4f70886, one commit each; Q7 referencesAny, reuse library-save/GlobalInstance/VisibleEdits, per-page results)
- Tasks 14–15: implementer done (44c1804 make-global + NewLibraryEntry shared + referencesAny; e733065 replace identical occurrences: pre-check all targets, per-page commit+revision, stop at first failure with changed/failed/unchanged lists; 2160 tests; smokes ok)
- Ruling Q24: make-global refuses Theme Builder layouts also as SOURCE (stricter than brief; keeps TB edits on the TB tools) — cost if wrong: a TB section can't be made global directly (copy to a page first)
- Tasks 14–15: review (opus, SEC): T14 Approved (referencesAny 27 spellings live, rights, rollback); T15 Important: Fingerprint::body ignores text parts / core-block inner HTML → "identical" target with different visible content replaced (live, silent content swap); minors: revision note on page-N failure, "pages and posts only" wording vs Divi-enabled types; Low: Divi re-runs do_blocks in shortcode module/Woo checkout text → escaped global-layout inside JSON value expands (document with P25)
- Ruling Q25: Fingerprint content hash includes non-whitespace text parts and full bytes of opaque blocks (structure hash unchanged); plans() additionally compares normalized serialized bytes of the node; regression tests for both variants; find-similar "identical" uses the same fix; failed-page message keeps "Revision X bleibt erhalten"; scope check matches wording (only page/post types, or wording = Divi-enabled types) — decide pages+posts only; Low item documented with P25 — fix round 1 — cost if wrong: none
- Tasks 14–15: fix round 1 (Q25; 4e95983; 2170 tests; smokes ok; live: altered copies no longer identical, forced confirm refused, pages unchanged) — verified by controller against the reviewer's repro scenario
- Tasks 14, 15: complete (4f70886..4e95983)
- Tasks 16 (docs, opus) and 17 (tb-smoke + acceptance, opus) dispatched in parallel, BASE 4e95983 (disjoint files)
- Task 16: implementer done (3db96a3; 2173 tests; v0.5.0); docs honest about open Q22/Q17-M1 (final wave)
- Task 16: review approved (spec ✅, quality approved; 2173 tests re-run green; only cosmetic line-wrap nit)
Task 16: complete
- Task 17: implementer done (0b7a1c2; 2173 tests; all 7 smokes green); deviations: enabled template on temp draft page via preview, temp pod never enabled, read-only → not found. Review dispatched (sonnet)
- Task 17: review approved (spec ✅, quality approved; smoke re-run live green, no leftovers, TB baseline 1065=0 1066=0 2394=0)
Ruling: Claude-Session trailer after Co-Authored-By is correct — the session's current attribution instruction requires both lines; common.md predates it — cost if wrong: cosmetic
Task 17: complete
- Final whole-branch review + security audit dispatched in parallel (opus), range 0edb474..0b7a1c2
- Final review done: 0 critical, 3 important (I-1 Q22, I-2 Q17M1 + TB-ID leak to library-only editors, I-3 Q17M3), 12 minor; report final-review.md. Ruling: drop Q17 M4 (shared confirm helper) — 13 call sites project-wide, out of scope — cost: minor duplication stays. Waiting for security audit before fix wave.
- Security audit done: 0 C/H/M, 4 Low (L1=Q17M1, L2=Q22, L3 TB/library revisions not restorable via MCP, L4 reattach accepts TB-library templates), 3 Info; report security-audit.md
Ruling: fix wave covers I-1..I-3, L1..L4, all final-review minors except Q17 M4 — both reports agree, all small — cost if wrong: extra churn
Ruling: L3 gets the minimal fix (restore_url to WP revision screen + corrected docs), not MCP restore for TB/library types — the full route needs new access wiring, belongs to Etappe U — cost: restore stays a manual step in wp-admin
Ruling: I1 stays a warning (display parity, preflight ruling), I2 documented in guide, I3 unchanged like 3a — cost: none beyond 3a status quo
- Final fix wave dispatched (opus), BASE 0b7a1c2
- Fix wave done: 7590da4 43dc3fb 79f2fdb dcae2d4 e64d32b 5290a9d e7bbe1e 14bc954 6288acf 50cfa42 beb8706; 2199 tests, lint clean, tb/library/write smokes green, TB baseline off
Ruling: accept stricter I-2 (read-only TB group also blocks global edits reaching TB layouts) — matches the guide and group semantics — cost: a global edit may be blocked where the owner expected it to pass; one-line revert noted in fixwave-report
Ruling: accept M-9 forbidden for accounts without any TB rights (tool-level, ID-independent, same as tb-list) — no existence oracle since answer does not depend on the ID; Q18 not_found stays for per-template refusals — cost: answer-code change for clients
- Scoped re-review dispatched (opus), range 0b7a1c2..beb8706
- Re-review: Approved (all in-scope findings addressed; N-1 minor docblock, N-2/N-3 info). Ruling: fix N-1, partial-write restore_url (completes L3) and make-global backup hint now via resumed fix-wave agent; N-2 as guide sentence; N-3 left — all tiny, closes L3 cleanly — cost: one more small commit set