ibex 0.1.0 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (603) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +89 -123
  3. data/docs/architecture.md +477 -31
  4. data/docs/bison-import.md +103 -0
  5. data/docs/comparison-policy.md +127 -0
  6. data/docs/configuration-model.md +59 -0
  7. data/docs/configuration-report.md +28 -0
  8. data/docs/conflict-explanation-reviews/v1/records/README.md +28 -0
  9. data/docs/conflict-explanation-study.md +62 -0
  10. data/docs/construction-profiling.md +157 -0
  11. data/docs/cst-migration.md +106 -0
  12. data/docs/cst.md +237 -0
  13. data/docs/decisions/0000-template.md +24 -0
  14. data/docs/decisions/0001-separate-ir-pipeline.md +34 -0
  15. data/docs/decisions/0002-opaque-user-code-boundary.md +32 -0
  16. data/docs/decisions/0003-self-hosted-grammar-frontend.md +32 -0
  17. data/docs/decisions/0004-shared-semantic-and-lossless-source-model.md +33 -0
  18. data/docs/decisions/0005-contained-grammar-composition.md +34 -0
  19. data/docs/decisions/0006-bounded-structural-grammar-lowering.md +32 -0
  20. data/docs/decisions/0007-shared-parser-construction-pipeline.md +33 -0
  21. data/docs/decisions/0008-versioned-runtime-package-boundary.md +36 -0
  22. data/docs/decisions/0009-isolated-parser-sessions.md +34 -0
  23. data/docs/decisions/0010-committed-runtime-observation.md +34 -0
  24. data/docs/decisions/0011-versioned-semantic-action-boundary.md +37 -0
  25. data/docs/decisions/0012-bounded-nonexecuting-analysis.md +37 -0
  26. data/docs/decisions/0013-transactional-generation-publication.md +37 -0
  27. data/docs/decisions/0014-versioned-generated-lexer.md +35 -0
  28. data/docs/decisions/0015-worker-isolated-browser-analysis.md +32 -0
  29. data/docs/decisions/0016-red-green-concrete-syntax.md +34 -0
  30. data/docs/decisions/0017-persistent-syntax-artifacts.md +35 -0
  31. data/docs/decisions/0018-conservative-incremental-syntax-reuse.md +38 -0
  32. data/docs/decisions/0019-runtime-syntax-session-boundary.md +51 -0
  33. data/docs/decisions/0020-grammar-ir-parser-contract.md +65 -0
  34. data/docs/decisions/0021-data-only-parser-table-sidecar.md +50 -0
  35. data/docs/decisions/0022-manifest-bound-verification-report.md +77 -0
  36. data/docs/decisions/0023-syntax-only-repair-results.md +48 -0
  37. data/docs/decisions/0024-direct-ielr-construction.md +42 -0
  38. data/docs/decisions/README.md +74 -0
  39. data/docs/declarative-configuration.md +262 -0
  40. data/docs/development.md +306 -0
  41. data/docs/direct-ielr-decision.md +120 -0
  42. data/docs/direct-multi-entry-decision.md +82 -0
  43. data/docs/editor-setup.md +26 -0
  44. data/docs/error-ux-review-rubric-v1.md +117 -0
  45. data/docs/error-ux-reviews/v1/records/README.md +22 -0
  46. data/docs/error-ux-round2-review-status-v1.json +27 -0
  47. data/docs/error-ux-round2-reviews/v1/records/README.md +30 -0
  48. data/docs/error-ux-round2-v1.json +1581 -0
  49. data/docs/error-ux-round2.md +111 -0
  50. data/docs/error-ux.md +114 -0
  51. data/docs/getting-started.md +80 -0
  52. data/docs/grammar-reference.md +629 -18
  53. data/docs/ielr-design.md +43 -0
  54. data/docs/ielr.md +92 -0
  55. data/docs/ja/bison-import.md +51 -0
  56. data/docs/ja/stable-api.md +53 -0
  57. data/docs/lexer-construction-profile.md +109 -0
  58. data/docs/lexer-migration.md +56 -0
  59. data/docs/maturity.md +128 -0
  60. data/docs/project-site-strategy.md +54 -0
  61. data/docs/racc-migration-evidence.md +45 -0
  62. data/docs/racc-migration.md +45 -6
  63. data/docs/release-readiness.md +221 -0
  64. data/docs/repair-semantics.md +123 -0
  65. data/docs/runtime-abi-evolution.md +307 -0
  66. data/docs/stability.md +234 -0
  67. data/docs/status.md +43 -0
  68. data/docs/syntax-sessions.md +183 -0
  69. data/docs/table-artifact.md +125 -0
  70. data/docs/test-interactions.md +219 -0
  71. data/docs/verification-report.md +137 -0
  72. data/docs/verifier-trust-boundary.md +199 -0
  73. data/docs/workloads.md +132 -0
  74. data/examples/README.md +60 -0
  75. data/examples/calculator.y +44 -0
  76. data/examples/csv.y +32 -0
  77. data/examples/ini.y +70 -0
  78. data/examples/json.y +48 -0
  79. data/examples/tiny_language.y +75 -0
  80. data/lib/ibex/analysis/digraph.rb +128 -0
  81. data/lib/ibex/analysis/sets.rb +5 -4
  82. data/lib/ibex/analysis.rb +1 -0
  83. data/lib/ibex/artifact_set.rb +63 -0
  84. data/lib/ibex/bison_import/importer.rb +516 -0
  85. data/lib/ibex/bison_import/tokenizer.rb +260 -0
  86. data/lib/ibex/bison_import.rb +200 -0
  87. data/lib/ibex/bounded_subprocess.rb +171 -0
  88. data/lib/ibex/cli/ambiguity.rb +75 -0
  89. data/lib/ibex/cli/analysis.rb +134 -0
  90. data/lib/ibex/cli/bison_import.rb +121 -0
  91. data/lib/ibex/cli/config.rb +128 -0
  92. data/lib/ibex/cli/counterexample_options.rb +6 -2
  93. data/lib/ibex/cli/coverage.rb +173 -0
  94. data/lib/ibex/cli/debug.rb +106 -0
  95. data/lib/ibex/cli/diagnostics.rb +136 -0
  96. data/lib/ibex/cli/documentation.rb +70 -0
  97. data/lib/ibex/cli/equiv.rb +169 -0
  98. data/lib/ibex/cli/error_messages.rb +184 -0
  99. data/lib/ibex/cli/explain.rb +85 -0
  100. data/lib/ibex/cli/fix.rb +203 -0
  101. data/lib/ibex/cli/formatting.rb +387 -0
  102. data/lib/ibex/cli/fuzz.rb +200 -0
  103. data/lib/ibex/cli/fuzz_regressions.rb +145 -0
  104. data/lib/ibex/cli/generation_artifacts.rb +189 -0
  105. data/lib/ibex/cli/generation_error_messages.rb +39 -0
  106. data/lib/ibex/cli/grammar_tests.rb +140 -0
  107. data/lib/ibex/cli/ir_tools.rb +128 -0
  108. data/lib/ibex/cli/lsp.rb +33 -0
  109. data/lib/ibex/cli/outputs.rb +133 -23
  110. data/lib/ibex/cli/racc_migration.rb +87 -0
  111. data/lib/ibex/cli/reduce.rb +202 -0
  112. data/lib/ibex/cli/reduce_reporting.rb +71 -0
  113. data/lib/ibex/cli/samples.rb +118 -0
  114. data/lib/ibex/cli/verify.rb +116 -0
  115. data/lib/ibex/cli/watch.rb +104 -0
  116. data/lib/ibex/cli.rb +825 -55
  117. data/lib/ibex/codegen/action_locations.rb +103 -0
  118. data/lib/ibex/codegen/action_method_source.rb +209 -0
  119. data/lib/ibex/codegen/action_source.rb +119 -0
  120. data/lib/ibex/codegen/ambiguity.rb +174 -0
  121. data/lib/ibex/codegen/cst_metadata.rb +171 -0
  122. data/lib/ibex/codegen/documentation.rb +170 -0
  123. data/lib/ibex/codegen/explain.rb +380 -0
  124. data/lib/ibex/codegen/generated_action_abi.rb +293 -0
  125. data/lib/ibex/codegen/html.rb +94 -10
  126. data/lib/ibex/codegen/mermaid.rb +43 -0
  127. data/lib/ibex/codegen/railroad.rb +197 -0
  128. data/lib/ibex/codegen/railroad_documentation.rb +59 -0
  129. data/lib/ibex/codegen/rbs.rb +331 -2
  130. data/lib/ibex/codegen/report.rb +67 -15
  131. data/lib/ibex/codegen/ruby.rb +305 -66
  132. data/lib/ibex/codegen/ruby_actions.rb +146 -0
  133. data/lib/ibex/codegen/ruby_ast.rb +121 -0
  134. data/lib/ibex/codegen/ruby_error_messages.rb +28 -0
  135. data/lib/ibex/codegen/ruby_lexer.rb +83 -0
  136. data/lib/ibex/codegen/ruby_syntax.rb +96 -0
  137. data/lib/ibex/codegen/ruby_table_metadata.rb +57 -0
  138. data/lib/ibex/codegen/ruby_value_printers.rb +56 -0
  139. data/lib/ibex/codegen/symbol_labels.rb +1 -1
  140. data/lib/ibex/configuration/analysis_grammar.rb +35 -0
  141. data/lib/ibex/configuration/explanation.rb +421 -0
  142. data/lib/ibex/configuration/inspector.rb +232 -0
  143. data/lib/ibex/configuration.rb +580 -0
  144. data/lib/ibex/coverage/collector.rb +198 -0
  145. data/lib/ibex/coverage/event_stream.rb +103 -0
  146. data/lib/ibex/coverage/report.rb +267 -0
  147. data/lib/ibex/coverage/runtime_event_validator.rb +169 -0
  148. data/lib/ibex/coverage.rb +13 -0
  149. data/lib/ibex/delta_reducer.rb +99 -0
  150. data/lib/ibex/diff.rb +140 -0
  151. data/lib/ibex/equiv/machine.rb +135 -0
  152. data/lib/ibex/equiv.rb +373 -0
  153. data/lib/ibex/error_messages/parser.rb +159 -0
  154. data/lib/ibex/error_messages/parser_v2.rb +198 -0
  155. data/lib/ibex/error_messages/renderer.rb +65 -0
  156. data/lib/ibex/error_messages/sentence_search.rb +196 -0
  157. data/lib/ibex/error_messages/update.rb +169 -0
  158. data/lib/ibex/error_messages.rb +165 -0
  159. data/lib/ibex/fix.rb +557 -0
  160. data/lib/ibex/frontend/ast.rb +166 -7
  161. data/lib/ibex/frontend/bootstrap_parser.rb +40 -4
  162. data/lib/ibex/frontend/diagnostic.rb +81 -0
  163. data/lib/ibex/frontend/diagnostic_recovery.rb +268 -0
  164. data/lib/ibex/frontend/dsl.rb +66 -7
  165. data/lib/ibex/frontend/formatter.rb +453 -0
  166. data/lib/ibex/frontend/generated_parser.rb +644 -190
  167. data/lib/ibex/frontend/generated_parser_base.rb +170 -32
  168. data/lib/ibex/frontend/generated_parser_includes.rb +51 -0
  169. data/lib/ibex/frontend/generated_parser_metadata.rb +61 -0
  170. data/lib/ibex/frontend/generated_parser_parameters.rb +60 -0
  171. data/lib/ibex/frontend/generation.rb +33 -0
  172. data/lib/ibex/frontend/lexer.rb +162 -10
  173. data/lib/ibex/frontend/lexer_recovery.rb +84 -0
  174. data/lib/ibex/frontend/parser/declarations.rb +262 -11
  175. data/lib/ibex/frontend/parser/parameters.rb +82 -0
  176. data/lib/ibex/frontend/parser/rules.rb +43 -6
  177. data/lib/ibex/frontend/parser.rb +182 -4
  178. data/lib/ibex/frontend/parser_configuration_support.rb +56 -0
  179. data/lib/ibex/frontend/regenerator.rb +27 -1
  180. data/lib/ibex/frontend/resolution.rb +70 -0
  181. data/lib/ibex/frontend/resolver.rb +217 -0
  182. data/lib/ibex/frontend/rule_documentation.rb +104 -0
  183. data/lib/ibex/frontend/source_cursor.rb +133 -9
  184. data/lib/ibex/frontend/source_document.rb +229 -0
  185. data/lib/ibex/frontend/source_loader.rb +150 -0
  186. data/lib/ibex/frontend/source_span.rb +89 -0
  187. data/lib/ibex/frontend/token_adapter/declaration_document_state.rb +47 -0
  188. data/lib/ibex/frontend/token_adapter/declaration_lexer_state.rb +83 -0
  189. data/lib/ibex/frontend/token_adapter/declaration_state.rb +244 -22
  190. data/lib/ibex/frontend/token_adapter/delimiter_tracker.rb +8 -2
  191. data/lib/ibex/frontend/token_adapter/rule_state.rb +60 -2
  192. data/lib/ibex/frontend/token_adapter.rb +18 -3
  193. data/lib/ibex/frontend.rb +14 -2
  194. data/lib/ibex/fuzz.rb +219 -0
  195. data/lib/ibex/generation_input.rb +57 -0
  196. data/lib/ibex/generation_manifest.rb +211 -0
  197. data/lib/ibex/generation_transaction.rb +261 -0
  198. data/lib/ibex/generation_transaction_recovery.rb +109 -0
  199. data/lib/ibex/generation_transaction_validation.rb +196 -0
  200. data/lib/ibex/grammar_tests.rb +206 -0
  201. data/lib/ibex/ir/automaton_ir.rb +86 -11
  202. data/lib/ibex/ir/grammar_ir.rb +170 -26
  203. data/lib/ibex/ir/lexer_ir.rb +76 -0
  204. data/lib/ibex/ir/parser_contract.rb +135 -0
  205. data/lib/ibex/ir/serialize.rb +268 -50
  206. data/lib/ibex/ir/validator/automaton.rb +375 -0
  207. data/lib/ibex/ir/validator/base.rb +147 -0
  208. data/lib/ibex/ir/validator/grammar.rb +634 -0
  209. data/lib/ibex/ir/validator/lexer.rb +113 -0
  210. data/lib/ibex/ir/validator.rb +63 -0
  211. data/lib/ibex/ir.rb +71 -5
  212. data/lib/ibex/lalr/build_metrics.rb +71 -0
  213. data/lib/ibex/lalr/builder.rb +514 -52
  214. data/lib/ibex/lalr/conflict.rb +1 -0
  215. data/lib/ibex/lalr/conflict_search.rb +26 -9
  216. data/lib/ibex/lalr/counterexample.rb +38 -18
  217. data/lib/ibex/lalr/direct_lookaheads.rb +289 -0
  218. data/lib/ibex/lalr/goto_follows.rb +229 -0
  219. data/lib/ibex/lalr/ielr/annotator.rb +214 -0
  220. data/lib/ibex/lalr/ielr/bits.rb +28 -0
  221. data/lib/ibex/lalr/ielr/inadequacy.rb +47 -0
  222. data/lib/ibex/lalr/ielr/item_lookaheads.rb +78 -0
  223. data/lib/ibex/lalr/ielr/pipeline.rb +75 -0
  224. data/lib/ibex/lalr/ielr/split_stability.rb +78 -0
  225. data/lib/ibex/lalr/ielr/split_state.rb +20 -0
  226. data/lib/ibex/lalr/ielr/state_splitter.rb +258 -0
  227. data/lib/ibex/lalr/ielr_partition.rb +166 -0
  228. data/lib/ibex/lalr/inadequacy_report.rb +50 -0
  229. data/lib/ibex/lalr/lookahead_propagation.rb +111 -0
  230. data/lib/ibex/lalr/lr0_collection.rb +121 -0
  231. data/lib/ibex/lalr/on_error_reductions.rb +74 -0
  232. data/lib/ibex/lalr/unreachable_states.rb +80 -0
  233. data/lib/ibex/lalr.rb +59 -1
  234. data/lib/ibex/location.rb +129 -0
  235. data/lib/ibex/lsp/document_handlers.rb +68 -0
  236. data/lib/ibex/lsp/document_store.rb +264 -0
  237. data/lib/ibex/lsp/document_store_diagnostics.rb +44 -0
  238. data/lib/ibex/lsp/document_store_validation.rb +61 -0
  239. data/lib/ibex/lsp/initialization_handlers.rb +80 -0
  240. data/lib/ibex/lsp/navigation_handlers.rb +70 -0
  241. data/lib/ibex/lsp/parser_configuration_assistance.rb +149 -0
  242. data/lib/ibex/lsp/position_codec.rb +113 -0
  243. data/lib/ibex/lsp/protocol_error.rb +33 -0
  244. data/lib/ibex/lsp/request_handlers.rb +46 -0
  245. data/lib/ibex/lsp/request_support.rb +94 -0
  246. data/lib/ibex/lsp/server.rb +148 -0
  247. data/lib/ibex/lsp/symbol_index.rb +241 -0
  248. data/lib/ibex/lsp/symbol_index_builder.rb +277 -0
  249. data/lib/ibex/lsp/symbol_index_precedence_references.rb +44 -0
  250. data/lib/ibex/lsp/symbol_index_source_queries.rb +61 -0
  251. data/lib/ibex/lsp/symbol_occurrence.rb +23 -0
  252. data/lib/ibex/lsp/transport.rb +128 -0
  253. data/lib/ibex/lsp/workspace.rb +128 -0
  254. data/lib/ibex/lsp/workspace_analyzer.rb +199 -0
  255. data/lib/ibex/lsp.rb +33 -0
  256. data/lib/ibex/messages/en.yml +28 -0
  257. data/lib/ibex/messages/ja.yml +28 -0
  258. data/lib/ibex/messages.rb +68 -0
  259. data/lib/ibex/metrics.rb +175 -0
  260. data/lib/ibex/normalize/declarations.rb +142 -7
  261. data/lib/ibex/normalize/diagnostics.rb +94 -24
  262. data/lib/ibex/normalize/expander.rb +64 -59
  263. data/lib/ibex/normalize/expression.rb +63 -40
  264. data/lib/ibex/normalize/grammar_builder.rb +26 -0
  265. data/lib/ibex/normalize/inline_expansion.rb +465 -0
  266. data/lib/ibex/normalize/inline_validation.rb +174 -0
  267. data/lib/ibex/normalize/lexer.rb +131 -0
  268. data/lib/ibex/normalize/named_references.rb +60 -0
  269. data/lib/ibex/normalize/nodes.rb +46 -0
  270. data/lib/ibex/normalize/parameter_ebnf_lowering.rb +70 -0
  271. data/lib/ibex/normalize/parameter_lowering.rb +143 -0
  272. data/lib/ibex/normalize/parameter_substitution.rb +125 -0
  273. data/lib/ibex/normalize/parameter_validation.rb +140 -0
  274. data/lib/ibex/normalize/parameters.rb +226 -0
  275. data/lib/ibex/normalize/parser_configuration.rb +70 -0
  276. data/lib/ibex/normalize/recovery_declarations.rb +84 -0
  277. data/lib/ibex/normalize.rb +172 -17
  278. data/lib/ibex/racc_migration/checker.rb +122 -0
  279. data/lib/ibex/racc_migration/harness.rb +177 -0
  280. data/lib/ibex/racc_migration/report.rb +97 -0
  281. data/lib/ibex/racc_migration.rb +12 -0
  282. data/lib/ibex/rake_task.rb +116 -0
  283. data/lib/ibex/samples.rb +216 -0
  284. data/lib/ibex/table_artifact/builder.rb +266 -0
  285. data/lib/ibex/table_artifact/cst_projection.rb +70 -0
  286. data/lib/ibex/table_artifact/document.rb +39 -0
  287. data/lib/ibex/table_artifact/executor.rb +187 -0
  288. data/lib/ibex/table_artifact/serializer.rb +57 -0
  289. data/lib/ibex/table_artifact/validator/metadata.rb +179 -0
  290. data/lib/ibex/table_artifact/validator/support.rb +86 -0
  291. data/lib/ibex/table_artifact/validator/tables.rb +238 -0
  292. data/lib/ibex/table_artifact/validator.rb +253 -0
  293. data/lib/ibex/table_artifact.rb +88 -0
  294. data/lib/ibex/table_simulation/result.rb +55 -0
  295. data/lib/ibex/table_simulation/simulator.rb +253 -0
  296. data/lib/ibex/table_simulation/step.rb +62 -0
  297. data/lib/ibex/table_simulation/text.rb +31 -0
  298. data/lib/ibex/table_simulation.rb +13 -0
  299. data/lib/ibex/tables.rb +22 -69
  300. data/lib/ibex/verifiable_generation_bundle.rb +86 -0
  301. data/lib/ibex/verification_report/builder.rb +159 -0
  302. data/lib/ibex/verification_report/canonical_ir.rb +123 -0
  303. data/lib/ibex/verification_report/logical_path.rb +68 -0
  304. data/lib/ibex/verification_report/validator.rb +329 -0
  305. data/lib/ibex/verification_report.rb +69 -0
  306. data/lib/ibex/verify/action_correspondence.rb +138 -0
  307. data/lib/ibex/verify/language_witness.rb +295 -0
  308. data/lib/ibex/verify/reference_collection.rb +190 -0
  309. data/lib/ibex/verify/result.rb +73 -0
  310. data/lib/ibex/verify/verifier.rb +598 -0
  311. data/lib/ibex/verify.rb +15 -0
  312. data/lib/ibex/version.rb +1 -1
  313. data/lib/ibex/watch/runner.rb +181 -0
  314. data/lib/ibex/watch/source_snapshot.rb +98 -0
  315. data/lib/ibex/watch.rb +11 -0
  316. data/lib/ibex.rb +35 -1
  317. data/schema/automaton-ir-definitions.schema.json +401 -0
  318. data/schema/automaton-ir.schema.json +65 -0
  319. data/schema/benchmark-v1.schema.json +212 -0
  320. data/schema/benchmark-v2.schema.json +61 -0
  321. data/schema/bison-import-v1.schema.json +106 -0
  322. data/schema/conflict-explanation-review-v1.schema.json +196 -0
  323. data/schema/conflict-explanation-study-v1.schema.json +528 -0
  324. data/schema/construction-profile-v1.schema.json +779 -0
  325. data/schema/cst-v1.json +170 -0
  326. data/schema/diff-v1.schema.json +41 -0
  327. data/schema/direct-ielr-decision-v1.schema.json +200 -0
  328. data/schema/equiv-v1.schema.json +64 -0
  329. data/schema/error-ux-review-v1.schema.json +609 -0
  330. data/schema/error-ux-round2-review-v1.schema.json +191 -0
  331. data/schema/error-ux-round2-v1.schema.json +519 -0
  332. data/schema/error-ux-v1.schema.json +258 -0
  333. data/schema/explain-v1.schema.json +495 -0
  334. data/schema/fix-v1.schema.json +64 -0
  335. data/schema/fix-v2.schema.json +66 -0
  336. data/schema/fix-v3.schema.json +101 -0
  337. data/schema/frontend-diagnostics-v1.schema.json +154 -0
  338. data/schema/fuzz-regression-v1.schema.json +79 -0
  339. data/schema/fuzz-v1.schema.json +114 -0
  340. data/schema/generation-manifest-v1.schema.json +115 -0
  341. data/schema/grammar-ir-extensions.schema.json +734 -0
  342. data/schema/grammar-ir-foundation.schema.json +426 -0
  343. data/schema/grammar-ir.schema.json +271 -0
  344. data/schema/ielr-benchmark-v1.schema.json +85 -0
  345. data/schema/lexer-ir-v1.schema.json +215 -0
  346. data/schema/lexer-profile-v1.schema.json +491 -0
  347. data/schema/metrics-v1.schema.json +60 -0
  348. data/schema/migration-check-v1.schema.json +60 -0
  349. data/schema/performance-comparison-v1.schema.json +395 -0
  350. data/schema/public-performance-comparison-v1.schema.json +506 -0
  351. data/schema/public-performance-profile-v1.schema.json +360 -0
  352. data/schema/reduce-v1.schema.json +22 -0
  353. data/schema/reduce-v2.schema.json +63 -0
  354. data/schema/runtime-coverage-v1.schema.json +86 -0
  355. data/schema/runtime-event-v1.schema.json +308 -0
  356. data/schema/table-artifact-v1.schema.json +377 -0
  357. data/schema/table-simulation-v1.schema.json +70 -0
  358. data/schema/verification-report-v1.schema.json +222 -0
  359. data/schema/verify-v1.schema.json +42 -0
  360. data/sig/ibex/analysis/digraph.rbs +19 -0
  361. data/sig/ibex/artifact_set.rbs +37 -0
  362. data/sig/ibex/bison_import/importer.rbs +140 -0
  363. data/sig/ibex/bison_import/tokenizer.rbs +91 -0
  364. data/sig/ibex/bison_import.rbs +95 -0
  365. data/sig/ibex/bounded_subprocess.rbs +76 -0
  366. data/sig/ibex/cli/ambiguity.rbs +28 -0
  367. data/sig/ibex/cli/analysis.rbs +43 -0
  368. data/sig/ibex/cli/bison_import.rbs +32 -0
  369. data/sig/ibex/cli/config.rbs +35 -0
  370. data/sig/ibex/cli/counterexample_options.rbs +2 -0
  371. data/sig/ibex/cli/coverage.rbs +53 -0
  372. data/sig/ibex/cli/debug.rbs +28 -0
  373. data/sig/ibex/cli/diagnostics.rbs +51 -0
  374. data/sig/ibex/cli/documentation.rbs +29 -0
  375. data/sig/ibex/cli/equiv.rbs +49 -0
  376. data/sig/ibex/cli/error_messages.rbs +63 -0
  377. data/sig/ibex/cli/explain.rbs +31 -0
  378. data/sig/ibex/cli/fix.rbs +53 -0
  379. data/sig/ibex/cli/formatting.rbs +107 -0
  380. data/sig/ibex/cli/fuzz.rbs +47 -0
  381. data/sig/ibex/cli/fuzz_regressions.rbs +40 -0
  382. data/sig/ibex/cli/generation_artifacts.rbs +69 -0
  383. data/sig/ibex/cli/generation_error_messages.rbs +19 -0
  384. data/sig/ibex/cli/grammar_tests.rbs +48 -0
  385. data/sig/ibex/cli/ir_tools.rbs +39 -0
  386. data/sig/ibex/cli/lsp.rbs +14 -0
  387. data/sig/ibex/cli/outputs.rbs +26 -3
  388. data/sig/ibex/cli/racc_migration.rbs +30 -0
  389. data/sig/ibex/cli/reduce.rbs +60 -0
  390. data/sig/ibex/cli/reduce_reporting.rbs +27 -0
  391. data/sig/ibex/cli/samples.rbs +38 -0
  392. data/sig/ibex/cli/verify.rbs +28 -0
  393. data/sig/ibex/cli/watch.rbs +43 -0
  394. data/sig/ibex/cli.rbs +182 -9
  395. data/sig/ibex/codegen/action_locations.rbs +45 -0
  396. data/sig/ibex/codegen/action_method_source.rbs +65 -0
  397. data/sig/ibex/codegen/action_source.rbs +50 -0
  398. data/sig/ibex/codegen/ambiguity.rbs +60 -0
  399. data/sig/ibex/codegen/cst_metadata.rbs +59 -0
  400. data/sig/ibex/codegen/documentation.rbs +50 -0
  401. data/sig/ibex/codegen/explain.rbs +105 -0
  402. data/sig/ibex/codegen/generated_action_abi.rbs +105 -0
  403. data/sig/ibex/codegen/html.rbs +18 -2
  404. data/sig/ibex/codegen/mermaid.rbs +16 -0
  405. data/sig/ibex/codegen/railroad.rbs +82 -0
  406. data/sig/ibex/codegen/railroad_documentation.rbs +31 -0
  407. data/sig/ibex/codegen/rbs.rbs +86 -4
  408. data/sig/ibex/codegen/report.rbs +16 -8
  409. data/sig/ibex/codegen/ruby.rbs +105 -28
  410. data/sig/ibex/codegen/ruby_actions.rbs +54 -0
  411. data/sig/ibex/codegen/ruby_ast.rbs +34 -0
  412. data/sig/ibex/codegen/ruby_error_messages.rbs +16 -0
  413. data/sig/ibex/codegen/ruby_lexer.rbs +25 -0
  414. data/sig/ibex/codegen/ruby_syntax.rbs +27 -0
  415. data/sig/ibex/codegen/ruby_table_metadata.rbs +26 -0
  416. data/sig/ibex/codegen/ruby_value_printers.rbs +28 -0
  417. data/sig/ibex/configuration/analysis_grammar.rbs +13 -0
  418. data/sig/ibex/configuration/explanation.rbs +195 -0
  419. data/sig/ibex/configuration/inspector.rbs +53 -0
  420. data/sig/ibex/configuration.rbs +242 -0
  421. data/sig/ibex/coverage/collector.rbs +78 -0
  422. data/sig/ibex/coverage/event_stream.rbs +44 -0
  423. data/sig/ibex/coverage/report.rbs +102 -0
  424. data/sig/ibex/coverage/runtime_event_validator.rbs +70 -0
  425. data/sig/ibex/coverage.rbs +7 -0
  426. data/sig/ibex/delta_reducer.rbs +38 -0
  427. data/sig/ibex/diff.rbs +47 -0
  428. data/sig/ibex/equiv/machine.rbs +54 -0
  429. data/sig/ibex/equiv.rbs +129 -0
  430. data/sig/ibex/error_messages/parser.rbs +58 -0
  431. data/sig/ibex/error_messages/parser_v2.rbs +67 -0
  432. data/sig/ibex/error_messages/renderer.rbs +23 -0
  433. data/sig/ibex/error_messages/sentence_search.rbs +80 -0
  434. data/sig/ibex/error_messages/update.rbs +43 -0
  435. data/sig/ibex/error_messages.rbs +85 -0
  436. data/sig/ibex/fix.rbs +138 -0
  437. data/sig/ibex/frontend/ast.rbs +237 -22
  438. data/sig/ibex/frontend/bootstrap_parser.rbs +13 -0
  439. data/sig/ibex/frontend/diagnostic.rbs +53 -0
  440. data/sig/ibex/frontend/diagnostic_recovery.rbs +98 -0
  441. data/sig/ibex/frontend/dsl.rbs +33 -4
  442. data/sig/ibex/frontend/formatter.rbs +143 -0
  443. data/sig/ibex/frontend/generated_parser.rbs +228 -68
  444. data/sig/ibex/frontend/generated_parser_base.rbs +65 -12
  445. data/sig/ibex/frontend/generated_parser_includes.rbs +23 -0
  446. data/sig/ibex/frontend/generated_parser_metadata.rbs +23 -0
  447. data/sig/ibex/frontend/generated_parser_parameters.rbs +24 -0
  448. data/sig/ibex/frontend/generation.rbs +6 -0
  449. data/sig/ibex/frontend/lexer.rbs +49 -2
  450. data/sig/ibex/frontend/lexer_recovery.rbs +25 -0
  451. data/sig/ibex/frontend/parser/declarations.rbs +57 -0
  452. data/sig/ibex/frontend/parser/parameters.rbs +28 -0
  453. data/sig/ibex/frontend/parser/rules.rbs +3 -0
  454. data/sig/ibex/frontend/parser.rbs +66 -0
  455. data/sig/ibex/frontend/parser_configuration_support.rbs +27 -0
  456. data/sig/ibex/frontend/regenerator.rbs +11 -0
  457. data/sig/ibex/frontend/resolution.rbs +34 -0
  458. data/sig/ibex/frontend/resolver.rbs +91 -0
  459. data/sig/ibex/frontend/rule_documentation.rbs +42 -0
  460. data/sig/ibex/frontend/source_cursor.rbs +38 -5
  461. data/sig/ibex/frontend/source_document.rbs +119 -0
  462. data/sig/ibex/frontend/source_loader.rbs +66 -0
  463. data/sig/ibex/frontend/source_span.rbs +56 -0
  464. data/sig/ibex/frontend/token_adapter/declaration_document_state.rbs +21 -0
  465. data/sig/ibex/frontend/token_adapter/declaration_lexer_state.rbs +27 -0
  466. data/sig/ibex/frontend/token_adapter/declaration_state.rbs +83 -3
  467. data/sig/ibex/frontend/token_adapter/rule_state.rbs +20 -0
  468. data/sig/ibex/frontend/token_adapter.rbs +11 -2
  469. data/sig/ibex/frontend.rbs +1 -1
  470. data/sig/ibex/fuzz.rbs +71 -0
  471. data/sig/ibex/generation_input.rbs +37 -0
  472. data/sig/ibex/generation_manifest.rbs +70 -0
  473. data/sig/ibex/generation_transaction.rbs +82 -0
  474. data/sig/ibex/generation_transaction_recovery.rbs +36 -0
  475. data/sig/ibex/generation_transaction_validation.rbs +65 -0
  476. data/sig/ibex/grammar_tests.rbs +93 -0
  477. data/sig/ibex/ir/automaton_ir.rbs +35 -10
  478. data/sig/ibex/ir/grammar_ir.rbs +96 -22
  479. data/sig/ibex/ir/lexer_ir.rbs +57 -0
  480. data/sig/ibex/ir/parser_contract.rbs +69 -0
  481. data/sig/ibex/ir/serialize.rbs +75 -23
  482. data/sig/ibex/ir/validator/automaton.rbs +112 -0
  483. data/sig/ibex/ir/validator/base.rbs +69 -0
  484. data/sig/ibex/ir/validator/grammar.rbs +195 -0
  485. data/sig/ibex/ir/validator/lexer.rbs +37 -0
  486. data/sig/ibex/ir/validator.rbs +16 -0
  487. data/sig/ibex/ir.rbs +45 -5
  488. data/sig/ibex/lalr/build_metrics.rbs +60 -0
  489. data/sig/ibex/lalr/builder.rbs +150 -19
  490. data/sig/ibex/lalr/conflict_search.rbs +12 -5
  491. data/sig/ibex/lalr/counterexample.rbs +20 -14
  492. data/sig/ibex/lalr/direct_lookaheads.rbs +93 -0
  493. data/sig/ibex/lalr/goto_follows.rbs +89 -0
  494. data/sig/ibex/lalr/ielr/annotator.rbs +67 -0
  495. data/sig/ibex/lalr/ielr/bits.rbs +14 -0
  496. data/sig/ibex/lalr/ielr/inadequacy.rbs +24 -0
  497. data/sig/ibex/lalr/ielr/item_lookaheads.rbs +35 -0
  498. data/sig/ibex/lalr/ielr/pipeline.rbs +17 -0
  499. data/sig/ibex/lalr/ielr/split_stability.rbs +27 -0
  500. data/sig/ibex/lalr/ielr/split_state.rbs +14 -0
  501. data/sig/ibex/lalr/ielr/state_splitter.rbs +76 -0
  502. data/sig/ibex/lalr/ielr_partition.rbs +71 -0
  503. data/sig/ibex/lalr/inadequacy_report.rbs +21 -0
  504. data/sig/ibex/lalr/lookahead_propagation.rbs +38 -0
  505. data/sig/ibex/lalr/lr0_collection.rbs +50 -0
  506. data/sig/ibex/lalr/on_error_reductions.rbs +22 -0
  507. data/sig/ibex/lalr/unreachable_states.rbs +25 -0
  508. data/sig/ibex/lalr.rbs +17 -1
  509. data/sig/ibex/location.rbs +67 -0
  510. data/sig/ibex/lsp/document_handlers.rbs +24 -0
  511. data/sig/ibex/lsp/document_store.rbs +94 -0
  512. data/sig/ibex/lsp/document_store_diagnostics.rbs +20 -0
  513. data/sig/ibex/lsp/document_store_validation.rbs +26 -0
  514. data/sig/ibex/lsp/initialization_handlers.rbs +30 -0
  515. data/sig/ibex/lsp/navigation_handlers.rbs +33 -0
  516. data/sig/ibex/lsp/parser_configuration_assistance.rbs +49 -0
  517. data/sig/ibex/lsp/position_codec.rbs +44 -0
  518. data/sig/ibex/lsp/protocol_error.rbs +32 -0
  519. data/sig/ibex/lsp/request_handlers.rbs +26 -0
  520. data/sig/ibex/lsp/request_support.rbs +40 -0
  521. data/sig/ibex/lsp/server.rbs +55 -0
  522. data/sig/ibex/lsp/symbol_index.rbs +77 -0
  523. data/sig/ibex/lsp/symbol_index_builder.rbs +88 -0
  524. data/sig/ibex/lsp/symbol_index_precedence_references.rbs +18 -0
  525. data/sig/ibex/lsp/symbol_index_source_queries.rbs +26 -0
  526. data/sig/ibex/lsp/symbol_occurrence.rbs +31 -0
  527. data/sig/ibex/lsp/transport.rbs +47 -0
  528. data/sig/ibex/lsp/workspace.rbs +42 -0
  529. data/sig/ibex/lsp/workspace_analyzer.rbs +69 -0
  530. data/sig/ibex/lsp.rbs +7 -0
  531. data/sig/ibex/messages.rbs +26 -0
  532. data/sig/ibex/metrics.rbs +50 -0
  533. data/sig/ibex/normalize/declarations.rbs +31 -0
  534. data/sig/ibex/normalize/diagnostics.rbs +13 -4
  535. data/sig/ibex/normalize/expander.rbs +22 -16
  536. data/sig/ibex/normalize/expression.rbs +11 -9
  537. data/sig/ibex/normalize/grammar_builder.rbs +11 -0
  538. data/sig/ibex/normalize/inline_expansion.rbs +129 -0
  539. data/sig/ibex/normalize/inline_validation.rbs +40 -0
  540. data/sig/ibex/normalize/lexer.rbs +37 -0
  541. data/sig/ibex/normalize/named_references.rbs +20 -0
  542. data/sig/ibex/normalize/nodes.rbs +14 -0
  543. data/sig/ibex/normalize/parameter_ebnf_lowering.rbs +33 -0
  544. data/sig/ibex/normalize/parameter_lowering.rbs +35 -0
  545. data/sig/ibex/normalize/parameter_substitution.rbs +42 -0
  546. data/sig/ibex/normalize/parameter_validation.rbs +44 -0
  547. data/sig/ibex/normalize/parameters.rbs +51 -0
  548. data/sig/ibex/normalize/parser_configuration.rbs +23 -0
  549. data/sig/ibex/normalize/recovery_declarations.rbs +24 -0
  550. data/sig/ibex/normalize.rbs +129 -18
  551. data/sig/ibex/racc_migration/checker.rbs +36 -0
  552. data/sig/ibex/racc_migration/harness.rbs +16 -0
  553. data/sig/ibex/racc_migration/report.rbs +55 -0
  554. data/sig/ibex/racc_migration.rbs +8 -0
  555. data/sig/ibex/rake_task.rbs +51 -0
  556. data/sig/ibex/samples.rbs +60 -0
  557. data/sig/ibex/table_artifact/builder.rbs +93 -0
  558. data/sig/ibex/table_artifact/cst_projection.rbs +20 -0
  559. data/sig/ibex/table_artifact/document.rbs +27 -0
  560. data/sig/ibex/table_artifact/executor.rbs +66 -0
  561. data/sig/ibex/table_artifact/serializer.rbs +25 -0
  562. data/sig/ibex/table_artifact/validator/metadata.rbs +52 -0
  563. data/sig/ibex/table_artifact/validator/support.rbs +46 -0
  564. data/sig/ibex/table_artifact/validator/tables.rbs +63 -0
  565. data/sig/ibex/table_artifact/validator.rbs +66 -0
  566. data/sig/ibex/table_artifact.rbs +32 -0
  567. data/sig/ibex/table_simulation/result.rbs +36 -0
  568. data/sig/ibex/table_simulation/simulator.rbs +98 -0
  569. data/sig/ibex/table_simulation/step.rbs +42 -0
  570. data/sig/ibex/table_simulation/text.rbs +14 -0
  571. data/sig/ibex/table_simulation.rbs +7 -0
  572. data/sig/ibex/tables.rbs +10 -35
  573. data/sig/ibex/verifiable_generation_bundle.rbs +24 -0
  574. data/sig/ibex/verification_report/builder.rbs +53 -0
  575. data/sig/ibex/verification_report/canonical_ir.rbs +41 -0
  576. data/sig/ibex/verification_report/logical_path.rbs +34 -0
  577. data/sig/ibex/verification_report/validator.rbs +114 -0
  578. data/sig/ibex/verification_report.rbs +44 -0
  579. data/sig/ibex/verify/action_correspondence.rbs +50 -0
  580. data/sig/ibex/verify/language_witness.rbs +112 -0
  581. data/sig/ibex/verify/reference_collection.rbs +63 -0
  582. data/sig/ibex/verify/result.rbs +52 -0
  583. data/sig/ibex/verify/verifier.rbs +170 -0
  584. data/sig/ibex/verify.rbs +6 -0
  585. data/sig/ibex/watch/runner.rbs +58 -0
  586. data/sig/ibex/watch/source_snapshot.rbs +46 -0
  587. data/sig/ibex/watch.rbs +7 -0
  588. data/sig/ibex.rbs +2 -0
  589. metadata +524 -19
  590. data/.rubocop.yml +0 -43
  591. data/CHANGELOG.md +0 -30
  592. data/Rakefile +0 -25
  593. data/Steepfile +0 -10
  594. data/docs/compat-notes.md +0 -37
  595. data/docs/lexer-coverage.md +0 -14
  596. data/docs/phase10-extensions.md +0 -27
  597. data/gemfiles/Gemfile +0 -7
  598. data/gemfiles/Gemfile.lock +0 -98
  599. data/lib/ibex/frontend/grammar.y +0 -156
  600. data/lib/ibex/runtime/parser.rb +0 -360
  601. data/lib/ibex/runtime.rb +0 -8
  602. data/sig/ibex/runtime/parser.rbs +0 -167
  603. data/sig/ibex/runtime.rbs +0 -6
data/docs/architecture.md CHANGED
@@ -1,28 +1,258 @@
1
+ ---
2
+ title: Architecture
3
+ description: Ibex's grammar, IR, parser construction, runtime, and verification boundaries.
4
+ ---
5
+
1
6
  # Architecture and IR schemas
2
7
 
3
- Ibex keeps syntax, grammar meaning, automaton construction, and output concerns behind two versioned immutable contracts.
8
+ Ibex keeps syntax, grammar meaning, automaton construction, and output concerns behind two immutable current contracts.
4
9
 
5
10
  ```text
6
- .y Lexer -> Token adapter -> self-hosted LR Parser ─┐
7
- Ruby DSL ────────┴─> Grammar AST -> Normalizer -> Grammar IR
11
+ .y root/fragments -> Frontend Lexer/CST -> self-hosted LR Parser -> canonical Resolver ─┐
12
+ Ruby DSL ───────────────────────────────────────────────────────┴─> Grammar AST -> Normalizer -> Grammar IR
13
+ | |
14
+ | Lexer IR v1
8
15
  |
9
- set analysis
16
+ set analysis
10
17
  |
11
- SLR/LALR/LR1 Builder -> Automaton IR
18
+ SLR/LALR/IELR/LR1 Builder -> Automaton IR
12
19
  |
13
- Ruby/RBS generators / report / DOT / HTML / counterexamples
20
+ Ruby/RBS/action-shadow generators / report / DOT / Mermaid / HTML / counterexamples
14
21
  ```
15
22
 
16
23
  Frontend changes stop at the Normalizer. Algorithm strategies consume Grammar IR and produce identical Automaton IR shapes.
17
24
  Outputs consume Automaton IR and never call builder internals. The CLI only connects stages and supports JSON resumption.
18
25
 
26
+ IELR has two construction strategies. The conservative `partition` strategy
27
+ builds canonical LR(1) and partitions compatible isocores. The opt-in `direct`
28
+ strategy works from LR(0), goto-follow closures, lane annotations, and targeted
29
+ state splitting before rerunning lookahead propagation. Both use the shared
30
+ conflict resolver and downstream Automaton IR pipeline. See the [IELR guide](ielr.md).
31
+
32
+ ## Execution trust boundary
33
+
34
+ `syntax-only` means that the LR runtime suppresses parser production actions.
35
+ It does not mean that no application Ruby executes.
36
+
37
+ | Execution path | Parser production actions | Generated lexer actions | User `header` / `inner` / `footer` | Trust |
38
+ | --- | --- | --- | --- | --- |
39
+ | Grammar parse/normalize, format, LSP, reports, conflict/diff/equiv/verify/debug, internal fuzz | No | No | No | Nonexecuting without an external-command option |
40
+ | Generated-lexer semantic: `parse`, `lex(...).do_parse`, `parse_with_syntax(source)` | Yes | Yes | May execute when the generated file loads | Trusted application code; not a sandbox |
41
+ | Handwritten pull semantic: `do_parse`, no-argument `parse_with_syntax` | Yes | No | May execute when the generated file loads | Trusted application code; not a sandbox |
42
+ | Caller-fed semantic: `yyparse`, `push` / `finish` | Yes | No | May execute when the generated file loads | Trusted application code; not a sandbox |
43
+ | Generated syntax-only parse | No | Yes | May execute when the generated file loads | Trusted application code; not a sandbox |
44
+ | Future safe syntax profile | No | Declarative built-ins only | No | Nonexecuting profile; not currently available |
45
+
46
+ Static paths operate on source, Grammar IR, Lexer IR, Automaton IR, or parser
47
+ tables without requiring the generated application parser. Parser actions,
48
+ lexer actions, conversions, and user sections remain opaque data on those
49
+ paths. Code generation may emit source that compiles them when the artifact is
50
+ loaded, but the generator does not load that artifact.
51
+
52
+ The static guarantee excludes explicit external-command options.
53
+ `ibex fuzz --against=COMMAND` and `ibex reduce --command=COMMAND` spawn the
54
+ supplied executable and may run arbitrary application code with host permissions.
55
+ Subprocess resource limits and process-group cleanup are not sandboxes and do
56
+ not confine side effects.
57
+
58
+ Semantic runtime entry points execute committed parser production actions.
59
+ Generated lexer actions execute only when tokens are pulled through
60
+ `GeneratedLexer#next_token`; handwritten `next_token`, `yyparse`, and
61
+ `push` / `finish` paths do not invoke that lexer. Syntax-only entry points
62
+ suppress parser actions but still use the generated lexer to emit tokens,
63
+ convert values, and mutate lexer state. Every generated runtime path crosses
64
+ the trusted application boundary because loading the generated Ruby file may
65
+ execute arbitrary user sections. Resource budgets and process-isolation
66
+ building blocks do not make those paths sandboxes.
67
+
68
+ A future profile for untrusted syntax work must use data-only parser tables, a
69
+ declarative lexer whose operations are restricted to built-ins, no parser
70
+ actions, no arbitrary conversions, and no `header`, `inner`, or `footer`
71
+ sections. The current generated parser API must not be described as that
72
+ profile.
73
+
74
+ An optional root-only `lexer` declaration normalizes to the independently versioned
75
+ Lexer IR and its flat rule list, which are embedded unchanged in the current Grammar IR.
76
+ records state, declaration id, pattern source/options, action, and provenance;
77
+ `--emit=lexer-ir` exposes the same document. Code generation compiles every
78
+ pattern with an internal current-position anchor and emits immutable,
79
+ state-indexed rules. Per-parser mutable input, position, emission, and state
80
+ stacks live in `Runtime::GeneratedLexer`, never in the tables. See
81
+ [ADR 0014](decisions/0014-versioned-generated-lexer.md).
82
+
83
+ `pragma cst` remains an optional current Grammar IR flag. Regenerated format-v6
84
+ tables add deterministic kind and normalized slot metadata. `Runtime::Parser`
85
+ builds a pure-syntax Green entry for every shift and reduction on a stack
86
+ parallel to the semantic stack, so tree shape no longer depends on semantic
87
+ actions. Generated lexer skips become token-owned trivia. Parser failure,
88
+ repair, and lexer failure remain explicit and lossless. See
89
+ [ADR 0016](decisions/0016-red-green-concrete-syntax.md) and the
90
+ [CST guide](cst.md). Batch CST, typed views, editing, and serialization form
91
+ the Stable v1 contract. The runtime accepts structured CST metadata only in
92
+ the current format and rejects older CST tables before reading input; see
93
+ [ADR 0008](decisions/0008-versioned-runtime-package-boundary.md).
94
+
95
+ ## Red/Green CST v2
96
+
97
+ Green nodes and tokens contain no parents, source objects, absolute positions,
98
+ semantic values, or parser states. Their integer kinds, binary text, trivia,
99
+ flags, widths, children, and descendant counts are immutable and
100
+ Ractor-shareable. A session-owned `NodeCache` interns unannotated values. Lazy
101
+ Red wrappers add occurrence-specific parent, index, offset, span, location, and
102
+ typed-field navigation. The root is `source_file(start, EOF)`, and
103
+ `to_source` is byte exact for the `leading` and `balanced` trivia policies.
104
+
105
+ Generated `Parser::Syntax::<Name>` classes are typed views over Red nodes using
106
+ the same normalized `@node` metadata as Data AST generation. Persistent edits
107
+ replace one Green occurrence and copy its ancestor path; rewriters, batched
108
+ editors, annotations, and identity-skipping text diffing share that mechanism.
109
+ See [ADR 0017](decisions/0017-persistent-syntax-artifacts.md).
110
+
111
+ `ibex_cst` schema v1 serializes the Green root, kind metadata, compatibility
112
+ counts, and optional preorder parser memo independently of Grammar IR.
113
+ Validation reconstructs every derived width, flag, and descendant count.
114
+ Non-UTF-8 bytes use canonical Base64. See
115
+ [ADR 0017](decisions/0017-persistent-syntax-artifacts.md).
116
+
117
+ Incremental sessions are syntax-only: parser production actions do not run,
118
+ but generated lexer actions do. The generated lexer first validates token/state
119
+ resynchronization. `Blender`
120
+ then offers either a fresh token or an old Green nonterminal to the LR driver.
121
+ A subtree is pushed directly through `goto` only when damage, recorded
122
+ left-state, follow-token identity, error flags, and positive width satisfy the
123
+ conservative reuse proof. Token and parse memos remain preorder/occurrence
124
+ state owned by one session; resource exhaustion falls back to the fresh token
125
+ stream. See [ADR 0018](decisions/0018-conservative-incremental-syntax-reuse.md).
126
+
127
+ `Runtime::SyntaxSession` is a thin generated-language service boundary over
128
+ that same engine. Current generated classes expose only
129
+ `:trusted_application_code`, and callers must explicitly acknowledge that
130
+ profile because lexer actions still execute. Immutable operation snapshots add
131
+ expected-token and reuse/fallback evidence plus cooperative cancellation and
132
+ service bounds. The façade belongs to `ibex-runtime`; it defines neither LSP
133
+ nor workspace semantics. Its additive `repair` operation projects bounded
134
+ syntax repairs into byte edits and fresh syntax results without exposing
135
+ semantic values or invoking application repair callbacks. See
136
+ [ADR 0019](decisions/0019-runtime-syntax-session-boundary.md).
137
+
138
+ Alternative-level `@node` declarations are preserved in the current Grammar IR
139
+ production metadata. Runtime Ruby, static action-shadow Ruby, and generated
140
+ RBS all derive Data node classes and Visitor/Listener hooks from that same
141
+ metadata; action source is never inspected to infer a shape. Symbol semantic
142
+ types and fully annotated nonterminals supply field types.
143
+
19
144
  The text frontend's canonical syntax is `lib/ibex/frontend/grammar.y`. Ibex generates and commits
20
145
  `lib/ibex/frontend/generated_parser.rb`; the public `Frontend::Parser` always delegates to that class. Lexer `Token` objects remain
21
146
  the semantic values passed through `TokenAdapter`, preserving their `Location` in AST nodes and diagnostics. The explicitly named
22
147
  handwritten `BootstrapParser` is excluded from normal loading and exists only to break the regeneration cycle. See
23
- [ADR 0015](decisions/0015-self-hosted-grammar-frontend.md) for the update procedure and boundary.
148
+ [ADR 0003](decisions/0003-self-hosted-grammar-frontend.md) for the update procedure and boundary.
149
+ `lib/ibex/frontend/shadow_grammar.y` describes the same frontend with parameterized list rules and an inline terminal wrapper.
150
+ It is generated only in tests and must match the production parser's AST across the canonical grammar and extended fixtures;
151
+ see the [development guide](development.md).
152
+
153
+ The lexer also retains an immutable lexical CST without changing the semantic token stream. `Frontend::Parser#parse_document`
154
+ returns a `SourceDocument` whose source, token-indexed segments, and AST come from that single lexer/parser pass.
155
+ `SourceSpan` uses half-open zero-based byte offsets and one-based Unicode-scalar line/column positions. Actions and user-code
156
+ bodies remain opaque segments; whitespace, line breaks, both comment forms, user-code markers, and EOF remain individually traversable.
157
+ `render`, byte slicing, and byte/line/column conversion provide the common source contract for formatter, documentation, include,
158
+ and language-server layers. `RuleDocumentation` correlates immediately preceding `##` comment-only lines with semantic rule
159
+ locations and copy-enriches generated Root/Fragment nodes; occupied opaque-segment lines are never scanned as comments. See
160
+ [ADR 0004](decisions/0004-shared-semantic-and-lossless-source-model.md).
161
+
162
+ `Frontend::Formatter` classifies the document's existing semantic tokens, replaces only whitespace/newline trivia, and protects
163
+ token, comment, action, heredoc, marker, and user-code bytes. It reparses the rendered root or fragment in the same frontend mode
164
+ and compares ASTs with an explicit work stack after removing location fields. The CLI's stdout, batch check, and transactional
165
+ in-place surfaces are therefore downstream consumers of `SourceDocument`, not an alternate grammar parser. Existing newline
166
+ segment spellings and blank-line counts survive required line boundaries; new boundaries use the first newline even when it is
167
+ inside opaque text. Batch stages and hard-link backups live beside each resolved target. Alias rejection, reverse rollback, and
168
+ all-directory synchronization preserve full file modes and relative or absolute symlink identities. Backups are synchronized
169
+ before installation; a failed restore preserves its backup, while post-commit cleanup problems are status-0 warnings. See
170
+ [ADR 0004](decisions/0004-shared-semantic-and-lossless-source-model.md).
171
+
172
+ `Frontend::SourceLoader` is the shared disk/overlay read boundary. Resolver's default loader retains canonical filesystem
173
+ behavior; LSP injects open buffers, including safe new files, while the resolver continues to enforce realpath containment,
174
+ symlink escape rejection, cycle identity, and diamond deduplication. `LSP::DocumentStore` layers monotonic open versions,
175
+ root/include closures, reverse dependencies, and disk restoration over that loader. `PositionCodec` is the only UTF-16 adapter
176
+ over frontend byte/scalar spans. `SymbolIndex` derives navigation and guarded rename edits from parsed nodes and lossless tokens,
177
+ never from opaque Ruby or textual scanning. Content-Length transport, lifecycle handling, and request handlers remain separate
178
+ from workspace semantics; see [ADR 0004](decisions/0004-shared-semantic-and-lossless-source-model.md).
179
+
180
+ CLI file generation renders every requested output into an immutable `ArtifactSet` before entering `GenerationTransaction`.
181
+ The transaction records the exact root, fragment, IR, and message bytes read through `GenerationInput`, rejects portable target
182
+ collisions and input aliases, takes stable sidecar locks, stages and synchronizes every file, and can restore hard-link backups
183
+ in reverse publication order. Ordinary companions publish first, the parser second, and an opt-in generation manifest last.
184
+ That manifest is the coherence marker: readers verify its listed paths, sizes, and SHA-256 digests and retry from a newly read
185
+ manifest on a mismatch. It is not a claim that several filesystem renames occur atomically. `--watch` feeds the same transaction
186
+ only candidates whose complete canonical source closure and failed include attempts remain unchanged across rendering and
187
+ publication. Portable polling, bounded debounce, failure deduplication, and cancellable nonblocking locks keep the last successful
188
+ generation usable while a source is invalid; see [ADR 0013](decisions/0013-transactional-generation-publication.md).
189
+ The executable's ordinary generation path declares this pipeline directly instead of loading the complete library and every
190
+ subcommand. Optional subcommands and generation outputs load at their invocation boundary while their public constants remain
191
+ autoloadable.
192
+
193
+ ### Effective configuration boundary
24
194
 
25
- The RBS generator emits the generated class namespace, superclass, parser-table constants, and `.parser_tables` contract. The
195
+ `Ibex::Configuration` gives generation, grammar-test, and analysis paths one closed definition for parser construction and
196
+ build-policy concepts. Each immutable value records its canonical key, typed domain, owner, override policy, selected origin,
197
+ explicitness, and whether the selection is canonical. `Configuration::CLIAdapter` translates the existing internal option
198
+ hash into domain values such as `parser.entries=isolated`, `cst.trivia=leading`, and
199
+ `source.line_mapping=all`; code generators do not interpret legacy CLI shapes directly.
200
+
201
+ `Configuration::Resolver` applies fixed and monotone-minimum algebra without loading a grammar file or executing user code.
202
+ A fixed grammar declaration accepts a matching request and raises `Configuration::Conflict` for a contradiction. An explicit
203
+ analysis override remains noncanonical and serializes both the declared and selected values. Evidence JSON is emitted in
204
+ canonical-key order. This boundary intentionally adds neither grammar syntax nor a project configuration file; those adapters
205
+ must supply the same closed keys when their separately reviewed formats exist.
206
+
207
+ Extended grammar paths cross an explicit `Frontend::Resolver` boundary. The canonical `import` declaration and compatible
208
+ `include` spelling share this boundary. Roots retain class, start, options, and user code;
209
+ fragments contain composable declarations and rules. Canonical realpaths define DFS order, diamond deduplication, cycle identity,
210
+ and the Rake dependency closure. Canonical dirname ancestry keeps every resolved target below the root grammar directory after
211
+ symlink resolution, including when that directory is a filesystem or drive root. The source-only Parser never follows an
212
+ include. A `Resolution` recursively freezes its owned AST and defensive provenance copies while retaining rule identity for
213
+ include-chain lookup. Rake resolves this closure at task definition and refuses invalid graphs before timestamp checks can reuse
214
+ a stale output; see [ADR 0005](decisions/0005-contained-grammar-composition.md).
215
+
216
+ Extended parameterized definitions remain structural AST templates rather than grammar symbols. The Normalizer validates the
217
+ complete template graph, interns an impossible `$parameter_N` helper for each canonical call, records that helper in a memo
218
+ before expanding its body, and substitutes formals through nested EBNF and calls. Resumable alternative, item, and EBNF
219
+ continuations on an explicit depth-first worklist preserve ordinary lowering order and active-depth semantics without consuming
220
+ the Ruby call stack. Same-argument recursion therefore closes over the memo, while a configurable total-specialization budget
221
+ and structural constructor-growth detection bound argument-growing recursion without an arbitrary depth cutoff. Template actions,
222
+ precedence, metadata, documentation, locations, and definition include chains flow into the specialized productions; see
223
+ [ADR 0006](decisions/0006-bounded-structural-grammar-lowering.md).
224
+
225
+ Inline definitions are lowered temporarily, then a bounded deterministic post-pass substitutes marked alternatives through
226
+ ordinary, parameterized, and EBNF productions before diagnostics and LR construction. It removes every marked symbol and
227
+ production, remaps the dense symbol/production ids, and retains eliminated semantic reductions as a stable post-order
228
+ action plan. The plan addresses flattened physical values followed by earlier logical results, records a nullable semantic
229
+ `result_type` on every newly emitted step, reconstructs surrounding stack
230
+ prefixes and semantic spans, and remains executable after IR serialization. Cycle validation covers paths through ordinary
231
+ rules and templates; the default 10,000-production cartesian budget is configurable. See
232
+ [ADR 0006](decisions/0006-bounded-structural-grammar-lowering.md).
233
+
234
+ The strict generated frontend remains the grammar authority during batch diagnostics. A diagnostic parse retries it after
235
+ suppressing only a whole declaration, whole rule, or outer alternative at balanced delimiters. Each retry must remove a new
236
+ original token and both attempts and emitted diagnostics are bounded. Lexical and syntax phases collect independently before a
237
+ global source-order limit is applied, so an earlier syntax error cannot be hidden by a later lexical error. Machine-readable
238
+ diagnostics retain source spans, defensive locations, and stable codes. A repaired AST is marked partial by `ParseResult`, and
239
+ is not attached to the unchanged source document. After a successful root parse, the CLI reports the first resolver grammar
240
+ failure through the same diagnostic schema, while actual resolution I/O failures remain invocation errors. The CLI exposes this
241
+ analysis only through `ibex diagnose`; see [ADR 0004](decisions/0004-shared-semantic-and-lossless-source-model.md).
242
+
243
+ The RBS generator emits the generated class namespace, superclass, parser-table constants, `.parser_tables` contract, and
244
+ private reduction and composed-fragment signatures. Declared symbol types refine the RHS tuple and LHS result independently,
245
+ with `untyped` used at undeclared boundaries; composed inputs resolve either a physical symbol type or an earlier plan step's
246
+ `result_type`. Reduction methods also receive a location tuple, surrounding location stack, and optional
247
+ `Runtime::LocationSpan`. Generated tables mark whether actions require locations. The runtime leaves the location stack
248
+ unallocated for ordinary two-element-token parses and creates or backfills it only when an action, tooling observer, or
249
+ three-element token requires it. The public immutable `Ibex::Location` range and `loc`/`result_loc` action helpers sit above the
250
+ same stack contract.
251
+ Default source mapping compiles opaque action methods with `class_eval` when the generated class loads. The opt-in action-shadow
252
+ generator makes those exact method bodies visible to Steep without runtime loading: runtime and shadow output share one method
253
+ source builder, while the shadow omits parser infrastructure and every user-code section. Ibex only generates this source;
254
+ executing Steep remains an application/CI boundary. See
255
+ [ADR 0011](decisions/0011-versioned-semantic-action-boundary.md). The
26
256
  gem also ships a one-to-one rbs-inline-generated signature tree under `sig/` for every Ruby source in `lib/`, including the
27
257
  self-hosted parser. CI regenerates into an empty temporary directory, compares the complete trees, validates the RBS environment,
28
258
  and runs Steep against the entire library. Token/location records, grammar AST nodes, parser classifier and bootstrap state, the
@@ -30,38 +260,91 @@ Ruby DSL, IR records, and automaton actions use concrete domain types. Generated
30
260
  cells, decoded JSON values, and user methods embedded as opaque Ruby source remain `untyped`; applications can reopen the generated
31
261
  class in their own RBS files to declare embedded methods.
32
262
 
33
- ## Grammar IR v1
263
+ ## Current Grammar IR
264
+
265
+ <!-- stable:current-ir:v1 -->
34
266
 
35
267
  Top-level fields:
36
268
 
37
269
  | Field | Meaning |
38
270
  |---|---|
39
- | `ibex_ir`, `schema_version` | `"grammar"`, `1` |
271
+ | `ibex_ir`, `schema_version` | `"grammar"`, current format |
40
272
  | `class_name`, `superclass` | Generated Ruby class contract |
41
- | `start`, `expect`, `options` | Start name, unresolved S/R expectation, result/action flags |
273
+ | `start`, optional `starts`, `expect`, `options` | Primary/ordered start names, unresolved S/R expectation, result/action flags |
274
+ | optional `params`, `printers` | Generated-constructor keywords and symbol-specific debug value formatters |
275
+ | optional `lexer` | Embedded independently versioned Lexer IR |
42
276
  | `symbols` | Interned terminals and nonterminals; `$eof` id 0 and `error` id 1 |
43
277
  | `productions` | Numeric LHS/RHS ids, action, precedence override, source origin |
44
278
  | `user_code`, `conversions`, `warnings` | Concatenated code, external token expressions, structured diagnostics |
45
279
  | `user_code_chunks` | Optional opaque chunks with first-code-line locations for compatible source mapping |
46
280
 
47
- Warning records use stable type names (`undeclared_terminal`, `unused_terminal`, `unreachable_nonterminal`,
48
- `duplicate_production`, and `empty_language`) and retain source locations. The CLI applies display/error policy at the boundary;
281
+ Warning records use the additive type vocabulary `undeclared_terminal`, `unused_terminal`, `unused_precedence`,
282
+ `unreachable_terminal`, `unreachable_nonterminal`, `duplicate_production`, and `empty_language`, and retain source locations.
283
+ The CLI applies display/error policy at the boundary;
49
284
  normalization and IR serialization do not discard diagnostics.
50
285
 
51
- A symbol has `id`, `name`, `kind`, `reserved`, optional `prec {associativity, level}`, and `loc`. A production has `id`, `lhs`,
52
- `rhs`, optional `action`, optional `prec_override`, and `origin`. Synthetic EBNF origins include an additive, deterministic
53
- `expression` label used by text, DOT, and HTML presentation while numeric symbol identities remain unchanged. An action has opaque
54
- `code`, `loc`, `named_refs [{name,index}]`, and `context_length`; middle-action helpers use the last field to view preceding stack
55
- values.
286
+ A symbol has `id`, `name`, `kind`, `reserved`, optional `prec {associativity, level}`, `loc`, `display_name`, and
287
+ `semantic_type`.
288
+ A production has `id`, `lhs`, `rhs`, optional `action`, optional `prec_override`, and `origin`. Synthetic EBNF origins include
289
+ an additive, deterministic `expression` label used by text, DOT, and HTML presentation while numeric symbol identities remain
290
+ unchanged. An action has opaque `code`, `loc`, `named_refs [{name,index}]`, and `context_length`; middle-action helpers use the
291
+ last field to view preceding stack values.
56
292
 
57
- IR objects and nested collections are frozen. JSON keys have deterministic order, so dump/load/dump is byte-stable. Incompatible
58
- schema changes require a new version. The additive `user_code_chunks` field is optional so older schema-v1 JSON remains loadable;
59
- new text-front-end IR retains it to make direct and resumed `--line-convert-all` generation identical.
293
+ IR objects and nested collections are frozen. JSON keys have deterministic order, so dump/load/dump is byte-stable.
60
294
 
61
- ## Automaton IR v1
295
+ Normalized grammars use the current format for declaration-free source and carry explicit nullable metadata:
62
296
 
63
- Top-level fields are `ibex_ir: "automaton"`, `schema_version`, `algorithm`, `grammar_digest`, embedded `grammar`, `states`, and
64
- `conflict_summary`. Embedding Grammar IR makes automaton JSON sufficient for code generation after `--from=automaton-ir`.
297
+ | Record | Current-format metadata |
298
+ |---|---|
299
+ | grammar | `source_provenance {file, root, byte_span {start,end}}` |
300
+ | symbol | `doc` |
301
+ | production | `doc` and `expansion {parameter, inline, include_chain}` |
302
+ | action | `composition {strategy, fragments, plan {version, physical, steps}}`; new steps include nullable `result_type` |
303
+
304
+ The source-only text frontend supplies the source filename and leaves unknown metadata null. A resolved grammar also supplies its
305
+ canonical source root and each production's include chain while preserving its original-file origin. Lossless rule comments
306
+ populate symbol and user-production documentation, including through fragment resolution; synthetic EBNF helpers remain
307
+ undocumented. Parameterized specializations populate `expansion.parameter` with the template name and canonical structural
308
+ arguments while retaining the definition's include chain.
309
+ The current format adds one closed, root-owned `parser_contract`. Its `algorithm`, `entries`, and `cst_trivia` members each carry
310
+ `value`, `explicit`, and `loc`. An explicit member has an admitted value and source location; an unspecified member has all
311
+ three states fixed to `value: null`, `explicit: false`, and `loc: null`. Unspecified is not an encoding of the current built-in
312
+ default. The contract sits only at the root, so fragments cannot change parser-wide construction while their normalized
313
+ productions and source provenance remain composable.
314
+
315
+ Extended root grammars can populate `algorithm` and `entries` through one
316
+ domain-specific `parser ... end` declaration. The frontend rejects that block
317
+ in fragments and compatible mode, and rejects duplicate blocks, duplicate or
318
+ unknown keys, unknown values, and `algorithm auto` before normalization. The
319
+ typed configuration resolver treats those values as fixed grammar contracts:
320
+ canonical generation accepts only an absent or matching CLI request. Analysis
321
+ and grammar-test commands may move an explicitly different algorithm into a
322
+ reported noncanonical analysis origin; entry construction remains fixed. The
323
+ configuration inspector reads the same AST and import closure without running
324
+ actions or user sections.
325
+
326
+ `Serialize.load` and `Validator.validate` accept only the current Grammar IR format. Both declaration-free and
327
+ `parser`-declared sources write that same format, so there is no in-process migration path or compatibility reader.
328
+ Callers construct the current object directly through `IR::Grammar.new`; see
329
+ [ADR 0020](decisions/0020-grammar-ir-parser-contract.md).
330
+
331
+ The v1 stabilization freeze covers required core fields, meanings, ordering,
332
+ identity, and validation behavior. The future `x-` experimental namespace is
333
+ outside that freeze, but current schemas remain closed and reject unknown
334
+ fields. Experimental data must therefore begin in a new additive schema
335
+ version rather than weakening an existing document. See
336
+ [stability and deprecation](stability.md).
337
+
338
+ `Codegen::Documentation` renders normalized user rules and alternatives as escaped Markdown, self-contained accessible HTML, or
339
+ railroad SVG. The railroad renderer includes visible wrapped rule descriptions in its section-height calculation and exposes the
340
+ full escaped text through SVG descriptions. `ibex doc` resolves the same canonical include graph and writes to stdout or an
341
+ atomic file without generating or executing application parser code.
342
+
343
+ ## Current Automaton IR
344
+
345
+ Top-level fields are `ibex_ir: "automaton"`, `schema_version`, `algorithm`, `grammar_digest`, embedded `grammar`, `states`,
346
+ optional `entry_states`, and `conflict_summary`. Embedding Grammar IR makes automaton JSON sufficient for code generation after
347
+ `--from=automaton-ir`. A multi-entry automaton maps every ordered grammar start name to its initial state.
65
348
 
66
349
  Each state contains:
67
350
 
@@ -70,30 +353,193 @@ Each state contains:
70
353
  - resolved terminal `actions` and nonterminal `gotos`;
71
354
  - an optional reduce `default_action`, selected only when explicit error masks preserve every terminal lookup and reduce the
72
355
  total encoded ACTION entries;
73
- - every conflict, including precedence-resolved conflicts and the resolution reason.
356
+ - every conflict, including precedence-resolved conflicts and the resolution reason; multi-entry conflicts also carry their
357
+ reachable `entries` and optional `composite` marker.
74
358
 
75
359
  `conflict_summary.sr` counts unresolved default-shift conflicts for `expect`; `resolved_sr` counts retained precedence or
76
360
  associativity decisions; `rr` counts reduce/reduce cells.
77
361
 
362
+ The current Automaton IR embeds the exact current Grammar IR, includes the parser contract in `grammar_digest`, and records
363
+ `entry_construction` as `shared` or `isolated`. Older documents are rejected rather than migrated. Callers construct the
364
+ current object directly through `IR::Automaton.new`.
365
+
366
+ `--from=grammar-ir` applies the current parser contract through the typed configuration resolver before constructing tables;
367
+ matching CLI values are allowed and conflicts are rejected with the contract location. `--from=automaton-ir` generates without
368
+ the original source and rejects algorithm/entry construction flags because its tables are already built. A generation
369
+ manifest records the grammar digest and contract separately from the embedded automaton's algorithm/entry facts and codegen-only
370
+ effective configuration. Static IR views validate opaque action strings but never execute them. Published Draft 2020-12
371
+ contracts for both current IR documents live under `schema/`; see
372
+ [ADR 0001](decisions/0001-separate-ir-pipeline.md).
373
+
374
+ `--emit=sets` is a deterministic analysis view rather than another IR: it emits lexically sorted nullable nonterminals and
375
+ FIRST/FOLLOW maps for nonterminals. DOT, Mermaid, and the self-contained searchable HTML report are deterministic presentation
376
+ views over Automaton IR.
377
+
378
+ ## Construction algorithms and counterexamples
379
+
380
+ The `lalr` and `slr` strategies construct LR(0) states directly for a single entry. LALR lookaheads are the least fixed point of deterministic
381
+ shift, spontaneous-FIRST, and nullable-suffix propagation edges over item occurrences; SLR replaces completed lookaheads with
382
+ FOLLOW sets. Multiple entries seed distinct augmented canonical items and use canonical core merging because the direct
383
+ lookahead graph has a single-root contract. Canonical `lr1` retains the canonical collection. An explicit canonical-and-merge
384
+ LALR reference strategy proves byte equivalence without changing the Automaton IR algorithm label. `ielr` conservatively merges action-compatible canonical
385
+ states and refines partitions until outgoing transitions are congruent, avoiding LALR inadequacies without promising a minimum
386
+ state count. `--entry-isolation` instead constructs each start independently and concatenates the resulting state sets with
387
+ deterministic offsets. Shared builds attribute reachable entries to conflicts and compare isolated conflict fingerprints to
388
+ identify merge-created composite conflicts. All strategies use the same conflict resolver and default reduction pass. After a build, frozen diagnostic
389
+ `metrics` record the strategy and construction/final state counts, plus a canonical count only when one was actually built. See
390
+ [ADR 0007](decisions/0007-shared-parser-construction-pipeline.md).
391
+
392
+ `Ibex::LALR::Counterexample` consumes only Automaton IR. For each conflict it explores parser-stack configurations, forces the
393
+ competing actions, and searches for a common accepting suffix. A successful result contains both complete derivation trees and is
394
+ marked `unifying: true`. Search defaults to 32 tokens and 50,000 configurations; the Ruby and CLI APIs can set both positive
395
+ budgets. If no common sentence is found within them, the result is explicitly marked nonunifying and contains the deterministic
396
+ shortest reachability witness instead of claiming ambiguity.
397
+
398
+ `Ibex::Codegen::Explain` filters those immutable conflicts by state and canonical token identity before asking
399
+ `Counterexample#for_conflict` to search only the selected entries, then renders text or the versioned `explain` JSON analysis
400
+ shape. `Counterexample#all` retains its original all-conflict behavior. The view performs no additional parser analysis and does
401
+ not extend Grammar or Automaton IR.
402
+
403
+ `Ibex::Verify::Verifier` accepts validated Automaton IR and derives LR(0) or
404
+ canonical LR(1) collections from the embedded Grammar IR without calling the
405
+ parser builder. Default checks validate item/action soundness,
406
+ algorithm-specific lookaheads, expanded default reductions and error masks,
407
+ reachability, productivity, epsilon termination, resolver consistency, and
408
+ rebuilt plain/compact row equality. `--strict` adds collection completeness
409
+ and reports that same row equality as V5 rather than V4. The verifier does not
410
+ consume generated Ruby or a supplied executable table artifact. Strict IELR
411
+ verification also runs the bounded V9 canonical acceptance witness; this is
412
+ not an unbounded equivalence proof. Its exact
413
+ shared dependencies, algorithm limits, resource semantics, fault mapping, and
414
+ non-goals are documented in the [verifier trust boundary](verifier-trust-boundary.md).
415
+ `ibex verify` uses exit statuses 0 for valid, 1 for a violation, and 2 for
416
+ reference-budget exhaustion.
417
+
418
+ `Ibex::Equiv` first compares normalized grammar structure, then generates
419
+ sentences in both directions and explores the product of two immutable LR
420
+ state-stack machines in breadth-first order. The product key includes both
421
+ stacks, statuses, and consumed-action counts; a supplied rule map also adds
422
+ both postorder reduction traces. The first reported token witness is therefore
423
+ shortest within the declared token/configuration bounds. Simulation uses only
424
+ Automaton IR actions and gotos. It validates both inputs with the independent
425
+ verifier and does not evaluate semantic actions. A rule map requests bounded
426
+ tree comparison; without one, only accepted language is compared. Every
427
+ successful bounded report explicitly states that it is not an equivalence
428
+ proof.
429
+
430
+ `Ibex::Fix` composes those two read-only safety oracles around a finite repair
431
+ space. It rebuilds a candidate through the shared construction pipeline, but
432
+ accepts it only after the target fingerprint disappears, other fingerprints
433
+ do not increase, independent verification succeeds, and bounded language plus
434
+ identity-mapped reduction traces find no difference. User actions remain
435
+ opaque. Source proposals are whole-file deterministic edits; the CLI delegates
436
+ application to the existing transactional writer and refuses aliased inputs.
437
+ `Ibex::Diff` and `Ibex::Metrics` are deterministic views over the same frozen
438
+ Grammar and Automaton IR. They do not add an IR stage or alter generated
439
+ parsers.
440
+
441
+ `Ibex::BisonImport` is a clean-room adapter in front of that frozen pipeline.
442
+ Its iterative scanner recovers declarations, production alternatives, source
443
+ positions, and opaque C actions under byte/token/rule/action budgets, then
444
+ emits ordinary extended source. It adds no frontend syntax or IR field.
445
+ Deterministic terminal/nonterminal namespaces prevent Bison casing and keyword
446
+ rules from changing symbol kinds. The report separates unsupported directives
447
+ that leave the recovered production graph complete from structural gaps.
448
+ Analysis may continue across either result, but Ruby generation rejects the C
449
+ action sentinel and `Fix` rejects structurally incomplete source. Pinned
450
+ third-party grammars exist only in temporary external CI directories; see the
451
+ [import guide](bison-import.md).
452
+
453
+ The repository's self-authored representative grammar feeds the current versioned `ibex_benchmark` v2 document. Its JSON Schema
454
+ is shipped beside the IR schemas, while committed environment-specific observations live under the matching
455
+ `benchmark/results/vN` directory. Timing and peak RSS remain non-gating; CI reproduces only deterministic structure and digests.
456
+ See the [benchmark guide](../benchmark/README.md).
457
+
78
458
  ## Runtime table contract
79
459
 
80
460
  Generated subclasses expose `.parser_tables` with a required `format_version`, external `tokens`, display `token_names`, ACTION
81
461
  and GOTO tables, per-state default actions, and production `{lhs,length,action}` records. The runtime validates the version before
82
- reading input and rejects missing or unsupported formats with a regeneration instruction; see
83
- [ADR 0018](decisions/0018-parser-table-format-version.md). Plain tables are arrays of Hash rows. Compact tables use row
462
+ reading input and rejects missing or unsupported formats with a regeneration instruction. The generator emits v6. For non-CST
463
+ tables, the runtime accepts v1's two-argument actions, v2/v3 explicitly marked five-argument location actions, v3 explicitly
464
+ marked six-argument composed actions, v4 one-Array values actions, and v5/v6 positional actions. Marker contracts are validated
465
+ before input. A CST table is executable only when it uses current format-v6 structured metadata; older or boolean CST shapes
466
+ must be regenerated. See
467
+ [ADR 0008](decisions/0008-versioned-runtime-package-boundary.md). Plain tables are arrays of Hash rows. Compact tables use row
84
468
  displacement with offsets, values, and row-ownership checks; both expose equivalent lookups. Default reductions are restricted
85
469
  to known token ids, and explicit error masks preserve the pre-optimization result of every declared terminal cell, including
86
- the synthetic `error` terminal. The deterministic size policy is fixed by
87
- [ADR 0014](decisions/0014-compatibility-safe-default-reductions.md).
470
+ the synthetic `error` terminal. Extended parser tables opt `expected_tokens` into lookahead correction: the runtime copies only
471
+ the state stack and simulates reductions and gotos for each declared terminal, without evaluating semantic actions. The explicit
472
+ `expected_tokens_exact` API exposes the same result for compatible tables. The deterministic size policy is fixed by
473
+ [ADR 0008](decisions/0008-versioned-runtime-package-boundary.md).
474
+
475
+ Runtime execution is packaged independently as `ibex-runtime`, with its own version and RBS tree. The generator package depends
476
+ on a compatible runtime series but does not duplicate runtime-owned files. Compact lookup values live in a runtime-safe leaf
477
+ file, while table construction remains generator-only. Normal output requires only `ibex/runtime`; `-E` embeds the same sources.
478
+ See [ADR 0008](decisions/0008-versioned-runtime-package-boundary.md).
88
479
 
89
480
  The runtime maintains state and value stacks, pulls a lookahead only when required, and applies tagged `shift`, `reduce`,
90
481
  `accept`, and `error` actions. Recovery pops to a state that shifts token id 1, suppresses repeated reports for three successful
91
- shifts, and honors `yyerrok`. No-op `on_shift`, `on_reduce`, and `on_error_recover` extension points observe successfully
482
+ shifts, and honors `yyerrok`. No-op shift, reduce, recovery, location-aware, and discard extension points observe successfully
92
483
  committed events without changing parser results; the recovery hook retains the pre-pop error context and is distinct from an
93
- ordinary token shift. Their ordering and payload contract is fixed by [ADR 0013](decisions/0013-runtime-observation-hooks.md).
484
+ ordinary token shift. A configured value printer affects only human `yydebug` output. Their ordering and payload contract is
485
+ extended additively by
486
+ [ADR 0010](decisions/0010-committed-runtime-observation.md). Grammar-declared
487
+ symbol printers are optional current IR metadata compiled into private methods and
488
+ an id-indexed table.
489
+
490
+ Ordinary generated tables are recursively frozen and made Ractor-shareable. Threads and Ractors share those tables but parse
491
+ through distinct instances; stacks, lookahead, lexer state, callbacks, observers, and semantic values are session-owned. A
492
+ single instance rejects overlapping drivers. Immutable `Runtime::ResourceLimits` values bound every stack push and recovery
493
+ entry with finite defaults. Exhaustion raises the structured `ResourceLimitError`; see
494
+ [ADR 0009](decisions/0009-isolated-parser-sessions.md).
495
+
496
+ Extended current Grammar IR may additionally carry synchronization terminals and ordered `%on_error_reduce` groups. Table
497
+ construction fills only otherwise erroneous ACTION cells with a unique highest-priority completed declared production. At
498
+ runtime, an explicit shift of the synthetic `error` token always wins; only when it is unavailable does panic recovery discard
499
+ through a configured synchronization token and pop to a state that accepts that retained lookahead. Generated parsers without
500
+ sync declarations omit the optional table field. The pull/push ordering and observer contract are fixed by
501
+ the runtime and grammar reference documentation.
502
+
503
+ The separate `Runtime::Parser#observe` API publishes ordered, immutable schema-v1 events for tooling. Its bounded sanitizer
504
+ copies only JSON data and never retains application identities or private stacks. With no observer, parse transitions construct
505
+ no Event, payload summary, or dispatch snapshot; parser initialization still creates its ownership mutex. Generated tables
506
+ contribute grammar digest, table format, state count, and production count to the `start` event. `Runtime::EventJSONLTracer`
507
+ exposes the versioned stream. The protocol and
508
+ exception/threading behavior are fixed by
509
+ [ADR 0010](decisions/0010-committed-runtime-observation.md).
510
+
511
+ Optional `Runtime::RepairPolicy` drives a bounded Dijkstra search over copied state stacks and buffered token identities. Search
512
+ uses explicit/default ACTION, GOTO, and production shape only; it never executes semantic code. A selected immutable edit plan is
513
+ reported once, then replayed through the ordinary runtime so actions and hooks remain committed-path effects. Pull lookahead,
514
+ push buffering, deterministic tie-breaking, fallback to yacc recovery, and no-policy compatibility are fixed by
515
+ [ADR 0012](decisions/0012-bounded-nonexecuting-analysis.md).
516
+
517
+ `Coverage::Collector` accepts only contiguous, complete runtime-event sessions with generated parser metadata. It counts entries
518
+ to the initial, shift, reduce-goto, and recovery states and counts committed reductions by production id. `Coverage::Report`
519
+ publishes ascending sparse hit arrays under the versioned runtime-coverage schema. Merge requires identical full grammar digest,
520
+ table format, and totals and uses checked addition. The coverage CLI only reads bounded JSON/JSON Lines and never loads generated
521
+ Ruby or executes semantic actions; collection, merge, threshold, and atomic-output policy are fixed by
522
+ [ADR 0010](decisions/0010-committed-runtime-observation.md).
523
+
524
+ `TableSimulation::Simulator` is a separate state-stack interpreter over validated Automaton IR. It resolves an explicit ACTION
525
+ cell before a default action, so explicit error masks remain authoritative, and never evaluates the opaque semantic-action
526
+ source stored in Grammar IR. Immutable steps expose state, lookahead, selected action source, reduction/goto metadata, and stack
527
+ depth. Action and stack budgets bound default/epsilon cycles and growth. The text/JSON CLI and versioned output contract are
528
+ fixed by [ADR 0012](decisions/0012-bounded-nonexecuting-analysis.md).
529
+
530
+ The current Grammar IR may carry ordered accept/reject source tests without adding them to parser tables. `GrammarTests::Runner` generates
531
+ one embedded parser and executes fresh parser instances in a separate Ruby process, distinguishing `ParseError` rejection from
532
+ lexer/application errors and bounding the whole suite by a timeout. The separate runner loads the generated file, so guarded
533
+ footer programs stay inactive. The source contract, isolation boundary, and CI behavior are fixed by
534
+ the grammar reference documentation.
94
535
 
95
536
  ## Clean-room boundary
96
537
 
97
538
  Implementation work uses public racc documentation, CLI black-box behavior, and published LR algorithms only. racc implementation
98
539
  sources and generated source are not inputs to the design. Self-authored compatibility grammars execute both outputs in separate
99
540
  processes and compare observable results.
541
+
542
+ `RaccMigration::Checker` treats grammar code as opaque while reporting default-mode parse/normalization errors and known runtime
543
+ coupling. The separate harness generator emits source only; its output refuses an empty corpus and makes bounded child-process
544
+ execution explicit. The boundary is fixed by
545
+ [ADR 0012](decisions/0012-bounded-nonexecuting-analysis.md).