Skip to content

Make Parse return value-canonical Subject Identifier form#23

Merged
hstern merged 2 commits into
mainfrom
subjid-32-canonical-parse-form
Jun 21, 2026
Merged

Make Parse return value-canonical Subject Identifier form#23
hstern merged 2 commits into
mainfrom
subjid-32-canonical-parse-form

Conversation

@hstern

@hstern hstern commented Jun 21, 2026

Copy link
Copy Markdown
Owner

What

Parse now returns the value form of a Subject Identifier (subjectid.IssSubID, never *IssSubID), so the dynamic type a caller reads back from Parse is identical to the struct literal they construct by hand.

Why

Registry constructors return pointers (&IssSubID{}) so the codec can populate them via UnmarshalJSON, but Parse leaked that pointer form. Since every behavior method has a value receiver, a caller naturally builds IssSubID{} but read back *IssSubID — a direct type assertion silently took the !ok branch on whichever form it didn't expect. The library's API now commits to one canonical dynamic form.

This is settled before the first v0.1.0 tag, so there is no released contract to break.

Changes

  • unmarshal.go — new reflection deref helper; Parse returns value form for built-ins, the UnknownFormat carrier, and nested aliases elements. deref falls back to the original pointer for a pointer-receiver extension type instead of panicking.
  • aliases.go — nested-aliases detection now uses Format() == "aliases" instead of a value type assertion. This fixes a latent bug: a nested aliases identifier arriving from the wire (pointer form) previously escaped ErrNestedAliases, while a hand-built value-form one was caught. New test TestParseNestedAliasesFromWireRejected covers it.
  • subjectid.go / registry.go — godoc documents the canonical value form and the extension-type value-receiver constraint.
  • opaque.go / unknown.go — compile-time assertions switched to value form, matching the other six built-ins, so a future pointer-receiver regression fails to compile.
  • Tests — pointer-form assertions migrated to value form; new canonical_form_test.go.

Verification

gofmt clean · go vet clean · golangci-lint 0 issues · go test -race ./... green.

🤖 Generated with Claude Code

hstern and others added 2 commits June 21, 2026 13:08
Registry constructors return pointers so the codec can populate them
via UnmarshalJSON, but Parse previously leaked that pointer form. A
caller constructs identifiers as value literals (IssSubID{}) yet read
them back as *IssSubID, so a direct type assertion silently took the
!ok branch on whichever form it did not expect.

Normalize Parse to the value form: a reflection-based deref dereferences
the populated pointer before returning, applied to the built-ins, the
UnknownFormat carrier, and every nested aliases element. deref falls
back to the original pointer for an extension type registered with
pointer-receiver methods rather than panicking. Parse and the
SubjectIdentifier interface godoc now document the canonical value form
and the extension-type value-receiver constraint.

Also make AliasesID.Validate detect nesting by the format discriminator
(Format() == "aliases") instead of a value type assertion. The old
check missed a nested aliases identifier arriving from the wire, which
Parse populates in pointer form, so ErrNestedAliases silently failed to
fire on real input; a hand-built value-form nested alias was still
caught. Switch the OpaqueID and UnknownFormat compile-time assertions
to value form to match the other built-ins.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Record the initial 0.1.0 API surface and the 0.2.0 value-canonical
Parse change, replacing the stale pre-release "no public API yet" note.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@hstern hstern merged commit 5fa756f into main Jun 21, 2026
4 checks passed
@hstern hstern deleted the subjid-32-canonical-parse-form branch June 21, 2026 16:14
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