Files
archy/.planning/phases/10-key-material-hardening/deferred-items.md
T

2.1 KiB

Deferred items — Phase 10

Out-of-scope discoveries found while executing this phase. Logged, not fixed.

From 10-01 (KEY-01 / F-01)

Flaky test: credentials::operations::tests::test_list_credentials_no_filter

  • Discovered: 2026-08-02, during the post-plan full-suite run (cargo test -p archipelago).
  • Symptom: called Result::unwrap() on an Err value: UTF-8 credentials / invalid utf-8 sequence of 1 bytes from index 3.
  • Root cause (read, not fixed): credentials/store.rs:29 sniffs the FIRST BYTE of the stored blob for [ or { to distinguish a plaintext-JSON legacy store from the encrypted binary one. When the encrypted ciphertext happens to begin with 0x5B or 0x7B — about a 1-in-128 chance per run — the encrypted store is misread as plaintext and String::from_utf8 fails. This is a real bug in the migration sniffing, not just a test problem: a real node whose credential ciphertext starts with one of those bytes cannot load its credentials.
  • Why deferred: unrelated to KEY-01, different subsystem, untouched by this plan (git status shows credentials/ unmodified). Fixing it means adding a format marker or version header to the store, which is an envelope change.
  • Suggested fix: prepend an explicit magic/version byte on write and branch on that, keeping the first-byte sniff only as the legacy fallback.
  • RESOLVED 2026-08-02 — fixed along the suggested lines, with one improvement. Writes are now prefixed with a fixed ARCHYCRED1 marker, which cannot collide with a random nonce. Legacy unmarked files are detected by successful AEAD decryption rather than by a byte sniff: a Poly1305 tag that verifies under the node key is a cryptographic discriminator (~2^-128 false positive), strictly stronger than the structural sniff the fallback would have kept. Plaintext JSON stays the last resort, and an undecodable file now errors instead of silently becoming an empty store that the next save would overwrite. Legacy files upgrade on write, never on read. Regression tests drive the collision deterministically via an explicit nonce (0x5B/0x7B) instead of waiting on the 1-in-128 draw.