Skip to content

feat(miner): integrate compute_hallways_for_wing into post-mine flow#1560

Merged
igorls merged 1 commit into
feat/hallways-within-wing-connectorsfrom
feat/integrate-hallways-in-miner
May 20, 2026
Merged

feat(miner): integrate compute_hallways_for_wing into post-mine flow#1560
igorls merged 1 commit into
feat/hallways-within-wing-connectorsfrom
feat/integrate-hallways-in-miner

Conversation

@milla-jovovich

Copy link
Copy Markdown
Collaborator

Wires the hallway primitive from PR #1558 into the project miner's post-mine flow.

This PR stacks on #1558. Base branch is feat/hallways-within-wing-connectors. When #1558 merges, GitHub auto-updates this PR's base to develop and the diff shrinks to just the miner.py + test changes.

Why this is necessary

PR #1558 introduces the compute_hallways_for_wing function — but no miner calls it yet. Without this integration, that module is dead code: no hallways ever materialize in ~/.mempalace/hallways.json.

This PR wires the call into _mine_impl so every project mine triggers hallway computation for the wing it just touched.

What changes

  1. Module-level import in miner.py:

    from .hallways import compute_hallways_for_wing

    Module-level (not lazy inside a function) so tests can patch the seam as mempalace.miner.compute_hallways_for_wing.

  2. Post-mine call block in _mine_impl, immediately after the existing topic-tunnel computation. Mirrors that block's fault-tolerance pattern exactly:

    try:
        hallways_created = compute_hallways_for_wing(wing, col=collection)
        if hallways_created:
            print(f"\n  Hallways: +{len(hallways_created)} within-wing entity link(s)")
    except Exception as e:
        print(f"\n  WARNING: hallway computation skipped — {e}", file=sys.stderr)

    Hallway computation is a derived analytic. If it fails, the drawer write (which happens earlier in _mine_impl) has already committed. The failure must never propagate.

Tests

Two new RED-first tests in tests/test_miner.py:

Test What it verifies
test_mine_computes_hallways_for_wing_post_mine Stubs the hallway function, runs a real mine, asserts it was called once with the wing name + the live ChromaDB collection.
test_mine_hallway_failure_does_not_crash_mine Stubs the hallway function to raise. Mine still completes, drawer write commits, exception doesn't propagate.

Both RED before this commit (AttributeError: module had no compute_hallways_for_wing attribute). Both GREEN after.

Verification

Gate Result
2 RED-first tests ✅ both pass
ruff check + ruff format --check ✅ clean (pinned 0.15.9)
Full tests/test_miner.py ✅ 47 passed (2 new + 45 pre-existing)
Full mempalace suite ✅ 1938 passed, 1 skipped, 0 regressions
Linux CI parity (OrbStack, Python 3.9 / 3.11 / 3.13) ✅ 2/2 pass, ruff clean on all three

Out of scope (deferred to follow-up PRs)

This PR is intentionally narrow: just turn on hallway computation for the most-used miner. Convo / format miners follow in stacked PRs.

Wires the hallway primitive (from PR #1558) into the project miner so
that every mine that touches a wing also materializes within-wing
entity hallways for that wing. Without this integration, the hallway
module is dead code — no miner triggers it, no hallways ever land in
~/.mempalace/hallways.json.

## What this commit does

1. Adds a module-level import of ``compute_hallways_for_wing`` from
   ``.hallways`` near the top of ``miner.py``. Module-level (not lazy)
   so tests can patch it as ``mempalace.miner.compute_hallways_for_wing``
   — lazy imports inside a function wouldn't expose the seam.

2. In ``_mine_impl``, immediately after the existing
   ``_compute_topic_tunnels_for_wing(wing)`` post-mine block, adds a
   parallel hallway block. The block:

   - calls ``compute_hallways_for_wing(wing, col=collection)``
   - prints the count if any hallways were materialized
   - wraps the whole thing in try/except so a hallway-compute failure
     is logged + degraded, never propagated. Mirrors the tunnel block's
     fault-tolerance pattern exactly. Hallway computation is a derived
     analytic, not load-bearing for the drawer write that already
     committed above.

## Stacking

This PR stacks on PR #1558 (which introduces the hallway primitive
module). PR #1558 is the prerequisite — without it, the import
``from .hallways import compute_hallways_for_wing`` doesn't resolve.

Base branch for this PR is ``feat/hallways-within-wing-connectors``
(PR #1558's branch). When PR #1558 merges to develop, GitHub will
auto-update this PR's base to develop and the diff will reduce to
just the miner.py and tests/test_miner.py changes.

## Out of scope (deferred to follow-up PRs)

- ``format_miner.py`` integration: lives on a different branch (PR #1555)
  so the parallel call there goes in as a follow-up amendment to that
  branch (or a separate post-merge PR).
- ``convo_miner.py`` integration: convo_miner currently doesn't call
  ``_compute_topic_tunnels_for_wing`` either. Adding both calls is a
  separate concerned PR about convo_miner parity, not just hallways.
- Refactoring ``_compute_topic_tunnels_for_wing`` to BUILD ON hallways
  (rather than computing from raw topic words): the architecturally
  meaningful follow-up that completes the Wing → Drawer-entities →
  Hallway → Tunnel sequence. Real refactor, separate PR.

## Tests

Two new RED-first tests in ``tests/test_miner.py``:

  test_mine_computes_hallways_for_wing_post_mine
      Stubs ``mempalace.miner.compute_hallways_for_wing`` via monkeypatch.
      Runs a real mine into a tmp palace. Asserts the stub was called
      exactly once, with the wing name from mempalace.yaml and a live
      ChromaDB collection (not None).

  test_mine_hallway_failure_does_not_crash_mine
      Stubs the hallway function to raise. Runs a real mine. Asserts
      mine() doesn't propagate, and that the drawer write (which
      happens BEFORE the hallway block) still committed.

Both RED before this commit (AttributeError — module had no attribute
``compute_hallways_for_wing``). Both GREEN after.

## Verification

  ruff check mempalace/miner.py tests/test_miner.py
    → All checks passed!
  ruff format --check ...
    → 2 files already formatted (pinned 0.15.9)
  pytest tests/test_miner.py
    → 47 passed (the 2 new + 45 pre-existing)
  pytest -q (full mempalace suite)
    → 1938 passed, 1 skipped, 0 regressions

Linux CI parity replicated locally via OrbStack containers
(Python 3.9, 3.11, 3.13): 2/2 new integration tests pass, ruff clean
on all three.
@milla-jovovich milla-jovovich requested a review from igorls as a code owner May 20, 2026 11:11

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request integrates hallway computation into the mining process by calling compute_hallways_for_wing within _mine_impl. The implementation uses a try-except block to ensure that failures in this derived analytic do not crash the main mining operation. Corresponding integration tests have been added to verify the call occurs correctly and that exceptions are handled gracefully. I have no feedback to provide.

@igorls igorls merged commit 923f797 into feat/hallways-within-wing-connectors May 20, 2026
mvalentsev pushed a commit to mvalentsev/mempalace that referenced this pull request May 21, 2026
Adds the architectural counterpart to ``compute_topic_tunnels`` that
materializes cross-wing tunnels from the within-wing hallway records
introduced in PR MemPalace#1558. When an entity (person, project, concept,
interest) has hallways in two wings, an entity tunnel bridges them —
anchored on the entity. This completes the v4 sequence: Wing →
Drawer-entities → Hallway → Tunnel.

Topic tunnels are NOT replaced. Both systems coexist for one release
cycle so existing palaces don't lose tunnels between mines. Deprecation
of topic tunnels is a separate follow-up PR after entity tunnels prove
out in real use.

## What this commit does

1. Adds ``entity_tunnels_for_wing(wing, hallways, label_prefix)`` to
   ``mempalace/palace_graph.py``. Pure function: groups hallway records
   by entity-and-wing, finds entities present in ``wing`` AND ≥1 other
   wing, and emits one ``create_tunnel`` call per (entity, other_wing)
   pair. Uses ``kind="entity"`` and synthetic endpoint room
   ``entity:<name>`` so the new tunnels are distinguishable from
   explicit/topic tunnels at read time but interchangeable with them
   via the standard ``list_tunnels`` / ``follow_tunnels`` API.

2. Adds ``_compute_entity_tunnels_for_wing(wing)`` wrapper to
   ``mempalace/miner.py``. Loads hallway records via
   ``hallways.list_hallways()`` and calls the algorithm. Module-level
   so tests can patch it as ``mempalace.miner._compute_entity_tunnels_for_wing``.

3. Wires the wrapper into ``_mine_impl`` immediately after the existing
   hallway-compute block. Same try/except fault-tolerance pattern as
   the topic-tunnel and hallway blocks — entity-tunnel computation is
   a derived analytic and must never fail a mine.

## Tests (RED-first)

Nine algorithm tests in ``tests/test_palace_graph_tunnels.py``
(new ``TestEntityTunnels`` class):

  test_entity_tunnels_creates_cross_wing_tunnel_for_shared_entity
  test_entity_tunnels_skips_entities_in_only_one_wing
  test_entity_tunnels_counts_entity_in_either_pair_position
  test_entity_tunnels_three_wings_pairwise_from_focus_wing
  test_entity_tunnels_idempotent_on_rerun
  test_entity_tunnels_retrievable_via_list_tunnels
  test_entity_tunnels_empty_hallways_is_noop
  test_entity_tunnels_unknown_wing_is_noop
  test_entity_tunnel_room_does_not_collide_with_literal_room

Two integration tests in ``tests/test_miner.py``:

  test_mine_computes_entity_tunnels_for_wing_post_mine
  test_mine_entity_tunnel_failure_does_not_crash_mine

All 11 RED before this commit (AttributeError on the missing names).
All 11 GREEN after.

## Out of scope (deferred to follow-up PRs)

- ``format_miner.py`` and ``convo_miner.py`` integration: separate PRs
  per the scope discipline used for MemPalace#1560.
- Deprecating ``_compute_topic_tunnels_for_wing``: separate PR after
  entity tunnels prove out in real use.
- Surfacing ``kind="entity"`` in MCP / search-result UI: not yet
  required by any reader; behaviorally interchangeable with the other
  tunnel kinds today.

## Stacking

This PR stacks on PR MemPalace#1558 (which introduces the hallway primitive and
its miner integration). Base branch is
``feat/hallways-within-wing-connectors``. When MemPalace#1558 merges to develop,
GitHub auto-updates this PR's base to ``develop`` and the diff reduces
to just the entity-tunnel additions.

## Verification

  pytest tests/test_palace_graph_tunnels.py::TestEntityTunnels
    → 9 passed (RED before, GREEN after)
  pytest tests/test_miner.py::test_mine_computes_entity_tunnels_for_wing_post_mine
        tests/test_miner.py::test_mine_entity_tunnel_failure_does_not_crash_mine
    → 2 passed (RED before, GREEN after)
  pytest tests/test_palace_graph_tunnels.py
    → 39 passed (no regressions)
  pytest tests/test_miner.py
    → 49 passed (no regressions)
  pytest -q (full mempalace suite)
    → 1949 passed, 1 skipped, 0 regressions
  ruff check mempalace/palace_graph.py mempalace/miner.py tests/
    → All checks passed!
  ruff format --check ...
    → 4 files already formatted (pinned 0.15.9)
arnoldwender pushed a commit to arnoldwender/mempalace that referenced this pull request May 24, 2026
Bumps version 3.3.5 → 3.3.6 across pyproject.toml, version.py, plugin
manifests (.claude-plugin/plugin.json, .claude-plugin/marketplace.json,
.codex-plugin/plugin.json), README badge, and uv.lock. Flips CHANGELOG.md
from ``[Unreleased]`` to ``[3.3.6] — 2026-05-24`` and backfills the
major user-facing entries that landed without changelog entries during
the cycle:

Features:
- MemPalace#1555 office-document mining via --mode extract + virtual line numbers
- MemPalace#1584 surgical closet pointers with date+line locators (Tier 6a)
- MemPalace#1558 + MemPalace#1560 within-wing hallways (entity co-occurrence graph)
- MemPalace#1565 cross-wing tunnels auto-promoted from hallways
- MemPalace#1578 Hebbian potentiation + Ebbinghaus decay on hallways/tunnels
- MemPalace#1236 API-tool transcripts auto-route to wing_api
- MemPalace#711 hooks.auto_save toggle for silent-mode sessions
- MemPalace#1605 COCA content-word filter for entity detection
- MemPalace#1557 case-insensitive entity matching at mine time
- MemPalace#1483 multilingual embeddings (embeddinggemma-300m) by default

Bug Fixes (selected, user-visible):
- MemPalace#1540 silent data loss in three unchunked upsert sites
- MemPalace#1538 paragraph chunker oversized chunks
- MemPalace#1554 per-file chunk cap too low for transcripts
- MemPalace#1562 Windows hook subprocess/ChromaDB deadlock
- MemPalace#1529 create_tunnel corrupted hyphenated wing names
- MemPalace#1424 save-hook truncated hyphenated project folders
- MemPalace#1383 KG cache duplicated graphs for symlinked/cased paths
- MemPalace#1466 silent symlink skip now logged
- MemPalace#1441 macOS stock-bash 3.2 hook compatibility
- MemPalace#1500 / MemPalace#1513 structured JSON-RPC errors on bad MCP input
- MemPalace#1523 VACUUM + FTS5 rebuild after repair
- MemPalace#1548 FTS5 validation at end of mine
- plus MemPalace#1216, MemPalace#1408, MemPalace#1438, MemPalace#1439, MemPalace#1445, MemPalace#1452, MemPalace#1459, MemPalace#1461, MemPalace#1466,
  MemPalace#1470, MemPalace#1477, MemPalace#1485, MemPalace#1500, MemPalace#1513, MemPalace#1528, MemPalace#1532, MemPalace#1543, MemPalace#1546, MemPalace#1585

Performance:
- MemPalace#1474 convo miner pre-fetches mined-set
- MemPalace#1487 rebuild_index progress callback
- MemPalace#1530 MCP cold-start diagnostics + opt-in warmup

Lint passes (ruff 0.15.14); mempalace-mcp entry point alignment
verified per RELEASING.md.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants