ADR-0028: Dual-Plane Memory Audit Architecture (Separate Regions)¶
| Field | Value |
|---|---|
| Status | Accepted (Implemented) |
| Date | 2026-08-28 |
| Authors | Spector Maintainers & Architecture Working Group |
| Deciders | Spector Technical Steering Committee (TSC) |
| Supersedes | None |
| Superseded By | ADR-0029 (for §D4 Provenance) |
| Last Verified | 2026-09-16 (Verified against main) |
1. Context¶
1.2 The Two Distinct Audit Needs in Spector Architecture¶
A deep architectural analysis across the Spectrayan portfolio reveals two fundamentally distinct auditing tiers within the spector-memory engine (in addition to the high-level application/REST audit log in spector-synapse #211):
| 1. SYNAPSE GOVERNANCE AUDIT (spector-synapse #211) | 2. SYNAPTIC RECALL AUDIT (spector-memory #506) | 3. KERNEL PROVENANCE CHRONICLE (spector-memory MF-001) |
|---|---|---|
| • Layer: Spring Boot / REST • Scope: Agent / System Level • Storage: H2 / JDBC / RDBMS • Events: Chat sessions, tool calls, guardrail blocks, approval requests, PII redactions, config changes • Purpose: Enterprise SOC2 / compliance querying | • Layer: Off-Heap Cortex • Scope: Per-Memory Slot • Storage: Fixed-Stride Mmap • Metrics: Recall counters, ACT-R 8-slot ring buffer, Two-Factor S(t), LTP cooldowns, agent hash, rank • Purpose: SIMD cache-line isolation & spacing effect | • Layer: Off-Heap Kernel • Scope: Engine History • Storage: Append-Only • Chronicle: Ingestion source lineage (S3, Git SHA, URI), reconsolidate diffs, consolidate lineage, pruning & retractions |
2. Problem Statement¶
1.1 The Mixed 64-Byte Cache Line Pathology¶
In Spector Memory, every cognitive memory record in off-heap Panama FFM storage (spector-memory) consists of a 64-byte SynapticHeader (HeaderLayout64) followed by a quantized vector payload (INT8 scalar quantized float vector).
The 64-byte header was designed to match a single CPU cache line (64 bytes). However, as cognitive capabilities evolved (emotional gating, Zeigarnik effect, Two-Factor Bjork memory decay, auto-LTP cooldowns, adaptive cognitive profile learning, and soul-state tracking), the 64-byte header became a mixed-tenancy cache line containing two fundamentally opposing classes of data:
- Immutable Encoding Identity:
header_version,flags,valence,arousal,base_importance,timestamp_ms,exact_norm,synaptic_tags(Bloom filter),centroid_id,consolidation_flags,encoding_profile,encoding_alpha/beta,soul_version,encoding_surprise. (Written once during ingestion). - Mutable Recall Audit Telemetry:
agent_recall_count,storage_strength(\(S(t)\)),spector_recall_cnt,last_auto_ltp,last_recall_profile,effective_importance. (Mutated on every query retrieval and reinforcement).
3. Decision Drivers¶
- 100% Cache Line Isolation: Immutable memory identity headers must remain untouched by frequent query retrieval mutations.
- Sub-Millisecond ACT-R Power-Law Decay: Support 8-slot ring-buffer timestamp tracking for Anderson (1993) spacing effect without heap churn.
- Zero-Allocation Mmap Stride: Per-slot recall audit telemetry must align to fixed byte strides accessed via Panama FFM memory segments.
- Append-Only Provenance Separation: Decouple high-frequency per-slot recall stats from long-term immutable ingestion and consolidation provenance logs.
4. Considered Options¶
Option 1: Monolithic 128-Byte Expanded Header¶
- Description: Expand
HeaderLayout64to 128 bytes, putting both identity and audit telemetry on adjacent cache lines. - Advantages: Single contiguous allocation per record.
- Disadvantages: Doubling header footprint severely impairs vector scan cache residency; false sharing across threads.
Option 2: External Relational / JDBC Audit Logging¶
- Description: Direct all recall counters and timestamp updates to an external RDBMS or embedded H2 database.
- Advantages: Rich SQL querying.
- Disadvantages: Introduces multi-millisecond disk I/O and transaction serialization onto the sub-millisecond recall hot path.
Option 3: Dual-Plane Separate Region Architecture (Selected)¶
- Description: Physically split immutable encoding headers (in data slabs) from mutable recall telemetry (in dedicated fixed-stride mmap regions:
RegionId.STRENGTH/RECALL_AUDIT), while recording engine-level provenance in append-only chronicle regions (RegionId.PROVENANCE_CHRONICLE, superseded by ADR-0029). - Advantages: 100% L1/L2 cache isolation; zero-allocation point updates; unblocks ACT-R 8-slot power-law calculations.
- Disadvantages: Requires managing an additional mmap region per partition.
5. Decision Outcome¶
D1: Pure 64-Byte V2 Synaptic Header (HeaderLayout64V2)¶
The Synaptic Header is bumped to header_version = 2. All mutable runtime counters are excised from the header cache line.
The freed space is leveraged to:
- Upgrade Synaptic Tags Bloom Filter to 128-Bit (16 Bytes): Offsets 24–39 now hold a 128-bit double-hash Bloom filter, reducing false-positive rates during pre-filtering from ~3.2% down to <0.05% across 100K concepts.
- Establish 16-Byte Reserved Gating Block: Offsets 48–63 provide future-proof reserved capacity for holographic manifold representations, Riemannian curvature invariants, and multi-modal sensory routing without requiring further header size shifts.
Complete V2 Synaptic Header Byte Map (64 Bytes)¶
| Offset | Size | Type | Field Name | Access Mode | Biological & Functional Meaning |
|---|---|---|---|---|---|
0 | 1B | uint8 | header_version | Read-Once | Set to 2 (identifies V2 pure encoding header). |
1 | 1B | uint8 | flags | Scan Hot Path | Bitfield: tombstone(0), type(1-2), consolidated(3), pinned(4), resolved(5), modality(6-7). |
2 | 1B | int8 | valence | Scan Filter | Initial emotional valence at formation (signed: -128 to +127). |
3 | 1B | uint8 | arousal | Scan Filter | Emotional intensity at formation (unsigned: 0 to 255). |
4 | 4B | float32 | base_importance | Scan Filter | Initial ICNU importance score calculated at ingestion (0.05 to 10.0). |
8 | 8B | int64 | timestamp_ms | Scan Filter | Unix epoch millisecond timestamp when the memory was formed. |
16 | 4B | float32 | exact_norm | SIMD Norm | L2 norm of the unquantized float vector for exact cosine denominator. |
20 | 2B | int16 | centroid_id | IVF Partition | Routing cluster ID for inverted file index coarse quantization. |
22 | 2B | bytes | _pad0 | Alignment | Natural 8-byte boundary alignment padding. |
24 | 8B | uint64 | synaptic_tags_lo | Tag Gating | 128-bit Bloom filter low 64 bits (contextual semantic markers). |
32 | 8B | uint64 | synaptic_tags_hi | Tag Gating | 128-bit Bloom filter high 64 bits (hash salt 2 markers). |
40 | 1B | uint8 | consolidation_flags | Provenance | Governance: CONTRADICTED(0), RETRACTED(1), UNVERIFIED(2), RESTRICTED(3), CRYSTALLIZED(4), SIMULATED(5), DREAMED(7). |
41 | 1B | uint8 | encoding_profile | State Stamp | Cognitive profile ordinal active during ingestion (bit 7 = soul derived). |
42 | 1B | uint8 | encoding_alpha | State Stamp | Quantized scoring alpha weight at encoding time (\([0.0, 1.0] \to [0, 255]\)). |
43 | 1B | uint8 | encoding_beta | State Stamp | Quantized scoring beta weight at encoding time (\([0.0, 1.0] \to [0, 255]\)). |
44 | 2B | uint16 | soul_version | State Stamp | Monotonic configuration generation counter of the active soul. |
46 | 2B | bytes | _reserved_geo | Alignment | Reserved for manifold geodesic coordinates. |
48 | 4B | float32 | encoding_surprise | State Stamp | Bayesian surprise z-score at encoding time from predictive coding. |
52 | 12B | bytes | _reserved | Alignment | Zero-padded reserved block for future neural tensor invariants. |
D2: Single Unified Partition Strength Region (RegionId.STRENGTH & StrengthLayout)¶
Instead of creating separate strength/audit regions per tier (AUDIT_SEMANTIC, AUDIT_EPISODIC, AUDIT_PROCEDURAL), PartitionBundle allocates a single unified RegionId.STRENGTH(4) region (originally named RegionId.AUDIT(4) in initial design; renamed to RegionId.STRENGTH to disambiguate recall strength and retention telemetry from operational execution auditing).
Note
Diagnostic CLI (spector-inspect) Drift: For on-disk backward compatibility, StrengthLayout.LAYOUT_ID remains pinned to 0x41554454 ('AUDT'), while RegionId(4) is STRENGTH. Consequently, spector-inspect bundle displays Region ID: STRENGTH alongside Layout ID: 0x41554454 ("TDUA" / 'AUDT').
Architectural Design of Unified Strength Space:¶
- Memory Type Ordinal Embedded: The
StrengthLayoutembeds thememoryTypeordinal (2 bits inaudit_flags), matching the memory type bits inSynapticHeaderConstants.FLAG_TYPE_MASK. -
Cumulative Slot Indexing: The total capacity of the strength region equals \(C_{\text{total}} = C_{\text{semantic}} + C_{\text{episodic}} + C_{\text{procedural}}\). Addressing is computed by cumulative tier base offsets: $\(\text{strengthOffset}(\text{tier}, \text{slot}) = (\text{tierBaseSlot}(\text{tier}) + \text{slot}) \times \text{recordStride}\)$
-
Parity with Text Region: Just as
RegionId.TEXTinPartitionBundleserves all tiers as a single shared text blob store,RegionId.STRENGTHserves all tiers as a single shared strength store.
flowchart TD
subgraph bundle ["PARTITION BUNDLE FILE (partition.bundle)"]
direction TB
header["64B SMKM MemoryHeader"]
subHeader["64B SPTB BundleSubHeader"]
dirEntries["Bundle Directory Entries (SEMANTIC, EPISODIC, PROCEDURAL, TEXT, STRENGTH)"]
region0["Region 0: SEMANTIC (64B V2 Header + INT8 Vector) ──► Pure Read-Only Pages"]
region1["Region 1: EPISODIC (Episodic Log Structure)"]
region2["Region 2: PROCEDURAL (64B V2 Header + INT8 Vector) ──► Pure Read-Only Pages"]
region3["Region 3: TEXT (Shared variable length text blobs)"]
subgraph region4 ["Region 4: STRENGTH (Single Unified Recall Strength Region) ──► Write-Heavy"]
direction TB
semStr["[0 .. N_sem - 1] : Semantic Strength Records"]
epiStr["[N_sem .. N_sem+epi] : Episodic Strength Records"]
proStr["[N_sem+epi .. Total] : Procedural Strength Records"]
semStr ~~~ epiStr ~~~ proStr
end
header ~~~ subHeader ~~~ dirEntries ~~~ region0 ~~~ region1 ~~~ region2 ~~~ region3 ~~~ region4
end Complete AuditRecordLayout Byte Map (96 Bytes, 32-Byte Aligned)¶
| Offset | Size | Type | Field Name | Atomic / Op | Purpose & Mathematical Model |
|---|---|---|---|---|---|
0 | 1B | uint8 | audit_flags | Plain Set | Bit 0-1: memory_type ordinal (0=WORKING, 1=EPISODIC, 2=SEMANTIC, 3=PROCEDURAL). |
1 | 1B | uint8 | last_recall_profile | Plain Set | CognitiveProfile ordinal used during last recall. |
2 | 1B | int8 | last_recall_valence | Plain Set | Valence signal recorded during reinforcement. |
3 | 1B | uint8 | _pad0 | Alignment | Byte alignment. |
4 | 4B | int32 | agent_recall_count | VarHandle.getAndAdd | Count of explicit agent reinforcements via reinforce(). |
8 | 4B | int32 | spector_recall_cnt | VarHandle.getAndAdd | Count of passive auto-LTP retrievals via recall pipeline. |
12 | 4B | float32 | effective_importance | VarHandle.compareAndSet | Mutable importance score updated by ICNU hint re-fusion. |
16 | 4B | float32 | storage_strength | VarHandle.compareAndSet | Two-Factor Bjork \(S(t) \in [1.0, 5.0]\), \(\Delta S = s_{\text{gain}} \cdot (1 - R(t))\). |
20 | 4B | uint32 | last_agent_hash | Plain Set | MurmurHash3 of the agent ID that performed the recall. |
24 | 8B | int64 | last_auto_ltp | Volatile Write | Epoch millisecond of the most recent auto-LTP cooldown. |
32 | 8B | int64 | last_recall_ts | Volatile Write | Epoch millisecond of the most recent query retrieval. |
40 | 32B | int32[8] | act_r_ring_buffer | Volatile CAS | Ring buffer of 8 relative-second offsets for Anderson (1993) ACT-R. |
72 | 8B | int64 | reconsolidation_delta | CAS | Micro-plasticity weight shift history. |
80 | 16B | bytes | _reserved_telemetry | Alignment | Future caller trace pointer / execution context ID. |
D3: Full Anderson (1993) ACT-R 8-Slot Ring Buffer Engine¶
With 32 dedicated bytes in AuditRecordLayout, we expand the ACT-R ring buffer from a disabled 3-slot construct to an active 8-slot circular ring buffer:
where \(t_j = \text{nowMs} - (\text{creationMs} + \Delta t_j \times 1000)\).
Evaluation:¶
- Stored as
uint32seconds elapsed sincecreationMs(\(\approx 136\) years range). - Evaluated in \(O(1)\) via precomputed decay table lookup (
DecayStrategy#ageToBucket) and algebraic sigmoid normalization \(\sigma(\ln x) = \frac{x}{x + 1}\) — zeroMath.pow, zeroMath.log, zeroMath.expat query time.
D4: Kernel Provenance & Lineage Chronicle Region (RegionId.PROVENANCE_LOG)¶
To fulfill MF-001 (Memory Model Algebra & Conformance Rules) and Issue #171 (Memory Lineage & Provenance) at the storage layer:
- Dedicated Append-Only Region:
RuntimeBundleandPartitionBundlesupportRegionId.PROVENANCE_LOG(26). -
Binary Provenance Record (
ProvenanceEntry):timestamp_ms(8B),target_memory_id(16B TSID),operation_code(1B:INGEST,CONSOLIDATE,RECONSOLIDATE,REINFORCE,FORGET,RETRACT,SIMULATE_COMMIT).source_uri_hash(8B),parent_trace_count(2B),parent_trace_ids(variable array of parent TSIDs collapsed during semantic reflection),lineage_diff(text/binary delta).
-
Difference from
MemoryWal: WhileMemoryWalis a short-lived, rolling recovery log compacted during checkpoints, thePROVENANCE_LOGis an immutable longitudinal audit chronicle that guarantees full explainability: "Why does the agent know this fact, which raw episodes were synthesized to form it, and when was it modified?"
3. Class Hierarchy & SPI Contracts¶
classDiagram
class HeaderLayout {
<<sealed interface>>
+headerBytes() int
+version() int
+readTimestamp(seg, off) long
+readSynapticTags(seg, off) long
+readExactNorm(seg, off) float
+readBaseImportance(seg, off) float
+readFlags(seg, off) byte
}
class HeaderLayout64V1 {
<<legacy record>>
+version() 1
}
class HeaderLayout64V2 {
<<record>>
+version() 2
+readSynapticTagsLo(seg, off) long
+readSynapticTagsHi(seg, off) long
+readConsolidationFlags(seg, off) byte
+readEncodingProfile(seg, off) byte
+readEncodingSurprise(seg, off) float
}
class AuditRecordLayout {
<<record>>
+recordStride() 96
+layoutId() int
+schemaVersion() int
+readAgentRecallCount(seg, off) int
+incrementAgentRecallCount(seg, off) int
+readEffectiveImportance(seg, off) float
+casEffectiveImportance(seg, off, fn) float
+readStorageStrength(seg, off) float
+casStorageStrength(seg, off, fn) float
+recordRecall(seg, off, creationMs, nowMs) void
+computeBaseLevelActivation(seg, off, creationMs, nowMs) float
}
class CognitiveRecordLayout {
+headerLayout() HeaderLayout
+auditLayout() AuditRecordLayout
+vectorOffset(recordOffset) long
+stride() int
}
class AuditRecordMemory {
<<class>>
-MemorySegment auditSegment
-AuditRecordLayout auditLayout
+auditOffset(type, slot) long
+auditRecord(type, slot) AuditRecord
}
HeaderLayout <|-- HeaderLayout64V1 : permits
HeaderLayout <|-- HeaderLayout64V2 : permits
CognitiveRecordLayout o-- HeaderLayout
CognitiveRecordLayout o-- AuditRecordLayout
AuditRecordMemory o-- AuditRecordLayout 6. Pros and Cons of the Options¶
| Option | Pros | Cons |
|---|---|---|
| Option 1: 128B Header | Single region | False sharing, vector scan cache pollution |
| Option 2: JDBC Logging | SQL queries | 100× latency penalty on recall hot paths |
| Option 3: Dual-Plane Regions | Pristine cache isolation, zero GC, ACT-R power-law ready | Additional mmap region per partition |
7. Implementation Plan¶
- Phase 1: Define
RegionId.STRENGTH/RecallAuditLayoutinmemory/spector-kernel. - Phase 2: Migrate mutable telemetry fields out of
HeaderLayout64. - Phase 3: Implement 8-slot timestamp ring buffer for ACT-R Bjork spacing decay.
- Phase 4: Author
BundleMigrationClito migrate V1 shards to the dual-plane layout. - Phase 5: Superceded §D4 provenance chronicle via ADR-0029 (
LineageProvenanceRegion).
8. Code Reference & Verification¶
Positive¶
- 100% Cache Isolation: Read-mostly encoding headers remain pristine in CPU caches during intense concurrent recall and reinforcement.
- Unified Region Efficiency: Exactly 1 strength region (
RegionId.STRENGTH, formerlyRegionId.AUDIT) per partition bundle simplifies directory structure, allocations, and OS paging. - Unblocks ACT-R Cognitive Modeling: Provides 8 dedicated timestamp slots for full Anderson (1993) power-law decay and spacing effect calculations.
- 60× Higher Tag Filtering Precision: 128-bit Bloom filter slashes false-positive candidate generation in large memory stores.
- Full MF-001 Provenance Conformance: Cleanly separates fast slot-indexed recall telemetry from long-term immutable provenance logs.
Negative / Trade-Offs¶
- Disk Footprint Growth: +96 bytes per allocated record in the partition bundle (~91 MB per 1M records). Mitigated by fixed-size bundle provisioning and sparse allocation.
- Migration Requirement: Existing V1 persistent shards require a one-time migration step via
BundleMigrationCli.
Code Reference & Verification Gate¶
- Primary Module(s):
memory/spector-kernel,memory/spector-memory,bench/spector-bench - Key Packages:
com.spectrayan.spector.kernel.layout,com.spectrayan.spector.memory.scheduler - Classes:
EncodingHeaderLayout.java,TaskRunAuditRecord.java,MindSpanStrengthAndAuditInspectionTest.java - Verification Tests:
EncodingHeaderLayoutTest.java,EncodingHeaderFieldsTest.java