docs: say what stride is, and what 1.0 actually promises - #222
Merged
Conversation
…tract PLAN.md exists against AGENTS.md's standing advice, deliberately and in a shape that answers why that advice was given. The last plan file rotted because it restated work that lived in issues, so the copies drifted and nothing read either; a watch-item it tracked fired unnoticed. This one holds no work — only the ORDER and the two constraints that set it, which is the part GitHub cannot carry. Every item is a pointer, and the file says to delete itself when the phases merge. The order is not arbitrary. #217 has to decide whether adding a payload key is breaking before #219 and #221 add keys — the envelope docs say it is not, every schema carries additionalKeys: false, and those cannot both be true for a consumer validating against one. And #216/#217 share ADR 0000 while #218/#219/#138 share app.roc, which is why the phases are sequential rather than parallel. Also fixes the plan drift a 1.0 audit found. The skill's workflow line sold `stride plan` as "summary + open sessions + last-14d activities", omitting plan_history_28d and adherence_28d — the two fields that make the coaching loop closed rather than a fresh guess each week. The payload table forty lines down already documented both, so the contract was right and the instruction was not.
Closes #216. Closes #217. ADR 0000 stated its boundary almost entirely in the negative — section 10 is a list of refusals, and the only positive line was the thesis at the top. Section 9b now says what stride IS: the deterministic local source of athlete state, with data providers as inputs rather than the identity, and a reasoning layer that is interchangeable by construction. Every refusal in section 10 follows from one of those three consequences, which turns the MCP entry from an apparent oversight into the claim it actually is: the CLI plus versioned JSON already IS the agent interface. The cost of not having said that is in the issue and is measurable. A careful reader wrote a page proposing an architecture stride already ships, then proposed two things sections 10 and ADR 0006 rule out, without engaging the reasoning, because nothing pointed at it. Section 9c defines the 1.0 contract across the six surfaces that version independently. The one that needed deciding rather than recording: adding a payload key is documented as non-breaking because "a consumer reading known keys is unaffected", while every schema carries additionalKeys: false, so anything validating against one fails the moment a key appears. Both were true; consumer meant two different things. The resolution is that the schemas are stride's contract with ITSELF — additionalKeys: false exists so a payload that GREW without a schema update fails CI, which is why schema-check runs against a real database — and a downstream consumer validates its own required subset rather than treating ours as closed-world. So adding a key stays additive, removing or retyping bumps the envelope, and a change that breaks a reader of known keys is a v3 directory rather than an edit to v2. Error codes are additive in 1.x: the vocabulary is published and diffed against source in CI, so a caller branching on a code keeps working. Section 6's breaking-is-fine permission now says it expires at 1.0 and points at 9c, rather than sitting ambient where a reader meets it first.
… above Review found ten things. Four mattered. Section 9c said `additionalKeys: false` "is why `just schema-check` runs against a real database". schema-check runs in NO CI job — `grep -rn schema-check .github/` returns nothing. CI's enforcement is `just e2e` running validate.jq against seeded fixtures; schema-check is the local "does MY data conform" pass, and the causality is inverted: it runs against a real database BECAUSE CI's fixtures are not real data. Three other files state the division correctly and this ADR was the only one fusing them. The section now names e2e as the CI mechanism, and records that coverage is not total — complete, import, init, rate and sync are validated by neither pass, tte only by the local one, so a key added there is caught by nothing today. Then the PR added PLAN.md while the same file, forty lines below the new sections, said there is deliberately no scratch plan file. AGENTS.md carried the twin. Both now draw the line where it actually belongs: no plan file DESCRIBES work, sequencing and its constraints are the one thing issues cannot carry, and the file must be pointers, scanned by the drift guard, and self-deleting. Which it was not. PLAN.md is the file in this repo densest with issue-state claims and `tools/issue-claims.sh` did not scan it — the guard that shipped two commits ago for exactly this class. Added: 1887 blocks and 1 checked ref becomes 1899 and 5. And PLAN.md gave #188's blocker as "one Run in the database", which is the argument the issue itself retracts — a per-athlete measurement cannot rank a feature aimed at the circle. The real blocker is that no mean-max SPEED curve exists: the power path stores best_5s_w through best_3600s_w at analyze time and the pace equivalent has no columns and no producer. Smaller, same review: "every refusal in section 10 follows from one of them" overclaimed — graphs is an empirical result, social is a market fact, medical is a limit on the data. The error-code diff asserts set EQUALITY, so it enforces sync rather than additivity, and the unguarded count of 43 came out with it. #219 RETYPES `commands` rather than adding a key, which under 9c's own rule is the heavier change. "Six surfaces version independently" — only three carry a version; the other three are why the section is needed. And "no API key" now says no MODEL API key, since section 1 stores Strava tokens.
Round 2 answered the question I asked it — is PLAN.md rot-resistant, or did I just write a rule it will violate — and the answer was the second. Three files in the last commit published "the moment it describes what a ticket contains, it has become the file that rotted". PLAN.md's #188 row, which that same commit rewrote, was sixty words of ticket contents including two symbol names copied from an issue comment. It was twelve words before I "fixed" it. More accurate and five times more of a violation. Worse, the guard I added covered the wrong half. All four refs it resolves come from the Parked table, because that is the only block pairing a state phrase with a ref. The ten refs in the phases and feature track carry no state phrase and therefore no oracle — the guard covered the four tickets least likely to move and none of the sequencing the file exists to hold. And the state column would have shipped 1/4 wrong on merge, with no mechanism to update it, which is exactly how the last plan file survived. So the file is now what justified it and nothing else: two ordering constraints and a four-line order. Twenty-seven lines. The Parked table went because every fact in it lives on its own issue, the standing rules went because a workflow is not a plan and a Copilot observation is a snapshot, and the state column went because a column nobody updates is worse than no column. Three smaller ones from the same round: The section-10 attribution replaced "every refusal follows" with a new unearned claim — that graphs, social and medical all come from the header — when the header speaks to none of graphs' grounds. A graph renders deterministic provenanced facts perfectly well; the reason it is refused is that the experiment ran and failed. Now each exception carries its own ground. The coverage sentence swept `tte` into "caught by nothing" when the clause before it says the local recipe covers `tte`. It is caught by nothing IN CI. And the plan-file rule was published twice with different conditions — AGENTS.md required the drift guard, the ADR did not. The dropped condition was the only one with a mechanism, and it is the one that round implemented. A twin divergence introduced by the fix for a twin divergence.
Round 3 returned MERGE and handed over something better than a fix: the one condition with no mechanism now has one. "Delete this file when the sequence is done" was a request. That is precisely how `.claude/PLAN.md` survived long enough to rot — nothing failed when it outlived its purpose. PLAN.md now says it remains open until #220 lands, which `just issue-claims` reads as a state claim about an issue. On the day #220 closes, CI goes red naming this file. Mutation-proved rather than asserted: with #220 open the run is clean at 1895 blocks and 2 claims resolved; substituting a closed ref gives STALE PLAN.md:8. Before this the file contributed zero checked refs, because "must land before" matches nothing in the pattern. Also closes the wording gap round 3 flagged in the rule itself. Both files paired a permission — sequencing AND ITS REASONS — with an absolute that forbade naming a ticket's contents at all. You cannot say why two tickets conflict without naming the fact that makes them conflict, so the absolute was worded past what the permission allows. Both now scope it to the one fact that creates the constraint. And the section rename left two pointers to the old name behind.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #216. Closes #217.
Two ADR 0000 changes that had to ship together because they edit the same file, and because the second one gates the payload work behind it.
§9b — what stride IS
ADR 0000 stated its boundary almost entirely in the negative. §10 is a list of refusals; the only positive line was the one-sentence thesis at the top. Nothing said stride is the deterministic local source of athlete state, that data providers are inputs rather than the identity, or that the reasoning layer is interchangeable by construction.
The cost is measurable rather than theoretical. A careful outside reviewer read this repo and wrote a page proposing, as future direction, an architecture stride already ships — provenance, confidence tiers, plan and adherence memory, null semantics, versioned schemas, rep-level progression, the engine/coach boundary. Then proposed two things §10 and ADR 0006 explicitly rule out, without engaging the recorded reasoning, because nothing pointed at it.
The section is deliberately three consequences rather than a manifesto, and every refusal in §10 now follows from one of them.
MCP serverin particular stops reading as an oversight and becomes the claim it always was: the CLI plus versioned JSON already IS the agent interface. §9b points at §10 and does not restate it — ADR 0000 already records that a second overlapping scope list existed once and neither was a superset of the other.§9c — the 1.0 compatibility contract
Six surfaces version independently and they are not one promise. Most of the table is recording what is already true. One row needed deciding.
Adding a payload key was documented two ways that appear to contradict. The envelope rule says adding a field does not bump the version, because "a consumer reading known keys is unaffected by a new one appearing". Every schema carries
additionalKeys: false, so anything validating a payload against the checked-in schema fails the moment a key is added.Both are true.
consumermeans two different things.The 1.x resolution: the schemas are stride's contract with itself, not a closed-world validator for third parties.
additionalKeys: falseexists so a payload that GREW without a schema update fails CI — that is its entire job, and it is whyjust schema-checkruns against a real database. A downstream consumer reads the keys it needs and validates its own required subset; stride does not promise its schema works as a closed-world check.So adding a key is additive, removing or retyping bumps
json_schema_version, and a change that breaks a reader of known keys is av3/directory rather than an edit tov2/. Error codes are additive in 1.x, since the vocabulary is published and diffed against source in CI.This is why #217 sequences before #219 and #221. Both add payload keys. Deciding whether that is breaking after shipping the additions is backwards.
§6's breaking-is-fine permission now states that it expires at 1.0 and points at §9c, instead of sitting ambient where a reader meets it first.
Also in this PR
PLAN.md— a 1.0 order-of-work breadcrumb, added against AGENTS.md's standing advice and deliberately. The last plan file rotted because it restated work that lived in issues, so the copies drifted and a watch-item it tracked fired unnoticed. This one holds no work: only the order, the two constraints that set it, and pointers. It says to delete itself when the phases merge.And a skill fix a 1.0 readiness audit surfaced: the workflow line sold
stride planas "summary + open sessions + last-14d activities", omittingplan_history_28dandadherence_28d— the two fields that make the coaching loop closed rather than a fresh guess each week. The payload table forty lines below already documented both, so the contract was right and the instruction was not.Docs only.
just issue-claimsclean at 1887 blocks.