Skip to content

fix(managedstream): add stored timestamp cursor keys#266

Closed
michiosw wants to merge 1 commit into
mainfrom
feat/managedstream-stored-timestamp-cursor
Closed

fix(managedstream): add stored timestamp cursor keys#266
michiosw wants to merge 1 commit into
mainfrom
feat/managedstream-stored-timestamp-cursor

Conversation

@michiosw

@michiosw michiosw commented Jun 8, 2026

Copy link
Copy Markdown
Contributor

Where We Are

Katana managed observe can still fail hosted ingest when legacy ledger rows contain timestamps without a timezone, like 2026-06-08T12:20:07.853885. Hosted expects offset-aware timestamps, so those rows turn into 400 responses.

Where We Want To Go

Managed observe should upload the same ledger rows with valid UTC timestamps and keep cursor pagination stable. It must not skip rows, leak internal cursor fields into the payload, or rely on SQLite timestamp rounding.

How do we get there

This adds a stored Go-computed updated_at cursor key, backfills it during SQLite migration, uses it for bounded cursor filtering, and normalizes exported *_at fields to RFC3339 UTC. Covered by focused ledger/managed-stream tests and verified with go test -count=1 ./internal/guard/store/sqlite ./internal/managedstream plus go test ./...

michiosw commented Jun 8, 2026

Copy link
Copy Markdown
Contributor Author

This stack of pull requests is managed by Graphite. Learn more about stacking.

@greptile-apps

greptile-apps Bot commented Jun 8, 2026

Copy link
Copy Markdown

Greptile Summary

This PR updates managed stream ledger exports to use stable timestamp cursor keys. It changes:

  • Adds updated_at_cursor_key to authorization actions and backfills it during migration.
  • Uses the stored cursor key for action pagination and persisted managed-stream state.
  • Normalizes exported ledger timestamp fields to RFC3339 UTC.
  • Adds focused tests for legacy timestamps, cursor pagination, and managed stream state parsing.

Confidence Score: 3/5

This is close, but the legacy bad-timestamp path should be fixed before merging.

  • A migrated row with an unparseable updated_at can still stop managed observe during export.
  • The main cursor-key path and payload normalization look otherwise focused and covered by tests.
  • No security-specific issue was found in the changed code.

internal/guard/store/sqlite/ledger.go

Important Files Changed

Filename Overview
internal/guard/store/sqlite/ledger.go Adds cursor-key pagination and timestamp normalization, but still parses raw fallback cursor keys during export.
internal/guard/store/sqlite/store.go Adds and backfills updated_at_cursor_key, including raw fallback values for unparseable legacy timestamps.
internal/managedstream/stream.go Persists and reloads managed-stream cursor timestamps using the normalized cursor-key format.

Reviews (2): Last reviewed commit: "fix(managedstream): add stored timestamp..." | Re-trigger Greptile

Comment thread internal/guard/store/sqlite/store.go Outdated

@chatgpt-codex-connector chatgpt-codex-connector 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: aa28484a7c

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread internal/guard/store/sqlite/ledger.go Outdated
@michiosw michiosw force-pushed the feat/managedstream-stored-timestamp-cursor branch 2 times, most recently from aa8281e to 17d7e2f Compare June 8, 2026 13:28

@chatgpt-codex-connector chatgpt-codex-connector 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 17d7e2f431

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread internal/guard/store/sqlite/ledger.go Outdated
query := authorizationActionsSelectWithCursorKey()
args := []any{}
if opts.UpdatedAfter != nil {
updatedAfter := opts.UpdatedAfter.UTC().Format(time.RFC3339Nano)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Normalize fallback cursor key before filtering

When a caller provides UpdatedAfter without the new UpdatedAfterKey, this fallback still formats exact-second cursors as RFC3339Nano like 2026-06-08T12:20:07Z. The query now compares that text to fixed-width updated_at_cursor_key values such as 2026-06-08T12:20:07.000000000Z and .100000000Z; because . sorts before Z, updated_at_cursor_key > ? skips all later fractional rows in the same second. Managed stream supplies a key, but the store API still supports UpdatedAfter-only callers, so the fallback should use the fixed cursor-key layout as well.

Useful? React with 👍 / 👎.

@michiosw

michiosw commented Jun 8, 2026

Copy link
Copy Markdown
Contributor Author

@greptileai review

Comment on lines +164 to 166
updatedAt, err := parseLedgerTimestamp(updatedAtKey)
if err != nil {
return nil, err

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Bad cursors still block export

backfillAuthorizationActionCursorKeys now tolerates an unparseable legacy updated_at by storing the raw value as updated_at_cursor_key, but this path later parses that same key and returns the error. For a migrated row like the new act_bad_timestamp fixture, OpenStore succeeds, then LedgerBatch fails with invalid timestamp "not-a-timestamp" as soon as that row is selected for the cursor. Managed observe still stops before uploading any rows, so the lockout moves from migration time to export time.

@michiosw michiosw force-pushed the feat/managedstream-stored-timestamp-cursor branch from 17d7e2f to 6967a4e Compare June 8, 2026 13:34
@michiosw michiosw closed this Jun 8, 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.

1 participant