Skip to content

fix(hivemind): two silent cross-space corruption paths in ec_merge - #467

Open
dennys246 wants to merge 3 commits into
mainfrom
fix/hivemind-cosine-dim-mismatch
Open

fix(hivemind): two silent cross-space corruption paths in ec_merge#467
dennys246 wants to merge 3 commits into
mainfrom
fix/hivemind-cosine-dim-mismatch

Conversation

@dennys246

Copy link
Copy Markdown
Owner

Found by a design-review round on the cross-modal perception-fabric plan; both bugs are live on the shipped merge surface independent of that plan, which is why they ship separately.

  1. _cosine truncated via zipec_merge gates on modality only, never dimension, and EC node payloads carry no encoder identity. A 384-dim and a 768-dim node with the same modality tag were compared over the first 384 dims and merged if that partial cosine cleared 0.44. Now returns 0.0 on length mismatch, so the node inserts separately rather than contaminating a centroid.
  2. DEFAULT_FROZEN_CENTROID_MODALITIES silently diverged from ECConfig{interoception} vs {interoception, audio}, while the comment claimed they matched. A default-argument ec_merge running-mean-updated audio centroids across contributors, precisely what the local EC forbids for that modality (EC centroid-drift lesson). Corrected + pinned by a test, since this layer deliberately avoids internal-module imports.

4 guard tests added. Full hivemind suite green.

🤖 Generated with Claude Code

dennys246 and others added 2 commits August 6, 2026 11:24
Both found by a design-review round on the perception-fabric plan; both are
live on the shipped merge surface, independent of that plan.

1. _cosine used zip(a, b), which TRUNCATES to the shorter vector. ec_merge
   gates on modality only (never dimension) and EC node payloads carry no
   encoder identity, so a 384-dim node and a 768-dim node of the same
   modality tag were compared over the first 384 dims and merged whenever
   that partial cosine cleared the 0.44 threshold. Different-length vectors
   come from different encoder spaces and are not comparable: return 0.0 so
   the pair falls below every threshold and the right-side node inserts as
   its own node (non-destructive, matches the zero-norm convention).

2. DEFAULT_FROZEN_CENTROID_MODALITIES was {interoception} while
   ECConfig.frozen_centroid_modalities is {interoception, audio} — the
   comment already CLAIMED they matched. A default-argument ec_merge
   therefore running-mean-updated audio centroids across contributors,
   exactly what the local EC forbids for that modality (the EC
   centroid-drift lesson). Literal corrected; equality pinned by a test
   since the layer deliberately avoids internal-module imports.

Guards: 4 tests (dim-mismatch cosine, cross-dim nodes stay separate,
frozen-set equality with ECConfig, audio centroid stays frozen).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
git add -A picked up an untracked design-plan draft that belongs on its own
branch. This PR is a pure src/ + tests fix; the plan ships separately after
its review-fold.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…CLAUDE.md's false parity claim

A release-readiness audit independently rediscovered the merge.py bugs and
rated them 1.1-blocking, and found two things this PR missed:

1. similarity/ec.py::_cosine_similarity has the SAME unguarded zip. Reachable
   within a single agent across a LOAD boundary, not just cross-contributor: an
   ec.json written while sentence-transformers was installed holds 768-dim
   LinguisticEncoder nodes, but the same encoder silently falls back to a
   384-dim bag-of-words hash when the semantic extra is absent — so the next
   session compares 384 against 768, truncates, and pattern-COMPLETES onto an
   incomparable node. Now returns 0.0 so it pattern-separates instead.

2. CLAUDE.md asserted the hivemind default is frozenset({interoception})
   matching ECConfig.frozen_centroid_modalities. That was already false —
   audio was added to ECConfig in PR #383 and never mirrored — so a
   behavioral-tier invariant documented a parity that did not hold, on the
   modality Exp 45/48 both rest on. Corrected, with the divergence history and
   the pinning test named.

Guard: test_cosine_similarity_returns_zero_on_dimension_mismatch.
CLAUDE.md invariant lint passes.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
dennys246 added a commit that referenced this pull request Aug 7, 2026
…ty + safety consequences

Operator report: Stewart motors 2 and 3 were broken across essentially all of
1.0+, replaced ~2026-08-05, all six legs now healthy.

ROOT CAUSE IS OURS: an earlier Maxim commanded a pose beyond physical
capability, the motors glitched, the head snapped to the opposite extreme, and
the robot rotated off the table. That is a workspace-limit enforcement failure,
connecting directly to the orient-vocabulary audit: MoveTool gaze and
turn_around both bypass ReachyMiniController.goto_target, so they plausibly
bypass workspace clamping too. Item 8 elevated from correctness to SAFETY,
top priority after PR #467.

DATA QUALITY: every live-hardware measurement in 1.0+ was taken on a degraded
platform — including the 2026-07-16 'TRUE characterization' (0.57 az/rad,
R^2=0.9982), which the previous note wrongly assumed was the healthy baseline.
Better hypothesis for the contested DoA curve: PROGRESSIVE degradation, with
0.57 (July) and 0.19 (August) both real measurements of a declining platform.
Predicts healthy hardware now measures >=0.57, nearer geometric 0.637.

Direction findings likely survive; MAGNITUDE findings do not — delivered shift
is exactly what degradation corrupts, and that line rested on n=1 sessions.
All magnitude claims provisional pending re-measurement.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
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.

1 participant