Skip to content

Commit 5a73a00

Browse files
committed
docs: add TODO files for remaining ISC migration work
TODO.rababa/: 01-fix-deep-equivalence-diffs — 13 remaining cosmetic/edge-case differences 02-investigate-imp-failing-maps — 2 maps Ruby DSL can't parse (ISC can) 03-fix-isc-spec-failures — bundler/Ruby 3.4 incompatibility workaround 04-commit-isc-to-maps-repo — push 289 .isc files to interscript/maps 05-performance-large-cjk-maps — Parslet PEG backtracking on 40k+ line maps TODO.secryst/: 01-typescript-runtime-parity — port ISC parser to TS (user requirement) 02-is1-specification-compilation — compile Metanorma spec document 03-isc-compiler — compile .isc to executable Ruby/JS for performance 04-ruby-dsl-array-keys-bug — DSL silently drops url/notes fields 05-isc-runtime-integration — bridge ISC document hash to Node objects
1 parent da3118a commit 5a73a00

10 files changed

Lines changed: 366 additions & 0 deletions
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
# 01 — Fix remaining 13 deep equivalence differences
2+
3+
## Priority: HIGH
4+
5+
## Current State
6+
- 274/289 deep equivalent
7+
- 2 IMP-fail (ISC parses, Ruby DSL can't — ISC is strictly more capable)
8+
- 13 differ (cosmetic / edge cases)
9+
10+
## Remaining Differences
11+
12+
### Description whitespace normalization (5 maps)
13+
- `alalc-kor-Hang-Latn-1997`: description quoted value spans multiple lines
14+
- `gki-bel-Cyrl-Latn-2000`: description has relative indentation preserved by DSL
15+
- `var-pra-Deva-Latn-iast-1912`, `var-san-Deva-Latn-iast-1912`: description content truncation
16+
17+
**Fix:** The `normalize_heredoc` in `DocumentBuilder` strips ALL leading whitespace.
18+
The DSL strips only the COMMON indent (YAML dedent). Need a proper dedent
19+
algorithm that:
20+
1. Finds the minimum indent across all non-blank lines
21+
2. Strips only that amount, preserving relative indentation
22+
3. Handles the first line specially (grammar consumed its indent after `{`)
23+
24+
### Codemod edge cases (6 maps)
25+
- `alalc-tir-Ethi-Latn-1997/2011`: description includes `implementation_notes:` text
26+
- `bgnpcgn-fas-Arab-Latn-1956`: `TODO: Add tests from PDF` treated as metadata field
27+
- `mext-jpn-Hrkt-Latn-1954`: metadata name has CJK text, description mismatch
28+
- `odni-ara/fas/prs-Arab-Latn-2004`: description `[]` or `notes:` text leaking
29+
30+
**Fix:** Audit each .imp file's metadata block structure and extend the codemod
31+
to handle the specific patterns. Most are multi-line description values where
32+
the codemod's handler chain misidentifies the field boundaries.
33+
34+
### Rule count (2 maps)
35+
- `din-san-Deva-Latn-33904-2018`: imp=155 isc=154 (off by 1)
36+
- `var-ara-Arab-Arab-rababa`: imp=1 isc=0 (rababa directive — expected, not a bug)
37+
38+
**Fix for din-san:** Compare the stage body item-by-item between .imp and .isc
39+
to find the missing rule. Likely a `run` or `deep`/`compose` directive not counted.
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
# 02 — Investigate 2 IMP-failing maps
2+
3+
## Priority: MEDIUM
4+
5+
## Current State
6+
Two maps fail on the Ruby DSL side but parse correctly on the ISC side:
7+
- `bgnpcgn-tuk-Cyrl-Latn-1979`
8+
- `bgnpcgn-tuk-Cyrl-Latn-1993`
9+
10+
ISC captures: 1 stage, 21 tests each. Ruby DSL raises on parse.
11+
12+
## Investigation Needed
13+
14+
1. Open each `.imp` file and identify the syntax that breaks the Ruby DSL.
15+
2. Check whether the ISC parser's extracted data matches what the .imp intends.
16+
3. If the ISC parser is correct (likely — it parsed successfully), the Ruby DSL
17+
has a bug. File an issue against the Ruby DSL.
18+
19+
## Files to Examine
20+
- `/Users/mulgogi/src/interscript/maps/maps/bgnpcgn-tuk-Cyrl-Latn-1979.imp`
21+
- `/Users/mulgogi/src/interscript/maps/maps/bgnpcgn-tuk-Cyrl-Latn-1993.imp`
22+
- `/tmp/isc-verify/bgnpcgn-tuk-Cyrl-Latn-1979.isc`
23+
- `/tmp/isc-verify/bgnpcgn-tuk-Cyrl-Latn-1993.isc`
24+
25+
## Likely Root Cause
26+
The Ruby DSL uses `instance_exec` to parse the metadata block. Tukmen (tuk) maps
27+
may have metadata fields with characters or syntax that the DSL's metadata
28+
parser can't handle (e.g., Turkmen-specific characters, unusual date formats,
29+
or specific field names not in `STANDARD_STRING_KEYS`).
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
# 03 — Debug and fix ISC spec failures (bundler workaround)
2+
3+
## Priority: HIGH
4+
5+
## Current State
6+
- 73 ISC specs written, 45 failing due to Ruby 3.4 + bundler incompatibility.
7+
- The project's `spec/spec_helper.rb` requires `bundler/setup` which raises
8+
`DidYouMean::SPELL_CHECKERS` NameError on Ruby 3.4.8.
9+
- ISC specs have their own `spec/interscript/isc/spec_helper.rb` that avoids
10+
bundler, but `rspec` loads the project `.rspec` file which points to the main
11+
helper.
12+
13+
## Workaround
14+
Run ISC specs with:
15+
```bash
16+
rspec --options /dev/null --no-profile \
17+
--require ./spec/interscript/isc/spec_helper.rb \
18+
spec/interscript/isc/
19+
```
20+
21+
## Remaining Issues
22+
1. Some specs use `parser.parse(...)` but the parser returns a hash tree, not
23+
an object. Assert on `tree[:system][:body]` being an Array.
24+
2. Transform specs construct Parslet trees manually — the shape may not match
25+
what the parser produces. Verify by parsing a minimal .isc and inspecting
26+
the tree.
27+
3. The `system_code` in the parser output is a `Parslet::Slice`, not a String.
28+
Call `.to_s` in assertions.
29+
30+
## Fix Steps
31+
1. Fix the bundler issue globally (upgrade bundler or pin Ruby version).
32+
2. Update spec assertions to match actual parser output shapes.
33+
3. Add a `Rakefile` target for ISC specs: `rake spec:isc`.
34+
4. Run in CI with `--tag isc` to isolate from the main suite.
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
# 04 — Commit .isc files to the maps repo
2+
3+
## Priority: HIGH
4+
5+
## Current State
6+
- All 289 .isc files generated in `/tmp/isc-verify/` and `/Users/mulgogi/src/interscript/maps/maps/`.
7+
- The maps repo (`interscript/maps`) has 289 untracked .isc files.
8+
- The interscript-ruby repo (`feat/isc-parser-codemod` branch) has the codemod
9+
and grammar but not the .isc files.
10+
11+
## Steps
12+
1. In the maps repo, create a branch: `feat/isc-maps`.
13+
2. Stage all .isc files: `git add maps/*.isc` (explicit, not `-A`).
14+
3. Verify: `git diff --cached --name-only | grep -c '.isc'` should be 289.
15+
4. Commit with message: `feat: add ISC-format maps for all 289 systems`.
16+
5. Push and open a PR against `interscript/maps`.
17+
18+
## Considerations
19+
- The .isc files are GENERATED from .imp via the codemod. Consider adding a
20+
CI check that re-runs the codemod and verifies no drift.
21+
- The maps repo may have its own CI (CodeQL, lint). Check before pushing.
22+
- Coordinate with the user before pushing — this is a large change to a
23+
shared repo.
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
# 05 — Performance optimization for large CJK maps
2+
3+
## Priority: MEDIUM
4+
5+
## Current State
6+
6 maps take 15-38 seconds to parse due to Parslet PEG backtracking:
7+
8+
| Map | Lines | Parse Time |
9+
|-----|-------|------------|
10+
| var-kor-Kore-Hang-2013 | ~30k | 38.4s |
11+
| lshk-yue-Hani-Latn-jyutping-1993 | ~20k | 29.4s |
12+
| hk-yue-Hani-Latn-1888 | ~20k | 23.2s |
13+
| acadsin-zho-Hani-Latn-2002 | ~15k | 22.7s |
14+
| var-zho-Hani-Latn-wd-1979 | ~43k | 19.7s |
15+
| sac-zho-Hans-Latn-1979 | ~26k | 15.1s |
16+
17+
## Root Cause
18+
The `alias_arg` rule adds `zero_width_primitive.absent?` lookahead, which is
19+
evaluated for every `any()` call. With 5000+ `any()` calls in var-zho, the
20+
overhead compounds.
21+
22+
## Optimization Options
23+
24+
### Option A: Memoize keyword/primitive lookaheads (quick win)
25+
Cache the result of `keyword.absent?` and `zero_width_primitive.absent?` per
26+
position. Parslet doesn't support this natively, but a wrapper atom could.
27+
28+
### Option B: Switch to a faster parser (medium effort)
29+
Replace Parslet with:
30+
- **Tree-sitter**: Compile a grammar for ISC, get C-speed parsing.
31+
- **Racc (yacc)**: Generate an LALR parser — no backtracking.
32+
- **Hand-written recursive descent**: Fastest but most maintenance.
33+
34+
### Option C: Pre-compile .isc to Ruby AST (long-term)
35+
Instead of parsing .isc at runtime, compile it to a Ruby file at build time.
36+
The compiled file constructs `Interscript::Node` objects directly.
37+
38+
## Recommendation
39+
Option A for immediate relief (target: <5s per file).
40+
Option C for the long term — ISC becomes a source format, compiled to Ruby
41+
or JS at distribution time.
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
# 01 — TypeScript runtime parity
2+
3+
## Priority: HIGH
4+
5+
## Current State
6+
- ISC parser exists only in Ruby (Parslet-based).
7+
- The user explicitly requires: "Both Ruby and TS must be first class."
8+
- The TS runtime has no ISC parser — it still uses the old .imp format.
9+
10+
## Scope
11+
1. Port the ISC grammar to TypeScript using a PEG parser library:
12+
- ** Peggy.js** (formerly peggy) — mature PEG parser generator for JS/TS
13+
- **tree-sitter-grammar** — if going the C-speed route
14+
- **Hand-written parser** — following the Ruby grammar's structure
15+
16+
2. Port the DocumentBuilder equivalent (tree → typed object model).
17+
3. Port the codemod (`.imp``.isc`) — likely in TS or as a Ruby-generated tool.
18+
4. Ensure the TS runtime can LOAD `.isc` files and produce the same
19+
transliteration output as Ruby.
20+
21+
## Architecture
22+
```
23+
packages/
24+
isc-parser/ # TS ISC parser (Peggy grammar)
25+
isc-document-builder/ # tree → typed model
26+
isc-codemod/ # .imp → .isc converter
27+
```
28+
29+
## Verification
30+
- Cross-validate: Ruby and TS parsers produce identical document hashes for
31+
all 289 maps.
32+
- Integration test: run transliteration on test cases, compare Ruby vs TS
33+
output character-by-character.
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
# 02 — IS 1 specification compilation
2+
3+
## Priority: MEDIUM
4+
5+
## Current State
6+
- The IS 1 specification exists as a Metanorma AsciiDoc file at
7+
`spec/isc/document.adoc`.
8+
- It has not been compiled to HTML/PDF/XML yet.
9+
- The spec describes the ISC format formally but may be out of date with
10+
recent grammar changes.
11+
12+
## Steps
13+
1. Review `spec/isc/document.adoc` against the current grammar:
14+
- Verify all grammar rules are documented.
15+
- Update the metadata, tests, stages, and items sections.
16+
- Add the escaped-brace syntax (`\{`, `\}`) for raw text blocks.
17+
- Document the `separate separator` and `decompose` directives.
18+
19+
2. Compile the spec:
20+
```bash
21+
bundle exec metanorma spec/isc/document.adoc
22+
```
23+
24+
3. Publish the compiled HTML/PDF to the interscript.org website.
25+
26+
## Annexes to Add
27+
- **Migration Annex**: step-by-step guide for converting .imp → .isc.
28+
- **Grammar Reference**: complete BNF/PEG grammar extracted from the Ruby code.
29+
- **Examples**: real-world ISC snippets from the 289 maps.

TODO.secryst/03-isc-compiler.md

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
# 03 — ISC compiler: compile .isc to executable Ruby/JS
2+
3+
## Priority: MEDIUM
4+
5+
## Current State
6+
- ISC files are parsed at runtime by the Parslet parser.
7+
- For large CJK maps (40k+ lines), parsing takes 20-38 seconds.
8+
- The Ruby DSL (.imp) is compiled to `Interscript::Node` objects via
9+
`instance_exec` — also not fast, but cached.
10+
11+
## Proposal
12+
Build a compiler that transforms `.isc` source into an executable artifact:
13+
14+
### Ruby target
15+
Compile `.isc``.rb` that constructs `Interscript::Node` objects directly:
16+
```ruby
17+
# Generated from foo.isc
18+
Interscript::Node::Document.new.tap do |doc|
19+
doc.metadata = Interscript::Node::MetaData.new(...)
20+
doc.stages[:main] = Interscript::Node::Stage.new(...)
21+
end
22+
```
23+
24+
### JavaScript target
25+
Compile `.isc``.js` that constructs equivalent JS objects.
26+
27+
### Distribution
28+
- Ship compiled `.rb`/`.js` files alongside (or instead of) `.isc` source.
29+
- The `.isc` source is for humans; the compiled artifact is for runtime.
30+
- A `rake compile` task generates all artifacts from `.isc` sources.
31+
32+
## Benefits
33+
1. **Performance**: No parser overhead at runtime — load a `.rb` file.
34+
2. **Validation**: Compilation catches errors at build time, not runtime.
35+
3. **Distribution**: Compiled files are deterministic and cacheable.
36+
37+
## Implementation
38+
- New class: `Interscript::Isc::Compiler`
39+
- Methods: `compile_to_ruby(tree)`, `compile_to_javascript(tree)`
40+
- Integrates with existing `Interscript::Compiler::Ruby` and `::Javascript`.
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
# 04 — Ruby DSL STANDARD_ARRAY_KEYS bug fix
2+
3+
## Priority: LOW (affects Ruby DSL only, ISC already correct)
4+
5+
## Current State
6+
The Ruby DSL's `lib/interscript/dsl/metadata.rb` defines:
7+
8+
```ruby
9+
STANDARD_ARRAY_KEYS = %i[notes implementation_notes original_notes url]
10+
11+
STANDARD_ARRAY_KEYS.each do |sym|
12+
define_method sym do |stuff|
13+
stuff = Array(stuff)
14+
stuff.map do |i|
15+
case i
16+
when String
17+
i
18+
else
19+
warn "[#{@map_name}] Metadata key #{sym} expects all Array elements to be String"
20+
i.inspect
21+
end
22+
end
23+
# BUG: the processed array is never stored in @node!
24+
end
25+
end
26+
```
27+
28+
The method processes `stuff` but **never assigns the result to `@node[sym]`**.
29+
This means `notes`, `implementation_notes`, `original_notes`, and `url` are
30+
parsed from `.imp` files but silently discarded by the Ruby DSL.
31+
32+
## Impact
33+
- Deep equivalence checker shows `imp=nil` for these fields across ALL maps.
34+
- The ISC parser correctly stores them — ISC is strictly more capable.
35+
- Users relying on Ruby DSL `metadata.data[:url]` get `nil`.
36+
37+
## Fix
38+
```ruby
39+
STANDARD_ARRAY_KEYS.each do |sym|
40+
define_method sym do |stuff|
41+
@node[sym] = Array(stuff).map do |i|
42+
case i
43+
when String then i
44+
else
45+
warn "[#{@map_name}] Metadata key #{sym} expects String, got #{i.class}"
46+
i.inspect
47+
end
48+
end
49+
end
50+
end
51+
```
52+
53+
## Verification
54+
After fix, re-run `exe/verify_isc_deep` — the metadata comparison for
55+
`url`, `notes`, `implementation_notes`, and `original_notes` should pass
56+
for all 289 maps.
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
# 05 — ISC integration with existing Interscript runtime
2+
3+
## Priority: HIGH
4+
5+
## Current State
6+
- The ISC parser produces a document hash (metadata, tests, stages, aliases).
7+
- The existing Interscript runtime uses `Interscript::Node::*` objects.
8+
- There is NO bridge between ISC document hash and Interscript::Node objects.
9+
- Users cannot call `Interscript.transliterate("foo.isc", "hello")` yet.
10+
11+
## Required Bridge
12+
Add a method to convert ISC document hash → `Interscript::Node::Document`:
13+
14+
```ruby
15+
class Interscript::Isc::NodeAdapter
16+
def self.to_interscript_node(isc_doc)
17+
Interscript::Node::Document.new.tap do |doc|
18+
doc.metadata = build_metadata(isc_doc[:metadata])
19+
doc.tests = build_tests(isc_doc[:tests])
20+
doc.stages = build_stages(isc_doc[:stages])
21+
doc.aliases = build_aliases(isc_doc[:aliases])
22+
end
23+
end
24+
end
25+
```
26+
27+
Then update `Interscript.load_map` to detect `.isc` extension and route
28+
through the ISC parser + adapter instead of the Ruby DSL.
29+
30+
## Files to Create/Modify
31+
- `lib/interscript/isc/node_adapter.rb` (new)
32+
- `lib/interscript.rb` — update `load_map` to support `.isc`
33+
- `lib/interscript/path.rb` — resolve `.isc` files in the maps path
34+
35+
## Verification
36+
```ruby
37+
# Should work identically:
38+
Interscript.transliterate("alalc-amh-Ethi-Latn-1997", "ሀለሐ") # .imp
39+
Interscript.transliterate("alalc-amh-Ethi-Latn-1997.isc", "ሀለሐ") # .isc
40+
```
41+
42+
Both should produce the same output.

0 commit comments

Comments
 (0)