Production and test module layout¶
Production packages¶
The project grows through narrow packages rather than large cross-cutting modules:
src/lclang/
__version__.py sole package version definition
error/ exceptions, diagnostic records, causes, groups and rendering
codes/ e0-e9 enum vocabularies and parent-relative classifications
lang/ preferred parsing and Module/Frame construction APIs
common/ identifiers, source locations, records, grammar version and markers
ast/ immutable node families and visitor contracts
engine/
lexer/ tokens, string scanning and f-string scanning
parser/ Pratt core, displays, comprehensions and special forms
printer/ precedence-aware canonical source rendering
evaluator/ node-family evaluation handlers
runtime/ Modules, Presets and construction factories
frame/ lookup, evaluation, cache lifecycle and inspection
dependency/ static/dynamic analytics and qualified Frame graphs
stdlib/ manifests, namespaces, calendar adapter and async helpers
config/ logical lines, includes, origins and loading
logger/ configuration, process scope, queue writer, sinks and rotation
cli/ typed contexts, parsing, routing, runners and built-ins
workflow/ task trees, execution, CLI and status
mappings/ structure, annotations, binding and mapping diagnostics
utils/
*.py Python awaiting, masks, defaults, proxies, dates and value helpers
calendar/ calendars, mappings, loaders and managers
Language-independent helpers live in utils/, which never imports lang/.
Language-specific identifiers, source locations and shared values live in
lang/common/. Errors live in error/; its root depends on code tables and
masking state. Source-aware records defer source-type imports until validation,
and source-free utility diagnostics avoid loading the language package.
Frame-bound environment lookup lives in lang/runtime/frame/environment_proxy.py;
live Python environment access and date conversion remain utilities. This keeps
utility, language and error imports acyclic. Package __init__.py files curate
exports with static imports.
The root exports no API. Only __init__.py and the sole version definition,
__version__.py, remain directly under src/lclang.
Each production Python file has at most 200 code-bearing physical lines,
excluding imports, docstrings, pure comments, and blank lines. Multiline
expressions, signatures, and runtime strings count; compressing statements or
embedding executable source is not an alternative to concise algorithms and
responsibility-based modules. Scripts and tests are outside this size policy.
Dependencies flow inward: CLI may depend on config/runtime; config may depend on language/runtime; runtime may depend on AST/language primitives. AST, source, types, errors, and workflow status never import runtime, config, or CLI. Logger Frame configuration depends on runtime and never imports CLI; CLI adds parameter recognition and entry-point defaults around the shared resolver.
Optional verbose diagnostics share one failure scope in error/verbose_guard.py.
The scope also supplies producer decorators through the standard-library
ContextDecorator. Explicit display work uses the scope's required flag;
the surrounding execution owns business exceptions and resource cleanup.
Test packages¶
Tests mirror subsystem ownership:
tests/
error/ code registry, constructor, protocol, cause and cleanup contracts
lang/ public language facade contracts
common/ identifiers, source locations, records and grammar-version contracts
ast/ node, visitor and round-trip contracts
engine/ lexer/parser/printer/evaluator behaviour
runtime/ module and preset behaviour
frame/ cache, concurrency, lifecycle and inspection behaviour
dependency/ static/dynamic and qualified graph behaviour
stdlib/ manifest and async-helper behaviour
config/ text, include, origin and diagnostic behaviour
logger/ configuration, ownership, output, timers and failure isolation
cli/ argv, routing, stream and exit-code behaviour
workflow/ definitions, execution, mappings, rendering and status
utils/
test_*.py Python utility behavior and language-independent imports
calendar/ calendar strategies, algebra, mapping, loading, and LCL integration
support/ reusable factories, fake resources and corpus loaders
stress/ default full-suite scale, concurrency and leak scenarios
Within each subsystem, tests correspond to production submodule responsibilities.
One test file may cover several closely related implementation files. Explicit
integration contracts live in test_integration_*.py modules. First pass the
existing tests, refactor production code, pass the same tests, and only then
reorganize test files and shared fixtures to match the resulting responsibilities.
Source contracts reject obsolete import paths and forwarding modules, require module overviews to name their declared contents, keep error enums in their owning facade, and prevent instance dictionary state copying. Native module discovery remains an explicit reflection exception. Shared packages retain their inward dependency direction.
A behaviour has one obvious owning test module. Tests assert public behaviour,
structured state, or diagnostics rather than private method calls. Shared
fixtures enter tests/support only after at least two subsystems need them.
Benchmarks remain separate from the quality gate. Deterministic stress and
property tests run in the default full behavior suite.
Frame responsibilities¶
lang/runtime/frame/default_frame_scope.py owns isolated fallback Frames. Direct workflows use
a task-local lookup scope; CLI invocation owners attach a fallback to their own
hierarchy. Neither mechanism rewrites borrowed parents or invalidates cached
dependencies. Factory definitions reuse the interpreter's single-flight and
failure caches. workflow/variable_default.py collects declarations; mapping-local
constructor fallbacks and scope-aware dependency discovery stay in mappings/.
lang/runtime/frame/frame.py owns Frame state and its public methods.
binding_lookup.py selects owner, kind and diagnostic path for one operation;
host_binding.py validates and atomically publishes mixins. binding_evaluation.py
reads selected values, while evaluation_flight.py coordinates cycles,
single-flight and recalculation. cache_lifecycle.py commits snapshots and
closes owned resources. dependency_snapshot.py owns static and dynamic
observations. variable_inspection.py, inspection_builder.py and
inspection_rendering.py separate the public result, construction and display.
frame_factory.py and evaluation_limit.py contain reusable creation policy
and work budgets. Public package exports retain the supported import surface.
Calendar period boundaries, range boundaries, directional adjustments and sparse filters share implementations by responsibility. Operand normalization preserves encounter order for fallback and sorts only commutative compositions.
Workflow mapping responsibilities¶
workflow/mappings/ owns recursive dataclass structure, specialized record
annotations, reference materialization, staged publication, and mapping logs.
Its __init__.py retains the mapping entry points used by workflow execution,
CLI analysis and static rendering. Tests for recursive and whole-record behavior
live in tests/workflow/mappings/.