Skip to content

Session end

The protocol for closing out cleanly so the next session has a clean handoff.

Update the existing wiki structure — never duplicate

The wiki has a fixed structure. Update existing files; don't create parallel ones.

  • decisions/ — ADRs. Append-mostly: when a decision changes, supersede with a note in the existing ADR's "Decision history" or add a new ADR that supersedes by reference. Never overwrite an Accepted ADR's body.
  • known-patterns.md — durable lessons. Things future sessions should not have to relearn. Add entries under the right section (Hero, Sections/matchers, Components/pipeline, Out-of-scope).
  • known-issues.md — transient triage. Open bugs, unresolved questions, things in flight. Fixed issues get deleted, not archived (git log is history).
  • session-<YYYY-MM-DD>-handover.md — written last, see below.

ADR changes are append-mostly

A locked ADR is a contract with future sessions. Don't overwrite the decision body. When a follow-on decision modifies the picture, prefer:

  • A "Decision history" section in the existing ADR (used in 0005 to capture the V1 → V2 → V3 supersession).
  • A new ADR that supersedes the old one by reference (e.g. ADR-0007 supersedes ADR-0003 §X).

Correcting a claim a previous session got WRONG

Distinct from "a bug was fixed" (delete the issue) and "a decision changed" (supersede the ADR). This is: the wiki asserts something that is not true, and a session believed it.

Correct it in place with a dated correction that keeps the wrong claim visible. Do not silently overwrite it. The false claim is not noise to be tidied away — it is the thing that cost the session, and the next reader needs to see why it was believable.

Shape:

Correction (YYYY-MM-DD): "" is false.

2026-07-13, two in one session — both worth reading as a pair, because both had the same shape (a correct observation, a wrong inference):

  • known-patterns said "logos are local-only" — no wixstatic source, so upload the local file. The observation was right (you cannot derive a wixstatic URL from /assets/logos/<Name>_logo.png). The inference was wrong: the logo is in the client's Wix library; the path just carries a display name where every other image carries a media id. The correction preserves both halves, because the derivation rule is still load-bearing.
  • known-issues + ADR-0009 said the header CTA was "reproducible-from-capture, not manual". The detector had only ever been run against a live browser session, never against a persisted artifact. The claim was written in good faith after a real verification — of the wrong thing.

Detection rule: a wiki claim asserting that something works / is reproducible / has no source deserves one command's worth of scepticism before you build on it. If a claim can be checked by grepping a committed artifact, check it — that is cheaper than the slice it will otherwise misdirect. When a claim turns out false, the correction is part of landing the fix, not optional polish.

A fix you did not EXECUTE is a HYPOTHESIS — label it, or don't write it

The rule above ("correcting a claim a previous session got wrong") is retrospective. This one is the prospective half, and it is the cheaper of the two, because it stops the wrong claim being written in the first place.

Measured facts and untested speculation currently look identical in this wiki. They sit in the same paragraph, in the same tone, with the same authority. The measurement is usually right. The untested fix proposal has been wrong every single time it mattered:

what the wiki proposed what it would have done
brand ranker — "make the ranker prefer a high-confidence logo cluster over a lower-scored surface candidate" broken garvanbay. Its dominant logo cluster is yellow-green and outscores the cyan that is actually its brand. The surface-over-logo rule was deliberate, not a bug.
responsive-doubles — "re-run dedupeLayoutMap's dup-collapse AFTER the re-match" collapsed ZERO pairs. The doubles are nested ancestor/descendant wrappers, not adjacent siblings, and the re-match never fires on the failing page.
isJunk"widen the heading-gated regex" to catch the Watch Now strips hidden the missing-video debt inside the junk filter. Those strips are the Wix video widgets.

Three for three. And in every case the observation recorded next to the proposal was correct — the flip was real, the duplicates were real, Watch Now really does slip the filter. The failure is never the measurement. It is the inference drawn from it by a session that then closed without testing that inference.

The harm is second-order and expensive: the proposal anchors the next session. It reads like a decision, so a slice gets scoped against it. On 2026-07-13 pt3 a whole dimension was built on an inverted premise. On 2026-07-14 the orchestrator repeated a fabricated mechanism as fact in a subagent brief — and it survived only because the subagent measured the DOM instead of trusting the brief.

The rule

Anything you propose but do not run is a hypothesis. Mark it, or leave it out.

  • If the proposal carries a causal claim ("because X, do Y"), it is the dangerous kind — the theory rides in disguised as the remedy. Mark it:

Fix candidate — UNTESTED HYPOTHESIS:

  • If it is a chore with no causal content ("pick one canonical BUILD_DIR"), it is safe to state plainly. The test is: could this be wrong about WHY?
  • Better than either: don't write the fix. Write the MEASUREMENT and the REOPEN TRIGGER, and let the next session derive the remedy from the evidence rather than inherit a guess. A measurement stays true. A guess rots into an instruction.
  • Executed fixes are facts and need no marker — say what shipped and what proved it.

Reading side

Never scope a slice against an UNTESTED HYPOTHESIS without re-measuring first. Treat it as a lead, not a plan. One command's worth of scepticism is cheaper than the slice it will otherwise misdirect — and cheaper still than the regression it ships to the other reference site, which is what two of the three above would have done.

Transient triage vs durable lessons

The split matters because it shapes what survives over time:

  • A bug that's been fixed → known-issues entry deleted; the lesson (if any) goes to known-patterns.
  • A pattern observed once and resolved → known-patterns.
  • An architectural decision → ADR.
  • A status snapshot for handoff → session handover.

If you find yourself adding the same fact in two places, you've duplicated.

Git add, commit, push — AND publish the site

After the session-handover note is written:

git add <files>
git commit -m "..."
git push
mkdocs build
npx wrangler pages deploy site --project-name=replatform-docs --branch=main

--branch=main is required: the Pages project's PRODUCTION branch is main while this repo's branch is master — without the flag, wrangler deploys the git-detected branch name and the deployment lands as a Preview (production stays stale, which is exactly the silent-failure shape this step exists to prevent; it bit within minutes of writing this protocol).

The push alone does NOT update the published wiki. The Cloudflare Pages site (https://replatform-docs.pages.dev) is deployed manually from the local mkdocs build output — there is no git integration. This was discovered 2026-07-09 after the published site had silently sat two months stale while every session-end faithfully pushed: the protocol used to claim "push → the published wiki updates", and nothing enforced the second half. Skip the build+deploy and the published wiki reads stale even though git is current.

New pages need a nav entry. mkdocs.yml carries an explicit nav: — add the session handover (and any new ADR/contract/scope doc) to it as part of writing the file, or the page builds unlisted (searchable but not navigable). The nav was regenerated complete on 2026-07-09; scripts/.tmp/nav.yml's generator shows the shape if it ever needs a bulk rebuild.

Verify the publish on the PRODUCTION domain — "Deployment complete" is not proof. wrangler prints a per-deployment hostname (https://<hash>.replatform-docs.pages.dev) whether the deployment is Production or a Preview, so its success message cannot distinguish the two — which is precisely the failure this step exists to catch. Fetch the new page on the real domain:

curl -s -o /dev/null -w "%{http_code}\n" \
  https://replatform-docs.pages.dev/pipeline/session-<date>-handover/

Expect a lag. An immediate 404 right after a correct deploy is normal — production propagates a few seconds behind. Re-fetch before concluding anything; do not re-deploy, and do not go looking for a bug in --branch=main (bit on 2026-07-13: a 404 seconds after a deploy that wrangler pages deployment list confirmed as Production / main, 200 moments later). If it is still 404 after a retry, then check the environment with npx wrangler pages deployment list --project-name=replatform-docs — the top row must read Production / main / your commit sha.

Write the dated session-handover note last

The handover is a pointer to what changed, not a re-summary. Reference the ADRs, known-patterns entries, and commits by link rather than re-explaining their content. The handover's job is "where to look", not "what was decided".

Match the existing handover format (see prior session-<date>-handover.md files for the structure).

Example of the protocol applied

Slice 1 + ADR-0005 promotion session (2026-05-10 afternoon):

  • ADR-0005 promoted in place — Status: Accepted, DRAFT marker dropped, Decision history section added (append-mostly: original DRAFT body preserved alongside V1/V2/V3 supersession trail).
  • known-issues.md entry "Spike-vs-production naming unsettled" deleted (resolved); CMS image migration entry rewritten to reference the Accepted ADR.
  • known-patterns.md gained one new entry (workspace path-alias literal-vs-regex trap).
  • Session handover written last, pointing at the three commits + the Accepted ADR + the new pattern entry, not re-summarising them.
  • Pushed.

Closing a slice as 'mostly complete' — deferral contract

A slice can be closed without all done-criteria met if the user directs deferral of a specific sub-issue. Treat this as a distinct shape from "done" — the deferral has to land in writing, with explicit reopen triggers, or it becomes "we'll get to it" debt.

2026-05-11 example. Slice 4 of ADR-0005 missed its 30-min/290k throughput target; the user directed close as "mostly complete with throughput deferred". The closeout work:

  • ADR-0005 Slice tracker — Slice 4 marked done with a sub-issue note, not silently re-targeted. The 30-min figure stays in the ADR's effort table; the deferral is an open issue against the spec, not a quiet spec relaxation.
  • known-issues.md — new entry "R2 upload — throughput ceiling" carrying the curve data, hypothesis status, EC2 pre-stage state, and an explicit deferral-trigger contract (50-site end-to-end proven / >200-site batch lands / R2 side changes — whichever first). The contract is what stops "deferred" from becoming "forgotten".
  • known-patterns.md — two new entries from the slice's diagnostic work (architectural-fix-fails → re-diagnose; parameter-sweep distinguishes hypotheses). Lessons from a deferred slice still get banked — the pattern entries pay forward.
  • Session handover names the deferral and the next priority (Slice 3 transformer integration; throughput re-opens only after the 50-site gate).

The shape: slice closes with a written deferral contract, not a verbal "we'll come back to it". The trigger conditions are the contract; without them the issue is forgotten by the next session that opens with a different priority.