DUNIN7 · LOOMWORKS · RECORD
record.dunin7.com
Status Current
Path scoping-notes/loomworks-remember-about-me-confirmation-loop-scoping-note-v0_1.md

Loomworks — remember-about-me confirmation-loop — scoping note — v0.1

Document: loomworks-remember-about-me-confirmation-loop-scoping-note-v0_1 Version: v0.1 Status: scoping note — precedes a fix CR. Three findings; the fix shape and sequencing are for the Operator to settle before a CR is drafted. Date: 2026-06-27 Origin: Operator testing on E0007 ("Goosey the Moose"), 2026-06-27 — "park the car on level 8" entered a permanent confirmation loop. Diagnosed read-only by CC (DB trace on conversation_turns + current_memory_objects, engine line citations). Not caused by: CR-2 list-loading. CR-2 is frontend/read-path; it touched zero engine files; classification and commit live in loomworks-engine, untouched. CR-2 is cleared to land independently.


What happened (the symptom)

The Operator said "park the car on level 8", then answered "yes" repeatedly. Each "yes" produced another confirmation prompt instead of committing the note. The note never appeared in the engagement's Held or Settled. The loop is permanent — every subsequent "yes" repeats it.

The diagnosis — a two-stage failure, plus a third question

CC traced it to the engine remember_about_me flow. Two stages caused the loop; a third observation is worth a decision.

Stage 1 — primary (origin): imperative mis-classified

"park the car on level 8" classified as general_conversation, not remember_about_me / add_knowledge. It is an imperative ("park the car…"); the classifier's write-intent patterns expect declaratives (add_knowledge → domain facts, remember_about_me → personal facts stated as facts). Contrast the immediately prior "Uncle John's birthday is April 25th" — a clean declarative — which classified correctly and committed in two turns. The imperative matched neither write-intent and fell to general_conversation. The responder LLM then free-formed "Noted — parked on Level 8. Want me to save that?" — an offer with no deterministic held-write behind it — which offset the confirmation rhythm by one turn.

Stage 2 — cascade (the visible stall): normalization too shallow

Once a held draft finally existed (the first "yes" took the new-fact path and created it), the confirmation branch became reachable. But the held content and the continuation fact no longer match:

_normalize_personal_fact (router.py:196) collapses punctuation/whitespace and expands month abbreviations — it does not reorder words or strip possessives. So is_confirmation (router.py:2388) is False. "yes" carries no refinement signal, so the handler falls to the pending_held_blocks_new_fact refuse-overwrite guard (router.py:2442) — which writes nothing and re-surfaces the pending. Permanent stall.

This is the Phase-60-recovery Bug A class (held-creation form vs continuation form mismatch) that _normalize_personal_fact was meant to close — but its normalization is too shallow for word-order/possessive drift, and that drift here was caused by Stage 1 (the held was minted from a general_conversation-worded turn while the continuation came from a differently-worded remember_about_me turn).

Stage 3 — observation (a decision, not necessarily a bug): wrong-engagement write

The held draft ("Car parked on Level 8.", display 18) was written to the Operator's personal engagement (95774ecd), not the active E0007. This is why it never appeared in E0007's Held — it was in a different engagement entirely. remember_about_me writes to the person's personal store, not the active engagement. This may be correct by design (a car-parked note is a personal fact, personal facts belong in the personal store) or it may be a surprise worth examining. It is a separate question from the loop.

Correction recorded (drift-surface): the earlier inference from the screenshot was "the note was never written." It was written — as a held draft — just to the personal engagement and never committed. The absence in E0007 was real; the cause was "written elsewhere + never committed," not "no write."

The three findings, and what each would take

| # | Finding | Layer | Shape of fix | |---|---|---|---| | F1 | Imperatives that imply a fact ("park the car on level 8" = "the car is parked") don't match any write-intent → fall to general_conversation | intent classifier | Broaden write-intent coverage to catch fact-bearing imperatives, or add a normalization/recognition step that maps imperative→declarative before classification. | | F2 | _normalize_personal_fact can't see through word-order/possessive drift between held-form and continuation-form → genuine "yes" fails is_confirmation → refuse-overwrite guard stalls | confirmation state machine | Deepen the match: word-order-insensitive and possessive-stripping comparison, or a different held↔continuation matching strategy (e.g. match on the held's id/pending reference rather than re-deriving and re-comparing the fact text). | | F3 | remember_about_me writes to the personal store while the Operator is in an engagement | routing / store selection | A decision, not obviously a fix: is personal-store routing correct here, or should a fact stated inside an engagement land in that engagement? |

The shape question — which finding is the real defect?

F2 is the deeper fragility. Even if F1 were fixed — even if "park the car" classified correctly — F2 could still strand a confirmation any time the Companion rewords the fact in its confirm-back, which is a normal thing it does. F1 triggered F2 here, but F2 is the load-bearing weakness: any held whose confirm-back gets reworded with a possessive or reordered words is a latent stuck-loop. Fixing only F1 makes this case work and leaves F2 waiting for the next reword.

So the recommended ordering of concern:

  1. F2 first / hardest — it is the structural fragility; the confirmation check must not depend on two independently-worded fact texts normalizing identically. The strongest fix may be to stop re-deriving and re-comparing the fact text at all on a "yes" — match the confirmation to the pending held reference directly (the held already exists; a "yes" with a pending held present is a confirmation of that held, not a new fact to re-extract and re-match). That removes the text-matching brittleness entirely rather than deepening the normalization arms race.
  2. F1 second — broaden write-intent classification to catch fact-bearing imperatives. Real, but secondary: it changes which path a first utterance takes; F2 is what makes the loop permanent.
  3. F3 as an explicit decision — confirm whether personal-store routing is intended for facts stated inside an engagement. If intended, document it (and consider whether the Companion should say "I'll keep this in your personal memory" so the Operator isn't surprised by its absence from the engagement). If not intended, it is a routing fix.

A note on the guard (it is not broken)

The pending_held_blocks_new_fact refuse-overwrite guard is working as designed — it prevents a new fact from silently overwriting a pending held (data-loss protection, the "shape β" guard). It is firing spuriously because the upstream confirmation check (F2) wrongly reads a genuine "yes" as a pivot to a new fact. The fix is upstream of the guard, not in it. Do not weaken the guard.

The stuck artifact

Held assertion display 18, "Car parked on Level 8.", in personal engagement 95774ecd, state held — recoverable once the fix lands (commit it, or retract it). Note it so it is not left as orphaned test residue.

Operator decisions before a CR

  1. Scope — fix all three (F1 + F2 + F3), or F2 alone (the deep fragility, smallest correct fix), or F2 + F1 (leave F3 as a documented decision)?
  2. F2 approach — deepen normalization, or switch to pending-held-reference matching (recommended — removes the text-match brittleness)?
  3. F3 — is personal-store routing for in-engagement facts intended (document it) or wrong (fix it)?
  4. The stuck held (display 18) — commit, retract, or leave for the fix to clean up?

None of these block CR-2 landing; CR-2 is independent and cleared.


DUNIN7 — Done In Seven LLC — Miami, Florida Loomworks — remember-about-me confirmation-loop — scoping note — v0.1 — 2026-06-27 Diagnosed by CC (read-only, DB trace + engine citations). Not a CR-2 regression. Three findings; F2 is the deep fragility. Precedes a fix CR pending Operator scope decisions.