feat(telemetry): a refused reply records the reason and the rule that refused #801
No reviewers
Labels
No labels
move-to-repo
coilyco-bridge-deploy
move-to-repo
coilyco-flight-deck-agent-compose
move-to-repo
coilyco-gaming-eco-app
move-to-repo
coilysiren-inbox
move-to-repo
unknown
🔒⚠️📦⚠️🔒 SANDBOXED 🔒⚠️📦⚠️🔒
autonomy
async-consult
autonomy
epic
autonomy
headless
autonomy
live-collab
c#
priority
P0
priority
P1
priority
P2
priority
P3
priority
P4
role/ai
role/creator
role/design
role/director
role/engineer
role/exec
role/human
role/ops
role/qa
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set
Reference
coilyco-gaming/sirens-echo!801
Loading…
Reference in a new issue
No description provided.
Delete branch "aos/claude/wy58-refusal-reason"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Closes #795.
What changed
The reason reaches the span and the log.
response.validatecarriesresponse.check.reason, andresponse.check.refusedlogs the same sentence underrefused, matching whatmodel.response.repairalready does on the completion path. The four diagnosis steps on #794 collapse to reading the span.response.checknames the rule, not the family.groundingcovered four independent rules, so the value narrowed nothing and a refusal rate over it could not separate an invented channel from a claimed action. The set grows by four:grounding.invented_channel,grounding.claimed_action,grounding.tracker_action,grounding.continuing_work. Span names are unchanged.The invented channel is bounded.
channelPatternalready constrains it to a#token, and it is now truncated at 64 runes before it enters the sentence.One deliberate departure from the proposal
The issue proposes passing
errintoMarkSpanErrorso the spanstatus_messagecarries the reason. That collides with a documented hard boundary:docs/sirens-echo-exceptions.mdstates the recording API accepts only the catalog code and that upstream error text cannot enter the exception event, andexceptions_test.gopins it.So the reason rides an ordinary span attribute beside the exception fields rather than through them. Same readable outcome, and
exception.type,exception.message,error.stage,error.outcome, and the span status keep their fixed cataloged wording. A new rule needs no catalog entry and no reviewed increase to the exception cardinality bound.TestARefusalReasonStaysOutOfTheExceptionFieldspins the separation.The reply-fragment crossing, stated rather than discovered
docs/sirens-echo-observability.mdsaid replies are never logged, absolutely. The invented channel token is a reply fragment, so that sentence now names the exception and links the reasoning instead of quietly becoming false. The token is the diagnosis: it separates a channel missing from supplied context, a prompt problem, from a pure hallucination. It names no real channel and carries no member content.Acceptance
response.check.reason.response.checkdistinguishes the rule, not only the family - four grounding values.Verification
ward gategreen: build, policy-check, vet, test, test-skips, pre-commit. Four new tests inturnstages_test.go, each run and confirmed passing individually.Not done
No FEATURES.md entry. This refines diagnostics on an existing capability rather than adding or reshaping one, and neither
docs/FEATURES.mdnordocs/features-observability.mdenumerates the check set.🤖 Generated with Claude Code