Skip to content

feat(contacts)!: contacts unlink needs --from, the person the identity leaves - #2848

Merged
leemour merged 3 commits into
mainfrom
fix/contacts-unlink-from
Nov 11, 2026
Merged

leemour merged 3 commits into
mainfrom
fix/contacts-unlink-from

Conversation

@leemour

@leemour leemour commented Nov 10, 2026

Copy link
Copy Markdown
Member

Why

memo people unlink took a colleague's mailbox off the colleague instead of off the owner, because it never asked which person the identities leave (BUG-709). cli-core #2841 added the "from whom" check to the store, and memo #806 makes --from required. tg, max and wa contacts unlink still took an identity off whoever held it. The owner approved the same check there (NEED-2525 A), with --from required.

What

  • contacts unlink <person> --from person:<uid>|person:me (and services.people.unlink(person, { by, from })). Without --from it is refused with validation_error, reason person.from-required. The message names who holds the identity and gives the command to run with their --from. An identity on someone else is refused with identity.held-elsewhere, and nothing moves.
  • cli-base 0.96.0, whose vocabulary has --from <person> (cli-base chore: release 0.148.2 #563, NEED-2530 A). bot search messages --from now shows <person>, and its option-role baseline entry goes.
  • parity.json lists --from for contacts unlink; docs/dev/STANDARD.md is regenerated.
  • mongoose 9.12.1 in bench/stemming/pnpm-lock.yaml only, for Dependabot alert 29 (SEC-183, NEED-2527 A).
  • The changelog entry is under "Changed — may break callers". tg, max and wa need their docs regenerated at their next cli-core bump.

Testing

  • Full vitest run on cli-base 0.96.0 (11179 passed, 16 skipped). This includes fix(permissions): deny contact-context body reads with messages #562's refusal of the owner's real home.
  • ci:quick, lint, docs:check, and the command lint (0 new violations).
  • New tests: the service refuses without --from and names the holder and the command; it refuses a wrong --from and person:me when the identity sits elsewhere. The CLI test reads the --from out of the refusal and unlinks with it.

🤖 Generated with Claude Code

leemour and others added 3 commits November 11, 2026 01:05
…y leaves

Without it the command is refused (person.from-required) and the message names who holds the identity and the
command to run; an identity on someone else is refused with identity.held-elsewhere, as memo's people unlink is.
person:me names the owner. Also bumps mongoose in bench/stemming to 9.12.1 (Dependabot alert 29, SEC-183).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…erson>

The vocabulary now gives --from one meaning, a person, so the bot flag's option-role baseline entry goes.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…om to add, and from is required in the type

- The missing --from refusal names `provider:id`, the person it sits on and `--from person:<uid>` to run it again
  with; a lone identity still answers "not linked to anyone" first.
- `services.people.unlink` takes `from: string`, so a caller's typecheck catches the change; `person:me` goes through
  withOwner, which refuses an owner with no identity and says how to mark one.
- The help example passes `--from person:me`; parity.json's `--from` says `<person>` and both meanings.
- The changelog fragment is named after the branch.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@leemour
leemour force-pushed the fix/contacts-unlink-from branch from 3e6617a to 94f4c5a Compare November 11, 2026 00:07
@leemour
leemour merged commit aa05e8f into main Nov 11, 2026
49 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant