Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 32 additions & 0 deletions .planning/MILESTONES.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,37 @@
# Milestones: Maestro

## v1.5.0 Per-User Visibility (Shipped: 2026-08-09)

**Phases:** 21 (built under the v1.4 roadmap) + 26 (release). **Release tag:** `v1.5.0` (commit `694b1bf`) · GitHub Release + WordPress.org SVN `trunk`/`tags/1.5.0`, verified from SVN.

**Delivered:** ROLE-02's **per-user half**. An admin can hide a menu item from named individuals as well as whole roles, on four independent axes (role × person, item × sub-items). Cosmetic only, like every other hide in Maestro: a hidden page still opens by URL for anyone authorized, and no capability changes.

**Key accomplishments:**
- `items[slug].hidden_users` / `child_hidden_users` storage, sparse and capped at `MAX_HIDDEN_USERS`
- `is_hidden_for_current_user()` widened to independent OR'd terms, with the third reserved for the deferred `hidden_profiles` half — the seam stays a pure identity intersect and never touches a capability
- `resolved_hidden_roles()` **generalized** into a field-parameterized resolver rather than duplicated, so the user axis inherits the qualified-key, schema-v2 and Axis-1 guards from one implementation
- The feasibility note's §6 cosmetic-invariant guardrail made **enforcing** (`CosmeticInvariantUsersTest`)
- Four-group visibility popover with an async person picker on core's `wp/v2/users`, gated by `list_users` on both sides
- A multisite CI lane, closing the super-admin exemption's coverage gap

**NOT in this milestone:** the cloned-role **"profiles"** half of ROLE-02, still a backlog item (`todos/pending/2026-08-02-cloned-role-hiding-profiles.md`). ROLE-02 remains **partially delivered**. Phase 22 (demo) and Phase 25 (toolbar polish) were optional inclusions that did not land.

### What this milestone should be remembered for

**Nine defects were found by verification and review; almost none by the test suite as first written.** Three surfaced during Phase 21's own browser checks — including a guardrail that could not detect a broken seam, because `current_user_can()` answers from a cached allcaps array. Two more came from Codex rounds on the plans, both of which I then hit as live bugs anyway. The adversarial security gate found two. The final ultrareview found three.

Most instructive: **four consecutive holes in `Config::sanitize()`'s per-user authorization path**, each fix correct about the case in front of it and blind to the next — client-only gate → payload-scoped preserve → raw-key matching → item-cap starvation, plus a DELETE endpoint that bypassed all of them. After each fix the path looked settled. It was only resolved by *collapsing* three mechanisms into one normalized-key map with reserved capacity, rather than adding a fifth guard.

The transferable lesson: when a fix keeps needing another fix, the shape is wrong, not the coverage.

**Known limitations, carried deliberately rather than dropped at the finish line:**
- The final round of fixes (#128) is itself unreviewed — the ultrareview ran against the prior commit
- No human screen-reader pass on the person picker; axe is clean across empty and populated states, which is not the same claim
- 21-05 Task 5 (human browser verification) was never performed; the phase was accepted on automated evidence
- On multisite, super admins are exempt from the person axis only — deliberate, now tested both ways

---

## v1.3.0 Slug-Resolution Hardening (Shipped: 2026-06-30)

**Phases completed:** 2 phases (17–18), 6 plans. **Release tag:** `v1.3.0` (commit `884c6df`) · GitHub Release + WordPress.org SVN `trunk`/`tags/1.3.0`.
Expand Down
6 changes: 3 additions & 3 deletions .planning/REQUIREMENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ backlog IDs without renumbering.
### Roles (cosmetic only)

- [x] **ROLE-01**: A feasibility note determines whether per-user and/or cloned-role cosmetic menu hiding can be delivered **without** touching capabilities (stays cosmetic per the core value) within WordPress's role/user model, and specifies the storage shape + resolution seam. **Gates ROLE-02** — if it can't stay cosmetic, ROLE-02 defers. *(Complete 2026-07-05 — Phase 19. Verdict: **partial-go**; both branches clear the cosmetic-only bar. Storage: inline `items[slug].hidden_users` axis + a `profiles` registry compiling onto `items[slug].hidden_profiles`; seam: widen `is_hidden_for_current_user()`. Phase 21 unblocked, per-user first. See `phases/19-cosmetic-hiding-feasibility/19-FEASIBILITY-NOTE.md`.)*
- [~] **ROLE-02**: An admin can apply cosmetic menu-hiding rules scoped to a **specific user** (or a cloned role), intersected against that user's live roles. The rules never grant or remove a capability; a hidden page still loads by URL for a user who has the capability. *(conditional on ROLE-01)* — **PARTIALLY DELIVERED (Phase 21, v1.5).** The **per-user** half is complete: `items[slug].hidden_users` + `child_hidden_users`, resolved through the same single `is_hidden_for_current_user()` seam as the role axes, with the cosmetic invariant enforced by `tests/integration/CosmeticInvariantUsersTest.php` and the effect proven in a targeted user's real sidebar by `tests/e2e/specs/hidden-users.spec.ts`. The **cloned-role "profiles"** half is NOT delivered and remains a v1.5 backlog item — see `todos/pending/2026-08-02-cloned-role-hiding-profiles.md`; the seam is built as an OR of independent terms so `hidden_profiles` lands as a third term without rework. Known limitation: on multisite, network super admins are exempt from the per-user axis only (the role axes keep their v1.4.1 behaviour); that exempt branch is not covered by the single-site test suite.
- [~] **ROLE-02**: An admin can apply cosmetic menu-hiding rules scoped to a **specific user** (or a cloned role), intersected against that user's live roles. The rules never grant or remove a capability; a hidden page still loads by URL for a user who has the capability. *(conditional on ROLE-01)* — **PARTIALLY DELIVERED (Phase 21, v1.5).** The **per-user** half is complete: `items[slug].hidden_users` + `child_hidden_users`, resolved through the same single `is_hidden_for_current_user()` seam as the role axes, with the cosmetic invariant enforced by `tests/integration/CosmeticInvariantUsersTest.php` and the effect proven in a targeted user's real sidebar by `tests/e2e/specs/hidden-users.spec.ts`. The **cloned-role "profiles"** half is NOT delivered and remains a v1.5 backlog item — see `todos/pending/2026-08-02-cloned-role-hiding-profiles.md`; the seam is built as an OR of independent terms so `hidden_profiles` lands as a third term without rework. Known limitation: on multisite, network super admins are exempt from the per-user axis only (the role axes keep their v1.4.1 behaviour) — an intentional asymmetry, now covered by a dedicated multisite CI lane (`npm run test:php:multisite`). SHIPPED in v1.5.0 (tag `v1.5.0` on `694b1bf`, 2026-08-09).

### Editor UX

Expand Down Expand Up @@ -60,7 +60,7 @@ first; neither blocks the cut.

### Release

- [ ] **REL-11**: v1.5 is cut and shipped — runtime zip builds clean, Plugin Check 0 errors, full PHP/JS/e2e suites green, tagged `v1.5.0`, deployed to WordPress.org SVN `trunk` following the v1.2/v1.3/v1.4 pipeline (**including the manual `wp-deploy.yml` dispatch**, which has never been automatic); changelog verified against the `v1.4.1..main` diff rather than the phase list; **screenshot 3 recaptured** to show the visibility popover's four groups instead of two; and the multisite super-admin exemption stated as a known limitation.
- [x] **REL-11**: v1.5 is cut and shipped — runtime zip builds clean, Plugin Check 0 errors, full PHP/JS/e2e suites green, tagged `v1.5.0`, deployed to WordPress.org SVN `trunk` following the v1.2/v1.3/v1.4 pipeline (**including the manual `wp-deploy.yml` dispatch**, which has never been automatic); changelog verified against the `v1.4.1..main` diff rather than the phase list; **screenshot 3 recaptured** to show the visibility popover's four groups instead of two; and the multisite super-admin exemption stated as a known limitation.

---

Expand Down Expand Up @@ -96,7 +96,7 @@ Which phases cover which requirements. Populated during roadmap creation.
| UX-13 | Phase 23 | ✅ Complete 2026-07-05 |
| BUG-08 | Phase 23 | ✅ Complete 2026-07-05 |
| REL-10 | Phase 24 | ✅ Complete 2026-08-04 (v1.4.0; patch v1.4.1 2026-08-05) |
| REL-11 | Phase 26 (v1.5) | Pending — ships Phase 21's per-user hiding |
| REL-11 | Phase 26 (v1.5) | ✅ Complete 2026-08-09 (tag v1.5.0 on 694b1bf; SVN verified) |

**Coverage:**
- v1.4 requirements: 11 total
Expand Down
4 changes: 2 additions & 2 deletions .planning/ROADMAP.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
- ✅ **R1 Third-Party Compatibility Research** — Phases 13–16 (completed 2026-06-29; non-versioned research — no plugin code, no release tag, no SVN deploy) → [archive](milestones/R1-ROADMAP.md)
- ✅ **v1.3.0 Slug-Resolution Hardening** — Phases 17–18 (shipped 2026-06-30; release tag `v1.3.0`) → [archive](milestones/v1.3.0-ROADMAP.md)
- ✅ **v1.4 Compatibility, Roles & Showcase** — Phases 19–24 (shipped 2026-08-04; release tag `v1.4.0`, patch `v1.4.1` 2026-08-05). Shipped **without** Phase 21 (ROLE-02, deferred to v1.5 under the Release Binding fallback) and Phase 22 (not reached; still open).
- 🚧 **v1.5 Per-User Visibility** — Phase 21 (built under the v1.4 roadmap, ships here) + Phase 26 (release). Phases 22 and 25 are **optional inclusions**: they ship in v1.5 if they land before the cut, and otherwise slip without blocking it.
- **v1.5 Per-User Visibility** — Phase 21 + Phase 26 (shipped 2026-08-09; release tag `v1.5.0` on `694b1bf`). Delivered ROLE-02's **per-user half**; the cloned-role "profiles" half remains a backlog item. Phases 22 and 25 were optional inclusions and did **not** land, per the fallback.

## Phases

Expand Down Expand Up @@ -295,7 +295,7 @@ feature is built (Phase 21, 5/5 plans, 2026-08-08) but unreleased — v1.4.0 was
cut before it landed. This milestone exists to get it to users.

- [~] **Phase 21: Cosmetic Per-User Hiding** — built under the v1.4 roadmap (details in the v1.4 section above); ships here. Per-user half complete; cloned-role profiles remain a backlog item.
- [ ] **Phase 26: Release v1.5.0** — cut and ship to WordPress.org
- [x] **Phase 26: Release v1.5.0** — cut and shipped to WordPress.org 2026-08-09 (tag `v1.5.0` on `694b1bf`; GitHub Release + SVN `trunk`/`tags/1.5.0` verified from SVN)
- [ ] *(optional)* **Phase 22: Slug-Resolution Showcase Demo** — ships in v1.5 if it lands before the cut
- [ ] *(optional)* **Phase 25: Edit-Mode Toolbar Dark-Surface Polish** — ships in v1.5 if it lands before the cut

Expand Down
Loading
Loading