Files
claude-skills/.wiki/concepts/session-inbox-monitor-received-msg-fp.md
vitya 951bc62c04 docs(wiki): capture session-inbox-monitor received-msg FP as concept
New page concepts/session-inbox-monitor-received-msg-fp.md — sibling of
delegate-task-negative-trigger-fp. Same FP family, new dimension: the carve-out
is already literal+routed (NOT for handling a received message ->
inter-session-peer-discipline) but the route target is not installed, so it has
no competitor and the nearest in-domain skill wins anyway. Borderline (neg 2/3,
EN twin clean), self-corrects on body-load. Bidirectional cross-link +
index + log. New principle: a routed negative competes only if its route
target is installed. Captured in the wiki (not private memory) per owner direction.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-17 11:28:31 +03:00

3.9 KiB
Raw Blame History

title, type, tags, updated
title type tags updated
session-inbox-monitor — a routed negative only competes if its sibling is installed concept
skill-triggers
false-positive
trigger-discrimination
test-trigger
2026-06-17

session-inbox-monitor — a routed negative only competes if its sibling is installed

Sibling of delegate-task-negative-trigger-fp. Same failure family (a skill false-positive-fires on a phrase its description tries to exclude), but a distinct mechanism — and it stays open as of this writing (follow-up task session-inbox-monitor-received-msg-fp, not yet fixed).

Symptom

In the session-inbox-monitor-test-trigger run (2026-06-17, clean session, 7 unprimed clean-context subagents), the negative phrase «В .claude-inbox пришло сообщение от другой Claude-сессии. Прочитай его и ответь отправителю.» (N1, RU) routed to session-inbox-monitor — a false-positive. The skill is about raising the monitor, not handling a received message; the latter belongs to inter-session-peer-discipline / the CLAUDE.md inter-session rule.

The English twin of the same scenario (N3, «A message arrived in my inbox … handle it and reply») and the multi-machine-backend negative (N2) both routed to none cleanly, citing the carve-out. So the FP is borderline / non-deterministic, not a hard miss: pos 4/4, neg 2/3.

Root cause

The description does carry a literal, routed carve-out — NOT for how to handle a received message (→ inter-session-peer-discipline) — which is exactly the fix shape delegate-task-negative-trigger-fp prescribes. The new twist:

The route target inter-session-peer-discipline is not an installed skill. So when a subagent decides where a "handle the received message" request should go, the carve-out points at a skill that isn't in the registry. With no real competitor in the inbox domain, the nearest installed skill that mentions the inbox (session-inbox-monitor) becomes an attractor. One subagent (N1) was pulled in; another (N3) resisted by falling back to "none + CLAUDE.md rule." Hence the non-determinism.

Mitigating property: the FP self-corrects on body-load. Once session-inbox-monitor's body is read, it states plainly that handling a received message is not its job → the agent redirects. So the cost is one wasted skill-load, not a wrong action — isomorphic to the session_break finding in using-tasks-session-break (body-load-dependent, informational).

Status — open

No fix shipped. Options under the follow-up task (decide, not necessarily implement):

  • (a) Harden the description — surface NOT for handling a received message earlier / more prominently. Cheap, but a description edit forces a re-run of -test-trigger and feeds back into -review.
  • (b) Install the sibling — give the carve-out a real target by installing inter-session-peer-discipline (likely the true root, but it's a separate skill that may not exist yet, with its own promotion ledger).
  • (c) Accept as informational — like session_break: low harm + body-load self-correct.

Reusable principle

delegate-task-negative-trigger-fp established: make the negative literal and routed, not abstract. This case adds the next clause:

A routed negative competes only if its route target is installed. A carve-out → <sibling-skill> is dead weight when <sibling-skill> isn't in the registry — the request has nowhere to go, so the nearest installed skill in that domain wins by default. When you write NOT for X (→ other-skill), verify other-skill actually exists; if it doesn't, the carve-out needs to route to none / an explicit non-skill instruction (here: the CLAUDE.md inter-session rule), or the sibling must be promoted alongside.

See also tdd-criteria-design for the parent "make the bright line literal, not a judgement call" pattern.