Repository navigation
Conversation
MisonL
force-pushed
the
feat/workbuddy-support
branch
from
October 13, 2026 03:50
294226c to
4a04c10
Compare
This was referenced Oct 13, 2026
MisonL
force-pushed
the
feat/workbuddy-support
branch
3 times, most recently
from
October 13, 2026 16:56
556a837 to
c05df4a
Compare
Add "workbuddy" to the Source union and SOURCES, wire it through both exhaustive sourceKey() switches, SyncResult/SessionSyncResult buckets, DiscoverOpts, resolveDefaultPaths, cli isSource/SOURCE_LABELS/summaries, status classifySource, enrich sourceOptions, the accounting-queue source allowlist, and usesJsonlOffsetResume. Update the source-count test expectations (9 -> 10 active sources, 18 -> 19 path properties). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Parse ~/.workbuddy/projects/<slug>/<sessionId>.jsonl: one delta per usage-bearing record, deduped by providerData.messageId, with inclusive prompt/completion counters split into pew's disjoint TokenDelta buckets. Two traps handled, both verified against real installs: the cache-read count lives in prompt_tokens_details.cached_tokens / prompt_cache_hit_tokens (cache_read_input_tokens and top-level cached_tokens are stale zeros), and prompt_tokens / completion_tokens already include the cache read and the reasoning tokens, so both are subtracted before bucketing. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Discover ~/.workbuddy/projects/<slug>/<sessionId>.jsonl depth-2 only, so subagent transcripts and tool outputs nested deeper are excluded by design. Register a byte-offset token driver (per-parse messageId dedup, no cross-sync id ring — WorkBuddy never rewrites a request's usage) and a full-scan session driver using the mtime+size dual check. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The chart palette was capped at 15 colors, so add a 16th (leaf green, chart-16) in light and dark themes. Also register workbuddy in the source labels, the per-source pricing fallback defaults, the four ?source= query allowlists, and the landing/harness agent lists. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Add docs/52-workbuddy-support.md (data model, both usage traps, dedup key, golden verification numbers, accepted limitations, change list) and register it in the docs index. Update README/README.en/AGENTS supported-tool lists and the PRIVACY.md read-only path disclosure. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The JSON.parse catch branch was the only uncovered line in parsers/workbuddy.ts. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The workbuddy ?source= case ingests a usage row, so the by-device breakdown test (which asserts exact device, timeline and detail-row counts) must account for it the same way grok and zcode already do. Verified with the full local e2e suites: L2 API e2e 100/100, L3 browser e2e 91/91. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Both "all 15 sources" cases listed every source except the one added in this branch, leaving the validators untested for the new slug. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…table Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
… tests Complete the per-source enumeration tests for the workbuddy wiring, which compared green only by omission before: - status.test.ts: SourceDirs fixture was missing workbuddyDir; add it plus a classification case for cursors under ~/.workbuddy. - session-sync-helpers.test.ts: sourceKey's mapped list predates workbuddy — and zcode/omp were missing too; add all three. - continuity-anchor.test.ts: usesJsonlOffsetResume covers every offset-JSONL source explicitly; add workbuddy. Each assertion verified by mutation: deleting the production wiring branch for each source makes exactly that case fail. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
collectWorkbuddySessions excluded only rows without a sessionId, so on live installs the ai-title row — which does carry a sessionId — was counted, inflating totalMessages by one per session. Verify against a live install: the two sample sessions reported 64 and 34, now correct at 63 and 33. Exclude ai-title and file-history-snapshot by type instead. Time bounds are unchanged (the title row never set them). The unit test now pins the aux row with a sessionId present, and the parser header and docs/52 are corrected — they previously claimed the title row had no session id. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The international build installs under ~/.workbuddy-ai (product name `workbuddy-ai`, endpoint workbuddy.ai, locale en-US) while the domestic build uses ~/.workbuddy (endpoint copilot.tencent.com, zh-CN). Both keep the same on-disk layout — projects/<slug>/<sessionId>.jsonl, identical workbuddy.db schema — so the only gap was discovery: the driver read a single root. Replace the singular workbuddyDir with workbuddyDirs: string[], defaulting to both roots and following the vscodeCopilotDirs precedent. Discovery merges the roots (deduped, globally sorted, missing roots tolerated); the token and session drivers, status classification and paths all take the list. Verified on a live machine: with a synthetic international session present the dual-root scan reports 30 deltas / 3 files (29 domestic + 1 international) and 3 session snapshots; a domestic-only scan reports 29. Mutation-checked: dropping to roots[0], dropping the -ai default, or classifying only the first root each fail a test. The status fixture uses non-prefix-overlapping roots so it cannot pass by accident. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
WorkBuddy 5.7.6 (both the domestic ~/.workbuddy and international ~/.workbuddy-ai builds, same build 306add2a) writes a `session-meta` row that carries a sessionId, so the session collector counted it — one extra totalMessages per session, two per file on observed sessions. Exclude it by type alongside ai-title and file-history-snapshot. Verified on live 5.7.6 sessions: the two new files now report 32 and 53 totalMessages, matching an independent jq recount; a 5.5.x file without session-meta is unaffected. The token parser needs no change — session-meta carries no usage and is not matched by the '"usage"' fast filter. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…d shape gaps
Three defensive gaps found by review, all reproduced before fixing:
- Out-of-range timestamps crashed the whole file. A finite-but-unrepresentable
epoch (e.g. 1e20) passed the Number.isFinite guard, then
new Date(ts).toISOString() threw RangeError inside the parse loop, discarding
every delta in the file and never advancing the cursor — so the file's usage
was lost on every sync. Guard with isRepresentableEpochMs (|ms| <= 8.64e15)
in both the token and session parsers; coerceEpochMs gets the same bound.
- The '"usage"' fast filter skipped rawUsage-only rows. "rawUsage" does not
contain the substring "usage", so a line whose only usage shape was the
documented primary rawUsage was dropped. Match '"rawUsage"' too.
- An empty rawUsage {} shadowed a populated message.usage, because ?? stopped
at the empty object and normalization produced all-zero. Treat an empty
object as absent so the fallback chain continues.
Verified on live data: the 68-request total is unchanged (prompt 4,267,488 =
cache 3,814,535 + uncached 452,953; completion 122,069 = output 53,211 +
reasoning 68,858). docs/52 corrected where it described the accounting group
shape, the discovery entry point and the data-model table.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Each added assertion is mutation-checked: deleting the production code under test makes exactly the new case fail. - workbuddy-parser: zero-token stub must not occupy a messageId slot the real row needs; camelCase providerData.usage fallback (array details carry the cache and reasoning split); prompt_cache_write_tokens alias; rawUsage-only rows and an empty rawUsage that must fall through. - workbuddy-session: file-history-snapshot exclusion reachable with a sessionId; ISO string timestamp as a bound; out-of-range timestamp ignored. - workbuddy-session-driver: multi-root discover, symmetric with the token driver. - accounting-queue: a workbuddy-sourced record passes checkedRecord's hand-written source whitelist. - usage/sessions route tests: it.each over every accepted source, so dropping a whitelist entry from VALID_SOURCES fails the unit suite, not only L2. - pricing: every entry in SOURCES has a source-default fallback price. - cli: isSource accepts every SOURCES entry (exported for the test). - api-e2e: stale comment and "three devices" title corrected to four. docs/52 documents the accepted no-cross-run-dedup limitation; CHANGELOG gets the WorkBuddy entries. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The mocked SyncResult/SessionSyncResult literals omitted workbuddy (and omp), which tsc cannot see through the vi.mock factory. Add them so the fixture matches the real result shape. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Count each providerData.messageId once per sync across both WorkBuddy roots (domestic + international), and persist a bounded per-file ring on the cursor, so a session copied between ~/.workbuddy and ~/.workbuddy-ai — or a row re-emitted past the cursor — is no longer counted twice. - parser: accept an external seenMessageIds set, return emittedMessageIds - driver: WorkbuddyCursor ring + preload/needsReplay/resumeState/buildCursor, mirroring the Claude driver; keyed on seenMessageIds so preload() never pulls a sibling source's seenIds into the workbuddy set - shared state: snapshot/restore the workbuddy set across discarded parses - docs + changelog: replace the "no cross-file/cross-run dedup" limitations with the ring design; note the 5.7.6 startsNewUserRequest user-prompt row Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The rebase onto upstream/main retired six sources and added antigravity, which left a batch of stale expectations and a few real regressions. Fold them into one commit: - add the isWorkbuddyEmptyEpochCursor guard to prevent a persistently- empty workbuddy file from oscillating between legacy and modern cursors - restore the Grok line in the session-sync progress output - restore the docs index rows for 47-50 and renumber the workbuddy doc - drop zcode/omp from the sourceKey expectations and cover the retired copilot roots, so status no longer replays them - add the antigravity key to DEFAULT_SOURCE_DEFAULTS and widen the palette, session and usage test expectations to 16 sources - cover the workbuddy discovery/parser/session paths the review flagged as false-green, and assert route acceptance for every VALID_SOURCES entry Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…d coverage Follow-up on the review of the previous commit. Three fixes: - source-filter-parity asserted `not.toBe(400)` for every source, but the mocked DB reads returned undefined, so each route threw and answered 500 — which also satisfies `not.toBe(400)`. The gate was never actually exercised. Give the mock typed empty results and assert 200, so a route that drops the allowlist now fails the test. Mutation-checked: hardcoding the usage route's source list turns it red. - The parity test comment (and the CHANGELOG/doc) claimed each route used to carry its own 15-source literal. It never did — all four gated on core's VALID_SOURCES before this branch. Reword to describe what the test guards. - leaderboard.test's source-filter matrix had been narrowed from 14 literals (including the six retired sources) to [...SOURCES] (10 active). Iterate VALID_SOURCES instead to keep the retired-source coverage. Also two robustness fixes on the new workbuddy paths: - sync/session-sync activePaths now include opts.workbuddyDirs, so a workbuddy cursor is never mistaken for a retired one and dropped. - status.classifySource iterates workbuddyDirs with a `?? []` guard, matching the optional-chained reads elsewhere. And tighten AGENT_COLOR_MAP to Record<Source,...> so a new source can't be added without a color. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…itle The AGENT_COLOR_MAP entries are ordered by chart color number, not by source slug (opencode precedes openclaw), so the title overclaimed. It has read that way since before this branch; reword to describe what the case actually checks. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ling newline The previous commit corrected the palette test title but left three siblings that describe the same source-keyed maps as alphabetical when they are ordered by chart color (opencode precedes openclaw). All three predate this branch; reword them the same way rather than reorder the maps, which would churn many assertions for no behavioral gain. Also add the trailing newline the parity test was missing. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Two review findings, both fixed with a failing test first: - The workbuddy parsers emitted `model` and the constructed `workbuddy:<sessionId>` session key with no length bound. The server rejects either over MAX_STRING_LENGTH with a 400, and the upload engine does not retry or skip a 4xx, so a single over-long row (a malformed sessionId, or a hostile edit to a synced project file) would wedge every later upload for the account. Drop the offending row at parse time, as antigravity already does, and keep the rest of the file. - `leaderboard.spec.ts` asserted `toHaveCount(15)` for the harness source dropdown and titled the landing test "nine active collectors". Both were correct before this branch (9 active + 6 retired = 15) but adding workbuddy makes them 16 and ten, so the L3 gate would have gone red on merge to main. Derive the count from `VALID_SOURCES` and reword the title instead of re-hardcoding the next number. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ence The fault-injection review found two doc-accuracy gaps in doc 52: - The coverage table said "partial-line round-trip", but the tested case is a trailing partial line after complete content; a file whose FIRST line is unterminated falls to the shared continuity-anchor path (same as claude), so scope the claim to what the test pins. - Section 4 did not say which copy wins when the two roots carry the same messageId with different values. Discovery sorts paths lexicographically and `.workbuddy-ai` (hyphen) sorts before `.workbuddy` (slash), so the international copy wins; write that down. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…table Fourth-round review follow-ups, both documentation-only: - sync.ts's sourceKey default claimed a compile-time exhaustiveness check, but retired sources legitimately flow through it (they are Source members without drivers), so `source` is not `never` there and no `const _: never` assertion can compile — verified by attempting it. Reword the comment to state the actual invariant; the session-side switch keeps its real assertion. - docs/52 §6 was missing the length-cap parser tests and the L3 leaderboard spec change added by 15f664d. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The cold-path review found that isRepresentableEpochMs allows ±275,760 years while the server's ISO regex only accepts a 4-digit year. A row with, say, ts=5e15 passes the representable guard and formats as `+160413-09-10T…Z`, which validateIngestRecord rejects with a 400 — and the upload engine does not retry or skip a 4xx, so one such row wedges every later upload for the account. The token parser now drops the row via isValidISODate on its own output, and the session parser bounds min/max with the same rule, so snapshots stay server-compatible by construction. Mutation-checked: the new test fails without the guard. Shared-baseline note: opencode and other coerceEpochMs consumers carry the same wider window upstream; filed separately rather than swept here. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The 2f82099 fix added an isValidISODate gate in both workbuddy parsers; the data-model section still described the timestamp rule as only "representable epoch", and the coverage table did not name the new test cases. Align both with the shipped behavior. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The 4-digit-year gate landed in two places but not symmetrically:
- The session parser's ISO-string path ran Date.parse without the gate,
and Date.parse accepts extended years ("+275760-…Z"). The resulting
ms formatted back out of toISOString with a 6-digit year, which the
server's ingest regex rejects — wedging the upload batch. Gate both
timestamp paths once on the parsed ms.
- The token parser claimed the row's providerData.messageId before the
ISO check, so a row dropped for an out-of-window timestamp still
occupied the dedup ring — permanently suppressing a later corrected
rewrite of the same request. Move the check before the claim, matching
the zero-usage-stub rule.
Both behaviors pinned in workbuddy-timestamp-gate.test.ts.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ddy coverage Three behaviors had no test that would fail if the implementation changed: - The three usage shapes can disagree: pin that rawUsage wins wholesale (no field-wise merging) when all three are present. - The session key sits exactly at MAX_STRING_LENGTH: the boundary is kept (the existing overflow test only covered the drop side). - The session parser's bounds reject a representable-but-far-future epoch, matching the token parser's server-window gate. Also pin the dual-root same-id precedence end to end: a session copied between the international and domestic roots counts once, with the international copy's value, because discovery sorts paths and the international root's file is parsed first into the shared dedup ring. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The dropdown gate derived its expected count from core, but only named the retired sources explicitly — a duplicate label colliding with WorkBuddy's would still pass on count alone. Name it in the visibility loop too. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…atch Two review follow-ups: - Doc 52 claimed the international copy wins whenever the two roots carry the same id with different values. That holds only when both copies are new in the same sync: if the domestic copy was counted in an earlier sync, its persisted ring suppresses the international copy instead. Scope the claim, and record the prune-loses-the-ring limitation next to the other accepted ones. - classifySource matched the workbuddy roots with a bare startsWith, and `.workbuddy` is a string prefix of `.workbuddy-ai` — correct today only because both roots share a label. Require the path separator so a future sibling root cannot be misclassified. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The ISO-gate regression tests only covered the bad and corrected rows in one parse. Add the two-sync shape — bad row dropped and offset advanced, corrected row appended, incremental read resumes from the previous endOffset — and record the timestamp-gate file in doc 52's coverage list. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The server rejects any token field over MAX_RECORD_TOKENS and any session duration over MAX_SESSION_DURATION_SECONDS with a 400, and the upload engine does not retry a 4xx — one over-cap record would wedge every later upload for the account. Antigravity already gates both at its parser; the workbuddy parser queueed such records instead: - Two individually-valid timestamps on a clock-skewed machine (year 1 and year 9999) compose a duration of ~315 billion seconds. Drop the snapshot when its duration crosses the server's cap. - Aliased inclusive counters can compose buckets over the token cap even when each raw counter stays under it. Check the composed buckets before emitting, after the ISO gate and before the id is claimed, so a dropped row also never occupies the dedup ring. Both behaviors pinned in workbuddy-record-caps.test.ts, including the exact-at-cap boundaries. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
MisonL
force-pushed
the
feat/workbuddy-support
branch
from
October 14, 2026 02:55
e8c6d8b to
2ca503c
Compare
Community parsers (fuyi, Jimmy6188) also read cache-write from the nested details objects — cached_creation_tokens / cache_write_tokens — and a build that only fills the nested fields would land its write tokens in the miss bucket. The top-level aliases stay first so the verified shapes win. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The changelog stated cross-root dedup without the 2000-id window bound that doc 52 documents, and doc 52's coverage list missed the workbuddy-record-caps tests added with the server-limit gates. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…dual-root edges status.ts required a literal "/" after the root, which never matches the backslash paths a Windows cursor store produces — workbuddy cursors fell into "unknown". Accept either separator after the root prefix. Doc 52's dedup-key section now names the two real-world triggers of the documented window bound: renaming a project slug directory re-sums ids outside the ring once, and a root that temporarily disappears is re-summed from scratch when it returns (the accounting merge keeps queue values stable there). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…tion Records two design notes from the final logic review: the decoy read aliases are last-resort and protected by firstPositive chain order, and the miss fallback (prompt - read) assumes cache-write tokens are already inside the miss total. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Two coordinated changes are needed to retire workbuddy (RETIRED_SOURCES plus a regex branch that only matches once workbuddyDirs leaves paths.ts), and future cursor migrations must not fill seenMessageIds on an empty-epoch cursor — the field's absence is load-bearing. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The accounting ingest endpoint validates model with the strict label rule (ASCII, at most 128 chars) while the token endpoint accepts any non-empty string up to 1024. A delta whose model passes the token upload but not the accounting one would make the details upload 400 forever (no retry on 4xx, dirty keys never clear), leaving accounting details permanently pending. planAccountingUpdates now normalizes every record's model through usageLabel — a plain ASCII model is unchanged — and looks the token basis up by the raw model, since the token bucket keeps its own key. Covered by accounting-model-label.test.ts. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
A corrupted or hostile file carrying huge providerData.messageId values grows the cursor's dedup ring (2000 entries) to hundreds of megabytes, taxing every later sync's cursor read/write; an over-long id is now treated like a missing one, before the row can claim the id slot. A session snapshot whose message counts exceed the server's MAX_RECORD_MESSAGES would 400 and wedge every later session upload, so the collector drops it — same wedge defense the duration and sessionKey gates already had. The snapshot-builder part of the collector is extracted into buildWorkbuddySessionSnapshots so the 1e8 count gate is testable without writing 1e8 lines. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
§6 records the message-count, messageId and accounting-label gate tests; §2 records the nested cache-write aliases and widens the rawTotal diagnostic wording to cover the invalid-counts branch; CHANGELOG gains entries for the accounting model normalization and the new parser gates. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
MisonL
force-pushed
the
feat/workbuddy-support
branch
from
October 14, 2026 06:24
572615e to
1c34284
Compare
…path Two review-round findings worth recording: the 2000-id ring's measured cursor cost (78-134KB per file, hundreds of MB at the 10k-file extreme) and the fact that downgrading to 3.3.2 makes pew sync throw "Invalid accounting ledger" on a WorkBuddy record until the queue file is moved aside — retired sources never hit this because both versions' whitelists contain their slugs. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This branch has not been deployed
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.
Summary
Implements the WorkBuddy portion of #696 (QwenWork, DoubaoWork and the rest of
that list remain open). Adds WorkBuddy as a supported
AI coding tool, tracking both the domestic (
~/.workbuddy) and international(
~/.workbuddy-ai) roots.anchors, mirroring the existing per-source driver architecture.
providerData.messageId, so a sessioncopied between the two roots is not counted twice.
chart-16), source labels, per-source pricingfallback,
?source=allowlists and the landing/harness agent lists.SOURCES;RETIRED_SOURCESunchanged. Total supportedidentities go from 15 to 16.
packages/workerandpackages/worker-readneed no change: they consumecore's validator and pass
sourcethrough to bound SQL parameters.Parsing notes (both verified against a live install)
the normalizer picks the live value and splits
miss+write/completion-reasoning.ai-title,session-metaandfile-history-snapshotrows are metadata, notmessages; they are excluded from message counts.
the whole file.
full rescan every other sync.
Alignment with upstream
Rebased onto current
main(now at 3.3.2, Next 16.4.0), which retired six collectors and addedantigravity. Commit
6944f641reconciles the stale expectations, restores theGrok session-progress line and updates the palette/label/pricing maps. The
later commits (
fc8aad50,a9ff81b4,cc9bd6d5) tighten the reviewfindings from that rebase:
fc8aad50makes the source-filter parity assertionreal and restores retired-source coverage,
a9ff81b4drops stale"alphabetical" claims, and
cc9bd6d5caps the workbuddy string fields (anover-long
modelorsessionIdwould 400 every upload) and derives the L3harness source count from core, and
b00b42a9gates timestamps on the server's4-digit-year ISO window (a representable-but-far-future row would format as
+160413-…Z, also 400ing the batch). A later review round added threemore server-limit gates:
e93b867enormalizes accounting record modelsthrough
usageLabel(a model that passes the token endpoint but not theaccounting endpoint's stricter label rule would leave accounting details
pending forever), and
9b1cbfcegates oversizedproviderData.messageIdvalues (which would bloat the cursor's dedup ring) and over-cap session
message counts (which would 400 and wedge every later session upload).
Testing
environment flake in
scripts/__tests__/e2e-utils.test.tsaside — that fileis untouched by this branch and passes on upstream
main).tscpasses for every commit (the last one is docs-only).source-filter-paritydrives everyVALID_SOURCESentry through all four?source=routes and asserts 200 (mutation-checked: hardcoding a route'ssource list turns it red).
Note: L2/L3 jobs are skipped on fork PRs by
.github/workflows/ci.yml(
if: ... head.repo.full_name == github.repository), so they run on themerge-to-main push rather than here. Pre-push runs the full L2+L3+gitleaks stack locally on an internal-disk
clone; the network-attached working copy cannot meet the L3 dev-server
readiness budget.
🤖 Generated with Claude Code