Skip to content

fix: a failed target resolution names the rung that declined (#72) + release 0.12.4 - #73

Merged
TerrifiedBug merged 1 commit into
masterfrom
fix/name-the-failed-rung
Aug 23, 2026
Merged

fix: a failed target resolution names the rung that declined (#72) + release 0.12.4#73
TerrifiedBug merged 1 commit into
masterfrom
fix/name-the-failed-rung

Conversation

@TerrifiedBug

Copy link
Copy Markdown
Owner

Closes #72. Also bumps to 0.12.4 — this is the only open issue, so it is a single-issue patch.

What was wrong

The refusal was no active telegram chat — pass chat_id: true, and unactionable. It could not separate "topics are off" from "a live claim exists but its session identity is not mine" — and those want opposite responses.

Measured on conductor#882, that ambiguity cost two 300-second arming attempts and a five-hour delivery hold while a matching claim sat in the registry the whole time.

The ladder logged only its successes, at debug:

if (resolved && resolved.source !== "active inbound") {
  log.debug(`[telegram] ${tool} target resolved from ${resolved.source}`);
}

resolved === undefined — the one case a human is debugging — logged nothing.

Now

no active telegram chat — pass chat_id. [telegram] telegram_send found no target:
nothing inbound this turn; this session owns no topic; topic registry has 2 claim(s),
none matching this session's identity; no DM owner pinned

Four cases that previously read identically are now distinguishable:

situation wording
registry present, no claims topic registry carries no claims
registry for another chat topic registry names a different chat
claims exist, none mine topic registry has N claim(s), none matching this session's identity
DM owner is somebody else DM owner is another session (vs no DM owner pinned)

The third is the one #882 could not diagnose: claims are present, so the registry is fine and the bridge has run — the mismatch is identity, which points at a resumed session or a plugin too old to compare session files.

One line per failed call, never one per rung. Also carried on telegram_ask's no-surface refusal, where "no surface available" reads as a config problem while the common cause is a target that nearly resolved.

Counts, never ids. The precedent is resolveProjectTopicId's rule that a log line is a place ids leak from; a test asserts no thread id, pid or session file appears in the sentence.

Two assertions changed on purpose

index.wiring.test.ts:405 and :413 pinned the exact old string. Both now assert the actionable prefix plus the rung — and one pins the distinction it was previously blind to:

expect(text).toContain("DM owner is another session");
expect(text).not.toContain("no DM owner pinned");

Verified against the fake #72 names

#72 warns the likely fake is logging rung names without their reasons. Replacing the reasons with a bare "topic registry":

2 of 3 new tests fail
restored → 3 pass

Proof

bun run check   → 317 pass, 0 fail   (0.12.3 shipped 314)

Live sanity against this host's real registry (1 claim): a foreign session is now told topic registry has 1 claim(s), none matching this session's identity rather than the bare refusal.

After merge

npm whoami is still 401 for me, so publishing needs your credential:

npm publish --access public
npm view omp-telegram version           # expect 0.12.4
omp plugin install omp-telegram@0.12.4

release 0.12.4

The refusal callers got was "no active telegram chat - pass chat_id": true, and
unactionable. It could not separate "topics are off" from "a live claim exists
but its session identity is not mine", and those want opposite responses.

Measured on conductor#882, that ambiguity cost two 300-second arming attempts
and a five-hour delivery hold while a matching claim sat in the registry the
whole time. The ladder logged only its successes, at debug; the one case a human
is debugging - `resolved === undefined` - logged nothing at all.

So the ladder now reports why each rung declined, and the refusal carries it:

  no active telegram chat - pass chat_id. [telegram] telegram_send found no
  target: nothing inbound this turn; this session owns no topic; topic registry
  has 2 claim(s), none matching this session's identity; no DM owner pinned

One line per failed call, never one per rung. Counts, never ids - the precedent
is `resolveProjectTopicId`'s rule that a log line is a place ids leak from, and
a test asserts no thread id, pid or session file appears.

Four cases are now distinguishable that previously read identically: an empty
registry, a registry for another chat, claims that exist but do not match this
session, and a DM owner pinned to somebody else.

Two existing assertions changed on purpose: they pinned the exact old string.
Both now assert the actionable prefix plus the rung, and one of them pins the
distinction it was blind to - "DM owner is another session" is not "no DM owner
pinned".

Verified against the fake #72 names: replacing the reasons with bare rung names
("topic registry") turns two of the three new tests red.

bun run check: 317 pass, 0 fail.
@TerrifiedBug
TerrifiedBug merged commit 96db014 into master Aug 23, 2026
1 check passed
@TerrifiedBug
TerrifiedBug deleted the fix/name-the-failed-rung branch August 23, 2026 09:34
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.

A failed target resolution does not say which rung failed, so an identity mismatch is indistinguishable from no claims at all

1 participant