Skip to content

fix(conflict-resolution): document default source_priority=100 footgun + SOURCE_PRIORITY_ESCALATION warning (#1838)#1853

Merged
markmhendrickson merged 1 commit into
mainfrom
fix/1838-source-priority-default-docs-warning
Jun 30, 2026
Merged

fix(conflict-resolution): document default source_priority=100 footgun + SOURCE_PRIORITY_ESCALATION warning (#1838)#1853
markmhendrickson merged 1 commit into
mainfrom
fix/1838-source-priority-default-docs-warning

Conversation

@markmhendrickson

Copy link
Copy Markdown
Owner

The footgun

source_priority defaults to 100 (z.number().optional().default(100) in src/shared/action_schemas.ts). On any field whose reducer policy is highest_priority (or most_specific with tie_breaker: "source_priority"), an unprioritized write silently inherits priority 100 — which outranks any prior observation written with an explicit priority ≤ 99 (e.g. a trusted import at 50). The unprioritized write wins the field. This is a silent trust-escalation: a caller who never thought about priority can override a value that was deliberately ranked lower.

Per the operator verdict on #1838, the default value is unchanged (lowering it would silently flip the winner of existing reductions everywhere — a breaking semantic change). The fix is detection + docs, not a new default.

The fix (docs + warn only — no merge semantics change)

  • Docs: new "The default source_priority = 100 footgun" subsection in docs/subsystems/conflict_resolution.md (§5 Current Limitations) with a worked example and the mitigation: always pass an explicit --source-priority / source_priority for priority-semantic writes. Added a Related-Documents entry for default source_priority is 100 — undocumented, causes silent trust-escalation for unprioritized writes #1838.
  • CLI: --source-priority help on both store commands (src/cli/index.ts) now states the default-100 escalation edge and references docs/subsystems/conflict_resolution.md.
  • Warning: new buildSourcePriorityEscalationWarning(...) in src/services/source_priority_warning.ts returns a { code: "SOURCE_PRIORITY_ESCALATION", message, ... } (or null). Condition: sourcePriority === 100 and at least one written field uses highest_priority. Wired into both store paths — src/actions.ts (HTTP/API storeStructuredForApi) and src/server.ts (MCP store) — right after the existing buildSourcePriorityIgnoredWarning call, pushed to store_warnings[]. Non-blocking; nothing is rejected.

Limitation (default vs. explicit 100)

zod applies .default(100) before the request handler runs, so an explicit source_priority: 100 is indistinguishable from an omitted value at write time. The advisory therefore fires on both, framed as "default/non-explicit 100". This is called out in the warning message, the docs subsection, and the code comments.

Tests

  • Unit (tests/unit/source_priority_ignored_warning.test.ts): priorityHonouringFields, sourcePriorityMayEscalate, and buildSourcePriorityEscalationWarning (fires on default-100 + highest_priority; null on non-default priority; null when no honouring field; most_specific tie-breaker case; message names the honouring field and documents the limitation).
  • Integration (tests/integration/store_source_priority_ignored_warning.test.ts): asserts SOURCE_PRIORITY_ESCALATION fires on a default-100 write to a highest_priority field on both the MCP and HTTP /store paths, and does not fire on a non-default-priority write.
  • Result: 52 tests green (43 unit + 9 integration). type-check, lint (0 errors), prettier --check, validate:test-catalog, and validate:doc-deps all clean. No generated-file drift (openapi.yaml untouched; the docs audit lists paths only, no content/hash dependency).

Closes #1838

🤖 Generated with Claude Code

…n + SOURCE_PRIORITY_ESCALATION warning (#1838)

source_priority defaults to 100 (z.number().optional().default(100)).
An unprioritized write silently inherits 100 and, under a highest_priority
reducer, outranks any prior observation written with an explicit priority
<= 99 -- a silent trust-escalation. Operator verdict: docs + a warning; do
NOT change the (breaking) default.

- docs: new "default source_priority = 100 footgun" subsection in
  docs/subsystems/conflict_resolution.md with mitigation (always pass an
  explicit --source-priority for priority-semantic writes) + #1838 ref.
- CLI: --source-priority help on both store commands now states the
  default-100 escalation edge and points at the conflict-resolution docs.
- warning: buildSourcePriorityEscalationWarning() in
  src/services/source_priority_warning.ts emits a non-blocking
  SOURCE_PRIORITY_ESCALATION store_warning when priority===100 AND a written
  field uses highest_priority. Wired into both store paths (src/actions.ts
  HTTP/API, src/server.ts MCP) right after the existing IGNORED warning.

Limitation: zod applies .default(100) before the handler, so an explicit
100 is indistinguishable from an omitted value at write time; the advisory
fires on both (framed as "default/non-explicit 100").

Tests: unit coverage for priorityHonouringFields / sourcePriorityMayEscalate
/ buildSourcePriorityEscalationWarning; integration assertions that the
escalation warning fires on a default-100 write to a highest_priority field
on both MCP and HTTP paths (52 tests green).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@markmhendrickson markmhendrickson merged commit 05f7bb6 into main Jun 30, 2026
10 checks passed
@github-actions

Copy link
Copy Markdown

Docs preview

Preview URL: https://dev.neotoma.io/pr-1853/

Built from 9803a49a80160b735b554d7d2216e060cce057cb. The preview is a static export — manifest-driven category ordering is not applied, but all doc content is rendered.

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.

default source_priority is 100 — undocumented, causes silent trust-escalation for unprioritized writes

1 participant