Skip to content
Merged
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
96 changes: 78 additions & 18 deletions docs/CODEBASE_MAP.md
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
---
last_mapped: 2026-05-04T00:00:00Z
last_mapped: 2026-05-15T09:09:50Z
total_files: 557
total_modules: 30
---

# Codebase Map

> Auto-generated by Cartographer. Last mapped: 2026-05-04T00:00:00Z
> Auto-generated by Cartographer. Last mapped: 2026-05-15T09:09:50Z

## System Overview

Expand Down Expand Up @@ -438,42 +438,82 @@ static { Marshalling.registerEnum(Color.class); }

### base-query

**Purpose:** Annotation-driven in-memory object index with fluent query DSL.
**Purpose:** Annotation-driven in-memory object index with fluent, supertype-aware query DSL. Objects opt in via `public static final Function` fields annotated `@Indexable`; the index maintains dual forward/reverse hash maps for O(1) lookup by extracted value, with automatic fallback to composite traversal for non-indexed scopes.

```java
index.match(Foo.class)
.where(Foo::getName).isEqualTo("bar")
index.match(Foo.class) // finds Foo and all indexed subclasses
.where(Foo.NAME).isEqualTo("bar")
.scope(Scope.DepthFirst)
.findAll();
```

**Public API:**

| Type | Role |
|---|---|
| `@Indexable` | On class: makes type indexable. On `public static final Function` field: value-based index |
| `Index` | `index(obj)`, `unindex(obj)`, `add(Class,T)`, `remove(Class,T)` |
| `AbstractHeapBasedIndex` | Core thread-safe impl; O(1) hash lookup + fallback to traversal |
| `Scope` | `Indexed` (hash-only), `Direct`, `DepthFirst`, `BreadthFirst` |
| `Match` / `Condition` / `Terminal` | Fluent query chain |
| `@Indexable` | On a `public static final Function` field: value-based index entry. On a type: syntactic marker (accepted but field-level annotation is canonical). |
| `@Unique` | Combined with `@Indexable`: enforces uniqueness per key; enables O(1) single-object lookups. |
| `@Dynamic` | Combined with `@Indexable`: declares the extracted value may change post-construction; enables `reindexDynamic`. |
| `Index` | Write surface: `index(obj)`, `unindex(obj)`, `reindex(obj)`, `reindexDynamic(obj)`, `add(Class,T)`, `remove(Class,T)` |
| `Queryable` | Read-only surface: `match(Class)`, `get(Class, Function, key)` |
| `AbstractHeapBasedIndex` | Thread-safe core impl (dual `ConcurrentHashMap` forward/reverse maps per `@Indexable` field); `traverse` hooks are abstract for subclass traversal strategies |
| `HeapBasedIndex` | Concrete `AbstractHeapBasedIndex` with empty traversal (index-only; no composite backing) |
| `Scope` | `Indexed` (hash-only), `Direct`, `DepthFirst`, `BreadthFirst` — controls fallback traversal depth |
| `Match` / `Condition` / `Terminal` | Fluent query chain: `match → where → isEqualTo/isNotEqualTo/matches → findAll/findFirst/get` |

**Key behaviors:**

- **Supertype-aware queries:** `match(Shape.class)` finds indexed `Circle` and `Square` instances by scanning all assignable classes in the index. Applies to both `@Unique` and non-unique indexes, and to `objectByClass` membership.
- **`reindex(obj)`:** Full `unindex` + `index` cycle. Uses the stored reverse map for unindex so it is safe to call even after the object's state has already changed.
- **`reindexDynamic(obj)`:** Partial update touching only `@Dynamic`-annotated fields. Reads the old value from the reverse map, removes it, re-invokes the function on the current object state, and inserts the new value. Stable fields are untouched. Compatible with `@Unique @Dynamic`.
- **`add(Class, T)`:** Registers the object in `objectByClass` only — does NOT invoke any `@Indexable` functions. Fallback linear scan applies to `where(...).isEqualTo(...)` queries for these objects.
- **`unindex`:** Always uses the stored reverse map — never re-invokes the function. Safe even when the object's indexed property has already changed.
- **Null values:** Indexed via a `NULL_OBJECT` sentinel so `null` extracted values are fully supported, including on the `isEqualTo(null)` fast path.

**Gotchas:**
- `@Indexable` on non-`public static final Function` fields is silently ignored.
- `@Unique` carves the field out of the non-unique index — omitting it disables uniqueness enforcement.
- `getOrNull()` returns `null` for both "no match" and "more than one match" — use `getOrThrow()` to distinguish.
- `Scope` propagation: scope set on `Match` is inherited by the terminal; a later `.scope()` call on the terminal overrides it.
- The `putIfAbsent` uniqueness check in `reindexDynamic` is not transactional with the remove — concurrent calls on the same object may observe partial state.

**Gotcha:** `@Indexable` on non-`public static final` fields is silently ignored. `get()` enforces exactly-one semantics.
**Dependencies:** `base-foundation`.

---

### base-mereology

**Purpose:** Part-whole hierarchy modeling and traversal (mereology = the study of parts and wholes).
**Purpose:** Part-whole hierarchy modeling and traversal (mereology = the study of parts and wholes). Implements BFS/DFS traversal of `Composite` trees with cycle detection, reflexive inclusion, subtree exclusion, and ancestry context via `Entity<T>`. Also provides `HeapBasedCompositeIndex` which bridges composite traversal into the `base-query` framework.

**Public API:**

| Type | Role |
|---|---|
| `Composite` | `@FunctionalInterface`; `iterator(Class<T>)` returns direct parts of type T |
| `Traversal<T,B>` | Fluent builder: `strategy()`, `reflexive()`, `filter()`, `exclude()`, `abort()` |
| `Composites` | Utility: `of(parts...)`, `keysOf(Map)`, `valuesOf(Map)`, `verify(Composite, Predicate)` |
| `Traversal<T,B>` | Fluent builder: `strategy()`, `reflexive()`, `filter(Class)`, `filter(Predicate)`, `exclude(Predicate<Composite>)`, `abort(Predicate)`, `stream()`, `hierarchical()`, `iterator()` |
| `Strategy` | `Direct`, `DepthFirst`, `BreadthFirst` |
| `Hierarchical<T>` | `Iterable<Entity<T>>` with ancestry context |
| `Entity<T>` | `object()`, `composite()` (parent), `hierarchy()`, `distance()`, `isBoundary()` |
| `HeapBasedCompositeIndex` | `AbstractHeapBasedIndex` that delegates to a `Composite` for traversal |
| `Hierarchical<T>` | `Iterable<Entity<T>>` with ancestry context; `abort(Predicate<Entity<T>>)` for early exit |
| `Entity<T>` | `object()`, `composite()` (direct parent), `hierarchy()` (boundary-to-parent ordered list), `distance()`, `isBoundary()`, `isAtom()` |
| `HeapBasedCompositeIndex` | Extends `AbstractHeapBasedIndex`; overrides `traverse(Class, Scope)` and `traverse(Scope)` to delegate to a backing `Composite` with the corresponding `Strategy` |

**Key behaviors:**

- **`Composites.verify(root, suspect)`:** Diagnostic utility. Traverses all reachable composites from `root`, filters to those matching the `suspect` predicate, then returns the subset that expose no parts (`iterator(Object.class).hasNext() == false`). Useful for detecting incorrectly wired composites that should have parts but don't.
- **Cycle detection:** Identity-based (`IdentityHashMap`). A `Composite` appearing twice by reference (diamond DAG) is visited once. A self-referencing composite is yielded as an element but not recursed into.
- **`Entity.hierarchy()`:** Returns composites ordered from outermost boundary to direct parent (boundary-first). The DFS iterator internally accumulates innermost-first from the stack and reverses for storage; BFS builds the list explicitly and reverses it.
- **`Entity.distance()`:** Number of enclosing composites. Directly-enclosed objects have distance 1.
- **`filter(Class)` ordering constraint:** Must be called before `filter(Predicate)` and `abort(Predicate)`. Calling it after a predicate/abort has been set throws `IllegalStateException`.
- **`abort(Predicate)`:** Consumes the aborting element without yielding it to the caller.
- **Traversal reusability:** Each call to `stream()` or `iterator()` on a `Traversal` creates a fresh iterator — repeated calls are safe.
- **Deduplication in transitive traversal:** The framework calls both `iterator(Composite.class)` and `iterator(elementClass)` and deduplicates by identity, so an object that is both a `Composite` and the target type is yielded exactly once.

**Gotchas:**
- Default strategy is `Direct` (immediate children only) and not reflexive (root excluded from results).
- `filter(Class)` must precede any predicate/abort configuration or `IllegalStateException` is thrown.
- `abort(Predicate)` stops traversal without yielding the matching element.
- `HeapBasedCompositeIndex` falls back to composite traversal only when the indexed scope has no hits — the backing `Composite` is the fallback, not the primary source.

**Gotcha:** Default strategy is `Direct` (immediate children only) and not reflexive (root excluded).
**Dependencies:** `base-foundation`, `base-query`.

---
Expand Down Expand Up @@ -1162,6 +1202,16 @@ All modules use JPMS `module-info.java`. Most are open modules (allowing deep re

4. **`@Indexable` on non-`public static final` fields** is silently ignored in `base-query`.

4a. **`@Unique` carves the field out of the non-unique index** in `base-query` — omitting `@Unique` on a function you intend to be unique disables uniqueness enforcement silently.

4b. **`add(Class, T)` does NOT invoke `@Indexable` functions** in `base-query` — it only registers membership in `objectByClass`. `where(fn).isEqualTo(x)` queries for these objects fall through to the linear scan fallback.

4c. **`getOrNull()` returns `null` for both "no match" and "more than one match"** in `base-query` — use `getOrThrow()` if you need to distinguish these cases.

4d. **`Traversal.filter(Class)` must be called before `filter(Predicate)` and `abort(Predicate)`** in `base-mereology` — calling it after a predicate has been set throws `IllegalStateException`.

4e. **`Traversal.abort(Predicate)` consumes the aborting element without yielding it** in `base-mereology` — the element that matches the abort predicate is not returned to the caller.

5. **`get(MappedOption.class)` always returns null** in `Configuration` — use `get(class, key)` for mapped options.

6. **Java serialization** in `base-network` — both client and server must share identical class definitions.
Expand Down Expand Up @@ -1269,10 +1319,20 @@ composite.traverse(MyType.class)

**To query an indexed object graph:**
```java
// Basic index query (also finds subclasses of MyType)
index.match(MyType.class)
.where(MyType::getName).isEqualTo("target")
.where(MyType.NAME).isEqualTo("target")
.scope(Scope.DepthFirst)
.findFirst();

// Re-index an object after any property changes
index.reindex(obj);

// Re-index only @Dynamic fields (cheaper when stable fields didn't change)
index.reindexDynamic(obj);

// Diagnose composites that should have parts but don't
List<Composite> empty = Composites.verify(root, c -> c instanceof MyCompositeType);
```

**To build and run a CLI application:**
Expand Down
Loading