Skip to content

feat(parser): builtin/lowercase qualified paths + TOTAL field name (Refs gitbot-fleet#148) - #372

Merged
hyperpolymath merged 2 commits into
mainfrom
claude/parser-builtin-qualified-paths-148
May 27, 2026
Merged

feat(parser): builtin/lowercase qualified paths + TOTAL field name (Refs gitbot-fleet#148)#372
hyperpolymath merged 2 commits into
mainfrom
claude/parser-builtin-qualified-paths-148

Conversation

@hyperpolymath

Copy link
Copy Markdown
Owner

Summary

Three closely-related `expr_primary` / `field_name` extensions, all driven by sustainabot hand-port shapes (gitbot-fleet#148):

1. Builtin-type-qualified value path

`Int::to_string(n)`, `String::len(s)`, `Float::to_string(f)`, etc. The built-in type names are reserved keyword tokens (NAT/INT_T/BOOL/FLOAT_T/STRING_T/CHAR_T), not UPPER_IDENT, so the existing `upper_ident COLONCOLON lower_ident` production never fired for them. Six new productions, one per builtin keyword, producing the canonical `ExprField (ExprVar TypeName, fname)` shape that [Resolve] already expects.

2. Lowercase-module-qualified value path

`json::encode_string(s)`, `string::join(xs, sep)`, etc. The stdlib already defines lowercase modules (`module json;`, `module string;`) and `use json::{...}` parses, but the expression-position qualified path only covered uppercase modules. The new `lower_ident COLONCOLON lower_ident` rule mirrors the upper-ident form.

LR(1)-safe: the only competing reduction for `lower_ident` at this position is `name = lower_ident { ExprVar ... }`, and on a COLONCOLON lookahead no rule starting from `expr_primary COLONCOLON` exists, so the parser shifts unambiguously.

3. `total` as a record-field name

Added to `field_name` alongside the existing `handle` contextual-keyword exception. Safe by the same reasoning HANDLE is safe: as a function-decl modifier TOTAL appears between `visibility?` and `FN`, never after DOT/before COLON in a record body; as a field name it appears between COLON / DOT and the field value. Surrounding token disambiguates. Used by sustainabot's `HealthIndex.total`, `Recommendation.total`, etc.

Conflict-cost

Zero. Parser builds with 21 S/R + 1 R/R, identical to the pre-patch baseline.

Test plan

  • `dune build` green
  • Conflict count unchanged: 21 S/R + 1 R/R
  • CI green
  • Smoke: `Int::to_string(42)` parses
  • Smoke: `json::encode_string("x")` parses
  • Smoke: `r.total` parses as field access; `#{ total: 99 }` parses as record literal

Companion PRs (gitbot-fleet#148 spine)

  1. trailing-comma in fn params + expr lists (feat(parser): trailing-comma in fn params and expr lists (Refs gitbot-fleet#148) #370)
  2. fn-type with effect arrow in type position (feat(parser): fn-type with effect arrow in type position (Refs gitbot-fleet#148) #371)
  3. this PR — builtin/lowercase qualified paths + TOTAL field name
  4. lexer `_`-prefix idents
  5. (hypatia) Levenshtein perf fix

🤖 Generated with Claude Code

@github-actions

Copy link
Copy Markdown

🔍 Hypatia Security Scan

Findings: 41 issues detected

SeverityCount
🔴 Critical15
🟠 High15
🟡 Medium11

⚠️Action Required: Critical security issues found!

View findings
[
{
"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": "Action actions/checkout@v6 needs attention",
"type": "unpinned_action",
"file": "publish-jsr.yml",
"action": "pin_sha",
"rule_module": "workflow_audit",
"severity": "medium"
},
{
"reason": "Action denoland/setup-deno@v2 needs attention",
"type": "unpinned_action",
"file": "publish-jsr.yml",
"action": "pin_sha",
"rule_module": "workflow_audit",
"severity": "medium"
},
{
"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"
},
{
"reason": "TypeScript file detected -- banned language",
"type": "banned_language_file",
"file": "/home/runner/work/affinescript/affinescript/affinescript-deno-test/lib/discover.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/packages/affine-js/types.d.ts",
"action": "flag",
"rule_module": "cicd_rules",
"severity": "critical"
}
]

Powered by Hypatia Neurosymbolic CI/CD Intelligence

hyperpolymath added a commit that referenced this pull request May 26, 2026
…tch workflow regex (#374)
## Summary
The `governance / Language / package anti-pattern policy` job in the
reusable
[governance-reusable.yml](https://github.com/hyperpolymath/standards/blob/main/.github/workflows/governance-reusable.yml)
scans `.claude/CLAUDE.md` for a section heading matching the regex
`TypeScript [Ee]xemptions` to find the exemption table.
This repo's heading was `### TypeScript / JavaScript Exemptions
(Approved)`. The `/ JavaScript ` between the two words prevents the
regex from matching.
The parser then falls through to the next mention of the phrase ("the
TypeScript exemptions above") in the **Runtime Exemptions** section's
prose, and parses the **Runtime Exemptions** table — picking up 2 JS
entries (`packages/affinescript-cli/mod.js`,
`editors/vscode/test/**/*.js`) instead of the 3 TypeScript entries
(including `affinescript-deno-test/*.ts`).
Result:
`affinescript-deno-test/{cli,example/smoke_driver,lib/{compile,discover,runner}}.ts`
were reported as forbidden TypeScript files on every PR — blocking the
check estate-wide for weeks.
## Fix
Rename `### TypeScript / JavaScript Exemptions (Approved)` → `###
TypeScript Exemptions (Approved)`.
JavaScript exemptions already live in their own `### Runtime Exemptions
(Approved)` section immediately below, so the original heading's `/
JavaScript` was misleading anyway.
## Verification
Simulated the workflow's Python parser locally on the post-fix
`.claude/CLAUDE.md`:
```
Parsed 3 exemption(s)
✅ No TypeScript files outside allowlist (3 per-repo exemption(s) parsed).
```
(Pre-fix: parsed 2 exemptions — the wrong table — and 5
`affinescript-deno-test/*.ts` files were reported bad.)
## Test plan
- [x] Local Python simulation of the workflow parser
- [ ] CI: `governance / Language / package anti-pattern policy` green on
this PR
- [ ] Downstream: re-run CI on #370, #371, #372, #373 — same check
should turn green after merge
Refs gitbot-fleet#148 (unblocks affinescript #370/#371/#372/#373 et al)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
hyperpolymath added a commit to hyperpolymath/gitbot-fleet that referenced this pull request May 26, 2026
…Refs #148) (#206)
## Summary
Two hand-port corrections after re-validating sustainabot's
ReScript→AffineScript files against the live `affinescript check`:
1. **OCaml-style float operators** `/.`, `*.`, `+.`, `-.` → AffineScript
`/`, `*`, `+`, `-`. AffineScript uses unified arithmetic operators for
Int and Float (see `examples/lessons/01_hello.affine`: `subtotal *
0.08`), so the OCaml separation was a hand-port artefact. Affected:
`GitHubApp.affine`, `Oikos.affine`, `Report.affine`.
2. **`handle` is a contextual keyword** in AffineScript (HANDLE token,
used in `handle body { handlers }` effect expressions), so it cannot be
a function name. Renamed `Router.affine`'s `pub fn handle(...)` → `pub
fn dispatch(...)`. The function dispatches a request to its matching
route handler — the rename is also more accurate.
## Gate
This PR's parse-time fix is fully effective only once the four parser
PRs gated on the same issue have merged:
- hyperpolymath/affinescript#370 (trailing-comma in fn params + expr
lists + effect-annotated lambda)
- hyperpolymath/affinescript#371 (fn-type with effect arrow in type
position)
- hyperpolymath/affinescript#372 (builtin/lowercase qualified paths +
TOTAL field name)
- hyperpolymath/affinescript#373 (underscore-prefix idents
`_key`/`_unused`)
- hyperpolymath/affinescript#376 (record-update spread at start)
## Test plan
- [x] After landing the 5 affinescript PRs + this PR: `affinescript
check` on all 13 sustainabot `.affine` files reaches at least Resolution
(no parse errors). 12 hit `Resolve.UndefinedModule` (stdlib not loaded
by the check), 1 (`tea/Sub.affine`) hit it from the start.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@github-actions

Copy link
Copy Markdown

🔍 Hypatia Security Scan

Findings: 41 issues detected

SeverityCount
🔴 Critical15
🟠 High15
🟡 Medium11

⚠️Action Required: Critical security issues found!

View findings
[
{
"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": "Action actions/checkout@v6 needs attention",
"type": "unpinned_action",
"file": "publish-jsr.yml",
"action": "pin_sha",
"rule_module": "workflow_audit",
"severity": "medium"
},
{
"reason": "Action denoland/setup-deno@v2 needs attention",
"type": "unpinned_action",
"file": "publish-jsr.yml",
"action": "pin_sha",
"rule_module": "workflow_audit",
"severity": "medium"
},
{
"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"
},
{
"reason": "TypeScript file detected -- banned language",
"type": "banned_language_file",
"file": "/home/runner/work/affinescript/affinescript/affinescript-deno-test/lib/discover.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/packages/affine-js/types.d.ts",
"action": "flag",
"rule_module": "cicd_rules",
"severity": "critical"
}
]

Powered by Hypatia Neurosymbolic CI/CD Intelligence

… field name (Refs gitbot-fleet#148)
Three closely-related expr_primary/field_name extensions, all driven by
sustainabot hand-port shapes (gitbot-fleet#148):
1. Builtin-type-qualified value path: `Int::to_string(n)`,
`String::len(s)`, etc. The built-in type names are reserved keyword
tokens (NAT/INT_T/BOOL/FLOAT_T/STRING_T/CHAR_T), not UPPER_IDENT, so
the existing `upper_ident COLONCOLON lower_ident` production never
fired for them. Six new productions, one per builtin keyword,
producing the canonical `ExprField (ExprVar TypeName, fname)` shape
that [Resolve] already expects from upper-ident paths.
2. Lowercase-module-qualified value path: `json::encode_string(s)`,
`string::join(xs, sep)`, etc. The stdlib already defines lowercase
modules (`module json;`, `module string;`) and `use json::{...}`
parses, but the expression-position qualified path only covered
uppercase modules. The new `lower_ident COLONCOLON lower_ident`
rule mirrors the upper-ident form.
3. `total` as a record-field name. Added to `field_name` alongside the
existing `handle` contextual-keyword exception. Safe by the same
reasoning HANDLE is safe: as a function-decl modifier TOTAL appears
between `visibility?` and `FN`, never after DOT/before COLON in a
record body; as a field name it appears between COLON / DOT and the
field value. The surrounding token disambiguates. Used by
sustainabot's `HealthIndex.total`, `Recommendation.total`, etc.
Conflict-cost: zero. Parser builds with 21 S/R + 1 R/R, identical to
the pre-patch baseline.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@hyperpolymath
hyperpolymathforce-pushed the claude/parser-builtin-qualified-paths-148 branch from a6b400b to 9f83930CompareMay 26, 2026 11:23
@github-actions

Copy link
Copy Markdown

🔍 Hypatia Security Scan

Findings: 43 issues detected

SeverityCount
🔴 Critical15
🟠 High16
🟡 Medium12

⚠️Action Required: Critical security issues found!

View findings
[
{
"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": "Action actions/checkout@v6 needs attention",
"type": "unpinned_action",
"file": "publish-jsr.yml",
"action": "pin_sha",
"rule_module": "workflow_audit",
"severity": "medium"
},
{
"reason": "Action denoland/setup-deno@v2 needs attention",
"type": "unpinned_action",
"file": "publish-jsr.yml",
"action": "pin_sha",
"rule_module": "workflow_audit",
"severity": "medium"
},
{
"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"
},
{
"reason": "TypeScript file detected -- banned language",
"type": "banned_language_file",
"file": "/home/runner/work/affinescript/affinescript/affinescript-deno-test/lib/discover.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/packages/affine-js/types.d.ts",
"action": "flag",
"rule_module": "cicd_rules",
"severity": "critical"
}
]

Powered by Hypatia Neurosymbolic CI/CD Intelligence

@hyperpolymath
hyperpolymath merged commit d9f9971 into mainMay 27, 2026
21 checks passed
@hyperpolymath
hyperpolymath deleted the claude/parser-builtin-qualified-paths-148 branch May 27, 2026 12:07
Sign up for freeto 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

@hyperpolymath