aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCraig Jennings <c@cjennings.net>2026-06-01 08:29:25 -0500
committerCraig Jennings <c@cjennings.net>2026-06-01 08:29:25 -0500
commit225c60df3ffe4d2163d8d42975d4cb74fe5ada39 (patch)
treeb8a7b5a8bdf6bead5595bcf536c57b6fbcf6ecb5
parent0e7741c927b0baf588e33cc7889307e4e5a19560 (diff)
downloadrulesets-225c60df3ffe4d2163d8d42975d4cb74fe5ada39.tar.gz
rulesets-225c60df3ffe4d2163d8d42975d4cb74fe5ada39.zip
feat(daily-prep): store prep docs in daily-prep/ with a root symlink
Prep docs are now born in daily-prep/YYYY-MM-DD-daily-prep.org and never move. A stable symlink at the project root, daily-prep.org, points at the current day's file and is the only thing that changes day to day. I replaced the old model where the doc was born in inbox/, yesterday's lingered there, and older docs were moved into a daily-prep/ archive. Consumers resolve the root symlink instead of reconstructing a dated filename or scanning inbox/: the standup lookback, next-day Phase 2, and the Emacs opener. Phase 8 becomes a symlink repoint rather than an archive move, and triage-intake's prep-doc anchor fallback now points at daily-prep/ only.
-rw-r--r--.ai/workflows/daily-prep.org50
-rw-r--r--.ai/workflows/triage-intake.org2
-rw-r--r--claude-templates/.ai/workflows/daily-prep.org50
-rw-r--r--claude-templates/.ai/workflows/triage-intake.org2
4 files changed, 76 insertions, 28 deletions
diff --git a/.ai/workflows/daily-prep.org b/.ai/workflows/daily-prep.org
index d8e186d..e58fd88 100644
--- a/.ai/workflows/daily-prep.org
+++ b/.ai/workflows/daily-prep.org
@@ -56,19 +56,21 @@ Runs *only* a slim Phase A + Phase 6 + a conditional Phase 8 + Phase 9. Skip Pha
Fetch only what Phase 6 needs:
1. =todo.org= — for WAITING items (blockers) and DONE-since-cutoff (completed work).
-2. Previous prep doc — anchor for the lookback (check =inbox/= then =daily-prep/=, take most recent).
+2. Previous prep doc — anchor for the lookback. Glob =daily-prep/*-daily-prep.org=, sort by date, take the file *before* the one the root =daily-prep.org= symlink currently resolves to (i.e. the prior prep day, not today's).
3. Most recent =.ai/sessions/= summary — for the "what did I do" question.
Skip the calendar fetches, the Proton grep, and the [#A]/[#B] todo pull. Phase 6 Step 1's sweep handles the rest.
*** Where the brief lands
-- If a prep doc for today already exists at =inbox/YYYY-MM-DD-daily-prep.org=, append or replace its =* Standup Brief= section.
-- If no prep doc for today exists, create =inbox/YYYY-MM-DD-daily-prep.org= with only the =* Standup Brief= section populated. Full prep can be added later by re-running in full-prep mode.
+- If a prep doc for today already exists at =daily-prep/YYYY-MM-DD-daily-prep.org=, append or replace its =* Standup Brief= section.
+- If no prep doc for today exists, create =daily-prep/YYYY-MM-DD-daily-prep.org= with only the =* Standup Brief= section populated, then repoint the root symlink at it (=ln -sf daily-prep/YYYY-MM-DD-daily-prep.org daily-prep.org=). Full prep can be added later by re-running in full-prep mode.
+
+See *Phase 8* for the prep-doc home and symlink convention.
*** Phase 8 in standup-only mode
-Only run if a stale prep doc exists in =inbox/= that's older than yesterday. Otherwise skip — there's nothing to archive.
+If standup-only created a new dated file in =daily-prep/= (no prep doc for today existed), repoint the root =daily-prep.org= symlink at it. "Where the brief lands" above already does this; Phase 8 is a no-op when it did. If today's prep doc already existed and the brief was appended to it, the symlink already resolves to it — nothing to do.
Use standup-only mode when Craig wants the brief fast (e.g., right before standup) without rebuilding the day's plan.
@@ -155,7 +157,7 @@ Before any synthesis or interaction, pull every source the prep doc needs in a *
2. =mcp__google-calendar__list-events= for the *work* account, same scope.
3. Grep =~/.emacs.d/data/pcal.org= for items on that day. This is the Proton Calendar export (=pcal= = personal calendar). The same directory has =gcal.org= and =dcal.org= for Google personal + DeepSat, but those are already covered by the MCP queries in steps 1 and 2 — only =pcal.org= adds non-redundant items.
4. Read =todo.org= — collect [#A] and [#B] tasks plus anything with DEADLINE: or SCHEDULED: touching the day.
-5. List + read the *previous* prep doc. Check =inbox/= first (active prep docs not yet archived), then =daily-prep/= (the archive). Take the most recent file by date — usually yesterday's, but may be older if Craig was off (PTO, weekend, missed days). The lookback for the standup brief is anchored on this file's date, so accuracy matters.
+5. List + read the *previous* prep doc. Glob =daily-prep/*-daily-prep.org= (all prep docs live there, born and kept — no separate archive). Sort by date and take the file *before* the one the root =daily-prep.org= symlink currently resolves to — usually yesterday's, but may be older if Craig was off (PTO, weekend, missed days). If the symlink doesn't resolve yet (no prep ever run), take the most recent file by date. The lookback for the standup brief is anchored on this file's date, so accuracy matters.
6. Read the most recent =.ai/sessions/= summary file (for the standup brief's "What did I do since last standup?" question).
Phases 1-5 below all work from this in-memory snapshot. *Do NOT re-query the calendars in Phase 4* — the time-blocking pass uses the same data Phase A fetched. A typical daily-prep used to run 4-5 sequential round-trips just for data gathering; this collapses to one.
@@ -450,20 +452,39 @@ Format: bullet list or =** TODO= headings, with optional time estimates (e.g., "
This section is the explicit handoff to next-day's Phase 2. If it's empty, write the header with "(none flagged)" so the next day's prep doesn't mistake an empty section for a missing one.
-** Phase 8: Archive Older Prep Docs
+** Phase 8: Repoint the Current-Day Symlink
+
+Prep docs are *born* in their permanent home and never move. The home is
+=daily-prep/= at repo root: every prep doc is created directly as
+=daily-prep/YYYY-MM-DD-daily-prep.org= (Phase A onward writes there), and the
+dated files accumulate in place. There is no archive move — =daily-prep/= is
+both the working location and the archive.
-After the new prep doc is written, archive any prep docs in =inbox/= older than yesterday's. Yesterday's prep doc stays in =inbox/= because the new prep doc may still need to reference it (Planned vs Actual, talking-point carry-forward).
+A single stable symlink at the project root — =daily-prep.org= — points at the
+current day's file. The only day-to-day change is repointing it. After the new
+prep doc exists, point the symlink at it:
#+begin_src bash
-# Move any inbox/*-daily-prep.org file dated before yesterday into the archive.
-mv inbox/YYYY-MM-DD-daily-prep.org daily-prep/
+# Relative target so the symlink stays valid if the project tree moves.
+ln -sf daily-prep/YYYY-MM-DD-daily-prep.org daily-prep.org
#+end_src
-The archive lives at =daily-prep/= at repo root. Don't put prep docs in =deepsat/meetings/= — the prep doc covers personal calendar, all 1:1s, and all projects, not just DeepSat work.
+Consumers — the Emacs opener (=C-c p d=), next-day Phase 2, the standup
+lookback — resolve =daily-prep.org= rather than computing a filename or
+searching =inbox/=. Nothing prep-related lands in =inbox/= anymore.
-If =daily-prep/= doesn't exist yet (new project), create it. If a stale prep doc lives in =assets/= (an older convention), move it to =daily-prep/= as part of this archive pass.
+Setup / migration (first run in a project on this convention):
-This step keeps =inbox/= clean. The previous-day's prep is the only one that still has consumers.
+- If =daily-prep/= doesn't exist yet, create it.
+- Move any existing =inbox/*-daily-prep.org= (the old born-in-inbox location)
+ into =daily-prep/=, and any stale prep doc under =assets/= (an even older
+ convention) likewise. Then create the root =daily-prep.org= symlink at the
+ most recent one.
+- Don't put prep docs in =deepsat/meetings/= — the prep doc covers personal
+ calendar, all 1:1s, and all projects, not just DeepSat work.
+
+This keeps =inbox/= free of prep-doc churn and makes "today's prep" a single
+predictable path instead of a dated filename that has to be reconstructed.
** Phase 9: Project Extension
@@ -503,7 +524,7 @@ Created during first daily prep session. Validated against tomorrow's schedule (
When referring to past meetings or events, always include the explicit day (e.g., "from Monday's meeting" not "from this morning's meeting"). The prep doc may be written the day before and read the day of -- relative references like "this morning" or "today" become ambiguous. Include the day name so Craig doesn't have to calculate days in his head while focused on making a point.
*** 2026-02-23: Prep doc output
-The prep is written to =inbox/YYYY-MM-DD-daily-prep.org= where the date is the day being prepped for.
+The prep was originally written to =inbox/YYYY-MM-DD-daily-prep.org= where the date is the day being prepped for. (Superseded 2026-06-01 — prep docs now live in =daily-prep/= with a root =daily-prep.org= symlink. See the 2026-06-01 entry below and Phase 8.)
The startup workflow checks for this file and asks whether to open it. Note: need to resolve where the daily prep reference in startup.org lives so template syncing doesn't overwrite it (see todo.org task).
*** 2026-02-23: Check for dependencies between tasks and meetings
@@ -575,3 +596,6 @@ Craig's call, originally landed in the work project's =triage-intake= workflow o
*** 2026-05-31: Delegate triage to the triage-intake engine
Phase 3's inline source scans — sub-steps 3b (email), 3c (mark-read), 3d (Slack), 3e (Linear), 3f (PRs), and 3g's cross-source dedup, ~280 lines — duplicated what the =triage-intake.org= engine has owned since its 2026-05-26 engine/plugin refactor. Collapsed them to four steps: 3b runs the engine (it fans out across general + project source plugins, classifies, synthesizes, writes the =:quick:reactive:= tasks, and executes star/mark-read/trash on confirmation); 3c surfaces today's reactive items as Day's Priorities thin links; 3d re-sorts by urgency; 3e writes the audit footer from the engine's per-source coverage. Source coverage carries because the engine's Phase 0 globs both =.ai/workflows/= and =.ai/project-workflows/= plugins, so the work account's Gmail/Slack/Linear/GHE plugins are still scanned — the delegation must not drop them, and Phase 0's two-dir glob is what guarantees it. The Recommended Approach Pattern stayed here as the shared reference (the engine applies it when writing reactive-task bodies); a future tidy could move it into the engine. Also closes the 2026-05-12 follow-up about rewording sub-steps 3b-3f.
+
+*** 2026-06-01: Prep docs live in =daily-prep/= with a root =daily-prep.org= symlink — no inbox churn, no archive move
+Craig's call. The prep doc is now *born* in =daily-prep/YYYY-MM-DD-daily-prep.org= and never moves; the dated files accumulate there as both working location and archive. A single stable symlink at the project root — =daily-prep.org= — points at the current day's file, repointed each prep run with =ln -sf=. Replaces the prior model where the doc was born in =inbox/YYYY-MM-DD-daily-prep.org=, yesterday's stayed in =inbox/=, and older docs were =mv='d into the =daily-prep/= archive (old Phase 8). Consumers resolve the root symlink instead of computing a dated filename or searching =inbox/=: the Emacs opener =C-c p d= (=cj/open-project-daily-prep=, repointed from =inbox/today-prep.org= to =daily-prep.org= — handoff filed to the =.emacs.d= project 2026-06-01), next-day Phase 2, and the standup lookback (Phase A step 5, which now globs =daily-prep/= and takes the file before the symlink's target). Touchpoints updated: Phase A step 5 + slim-Phase-A step 2 (lookback), standup-only "Where the brief lands," Phase 8 (rewritten as "Repoint the Current-Day Symlink"). Cross-workflow: =triage-intake.org='s sentinel-anchor fallback dropped its =inbox/= prep-doc path. (=wrap-it-up.org= was left as-is — its =inbox/= references are about =lint-followups.org= routing, not the prep doc, so they stay correct.) Migration is one-time per project: move existing =inbox/*-daily-prep.org= into =daily-prep/= and create the root symlink at the most recent.
diff --git a/.ai/workflows/triage-intake.org b/.ai/workflows/triage-intake.org
index cfcf9d7..844b2c0 100644
--- a/.ai/workflows/triage-intake.org
+++ b/.ai/workflows/triage-intake.org
@@ -202,7 +202,7 @@ The workflow needs a "scan since" timestamp. Resolution order:
1. *Sentinel file content:* first whitespace-delimited token in =.ai/last-triage-intake= is the Phase A scan-kickoff epoch from the most recent successful run (see "Capture the Phase A timestamp" below). Most accurate.
2. *Sentinel file mtime* (back-compat): if the file exists but is empty, read its mtime — that's the older mtime-based convention that pre-dates the content-based change. Still accurate on the machine that wrote it.
-3. *Most recent prep doc:* if no sentinel content or readable mtime, anchor on the latest =inbox/YYYY-MM-DD-daily-prep.org= or =daily-prep/YYYY-MM-DD-daily-prep.org= mtime.
+3. *Most recent prep doc:* if no sentinel content or readable mtime, anchor on the latest =daily-prep/YYYY-MM-DD-daily-prep.org= mtime.
4. *Most recent session file:* if none of the above, anchor on the most recent =.ai/sessions/= file's mtime.
5. *Session start:* fall back to the current session's start time. Last resort.
diff --git a/claude-templates/.ai/workflows/daily-prep.org b/claude-templates/.ai/workflows/daily-prep.org
index d8e186d..e58fd88 100644
--- a/claude-templates/.ai/workflows/daily-prep.org
+++ b/claude-templates/.ai/workflows/daily-prep.org
@@ -56,19 +56,21 @@ Runs *only* a slim Phase A + Phase 6 + a conditional Phase 8 + Phase 9. Skip Pha
Fetch only what Phase 6 needs:
1. =todo.org= — for WAITING items (blockers) and DONE-since-cutoff (completed work).
-2. Previous prep doc — anchor for the lookback (check =inbox/= then =daily-prep/=, take most recent).
+2. Previous prep doc — anchor for the lookback. Glob =daily-prep/*-daily-prep.org=, sort by date, take the file *before* the one the root =daily-prep.org= symlink currently resolves to (i.e. the prior prep day, not today's).
3. Most recent =.ai/sessions/= summary — for the "what did I do" question.
Skip the calendar fetches, the Proton grep, and the [#A]/[#B] todo pull. Phase 6 Step 1's sweep handles the rest.
*** Where the brief lands
-- If a prep doc for today already exists at =inbox/YYYY-MM-DD-daily-prep.org=, append or replace its =* Standup Brief= section.
-- If no prep doc for today exists, create =inbox/YYYY-MM-DD-daily-prep.org= with only the =* Standup Brief= section populated. Full prep can be added later by re-running in full-prep mode.
+- If a prep doc for today already exists at =daily-prep/YYYY-MM-DD-daily-prep.org=, append or replace its =* Standup Brief= section.
+- If no prep doc for today exists, create =daily-prep/YYYY-MM-DD-daily-prep.org= with only the =* Standup Brief= section populated, then repoint the root symlink at it (=ln -sf daily-prep/YYYY-MM-DD-daily-prep.org daily-prep.org=). Full prep can be added later by re-running in full-prep mode.
+
+See *Phase 8* for the prep-doc home and symlink convention.
*** Phase 8 in standup-only mode
-Only run if a stale prep doc exists in =inbox/= that's older than yesterday. Otherwise skip — there's nothing to archive.
+If standup-only created a new dated file in =daily-prep/= (no prep doc for today existed), repoint the root =daily-prep.org= symlink at it. "Where the brief lands" above already does this; Phase 8 is a no-op when it did. If today's prep doc already existed and the brief was appended to it, the symlink already resolves to it — nothing to do.
Use standup-only mode when Craig wants the brief fast (e.g., right before standup) without rebuilding the day's plan.
@@ -155,7 +157,7 @@ Before any synthesis or interaction, pull every source the prep doc needs in a *
2. =mcp__google-calendar__list-events= for the *work* account, same scope.
3. Grep =~/.emacs.d/data/pcal.org= for items on that day. This is the Proton Calendar export (=pcal= = personal calendar). The same directory has =gcal.org= and =dcal.org= for Google personal + DeepSat, but those are already covered by the MCP queries in steps 1 and 2 — only =pcal.org= adds non-redundant items.
4. Read =todo.org= — collect [#A] and [#B] tasks plus anything with DEADLINE: or SCHEDULED: touching the day.
-5. List + read the *previous* prep doc. Check =inbox/= first (active prep docs not yet archived), then =daily-prep/= (the archive). Take the most recent file by date — usually yesterday's, but may be older if Craig was off (PTO, weekend, missed days). The lookback for the standup brief is anchored on this file's date, so accuracy matters.
+5. List + read the *previous* prep doc. Glob =daily-prep/*-daily-prep.org= (all prep docs live there, born and kept — no separate archive). Sort by date and take the file *before* the one the root =daily-prep.org= symlink currently resolves to — usually yesterday's, but may be older if Craig was off (PTO, weekend, missed days). If the symlink doesn't resolve yet (no prep ever run), take the most recent file by date. The lookback for the standup brief is anchored on this file's date, so accuracy matters.
6. Read the most recent =.ai/sessions/= summary file (for the standup brief's "What did I do since last standup?" question).
Phases 1-5 below all work from this in-memory snapshot. *Do NOT re-query the calendars in Phase 4* — the time-blocking pass uses the same data Phase A fetched. A typical daily-prep used to run 4-5 sequential round-trips just for data gathering; this collapses to one.
@@ -450,20 +452,39 @@ Format: bullet list or =** TODO= headings, with optional time estimates (e.g., "
This section is the explicit handoff to next-day's Phase 2. If it's empty, write the header with "(none flagged)" so the next day's prep doesn't mistake an empty section for a missing one.
-** Phase 8: Archive Older Prep Docs
+** Phase 8: Repoint the Current-Day Symlink
+
+Prep docs are *born* in their permanent home and never move. The home is
+=daily-prep/= at repo root: every prep doc is created directly as
+=daily-prep/YYYY-MM-DD-daily-prep.org= (Phase A onward writes there), and the
+dated files accumulate in place. There is no archive move — =daily-prep/= is
+both the working location and the archive.
-After the new prep doc is written, archive any prep docs in =inbox/= older than yesterday's. Yesterday's prep doc stays in =inbox/= because the new prep doc may still need to reference it (Planned vs Actual, talking-point carry-forward).
+A single stable symlink at the project root — =daily-prep.org= — points at the
+current day's file. The only day-to-day change is repointing it. After the new
+prep doc exists, point the symlink at it:
#+begin_src bash
-# Move any inbox/*-daily-prep.org file dated before yesterday into the archive.
-mv inbox/YYYY-MM-DD-daily-prep.org daily-prep/
+# Relative target so the symlink stays valid if the project tree moves.
+ln -sf daily-prep/YYYY-MM-DD-daily-prep.org daily-prep.org
#+end_src
-The archive lives at =daily-prep/= at repo root. Don't put prep docs in =deepsat/meetings/= — the prep doc covers personal calendar, all 1:1s, and all projects, not just DeepSat work.
+Consumers — the Emacs opener (=C-c p d=), next-day Phase 2, the standup
+lookback — resolve =daily-prep.org= rather than computing a filename or
+searching =inbox/=. Nothing prep-related lands in =inbox/= anymore.
-If =daily-prep/= doesn't exist yet (new project), create it. If a stale prep doc lives in =assets/= (an older convention), move it to =daily-prep/= as part of this archive pass.
+Setup / migration (first run in a project on this convention):
-This step keeps =inbox/= clean. The previous-day's prep is the only one that still has consumers.
+- If =daily-prep/= doesn't exist yet, create it.
+- Move any existing =inbox/*-daily-prep.org= (the old born-in-inbox location)
+ into =daily-prep/=, and any stale prep doc under =assets/= (an even older
+ convention) likewise. Then create the root =daily-prep.org= symlink at the
+ most recent one.
+- Don't put prep docs in =deepsat/meetings/= — the prep doc covers personal
+ calendar, all 1:1s, and all projects, not just DeepSat work.
+
+This keeps =inbox/= free of prep-doc churn and makes "today's prep" a single
+predictable path instead of a dated filename that has to be reconstructed.
** Phase 9: Project Extension
@@ -503,7 +524,7 @@ Created during first daily prep session. Validated against tomorrow's schedule (
When referring to past meetings or events, always include the explicit day (e.g., "from Monday's meeting" not "from this morning's meeting"). The prep doc may be written the day before and read the day of -- relative references like "this morning" or "today" become ambiguous. Include the day name so Craig doesn't have to calculate days in his head while focused on making a point.
*** 2026-02-23: Prep doc output
-The prep is written to =inbox/YYYY-MM-DD-daily-prep.org= where the date is the day being prepped for.
+The prep was originally written to =inbox/YYYY-MM-DD-daily-prep.org= where the date is the day being prepped for. (Superseded 2026-06-01 — prep docs now live in =daily-prep/= with a root =daily-prep.org= symlink. See the 2026-06-01 entry below and Phase 8.)
The startup workflow checks for this file and asks whether to open it. Note: need to resolve where the daily prep reference in startup.org lives so template syncing doesn't overwrite it (see todo.org task).
*** 2026-02-23: Check for dependencies between tasks and meetings
@@ -575,3 +596,6 @@ Craig's call, originally landed in the work project's =triage-intake= workflow o
*** 2026-05-31: Delegate triage to the triage-intake engine
Phase 3's inline source scans — sub-steps 3b (email), 3c (mark-read), 3d (Slack), 3e (Linear), 3f (PRs), and 3g's cross-source dedup, ~280 lines — duplicated what the =triage-intake.org= engine has owned since its 2026-05-26 engine/plugin refactor. Collapsed them to four steps: 3b runs the engine (it fans out across general + project source plugins, classifies, synthesizes, writes the =:quick:reactive:= tasks, and executes star/mark-read/trash on confirmation); 3c surfaces today's reactive items as Day's Priorities thin links; 3d re-sorts by urgency; 3e writes the audit footer from the engine's per-source coverage. Source coverage carries because the engine's Phase 0 globs both =.ai/workflows/= and =.ai/project-workflows/= plugins, so the work account's Gmail/Slack/Linear/GHE plugins are still scanned — the delegation must not drop them, and Phase 0's two-dir glob is what guarantees it. The Recommended Approach Pattern stayed here as the shared reference (the engine applies it when writing reactive-task bodies); a future tidy could move it into the engine. Also closes the 2026-05-12 follow-up about rewording sub-steps 3b-3f.
+
+*** 2026-06-01: Prep docs live in =daily-prep/= with a root =daily-prep.org= symlink — no inbox churn, no archive move
+Craig's call. The prep doc is now *born* in =daily-prep/YYYY-MM-DD-daily-prep.org= and never moves; the dated files accumulate there as both working location and archive. A single stable symlink at the project root — =daily-prep.org= — points at the current day's file, repointed each prep run with =ln -sf=. Replaces the prior model where the doc was born in =inbox/YYYY-MM-DD-daily-prep.org=, yesterday's stayed in =inbox/=, and older docs were =mv='d into the =daily-prep/= archive (old Phase 8). Consumers resolve the root symlink instead of computing a dated filename or searching =inbox/=: the Emacs opener =C-c p d= (=cj/open-project-daily-prep=, repointed from =inbox/today-prep.org= to =daily-prep.org= — handoff filed to the =.emacs.d= project 2026-06-01), next-day Phase 2, and the standup lookback (Phase A step 5, which now globs =daily-prep/= and takes the file before the symlink's target). Touchpoints updated: Phase A step 5 + slim-Phase-A step 2 (lookback), standup-only "Where the brief lands," Phase 8 (rewritten as "Repoint the Current-Day Symlink"). Cross-workflow: =triage-intake.org='s sentinel-anchor fallback dropped its =inbox/= prep-doc path. (=wrap-it-up.org= was left as-is — its =inbox/= references are about =lint-followups.org= routing, not the prep doc, so they stay correct.) Migration is one-time per project: move existing =inbox/*-daily-prep.org= into =daily-prep/= and create the root symlink at the most recent.
diff --git a/claude-templates/.ai/workflows/triage-intake.org b/claude-templates/.ai/workflows/triage-intake.org
index cfcf9d7..844b2c0 100644
--- a/claude-templates/.ai/workflows/triage-intake.org
+++ b/claude-templates/.ai/workflows/triage-intake.org
@@ -202,7 +202,7 @@ The workflow needs a "scan since" timestamp. Resolution order:
1. *Sentinel file content:* first whitespace-delimited token in =.ai/last-triage-intake= is the Phase A scan-kickoff epoch from the most recent successful run (see "Capture the Phase A timestamp" below). Most accurate.
2. *Sentinel file mtime* (back-compat): if the file exists but is empty, read its mtime — that's the older mtime-based convention that pre-dates the content-based change. Still accurate on the machine that wrote it.
-3. *Most recent prep doc:* if no sentinel content or readable mtime, anchor on the latest =inbox/YYYY-MM-DD-daily-prep.org= or =daily-prep/YYYY-MM-DD-daily-prep.org= mtime.
+3. *Most recent prep doc:* if no sentinel content or readable mtime, anchor on the latest =daily-prep/YYYY-MM-DD-daily-prep.org= mtime.
4. *Most recent session file:* if none of the above, anchor on the most recent =.ai/sessions/= file's mtime.
5. *Session start:* fall back to the current session's start time. Last resort.