Repository navigation
Conversation
A box was auto-named "Dinner plans for two in the city tonight?" from a first prompt that asked to find and wake another box. The title call succeeded, so harness logged nothing: no record holds the system prompt that the backend sent or the raw answer of the model, and the cause could not be found. 178 reruns of the same call with another box's prompt all gave a correct title. Design: ask is the one path of every model call with no tools (title, compaction summary, goal evaluation, plugin model call) on every backend, so it owns one oneshot_call INFO line, beside turn_metrics. The system text is what the backend reports through Request.Sent (Claude Code sends the instructions plus the append_system_prompt entries), else the request instructions (a model API backend sends those alone). serve already writes JSON on stderr, which the boxes log collector ships to BetterStack. turn now imports toolresult for Mask, the masker of turn errors and child reports; toolresult imports only protocol, so the turn-seam depguard list and the spec import sentence add it. Semantic change: one new INFO line per one-shot call, after its last attempt, also on failure: session_id, turn_id, model, duration_ms, input_tokens, output_tokens, system_bytes, system, messages_count, messages (role and text), answer, and error on failure. Each text is masked with toolresult.Mask, so a provider error that echoes an Authorization header logs "***", then capped: system 32 KiB, messages 32 KiB and 64 messages, answer 8 KiB, error 1 KiB, about 73 KiB of text per line, under the 900 KB batch of the boxes log collector. The line holds prompt text. No event, request, or result changes. Verification: TestContractOneShotCallLineOfATitleCall fails without the change (no oneshot_call line) and passes with it, on a model API title model and on claude-code over fakeclaude. It checks that the Claude Code line holds the append_system_prompt entry and the model API line does not. A failure row checks that a bearer token in the provider error is masked; it was red before the mask. go test -race ./... passes.
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.
Problem
A boxes box was auto-named "Dinner plans for two in the city tonight?" from a first prompt that asked to find and wake another box. The title call (
claude-code/haiku) succeeded, so harness logged nothing. No record holds the system prompt that the backend sent or the raw answer of the model, so the cause could not be found. 178 reruns of the same call, with the same request shape and another box's prompt, all gave a correct title.Design
askininternal/turn/compact.gois the one path of every model call with no tools on every backend: the title call, a compaction summary, a goal evaluation, and a plugin model call. It now writes oneoneshot_callINFO line besideturn_metrics(docs/architecture.md, theturn_metricsparagraph of the turn section). The system text is what the backend reports throughRequest.Sent. Claude Code reports the instructions plus theappend_system_promptentries; a model API backend reports none, so the line uses the request instructions, which is what it sends.Backend.Runis synchronous, soSentfires before the line is written.servealready writes JSON logs on stderr, and the boxes log collector ships them to BetterStack, so boxes needs only a pin bump.turnnow importstoolresultforMask, the masker of turn errors and child reports.toolresultimports onlyprotocol. Theturn-seamdepguard list and the spec's import sentence (docs/architecture.md, the frozen-graph paragraph) add it. Andy approved this dependency.Semantic change
oneshot_callper one-shot call, after its last attempt, also on failure.session_id,turn_id,model,duration_ms,input_tokens,output_tokens,system_bytes,system,messages_count,messages(role,text),answer(raw, before the caller cleans it), anderroron failure.toolresult.Mask, then capped: system 32 KiB, messages 32 KiB in total and 64 messages, answer 8 KiB, error 1 KiB. That is about 73 KiB of text per line, under the 900 KB batch of the boxes log collector even at worst-case JSON escaping.Verification
TestContractOneShotCallLineOfATitleCall(new,e2e/) has three rows: a model API title model, a model API title call that fails, and claude-code over fakeclaude. It failed before the change (nooneshot_callline) and passes after it.append_system_promptentry; the model API row checks that it does not, because that backend does not send it.Authorization: Bearer sk-live-…in the provider error and checks that the logged error holds no token. It was red before the mask.go test -race ./...passes locally.golangci-lintis not installed in this box, so CI runs depguard.Review
Cross-provider review by
codex/gpt-6.1-sol(appliedAGENTS.md,architecture-review,harness-architecture-review,go-guide):toolresult.Mask, and a contract row covers it.turnmay not importtoolresult: fixed by allowing the dependency in.golangci.ymland the spec, as Andy decided.Request.Sentis sequenced before the line, that every caller passesLimits.Log, and that ACP still logs to stderr only.