Commit Graph

19 Commits

Author SHA1 Message Date
Bo c48b561b70 chore(lint): enable errorlint + unused, burn backlog (age-a-plus-report-card-ieyp2.8) 2026-07-19 17:06:04 -04:00
boshu 61b3f5286a fix(membrane): ao yield tokens parses Codex transcripts too (cross-family REFUTE)
Round-2 cross-family review (Codex) caught that the command advertised
"Claude Code or Codex" transcripts but deriveTranscriptTokens only summed
message.usage (the Claude shape). A real Codex transcript returned 0 0 —
and Codex is the default runtime on this machine, so reconcile would have
silently recorded zero spend for Codex-produced work.

Codex reports a CUMULATIVE total_token_usage on each token_count event
(input_tokens already includes cache; total = input + output), so the LAST
one is the session total — NOT a per-message sum.

- parser: capture token_count's total_token_usage into the last-wins
  ParseResult.FinalUsage (folded in processLine, never added to the summed
  message list).
- ParseResult.TokenTotals() picks the right aggregation per runtime: Codex
  cumulative FinalUsage, else Claude per-message SumUsage (dedup-by-id).
- deriveTranscriptTokens + forge_tier1 use TokenTotals(); the malformed
  guard now treats a Codex transcript with FinalUsage (few messages) as parseable.

Verified on a real Codex session (32397/40 == ground-truth last total) and
the real Claude fixture (10946330/228 unchanged). Tests use real Codex +
Claude persisted shapes. Full build/vet/test green.

Refs: age-membrane-memory-arch-tz2s.3.2
2026-06-20 14:42:13 -04:00
boshu df37c81b49 fix(membrane): dedup usage by response id + fail-open hardening (cross-family REFUTE)
A fresh-context cross-family review (Codex) REFUTED the E4 producer-truth
diff and caught three real defects self-review missed — the membrane
working as designed:

1. OVERCOUNT (severe): real Claude Code transcripts write one model
   response as several rows (thinking/text/tool_use) that ALL repeat the
   same usage block under one message.id. Summing every row inflated
   tokens 2-3x (real fixture: 26781956 vs correct 10946330). Fix: capture
   message.id (fallback requestId) in the parser; new types.SumUsage dedups
   by response id; forge_tier1 + deriveTranscriptTokens both use it.
2. reconcile HOLD/REFUTED path ignored AO_YIELD_TRANSCRIPT -> rejected
   spend silently recorded 0 (broke L/R loss accounting). Fix: shared
   derive_yield_tokens() helper used by BOTH the accepted and rejected
   emit paths.
3. malformed transcript returned success 0 0 (SkipMalformed) instead of a
   visible fail-open. Fix: deriveTranscriptTokens errors when content
   yields zero messages, so reconcile keeps the honest default.

Plus: dropped misleading omitempty on value-type StreamEvent.Usage;
real-fixture regression test locking the deduped total (10946330/228);
dedup + malformed + message.id capture tests using real persisted shapes
(the synthetic one-row fixtures hid the overcount — go.md fixture-fidelity).

Full build/vet/test green; reconcile bash + shellcheck clean.

Refs: age-membrane-memory-arch-tz2s.3.1, age-membrane-memory-arch-tz2s.3.2
2026-06-20 14:31:54 -04:00
boshu 4dc8f5ad0f feat(membrane): real per-bead token capture — kill the hardcoded 0 (age-membrane-memory-arch-tz2s.3.1)
Producer truth, E4.1. Tokens were silently dropped to 0 at every
observation point, making the medallion's bronze tier lossy.

- stream_events.go: parse the result event's usage block (StreamUsage:
  input/output + cache-creation/cache-read) with TotalInputTokens/
  TotalTokens helpers.
- stream_parser.go: wire usage into PhaseProgress.Tokens (live status
  now shows real tokens, not 0).
- types.TranscriptMessage: carry a per-message *TokenUsage.
- parser: capture the assistant message usage block from transcripts.
- forge_tier1.deriveSessionMeta: sum real TokensIn/TokensOut across
  messages (killed the 'not tracked in v1' hardcoded 0) — the bronze
  capture E4.2 (bronze->silver) will emit.

TDD: token tests added at stream, parser, and bronze-ingest layers; all
red before, green after. Full cmd/ao + parser + types + llm green.

Refs: age-membrane-memory-arch-tz2s.3.1
2026-06-20 14:01:44 -04:00
Claude 8dca64ffb1 perf(parser): ASCII fast-path for truncateForError
When the input byte length already fits within maxLen, the rune count
cannot exceed it either (bytes >= runes). Short-circuit before the
[]rune allocation. Adds multibyte test cases proving both the fast-path
(bytes==runes), the rune-count fit case (bytes>maxLen, runes<=maxLen),
and the truncation case.

Closes finding: ag-yht / Add ASCII fast-path comment to truncate()
2026-04-17 02:45:14 +00:00
Boden Fuller 3ccc2a3494 test: refactor codex parser edge cases 2026-04-13 21:01:45 -04:00
Boshu2 5cf8f7b22f test: restore parser coverage ratchet 2026-03-22 10:06:37 -04:00
Boshu2 e5b4936724 fix: align ao search with forged session history 2026-03-22 09:56:37 -04:00
Boshu2 e442a414a8 fix(tests): push internal packages to 100% coverage with error-path tests
Add comprehensive error-path tests across all internal packages and cmd/ao.
14 packages now at 100% statement coverage; 4 remaining packages at
98-99% ceiling (provably unreachable defensive code).

Key changes:
- Add injectable test hooks (getwdFunc, marshalJSON, openFileFunc, etc.)
  to cover OS-level error branches unreachable on macOS
- Cover deferred f.Close() errors, json.Marshal failures on typed structs,
  filepath.Walk errors, and crypto/rand.Read fallbacks
- Add Linux-only build-constrained tests for filepath.Abs double-failure
- Fix flaky TestMergeWorktree_UntrackedFileDirtyRepo (100ms -> 5s timeout)
- Split ratchet_extra_test.go into per-source test files per convention
- Remove duplicate test declarations from prior agent merges
2026-03-11 12:33:52 -04:00
Boden Fuller 5c25849dc8 fix(goals/parser): harden edge cases — paired backtick strip + rune-aware truncation
- markdown.go: replace strings.Trim(s, "`") with paired-backtick check in
  parseGateRow; asymmetric/lone backticks are now preserved instead of
  being silently corrupted or data-lost
- parser.go: truncate() now slices at rune boundaries ([]rune) to avoid
  splitting multi-byte UTF-8 chars (CJK, emoji) and producing \uFFFD
- Tests: +3 adversarial cases (asymmetric, single-backtick, matched-pair)
         +1 Unicode truncation case (CJK at rune boundary)

Closes: ag-yht.1, ag-yht.2
2026-02-27 23:22:19 -05:00
Boden Fuller 4380e85658 evolve: extract helpers, modernize slices, add slow-test CI warning
- Extract parseFrontmatterBlock/extractPatternNameAndDescription (inject_patterns)
- Extract runCommitLanding/runSyncPushLanding (supervisor landing)
- Extract recordEventOrWarn/bulkApproveEntry (pool)
- Replace sort.Slice with slices.SortFunc across cmd/ao and pool
- Add slow test package duration warning to CI validate workflow
- Add evolve-coverage-delta.sh, evolve-file-complexity.sh, pre-commit-gate.sh
- Modernize test helpers with t.Helper() and slices patterns
2026-02-22 09:14:11 -05:00
Boden Fuller 456dbb17dc modernize Go to idiomatic 1.23: slices, cmp.Or, range, CutPrefix
Apply version-aware modern Go patterns across cli/cmd/ao/ and cli/internal/:

- sort.Slice → slices.SortFunc with .Compare() (19 in cmd/ao, 15 in internal)
- C-style for loops → for i := range n / for range n (18 conversions)
- default-value chains → cmp.Or (19 conversions across 11 files)
- HasPrefix+TrimPrefix → strings.CutPrefix (2 in internal)
- strings.Index+slice → strings.Cut (1 in internal)
- sort.Strings → slices.Sort (3 in internal)

All 18 packages pass with -race. Sourced from JetBrains go-modern-guidelines RPI.
2026-02-22 07:57:49 -05:00
Boden Fuller f009fde2d6 evolve: cycle 113 -- use errors.Is/errors.As instead of direct error comparison
Replace == and type assertions on errors with errors.Is() and
errors.As() to correctly handle wrapped errors. Fixes production
code in goals/measure.go and rpi/worktree.go, and test code in
pool, ratchet, parser, and types test files. Resolves errorlint.
2026-02-22 05:49:23 -05:00
Boden Fuller 7452e87262 evolve: cycle 104 -- add classifyBlock edge case tests, parser 98.9% -> 99.4%
Test text block with non-string "text" field, unknown block type, and
missing type field. Covers previously untested classifyBlock branches.
2026-02-22 05:00:58 -05:00
Boden Fuller 8bddb92333 evolve: cycle 83 -- modernize interface{} to any across 16 files
Replace all 135 occurrences of interface{} with the any alias
introduced in Go 1.18. The module uses Go 1.23 so this is safe.
Zero behavior change -- any is a built-in alias for interface{}.
2026-02-22 04:07:27 -05:00
Boden Fuller f6fbc17335 evolve: cycle 39 -- add parser benchmarks for Parse, Extract, ExtractBest 2026-02-22 02:23:31 -05:00
Boden Fuller 29ee2495d4 evolve: cycle 35 -- boost parser 97.6%->99.4%
Add three targeted tests:
- TestExtractBest_HigherScoreLaterInSlice: exercises the r.Score > best.Score
  branch by using custom patterns with divergent MinScores
- TestParse_ScannerError: feeds 2MB line to trigger scanner buffer overflow
- TestParseChannel_ScannerError: same for streaming channel parser

Remaining gap (ParseFile f.Close error) is an OS-level error path that
cannot be reliably triggered in unit tests.
2026-02-22 02:05:58 -05:00
Boden Fuller b66edce18c evolve: cycle 27 -- boost 4 packages: formatter 98.7%, parser 98.2%, search 95.9%, storage 96.0%
formatter (97.3% -> 98.7%):
- TestTable_TruncateMaxLessThanThree: truncate with max <= 3 raw slice
- TestTable_TruncateExactlyAtMax: boundary test at max length

parser (97.0% -> 98.2%):
- TestParser_ParseChannel_EmptyLines: empty line skip path

search (95.1% -> 95.9%):
- TestLoadIndex_ScannerError: line exceeding 1MB scanner buffer
- TestSaveIndex_ReadOnlySubDir: MkdirAll error
- TestSaveIndex_TargetIsDirectory: os.Create fails on directory

storage (95.4% -> 96.0%):
- TestAppendJSONL_MarshalError: unmarshalable channel value
- TestAppendJSONL_WriteError: target path is directory
2026-02-22 01:15:49 -05:00
Boden Fuller 37d4b5b2ae Merge branch 'codex/rpi-supervisor-cli' into main 2026-02-21 19:41:50 -05:00