Skip to content

fix(catalog): demonstrate * 1000 Date conversion in time-series exampleCalls - #30

Merged
Aliiiu merged 2 commits into
mainfrom
fix/time-series-date-conversion
Jun 23, 2026
Merged

fix(catalog): demonstrate * 1000 Date conversion in time-series exampleCalls#30
Aliiiu merged 2 commits into
mainfrom
fix/time-series-date-conversion

Conversation

@Aliiiu

@Aliiiu Aliiiu commented Jun 23, 2026

Copy link
Copy Markdown
Contributor

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), got 1970-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 date as Unix seconds on the /v2-style series endpoints, while JS new Date(n) expects milliseconds. Verified live:

$ curl https://api.llama.fi/v2/historicalChainTvl/Ethereum
# last entry: { "date": 1782172800, "tvl": 37970061149 }
# new Date(1782172800 * 1000) → 2026-06-23T00:00:00.000Z  ✓
# new Date(1782172800)        → 1970-01-21T15:02:52.800Z  ✗  (the failure mode)

What changed

Same lever as PR #15 / #16 / #20 / #26 / #28 — the exampleCall is the contract surfaced to the model via search_docs. Update the three /v2-style time-series endpoints' projections to demonstrate the conversion inline:

Endpoint New projection
getHistoricalChainTvl date: new Date(p.date * 1000).toISOString() /* p.date is Unix seconds; multiply by 1000 for JS Date */
getStablecoinCharts same pattern, with totalCirculatingUSD
getStablecoinPrices same pattern, with prices

The fourth time-series endpoint (getHistoricalPoolData) is differentHistoricalPoolItemSchema declares timestamp: 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:

timestamp: p.timestamp /* already an ISO string, unlike the date:number fields on /v2 endpoints */

Deliberately scoped out

  • No instructions.md change. 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).
  • No type-layer fix. Latent issue from PR fix(catalog): shape responses inside execute(); guide narrow-vs-broad #28ProtocolData declares tvl: number but /protocol/{slug} returns tvl: array. Still out of scope; tracked separately.

Test plan

  • pnpm exec tsc --noEmit clean
  • pnpm test → 171 passed
  • Regenerated embedded-index.ts (ships the new exampleCall to search_docs consumers)
  • Verified live against https://api.llama.fi/v2/historicalChainTvl/Ethereum that the * 1000 conversion is the right idiom for this endpoint
  • Post-merge: confirm a fresh Aiden Phase-3 Q3 run no longer hits the 1970-01-XX failure mode or burns time in date-formatting retry loops

🤖 Generated with Claude Code

Aliiiu and others added 2 commits June 23, 2026 12:51
…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>

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

@Aliiiu
Aliiiu merged commit 7fbee13 into main Jun 23, 2026
1 check passed
@github-actions github-actions Bot mentioned this pull request Jun 23, 2026
Aliiiu added a commit that referenced this pull request Jun 23, 2026
…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>
@github-actions github-actions Bot mentioned this pull request Jun 23, 2026
@Aliiiu Aliiiu self-assigned this Jun 29, 2026
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.

Time-series exampleCalls don't demonstrate the * 1000 Unix-seconds → JS Date conversion; agents render 1970-01-XX dates and burn time recovering

1 participant