Skip to content

id(petname): Petnames::open replays journal records verbatim — names set() refuses (fold-duplicates, Cf chars, overlong) load unchecked #5225

Open

Description

@dezren39

Problem

Petnames::open (pkgs/id/crates/id-core/src/petname.rs:59) replays petnames.jsonl through apply (petname.rs:196-209), which inserts each Record::Set name verbatim. The write path, Petnames::set (petname.rs:128-163), refuses:

  • names that fail normalize_name — empty, longer than 64 chars, or containing control/format (Cf) characters (petname.rs:262-278);
  • a name whose fold equals another contact's petname for the same owner (Conflict);
  • a name whose UTS Bump checkmarx/ast-github-action from 2.0.19 to 2.0.20 #39 skeleton matches another contact's petname or a directory-alleged account name (the anti-mimicry guard the module doc states as its purpose: "the store refuses a petname that could be taken for someone else's name").

None of those invariants are re-checked at load. A journal written by an older build, a hand edit, a partial restore, or another writer therefore loads state the store itself would never create: two contacts of one owner holding fold-equal petnames (PayPal / paypal), a petname carrying U+200B, or an 80-char name — and the display/labels path consumes them as if they had passed the guards.

Evidence (verified this run, origin/main a51be0e)

Probe test on the laptop (worktree of origin/main, cargo test -p id-core --test probe_petname_load): a hand-written journal with four set records — fold-duplicate names for two accounts, a name containing U+200B, and an 80-char name — loads with all four records present verbatim; Petnames::open returns Ok.

This is the same shape as #5179 / PR #5190, where Registry::load for publications was fixed to validate persisted records against publish() invariants at load. The petname store was not covered by that fix. Related audits: #2898 Phase 3 and #4001 both name "directory/petname persistence restores" in their closing-inventory scope — this issue is the concrete, reproduced instance for the petname store and can serve as that inventory's named follow-up for this seam.

Note the deliberate legacy tolerance in the comparison paths (fold/skeleton strip Cf "so a name stored with one (before they were refused) cannot spoof by the comparison path", petname.rs:236-243): the fix must disposition legacy stored names explicitly — fail-loud like the publications registry, quarantine-with-warning, or normalise — rather than silently breaking existing journals.

Acceptance criteria

  • Petnames::open dispositions every replayed Set record against the set() invariants (normalisability, per-owner fold uniqueness, per-owner skeleton uniqueness), with the chosen behaviour for violations (error naming the line / skip-with-warning / normalise) stated in the module doc.
  • The alleged-name skeleton check that needs directory state is either applied where the directory is available at open time or explicitly documented as a load-time exemption with the reason.
  • Tests: journal with fold-duplicate names, a Cf-carrying name, and an overlong name each produce the documented disposition; a journal written by current set() calls reopens unchanged.
  • Existing petname tests stay green (laptop or CI).

🤖 Filed by new-issue-creator-code-a (lane A), 2026-11-03.

Activity

  1. added
    kind/bugSomething isn't working (prefixed form of the classic bug label)
    task/triageQueue packet kind: verify, reproduce, and route this item
    source/creatorFiled by the new-issue-creator job
    priority/normalOrdinary priority (the default)
    queue/queuedHas a queued task in the Supabase agent queue
    app/idPackage/app: id (pkgs/ or apps/ in this repo)
    on Nov 4, 2026
  2. dezren39 commented on Nov 4, 2026

    @dezren39
    MemberAuthor

    🤖 Agent note · filed

    • Agent: new-issue-creator job, lane A (new-issue-creator-code-a)
    • Session / ID: new-issue-creator-code-a cron run, 2026-11-04T01:00:56Z
    • Found via: filed this run
    • Task: Filed this issue: Petnames::open replays journal records verbatim, bypassing the set() invariants (verified by a passing probe test on the laptop against origin/main a51be0e). Enqueued as a triage packet on repo-health-code-pilot.
    • Expectation: effort s–m; done = load-time disposition of replayed records against the set() invariants, documented in the module doc, with tests (see acceptance criteria on the issue).
    • Links: body file hidden_files/petname-load-validation-body.md (goal workspace); probe: laptop ~/git/fleet/probe-petname-load (tests/probe_petname_load.rs)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

app/idPackage/app: id (pkgs/ or apps/ in this repo)kind/bugSomething isn't working (prefixed form of the classic bug label)priority/normalOrdinary priority (the default)queue/queuedHas a queued task in the Supabase agent queuesource/creatorFiled by the new-issue-creator jobstatus/needs-triageNot yet triaged; needs a first looktask/triageQueue packet kind: verify, reproduce, and route this item

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions