Skip to content

feat(lexer): underscore-prefix idents _key/_unused (Refs gitbot-fleet#148)#373

Merged
hyperpolymath merged 2 commits into
mainfrom
claude/lexer-underscore-idents-148
May 26, 2026
Merged

feat(lexer): underscore-prefix idents _key/_unused (Refs gitbot-fleet#148)#373
hyperpolymath merged 2 commits into
mainfrom
claude/lexer-underscore-idents-148

Conversation

@hyperpolymath
Copy link
Copy Markdown
Owner

Summary

Extends `lower_ident_start` from a single `lower` to `lower | ('_', alphanum)` — a lowercase letter, OR underscore followed by at least one alphanum. This is the conventional Rust-idiom spelling for "intentionally unused" bindings and parameters.

Bare `` (the wildcard pattern) is preserved as the distinct `UNDERSCORE` token: sedlex applies maximal munch, and the underscore branch of `lower_ident_start` requires at least one trailing alphanum, so `` standalone falls through to the existing UNDERSCORE rule.

Test changes

`test/test_lexer.ml::test_identifiers` now asserts the new tokenisation:

  • `_test` is a single `LOWER_IDENT "_test"` (was `UNDERSCORE; LOWER_IDENT "test"`).
  • Bare `_` still emits `UNDERSCORE`.

327/327 tests pass.

Why

Required by sustainabot hand-port (gitbot-fleet#148) — `GitHubApp.affine` declares unused cache-stub bindings as `let _key = ...; let _value = ...;`. Without this, every `_x` parses as wildcard + binding-name and breaks downstream pattern resolution.

Test plan

  • `dune build` green
  • `dune test` green (327/327)
  • CI green
  • Smoke: `let _key = json::encode(x);` parses

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. builtin/lowercase qualified paths + TOTAL field name (feat(parser): builtin/lowercase qualified paths + TOTAL field name (Refs gitbot-fleet#148) #372)
  4. this PR — lexer `_`-prefix idents
  5. (hypatia) Levenshtein perf fix

🤖 Generated with Claude Code

…leet#148)

Extends `lower_ident_start` from a single `lower` to
`lower | ('_', alphanum)` — a lowercase letter, OR underscore followed
by at least one alphanum. This is the conventional Rust-idiom spelling
for "intentionally unused" bindings and parameters.

Bare `_` (the wildcard pattern) is preserved as the distinct
UNDERSCORE token: sedlex applies maximal munch, and the underscore
branch of `lower_ident_start` requires at least one trailing alphanum,
so `_` standalone falls through to the existing UNDERSCORE rule.

Updates `test/test_lexer.ml::test_identifiers` to assert the new
tokenisation — `_test` is now a single `LOWER_IDENT "_test"`, and the
test additionally asserts that bare `_` still emits `UNDERSCORE`.

327/327 tests pass.

Required by sustainabot hand-port (gitbot-fleet#148) — `GitHubApp.affine`
declares unused cache-stub bindings as `let _key = ...; let _value = ...;`.

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

Severity Count
🔴 Critical 15
🟠 High 15
🟡 Medium 11

⚠️ 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 enabled auto-merge (squash) May 26, 2026 08:21
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

Severity Count
🔴 Critical 15
🟠 High 15
🟡 Medium 11

⚠️ 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 e8eb433 into main May 26, 2026
20 of 21 checks passed
@hyperpolymath hyperpolymath deleted the claude/lexer-underscore-idents-148 branch May 26, 2026 09:03
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