Skip to content

feat(irverify): hold Naming.Aliases to a rule - #361

Open
OmarAlJarrah wants to merge 1 commit into
mainfrom
feat/irverify-alias-invariants
Open

feat(irverify): hold Naming.Aliases to a rule#361
OmarAlJarrah wants to merge 1 commit into
mainfrom
feat/irverify-alias-invariants

Conversation

@OmarAlJarrah

Copy link
Copy Markdown
Member

Summary

Naming has four channels and irverify read three. Source, Canonical and
Hint are read by checkNaming; Aliases was read by nothing anywhere in the
pipeline — it appeared in production code exactly once, at its own declaration:

$ grep -rn "Aliases" --include='*.go' ir/ pass/ compilers/ engine/ | grep -v _test.go
ir/naming.go:28:  // Aliases are alternate names for schema-resolution matching (Avro
ir/naming.go:31:  Aliases []string `json:"aliases,omitempty"`

So a model whose aliases were cased, punctuated, empty and duplicated verified
clean and validated clean.

Which rules an alias is held to

The issue flagged this as the thing to settle before writing any check, and
warned against applying Canonical's rules unexamined. The answer is that they
do not apply.

An alias is matched against a name some other schema wrote. An Avro alias is
a full name such as com.example.User, and resolution compares it verbatim
against the writer schema's full name. Neutralizing it to a word sequence
discards the separators and the casing the match is made of — com.example.User
and com_example_user are not the same key, and only one of them matches. So an
alias is a verbatim channel like Source, not a neutral one like Canonical.
Source is the internal precedent: it carries UserID today and no content rule
touches it, because it records what the spec said rather than deciding a
spelling. Invariant #4 governs names the IR decides; invariant #2 forbids the
lossy normalization holding an alias to Canonical's grammar would require.

What is left is decidable without any grammar, and is what this check makes:

  • ir/naming-alias-empty — an empty alias matches nothing.
  • ir/naming-alias-duplicate — a repeated alias matches twice.

Neither can be what a producer intended; both say a list was built wrong rather
than that a name was spelled wrong. Each violation's path names the offending
entry (doc.Types[t/x/M].Name.Aliases[2]), spelled the way the walk would have
reached it, so a violation on a list of several says which one.

ir/naming.go's field comment now states what a well-formed entry looks like.
Before this it documented what the field is for and nothing about what may go
in it, which is why the question had to be re-derived to answer the issue.

Test plan

Seven tests in ir/irverify, including the issue's exact reproducer. Each rule
was confirmed to redden against a planted defect:

  • Replacing the appendAliasViolations call with _ = aliases fails the empty
    and duplicate tests with "[]" should have 1 item(s), but has 0.
  • Inverting the duplicate predicate to report first occurrences fails with
    should have 1 item(s), but has 3, naming Aliases[0], [1] and [2].
  • Applying Canonical's grammar to aliases fails
    TestVerify_VerbatimAliasesAreClean with two violations on
    com.example.User and UserID — so the settlement above is pinned by a test,
    and a later attempt to tighten it has to argue with that test rather than slip
    through.

TestVerify_RepeatedEmptyAliasReportsEachAsEmpty holds the interaction between
the two rules: a second empty entry is a repeat as well, and reporting it as a
duplicate would name the wrong repair.

Coverage note, stated rather than implied: no compiler in the tree writes an
alias yet, so no committed fixture reaches this check. That is the expected
state — the rule exists so the first compiler that does write one (Avro,
Protobuf json_name alternates) is held from its first commit — and the unit
fixtures above are what exercise it.

Full gate green: gofmt, go vet ./..., golangci-lint run (0 issues),
go build ./..., ./scripts/check-coverage.sh (all 4958 statements covered).

Closes #317

Naming has four channels and irverify read three. Aliases was read by
nothing anywhere in the pipeline -- it appeared in production code
exactly once, at its own declaration -- so a model whose aliases were
empty and duplicated verified clean and validated clean.

Which rules apply had to be settled first, and the answer is not
Canonical's. An alias is matched against a name some other schema wrote:
an Avro alias is a full name such as com.example.User, and neutralizing
it to words discards the separators and the casing the match is made of.
That makes it a verbatim channel like Source rather than a neutral one
like Canonical, and holding it to the neutrality rules would be the
lossy direction invariant 2 forbids. The IR is not deciding this
spelling, it is recording one.

What is left is decidable without a grammar. An empty alias matches
nothing and a repeated one matches twice, so neither can be what a
producer intended: both say a list was built wrong rather than that a
name was spelled wrong. checkNaming reports each as its own violation,
at a path naming the offending entry, and the field's doc comment now
states what a well-formed entry looks like instead of only what the
field is for.
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.

irverify: Naming.Aliases is held to no rule at all

1 participant