fix(catalog): demonstrate * 1000 Date conversion in time-series exampleCalls - #30
Conversation
…leCalls Session evidence from Aiden Phase-3 Q3 showed the model spending 54s in retry/recover loops on date formatting, ultimately returning "1970-01-18" instead of the actual date. Root cause is the classic Unix-seconds-vs-milliseconds JS Date trap: - DefiLlama returns `date` as Unix SECONDS on the /v2 series - JS `new Date(n)` expects MILLISECONDS - `new Date(1782172800)` → 1970-01-21 (wrong) - `new Date(1782172800 * 1000)` → 2026-06-23 (right) Verified live against `curl https://api.llama.fi/v2/historicalChainTvl/Ethereum`: last entry has date: 1782172800, which only resolves correctly with the * 1000 multiplier. Same lever as the other shape-discipline fixes on this PR: the exampleCall is the contract. Update the three /v2-style time-series endpoints (getHistoricalChainTvl, getStablecoinCharts, getStablecoinPrices) so their projection demonstrates the conversion inline: date: new Date(p.date * 1000).toISOString() /* p.date is Unix seconds; multiply by 1000 for JS Date */ The fourth time-series endpoint (getHistoricalPoolData) is different — HistoricalPoolItemSchema declares `timestamp: z.string()`, i.e. ISO already, so no * 1000 needed. Added an inline comment there making the asymmetry explicit, so the agent doesn't apply the * 1000 pattern to it by mistake. Deliberately did NOT add a generic "Unix-seconds vs ms" instruction to instructions.md — that's the cheat-sheet anti-pattern. The exampleCall demonstrating the right idiom is the right surface. 171 tests still pass. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Documents the * 1000 conversion fix for the next release. Patch bump — no behavior change to the published artifact beyond updated exampleCall strings in the embedded search index. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
Code Review
This pull request fixes a JS Date issue in the exampleCall definitions for several time-series endpoints (getHistoricalChainTvl, getStablecoinCharts, and getStablecoinPrices) by multiplying the Unix seconds timestamp by 1000 before converting it to an ISO string. It also adds an explanatory comment to getHistoricalPoolData where the timestamp is already formatted as an ISO string. These updates are applied to both tool-metadata.ts and embedded-index.ts. There are no review comments, and the changes look correct, so I have no feedback to provide.
Important
The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.
…s example The "Time-series" pattern in the always-loaded "Shape responses" section of instructions.md was using bare `p.date` without the * 1000 conversion — inconsistent with the per-endpoint exampleCalls in tool-metadata.ts (which DO convert), and would produce 1970-01-XX dates if the agent followed the instruction verbatim. This is a latent bug from the original PR #28: the instruction code block was written before PR #30 introduced the Date-conversion discipline, and PR #30 only updated the per-endpoint examples — not this canonical instruction. The restoration PR brought the instruction back verbatim along with the inconsistency. Fix: the time-series pattern now demonstrates `new Date(p.date * 1000).toISOString()` and has a one-line note explicitly calling out the Unix-seconds-vs-ms gotcha so the rule is teachable from the instructions surface, not only from the per-endpoint examples. Regenerated instructions.generated.ts to match. Caught by gemini-code-assist[bot] cross-referencing the instruction example against the tool-metadata exampleCalls — same cross-check pattern that caught the changeset-vs-code mismatch earlier in PR #28. 171 tests still pass. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Closes #39
Summary
Fixes the classic Unix-seconds-vs-ms JS Date trap that surfaced in the latest Aiden Phase-3 Q3 evidence: model called the historical-TVL endpoint, did
new Date(p.date)(no* 1000), got1970-01-XX, burned ~54s in retry/recover loops on the formatting, and ultimately returned a degraded answer.Root cause is upstream-shape, not a model bug: DefiLlama returns
dateas Unix seconds on the/v2-style series endpoints, while JSnew Date(n)expects milliseconds. Verified live:What changed
Same lever as PR #15 / #16 / #20 / #26 / #28 — the
exampleCallis the contract surfaced to the model viasearch_docs. Update the three/v2-style time-series endpoints' projections to demonstrate the conversion inline:getHistoricalChainTvldate: new Date(p.date * 1000).toISOString() /* p.date is Unix seconds; multiply by 1000 for JS Date */getStablecoinChartstotalCirculatingUSDgetStablecoinPricespricesThe fourth time-series endpoint (
getHistoricalPoolData) is different —HistoricalPoolItemSchemadeclarestimestamp: z.string()(already ISO from yields.llama.fi), so it does not need the* 1000. Added an inline comment there so the model doesn't apply the pattern by mistake:Deliberately scoped out
instructions.mdchange. A generic "Unix-seconds vs ms" hint would be cheat-sheet territory. The right surface is the per-endpoint exampleCall demonstrating the right idiom (matches the same minimal-instruction approach the prior PRs used).ProtocolDatadeclarestvl: numberbut/protocol/{slug}returnstvl: array. Still out of scope; tracked separately.Test plan
pnpm exec tsc --noEmitcleanpnpm test→ 171 passedembedded-index.ts(ships the new exampleCall tosearch_docsconsumers)https://api.llama.fi/v2/historicalChainTvl/Ethereumthat the* 1000conversion is the right idiom for this endpoint🤖 Generated with Claude Code