Skip to content

test: id — Identifier generation, ordering, and timestamp extraction#400

Closed
anandgupta42 wants to merge 1 commit intomainfrom
claude/test-id-module-012maTw3RYyvmA13VfxTeYpJ
Closed

test: id — Identifier generation, ordering, and timestamp extraction#400
anandgupta42 wants to merge 1 commit intomainfrom
claude/test-id-module-012maTw3RYyvmA13VfxTeYpJ

Conversation

@anandgupta42
Copy link
Contributor

@anandgupta42 anandgupta42 commented Mar 23, 2026

What does this PR do?

Adds the first test coverage for the Identifier module (src/id/id.ts), which is the core ID generation system used by every session, message, part, permission, and workspace in altimate-code. Previously had zero tests.

1. Identifier.ascending and Identifier.descendingsrc/id/id.ts (7 new tests)

This module generates monotonic, lexicographically-sortable IDs that power message ordering, session listing, and data integrity throughout the system. Zero tests existed. New coverage includes:

  • Correct prefix generation for all 9 entity types (session, message, permission, question, user, part, pty, tool, workspace)
  • Monotonic ascending ordering: 100 sequential IDs are strictly increasing (lexicographic)
  • Monotonic descending ordering: 100 sequential IDs are strictly decreasing
  • Given-ID pass-through returns the exact input when prefix matches
  • Permissive prefix validation behavior is documented (any string starting with the 3-char prefix is accepted)
  • Mismatched prefix throws descriptive error

2. Identifier.timestampsrc/id/id.ts (2 new tests)

The timestamp() function extracts creation time from ascending IDs, used in tool/truncation.ts for age-based cleanup. Testing revealed that absolute timestamp extraction overflows for modern timestamps (the 6-byte / 48-bit encoding can't hold Date.now() * 0x1000), but relative comparisons between IDs created in the same era work correctly — which is exactly how the codebase uses it. Tests document this behavior:

  • Relative comparison: IDs created 60s apart have correctly ordered timestamps
  • Idempotency: same ID always extracts the same timestamp value

Discovery: 48-bit timestamp overflow

During testing, discovered that Identifier.timestamp() silently overflows for current-era timestamps. The encoding stores ts * 0x1000 in 48 bits, but modern timestamps exceed 2^36 ms (~1972). This doesn't affect production because the only caller (tool/truncation.ts) uses it for relative age comparisons where both sides overflow identically. Filed as a known behavior, not a blocking bug.

Type of change

  • New feature (non-breaking change which adds functionality)

Issue for this PR

N/A — proactive test coverage for core infrastructure

How did you verify your code works?

bun test test/id/id.test.ts       # 18 pass, 0 fail, 215 expect() calls

Checklist

  • I have added tests that prove my fix is effective or that my feature works
  • New and existing unit tests pass locally with my changes

https://claude.ai/code/session_012maTw3RYyvmA13VfxTeYpJ

Summary by CodeRabbit

  • Tests
    • Added comprehensive test coverage for identifier generation and validation functionality, ensuring reliability of ID operations across ascending, descending, and timestamp-based scenarios.

The Identifier module generates monotonic IDs for every session, message, part,
and permission. Zero tests existed. Covers ascending/descending ordering,
prefix validation, and documents the 48-bit timestamp overflow behavior.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

https://claude.ai/code/session_012maTw3RYyvmA13VfxTeYpJ
Copy link

@claude claude bot left a comment

Choose a reason for hiding this comment

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

Claude Code Review

This repository is configured for manual code reviews. Comment @claude review to trigger a review.

Tip: disable this comment in your organization's Code Review settings.

@coderabbitai
Copy link

coderabbitai bot commented Mar 23, 2026

📝 Walkthrough

Walkthrough

A new test suite for the Identifier class was added, covering ID generation methods (ascending, descending, timestamp) and prefix validation. The tests verify monotonic ordering, prefix matching behavior, timestamp extraction consistency, and edge case handling across known prefix patterns.

Changes

Cohort / File(s) Summary
Identifier Test Suite
packages/opencode/test/id/id.test.ts
Added 91 lines of Bun tests covering Identifier class behavior: ascending() and descending() ID generation with prefix validation, monotonic ordering verification, timestamp() extraction, and prefix pattern validation across all known prefix types.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

Poem

🐰 With whiskers twitching, I test each ID,
Ascending, descending, timestamps so spry!
Prefixes matched, monotonic and true,
The Identifier class now tested through and through!

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately and concisely summarizes the main change: adding test coverage for Identifier generation, ordering, and timestamp extraction.
Description check ✅ Passed The description is comprehensive and covers all required sections: what changed and why (detailed coverage), test plan (18 passing tests verified), and mentions the checklist items completed.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch claude/test-id-module-012maTw3RYyvmA13VfxTeYpJ

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

🧹 Nitpick comments (2)
packages/opencode/test/id/id.test.ts (2)

39-51: Consider adding passthrough test for descending.

The ascending tests include coverage for the given ID passthrough behavior (lines 19-36), but descending tests don't cover this scenario. Since both use the same underlying generateID function, adding a similar test would ensure consistent behavior.

📝 Optional: Add passthrough test
   test("generates monotonically decreasing IDs", () => {
     const ids = Array.from({ length: 100 }, () => Identifier.descending("session"))
     for (let i = 1; i < ids.length; i++) {
       expect(ids[i] < ids[i - 1]).toBe(true)
     }
   })
+
+  test("returns given ID when prefix matches", () => {
+    const given = "ses_abc123"
+    const id = Identifier.descending("session", given)
+    expect(id).toBe(given)
+  })
 })
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/opencode/test/id/id.test.ts` around lines 39 - 51, Add a passthrough
test for Identifier.descending similar to the ascending passthrough coverage:
call Identifier.descending with an already-formed ID string (e.g., one that
matches the "ses_" prefix used elsewhere) and assert it returns the input
unchanged; target the Identifier.descending function (which delegates to
generateID) to ensure the same passthrough behavior is exercised as in the
ascending tests.

84-89: Consider improving type safety in the loop.

The as any cast works but loses type safety. The type can be improved by explicitly typing the array elements.

📝 Optional: Improve typing
-  const prefixes = [
+  const prefixes: Array<[keyof typeof import("../../src/id/id").Identifier extends { ascending: (k: infer K) => any } ? K : never, string]> = [
     ["session", "ses_"],
     ...
   ] as const

   for (const [key, prefix] of prefixes) {
-    test(`${key} generates IDs starting with ${prefix}`, () => {
-      const id = Identifier.ascending(key as any)
+    test(`${key} generates IDs starting with ${prefix}`, () => {
+      const id = Identifier.ascending(key)
       expect(id).toStartWith(prefix)
     })
   }

Alternatively, a simpler approach using type assertion at the array level:

type PrefixKey = Parameters<typeof Identifier.ascending>[0]
const prefixes: [PrefixKey, string][] = [
  ["session", "ses_"],
  // ...
]
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/opencode/test/id/id.test.ts` around lines 84 - 89, The test loop
uses an unsafe cast `key as any` when calling Identifier.ascending; instead,
tighten types by declaring the prefixes array with an explicit tuple element
type that matches Identifier.ascending's first parameter (e.g., create a type
alias like PrefixKey = Parameters<typeof Identifier.ascending>[0] and type
prefixes as [PrefixKey, string][] or otherwise type each array element), then
remove the `as any` cast and pass the properly typed `key` to
Identifier.ascending.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@packages/opencode/test/id/id.test.ts`:
- Around line 39-51: Add a passthrough test for Identifier.descending similar to
the ascending passthrough coverage: call Identifier.descending with an
already-formed ID string (e.g., one that matches the "ses_" prefix used
elsewhere) and assert it returns the input unchanged; target the
Identifier.descending function (which delegates to generateID) to ensure the
same passthrough behavior is exercised as in the ascending tests.
- Around line 84-89: The test loop uses an unsafe cast `key as any` when calling
Identifier.ascending; instead, tighten types by declaring the prefixes array
with an explicit tuple element type that matches Identifier.ascending's first
parameter (e.g., create a type alias like PrefixKey = Parameters<typeof
Identifier.ascending>[0] and type prefixes as [PrefixKey, string][] or otherwise
type each array element), then remove the `as any` cast and pass the properly
typed `key` to Identifier.ascending.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 148e5749-5d05-4bd2-95ed-d426504be1ce

📥 Commits

Reviewing files that changed from the base of the PR and between 8eb13d4 and 82f63a4.

📒 Files selected for processing (1)
  • packages/opencode/test/id/id.test.ts

anandgupta42 added a commit that referenced this pull request Mar 23, 2026
Merges 9 test PRs (#390, #394, #395, #396, #397, #398, #399, #401, #387)
into a single PR, discarding 4 duplicates (#391, #392, #393, #400).

**New test coverage:**
- `id.test.ts` — 14 tests: Identifier generation, monotonic ordering, timestamp extraction, Zod schema
- `shell.test.ts` — 9 tests: shell blacklist enforcement for fish/nu, cache reset, fallback
- `path-traversal.test.ts` — 7 tests (new): `Protected.isSensitiveWrite` for .pem/.key, .gnupg, .env variants
- `ignore.test.ts` — 7 tests (new): `FileIgnore.match` directory patterns, globs, whitelist overrides
- `paths-parsetext.test.ts` — 16 tests: `ConfigPaths.parseText` env/file substitution, JSONC parsing
- `finops-formatting.test.ts` — 14 tests: `formatBytes`/`truncateQuery` edge cases
- `finops-role-access.test.ts` — 10 tests: RBAC `formatGrants`/`formatHierarchy`/`formatUserRoles`
- `tool-lookup.test.ts` — 4 tests: Zod schema introspection for tool parameters
- `summary-git-path.test.ts` — 10 tests: `unquoteGitPath` decoding for non-ASCII filenames
- `tracing.test.ts` — 2 tests (added): Recap loop detection boundaries
- `patch.test.ts` — 9 tests (added): `maybeParseApplyPatchVerified` entry point coverage
- `instruction.test.ts` — 13 tests (new): `InstructionPrompt.loaded()` dedup guards
- `message-v2.test.ts` — 23 tests (new): `MessageV2.filterCompacted()` boundary detection

**Bug fixes (discovered during testing):**
- `finops-formatting.ts`: fix `formatBytes` crash on negative/NaN/fractional inputs
- `finops-formatting.ts`: fix `truncateQuery` returning empty for whitespace-only, exceeding `maxLen` when < 4
- `training-import.test.ts`: fix pre-existing typecheck errors (missing `context`/`rule` mock keys)
- `instruction.test.ts`, `message-v2.test.ts`: fix `MessageV2.Part` cast and branded ID type errors

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@anandgupta42
Copy link
Contributor Author

Consolidated into #403

@anandgupta42 anandgupta42 deleted the claude/test-id-module-012maTw3RYyvmA13VfxTeYpJ branch March 23, 2026 17:11
anandgupta42 added a commit that referenced this pull request Mar 23, 2026
* test: consolidated test coverage across 9 modules (133 new tests)

Merges 9 test PRs (#390, #394, #395, #396, #397, #398, #399, #401, #387)
into a single PR, discarding 4 duplicates (#391, #392, #393, #400).

**New test coverage:**
- `id.test.ts` — 14 tests: Identifier generation, monotonic ordering, timestamp extraction, Zod schema
- `shell.test.ts` — 9 tests: shell blacklist enforcement for fish/nu, cache reset, fallback
- `path-traversal.test.ts` — 7 tests (new): `Protected.isSensitiveWrite` for .pem/.key, .gnupg, .env variants
- `ignore.test.ts` — 7 tests (new): `FileIgnore.match` directory patterns, globs, whitelist overrides
- `paths-parsetext.test.ts` — 16 tests: `ConfigPaths.parseText` env/file substitution, JSONC parsing
- `finops-formatting.test.ts` — 14 tests: `formatBytes`/`truncateQuery` edge cases
- `finops-role-access.test.ts` — 10 tests: RBAC `formatGrants`/`formatHierarchy`/`formatUserRoles`
- `tool-lookup.test.ts` — 4 tests: Zod schema introspection for tool parameters
- `summary-git-path.test.ts` — 10 tests: `unquoteGitPath` decoding for non-ASCII filenames
- `tracing.test.ts` — 2 tests (added): Recap loop detection boundaries
- `patch.test.ts` — 9 tests (added): `maybeParseApplyPatchVerified` entry point coverage
- `instruction.test.ts` — 13 tests (new): `InstructionPrompt.loaded()` dedup guards
- `message-v2.test.ts` — 23 tests (new): `MessageV2.filterCompacted()` boundary detection

**Bug fixes (discovered during testing):**
- `finops-formatting.ts`: fix `formatBytes` crash on negative/NaN/fractional inputs
- `finops-formatting.ts`: fix `truncateQuery` returning empty for whitespace-only, exceeding `maxLen` when < 4
- `training-import.test.ts`: fix pre-existing typecheck errors (missing `context`/`rule` mock keys)
- `instruction.test.ts`, `message-v2.test.ts`: fix `MessageV2.Part` cast and branded ID type errors

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: address code review findings — test artifact leakage and cleanup

- summary-git-path.test.ts: use tmpdir() instead of projectRoot to prevent
  Storage.write() from polluting the developer's .opencode/storage/ directory
- finops-role-access.test.ts: consolidate duplicate afterAll hooks to ensure
  ALTIMATE_TELEMETRY_DISABLED env var is cleaned up after tests

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants