Skip to content

Commit b24af62

Browse files
author
SqlRush
committed
Accept numeric microcompact string fields
1 parent e6c851b commit b24af62

5 files changed

Lines changed: 41 additions & 7 deletions

File tree

docs/cc-100-roadmap.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -592,7 +592,7 @@ M7 补充:prompt history `LogEntry` 读取现在接受 `sessionID`/`session`/`
592592

593593
本轮补充:remote history response parser 现在也接受 provider-style `choices`/`outputs`/`candidates`/`generations` wrapper 以及顶层 `message`/`content`/`text` envelope,可从 `message.content`、content-block array 和 `content.parts[].text` 中恢复 event page JSON(包括 fenced `json` code block),并保留 pagination 继续驱动 `before_id` 续抓。
594594

595-
本轮补充:microcompact disk cache loader 现在读取 Go 默认、camelCase、snake_case 和相邻实现常见字段别名/包装形态,包括 `result`/`data`/`cache`/`value` wrapper、`content`/`text` summary、`cacheKey`/`key`/`hash` digest、cache-hit 别名、计数字段别名/数字字符串/whole-number JSON number、RFC3339/Unix 秒/Unix 毫秒时间字段,以及 `createdAt` + `ttlSeconds`/`ttlMs`/`expiresIn`/`maxAge` 等相对 TTL 推导,提升 cached microcompact 文件在不同实现/版本间的恢复率;fractional count 仍会被拒绝。
595+
本轮补充:microcompact disk cache loader 现在读取 Go 默认、camelCase、snake_case 和相邻实现常见字段别名/包装形态,包括 `result`/`data`/`cache`/`value` wrapper、`content`/`text` summary、`cacheKey`/`key`/`hash` digest(JSON number 会原样转为字符串)、cache-hit 别名、计数字段别名/数字字符串/whole-number JSON number、RFC3339/Unix 秒/Unix 毫秒时间字段,以及 `createdAt` + `ttlSeconds`/`ttlMs`/`expiresIn`/`maxAge` 等相对 TTL 推导,提升 cached microcompact 文件在不同实现/版本间的恢复率;fractional count 仍会被拒绝。
596596

597597
本轮补充:microcompact disk cache loader 现在也接受 `cacheEntry`/`cache_entry``micro_compact`/`micro_compact_result` wrapper,以及 `summaryMarkdown`/`resultSummary`/`compressedText``cacheDigest`/`digestHash`/`fingerprint``summarizedCount`/`retainedCount``formatVersion``ttlMilliseconds`/`expiresInMilliseconds`/`maxAgeMilliseconds` 等相邻实现字段别名。
598598

docs/claude-code-go-rewrite-plan.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -314,7 +314,7 @@ test/parity/ # golden tests against TS/official behavior
314314
- 本轮补充:compact runner 的 summary 响应现在也接受 provider-style `choices`/`outputs`/`candidates`/`generations` wrapper,可在构建 compact plan 前从 `message.content`、content-block array、`content.parts[].text` 和 fenced `json` code block 中恢复 visible summary text。
315315
- 本轮补充:remote history `SDKEvent` type 现在会把 provider-style aliases 归一化为现有 canonical 事件类型,包括 `assistant_message`/`assistant_delta``userMessage`/`humanMessage``system-event``result_event`/`finalResult`/`response.completed``errorEvent`/`failureEvent``status_update`/`statusMessage`/`progress`,single-object page 与 transcript materialization 不再因事件类型拼写相邻而丢消息。
316316
- 本轮补充:conversation runner 会在用户消息入队后基于 compact window 计算 token warning state,并在达到 warning/error/auto-compact/blocking 阈值时发出 `token_warning` event;warning state 接入 blocking-limit env override,auto-compact 判断接入既有 `CLAUDE_AUTOCOMPACT_PCT_OVERRIDE`,避免 warning 和 compact 阈值来源分叉。
317-
- 本轮补充:microcompact disk cache loader 现在读取 Go 默认、camelCase 和 snake_case 字段别名,并容忍计数字段的数字字符串、whole-number JSON number 和 whole-number 数字字符串,同时继续拒绝 fractional count,以及 RFC3339、Unix 秒、Unix 毫秒时间字段,提升 cached microcompact 文件在不同实现/版本间的恢复率。
317+
- 本轮补充:microcompact disk cache loader 现在读取 Go 默认、camelCase 和 snake_case 字段别名,string-like cache ID/version 字段可把 JSON number 原样保留成字符串,并容忍计数字段的数字字符串、whole-number JSON number 和 whole-number 数字字符串,同时继续拒绝 fractional count,以及 RFC3339、Unix 秒、Unix 毫秒时间字段,提升 cached microcompact 文件在不同实现/版本间的恢复率。
318318
- 本轮补充:microcompact disk cache loader 现在接受 `cacheEntry`/`cache_entry``micro_compact`/`micro_compact_result` wrapper,以及 `summaryMarkdown`/`resultSummary`/`compressedText``cacheDigest`/`digestHash`/`fingerprint``summarizedCount`/`retainedCount``formatVersion``ttlMilliseconds`/`expiresInMilliseconds`/`maxAgeMilliseconds` 等相邻实现字段别名。
319319
- 本轮补充:microcompact disk cache loader 继续接受相邻 timestamp/expiry aliases,包括 `cachedAt``cacheCreatedAt``storedAt``generatedAt``updatedAt``timestamp``expiry``expirationTime``validUntil``notAfter`,以及 `timeToLiveSeconds``validForMs` 等相对 TTL 字段。
320320
- 本轮补充:microcompact disk cache loader 的相对 TTL 现在也接受分钟、小时和天级别名,例如 `ttlMinutes``expiresInHours``validForDays` 及 snake/camel 相邻形式,恢复 cached microcompact 过期时间时不再局限于秒/毫秒。

docs/first-second-parity-audit.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -123,7 +123,7 @@ M6 progress now includes:
123123

124124
- `internal/memory`: recursive `.md` memory scanning, frontmatter parsing, newest-first capped manifests, root-to-leaf `CLAUDE.md` discovery/loading, and team-memory secret detection.
125125
- `internal/compact`: effective context window calculations, auto-compact thresholds, token warning state, compact summary prompt construction, compact API runner, compact boundary/summary plan generation, auto-compact window env override application, microcompact/cache primitives, persistent cached microcompact storage, structural/rich-content microcompact cache digests, cache version/TTL/prune handling for disk and in-memory caches, memory-cache write-through to disk, atomic cache writes, corrupt-cache fail-open behavior, and filename/digest mismatch pruning.
126-
- `internal/compact`: microcompact disk cache loading now accepts Go default, camelCase, snake_case, and adjacent cache field aliases/wrappers such as `result`/`data`/`cache`/`value` objects, `content`/`text` summary, `cacheKey`/`key`/`hash` digest, cache-hit aliases, numeric strings and whole-number JSON/string numbers for count fields, RFC3339/Unix-seconds/Unix-millis time fields, and relative TTL fields such as `ttlSeconds`, `ttlMs`, `expiresIn`, and `maxAge`, so cached microcompact records from adjacent implementations remain usable.
126+
- `internal/compact`: microcompact disk cache loading now accepts Go default, camelCase, snake_case, and adjacent cache field aliases/wrappers such as `result`/`data`/`cache`/`value` objects, `content`/`text` summary, `cacheKey`/`key`/`hash` digest including JSON-number string-like fields, cache-hit aliases, numeric strings and whole-number JSON/string numbers for count fields, RFC3339/Unix-seconds/Unix-millis time fields, and relative TTL fields such as `ttlSeconds`, `ttlMs`, `expiresIn`, and `maxAge`, so cached microcompact records from adjacent implementations remain usable.
127127
- `internal/compact`: microcompact disk cache loading also accepts adjacent cache-entry wrappers and aliases such as `cacheEntry`/`cache_entry`, `micro_compact`/`micro_compact_result`, `summaryMarkdown`/`resultSummary`/`compressedText`, `cacheDigest`/`digestHash`/`fingerprint`, `summarizedCount`/`retainedCount`, `formatVersion`, and millisecond TTL aliases such as `ttlMilliseconds`, `expiresInMilliseconds`, and `maxAgeMilliseconds`.
128128
- `internal/compact`: microcompact disk cache loading now also accepts adjacent timestamp aliases such as `cachedAt`, `cacheCreatedAt`, `storedAt`, `generatedAt`, `updatedAt`, `timestamp`, `expiry`, `expirationTime`, `validUntil`, `notAfter`, and relative TTL aliases such as `timeToLiveSeconds` and `validForMs`.
129129
- `internal/compact`: microcompact disk cache relative TTL loading now also accepts minute, hour, and day aliases such as `ttlMinutes`, `expiresInHours`, and `validForDays`, including adjacent snake/camel forms.
@@ -552,6 +552,7 @@ M7 progress now includes:
552552
- `internal/compact`: microcompact disk cache loading now accepts broader summary-like direct and provider aliases including `body`, `markdown`, `description`/`details`, `finalSummary`, `summaryContent`, `plainText`/`displayText`, `answerText`, `refusal`, `resultText`, `completionText`, `responseText`, and `messageText`; provider summary recovery also follows wrapper-only `value`/`payload`/`data` chains without failing on non-summary metadata, preserving visible summaries through nested cache entries, JSON:API/resource envelopes, and provider-style response wrappers.
553553
- `internal/compact`: microcompact provider and cache summary extraction now unwraps inline fenced JSON payloads where the fence language and JSON object are on the same line, so SDK/model outputs no longer preserve the whole code fence as visible summary text.
554554
- `internal/compact`: microcompact count field loading now accepts whole-number JSON numbers and whole-number numeric strings, while fractional count values still fail validation.
555+
- `internal/compact`: microcompact string-like cache fields such as digest/cache key and version now accept JSON numbers by preserving their original numeric text as the stored string value.
555556

556557
Still missing for full M6/M7 parity:
557558

internal/compact/compact_test.go

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -343,6 +343,33 @@ func TestLoadMicroResultAcceptsWholeNumberCountFields(t *testing.T) {
343343
}
344344
}
345345

346+
func TestLoadMicroResultAcceptsNumericStringLikeFields(t *testing.T) {
347+
cacheDir := filepath.Join(t.TempDir(), "micro")
348+
if err := os.MkdirAll(cacheDir, 0o755); err != nil {
349+
t.Fatal(err)
350+
}
351+
digest := "12345"
352+
data := `{
353+
"summary": "numeric string-like fields summary",
354+
"cacheKey": 12345,
355+
"cacheVersion": 1,
356+
"createdAt": 100
357+
}`
358+
if err := os.WriteFile(microResultPath(cacheDir, digest), []byte(data), 0o600); err != nil {
359+
t.Fatal(err)
360+
}
361+
result, ok, err := LoadMicroResult(cacheDir, digest)
362+
if err != nil {
363+
t.Fatal(err)
364+
}
365+
if !ok {
366+
t.Fatal("expected numeric string-like cache result")
367+
}
368+
if result.Digest != digest || result.Version != "1" {
369+
t.Fatalf("result = %#v", result)
370+
}
371+
}
372+
346373
func TestLoadMicroResultRejectsFractionalCountFields(t *testing.T) {
347374
cacheDir := filepath.Join(t.TempDir(), "micro")
348375
if err := os.MkdirAll(cacheDir, 0o755); err != nil {

internal/compact/micro.go

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -561,15 +561,21 @@ func PruneMicroCache(dir string, options MicroPruneOptions) (int, error) {
561561
}
562562

563563
func microStringJSONField(fields map[string]json.RawMessage, names ...string) (string, bool, error) {
564-
raw, _, ok := microRawJSONField(fields, names...)
564+
raw, name, ok := microRawJSONField(fields, names...)
565565
if !ok || bytes.Equal(bytes.TrimSpace(raw), []byte("null")) {
566566
return "", false, nil
567567
}
568568
var value string
569-
if err := json.Unmarshal(raw, &value); err != nil {
570-
return "", false, err
569+
if err := json.Unmarshal(raw, &value); err == nil {
570+
return value, true, nil
571571
}
572-
return value, true, nil
572+
decoder := json.NewDecoder(bytes.NewReader(raw))
573+
decoder.UseNumber()
574+
var number json.Number
575+
if err := decoder.Decode(&number); err == nil {
576+
return number.String(), true, nil
577+
}
578+
return "", false, fmt.Errorf("invalid string field %q", name)
573579
}
574580

575581
func microSummaryJSONField(fields map[string]json.RawMessage, names ...string) (string, bool, error) {

0 commit comments

Comments
 (0)