Ka-Note/plans/rename-cascade.md

3.4 KiB

Plan: Rename Cascade + Duplicate Check

Features

  1. After renaming a person/project/company, update all @mentions in existing text
  2. On rename: prevent duplicate names of the same type

Affected Files

File Change
client/src/lib/utils/mentionReplace.ts NEW — renameMentions(text, oldName, newName, type)
client/src/lib/db/repositories.ts ADD renameMentionCascade(oldName, newName, type)
client/src/lib/components/ContextHeader.svelte UPDATE saveEdit() — duplicate check + cascade; add warning UI

New File: mentionReplace.ts

Pure function, no Dexie dependency.

export function renameMentions(
  text: string,
  oldName: string,
  newName: string,
  type: 'person' | 'project' | 'company'
): string

Regex patterns to replace:

Type Unquoted Quoted
person @OldName @"Old Name"
project @P:OldName / @p:OldName @P:"Old Name"
company @F:OldName / @f:OldName @F:"Old Name"
assignment (person only) -> OldName n/a (not supported by extractors)

Replacement: use quoteMention-logic — add quotes if newName contains spaces.

Boundary condition: match must end at [\w"] boundary to avoid partial matches (e.g. @Alice must not match @AliceBob).


renameMentionCascade in repositories.ts

Run in a single Dexie transaction (rw on historyEntries, topics, contexts, ratings).

Fields to scan:

Table Field Notes
historyEntries text Primary mention location
topics title Inline mentions possible
contexts meta.notes PersonMeta / ProjectMeta / CompanyMeta only
ratings comment Optional, may have @mentions
ratings personName Structured field, person rename only (exact match)

For each changed record: increment version, update updatedAt.

Pattern to follow: renameTitleInLinks() already exists in repositories.ts (line ~541).


ContextHeader.sveltesaveEdit() changes

1. trimmed = nameInput.trim()
2. if trimmed === editableName() → return (no-op)
3. if type is person/project/company:
   - check contextNameExists(fullName(trimmed), type)
   - if exists AND id !== context.id → show duplicate warning, revert, return
4. oldName = editableName()
5. await upsertContext({ id, name: fullName(trimmed) })
6. if type is person/project/company:
   - await renameMentionCascade(oldName, trimmed, type)

Add duplicateWarning state + small error message below input.


Sequencing

  1. mentionReplace.ts — implement + manual regex tests
  2. repositories.ts — add renameMentionCascade
  3. ContextHeader.svelte — wire up

Open Questions

  1. -> Name with spaces: extractors.ts arrow pattern only matches [\w]+. If renamed from single-word to multi-word, arrow assignments break silently. Extend extractors to support -> "First Last", or accept as edge case?
  2. EventMeta.participants: Plain string[], not mention syntax. Update on person rename?
  3. Case-only rename (Alice → ALICE): contextNameExists is case-insensitive — will incorrectly block. Need to exclude self from duplicate check.
  4. Performance: Full table scan (no text index). Acceptable for local-first small datasets — add a comment.
  5. Sync conflicts: Cascade causes many version++. Last-write-wins acceptable, or need special marker?