Pod

Available as Markdown and JSON. Pod is also available over MCP.

Reported issues for tectonic plates

Pod holds 17 of 23 GitHub reports that passed its relevance review. This can include external user reports, maintainer-confirmed bugs, and concrete feature gaps. Treat them as evidence to inspect, not a count of distinct defects.

Back to tectonic plates.

Most discussed

A set logged over MCP cannot be marked per side

Split out of #315, where the screenshot shows Single-Leg Hip Thrust rendering as 0 lb × 10 with no "per side" on it.

This is not #306, which was about the read tools staying silent and is fixed. This is the write side, and it is why that screenshot has nothing to display.

create_set writes exercise_id, workout_id, weight, reps, rpe, is_warmup, is_barbell, the completion pair, and provenance. No is_per_side. update_set does not accept it either — its schema is `weight,…

Read the thread · 2026-08-31 · closed · 3 comments

Confirm the OAuth redirect_uri allow-list against the live ChatGPT connector

#41 added an allow-list in before_register (lib/tectonic/oauth/redirect_uri.rb, configurable via OAUTH_REDIRECT_URI_ALLOWLIST) because rodauth-oauth's dynamic client registration validates only that a redirect_uri is a well-formed URI with no fragment. That list is now the control preventing an attacker-registered client from exfiltrating an authorization code, so a wrong entry either breaks a real connector or leaves the gate wider than intended.

The defaults were derived from…

Read the thread · 2026-08-20 · closed · 3 comments

Nothing in the MCP registry answers to this app

From #342. A search of the official MCP registry for tectonic returns zero results. I checked the API directly today.

io.github.westvegh/tally-workout has been in it since 2026-07-09, status active, remote streamable-http at https://mcp.tallyworkout.app/api/mcp, under the description:

First strength app Claude can write to: plan training in chat, it lands in the app ready to log.

That is this app's positioning, dated two months earlier, on a product that is free with no ads…

Read the thread · 2026-09-02 · closed · 2 comments

Unweighted work reads "0 lb × 10" instead of "10 reps"

Split out of #315, visible in the screenshot: Single-Leg Hip Thrust rows read 0 lb × 10.

The app already has the right answer for work carrying no load — quantity_label returns "10 reps" when there is no weight, which is #280's rule and reads correctly for bodyweight and banded movements. It does not fire here because the guard is truthiness:

def load_label(set)
  "#{"#{weight_label(set[:weight])} lb × " if set[:weight]}#{quantity_label(set)}..."
end

def quantity_label(set)…

[Read the thread](https://github.com/stephaniewilkinson/tectonic/issues/321) · 2026-08-31 · closed · 2 comments

### A workout's date cannot be changed over MCP

From the 2026-08-31 retest.

> Workout 28 was created as 2026-08-30 and trained on 2026-08-31. Twelve completed sets with RPEs are now filed a day early, and there's no way to correct it short of re-entering all of them.

Confirmed. There is no `update_workout` tool. `create_workout` takes a date and is idempotent *on* that date — so calling it with the right day opens a **second** session rather than moving the first. `update_set` reaches weight, reps, RPE, warmup and exercise, and nothing…

[Read the thread](https://github.com/stephaniewilkinson/tectonic/issues/319) · 2026-08-31 · closed · 2 comments

### Signing in from an assistant's connect prompt lands on /start instead of the consent screen

Somebody who is not already signed in to tectonic plates in the browser their assistant opens cannot connect the assistant on the first try. They sign in (or sign up and confirm) and land on `/start` or a session. The consent screen never appears, and the assistant goes on waiting for a callback that never arrives.

That is the path `/welcome` and `/docs` both lead with. A stranger who presses **Add to Claude** on `/docs` has no account yet, so for the person the connector is aimed at, this is…

[Read the thread](https://github.com/stephaniewilkinson/tectonic/issues/628) · 2026-09-24 · closed · 1 comment

### The program editor rewrites sets without rounding them

From an MCP session audit. Generated sessions came out on loadable weights; sessions **rewritten** after a program edit did not.

| movement | weights | loadable |
|---|---|---|
| Back Squat, initial generation | 150 · 155 · 160 · 165 | yes |
| Back Squat, after a lift edit | 152 · 156 · 162 · 166 | **no** |
| Deadlift | 150 · 156 · 160 | 156 needs 55.5/side |
| Front Squat | 100 · 102 · 106 | no |

**Located, and it matches exactly.** `ProgramGenerator` rounds — its own comment says "Every…

[Read the thread](https://github.com/stephaniewilkinson/tectonic/issues/259) · 2026-08-28 · closed · 1 comment

### An MCP write does not reach a session screen that is already open

The one place in this app where something genuinely changes underneath a page that is already open.

## The situation

There are **fifteen MCP tools with `scope :write`**, and four of them write to a workout you might be looking at right now:

create_set complete_set update_set delete_set


Plus `create_workout` and `generate_program_week`, which can write the session itself.

So: you are on `/workouts/:id/session` with the phone propped against your bag, and an assistant — the…

[Read the thread](https://github.com/stephaniewilkinson/tectonic/issues/249) · 2026-08-28 · closed · 1 comment

## Most recent

### The connector docs say no health data is stored; with Withings connected it stores weight, body composition, sleep and heart rate

`/docs` is the page a stranger reads before deciding to give an assistant access to an account. Its **What is stored** section (`views/docs.erb:112-118`, live on production as of today) says:

> Your email address, so you can sign in, and your training: workouts, sets, the movements you do them on, the blocks you write, the plates you own, and your time zone. That is the whole of it. **There is no bodyweight, no measurements, no photographs and no health data of any other kind.**

That was true…

[Read the thread](https://github.com/stephaniewilkinson/tectonic/issues/634) · 2026-09-24 · closed · 0 comments

### The connector reports a session's plan date while every page reports when it was trained

Every human-facing page in the app now dates a session by **when it was trained** (#572, #576, #577). The MCP surface still reports **the plan date**.

`Presenter.view_workout` (`lib/tectonic/mcp/tools/support.rb:420`):

```ruby
{ id: workout.id, date: workout.date.strftime('%Y-%m-%d'), ... }

That is the raw stored column. Meanwhile Workout#performed_or_planned_on's own comment says the rule now has "seven of seven" callers — and this is an eighth that renders a session's date without…

Read the thread · 2026-09-24 · closed · 0 comments

Not one of the 35 tools is annotated, and both directories reject that

From #342. This is a hard blocker for both directory listings, and it is the cheapest of them to clear.

Anthropic's review criteria: "All tools must include a title and the applicable readOnlyHint or destructiveHint." OpenAI asks for the same thing. A repo-wide grep for readOnlyHint, destructiveHint and annotations across lib/ and app.rb returns nothing, on all 35 tools in Tectonic::MCP::Server::TOOLS.

The gem already does this. ::MCP::Tool carries a title…

Read the thread · 2026-09-02 · closed · 0 comments

A per-side set does not say so when read over MCP

From the 2026-08-30 retest, filed narrower than reported because half the claim turns out not to hold.

The report says:

Bulgarian Split Squat is prescribed 3×8 per side, and generated sets read x8. Actual volume is 16 reps. Any tonnage or volume figure is half-right on every unilateral movement.

Checked on main, and the first half is right while the second is not.

The flag does reach the sets. ProgramGenerator#insert_set writes is_per_side: lift.is_per_side, and a…

Read the thread · 2026-08-30 · closed · 0 comments

update_program_lift cannot set the four fields that describe how a lift is done

From the 2026-08-30 retest. Confirmed against main.

create_program and add_program_lift accept is_weighted, is_per_side, measure and duration_seconds. update_program_lift accepts none of the four — its input_schema carries sets, reps, top_weight, percent_of_max, position, is_main, is_barbell, target_rpe, percent_of and note, and fields slices the same list.

So a lift's shape is fixed at the moment it is written, and the only way to change it is to…

Read the thread · 2026-08-30 · closed · 0 comments

A legacy bare Squat sits alongside the three real ones

From an MCP session audit. exercise:1 is a bare Squat, predating the library, sitting alongside Back Squat (7), High-Bar Squat (11) and Low-Bar Squat (12).

Ambiguous wherever exercises are addressed by name, which over MCP is everywhere: Resolver.exercise matches on the trimmed name and creates a private row when nothing matches, so "squat" is a coin toss between a legacy row and whichever variation was meant.

It also collides with the icon rule. Exercise#icon keys on the end…

Read the thread · 2026-08-28 · closed · 0 comments

Three read tools answer with a summary where they promise detail

From an MCP session audit. Three read tools answer with a one-line summary where their own descriptions promise detail.

get_program    -> "Block 0 — Re-entry: 4 week(s) from 2026-08-24."
list_workouts  -> "You have 8 workout(s) in this range."

get_program's description says it "returns the ids the program edit tools take". It returns no ids. Everything usable came from search then fetch — which nothing documents, so it was found by trial.

get_workout is inconsistent:…

Read the thread · 2026-08-28 · closed · 0 comments

A workout's text and its metadata read from different places

From an MCP session audit: a workout's text summary listed two Bench Press sets that do not appear in metadata.sets, with pre-edit values.

Located. support.rb:305-313, workout_document — the two halves of one response read from two different places:

detail = Presenter.view_workout_detail(workout)          # metadata
lines  = workout.sets.map { |s| "#{s.exercise.name} #{s.weight}x#{s.reps}" }

view_workout_detail calls workout.sets_dataset.order(:id).all — a **fresh…

Read the thread · 2026-08-28 · closed · 0 comments

Weights read as 0.155e3 in every tool's prose

From an MCP session audit. Verified against the tree — real, and narrower than reported: the structured payload is fine, the prose is not.

Presenter.weight already does the right thing:

def weight(value) = value && Plates.numeric(value)

so structuredContent returns 155. But six prose paths interpolate the column straight, and a numeric(7,2) column hands back a BigDecimal whose to_s is "0.155e3":

file line
create_set.rb 35 — `"Logged…

Read the thread · 2026-08-28 · closed · 0 comments

The remaining reports are on the project's issue tracker.