Skip to content

Add symbol-name registry for predictable, collision-free generated file names - #59

Merged
Malcolmnixon merged 15 commits into
mainfrom
feature/symbol-name-registry
Oct 15, 2026
Merged

Malcolmnixon merged 15 commits into
mainfrom
feature/symbol-name-registry

Conversation

@Malcolmnixon

Copy link
Copy Markdown
Member

Summary

Replaces the ad-hoc FileNameSanitizer with a shared symbol-name registry so every generated file name is predictable, legal, and collision-free across .NET, C++ and VHDL. Follow-up to #58, which deferred the collision findings (Copilot review threads, including the high-severity A.B namespace vs. type collision).

How it works

  1. Every symbol that needs a file is registered (no filename assigned yet).
  2. Every name is resolved once, up front, with no collisions (case-insensitive).
  3. Writers and link resolvers only read the approved map. Names are escaped exactly once.

Predictable names come first ("primary name wins"); a -N suffix (starting at -2) is used only as a last resort. The complete numbered rules (NR-01..NR-20) are in docs/design/api-mark-core/file-naming-rules.md.

Highlights:

  • Namespaces are registered: namespace A { class B } vs namespace A.B -> namespace keeps A/B.md, the type becomes A/B-2.md; children move with the displaced parent.
  • Generic types use brace arity: Foo{1}, Foo{2} (was Foo-1).
  • Explicit interface members keep type arguments: IFoo{int}.Get, IPair{int-string}.Get.
  • Reserved pages (api, operators), Windows device names, case twins, and VHDL entity/package twins (Api/API) are all handled.
  • Illegal characters become _; invisible symbols are registered so names are stable across visibility settings.
  • FileMarkdownWriterFactory rejects illegal segments; LinkPath builds/escapes link destinations.

Breaking change

Generated file names change (Foo-1.md -> Foo{1}.md, case twins get separate pages, etc.). No legacy mode: output is regenerated each build and shipped with the package, so only link integrity matters (brief note in build notes).

Testing

  • New Core tests (registry, rules, link paths), per-language naming tests, and a DotNet synthetic-assembly suite with exact-name assertions.
  • Property-style tests: all paths unique (case-insensitive) and legal across large fixtures at all visibilities; every link resolves to a real file.
  • Scenarios from every Fix DotNet output regressions reported against 0.5.8 and add regression tests #58 review thread have explicit regression tests; ~14 deliberate mutations each fail at least one test.
  • Local: Core 242, DotNet 852 (net8/9/10), VHDL 101, Tool 132, MSBuild 68 pass. C++ clang tests and the vcxproj package test can't run locally (no clang); CI covers them.

Reviews

Code review: no findings. Formal reviews of all affected review-sets: PASS (after fixing uncovered files, IsLegalSegment/LinkPath.Escape vs NR-06/NR-19, and empty-key handling). lint.ps1 clean; reqstream --enforce has no orphans.

Known limits

  • Links to types in another mapped assembly use that type's predictable name (wrong only if that package displaced it with -N).
  • Brace/percent-encoded link destinations haven't been spot-checked on a live Markdown renderer.
  • Optional exceptions manifest not implemented.

Malcolm Nixon and others added 13 commits October 15, 2026 00:59
Single source of truth for generated file names: register all symbols,
resolve names once with tiered precedence and a last-resort -N suffix,
then read approved names.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…gistry

Namespaces, types, nested types, members and operators pages are registered
up front for the whole module (independent of visibility) and resolved once.
Generic types use brace arity (Foo{1}); explicit interface members keep type
arguments; case twins get separate pages; links read the approved names.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Update the api.md naming appendix and wording in test comments.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Add numbered naming rules, design and verification docs, requirements, SysML2
model, review set, user guide notes, and breaking change notes (Foo-1 -> Foo{1}).

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…on tests

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…ject empty registry key

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot AI lite review requested due to automatic review settings October 15, 2026 06:49

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

Unresolved critical API compatibility findings, implementation defects, and stale tests/documentation remain.

5 open findings
What changed in this PR

This PR adds centralized, collision-free generated-name handling for .NET, C++, and VHDL, replacing the legacy sanitizer.

Changes:

  • Adds shared symbol registry, filename rules, and link-path handling.
  • Updates emitters, generators, and link resolvers.
  • Refreshes tests, requirements, design, verification, and user documentation.
File Summary
test/​ApiMark.Vhdl.Tests/​VhdlFileNamingTests.cs VHDL filename tests
test/​ApiMark.Vhdl.Tests/​VhdlEmitterGradualDisclosureTests.cs VHDL disclosure naming tests
test/​ApiMark.Tool.Tests/​ProgramTests.cs Tool link expectation updates
test/​ApiMark.DotNet.Tests/​TypeLinkResolverTests.cs .NET link resolver tests
test/​ApiMark.DotNet.Tests/​DotNetGeneratorTests.cs .NET generator tests
test/​ApiMark.DotNet.Tests/​DotNetEmitterTests.cs .NET emitter tests
test/​ApiMark.DotNet.Tests/​DotNetEmitterInheritedMembersTests.cs Inherited-member tests
test/​ApiMark.DotNet.Tests/​DotNetEmitterGradualDisclosureTests.cs Disclosure and case-twin tests
test/​ApiMark.DotNet.Tests/​DotNetEmitterGradualDisclosureGenericsTests.cs Generic disclosure tests
test/​ApiMark.DotNet.Tests/​DotNetEmitterGenericNamingTests.cs Generic naming tests
test/​ApiMark.DotNet.Tests/​DotNetEmitterExternalSignatureTests.cs External signature tests
test/​ApiMark.DotNet.Tests/​DotNetEmitterExternalNestedLinkTests.cs External nested-link tests
test/​ApiMark.DotNet.Tests/​DotNetEmitterBreadcrumbTests.cs Breadcrumb tests
test/​ApiMark.Cpp.Tests/​CppTypeLinkResolverTests.cs C++ link resolver tests
test/​ApiMark.Cpp.Tests/​CppFixtureFileNamingTests.cs C++ fixture naming tests
test/​ApiMark.Cpp.Tests/​CppEmitterTests.cs C++ emitter tests
test/​ApiMark.Cpp.Tests/​CppEmitterGradualDisclosureTests.cs C++ disclosure tests
test/​ApiMark.Core.Tests/​LinkPathTests.cs Link-path tests
test/​ApiMark.Core.Tests/​FileNameSanitizerTests.cs Legacy sanitizer tests
test/​ApiMark.Core.Tests/​FileNameRulesTests.cs Filename rule tests
test/​ApiMark.Core.Tests/​FileMarkdownWriterFactoryTests.cs Writer validation tests
src/​ApiMark.Vhdl/​VhdlNames.cs VHDL name registry integration
src/​ApiMark.Vhdl/​VhdlEmitterGradualDisclosure.cs VHDL resolved-path emission
src/​ApiMark.Vhdl/​VhdlEmitter.cs VHDL registry-backed emission
src/​ApiMark.DotNet/​TypeNameSimplifier.cs Generic name formatting
src/​ApiMark.DotNet/​TypeLinkResolver.cs Approved .NET link paths
src/​ApiMark.DotNet/​DotNetGenerator.cs .NET name registration
src/​ApiMark.DotNet/​DotNetEmitterGradualDisclosure.cs .NET resolved-path emission
src/​ApiMark.DotNet/​DotNetEmitter.cs .NET registry-backed emission
src/​ApiMark.Cpp/​CppTypeLinkResolver.cs Approved C++ link paths
src/​ApiMark.Cpp/​CppNames.cs C++ name registry integration
src/​ApiMark.Cpp/​CppGenerator.cs C++ name registration
src/​ApiMark.Cpp/​CppEmitter.cs C++ registry-backed emission
src/​ApiMark.Core/​SymbolNameRegistry.cs Central collision-resolution registry
src/​ApiMark.Core/​LinkPath.cs Relative link construction
src/​ApiMark.Core/​FileNameSanitizer.cs Legacy sanitizer removal
src/​ApiMark.Core/​FileNameRules.cs Filename legality and escaping
src/​ApiMark.Core/​FileMarkdownWriterFactory.cs Approved-name validation
requirements.yaml Requirement registration updates
docs/​verification/​introduction.md Verification documentation updates
docs/​verification/​definition.yaml Verification definition updates
docs/​verification/​api-mark-dot-net/​type-name-simplifier.md .NET simplifier verification
docs/​verification/​api-mark-dot-net/​type-link-resolver.md .NET link verification
docs/​verification/​api-mark-dot-net/​dot-net-generator.md .NET generator verification
docs/​verification/​api-mark-dot-net/​dot-net-emitter-gradual-disclosure.md .NET disclosure verification
docs/​verification/​api-mark-cpp/​cpp-type-link-resolver.md C++ link verification
docs/​verification/​api-mark-cpp/​cpp-emitter.md C++ emitter verification
docs/​verification/​api-mark-cpp/​cpp-emitter-gradual-disclosure.md C++ disclosure verification
docs/​verification/​api-mark-core/​symbol-name-registry.md Registry verification
docs/​verification/​api-mark-core/​file-name-sanitizer.md Sanitizer verification updates
docs/​user_guide/​vhdl.md VHDL naming guidance
docs/​user_guide/​dotnet.md .NET naming guidance
docs/​user_guide/​cpp.md C++ naming guidance
docs/​sysml2/​model/​api-mark-core/​symbol-name-registry.sysml Registry model updates
docs/​sysml2/​model/​api-mark-core/​file-name-sanitizer.sysml Sanitizer model updates
docs/​sysml2/​model/​api-mark-core.sysml Core model updates
docs/​reqstream/​api-mark-vhdl/​vhdl-emitter-gradual-disclosure.yaml VHDL requirement traceability
docs/​reqstream/​api-mark-dot-net/​type-name-simplifier.yaml .NET simplifier traceability
docs/​reqstream/​api-mark-dot-net/​type-link-resolver.yaml .NET resolver traceability
docs/​reqstream/​api-mark-dot-net/​dot-net-emitter-gradual-disclosure.yaml .NET disclosure traceability
docs/​reqstream/​api-mark-dot-net.yaml .NET requirement updates
docs/​reqstream/​api-mark-cpp/​cpp-type-link-resolver.yaml C++ resolver traceability
docs/​reqstream/​api-mark-cpp/​cpp-emitter.yaml C++ emitter traceability
docs/​reqstream/​api-mark-cpp/​cpp-emitter-gradual-disclosure.yaml C++ disclosure traceability
docs/​reqstream/​api-mark-core/​symbol-name-registry.yaml Registry traceability
docs/​reqstream/​api-mark-core/​file-name-sanitizer.yaml Sanitizer traceability
docs/​reqstream/​api-mark-core.yaml Core requirement updates
docs/​design/​definition.yaml Design definition updates
docs/​design/​api-mark-vhdl/​vhdl-emitter.md VHDL emitter design
docs/​design/​api-mark-dot-net/​type-name-simplifier.md .NET simplifier design
docs/​design/​api-mark-dot-net/​type-link-resolver.md .NET resolver design
docs/​design/​api-mark-dot-net/​dot-net-emitter.md .NET emitter design
docs/​design/​api-mark-dot-net/​dot-net-emitter-gradual-disclosure.md .NET disclosure design
docs/​design/​api-mark-cpp/​cpp-type-link-resolver.md C++ resolver design
docs/​design/​api-mark-cpp/​cpp-emitter.md C++ emitter design
docs/​design/​api-mark-cpp/​cpp-emitter-gradual-disclosure.md C++ disclosure design
docs/​design/​api-mark-core/​symbol-name-registry.md Registry design
docs/​design/​api-mark-core/​file-naming-rules.md Filename rules
docs/​design/​api-mark-core/​file-name-sanitizer.md Sanitizer design updates
docs/​design/​api-mark-core/​file-markdown-writer-factory.md Writer factory design
docs/​design/​api-mark-core.md Core design updates
docs/​build_notes/​introduction.md Breaking filename change notes
.reviewmark.yaml Review coverage configuration

🧠 Review effort: Lite


💡 Configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread src/ApiMark.Core/FileNameRules.cs
Comment thread test/ApiMark.Cpp.Tests/CppEmitterGradualDisclosureTests.cs
Comment thread docs/design/api-mark-core/symbol-name-registry.md Outdated
Comment thread docs/reqstream/api-mark-cpp/cpp-emitter.yaml
Comment thread docs/verification/api-mark-cpp/cpp-emitter-gradual-disclosure.md
… registry and sanitizer removal

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot AI lite review requested due to automatic review settings October 15, 2026 13:11

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔵 Needs a closer look

Unresolved moderate findings affect filename length bounds, C++ namespace naming, and obsolete .NET collision handling; documentation consistency nits also remain.

0 open findings

5 resolved since last review
Previously missed (1)

In code that hasn't changed since last review

Low severity Update naming documentation to describe overload pages

docs/​design/​api-mark-dot-net/​dot-net-emitter-gradual-disclosure.md:406

The updated naming description removes the case-collision combined page, but the next bullets still document a Combined page keyed by a lower-cased member name. The .NET emitter now gives case twins separate registry-approved pages; this section should describe the overload page instead so the design document does not specify a page that is no longer emitted.

🧠 Review effort: Lite

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot AI lite review requested due to automatic review settings October 15, 2026 14:09

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔵 Needs a closer look

Three moderate findings and one nit remain unresolved.

0 open findings

🧠 Review effort: Lite

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.

2 participants