Summary
Two related drift modes surface in /productivity:update when it's run on recurring days against a populated memory directory. Both reproduce cleanly. The fix for both is markdown-only — two surgical inserts to productivity/commands/update.md. Happy to open a PR if that's the preferred path.
Drift Mode 1: Day-of-week labels carry forward across runs
Observed. On a Wednesday-morning run, three meetings with Tuesday ISO timestamps in the source data were labeled "Mon" in the output. The labels appear to have been carried forward from the prior day's update narrative rather than recomputed against today's <env> date.
Expected. Day-of-week labels should be derived from the ISO date against the current <env> date on every run, not carried over from prior phrasing.
Repro.
- Run
/productivity:update --comprehensive on day N. Output references "Monday's meeting" against date YYYY-MM-DD.
- Run
/productivity:update --comprehensive again on day N+1. Source data still references the same meetings with their original ISO timestamps.
- Output continues to label them "Monday" rather than re-resolving the day-of-week from the ISO date against today's
<env>.
The drift is subtle because the ISO date stays correct in the source — only the day-of-week label gets fossilized in the narrative phrasing.
Drift Mode 2: Suggest-new-memories flags known people on name variants
Observed. The "Suggest New Memories" step proposes adding people who are already in memory/people/ under a different first-name variant (nickname vs. full form, or alternate spelling). On a real run, a person already in memory under a nickname was flagged as new when the source surfaced their full first name.
Expected. Before flagging an entity as new, the step should fuzzy-match against existing memory by (a) full name, (b) email handle / Slack username, and (c) last name alone — to catch nickname↔full-form pairs and variant spellings.
Repro.
- Have
memory/people/sue-park.md for "Sue Park."
- Have a source message (Slack, email, transcript) from "Susan Park" appear in the period the update is scanning.
- Run
/productivity:update --comprehensive. The Suggest New Memories step proposes "Susan Park" as a new entity rather than recognizing the last-name collision with the existing Sue Park record.
The drift compounds across runs: each new run re-proposes the same name variant unless the user manually merges it.
Proposed fix
Two markdown-only inserts into productivity/commands/update.md. No MCP, hook, or schema surface area changes.
diff --git a/productivity/commands/update.md b/productivity/commands/update.md
@@ -19,6 +19,15 @@
/productivity:update --comprehensive
```
+## Date discipline
+
+Every output reference to a past meeting, a deadline, "yesterday," or a schedule window must resolve cleanly to an ISO date. Two rules:
+
+1. **Cite past events as `YYYY-MM-DD (DayOfWeek)`** — e.g. `2026-05-05 (Tue)`, never bare `Mon May 5` or `May 5`. Compute the day-of-week from the date string (against the current date in `<env>` or via `date -d "<YYYY-MM-DD>" +%a`). Never use a day-of-week label without verifying it from the date.
+2. **Never write "yesterday," "Monday," or "this week" without first anchoring on the ISO date.** When a tool returns `2026-05-05T14:00:00Z`, fix the date first, then translate to relative phrasing. The relative wording is output convenience; the ISO date is the source of truth.
+
+This catches a recurring drift mode where a scheduled run mis-labels Tuesday as Monday because the prior day's update used "Monday" and the model carries the phrasing forward without recomputing.
+
## Default Mode
### 1. Load Current State
@@ -138,6 +147,13 @@
### Extra Step: Suggest New Memories
+Before flagging any new entity, **fuzzy-match against existing memory** — this catches the drift mode where two name variants of the same person get treated as two people across recurring runs.
+
+- **For people:** search `memory/people/` (and the People table in CLAUDE.md) by (a) full name, (b) email handle / Slack username, and (c) last name alone. First names often surface as nicknames or full forms — "Mike" and "Michael," or "Sue" and "Susan," can refer to the same person. If the email handle or last name matches anyone in memory, treat the name as already-known and update the existing record instead of flagging a new one.
+- **For projects/topics:** match against `memory/projects/` and the Active Projects context, including acronym ↔ full-name pairs.
+
+Only after the fuzzy match comes back empty should the entity surface as a new-memory suggestion.
+
Surface new entities not in memory:
Verification
- Date-discipline rule.
date -d '2026-05-05' +%a returns Tue, which is what the unpatched run mislabeled as Mon on a 2026-05-06 run. Rule produces the correct label.
- Fuzzy-match rule. Last-name match against existing memory catches the nickname/full-form collision the unpatched run missed. Bonus: the same rule also catches a second collision on the same run that the unpatched flow re-proposed as new.
Happy to open a PR with this diff if it's helpful. Either way, posting here so it's documented.
Summary
Two related drift modes surface in
/productivity:updatewhen it's run on recurring days against a populated memory directory. Both reproduce cleanly. The fix for both is markdown-only — two surgical inserts toproductivity/commands/update.md. Happy to open a PR if that's the preferred path.Drift Mode 1: Day-of-week labels carry forward across runs
Observed. On a Wednesday-morning run, three meetings with Tuesday ISO timestamps in the source data were labeled "Mon" in the output. The labels appear to have been carried forward from the prior day's update narrative rather than recomputed against today's
<env>date.Expected. Day-of-week labels should be derived from the ISO date against the current
<env>date on every run, not carried over from prior phrasing.Repro.
/productivity:update --comprehensiveon day N. Output references "Monday's meeting" against dateYYYY-MM-DD./productivity:update --comprehensiveagain on day N+1. Source data still references the same meetings with their original ISO timestamps.<env>.The drift is subtle because the ISO date stays correct in the source — only the day-of-week label gets fossilized in the narrative phrasing.
Drift Mode 2: Suggest-new-memories flags known people on name variants
Observed. The "Suggest New Memories" step proposes adding people who are already in
memory/people/under a different first-name variant (nickname vs. full form, or alternate spelling). On a real run, a person already in memory under a nickname was flagged as new when the source surfaced their full first name.Expected. Before flagging an entity as new, the step should fuzzy-match against existing memory by (a) full name, (b) email handle / Slack username, and (c) last name alone — to catch nickname↔full-form pairs and variant spellings.
Repro.
memory/people/sue-park.mdfor "Sue Park."/productivity:update --comprehensive. The Suggest New Memories step proposes "Susan Park" as a new entity rather than recognizing the last-name collision with the existing Sue Park record.The drift compounds across runs: each new run re-proposes the same name variant unless the user manually merges it.
Proposed fix
Two markdown-only inserts into
productivity/commands/update.md. No MCP, hook, or schema surface area changes.Verification
date -d '2026-05-05' +%areturnsTue, which is what the unpatched run mislabeled asMonon a 2026-05-06 run. Rule produces the correct label.Happy to open a PR with this diff if it's helpful. Either way, posting here so it's documented.