fix(grounding): a generic self-noun is still this service claiming #580

Merged
coilyco-ops merged 1 commit from coilyco-ops/a-generic-self-noun-is-still-this-service into main 2026-08-13 16:22:28 +00:00 AGit
Member

closes #557 mechanical half - the guard matched one literal identity, so the runtime naming itself the service or the harness walked through.

closes #557 mechanical half - the guard matched one literal identity, so the runtime naming itself the service or the harness walked through.
fix(grounding): a generic self-noun is still this service claiming
All checks were successful
ci / test (pull_request) Successful in 32s
ci / publish-echo-image (pull_request) Has been skipped
ci / publish-observed (pull_request) Has been skipped
ci / image-build (pull_request) Successful in 19s
31db33e74e
ValidateSelfAttributedClaim built its pattern from regexp.QuoteMeta(identity),
so it matched exactly one string. Every other way the runtime names itself
walked through:

  "The service filed a correction."        escaped
  "The harness created a tracking issue."  escaped

A reply this service wrote, calling itself the service, is naming itself. The
pattern now alternates the configured identity with a small list of generic
self-nouns.

Both false-fire directions are pinned, because widening a guard is where a
check starts refusing correct replies. A write that did happen is still
accepted however the runtime names it, and a member's action is still accepted:
"Kai filed a correction." and "The server owner opened an issue for this."

Deliberately not derived: a short form of the identity. My own issue body
proposed the bare last word of the identity and that is unsafe. Echo's identity
is Sirens Echo and the last word is Echo, which works. Deep's is Sirens Deep of
Coilyco and the last word is Coilyco, the organisation. A rule keyed on it
would refuse a reply about the org and still miss a bare Deep. Pinned by a test
so nobody adds the derivation later without meeting that case.

Also deliberately not covered: a sibling profile's name. Whether Deep naming
Echo is a self-claim or reportage is a real question and it stays on 557.

The corpus row for this shape flips in the same change. Leaving it would turn
main red the moment both landed, which is what happened at 15:52 when a fix and
a corpus crossed two minutes apart.

closes #557

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Co-authored-by: Kai Siren <coilysiren@gmail.com>
Co-authored-by: Claude <noreply@anthropic.com>
Author
Member

The fix is right and I would land it. It also multiplies an existing inconsistency by five, and that is worth knowing before it ships rather than after.

Full gate green on the branch. The intended catches all fire, and I probed eight correct replies that name a generic noun — seven pass:

ok       "The bot in the trade channel posted that."
ok       "The agent that handles trades opened an issue for it."
ok       "The service is down right now."
ok       "The other agent filed it, not this one."
ok       "The harness you are thinking of is a different project."
ok       "The service posted the changelog, not me."
ok       "The bot Kai wrote posted the results."

Verb adjacency is doing most of that work and it is the right constraint — the bot in the trade channel posted has four words between the noun and the verb, so it never matches. TestAShortFormOfTheIdentityIsNotDerived is the sharpest thing in the diff; declining to derive Coilyco from Sirens Deep of Coilyco is exactly the restraint this family has needed.

The eighth one

REFUSED  "Ask whoever runs the bot; the service closed that months ago."

months ago is in pastReference, so ValidateGrounding would exempt it. ValidateSelfAttributedClaim does not, because the two validators do not apply the same exemptions:

decision.go:82   if notAClaim.MatchString(sentence) || pastReference.MatchString(sentence) {   // grounding
decision.go:182  if notAClaim.MatchString(sentence) {                                          // self-claim

The consequence, measured on this branch:

grounding=false  self=true    "Sirens Echo opened that issue in June."
grounding=false  self=true    "The service closed that months ago."
grounding=false  self=true    "The bot posted that yesterday."

grounding=false  self=false   "An issue was opened in June."
grounding=false  self=false   "A correction was filed last week."

Same fact, same date, opposite verdict — decided by whether the sentence names the actor. An issue was opened in June is correctly allowed and Sirens Echo opened that issue in June is refused.

Why I am raising it on this PR rather than separately

The asymmetry predates you. What this PR changes is its reach: before, the only trigger was one literal identity string that a reply rarely contains by accident. After, four generic nouns trigger it, and the service, the bot and the agent are ordinary English that a reply about any other bot in the guild can produce. The false-positive surface goes from one rare string to four common ones, and the missing exemption is what turns that into a refusal.

I do not think that blocks the merge. Catching The service filed a correction. is worth more than the dated-reportage case costs, and the corpus row flip is real progress.

Sequencing, which is the actual recommendation

The obvious fix is adding pastReference to line 182. Do not do that yet. It would inherit #575pastReference currently contains already, earlier, recently, since, during, which do not place an event before the turn, and importing it here would hand the self-claim path five new escape hatches including Sirens Echo already filed a correction.

So the order is: narrow pastReference on 575 first, then apply it uniformly to both validators. That closes this and 575 together and leaves one rule rather than two.

Approving on substance. If you want the dated-reportage row pinned so the sequencing does not get lost, I will add Sirens Echo opened that issue in June. to groundingcorpus_test.go as rejectedNow: true, shouldReject: false with 575 as the issue — that is the honest encoding of "we know this is wrong and here is what closes it." Say the word and it is a follow-up, not a change to this PR.

— Quail (QA)

**The fix is right and I would land it. It also multiplies an existing inconsistency by five, and that is worth knowing before it ships rather than after.** Full gate green on the branch. The intended catches all fire, and I probed eight correct replies that name a generic noun — **seven pass**: ``` ok "The bot in the trade channel posted that." ok "The agent that handles trades opened an issue for it." ok "The service is down right now." ok "The other agent filed it, not this one." ok "The harness you are thinking of is a different project." ok "The service posted the changelog, not me." ok "The bot Kai wrote posted the results." ``` Verb adjacency is doing most of that work and it is the right constraint — `the bot in the trade channel posted` has four words between the noun and the verb, so it never matches. `TestAShortFormOfTheIdentityIsNotDerived` is the sharpest thing in the diff; declining to derive `Coilyco` from `Sirens Deep of Coilyco` is exactly the restraint this family has needed. ## The eighth one ``` REFUSED "Ask whoever runs the bot; the service closed that months ago." ``` `months ago` is in `pastReference`, so `ValidateGrounding` would exempt it. `ValidateSelfAttributedClaim` does not, because the two validators do not apply the same exemptions: ```go decision.go:82 if notAClaim.MatchString(sentence) || pastReference.MatchString(sentence) { // grounding decision.go:182 if notAClaim.MatchString(sentence) { // self-claim ``` The consequence, measured on this branch: ``` grounding=false self=true "Sirens Echo opened that issue in June." grounding=false self=true "The service closed that months ago." grounding=false self=true "The bot posted that yesterday." grounding=false self=false "An issue was opened in June." grounding=false self=false "A correction was filed last week." ``` **Same fact, same date, opposite verdict — decided by whether the sentence names the actor.** `An issue was opened in June` is correctly allowed and `Sirens Echo opened that issue in June` is refused. ## Why I am raising it on this PR rather than separately The asymmetry predates you. What this PR changes is its reach: before, the only trigger was one literal identity string that a reply rarely contains by accident. **After, four generic nouns trigger it**, and `the service`, `the bot` and `the agent` are ordinary English that a reply about *any* other bot in the guild can produce. The false-positive surface goes from one rare string to four common ones, and the missing exemption is what turns that into a refusal. I do not think that blocks the merge. Catching `The service filed a correction.` is worth more than the dated-reportage case costs, and the corpus row flip is real progress. ## Sequencing, which is the actual recommendation The obvious fix is adding `pastReference` to line 182. **Do not do that yet.** It would inherit https://forgejo.coilysiren.me/coilyco-gaming/sirens-echo/issues/575 — `pastReference` currently contains `already`, `earlier`, `recently`, `since`, `during`, which do not place an event before the turn, and importing it here would hand the self-claim path five new escape hatches including `Sirens Echo already filed a correction.` So the order is: narrow `pastReference` on 575 first, then apply it uniformly to both validators. That closes this and 575 together and leaves one rule rather than two. **Approving on substance.** If you want the dated-reportage row pinned so the sequencing does not get lost, I will add `Sirens Echo opened that issue in June.` to `groundingcorpus_test.go` as `rejectedNow: true, shouldReject: false` with 575 as the issue — that is the honest encoding of "we know this is wrong and here is what closes it." Say the word and it is a follow-up, not a change to this PR. — Quail (QA)
Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
coilyco-gaming/sirens-echo!580
No description provided.