Repository navigation
Record why a subscription reading was refused, and read the outcome from the last word - #169
Merged
Merged
Conversation
…rom the last word Every reading since the ledger gained the subscription block has been HTTP 403 and nothing more, which cannot say whether the token lacks a scope or the endpoint moved. The refusal body now contributes its error type to the reason and its message to the private reading. The outcome classifier reads the run's final message, where a handoff or a verdict means completed; the first live record had called a run that opened #163 blocked because its transcript discussed an Issue that was. Refs #168. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #168
Achieved outcome
A refused subscription reading now records the API's own error type in its reason (
HTTP 403 permission_error) and keeps the error message in the reading, which reaches the private ledger only; the public warning prints the reason alone, and the token appears in neither. The outcome of a run is classified from its final message, and a handoff or a verdict marker there meanscompletedwhatever else the message mentions; blocker markers are consulted only after that.Tested revision
d8a41a5Changed artifacts
scripts/subscription_usage.py—error_detail()reads at most 64 KB of a refusal body and returnserror.typeand a 200-charactererror.message;unavailable()and the success reading carry anerror_messagefield; the HTTP branch ofread()uses both.scripts/record_usage.py—COMPLETEDmarkers (handoff, verdict, a named pull request);final_text()returns the result text or the last assistant text;classify_outcome()checksCOMPLETEDbeforeBLOCKED;main()classifies fromfinal_text()while mentions and rework still read the whole transcript.scripts/tests/test_subscription_usage.py— refusal with a JSON body, without a JSON body, with no body, and with an overlong message; the token never appears in a reading.scripts/tests/test_record_usage.py— the Implement buildInitialWorld() 17-step initialization (REQ-CONFIG-003) #163 case (handoff plus a blocked mention iscompleted), acceptor verdicts, a blocker heading without a handoff, andfinal_text()in three shapes.Acceptance criteria
permission_erroris recorded with reasonHTTP 403 permission_errorand the message in the reading; a body that is not JSON leaves reasonHTTP 403and no message; the token appears nowhere in either —test_a_refusal_records_the_status_and_the_error_type_and_keeps_the_message,test_a_refusal_without_a_json_body_records_the_status_code_only,test_a_refusal_with_no_body_at_all_is_still_recorded.## AUTHOR handoffand a pull request number classifies ascompletedeven if it also says something is blocked; a final message carrying## AUTHOR blockerclassifies asblocked—test_a_handoff_is_completed_whatever_else_it_mentions,test_a_blocker_heading_without_a_handoff_is_still_blocked.python -m unittest discover -s scripts/testspasses — 275 tests atd8a41a5.Checks
python -m unittest discover -s scripts/testsd8a41a5python scripts/policy_guard.py --base origin/masterdotnet build --configuration Release/dotnet testnpm run typecheck && npm test && npm run buildNot checked
The live 403 body. The first run after merge records it; the reason then names the error type and the ledger holds the message, which is what decides the next step on the subscription figure.
Assumptions and unknowns
{"type": "error", "error": {"type": ..., "message": ...}}. Any other shape degrades to the status code alone.COMPLETEDis a heuristic like the rest of the classifier and is markedheuristicin the record. A run that opens a pull request and then reports a blocker in the same final message is recorded ascompleted; that is the intended reading — a pull request exists.Highest-risk area for review
COMPLETEDinrecord_usage.py: too broad a pattern would hide genuinely blocked runs behind any mention of a pull request. It is anchored to headings for the role markers and requires a number for the pull request forms;OutcomeTestscarries the negative controls.Remaining gate
None mandatory. Narrowing in substance: nothing new is printed except an error type, and no credential enters any workflow.