Skip to content

feat(field-memory): add governed packed attractor routing - #202

Draft
ruvnet wants to merge 1 commit into
mainfrom
agent/field-memory-package
Draft

feat(field-memory): add governed packed attractor routing#202
ruvnet wants to merge 1 commit into
mainfrom
agent/field-memory-package

Conversation

@ruvnet

@ruvnet ruvnet commented Aug 16, 2026

Copy link
Copy Markdown
Owner

Summary

Adds the experimental @metaharness/field-memory workspace package: a governed,
packed-multihead attractor field for cost-aware agent routing. Verified aggregate
outcomes change future route probabilities without putting predecessor prompts,
solutions, proofs, or tool traces into the context window.

This is deliberately called field memory, not morphic memory. The package
implements experimentally grounded mechanisms—associative attractors, decay,
drift windows, bounded history dependence, and support-gated collective updates—
without making a metaphysical claim.

Why this layout

The discovery swarm reproduced a structural failure in the expanded layout:
when one identical centroid vector is stored per configuration and
retrievalK < configurationCount, ANN selection censors valid reward heads
before scoring. In eight deterministic synthetic seeds, increasing K from 3 to
4 restored 25.00 percentage points of configuration coverage and added 11.13
success points.

Packing four reward heads behind one centroid:

  • reduced vector-index entries from 4 to 1 (4x fewer);
  • reduced serialized synthetic state by 64.66%;
  • changed success by exactly 0 across eight seeds at retrieval-equivalent depth;
  • made the centroid, rather than an arbitrary configuration head, the atomic
    retrieval unit.

These are mechanism results, not production task-quality claims. Promotion
remains gated on held-out signed trajectory replay.

Public API

import {
  createFieldMemory,
  InMemoryFieldStorage,
  createRuVectorFieldStorage,
  InMemoryRuVectorRecordRegistry,
  type FieldMemoryConfig,
  type FieldStorageAdapter,
  type PrincipalVerifier,
} from '@metaharness/field-memory';

createFieldMemory({ storage, verifier, identityHashKey, config, clock? })
exposes:

  • update(outcome) — verifies and atomically admits a bounded aggregate update;
  • choose(query) — retrieves packed centroids and returns a cost-aware route;
  • compact({ now }) — deterministic, explicit maintenance;
  • exportState() / exportStateJson() — bounded authenticated snapshots;
  • importState(state, { mode: 'replace' }) — privileged atomic restore.

The package exposes no episode list, prompt retrieval, solution reconstruction,
or proof-recovery API.

Implementation details

Packed field and temporal adaptation

  • One searchable vector per logical centroid, with all configuration reward
    heads behind it.
  • Configuration-specific embedding, reward, cost, support, and timestamp
    buckets.
  • Exponential reward/cost decay plus a hard drift window.
  • Stale centroids are compacted against a trusted clock before ANN top K, so an
    expired high-similarity row cannot censor an active row.
  • Compaction preserves below-threshold quarantine records so support can
    accumulate over time.

Routing policy

  • Cost-aware score combines semantic similarity, decayed reward, and normalized
    cost penalty.
  • hysteresisMargin defaults to zero.
  • Optional hysteresis applies only when the previous route remains within the
    configured margin and the old/new query embeddings clear the semantic
    continuity threshold.
  • Caller-owned update and query fields are cloned before the first await,
    preventing verifier/compaction TOCTOU mutation.

Governance and privacy boundary

  • The injected verifier authorizes the exact frozen update and returns the only
    principal/domain identities used for accounting.
  • HMAC-SHA-256 pseudonymizes principal, trust-domain, and principal-scoped
    idempotency identifiers with a required 32+ byte deployment key.
  • Per-update, per-centroid-principal, per-centroid-domain, and per-centroid
    aggregate budgets bound every accepted contribution.
  • Influence and replay retention use trusted acceptance time; reward recency
    uses the authenticated observation time.
  • Heads below minimumSupport remain outside the searchable centroid and cannot
    move an already eligible centroid.

The support gate is routing quarantine, not a confidentiality guarantee.
An authorized state export contains aggregates, and a singleton aggregate can
equal the original observation. Principal/domain caps are per centroid and do
not provide fleet-global Sybil resistance; verifier-side admission, global rate
limits, and centroid-creation policy remain required.

State safety

  • Schema: metaharness.field-memory/v1.
  • Canonical JSON plus HMAC-SHA-256 authenticity and a non-secret identity-key
    fingerprint; wrong-key restore fails closed.
  • Strict known-shape parsing, safe-integer/aligned time checks, unique head and
    bucket IDs, bounded cardinalities, aggregate/cap consistency, and derived
    centroid verification.
  • String and object imports share a 16 MiB / one-million-scalar budget.
  • Export applies the same budgets and throws rather than emitting a snapshot
    its own importer cannot restore.
  • Successful same-policy, same-key snapshots are byte deterministic and
    reversible only through an adapter with atomic replacement.

importState() is admin-only. Deployments must use a unique key per logical
field and enforce an external monotonic snapshot version/epoch to prevent
cross-field substitution under key reuse or rollback to an older valid HMAC.

Storage and concurrency contract

FieldStorageAdapter.atomicMutate() is a globally serialized read/modify/write
primitive. This makes idempotency, influence budgets, aggregate budgets, and
cardinality limits survive two FieldMemory instances sharing one adapter.
Adapters fail construction if required mutation methods or writer scope are
missing. writerScope: 'process' is explicitly single-process; multi-process
deployments require a distributed transaction/lock.

The dependency-free in-memory adapter is the deterministic reference oracle.
The RuVector seam is duck-typed and adds no mandatory native dependency.

RuVector dependency and compatibility

The v0.1 adapter intentionally supports only the canonical cosine-distance
contract (similarity = 1 - distance). It rejects Euclidean, dot-product, and
caller-defined score semantics.

The adapter requires the corrected contract from
RuVector PR #831 (or a later
coordinated release):

  • getIndexInfo().configurationVerified === true, backed by the native
    effective-options getter rather than requested wrapper options;
  • indexType === 'flat';
  • mutationMode === 'in-place';
  • exact dimension, lowercase cosine metric, and normalized absolute storage
    identity.

Searchable replacements use explicit-ID in-place upsert. Search requires native
metadata schema/revision to match the authoritative registry revision, turning
a partial native/registry mutation into safe unavailability instead of pairing
a new vector with old aggregates. Revision tags are a consistency check, not a
MAC; storage-writer compromise remains a trusted-boundary failure.

Published ruvector@0.2.41 is rejected because it cannot prove the effective
configuration through getIndexInfo(). This is intentional. Repeated mutable
HNSW replacement was observed to become unsearchable even while len() === 1,
and versioned IDs only delayed the failure. A direct flat-core test remained
searchable through 100 replacements, but final wrapper integration must be run
in CI against the new native effective-options build—not the transitional
sidecar wrapper or published core 0.1.32.

Draft release gate: do not enable the RuVector adapter in production until
the coordinated platform binaries and @ruvector/core release containing the
native getOptions() getter pass an actual-native, non-proxy integration smoke.

Production RuVector use also requires a durable RuVectorRecordRegistry with a
global withLock() and exact O(1) count(). The exported in-memory registry is
process-local and ephemeral. State import remains disabled unless the deployment
supplies an atomic index+registry replacement transaction.

Performance implications

  • Packed layout: 1 index row for 4 heads in the acceptance fixture (4x entry
    reduction).
  • Update: one global transaction plus an O(1) registry cardinality read;
    pruning/rebuilding is O(H * B * D) in the active centroid.
  • Choice: deterministic stale-row protection currently performs
    O(C * H * B * D) maintenance before ANN, then O(K * H * B * D) scoring.
  • With defaults K=8, H<=64, and B<=31, scoring visits at most 15,872
    head-buckets and performs up to 15,872 * D component aggregations, plus ANN
    and the maintenance pass.
  • Export/import are deliberately bounded at 16 MiB and one million structural
    scalars.
  • Runtime dependency count added by this package: 0. Knowledge changes
    routing state rather than adding predecessor tokens to each prompt.

The O(C * H * B * D) pre-search maintenance and global transaction are
correctness-first v0.1 choices and do not substantiate a
10,000-agent/100,000-centroid fleet-scale claim. Benchmark and/or replace them
with expiry-aware indexing and a durable transactional registry before that
scale.

Tests

Package tests: 41/41 passed. Publish-order tests: 6/6 passed. Combined
focused run: 47/47 passed twice, with byte-identical deterministic export.

Coverage includes:

  • four-head censorship prevention and 4x index-entry reduction;
  • configuration-specific recency ranking and deterministic drift windowing;
  • stale top-K censorship regression;
  • verified principal caps, non-grid/tiny contribution bounds, acceptance-time
    accounting, and principal-scoped idempotency;
  • 384-dimensional dense embeddings at the exact 1e-12 minimum through third-
    principal activation, choice, export/import, zero/oversized aggregate import
    rejection, and opposing-direction cancellation quarantine;
  • two-instance atomic mutation;
  • singleton rejection, searchable-centroid invariance, and quarantine retention;
  • cost-aware choice and hysteresis failure prevention;
  • update and query TOCTOU mutation;
  • malicious future query time unable to delete state;
  • deterministic authenticated export/import, wrong-key restore, future-skew
    round-trip, malformed/duplicate/over-cap hostile states;
  • byte-identical packed-centroid derivation under different configuration-head
    insertion orders;
  • numerical overflow and Euclidean magnitude guards;
  • exact RuVector effective-info fixtures, canonical cosine conversion,
    native/registry revision mismatch, insert rollback, and ambiguous-delete
    rollback;
  • release-order publication wiring.

Commands run:

./node_modules/.bin/tsc -p packages/field-memory/tsconfig.json --noEmit --pretty false
./node_modules/.bin/tsc -p packages/field-memory/tsconfig.json --pretty false
./node_modules/.bin/vitest run packages/field-memory/__tests__/field-memory.test.ts __tests__/publish-workspace.test.ts
# repeated once: 47/47 both runs
# exact upstream VectorDb shape -> RuVectorDbLike assignability: tsc --noEmit passed

Published compatibility smoke:

ruvector@0.2.41 -> rejected: getIndexInfo() from RuVector PR #831 or later required

The root ordered build and npm pack should remain CI/reviewer gates because the
execution sandbox rejected npm subprocess spawning. The package itself was
compiled directly, the scripts pass node --check, the exact settled upstream
duck type compiles, and the curated publish-order unit test passes.

Security assessment

Assessment scope: packages/field-memory, public API inputs, verifier boundary,
snapshot parser/authentication, storage transactions, native RuVector boundary,
and release dependencies.

  • Ruflo runtime: @claude-flow/cli@3.25.6.
  • Lockfile SHA-256:
    99c45988f9d5b500e81445e46dc5ec4814711494143d5f1ce1599e3b0a64f670.
  • Advisory check time: 2026-08-16T00:18:52Z.
  • Secret scan: 10 files scanned, 0 secrets.
  • STRIDE indicator scan: 10 files scanned, 0 automatic indicators; the manual
    threat model is documented in packages/field-memory/SECURITY.md.
  • npm audit --omit=dev --json: 0 total (0 critical/high/moderate/low).
  • Full workspace npm audit: 1 critical, 4 high, 3 moderate, all outside the
    production tree. Signals are the existing workspace test/tool chain
    (vitest/vite/vite-node/esbuild/nanoid/postcss) plus unrelated
    js-yaml; the new package has no runtime dependencies.
  • Ruflo reported 1 critical, 3 high, and 3 moderate dependency signals for
    both packages/field-memory and unchanged packages/router with the exact
    same package list. This confirms they are workspace dev-dependency signals,
    not new reachable field-memory or router code findings.
  • Confirmed critical/high findings in new reachable code: 0.

No scanner finding is being suppressed as a runtime issue. The dev-tool
advisories remain repository-level dependency maintenance and should be handled
separately rather than expanding this feature PR to a Vitest major upgrade.

Documentation and release wiring

  • Adds package README, full SECURITY threat model, and package-level MIT LICENSE.
  • Adds the package to phase-one ordered builds (runtime dependency-free).
  • Adds the package to curated tag publication order and updates its unit test.
  • Adds both required workspace lockfile links without unrelated install churn.
  • Adds an experimental/single-process-by-default root README entry.

Rollout and acceptance

Keep the package experimental until all of the following pass on held-out,
signed MetaHarness trajectories at equal inference/token budgets:

  • at least 5% utility lift over ordinary top-K retrieval;
  • membership-inference AUC <= 0.55;
  • less than 5 points degradation under a 10% single-principal poison cohort;
  • at least 90% post-drift recovery within 16 verified labels per task family;
  • native RuVector clear/rebuild accuracy within 2 points;
  • corrected upstream RuVector effective-options integration in CI.

Files changed (19 paths)

New package (13 source/docs/config files, 3,876 lines before generated dist):

  • packages/field-memory/{package.json,tsconfig.json,README.md,SECURITY.md,LICENSE}
  • packages/field-memory/src/{index,types,policy,util,storage,field-memory,ruvector-storage}.ts
  • packages/field-memory/__tests__/field-memory.test.ts

Repository wiring:

  • CHANGELOG.md
  • README.md
  • package-lock.json
  • scripts/build-ordered.mjs
  • scripts/publish-workspace.mjs
  • __tests__/publish-workspace.test.ts

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