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.
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.
Not a hypothesis. Every row is an artifact sitting in PressRaven-Corpus right now, mid-trip.
| Evidence | Where | What it means |
|---|---|---|
provenance on 99/105 entries | washington-dc/entries/ | Undeclared. Invisible in the app, dropped from packets. |
| The same record written twice | andys-pizza-georgetown | Blind append in ImportService.apply:320–329. |
| Five hand-dated rules in a prose blob | guide.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 days | washington-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-georgetown | The 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 filenames | The log shows items moving days, so ids routinely lie after a replan. |
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.
Stated up front so the scope is honest rather than discovered later.
localStorage star list, no backend. Deferred to Phase 8, unstarted, with the design written down rather than built — Phase 4's cut point covers the mid-day case without it.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.
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{ date, source, note } — source is claude-code | import | app | handImportService.apply; a shared appendProvenance helper so app edits stamp too (today they stamp nothing)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.
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.
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.
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.
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 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:
Contract additions on top of the existing direct-edit contract:
outcome on every plan item above the cut point — an unstamped item is the one outcome that says nothingprovenance with a one-sentence account on every entry touchededitorial_notes prosepick or lockThe same two operations appear over and over in the log. Both are currently multi-step hand edits.
day, appends to the target day's order, stamps provenancealt/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 sessionExisting 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.
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.
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.
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.
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.
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.
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:
profiles/<id>.json.if_time (○) stops actually happen? Did anchors survive? Did early items survive better than late ones? A convention that never predicts anything is decoration.travel_mode: driving but never asked is the car available during the day? — which is exactly what day 3 learned the hard way.provenance on day one instead of on trip three.Every claim cites entry ids, dates or commits. A pattern without evidence is a guess, and beating memory is the entire point.
| Kind of insight | Home | Exists? |
|---|---|---|
| A person's preferences | profiles/<id>.json | yes — and empty |
| Something we should have asked up front | categories/itinerary/brief.json | yes |
| A standing planning rule (pacing, photo windows) | nothing today | no |
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.
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.live(dc): Tysons abandoned at 12:15. A trip committed as "wip" produces nothing, and no tooling fixes that.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.
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.
SessionLaunchers and PacketService already have.skipped outcomes is workable and clumsy, and it will distort the post-mortem's cause counts by loading them with skips that share one reason. Worth a day_outcome if it happens twice.ref-joined place. The outcome lives on the plan item, which is correct (the same place can be visited twice) — but the place card won't show that you went. Deliberate; flagging it because it may read as a gap.replan into revision with an itinerary-only "replan from here" toggle. Fewer doors, less clear. Close call, easy to reverse.editorial_notes. Phase 7 strengthens the case for doing it, though — a graduating rule needs to be addressable.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.
| Question | Answer |
|---|---|
| Id convention | Existing stay; new entries stop day-prefixing. Nothing renamed. closed |
| Trip-rule split | PACING · PHOTO WINDOWS · THE CAR · PRICE CEILING move. BROWSABLE AND BUYABLE · ROSTERS RENDER IN THE DAY stay. closed |
| Mid-day replan | Day selector plus cut point, not a clock heuristic. Mid-day is a normal case. closed |
| Post-mortem | Added as Phase 7 — changelog, authored fields, analysis, graduation channel. added |
day_outcome need to exist for a cancelled day, or does it wait until a trip actually loses one?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.