grammar-inference-engine/experiments/HANDOVER.md
tobjend 36f9e9173d
Some checks failed
ci/woodpecker/push/woodpecker Pipeline failed
ci/woodpecker/pr/woodpecker Pipeline failed
docs: update experiment log, results, and handover for Round 19-20
2026-07-13 01:18:32 +02:00

167 lines
6.9 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Handover — Behavioral Grammar Inference Project
## Current Status
**Branch**: `feature/treesitter-tag-queries`
**Last commit**: `8b3a454` — feat: enable idregex_refine by default + AST rewrite of _count_optionals
**Tests**: 313 passed, 8 warnings, 0 failures
## What We Built
### Source Code Analysis Pipeline
A **language-agnostic pipeline** that infers per-package calling conventions from any codebase:
1. **Tree-sitter AST** → extract method-level behavioral sequences (call chains, control flow)
2. **Algorithm 7 (CRX)** — generalized regular expression inference from examples
3. **AST grammar nodes** — Symbol, Concat, Alt, Optional, Plus, Star, Empty
4. **Language Size scoring** — ranks grammars by compressed description length
5. **YAML/GBNF output** — structured grammars grouped by package, ready for constrained decoding
### Key Changes Since Last Handover
- **AST migration complete** — all SORE string operations purged from pipeline
- **Scoring**: Language Size (`lang_size_score`) chosen over MDL (ADR-13)
- **Decomposition ON by default** — `decompose=True`, `max_seq_length=4`
- **idregex_refine ON by default** — iDRefEx runs on small groups where it helps
- **`_COUNT_CAP` raised to 10^30** — no longer clamps scorer values
- **Memoization fixed** — `_count_concat` has `@lru_cache`, RAGSAK 54.9s→6.7s
### Default Parameters (Golden Config)
```python
{
'decompose': True,
'max_seq_length': 4,
'min_structure': 0.5,
'idregex_refine': True,
'min_methods': 3,
'min_coverage': 0.05,
}
```
## What Works
### High-Confidence Findings
1. **Decomposition** increases grammar count 3× and reduces pure bags
2. **Language Size scoring** discriminates between tight and bag grammars (20 vs 9975)
3. **CRX is fast and deterministic** — always produces a grammar
4. **Package grouping** — per-directory grammars are the right abstraction level
5. **Memoization is critical**`_count_concat` without cache = exponential blowup
### Grammar Quality Reality
~85% of grammars are orderless bags `(A|B|C)+`. ~15% are structured sequential flows:
- Web controller tests: `post→jsonPath→isEqualTo→exchange→expectStatus`
- API client patterns: `request→header→send→statusCode→jsonPath`
- Builder chains: `builder→field→value→build→validate`
Bags survive because:
1. CRX emits one grammar deterministically (no alternative to compare)
2. `lang_size_score` only ranks **between** algorithms (CRX vs iDRegEx), not within CRX's own output
3. Methods in large packages don't share sequential patterns — they're genuinely unrelated
## What Doesn't Work
### iDRegEx on Small Bags
iDRegEx achieves only 3.8× tighter on 3-method groups (below the 10× gate threshold).
The gate correctly rejects it. The `storage` group (91× tighter) was an outlier.
### MDL Scoring
Abandoned (ADR-13). MDL rewards short expressions, so generic `info+` beats specific
`a.b.c.d.e+` (21% vs 98% success in Bex paper).
### Cross-Package Grouping
Grouping by first 3 symbols gives 12% coverage but most groups are too sparse.
Package-specific patterns are the norm.
## Files to Know
| File | Purpose |
|------|---------|
| `bex/tag_preprocessor/analyze.py` | Pipeline: `analyze_directory()``analyze_by_package()``_infer_group()` |
| `bex/grammar.py` | AST nodes, `_count_concat` memoization, `_COUNT_CAP = 10^30` |
| `bex/crx.py` | CRX algorithm (AST-based) |
| `bex/mdl.py` | `lang_size_score()`, `model_cost()`, `data_cost()` |
| `bex/idregex.py` | iDRegEx algorithm |
| `bex/decompose.py` | Decomposition forest |
| `bex/gbnf.py` | GBNF converter, `grammar_structure_score()` |
| `bex/ensemble.py` | `infer_ensemble()` — combine multiple algorithms |
| `bex/mcp_server.py` | MCP server with `analyze_directory`, `get_grammar` |
| `bex/tag_preprocessor/code.py` | `preprocess_by_method()` — AST to behavioral sequences |
## How to Run
```bash
# Basic analysis (all defaults ON)
python -m bex.tag_preprocessor.analyze /path/to/codebase --verbose
# With custom settings
python -m bex.tag_preprocessor.analyze /path/to/codebase \
--decompose --idregex-refine --min-structure 0.5 --slice package
# Disable idregex refinement
python -m bex.tag_preprocessor.analyze /path/to/codebase --no-idregex-refine
# MCP server
python bex/mcp_server.py --port 8080
```
## Test Coverage
- `tests/test_analyze.py`: Pipeline integration tests
- `tests/test_grammar.py`: AST node tests, count_words memoization
- `tests/test_mdl.py`: Language Size scoring, MDL scoring
- `tests/test_crx.py`: CRX algorithm
- `tests/test_idregex.py`: iDRegEx algorithm
- `tests/test_decompose.py`: Decomposition forest
- `tests/test_distributional.py`: Distributional clustering
- `tests/test_gbnf.py`: GBNF conversion
- `tests/test_crx_refined.py`: Refined CRX
- `tests/test_grammar_index.py`: Grammar index
- `tests/test_reduce.py`: Algorithm 4
Total: 313 tests passing
## Decision Log
| Decision | Choice | Rationale |
|----------|--------|-----------|
| Scoring | Language Size (not MDL) | MDL rewards short over specific (ADR-13) |
| Decomposition | ON by default | 3× more grammars, fewer pure bags |
| idregex_refine | ON by default | Gate limits to groups where it helps |
| AST representation | Full AST nodes | Type safety, memoization, no string parsing |
| Algorithm | CRX (default) | Fast, deterministic, always produces output |
## Open Questions
### 1. Grammar Usefulness for LLM Code Generation
MCP tools are ready but haven't validated if grammars help an LLM during generation.
Need to test:
- Does constrained decoding with GBNF improve code quality?
- Do grammars reduce hallucination in call chains?
### 2. The 85% Bag Problem
Most grammars are orderless bags. Two possible directions:
- **Accept it**: Bags represent real diversity in method usage. Not a bug.
- **Better grouping**: If we group methods by semantic role (not just directory),
we might find ordering within sub-groups. Requires understanding method semantics.
### 3. Cross-Codebase Grammar Reuse
Can grammars from one project inform another? (e.g., "Spring Boot service patterns")
## Experiments Summary
| Round | What | Result |
|-------|------|--------|
| 1-5 | Context strategies | Package grouping wins (12% coverage) |
| 6-10 | Reduce, clustering | Reduce merges states, not packages |
| 11-15 | Distributional, ensemble | CRX is sufficient, no ensemble needed |
| 16-17 | Refined CRX | Better ~78% of the time when useful, but trivial ~36% |
| 18 | Decomposition | 3× more grammars, fewer bags |
| 19 | AST migration | 54.9s→6.7s after memoization fix |
| 20 | Scoring + defaults | Language Size works, decomposition ON, idregex ON |
## Next Steps
1. **Validate grammar usefulness** — test constrained decoding with llama.cpp
2. **Auto-detect decomposition** — skip if codebase already structured
3. **Cross-project grammar reuse** — share patterns across codebases
4. **IDE integration** — grammar-aware code completion
5. **No further algorithmic changes on bags** — they're a feature, not a bug