Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@ dist/
.aider*
security-reports/

# Transient phased-work checklist (see CLAUDE.md, Phase Completion Protocol).
/todo.md

# Generated from the marimo .py notebooks at docs build time.
docs/docs/examples/**/*.ipynb
__marimo__/
Expand Down
23 changes: 9 additions & 14 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,9 @@

## Phase Completion Protocol

Phased work uses a `memory-bank/todo.md` checklist. This file is **transient**: it is
created for the duration of a phased task and removed when the work lands, so it is not
part of the Memory Bank core files below and is normally absent from the repository.
Phased work uses a `todo.md` checklist at the repository root. This file is **transient**: it
is created for the duration of a phased task and removed when the work lands, so it is
normally absent from the repository.

When such a `todo.md` exists and contains phases:

Expand Down Expand Up @@ -96,15 +96,10 @@ When filing a GitHub issue (via `gh issue create` or otherwise), follow the stru

Issues that meet this bar are eligible for the `good first issue` label without further sharpening.

## Memory Bank
## Project Context

The `memory-bank/` directory contains project context documentation. Read both files at the start of tasks to understand the project.

### Core Files
| File | Purpose |
|------|---------|
| `systemPatterns.md` | System architecture, design patterns, the PropertySpec lifecycle |
| `activeContext.md` | Current work focus, what works, next steps, known issues |

### Hierarchy
`systemPatterns.md` holds the durable architecture; `activeContext.md` holds the current epic state and must be refreshed when an epic advances.
`docs/docs/` is the published documentation tree. Start a task by reading `docs/docs/index.md` and
`mloda/core/README.md` for the architecture, then the `in_depth/` page for the subsystem you are
touching (`in_depth/property-mapping.md` is the PropertySpec lifecycle). In-tree READMEs
(`mloda/core/`, `mloda_plugins/`, `tests/`) and `CONTRIBUTING.md` cover the rest. Current work state
comes from git history and the issue tracker, not from a checked-in status file.
23 changes: 9 additions & 14 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,9 +32,9 @@

## Phase Completion Protocol

Phased work uses a `memory-bank/todo.md` checklist. This file is **transient**: it is
created for the duration of a phased task and removed when the work lands, so it is not
part of the Memory Bank core files below and is normally absent from the repository.
Phased work uses a `todo.md` checklist at the repository root. This file is **transient**: it
is created for the duration of a phased task and removed when the work lands, so it is
normally absent from the repository.

When such a `todo.md` exists and contains phases:

Expand Down Expand Up @@ -103,15 +103,10 @@ When filing a GitHub issue (via `gh issue create` or otherwise), follow the stru

Issues that meet this bar are eligible for the `good first issue` label without further sharpening.

## Memory Bank
## Project Context

The `memory-bank/` directory contains project context documentation. Read both files at the start of tasks to understand the project.

### Core Files
| File | Purpose |
|------|---------|
| `systemPatterns.md` | System architecture, design patterns, the PropertySpec lifecycle |
| `activeContext.md` | Current work focus, what works, next steps, known issues |

### Hierarchy
`systemPatterns.md` holds the durable architecture; `activeContext.md` holds the current epic state and must be refreshed when an epic advances.
`docs/docs/` is the published documentation tree. Start a task by reading `docs/docs/index.md` and
`mloda/core/README.md` for the architecture, then the `in_depth/` page for the subsystem you are
touching (`in_depth/property-mapping.md` is the PropertySpec lifecycle). In-tree READMEs
(`mloda/core/`, `mloda_plugins/`, `tests/`) and `CONTRIBUTING.md` cover the rest. Current work state
comes from git history and the issue tracker, not from a checked-in status file.
23 changes: 22 additions & 1 deletion docs/docs/in_depth/property-mapping.md
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ does not understand can be absorbed silently.
| Match time (parser) | `allowed_values` membership | Each element of a **present** option is in the accepted set | One element | `ValueError`, surfaced to the end user |
| Match time (parser) | `element_validator` | Each element of a **present** option satisfies a predicate | One element | `ValueError`, surfaced to the end user |
| Match time (parser) | Required presence (config path) | A key that declares no `default` and no `required_when` was provided | The options | Non-match (`False`) |
| Match time (parser) | Required presence (string-named path) | Same, after declared defaults and name bindings resolve; `deferred_binding=True` and the source (`in_features`) key are exempt | The effective options | Non-match (`False`), with a warning naming the missing key(s) |
| Match time (parser) | Required presence (string-named path) | Same, after declared defaults and name bindings resolve; `deferred_binding=True` and the source (`in_features`) key are exempt | The name-bound options | Non-match (`False`), with a warning naming the missing key(s) |
| Match time (mixin) | `match_guard` | The whole value has an acceptable shape | The raw value | Non-match (`False`) |
| Match time (mixin) | `MIN/MAX_IN_FEATURES` | In-feature count is within bounds | The in-features | Non-match (`False`) |
| Match time (guard installed at class definition) | `required_when` | A conditionally required option is present | `Options` | Non-match (`False`) |
Expand Down Expand Up @@ -374,6 +374,10 @@ The framework applies this at two sites. At feature **intake**
directly. `options_with_defaults` remains for pre-materialization contexts (e.g. `resolve_subtype`
internals) and for read sites the framework hands pre-default options, `input_features` above all.

For an engine-driven request intake has already run, so the compute-boundary call is an idempotent
no-op. It carries the work only for direct `FeatureSet` use that bypasses the engine, and there the
collapsing twins raise instead of merging.

Both sites run *after* resolution, so materialization never changes **matching**. It does change
how features **group**: intake materialization deliberately canonicalizes default-equivalent twins,
so a feature that passes a declared default explicitly and one that omits it become equal and merge
Expand All @@ -385,6 +389,22 @@ declared default does NOT reach an `input_features` read site. A group that want
`options_with_defaults` itself, as `ConcatenatedFileContent` does (see
[A pattern-less feature group sits in between](#a-pattern-less-feature-group-sits-in-between)).

Which stage sees which view of the options:

| Stage | Options view |
| --- | --- |
| Parse, bind, match, resolve (subtype resolution applies defaults internally) | declared (pre-default) |
| `input_features()` and child option inheritance | declared (pre-default) |
| Splitting, planning, filter matching, `validate_input_features`, compute | effective (post-default) |

The last row assumes intake has run, which is every engine-driven request. On the direct `FeatureSet`
path the safety net materializes inside `run_calculate_feature`, which is after
`validate_input_features`, not before it.

Filter matching is the one place the same classmethod sees both views: `GlobalFilter` calls
`match_feature_group_criteria` again after intake, so it observes effective options where feature
resolution saw declared ones.

``` python
graph_type = feature.options.get("graph_type") # the declared default when the caller omitted it
```
Expand Down Expand Up @@ -591,6 +611,7 @@ if it really is a whole-value check.
| Declared defaults materialized into runtime options | `tests/test_core/test_abstract_plugins/test_options_with_defaults.py` |
| Declared defaults materialized at the compute boundary | `tests/test_core/test_abstract_plugins/test_materialize_defaults_boundary.py` |
| Declared defaults materialized at intake, canonicalizing default-equivalent twins | `tests/test_core/test_abstract_plugins/test_intake_default_canonicalization.py` |
| Filter criteria matching observes effective options | `tests/test_core/test_filter/test_filter_criteria_effective_options.py` |
| The reader surface: the spec type and its class-definition guard, the reserved framework key, the MRO merge, the loud undeclared key, the presence rule of `reader_option()` | `tests/.../test_components/test_reader_option_declarations.py` |
| Per-reader declarations, the `runtime_default` that is load-bearing at selection, and the bare-path branch it does not reach | `tests/.../input_data/test_reader_option_declarations.py` |
| A pattern-less group: enforced `required_when`, and defaults it applies itself | `tests/.../input_data/test_read_context_files_option_declarations.py` |
Expand Down
31 changes: 0 additions & 31 deletions memory-bank/activeContext.md

This file was deleted.

70 changes: 0 additions & 70 deletions memory-bank/systemPatterns.md

This file was deleted.

Loading