Skip to content

M2 follow-ups: related spans, stability registry, corpus coverage (#302, #304, #305)#307

Merged
cssbruno merged 2 commits into
mainfrom
codex/m2-followups
Jun 11, 2026
Merged

M2 follow-ups: related spans, stability registry, corpus coverage (#302, #304, #305)#307
cssbruno merged 2 commits into
mainfrom
codex/m2-followups

Conversation

@cssbruno

Copy link
Copy Markdown
Owner

Follow-up to #300. After reviewing the six follow-up issues I'd filed, I closed two and implemented the three that hold up.

Issue triage first

Implemented

#302 — Related spans on more duplicate diagnostics

Extended the "first declared here" related location (added in #300) to duplicate_page_id, duplicate_layout_id, duplicate_page_store, duplicate_component_name, duplicate_component_emit, and both duplicate_gowdk_use_alias sites. Left duplicate_route_param (no per-segment span) and duplicate_css_selection (spanForName returns the first match) nil, per the issue's "leave nil when unavailable" hedge.

#305 — Code-level construct stability registry

Added lang.ConstructStabilities() — a code registry of stability tiers for blocks, metadata keywords, g: directives, and endpoint forms (mirroring the diagnostics registry's Stability). Two guard tests: one asserts the registry covers every keyword/directive in code, the other asserts docs/language/stability.md matches the registry. Neither the table nor the registry can drift now.

#304 — Conformance corpus coverage

Added build-data, planned-directive, foreign-template, and legacy-metadata cases, plus TestConformanceCorpusCoversRejectionContracts which fails when a parser-surfaced rejection contract loses its reject case. Honest finding documented: markup rejections (g:await, {#if}) currently surface as generic parse_error, not their specific codes — those cases pin parse_error and will ratchet to the specific code when markup diagnostics are wired (tracked with #250).

Not in this PR

#306 (full tokenizer + recursive-descent parser rewrite) is the keystone but it's a genuine multi-phase effort — shared tokenizer, recovery, AST-equivalence gating, per-declaration cutover. Cramming it in here would be reckless; it stays open as the dedicated next effort, with #301's offset work folded in.

Verification

  • go test ./internal/... ./cmd/... . — all pass
  • gofmt -l + go vet — clean
  • node --test editors/vscode/*.test.js — 39 pass / 0 fail

🤖 Generated with Claude Code

Follow-up work on the M2 compiler/language-contract issues, after closing
#301 (folded into #306) and #303 (false positive: the LSP single-document
check can never surface a cross-file related location).

- #302: extend related "first declared here" spans to duplicate_page_id,
  duplicate_layout_id, duplicate_page_store, duplicate_component_name,
  duplicate_component_emit, and both duplicate_gowdk_use_alias sites. Left
  duplicate_route_param (no per-segment span) and duplicate_css_selection
  (spanForName returns the first match) nil per the issue's hedge.
- #305: add a code-level construct stability registry (lang.ConstructStabilities)
  covering blocks, metadata keywords, g: directives, and endpoint forms, with
  tests asserting the registry covers the code construct-sets and that
  docs/language/stability.md matches the registry.
- #304: expand the conformance corpus with build-data, planned-directive,
  foreign-template, and legacy-metadata cases, and add a coverage test that
  fails when a parser-surfaced rejection contract loses its reject case. Markup
  rejections currently surface as parse_error (tracked); their cases pin that
  and ratchet to specific codes later.

Tests: go test ./internal/... ./cmd/... . all pass; gofmt/vet clean; node
editor tests pass (39).

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 7df9007f58

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread internal/lang/stability.go Outdated
Comment on lines +80 to +82
{Name: "g:slot", Kind: ConstructDirective, Tier: TierPartial},

// Planned g: directives, rejected on use.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Include directive families in stability registry

Because this registry is introduced as the code-level source of truth for g: directive stability, omitting the accepted directive families makes consumers classify valid syntax as unknown. internal/view/directives.go accepts any g:on:* and the four g:message:* rules, and docs/language/stability.md documents both as Partial, but ConstructStabilities() ends the supported directive list without entries for those families; the guard test also won't catch this because SupportedDirectiveNames() explicitly excludes them. Add family-level entries such as g:on:* and g:message:* or derive/check those families alongside the exact-name directives.

Useful? React with 👍 / 👎.

Comment thread internal/lang/stability.go Outdated
{Name: "g:document", Kind: ConstructDirective, Tier: TierPlanned, DiagnosticCode: "unsupported_markup_directive"},
{Name: "g:body", Kind: ConstructDirective, Tier: TierPlanned, DiagnosticCode: "unsupported_markup_directive"},
{Name: "g:head", Kind: ConstructDirective, Tier: TierPlanned, DiagnosticCode: "unsupported_markup_directive"},
{Name: "g:await", Kind: ConstructDirective, Tier: TierPlanned, DiagnosticCode: "unsupported_markup_directive"},

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Register the diagnostic code actually emitted

For planned g: directives that are checked through lang.CheckSource, this DiagnosticCode does not match the diagnostic users receive: the new planned_directive.gwdk conformance case still expects parse_error, and internal/lang/tools.go falls back to parse_error unless the parser returns a typed diagnostic. Tooling that consumes ConstructStabilities() to know which rejection code to expect will therefore look for unsupported_markup_directive and miss the actual diagnostic until markup errors carry typed codes; either leave this unset/use parse_error for now, or wire the specific parser diagnostic before advertising it here.

Useful? React with 👍 / 👎.

Comment thread internal/lang/stability_doc_test.go Outdated
Comment on lines +61 to +62
if !strings.Contains(doc, construct.Name) {
t.Errorf("construct %q (%s) is missing from %s", construct.Name, construct.Kind, path)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Match stability entries exactly

This check uses a raw substring search, so it does not reliably prove the stability table contains a construct row. Short construct names like go, act, and api can be removed from their table rows while the test still passes because those strings appear in unrelated prose or inside other words such as diagnostics and contract, which defeats the drift guard this commit adds. Match the documented backticked construct/table cell instead of any substring.

Useful? React with 👍 / 👎.

- Include the accepted g: directive families g:on:* and g:message:* in
  lang.ConstructStabilities(); SupportedDirectiveNames() excludes them, so the
  registry would otherwise classify valid syntax as unknown. A test guards them
  against removal.
- Stop advertising unsupported_markup_directive for planned g: directives: that
  code is registered but never emitted, so users actually receive parse_error
  (proven by the conformance corpus). DiagnosticCode is left unset for planned
  directives, and the table documents the parse_error reality.
- Match the stability table by exact backticked tokens instead of raw substring,
  so short construct names (go, act, api) can no longer pass by appearing inside
  unrelated prose; registry block names align to their backticked `{}` forms and
  the endpoint table lists bare `act`/`api`/`fragment`.

Tests: go test ./internal/... ./cmd/... . all pass; gofmt/vet clean.
@cssbruno cssbruno merged commit 5ae8aa3 into main Jun 11, 2026
5 checks passed
@cssbruno cssbruno deleted the codex/m2-followups branch June 11, 2026 21:32
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.

[Compiler] Resolve cross-file related-location URIs in LSP relatedInformation [Compiler] Populate byte offsets from the parser front-end

1 participant