Skip to content

Fix legacy ID handling: accept occurrence IDs, hash verbatim - #5

Open
maximilliangeorge wants to merge 2 commits into
evanpurkhiser:mainfrom
maximilliangeorge:fix/legacy-repeating-instance-ids
Open

Fix legacy ID handling: accept occurrence IDs, hash verbatim#5
maximilliangeorge wants to merge 2 commits into
evanpurkhiser:mainfrom
maximilliangeorge:fix/legacy-repeating-instance-ids

Conversation

@maximilliangeorge

Copy link
Copy Markdown

Fixes #4

Problem

Histories that go back far enough contain IDs of the form <UUID>-YYYYMMDD (e.g. 5F3AE5FB-3FF3-49DE-BF34-91224AACC9FF-20170524), which early Things clients used for spawned occurrences of repeating tasks. They appear both as object keys and in relationship arrays (ts, rt). ThingsId::from_str rejected them, so the first log line containing one failed WireItem deserialization and every command aborted with:

Corrupt log entry at .../append-log/things.log byte 3224757: data did not match any variant of untagged enum OneOrMany

Same class of legacy-ID issue as #3.

Fix

ThingsId::from_str now recognizes the <UUID>-YYYYMMDD shape and canonicalizes it by SHA1-hashing the full uppercase string — the same scheme legacy UUIDs already use. Unlike the ACTIONGROUP- prefix, the date suffix is not stripped: the occurrence is a distinct entity from its template (it references the template via rt), so it must hash to its own distinct 16 bytes rather than collapsing into the template's ID.

Tests

  • Instance IDs parse, are case-insensitive, and stay distinct from their template and from other dates
  • serde deserialization of the suffixed form
  • Malformed suffixes are rejected (7/9 digits, non-digit characters, missing hyphen)
  • log_cache fold test seeded with the real-world entry shape

Verified against my real 12MB append log — previously aborted at byte 3224757, now folds cleanly. All unit tests pass; the 6 failing cli_trycmd snapshot tests fail identically on clean main in my environment, so they're unrelated.

🤖 Generated with Claude Code

Things Cloud histories from early clients contain IDs of the form
`<UUID>-YYYYMMDD` for spawned occurrences of repeating tasks. These
appear both as object keys and in relationship arrays, and failed
ThingsId parsing, so folding the append log aborted with "Corrupt log
entry" for affected accounts.

Parse the suffixed form by SHA1-hashing the full uppercase string, the
same scheme legacy UUIDs use. The suffix stays part of the hashed
identity: the occurrence is a distinct entity from its template (which
it references via `rt`), so it must not collapse into the template's ID
the way the `ACTIONGROUP-` prefix is stripped.

Fixes evanpurkhiser#4

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The server's compact-ID migration hashed each legacy ID string exactly
as written: histories reference an uppercase-keyed item by
base58(SHA1(uppercase string)) and a lowercase-keyed one by
base58(SHA1(lowercase string)). Case-normalizing to uppercase before
hashing therefore split a lowercase-keyed item from its own later
compact-keyed updates - in a real history the orphaned update was the
task's trash flag, so a trashed task kept showing up in Today.

Hash the verbatim string, making legacy UUID parsing case-sensitive to
match, and bump the state-cache version so stale folded caches rebuild.

Fixes evanpurkhiser#6

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@maximilliangeorge

Copy link
Copy Markdown
Author

Pushed a second commit fixing a related legacy-ID bug found right after: trashed items reappearing in Today (#6).

The server's compact-ID migration hashed legacy ID strings verbatim (verified against real history data: uppercase-keyed 35479CD2-…A8YNe3NdT4pgjEXRNnpMoh, lowercase-keyed 1d24677e-…Kaz7HNZURkT6J4Ws58kUjM), but ThingsId uppercased before hashing. That split lowercase-keyed items from their later compact-keyed updates — in my history the orphaned update carried the tr:true trash flag. The commit hashes verbatim, makes legacy UUID parsing case-sensitive to match, adds the real-world pairs as ground-truth test vectors, and bumps the state-cache version so stale folded caches rebuild.

@maximilliangeorge maximilliangeorge changed the title Accept legacy repeating-task occurrence IDs Fix legacy ID handling: accept occurrence IDs, hash verbatim Aug 27, 2026
@evanpurkhiser

Copy link
Copy Markdown
Owner

Did you reverse the things3 app to figure out how they translated these old IDs to new style IDs for compat?

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.

"Corrupt log entry" when history contains legacy repeating-task occurrence IDs (<UUID>-YYYYMMDD)

2 participants