Skip to content

fix: use Harper @createdTime instead of hand-rolled created_at - #169

Merged
heskew merged 1 commit into
mainfrom
claude/fix-168
Jul 9, 2026
Merged

fix: use Harper @createdTime instead of hand-rolled created_at#169
heskew merged 1 commit into
mainfrom
claude/fix-168

Conversation

@claude

@claude claude Bot commented Jul 9, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Annotate created_at with Harper's @createdTime directive on csrf_tokens, mcp_auth_codes, and mcp_refresh_families, and stop hand-writing the field in app code — Harper now assigns it on insert (epoch ms) and retains it across rotation writes.
  • Remove the reinvented created_at from the app DTOs (MCPAuthCodeRecord, MCPRefreshFamilyRecord), their encode/decode paths, and the manual Date.now() / nowSeconds() writes (CSRFTokenManager, mcp/callback.ts, mcp/token.ts). These fields were write-only / informational, so nothing reads them for logic.
  • Keep harper_oauth_mcp_keys.created_at as a hand-managed seconds field — keyStore deliberately mutates it to reorder GC/signer selection, which @createdTime (pinned to original insert time) cannot express. Added a schema comment documenting why it's the exception and why it's seconds.

This resolves the unit footgun called out in #168 (ms in two tables, seconds in three): created_at is now Harper-owned everywhere it's just informational, and the one place it's app-logic is explicitly documented.

Test plan

  • npm run build (tsc)
  • npm run lint (0 errors)
  • npm run format:check (only untracked .harper-skills/ flagged)
  • npm test — 840 pass, 0 fail
  • bun test — 840 pass, 0 fail
  • Regression: flipped CSRFTokenManager / OAuthProvider / callback assertions to require created_at is not hand-written (fails before this change, passes after).

Closes #168

Four oauth tables hand-wrote a created_at that Harper can populate
itself via @createdtime, and the unit differed per table (ms vs
seconds) — a latent 1000x footgun for whoever next reads one assuming
the other convention.

Annotate created_at with @createdtime on csrf_tokens, mcp_auth_codes,
and mcp_refresh_families (all informational / not computed on) and stop
hand-writing it in app code. harper_oauth_mcp_keys keeps its manual,
seconds-based field — keyStore deliberately mutates created_at to
reorder GC/signer selection, which @createdtime cannot express — now
documented in the schema.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
@claude

claude Bot commented Jul 9, 2026

Copy link
Copy Markdown
Contributor Author

Reviewed; no blockers found.

@heskew heskew added the gemini-review Trusted-member gesture: spawn Gemini review on a bot-authored PR. label Jul 9, 2026
@github-actions

github-actions Bot commented Jul 9, 2026

Copy link
Copy Markdown
Contributor

Reviewed; no blockers found.

Suggestions (non-blocking)

  • test/lib/mcp/token.test.js:142 (and tokenAuditHook.test.js:148) — remove created_at from the seedCode helper. The app code no longer reads this field for auth codes (it is dropped in decodeRecord), so keeping it in the test seeds is unnecessary and inconsistent with the PR's goal of removing hand-written timestamps.
  • test/lib/CSRFTokenManager.test.js:104 — remove created_at from the malformed-data test seed. Since the manager no longer reads or writes this field, removing it from the manual seed keeps the test aligned with the move to Harper-managed @createdTime.

@heskew
heskew merged commit 1eff515 into main Jul 9, 2026
14 checks passed
@heskew
heskew deleted the claude/fix-168 branch July 9, 2026 23:42
@heskew heskew mentioned this pull request Jul 11, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

gemini-review Trusted-member gesture: spawn Gemini review on a bot-authored PR.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

oauth tables hand-roll created_at instead of using Harper's @createdTime

1 participant