Skip to content

feat: measured output format changes and harness event classification (ADR-007, ADR-008) - #9

Merged
Mapleeeeeeeeeee merged 6 commits into
mainfrom
feat/adr-007-format-changes
Sep 1, 2026
Merged

feat: measured output format changes and harness event classification (ADR-007, ADR-008)#9
Mapleeeeeeeeeee merged 6 commits into
mainfrom
feat/adr-007-format-changes

Conversation

@Mapleeeeeeeeeee

Copy link
Copy Markdown
Owner

為什麼

用過 cc-session 的 Claude 會把工具的成功摘錄當成執行結果讀、無法驗證 Bash 實際跑了什麼、分不出哪幾行是人打的。這兩份 ADR 記錄的改動都先量過再做。

ADR-007:五項格式改動(docs/adr-007-format-changes-measured.md

  1. 成功結果的摘錄跳過雜訊行(echo 的區段標題、進度前綴、版本橫幅、ANSI),23% 的 Bash 行拿到更好的摘錄,0 行變差
  2. Bash 摘要帶 | <程式名 子命令>,先剝掉 cd、環境變數、shell 關鍵字再取動詞,1,258 個 Bash 呼叫全部抽到
  3. 成功不再標 -> ok,只標 FAILED
  4. 時間戳改 [HH:MM:SS],日期在換日時獨立一行 --- YYYY-MM-DD ---,比原本多秒與年份
  5. inherit 分頁 20,000 → 28,000 bytes(Bash 工具 stdout 門檻二分實測為 30,000),44 頁 → 32 頁

ADR-008:harness 事件漂移(docs/adr-008-harness-event-drift.md

  1. noiseTypes 補 8 個 CLI 後來加的 entry type(60 天內 597 KB 原本在 stats 裡隱形)
  2. 6 種 harness 注入的 user 訊息在 parser 層分類,各有 compact 形式
  3. 新增 harness: 角色標籤(context 格式為 H:),讀的人分得出哪幾行不是人打的
  4. teammate 偵測改多重標記;原主判斷字串 60 天內命中 0/133
  5. UserMessage.CountsAsTurn() 把 turn 判定從字元統計的 continue 拆出來,政策以 transcript 校準(8 個 session 誤差 70 → 29),修正 teammate 密集 session 的 K 高估
  6. skill 注入改走 sourceToolUseID 結構連結,沒有 base-directory 行的 bundled skill 不再全文渲染

驗證

  • gofmt / go vet / go test ./... 全綠,新增 success_excerpt_testcommand_verb_testtimestamp_testturn_testharness_classify_testharness_role_testskill_injection_link_test
  • count_tokens 實測 19 個 session:注入大小 −0.37%,K 在格式改動前後逐一相同;warm cache 中位 break-even 從 turn 2 提前到 turn 1(來自分頁)
  • ADR-008 修正後 K:edf31315 7.6 → 4.3、544c7a3d 8.6 → 5.5、其餘 ±1 以內
  • 真實 session b11858cf:46 則 user: → 36 則 user: + 10 則 harness:artifact-design skill 內文從全文渲染變成 [skill: artifact-design]

沒有包含

  • <agent-message> teammate 變體(80/1,112)與 teammate 偵測是否改成只認標籤,留待下次決定
  • search 子命令,等自己的 ADR

🤖 Generated with Claude Code

https://claude.ai/code/session_01TcvWErnKnuADJsomnZfwFr

Mapleeeeeeeeeee and others added 6 commits September 2, 2026 04:04
The success path took the first non-empty line with no filtering, so a
script's own "--- HEAD ---" was reported as the state of a working tree and
a test runner's "RUN v4.0.18" as the result of a test run. Failures already
skipped known-noise shapes; this gives success its own set (echoed section
headings, progress lines, version banners) and strips ANSI escapes on both
paths.

Section headings are recognized only when the same rule closes the line, so
a diff's "--- a/file.go" survives as an excerpt. The success-only shapes are
deliberately not applied to failures: a banner-shaped line can be the error
itself when the call failed.

Measured on a 1,258-Bash-call session: 292 lines (23%) now carry a better
excerpt, none lost one, and ANSI escapes drop from 95 lines to zero.

A prose usage banner (gh's "Work seamlessly with GitHub from the command
line.") has no shape to key on and is not covered; a test pins that limit.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01M8xGh8fwz3YjLhFTMYqvXB
#3)

Two changes that pay for each other. The Bash summary printed only the
description Claude wrote for itself, so 78% of a session's tool calls could
not be checked against what actually ran. And "-> ok" annotated 1,550 of
1,604 calls with the state a reader already assumes.

The verb is not a prefix of the command. Real commands open with
`cd <absolute path> &&`, an env assignment, a shell keyword, or an echoed
heading, so a 20-character prefix reads "cd /Users/maple/Desk" and names
nothing; a 60-character one costs +9.8% tokens for the same reason. Stepping
over those to the first real program name reaches one on 1,258 of 1,258 Bash
calls in the measured session at +2.0%, which the -2.0% from the dropped
marker cancels. Measured together over 5 sessions: -0.0%.

Success now renders its excerpt or diff stat alone, still introduced by "->"
so the call stays separable from its result. FAILED keeps its marker, and
with it formatRetryCollapse's insertion point for "×N".

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01M8xGh8fwz3YjLhFTMYqvXB
"[08-06 03:06]" repeated a date identical on every message of a day and had
no year at all, so a read output gave no way to place a session in time
(context could fall back to its session header; read has none).

The date moves to a "--- 2026-08-06 ---" marker emitted when it rolls over,
and the space it freed buys second precision. Measured over 5 sessions this
is -0.4% tokens while carrying strictly more than the old format: seconds and
the year. Sessions really do span days in the sample (2 and 3), but sparsely:
the marker fired twice across a 1,808-event session.

An unparseable timestamp renders a placeholder and leaves the day state
alone, so a malformed event cannot invent a date boundary.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01M8xGh8fwz3YjLhFTMYqvXB
The 20,000 limit existed to keep a page inside the harness's Bash stdout cap,
but that cap was never measured. Binary search on 2026-08-29 put it at 30,000
characters: 30,000 came back inline, 31,000 was persisted to a file with a
2KB preview.

28,000 leaves headroom for the page marker and footer; the largest real page
now renders at 28,073 bytes. A 871KB session drops from 44 pages to 32, so
inheriting it costs 12 fewer Bash round-trips, each of which was a separate
API request paying cache read on the whole prefix.

The constant is exported so the boundary tests derive their cases from it
instead of restating 20,000, which had already stopped describing the real
boundary in three of them.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01M8xGh8fwz3YjLhFTMYqvXB
The set lands at +0.3% tokens rather than the predicted -0.4%. The gap is
decision 1 doing its job: skipping a noise line reaches a longer, more
informative one. Also records the two rules the implementation tightened
(symmetric section headings only, indented code not skipped) and the shell
control keywords the verb extraction had to step over.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01M8xGh8fwz3YjLhFTMYqvXB
…-008)

Reader now recognizes eight entry types the CLI added after the noise
whitelist was written, classifies six harness-injected user messages in
the parser layer and renders them under a `harness:` role label, detects
teammate messages by a set of markers instead of a disclaimer string
that no longer matches, and resolves skill-body injections through the
sourceToolUseID link to the Skill tool_use so bundled skills without a
base-directory line compact to `[skill: name]`.

Turn counting moves out of the character-accounting loop into
UserMessage.CountsAsTurn(), calibrated against transcripts: teammate
messages, task notifications, and compaction summaries start a round
and count; interrupts and agents-stopped notices do not.

Docs: SKILL.md and README record the 28K page size and the harness role.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TcvWErnKnuADJsomnZfwFr
@Mapleeeeeeeeeee
Mapleeeeeeeeeee force-pushed the feat/adr-007-format-changes branch from fe92038 to 3e80212 Compare September 1, 2026 20:05
@Mapleeeeeeeeeee
Mapleeeeeeeeeee merged commit 7d98d83 into main Sep 1, 2026
3 checks passed
@Mapleeeeeeeeeee
Mapleeeeeeeeeee deleted the feat/adr-007-format-changes branch September 1, 2026 20:12
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.

1 participant