grammar-inference-engine/docs/adr/0010-universal-package-mapping-via-relpath.md
tobjend e23922a1b7
Some checks failed
ci/woodpecker/push/woodpecker Pipeline failed
feat: adaptive multi-assignment clustering; add ADRs 1-10
- Multi-assignment clustering (no greedy 'used' set)
- Adaptive ngram fallback (shrink when (other) > 60%)
- Add docs/adr/ with 10 architecture decision records
- Fix ADR 1 (query modification description)
- Fix ADR 3 (multi-assignment + adaptive shrink)
- Fix ADR 5 (import sort order clarification)
- Fix ADR 6 (remove Kotlin call_suffix references)
- New ADR 9 (adaptive clustering rationale)
- New ADR 10 (universal package mapping via relpath)
2026-07-03 22:58:09 +02:00

2.5 KiB

10. Universal package mapping via project-relative path

Date: 2026-07-03

Status: Accepted

Context

Each detected behavioral convention needs a "package" or "module" label so the LLM knows where to place generated code. Options:

  • No package info: LLM guesses wrong directory, generates code at project root.
  • Per-language directory lookup: Hardcode kotlin/java/python source root names. Breeds per-language branches — violates the zero-adapters constraint.
  • Full file path: Too verbose, exposes absolute system paths (/home/user/project/...).
  • Project-relative path: Pure path arithmetic, no language assumptions.

Decision

Derive the package from the file's directory relative to the project root:

def _file_to_package(fp, project_root):
    rel = os.path.relpath(os.path.dirname(fp), project_root)
    if rel == ".":
        return ""  # file at project root
    return rel

No source root markers. No per-language directory names. Just relpath from the root the user passed to analyze_directory.

Examples:

/project/src/main/kotlin/org/app/User.kt  →  src/main/kotlin/org/app
/project/mypackage/module.py               →  mypackage
/project/lib/core/helper.rb                →  lib/core
/project/src/main.rs                        →  src
/flat/project/file.py                       →  flat

The project root is the directory passed to analyze_directory(...) and threaded down through analyze_clusters_top_packages.

Consequences

Positive:

  • Zero per-language branches. Works identically for all 10 languages.
  • No configuration or convention list to maintain.
  • LLM sees the exact directory structure it should mirror in generated code.

Negative:

  • relpath assumes the project root is the scan root. Scanning a subdirectory gives partial paths (still correct, but missing context).
  • Files at the root of deeply nested projects get empty package strings. Mitigation: users should scan from the project root.

Alternatives Considered

  • Per-language source root list (reverted): Hardcoded kotlin/java/python directory names. Brittle, violated zero-adapters constraint. Reverted to feature/kotlin-specific-extras.
  • Source root markers (src/lib/pkg/app): Broader than per-language but still assumes project layout conventions. Broke for flat repos, non-standard layouts.
  • No package mapping: Simpler but useless — LLM can't locate generated code. The package label is essential for file placement.