Skip to content

pxf: @entry directive + zero-or-more named-directive prefix list - #16

Merged
trendvidia merged 3 commits into
mainfrom
pxf-entry-directive
May 11, 2026
Merged

pxf: @entry directive + zero-or-more named-directive prefix list#16
trendvidia merged 3 commits into
mainfrom
pxf-entry-directive

Conversation

@trendvidia

Copy link
Copy Markdown
Owner

Summary

  • Generalizes named_directive from [ identifier ] to { identifier } (zero-or-more prefix identifiers). Any v0.72.0-valid named directive still parses; the change is strictly additive.
  • Registers @entry (new draft §3.4.3) as the canonical PXF shape for bundling heterogeneous typed sub-messages — four permitted shapes covering anonymous/labeled × typed/typeless. Dot-disambiguation rule: dotted prefix → type; bare → label.
  • Editor support: VS Code TM grammar grows a named-directive pattern (dotted = type, bare = tag); JetBrains bundle regenerated.

Stacking

Based on pxf-reserved-names (PR #15). The new §3.4.3 cross-references §3.13 (reserved-name constraint), so this lands after PR #15 merges. GitHub auto-rebases the base on merge.

Tradeoffs / open items

  • Port coordination: every port must change named_directive from "accept one optional identifier" to "loop accepting identifiers until { or end-of-directive" — ~1 LoC in most ports. Plus consumer-layer enforcement of @entry's 0–2 cardinality cap. First-port companion PR lands on protowire-go.
  • Disambiguation rule ("dotted = type, bare = label") is the simplest stable rule that doesn't require lookahead beyond a single token. The alternative — require an explicit two-prefix form (@entry "" some.Type) — is uglier. Worth re-litigating only if real users hit edge cases (e.g. wanting a dotted label).
  • Cardinality enforcement split: the grammar accepts arbitrary prefix identifiers; §3.4.3 caps @entry specifically at two. That's a deliberate two-layer split — the grammar generalizes, individual registrations constrain. Documented in §3.4.2 conformance bullets.
  • IETF draft pagination drift compounds with PR pxf: reject schemas using PXF-reserved names (null/true/false) #15's drift; both want a re-pagination pass before submission.

Test plan

  • go build ./... — clean
  • Spec parses by inspection (no contradicting clauses between §3.3, §3.4.2, §3.4.3, §3.13)
  • testdata/example-entries.pxf exercises all four @entry shapes
  • VS Code TM grammar regex compiles (verified via sync_jetbrains_grammar.py which round-trips through plistlib)
  • Manual: open testdata/example-entries.pxf in VS Code with the local extension and verify highlighting on @entry, the optional label, and the dotted type
  • Manual: build the JetBrains plugin and verify highlighting parity (deferred — protowire-pxf.jar refresh sequenced into release-cut PR)

Enum value, message field, and oneof names that are case-sensitively
equal to `null`, `true`, or `false` lex as PXF value keywords, making
them unreachable from PXF surface syntax — `field = null` always
resolves to the null-literal branch, and an enum value literally
named `null` can never be selected by name. Protobuf does not reserve
these identifiers, so today the trap is silent.

Spec: new draft §3.13 "Schema Constraints" with MUST-language; ABNF
`directive-name` widened to exclude `null`/`true`/`false` alongside
`type`; grammar.ebnf gets a matching Schema Constraints notes block.

Tooling: a single shared `internal/pxfschema` package exposes
`ValidateReflect` (protoreflect) and `ValidateProto` (descriptorpb)
so every binary in this repo inherits the check at descriptor-bind.
`protoc-gen-pxf-java-meta` rejects in `generateFile`; `protowire`
gains a `lint` subcommand for standalone use.

Fixtures under `testdata/lint/` confirm protocompile accepts these
names (i.e. the trap is real) and that the case-sensitive rule
correctly accepts uppercase variants like `NULL`/`True`/`FALSE`.

IETF draft pagination downstream of §3.13 has drifted; re-paginate
before submission. Companion port PRs (protowire-go first) must
add the equivalent check at their bind layer.
Generalizes `named_directive` from one optional prefix identifier to
zero-or-more, then registers `@entry` as the first in-spec-defined
named directive — the canonical PXF shape for bundling heterogeneous
typed sub-messages alongside (or in place of) a document body.

Four shapes are permitted:

  @entry { ... }                       ; anonymous, typeless
  @entry name { ... }                  ; labeled, typeless
  @entry some.pkg.Type { ... }         ; typed only (dotted ident)
  @entry name some.pkg.Type { ... }    ; labeled and typed

The fourth disambiguates from the second by the presence of "." in
the prefix identifier: dotted = type, undotted = label.

Wire format unchanged. Strictly additive — any v0.72.0-valid named
directive still parses. Ports MUST relax `named_directive` to accept
zero-or-more prefix identifiers and MUST enforce `@entry`'s
cardinality (0–2 prefix identifiers) at the consumer layer.

Spec: grammar.ebnf `named_directive` uses `{ identifier }`; draft
ABNF uses `*( 1*WSP identifier )`. New §3.4.3 ("The @entry
Directive") defines the four shapes, the dot-disambiguation rule,
order preservation, and inherits §3.13's reserved-name constraint.
§3.4.2 rewritten to describe per-directive prefix-list semantics
and the registered-vs-unrecognized cardinality split.

Editor: VS Code TM grammar grows a `named-directive` pattern that
highlights `@<name>` plus prefix identifiers (dotted → type; bare
→ tag). JetBrains bundle regenerated via sync script.

Testdata: example-entries.pxf demonstrates all four shapes.

Stacked on PR #15 (pxf-reserved-names) — depends on §3.13 for the
reserved-name cross-reference in the new §3.4.3.
Base automatically changed from pxf-reserved-names to main May 11, 2026 22:17
@trendvidia
trendvidia merged commit b11e117 into main May 11, 2026
4 checks passed
@trendvidia
trendvidia deleted the pxf-entry-directive branch May 11, 2026 22:22
trendvidia added a commit that referenced this pull request May 11, 2026
New top-level directive form for representing many instances of a
single message type in a single PXF document:

  @table <type> ( <col1>, <col2>, ... )
  ( <val1>, <val2>, ... )
  ( <val1>, <val2>, ... )

Each row binds positionally to the header column list. The three
cell states map onto the existing pxf.required / pxf.default
semantics (§6.1) without any new annotation:

  - empty cell  (between two commas) → field absent
  - `null`      literal               → field present-but-null
  - any value   literal               → field present with value

v1 restrictions:
  - cells are scalar-shaped (no list `[…]`, no block `{…}`)
  - column entries are unqualified field names (no dotted paths)
  - strict row arity: row arity MUST equal column count
  - standalone: a @table document carries neither @type nor body
    field-entries; the @table header IS the type declaration

@table is consumer-interpreted (same side-channel pattern as
@Header / @entry). Rows are accessed via a parser API distinct
from the body's schema layer. The spec does NOT mandate a
canonical "decode-as-`repeated <type>`" semantics.

Wire format unchanged. Strictly additive: the new productions
occupy fresh top-level surface; any prior-version-valid PXF
document remains valid.

Spec changes: grammar.ebnf adds table_directive / column_list /
row / row_cell / row_value productions and extends directive_name
to exclude 'table'. Draft §3.3 ABNF matches. New §3.4.4 defines
syntax + semantics + conformance + the cell-grammar / column /
arity / standalone restrictions normatively.

Editor: VS Code TM grammar adds a `table-directive` pattern
mirroring `type-directive`, plus paren punctuation rules.
JetBrains bundle regenerated via sync_jetbrains_grammar.py.

Testdata: example-table.pxf demonstrates the three cell states
over test.v1.AllTypes; testdata/table/ contains seven adversarial
fixtures (short/long arity, @type collision, body collision, list
cell, block cell, dotted column) plus empty-rows acceptance.
Conformance-harness wiring deferred (cross_security_check.sh is
decode-corpus shaped; @table fixtures need a new tier).

Stacked on PR #16 (pxf-entry-directive); also folds a
forward-fix to PR #16's grammar.ebnf comment, which referenced
"Section 3.4.4" for @entry instead of §3.4.3.
trendvidia added a commit that referenced this pull request May 11, 2026
New top-level directive form for representing many instances of a
single message type in a single PXF document:

  @table <type> ( <col1>, <col2>, ... )
  ( <val1>, <val2>, ... )
  ( <val1>, <val2>, ... )

Each row binds positionally to the header column list. The three
cell states map onto the existing pxf.required / pxf.default
semantics (§6.1) without any new annotation:

  - empty cell  (between two commas) → field absent
  - `null`      literal               → field present-but-null
  - any value   literal               → field present with value

v1 restrictions:
  - cells are scalar-shaped (no list `[…]`, no block `{…}`)
  - column entries are unqualified field names (no dotted paths)
  - strict row arity: row arity MUST equal column count
  - standalone: a @table document carries neither @type nor body
    field-entries; the @table header IS the type declaration

@table is consumer-interpreted (same side-channel pattern as
@Header / @entry). Rows are accessed via a parser API distinct
from the body's schema layer. The spec does NOT mandate a
canonical "decode-as-`repeated <type>`" semantics.

Wire format unchanged. Strictly additive: the new productions
occupy fresh top-level surface; any prior-version-valid PXF
document remains valid.

Spec changes: grammar.ebnf adds table_directive / column_list /
row / row_cell / row_value productions and extends directive_name
to exclude 'table'. Draft §3.3 ABNF matches. New §3.4.4 defines
syntax + semantics + conformance + the cell-grammar / column /
arity / standalone restrictions normatively.

Editor: VS Code TM grammar adds a `table-directive` pattern
mirroring `type-directive`, plus paren punctuation rules.
JetBrains bundle regenerated via sync_jetbrains_grammar.py.

Testdata: example-table.pxf demonstrates the three cell states
over test.v1.AllTypes; testdata/table/ contains seven adversarial
fixtures (short/long arity, @type collision, body collision, list
cell, block cell, dotted column) plus empty-rows acceptance.
Conformance-harness wiring deferred (cross_security_check.sh is
decode-corpus shaped; @table fixtures need a new tier).

Stacked on PR #16 (pxf-entry-directive); also folds a
forward-fix to PR #16's grammar.ebnf comment, which referenced
"Section 3.4.4" for @entry instead of §3.4.3.
@trendvidia trendvidia mentioned this pull request May 11, 2026
4 tasks
trendvidia added a commit that referenced this pull request May 11, 2026
Promote [Unreleased] entries to [0.73.0] – 2026-05-11 in advance of
tagging v0.73.0 on this repo. Bundles three additive PXF text-format
changes that landed via #15 / #16 / #17:

  - schema-level reserved-name rule (§3.13)
  - @entry bundle directive + zero-or-more prefix list (§3.4.3)
  - @table bulk-rows directive (§3.4.4)

Wire format unchanged across all three. Spec-side counterpart to
protowire-go v0.73.0 (companion release); ports adopting these
features bump in lockstep to v0.73.0.
trendvidia added a commit that referenced this pull request Jul 16, 2026
)

Resolves spec issue #16 (GH #65) — the M4 blocker.

- proto/schema/v1/report.proto: Report, EnrichedViolation, Violation,
  structured FieldPath (typed map-key subscripts), typed Value oneof.
  Runtime artifact emitted by engines; allocates no extension numbers.
- google.protobuf.Value deliberately not used: folds int64 into double,
  cannot carry bytes, erases the set/null/absent distinction.
- RuleKind values carry the RULE_KIND_ prefix: EntryKind.TYPE_REFINEMENT
  in descriptor.proto already claims the bare name in package enum scope.
- RFC-001 §7 rewritten against the pinned shapes; §13 row 7 resolved.
- testdata/schema-extensions/07_report_golden.textproto: golden Report
  for the §5.3 worked example, verified with stock protoc
  (parse + --encode/--decode round-trip).
trendvidia added a commit that referenced this pull request Jul 16, 2026
Ticks the six open-question boxes and adds a resolution record to each
section — GH #60#65, PR train #94#99 — with pointers to the follow-up
trackers (protocompile#67/#68, GH #102/#103) and the fixtures 07–11.
trendvidia added a commit that referenced this pull request Jul 16, 2026
Ticks the six open-question boxes and adds a resolution record to each
section — GH #60#65, PR train #94#99 — with pointers to the follow-up
trackers (protocompile#67/#68, GH #102/#103) and the fixtures 07–11.
trendvidia added a commit that referenced this pull request Jul 16, 2026
Ticks the six open-question boxes and adds a resolution record to each
section — GH #60#65, PR train #94#99 — with pointers to the follow-up
trackers (protocompile#67/#68, GH #102/#103) and the fixtures 07–11.
trendvidia added a commit that referenced this pull request Jul 16, 2026
Ticks the six open-question boxes and adds a resolution record to each
section — GH #60#65, PR train #94#99 — with pointers to the follow-up
trackers (protocompile#67/#68, GH #102/#103) and the fixtures 07–11.
trendvidia added a commit that referenced this pull request Jul 16, 2026
Ticks the six open-question boxes and adds a resolution record to each
section — GH #60#65, PR train #94#99 — with pointers to the follow-up
trackers (protocompile#67/#68, GH #102/#103) and the fixtures 07–11.
trendvidia added a commit that referenced this pull request Jul 16, 2026
* spec: finalize Literal carrier shape (RFC-001 §8.1)

Resolves spec issue #15 (GH #64). In-place revision of the unreleased
carrier — the deliberate pre-freeze window for wire-shape changes.

- EnumLiteral {enum_type, value_name, number}: enum references lower
  RESOLVED; consumers never re-resolve bare names against a pool
  (replaces string enum_name).
- ListLiteral becomes repeated LiteralValue: elements are values, not
  arguments — no names, no expressions representable; homogeneous kind
  required (same enum_type for enum elements); nesting legal.
- Message literals stay google.protobuf.Any, with the explicit-typing
  rule pinned: type from the param declaration or an explicit use-site
  type name, never inferred from value shape; source spelling deferred
  to the IETF draft (#3).
- RFC-001 §8.1 excerpt + lowering rules prose; §13 row 6 resolved;
  CHANGELOG notes the protocompile descriptor.pb.go re-vendor follow-up.
- Fixtures: 10_literal_args.proto (schema-text: enum ref + list on
  any-typed params) and 11_literal_carrier_golden.textproto (lowered
  AnnotationList, all three kinds, protoc encode/decode-verified).

* docs: record S1 resolutions (#11#16) in RFC-001-issues.md

Ticks the six open-question boxes and adds a resolution record to each
section — GH #60#65, PR train #94#99 — with pointers to the follow-up
trackers (protocompile#67/#68, GH #102/#103) and the fixtures 07–11.
trendvidia added a commit that referenced this pull request Jul 16, 2026
* spec: ratify RFC-001 (issue #56)

Status Draft → Ratified (2026-07-16). §13 rows 13/14 now cite their
tracking issues (GH #111, #112) — with those filed, every open
question is either resolved in the RFC (S1: #11#16; S2: #15
source grammar, #21 sensitivity, #35 path scheme; S3: #22
engine-expression scope, #23 no dual-emission) or tracked as a
separate issue (GH #59, #66#69, #103, #111, #112). All v1.2 surface
is strictly additive; no locked decision blocks an existing port's
roadmap (per-port adoption is M9+, gated on the conformance corpus).

* docs: record #2 ratification (GH #56, PR #113)
trendvidia added a commit that referenced this pull request Jul 23, 2026
… value violations (#125) (#126)

* spec: EnrichedViolation.for_key — flag map-key violations (#125)

A subscripted FieldPath map segment addresses the entry's *value*, so a
map-key violation (e.g. a length rule on map<string, V> keys) and a
value violation on the same entry serialized to identical paths, with
neither RuleKind nor Violation.code required to disambiguate. Appending
a pseudo-segment for the entry's synthetic key = 1 field would collide
with a genuine 'key' field on message-typed map values.

- proto/schema/v1/report.proto: bool for_key = 8 on EnrichedViolation;
  subscript comment notes value-addressing
- RFC-001 §7: snippet + normative prose (engine MUST set for_key)
- IETF draft -01: enrichment-table row + prose, wire-shape summary;
  date bumped, txt/xml regenerated
- CHANGELOG: Unreleased entry

Golden 07_report_golden.textproto unchanged: the §5.3 worked example has
no map field; behavioral coverage lives in protocheck (trendvidia/protocheck#24).

* docs: RFC-001-issues.md — record #125 resolution under #16 (PR #126)
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