Skip to content

feat(parser)!: #{ record sigil + sound codemod migration [#218] (complete; supersedes #220)#221

Closed
hyperpolymath wants to merge 2 commits into
mainfrom
stage-c/218-records-and-codemod
Closed

feat(parser)!: #{ record sigil + sound codemod migration [#218] (complete; supersedes #220)#221
hyperpolymath wants to merge 2 commits into
mainfrom
stage-c/218-records-and-codemod

Conversation

@hyperpolymath
Copy link
Copy Markdown
Owner

#218#{ record sigil + sound codemod migration (complete, gate-green)

This is the complete implementation of #218, a superset of the
grammar-only work on PR #220 / stage-c/pc-brace-disambig (d22be56).
That branch is intentionally left untouched (parallel-session work,
shared identity); this PR supersedes it functionally — coordinate
closure of #220 against this.

What this adds over d22be56 (grammar-only)

  • d22be56 changes lexer.ml/parser.mly/token.ml only. It is
    missing the parse_driver.ml Token.HASH_LBRACE → Parser.HASH_LBRACE
    mapping
    — without it the lexer emits a token the driver cannot
    convert → Match_failure at runtime.
  • It has no .affine migration, so the 257 gate would be red.

This PR (fc1aa88 + d41315d):

  • Grammar + lexer + token and the parse_driver.ml mapping (4 files).
  • 45 in-repo .affine files migrated {…}#{…} by a sound
    convergent codemod
    that depends only on the new unambiguous grammar
    (parse → at each error insert # before the innermost enclosing
    record { → iterate to fixpoint; codepoint-correct). Tooling not
    committed.

Menhir conflicts (base a45b021)

S/R R/R
before 72 (23 states) 10 (4 states)
after 68 (21 states) 7 (1 state)

Gate

dune runtest = 257/257 green — identical to the pre-change
baseline. No regression; #{ is the record syntax across the suite.

Out of scope (follow-on, per #218 plan steps 3–4 / #215)

Refs #218 #215not Closes (closure is human-gated per the estate
requirements-target rule).

🤖 Generated with Claude Code

hyperpolymath and others added 2 commits May 18, 2026 16:42
Structurally removes the block-vs-record-literal ambiguity (#215
families C+D) with no lookahead heuristic, per the owner-approved
Rust-like model:

  - `{` in expression position is ALWAYS a block.
  - record/struct literals use `#{ … }` (anonymous `#{ x: 1 }` and
    typed `Foo #{ x: 1 }`).
  - record *patterns* unchanged (pattern position has no block
    alternative — no ambiguity there).

Changes: HASH_LBRACE token (token.ml), `#{` lexer rule (lexer.ml;
`#` was previously unused so longest-match is collision-free), both
ExprRecord productions rerouted LBRACE -> HASH_LBRACE (parser.mly).

Menhir conflicts on origin/main (a45b021): 72 S/R + 10 R/R
                                  after:  68 S/R +  7 R/R   (-4 / -3)
Build clean. BREAKING: legacy `{ … }` record syntax no longer parses;
the codemod-migrated repo `.affine` files land in the same PR so the
253/257 gate stays green.

Refs #218 #215

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Mechanical companion to the `#{` grammar change — 45 in-repo `.affine`
files (stdlib, tests, golden oracles, e2e fixtures, examples) rewritten
from legacy `{ … }` record literals to `#{ … }`.

Method: a sound, convergent codemod that depends ONLY on the new,
unambiguous grammar (never the old ambiguous parser): parse with the
new grammar, and at each parse error insert `#` before the innermost
enclosing record `{`, iterating to a fixed point. Codepoint-correct
(handles non-ASCII). The codemod tooling is intentionally not committed.

Result: `dune runtest` = 257/257 green (the #218 gate), identical to
the pre-change baseline — no regression; `#{` is now the record syntax
across the full test suite.

Out of scope (tracked, per the #218 plan steps 3–4):
  - estate-wide `.affine` sweep in other repos;
  - ~24 non-gating files the convergent codemod did not auto-migrate
    (LR error reported past the record's `}`): conformance/valid/*,
    docs/guides/warmup/*, codegen-deno/*, some tests/types/* — plus the
    intentional conformance/invalid/* error fixtures and face-syntax
    examples which must stay as-is. None are in the 257 gate.

Refs #218 #215

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@hyperpolymath
Copy link
Copy Markdown
Owner Author

Closing as redundant. The #{ record-literal sigil + codemod migration this PR carries was superseded by #222 ("feat!: Rust-like record syntax — bare { = block, records use #{ } (#218; resolves #215 C+D)"), which merged to main 2026-05-18 (commit 8de3e0b), with docs following in #223 (#218 step 5). #220 was already closed for the same reason. #221's head holds an older pre-#224 grammar state; nothing here is unmerged value. Remaining #218 work is the estate codemod sweep, not grammar. Refs #218 #222.

@github-actions
Copy link
Copy Markdown

🔍 Hypatia Security Scan

Findings: 44 issues detected

Severity Count
🔴 Critical 12
🟠 High 21
🟡 Medium 11

⚠️ Action Required: Critical security issues found!

View findings
[
  {
    "reason": "Stray AI.a2ml in root -- use 0-AI-MANIFEST.a2ml only",
    "type": "banned",
    "file": "AI.a2ml",
    "action": "delete",
    "rule_module": "root_hygiene",
    "severity": "high"
  },
  {
    "reason": "Superseded by 0-AI-MANIFEST.a2ml",
    "type": "banned",
    "file": "AI.djot",
    "action": "delete",
    "rule_module": "root_hygiene",
    "severity": "high"
  },
  {
    "reason": "Issue in quality.yml",
    "type": "missing_workflow",
    "file": "quality.yml",
    "action": "create",
    "rule_module": "workflow_audit",
    "severity": "high"
  },
  {
    "reason": "Issue in security-policy.yml",
    "type": "missing_workflow",
    "file": "security-policy.yml",
    "action": "create",
    "rule_module": "workflow_audit",
    "severity": "medium"
  },
  {
    "reason": "Action hyperpolymath/standards/.github/workflows/governance-reusable.yml@main needs attention",
    "type": "unpinned_action",
    "file": "governance.yml",
    "action": "pin_sha",
    "rule_module": "workflow_audit",
    "severity": "high"
  },
  {
    "reason": "TypeScript file detected -- banned language",
    "type": "banned_language_file",
    "file": "/home/runner/work/affinescript/affinescript/affinescript-deno-test/example/smoke_driver.ts",
    "action": "flag",
    "rule_module": "cicd_rules",
    "severity": "critical"
  },
  {
    "reason": "TypeScript file detected -- banned language",
    "type": "banned_language_file",
    "file": "/home/runner/work/affinescript/affinescript/affinescript-deno-test/cli.ts",
    "action": "flag",
    "rule_module": "cicd_rules",
    "severity": "critical"
  },
  {
    "reason": "TypeScript file detected -- banned language",
    "type": "banned_language_file",
    "file": "/home/runner/work/affinescript/affinescript/affinescript-deno-test/mod.ts",
    "action": "flag",
    "rule_module": "cicd_rules",
    "severity": "critical"
  },
  {
    "reason": "TypeScript file detected -- banned language",
    "type": "banned_language_file",
    "file": "/home/runner/work/affinescript/affinescript/affinescript-deno-test/lib/compile.ts",
    "action": "flag",
    "rule_module": "cicd_rules",
    "severity": "critical"
  },
  {
    "reason": "TypeScript file detected -- banned language",
    "type": "banned_language_file",
    "file": "/home/runner/work/affinescript/affinescript/affinescript-deno-test/lib/runner.ts",
    "action": "flag",
    "rule_module": "cicd_rules",
    "severity": "critical"
  }
]

Powered by Hypatia Neurosymbolic CI/CD Intelligence

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