feat(pxe)!: Add AppTaggingSecret kinds to keys in tagging stores#24604
Merged
vezenovm merged 8 commits intoJul 9, 2026
Conversation
Drop the legacy two-part unconstrained AppTaggingSecret key format (`secret:app`) so every persisted tagging-store key uses the uniform self-describing `kind:secret:app` form. `toString()` always emits the kind prefix and `fromString()` only accepts the three-part form, rejecting legacy keys. Because PXE tagging stores key their KV maps by `AppTaggingSecret` strings, this is a breaking on-disk change. Rather than a dual-read / self-healing path, bump `PXE_DATA_SCHEMA_VERSION` 12 -> 13; the version manager wipes any DB with a mismatched schema on open, so legacy keys never reach the new parser and legacy/prefixed keys cannot coexist. Note this wipe resets the entire PXE DB (notes, contracts, keys, tips, facts, tagging), so existing wallets re-sync from genesis on upgrade. Covers F-680.
Document the PXE data schema bump (12->13) and full PXE DB wipe in migration_notes.md. Rename PRE_F680_PXE_SCHEMA_VERSION -> PRE_KIND_PREFIXED_TAGGING_KEY_PXE_SCHEMA_VERSION and reword its comments to drop the Linear issue reference from source, mirroring the sibling constant.
This was referenced Jul 8, 2026
…tests (#24615) Stacked on #24604. Extracts the duplicated schema-mismatch DB-wipe ceremony in the PXE storage compatibility suite into one helper. The two "wipes rows written under schema vN" tests (the key-store removal at the schema-10 boundary, and the tagging-store key-format migration at the schema-12 boundary added earlier in this stack) were near-identical boilerplate: make a temp dir + `pxe_data` config, open the store at the old schema version, seed a legacy row, close, reopen at the current `PXE_DATA_SCHEMA_VERSION` (which makes `DatabaseVersionManager` wipe the mismatched DB on open), assert the row is gone, then remove the temp dir. `expectStoreWipedOnUpgradeFrom(oldSchemaVersion, tmpDirPrefix, seedLegacyRows, assertWiped)` now owns that lifecycle, so each test spells out only its own legacy write and post-wipe assertion, and the next schema-bump wipe test is a few lines rather than a copy of the whole dance. The shared "wipes on version mismatch" explanation moves into the helper's JSDoc; each test comment stays focused on its own assertion.
…-trip The unconstrained round-trip test pinned the literal kind:secret:app format, duplicating what the PXE schema-compat per-store snapshots already fingerprint for real stored keys. Leave format pinning to those snapshots; keep the round-trip test focused on serialize/deserialize identity and kind preservation.
mverzilli
approved these changes
Jul 9, 2026
mverzilli
left a comment
Contributor
There was a problem hiding this comment.
Looks good! I'm now working on changing the behavior on version/rollup change, the wipe out is a bit excessive, so some of the assumptions here will be outdated soon. But we can deal with that once that's done.
…e snapshots (#24614) Stacked on #24604. Adds a `constrained`-kind `AppTaggingSecret` to the Recipient and Sender tagging-store schema fixtures so the backwards-compatibility snapshots pin both the `constrained:` and `unconstrained:` key prefixes side by side. Previously the fixtures only used default (unconstrained) secrets. The constrained secret lands in all four persisted maps (recipient aged/finalized, sender pending/last-finalized).
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes F-680
What changed
Migrates PXE tagging-store keys off the legacy two-part
AppTaggingSecretstring format (secret:app) so every persisted key uses the uniform self-describingkind:secret:appform.AppTaggingSecret.toString()now always emitskind:secret:app(the unconstrained special case that emitted the legacy two-part key is gone).AppTaggingSecret.fromString()only accepts the three-part form; a two-part legacy key now throws instead of parsing.PXE_DATA_SCHEMA_VERSION12 → 13.Migration strategy (breaking)
Since the general PXE migration framework does not exist, and per the issue discussion, this cuts over via the schema-version bump rather than a dual-read / self-healing path.
initStoreForRollupAndSchemaVersionwipes any DB whose stored schema version differs from the current one on open, so a DB written with legacy keys is cleared before the new parser ever reads it.Blast radius: the wipe resets the entire PXE DB (addresses, notes, contracts, key store, L2 tips, facts, and tagging), not just tagging data, because they share one backing KV store. Existing wallets re-sync from genesis after upgrade. This is inherent to any
PXE_DATA_SCHEMA_VERSIONbump.Tests
app_tagging_secret.test.ts: pins the new three-part unconstrainedtoString(), adds a "rejects the legacy two-part format" case, drops the now-redundant kind-prefixed-unconstrained test.pxe_db_compatibility.test.ts: adds a pre-migration wipe test that writes a raw legacy two-part key at schema v12, reopens at v13, and asserts the raw map is empty (it asserts raw map contents rather than a high-level getter, which would false-pass since a new three-parttoString()never reconstructs a legacy key).