|
1 | 1 | ## Last session |
| 2 | +2026-08-16 (**the four pillars swept, Mark's ChatGPT bug root-caused and fixed, and every open PR resolved**) — Fahim's ask opened as "context, guardrails, tools and a system must work smoothly", turned into Mark Roach's ChatGPT report mid-session, and ended with "merge now" on the whole open-PR backlog. Eleven PRs merged (#90, #92, #94, #96, #98, #99, #66, #68, #69, #100, #101, #102); #70 closed as already-landed; **zero open PRs**. 575 tests, 0 lint errors. |
| 3 | + |
| 4 | +**Mark's bug is fixed, and it was ours.** His two-client experiment isolated it: Claude Desktop via mcp-remote worked end to end against staging.kesuk.net while ChatGPT completed OAuth and then reported no callable actions. That rules out abilities, tiers, OAuth and the endpoint, leaving the handshake. `Saddle_MCP` violated three Streamable-HTTP MUSTs, and one sits between "connected" and `tools/list`: a notification must be answered **202 with no body**, and Saddle answered `200` with the JSON literal `null`. mcp-remote shrugs; a strict client treats the handshake as unfinished and never asks what tools exist. Also fixed: GET now 405 (was 404), DELETE 405, unsupported `MCP-Protocol-Version` 400, unparseable body 400, and `resources/*`/`prompts/list` answer empty lists instead of Method-not-found. **This was never only Mark** — since `bff1a99` the .org zip has no adapter, so that transport is the only one a .org install will ever have. |
| 5 | + |
| 6 | +**A trap worth remembering:** leaving GET unregistered LOOKS conformant, because `WP_REST_Server::dispatch()` answers a method mismatch with 405 — so a test written against `dispatch()` passes while real clients get 404. I wrote that test, concluded "already correct", and only caught it by curling a Playground install running the built wporg zip. The suite cannot route to this transport at all (the dev tree carries the adapter), so the handler is unit-tested and the routing is verified on the wire. |
| 7 | + |
| 8 | +**The four pillars.** Guardrails: wrapped destructive tools passed no `bind`, so a confirm could carry different arguments than its preview — the two-step confirm doing the opposite of its job. Tools: `tools/list` advertised everything regardless of tier; a default read-tier install showed 30 tools that are refused on every call. Now filtered at dispatch (never at registration — that runs pre-auth), with the withheld count stated in prose so an agent can name the setting instead of reporting the site can't do it. Context: `Saddle_Context_Bundle::summary_lines()` was dead code, the steering still described the five calls `context-bundle` replaced, and recent-changes stuttered six lines for one post. System: `build-page` was gated on `wp_is_block_theme()`, so classic themes got no playbook; now gated on "no foreign builder", plus a new `fix-page`. |
| 9 | + |
| 10 | +**#86 closed.** The adapter's undeclared second endpoint is disabled, and disabling it let three test files drop the `_doing_it_wrong` workaround they carried. There is now a test asserting every MCP route is one of Saddle's own — verified to fail when the filter is removed. |
| 11 | + |
| 12 | +**The vendored lib was hand-edited, and now is not.** 147 text domains rewritten across 18 files, existing only as edits that a re-vendor would silently drop. Recorded as `scripts/revendor-wp-mcp.php`, verified by reverting the library and reproducing main byte-for-byte. Only the text-domain *argument* is rewritten; `'mcp-adapter'` also appears 5 times as an ability category and server id, which are identifiers. |
| 13 | + |
| 14 | +**Merging the July stack.** #67 auto-closed when #66's base branch was deleted, and GitHub won't reopen a PR whose base is gone — recreated as #99, then retargeted #68/#69 to `main` BEFORE merging their parents. Three real decisions in those merges: #69's **1.1.0 version bump reverted in four places** (readme's `Stable tag` was NOT a conflict and would have shipped silently); the wrapper bind kept as sha256-over-key-sorted rather than truncated md5 (without sorting, a client reordering its JSON has a legitimate confirm refused); and one of my own tests corrected, having asserted a precedence `permission()` does not use. |
| 15 | + |
| 16 | +**Branch cleanup.** 27 local / 19 remote → 5 local / 4 remote. Every merged branch deleted, including 9 squash-merged local-only ones verified upstream with `git cherry`. |
| 17 | + |
| 18 | +## Previous session |
2 | 19 | 2026-08-12 (**CLAUDE.md rewritten from scratch; positioning + direction set; self-hosted update channel built and SHIPPED LIVE; Mark's remaining ChatGPT bug diagnosed but NOT fixed**) — Fahim's asks, in order: read Brian Coords' agent-first block-theme post and find what applies to Saddle; audit Novamira (free repo + local `novamira-pro` 1.5.0); rewrite `CLAUDE.md` clean with the old roadmap and issue links dropped; discuss what Saddle stands for; then "focus Saddle free: make sure it updates from here" → "clean just an updater" → "recreate all" → "live now". |
3 | 20 |
|
4 | 21 | **Positioning landed (now the Direction section of CLAUDE.md).** Transport is table stakes — WP 7.0 shipped the Abilities API + AI Client + Connectors, and 7.1 (**Aug 19**) adds granular AI permissions and connector filtering, i.e. core is building Saddle's tier layer from the other end. The product is the layer *above*: understand the design system → commit constraints → build → verify. Buyer = developers/agencies running WordPress from Claude Code/Codex. Scope locked to **Gutenberg (free) + Divi (Pro)**; no third builder, no chat UI, no screenshot engine (the buyer arrives with eyes — Saddle makes the page judgeable, `get-preview-url` + honest coverage caveats, and lets the agent judge). |
@@ -246,24 +263,14 @@ Earlier 2026-07-12 — **Audit-backlog execution (P0–P4)**. Cleared the audit |
246 | 263 | - Earlier same day: the Closed-Loop Quality Engine free half (epic #22, PRs #28–#32, 300 green) — see git history. |
247 | 264 |
|
248 | 265 | ## Next up |
249 | | -- **Reply to Mark Roach** (support thread "Findings from testing Loggle & Saddle…", not asked for this session so not drafted): free's fixes ride in the refreshed `dist/saddle-1.0.0.zip` and Pro 1.2.2 removes the version demand — his three Saddle screenshots are all addressed. **Ask him to rotate the mrr.org.uk credentials he emailed in plaintext.** His offer of a live 20i test site stands if Fahim wants real-StackProtect confirmation of the `?rest_route=` fallback. |
250 | | -- **Ship Loggle's own fallback** — its `src/admin/api.js` WAF+nonce work is still **uncommitted** in the loggle working tree, and the customer's installed 1.0.0 lacks it (his "log out then log in again" workaround is the stale-nonce gap). Commit + release from the loggle repo. |
251 | | -- **Delete the v1.1.0 GitHub release + tag (Fahim, one command):** `gh release delete v1.1.0 --repo plugpressco/saddle --cleanup-tag --yes && git tag -d v1.1.0`. The code-side rollback to 1.0.0 is already committed (`f448d74`); this is the only piece left, blocked for the agent by the permission classifier. |
252 | | -- **Write meta descriptions for the 11 posts/pages that lack them — this is the actual lever on the 86/100.** `meta_coverage` scores 3/10 and counts posts + pages only (15 items), so the 38 docs done on 2026-08-02 cannot move it. Use `waggle/generate-seo-meta` for drafts, approve, then `waggle/update-seo-meta`. Same rules: 140–160 chars, unique, focus keyword must appear verbatim in the title or description or the lint warns. |
253 | | -- **Set the share-card default** in wp-admin → SEO → Social. Unreachable from the MCP side (see last session); needs a real 1200×630 branded card — none of the 21 uploaded screenshots is one. Clears the `og_image` warning on every doc at once; the per-post `featured_image` error stays open by decision. |
254 | | -- **Eight Waggle docs need an FAQ section and H3s:** `waggle-aeo-score`, `waggle-how-ai-bots-find-markdown-pages`, and the six `waggle-troubleshooting-*` pages. `waggle-troubleshooting-machine-files` also has only 2 internal links. Coordinate first — these were being edited by someone else on 2026-08-01. |
255 | | -- **Purge the page cache** after any docs change; plugpress.co serves stale HTML for a while otherwise. |
256 | | -- **Docs follow-ups (small):** capture the OAuth consent screen and a deletion-preview-as-a-client-renders-it, and drop them into `/docs/oauth-sign-in/` and `/docs/safe-deletions/` — both were skipped because the local Studio site has neither state. Optionally re-shoot the Permissions access-levels figure so both figures in that doc come from the same site. |
257 | | -- **[saddle#59](https://github.com/plugpressco/saddle/issues/59)** — Integrations screen ignores plugins that self-enrol via `saddle_integrations`; derive the category from the live catalog instead of the hardcoded prefix list at `class-saddle-rest.php:788`. One-file fix. |
258 | | -- **Live ChatGPT round-trip on plugpress.co — the real gate for the OAuth work, not yet run.** Turn on Settings → "Sign-in for ChatGPT", confirm the readiness strip says discoverable, then in ChatGPT (Developer Mode → Settings → Connectors → Create) paste the MCP address, pick OAuth, leave client ID/secret blank. Watch for: discovery found, consent screen renders, code exchange succeeds, `tools/list` returns, a read tool call works, then Revoke and confirm the connector dies immediately. Worth knowing before testing: **ChatGPT restricts write-capable custom connectors to Business/Enterprise/Edu** — on Plus or Pro it will be read-only regardless of the granted scope, which is ChatGPT's limit, not Saddle's. |
259 | | -- **Uncertainty this test resolves:** whether ChatGPT honours `resource_metadata` from the 401 challenge, or only probes `/.well-known/*` at the host root. If only the root, OAuth needs WordPress at the domain root and the Settings readiness strip should say so more bluntly. |
260 | | -- **Then rebuild the zip** (`npm run build && npx grunt build` — never `grunt release`, it bumps the version) and re-upload. |
261 | | -- **SUBMIT to WordPress.org — everything code-side is done (2026-07-23 audit: zero blockers).** Fahim's three steps, all in `WPORG-SUBMISSION.md`: (1) confirm `badhonrocks` is the submitting wp.org username (it's the readme `Contributors:` value), (2) upload `dist/saddle-1.0.0.zip` at wordpress.org/plugins/developers/add/, (3) after approval: screenshots ×4 + banner/icon into SVN `assets/`, then the first public GitHub tag/release (rolled-back v1.0.0 tag rule — tag only AFTER approval). Reviewer-pushback answers are pre-written in `WPORG-SUBMISSION.md`. |
262 | | -- **If HEAD moves before upload:** rebuild with `npm run build && npx grunt build` (never `grunt release` — it bumps the version). |
263 | | -- **Final visual pass in wp-admin** (fix-forward): topbar under admin bar at 32px/46px, status pill flips with tier/pause, Memory drawer, Permissions chip tooltips, 960 column everywhere, <782px icon rail; Unsplash demo-key round-trip (search → import → re-import reuse → force → Media filter → remove key), then close #60 + #61 on the board. |
264 | | -- **Feature backlog:** free has none open; Pro: #1 Rank Math / #2 CF7 / #3 Elementor all deferred by decision, #4 hygiene tail. |
265 | | -- Consider a free minor release (0.10.0) bundling the UI migration; Pro's min-free constant bump to match is still pending in Pro. |
266 | | -- CI PHPUnit still red on GitHub Actions (no WP core in the runner) — fix as its own PR so future PRs get a real green. |
| 266 | +- **Reply to Mark Roach with a build to test.** The handshake fix is in `main` and unreleased. Two things to tell him beyond "try this": at the read tier he is now offered 36 tools rather than 66 (the new filter working as designed — and relevant because **ChatGPT restricts write-capable connectors to Business/Enterprise/Edu**, so on Plus or Pro his connector is read-only whatever scope he approved); and if it still shows nothing, **Connections → Connection details & health → Client traffic** is the next diagnostic. A `tools/list` row with status 200 and a non-zero count means Saddle is conformant and the tools are being dropped inside ChatGPT — a [documented](https://community.openai.com/t/mcp-connected-but-not-invokable/1384847) connector bug. **Still ask him to rotate the mrr.org.uk credentials he emailed in plaintext.** |
| 267 | +- **Migrate saddle-pro and mailyard onto `saddle_context_sections`.** Free's half shipped in #102 and both still append through the old string filter, so Pro's `##` heading and Mailyard's floating "For email delivery problems:" sentence are still in the live context. Pro's tree currently has uncommitted release prep in it (a 1.4.0 → 1.4.1 bump), which is why it was left alone. Nothing breaks meanwhile — the compat path is tested. |
| 268 | +- **The three surviving branches are all superseded or dead — decide and delete.** `feat/admin-header` (9 commits) and `feat/ui-plugpress-ui-v0.6.0` (a strict subset of it) targeted `@plugpress/ui` v0.8.2; `main` is on **v0.11.3**, TopBar and `Saddle_Log::record_action()` are both there, and every file they add exists on main in restructured form. `feat/freemius-parent` puts Freemius in FREE, which contradicts both CLAUDE.md ("no licensing or upsell in free") and the decision that free ships on WP.org with no Freemius. |
| 269 | +- **Delete the v1.1.0 GitHub release + tag (one command):** `gh release delete v1.1.0 --repo plugpressco/saddle --cleanup-tag --yes && git tag -d v1.1.0`. Still outstanding, and #69 tried to reintroduce 1.1.0 this session — reverted in four places, including a `Stable tag` that was not a conflict and would have shipped silently. |
| 270 | +- **Run `php scripts/revendor-wp-mcp.php --check` before any release.** New pre-release guard: it exits non-zero if the vendored library was refreshed without re-applying Saddle's text domain. |
| 271 | +- **SUBMIT to WordPress.org.** Everything code-side is done and this session removed one of the reviewer-facing surfaces (#86). Fahim's three steps are in `WPORG-SUBMISSION.md`. Rebuild first: `npm run build && npx grunt build` — never `grunt release`, it bumps the version. |
| 272 | +- **Live ChatGPT round-trip on plugpress.co** — still the real gate for the OAuth work, and now also the confirmation that the handshake fix holds against the client that exposed it. |
| 273 | +- **CI PHPUnit still red on GitHub Actions** (no WP core in the runner). Worth its own PR so future PRs get a real green; "green" currently means someone ran the suite locally and said so. |
267 | 274 |
|
268 | 275 | ## Blockers / open questions |
269 | 276 | - Old work tickets #4–#6 remain from the previous scope — #5 (design-system unify) partially overlaps the shipped brief/bundle; triage against the new scope when convenient. (#8 closed 2026-07-11.) |
0 commit comments