Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions odd/ledger/learnings.jsonl
Original file line number Diff line number Diff line change
Expand Up @@ -38,3 +38,5 @@
{"id":"learn-20260412-0001","timestamp":"2026-04-12T00:52:00Z","summary":"Standalone Worker tools (telemetry, time) bypass orchestrate pipeline — they share oddkit_ MCP prefix but register directly in createServer with their own handler. CLI parity requires adding to TOOLS array (auto-cascades) plus explicit param threading in cli.js and server.js","trigger":"architecture","impact":"New standalone tools need 5 files touched: index.ts (Worker registration), tool-registry.js (TOOLS entry), actions.js (handler), server.js (param threading), cli.js (param threading). The TOOLS auto-derivation handles enum/listing but not param plumbing.","confidence":0.95,"sources":["workers/src/index.ts","src/core/tool-registry.js","src/core/actions.js","src/mcp/server.js","src/cli.js"],"evidence":[{"type":"artifact","ref":"PR #87 — oddkit_time implementation across 5 files"}],"candidate_targets":[],"proposed_escalation":"none"}
{"id":"L39","timestamp":"2026-04-13T11:12:00Z","type":"learning","summary":"raw.githubusercontent.com URL parsing must rejoin all path segments after owner/repo to support branch names with slashes — parts[2] truncates multi-segment refs like publish/four-essays-and-skill to just publish","context":"extractBranchRef() and getZipUrl() in zip-baseline-fetcher.ts both used parts[2] which only captured the first segment of a slash-containing branch name, causing 404s on both SHA resolution and ZIP download","resolution":"Changed to parts.slice(2).join(\"/\") in both functions — minimal 2-line fix"}
{"type":"D","summary":"E0008 challenge governance refactor: replaced hardcoded detectClaimType logic in runChallengeAction with four governance-driven fetch functions (discoverChallengeTypes, fetchBasePrerequisites, fetchNormativeVocabulary, fetchStakesCalibration). Voice-dump suppression invariant is load-bearing — questionTiers.length === 0 short-circuits all output. Four new caches cleared in runCleanupStorage. tsc clean. PR #100.","rationale":"Hardcoded challenge logic cannot evolve with governance articles; governance-driven extraction means challenge behavior updates when articles update, no code change required. Mirrors PR #96 encode precedent exactly.","context":"workers/src/orchestrate.ts, branch feat/e0008-challenge-governance-driven, commit aa4445c","date":"2026-04-17"}
{"date": "2026-04-24", "epoch": "E0008", "task": "feat/telemetry-semantic-names", "summary": "TypeScript bundler moduleResolution omits .js extensions on local imports in compiled output \u2014 Node.js ESM resolver requires explicit .js suffix. When compiling telemetry.ts for integration tests, all compiled .js files in the build dir must be post-processed to add .js to extensionless relative imports. Patch all files in the build dir, not just telemetry.js.", "detail": "telemetry.ts now imports KnowledgeBaseFetcher (a value import, not just a type import) from zip-baseline-fetcher.ts. The existing integration test only compiled tokenize.ts and telemetry.ts. Adding zip-baseline-fetcher.ts to the tsconfig include list is necessary but insufficient \u2014 the compiled JS has extensionless imports (./zip-baseline-fetcher, ./tracing) that Node ESM cannot resolve. Must patch all .js files in the build dir with a regex replace of from \"./foo\" -> from \"./foo.js\".", "pr": "https://github.com/klappy/oddkit/pull/137"}
{"date": "2026-04-24", "epoch": "E0008", "task": "feat/telemetry-semantic-names", "summary": "JSDoc block comments must not contain */ sequences \u2014 they terminate the comment prematurely. Patterns like blob*/double* in a JSDoc comment cause TypeScript parse errors. Use blob1..9/double1..6 or similar notation instead.", "detail": "detectRawSlotNames JSDoc had blob*/double* which the TypeScript parser reads as end-of-comment at the first */. tsc reported TS1109 (Expression expected) at line 459. The fix is trivial but the error message is cryptic \u2014 the real cause is invisible until you stare at the raw characters.", "pr": "https://github.com/klappy/oddkit/pull/137"}
35 changes: 23 additions & 12 deletions workers/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -425,20 +425,31 @@ Use when:

Dataset: oddkit_telemetry (Cloudflare Analytics Engine)
Schema:
blob1 — event_type "mcp_request" | "tool_call"
blob2 — method JSON-RPC method (e.g. "tools/call")
blob3 — tool_name oddkit action (e.g. "orient", "search")
blob4 — consumer_label best-effort caller identity
blob5 — consumer_source how label was resolved (e.g. "user-agent")
blob6 — knowledge_base_url which knowledge base is being served
blob7 — document_uri for get calls, the klappy:// URI requested
blob8 — worker_version oddkit version string
double1 — count always 1
double2 — duration_ms request processing time
index1 — sampling_key consumer label
event_type — "mcp_request" | "tool_call"
method — JSON-RPC method (e.g. "tools/call")
tool_name — oddkit action (e.g. "orient", "search")
consumer_label — best-effort caller identity
consumer_source — how label was resolved (e.g. "user-agent")
knowledge_base_url — which knowledge base is being served
document_uri — for get calls, the klappy:// URI requested
worker_version — oddkit version string
cache_tier — which storage tier served the index
count — always 1 (use SUM for aggregation)
duration_ms — request processing time (full wall-clock at worker edge)
bytes_in — UTF-8 byte length of the request body
bytes_out — UTF-8 byte length of the response body (0 for SSE streams)
tokens_in — cl100k_base token count of the request body
tokens_out — cl100k_base token count of the response body
index1 — sampling key (consumer label)

Use SUM(_sample_interval) instead of COUNT(*) to account for Analytics Engine sampling.
Time filter example: WHERE timestamp > NOW() - INTERVAL '30' DAY`,
Time filter example: WHERE timestamp > NOW() - INTERVAL '30' DAY

Example — tool leaderboard:
SELECT tool_name, SUM(_sample_interval) AS calls FROM oddkit_telemetry WHERE timestamp > NOW() - INTERVAL '30' DAY GROUP BY tool_name ORDER BY calls DESC LIMIT 10

Example — payload shape by tool:
SELECT tool_name, AVG(tokens_out) AS avg_tokens_out FROM oddkit_telemetry WHERE timestamp > NOW() - INTERVAL '7' DAY GROUP BY tool_name ORDER BY avg_tokens_out DESC`,
{
sql: z.string().describe("Analytics Engine SQL query against the oddkit_telemetry dataset."),
},
Expand Down
Loading
Loading