The trip changes

An itinerary is modelled as a document that is authored, then read. Three trips say it is authored, then continuously revised while being read — and the revision has a shape the framework doesn't know about.

6 August 2026 · revised after your four answers · nothing implemented · corpus untouched

What changed in this revision

Before anything else — a live bug

99 of the 105 DC entries carry a provenance field that nothing declares. It's absent from categories/itinerary/schemas/entry.json and from the framework envelope, which by the corpus's own rule means it renders nowhere in the app and is dropped from every session packet. The most valuable record we keep on the road is invisible to everything that reads the corpus.

andys-pizza-georgetown.json carries the same provenance record twice — ImportService.apply appends blind.

What the corpus already proves

Not a hypothesis. Every row is an artifact sitting in PressRaven-Corpus right now, mid-trip.

EvidenceWhereWhat it means
provenance on 99/105 entrieswashington-dc/entries/Undeclared. Invisible in the app, dropped from packets.
The same record written twiceandys-pizza-georgetownBlind append in ImportService.apply:320–329.
Five hand-dated rules in a prose blobguide.json → editorial_notes"PACING (learned on the road, 3 Aug)", "THE CAR (changed 4 Aug)", "PRICE CEILING (4 Aug)". Pre-trip stance and Wednesday's discovery at the same level, in one string, no order, no way to retire one.
Nine revision packets in six dayswashington-dc/sessions/32–105 KB each. Several exported twice within twenty seconds. Every one carries the whole guide to ask about one afternoon.
A badge reading "What Actually Happened"andys-pizza-georgetownThe corpus has no way to say this is the record, not the plan — so it went in a badge label.
Commits prefixed live(dc):corpus git log"Tysons abandoned at 12:15" · "Paradiso closed — Tuesday afternoon rebuilt" · "closing times invert the afternoon". You already invented the vocabulary. The framework has no word for it.
Ids encode the day (d4-lunch)entry filenamesThe log shows items moving days, so ids routinely lie after a replan.

The pattern underneath

The revision is day-scoped and forward-looking — tomorrow and the day after. It is driven by things that happened (a place shut, a day ran short, a kid refused) and by standing constraints discovered on the road (the car is gone 8 AM–4 PM).

The record of it currently lands in three places that cannot hold it: an invisible array, a growing prose blob, and a commit message.

What this plan does not do

Stated up front so the scope is honest rather than discovered later.

The seven phases

Phase 0

Corpus repair

A tools/dedupe-provenance.py that runs dry by default, reports every file, and collapses identical adjacent records. Blocked on your DC edits landing — every task here touches entry files you were editing tonight.

Phase 1

Provenance becomes real

It's written for every category and declared by none — envelope-shaped (who changed this, when, why), not category-shaped. So it goes beside sources and visuals.

  • provenance joins ResolvedSchema.envelopeKeys
  • One record shape: { date, source, note } — source is claude-code | import | app | hand
  • Append guard in ImportService.apply; a shared appendProvenance helper so app edits stamp too (today they stamp nothing)
  • Renders in the inspector envelope; the most recent three ride in every packet

Honest cost: packets get bigger — roughly 8–10 KB on a 60 KB packet. Capping at three is the mitigation; only Phase 4's scoping wins it back. Land them close together.

Phase 2

Trip rules as dated data

Split the rules discovered on the road out of editorial_notes, which keeps the pre-trip stance — the admission test, the voice, the standing conventions. A rule learned on Tuesday wants a date, an id, and the ability to be retired.

"trip_rules": [
  { "id": "pacing", "date": "2026-08-03",
    "rule": "Any block over ~3 hours on foot needs a real sit-down inside it.",
    "why": "This party needs materially more sitting than the plan allowed.",
    "scope": null, "retired": false }
]

The packet renders them under their own heading, newest first, below the editorial notes — so a session can tell "this is how we write" from "this is what Wednesday taught". Retired rules get a one-line "no longer in force" list, so nothing gets re-derived after being tried and dropped.

Proposed split of the DC notes: PACING, PHOTO WINDOWS, THE CAR and PRICE CEILING move to trip_rules. BROWSABLE AND BUYABLE and ROSTERS RENDER IN THE DAY stay — they're conventions about how the guide is written, not things the road taught.

Honest cost: a hand migration of authored prose. Five paragraphs, once, and the judgment about which four move is the whole cost. Reversible in five minutes if the split reads wrong.

Phase 3

Outcome — what actually happened

On plan_item only: outcome (done · partial · skipped · moved · replaced) and a one-line outcome_note ("closed; Andy's Pizza instead").

Renders as a quiet mark in the timeline gutter and a muted italic line — a past day should read as history, not as an alert. Not rendered on the phone. Validation is prompt-not-block, matching how checked staleness already behaves.

This is new authoring work that only pays off through Phase 4. Shipped alone it's a form nobody fills in. The mitigation is that the replan session stamps outcomes from the conversation rather than you typing them — which is why 3 and 4 ship together or not at all.

Phase 4

Replan From Here — one door

A new session phase, itinerary-only, that knows what a replan is instead of making you assemble one out of the generic revision door. Renamed from "Evening Replan" on your note: a morning that goes wrong is the same operation from a different starting point.

The cut point — the piece your note produced

A day selector, defaulted from the date but always visible and movable. And when the selected day is today, a second picker: the plan item you're standing at. Everything above it is history, everything below is still in play.

This uses the day's editorial order rather than parsing times — which is not a shortcut, it's the only correct approach, because itinerary times are strings and deliberately never sort. A clock heuristic would have guessed; this can't be wrong.

The day so far ──▶ items ABOVE the cut, with outcomes Still to come today ──▶ items BELOW the cut (omitted in the evening case) What's still ahead ──▶ remaining days, in full The pool ──▶ places NO plan item references — compact The rules so far ──▶ trip rules, dated, newest first The roster ──▶ traveler profiles (already carried)

The pool is the piece that's missing today. A replan draws from places that exist but aren't scheduled, and there is currently no way to see them without carrying the whole guide.

Four questions, pre-written in the sheet — inferred from six days of your commit messages. The first is worded to read correctly whether the day is over or halfway through:

What happened today that the plan did not expect?
What is the weather doing tomorrow?
What did they react to — loved, refused, want again?
What got dropped that should come back, and what should go?

Contract additions on top of the existing direct-edit contract:

  • Stamp outcome on every plan item above the cut point — an unstamped item is the one outcome that says nothing
  • Stamp provenance with a one-sentence account on every entry touched
  • Propose any new standing constraint as a trip rule, never by editing editorial_notes prose
  • Don't touch past days except to record their outcomes; don't touch pick or lock
Phase 5

The two edits a replan actually makes

The same two operations appear over and over in the log. Both are currently multi-step hand edits.

  • Move to Day… — sets day, appends to the target day's order, stamps provenance
  • Promote alternate to the plan — clears alt/alt_kind across that named alternate and offers to demote what it displaces into an alternate named for what was dropped. This is "Tysons abandoned at 12:15", which took a whole session

Ids decided

Existing ids stay. New entries stop day-prefixing — lunch-andys, not d4-lunch. Nothing gets renamed, because an id is a stable identifier and renaming would break ref: joins, annotation targets and git history for a cosmetic gain.

The DC guide stays mixed. That's the honest cost, and it's small. One addition worth making: write down that a day-prefixed id is historical and means nothing, so no future session helpfully renames one.

Phase 6

Know when the live page has gone stale

Record published on a successful publish; when the newest entry updated is ahead of it, the publish control fills and turns amber — exactly the machine-target drift pattern that already exists. Hover names the count. No auto-publish; publishing pushes to a live site and stays deliberate.

An hour of work, independent of everything else. Arguably do it first.

Phase 7

The Post-Mortem new

The evidence for this one is brutal

profiles/beckett.json:

{ "id": "beckett", "name": "Beckett", "dietary": "vegetarian",
  "palate": "picky", "loves": [], "avoids": [], "notes": "" }

Three trips in, and the cross-trip preference store has never been written to. The corpus has the field. Nothing in the framework has ever asked.

Three pieces, and conflating them would be the design error: the changelog is evidence (mechanical, no judgment), the post-trip fields are impression (authored by you), and the analysis is the argument between them.

7A — The changelog, derived and never authored

tools/trip-changelog.py, reading path-scoped git log plus provenance plus outcomes. Path-scoping matters: the log carries both live(dc): … and bare refactor: 16 revised entries, and only the path says which guide a generic commit touched.

The derived column that carries the whole analysis

Each change is classed by when it was made relative to the day it changed:

planning — a future day  ·  live — today  ·  record — a past day

A trip whose changes are mostly live was planned wrong. One that is mostly planning was replanned in advance. That distinction is computable from data you already have, and nothing today can see it.

7B — The post-trip fields, authored by you

postmortem: { completed, verdict, what_worked, what_to_change, per_traveler } on guide.json. per_traveler is keyed by profile id, so "Beckett refused every sit-down dinner" has somewhere to go. The section appears only once the last day is past — before that it isn't a form to ignore, it's absent. Runs before the existing freeze-snapshot step, since a frozen guide is read-only.

7C — The analysis, arguing with the evidence

A session phase carrying your account first, then the changelog, the outcomes, the trip rules, the brief as written before departure, the profiles as they stand, and the schema. What it returns, in order:

  1. Where the evidence disagrees with your account. First, because it's the only thing memory cannot produce. "You said Georgetown went well; three of its six items were replaced on the day."
  2. Recurring causes, counted, with entry ids — closure/hours · ran out of time · preference · logistics · weather. If half the replans are "ran out of time", the next itinerary carries fewer items per day, and that's a claim the corpus can support.
  3. Preference signals per traveler, as proposed edits to profiles/<id>.json.
  4. Which planning conventions held. Did if_time (○) stops actually happen? Did anchors survive? Did early items survive better than late ones? A convention that never predicts anything is decoration.
  5. Brief gaps. DC's brief captured travel_mode: driving but never asked is the car available during the day? — which is exactly what day 3 learned the hard way.
  6. Framework gaps — fields never filled, fields filled but rendered nowhere, and keys written that no schema declares. That last check would have caught provenance on day one instead of on trip three.
  7. Which trip rules should graduate, and where to.

Every claim cites entry ids, dates or commits. A pattern without evidence is a guess, and beating memory is the entire point.

7D — Where an insight actually goes

Kind of insightHomeExists?
A person's preferencesprofiles/<id>.jsonyes — and empty
Something we should have asked up frontcategories/itinerary/brief.jsonyes
A standing planning rule (pacing, photo windows)nothing todayno

The gap gets one small field: default_editorial_notes on CategoryConfig, seeding a new guide at creation — the same shape as default_design_system and default_publish_path, which already work exactly this way. A rule proven across two trips graduates there. One trip is an anecdote, and the framework shouldn't encode an anecdote.

Honest limits

  • The analysis will surface real things and plausible non-things. The defences are mandatory citation and never auto-applying. Read it as an argument, not a report.
  • Sample sizes are small. One trip might hold twenty ○ stops. The contract requires raw counts ("4 of 19 ○ stops happened") and forbids percentages, which lend false authority to n=19.
  • Cross-trip comparison doesn't work yet. asheville-2026 predates provenance, outcomes and trip rules. Trip three produces a baseline, not a trend, and the analysis has to say so rather than inventing one.
  • The changelog inherits whatever the git history is. DC reads well because you wrote live(dc): Tysons abandoned at 12:15. A trip committed as "wip" produces nothing, and no tooling fixes that.
Phase 8

Capture on the ground deferred

Written down so the design exists when it's wanted, and so Phase 4 isn't quietly assumed to cover it.

Each plan row gets three taps — did it · skipped it · note — into localStorage, exactly as stars already do. A "Today's marks" button composes a plain-text block and copies it. That block pastes into the Replan sheet's question field, where Phase 4's contract already knows what to do with it.

Honest limits: device-local (marks on your phone are invisible on Malcolm's), cleared by a browser data wipe, and it adds interactive state to a page whose current virtue is being a static artifact. The alternative — remembering until evening — is what happens today and mostly works, because the replan happens the same night.

Dependencies

Phase 0 ──▶ Phase 1 ──────▶ Phase 3 ──▶ Phase 4 ────────────┐ repair provenance outcome replan door │ │ ▲ ▼ └──▶ Phase 5 ──────── │ Phase 7 move / promote │ post-mortem Phase 2 ─────────────────────────────────────┴───────────────┘ trip rules Phase 6 publish staleness — independent, land any time Phase 8 on-the-ground capture — deferred

Phases 3 and 4 must ship together — Phase 3 alone is authoring burden with nothing consuming it. Phase 7 is the second consumer of Phases 1–3, which is what makes provenance and outcomes pay for themselves twice: once during the trip, once after it.

Phase 7 has to exist before the next trip ends, not after. A post-mortem run on a trip that had no changelog, no outcomes and no trip rules produces nothing worth reading — and there's no way to reconstruct them retroactively.

Final review

Pros

Cons

Edge cases this plan handles poorly

Adjustments worth considering

The cheapest real test in the plan — recommended

Run 7A alone against the DC trip. The changelog can be generated from git plus the existing (undeclared) provenance without any of Phases 1–3. It'd be lossy — no outcomes — but within an hour it would show whether the planning/live/record classification produces anything interesting, before the rest of Phase 7 gets built on top of it.

Decisions taken

QuestionAnswer
Id conventionExisting stay; new entries stop day-prefixing. Nothing renamed. closed
Trip-rule splitPACING · PHOTO WINDOWS · THE CAR · PRICE CEILING move. BROWSABLE AND BUYABLE · ROSTERS RENDER IN THE DAY stay. closed
Mid-day replanDay selector plus cut point, not a clock heuristic. Mid-day is a normal case. closed
Post-mortemAdded as Phase 7 — changelog, authored fields, analysis, graduation channel. added

Still open

Are those the right four replan questions? Still inferred from the DC trip's commit messages rather than confirmed. You lived it.
Test 7A against DC before building the rest of Phase 7? Recommended — it's an hour, and it's the only way to find out whether the analysis has anything to work with before committing to 7C.
Does day_outcome need to exist for a cancelled day, or does it wait until a trip actually loses one?

Confidence

80 / 100

Down two. The plan got materially larger and the newest part is the least proven — that's the honest direction for the number to move.

High on Phases 0, 1, 5 and 6. Those read the corpus's own evidence rather than designing anything, and your id decision removed the only structural unknown in Phase 5.

Phase 4 improved. The day selector plus cut point resolves the mid-day ambiguity honestly instead of papering over it with a clock heuristic — and it fell out of a real event rather than a hypothetical. The four questions are still inferred and still its weakest part.

Phase 7 splits sharply. 7A, 7B and 7D are high confidence: a changelog from git plus provenance is mechanical, authored post-trip fields are a form, and the three graduation homes are either existing corpus concepts or a one-field addition matching an established pattern. 7C is a genuine unknown. Whether a session reading one trip's changelog surfaces patterns you wouldn't have named yourself is not something I can predict from the code — the first run is an experiment. The design defends against the obvious failure (mandatory citation, counts not rates, proposals never applied), but defending against confident nonsense isn't the same as producing insight.

Phase 2 remains the phase most likely to come back. Splitting authored prose into data reads as obviously right in a plan and slightly wrong in practice.

Plan file · .claude/plans/2026-08-06-in-trip-revision.md