Version: 1.0.0 Status: Active — Semantic Interface Layer Last Updated: 2024-12-27 License: CC BY 4.0
Architecture Note: This document defines the Semantic Interface Layer — the developer-facing application-level addressing format. It is NOT deprecated. RPP operates as two complementary layers:
- v1.0 (this document): Semantic Interface — what developers write: Shell/Theta/Phi/Harmonic mapped to human-meaningful concepts (storage tier, data type, consent level, routing mode).
- v2.0 (RPP-CANONICAL-v2.md): Transport/Resonance Layer — what the substrate routes: θ/φ/h/r derived from Ra System constants.
This relationship is analogous to DNS vs. subnet addressing: both are correct, both are active, and they serve different levels of the protocol stack. See ADDRESSING-LAYERS.md for the full architecture.
This document defines the 28-bit RPP Semantic Interface Layer. This is the primary API for developers: addresses are encoded in human-meaningful terms (storage tier, data type, consent spectrum, routing mode). The transport substrate uses the v2.0 Ra-Canonical format; a translation layer bridges the two. See ADDRESSING-LAYERS.md.
Critical design property: RPP addresses are routing states, not permanent object identifiers.
A data record does not have one fixed RPP address. Its address is a function of:
address = f(data_type, current_consent_state, routing_context)
When consent changes, the address changes. An address resolved at time T is not guaranteed valid at time T+1. Callers MUST resolve addresses at the point of access — caching is not safe.
This means the 28-bit address space (268,435,456 values) represents concurrent routing capacity, not a universal object namespace. Addresses are recycled as consent states change, sessions end, or routing contexts expire.
Implications:
- Stolen addresses become stale — unlike stolen object IDs, which are permanently valid
- Consent revocation is immediate — the address ceases to resolve; no object can be located
- No central registry — nothing permanently maps "this data" to "this address"
- The Shell field encodes temporal scope (see Section 2.3)
On spintronic hardware, temporality is enforced physically: the spin state carrying a routing permission decoheres in T2 time. The address literally ceases to exist in the substrate. Software implementations MUST enforce equivalent TTL semantics per Shell tier.
┌─────────────────────────────────────────────────────────────┐
│ 28-BIT RPP ADDRESS │
├────────┬────────────┬────────────┬──────────────────────────┤
│ Shell │ Theta │ Phi │ Harmonic │
│ 2 bits │ 9 bits │ 9 bits │ 8 bits │
├────────┼────────────┼────────────┼──────────────────────────┤
│ [27:26]│ [25:17] │ [16:8] │ [7:0] │
└────────┴────────────┴────────────┴──────────────────────────┘
| Field | Bits | Position | Range | Type |
|---|---|---|---|---|
| Shell | 2 | 27:26 | 0-3 | Unsigned |
| Theta | 9 | 25:17 | 0-511 | Unsigned |
| Phi | 9 | 16:8 | 0-511 | Unsigned |
| Harmonic | 8 | 7:0 | 0-255 | Unsigned |
Total Width: 28 bits (unsigned integer) Address Space: 2²⁸ = 268,435,456 concurrent routing states (recycled over time — not a fixed namespace)
Shell encodes both storage proximity AND the temporal validity window of the routing address. Implementations MUST enforce address expiry per shell tier:
| Shell | Name | Storage | Address TTL (software) | Spintronic T2 |
|---|---|---|---|---|
| 0 | Hot | In-memory cache | Session duration | ~25 ns |
| 1 | Warm | Near-line storage | Transaction / day | ~100 ns |
| 2 | Cold | Archive | Agreement / month | ~400 ns |
| 3 | Frozen | Deep archive | Until explicit revocation | ~1,600 ns |
A Shell=0 (Hot) address resolved in one session MUST NOT be assumed valid in another session. A Shell=3 (Frozen) address persists until the data owner explicitly revokes consent.
This is the software equivalent of the spintronics T2 profile: Shell determines how long the routing permission physically (or logically) survives.
| Field | Mask | Shift |
|---|---|---|
| Shell | 0x0C000000 | 26 |
| Theta | 0x03FE0000 | 17 |
| Phi | 0x0001FF00 | 8 |
| Harmonic | 0x000000FF | 0 |
When RPP addresses are stored or transported in wider containers (e.g., 32-bit or 64-bit words):
- Bits 28-31 MUST be zero for any valid canonical RPP address
- Addresses with non-zero bits 28-31 MUST NOT be interpreted as valid RPP addresses
- These bits are reserved for potential future extension
- Implementations MUST validate that bits 28-31 are zero before interpreting an address
Rationale: This reservation allows future specification versions to extend the address space if needed, while maintaining backward compatibility with existing implementations that properly validate.
32-bit container:
┌────────────────┬─────────────────────────────────────────────┐
│ Reserved │ 28-bit RPP Address │
│ (MUST = 0) │ Shell | Theta | Phi | Harmonic │
├────────────────┼────────────────────────────────────────────┤
│ [31:28] │ [27:0] │
└────────────────┴────────────────────────────────────────────┘
address = (shell << 26) | (theta << 17) | (phi << 8) | harmonic
FUNCTION encode(shell, theta, phi, harmonic) -> address:
ASSERT 0 <= shell <= 3
ASSERT 0 <= theta <= 511
ASSERT 0 <= phi <= 511
ASSERT 0 <= harmonic <= 255
address = 0
address = address OR (shell SHIFT_LEFT 26)
address = address OR (theta SHIFT_LEFT 17)
address = address OR (phi SHIFT_LEFT 8)
address = address OR harmonic
RETURN address
def encode_rpp_address(shell: int, theta: int, phi: int, harmonic: int) -> int:
"""
Encode RPP components into a 28-bit address.
Args:
shell: Radial depth (0-3)
theta: Angular longitude (0-511)
phi: Angular latitude (0-511)
harmonic: Frequency/mode (0-255)
Returns:
28-bit unsigned integer
Raises:
ValueError: If any component out of range
"""
if not (0 <= shell <= 3):
raise ValueError(f"Shell must be 0-3, got {shell}")
if not (0 <= theta <= 511):
raise ValueError(f"Theta must be 0-511, got {theta}")
if not (0 <= phi <= 511):
raise ValueError(f"Phi must be 0-511, got {phi}")
if not (0 <= harmonic <= 255):
raise ValueError(f"Harmonic must be 0-255, got {harmonic}")
return (shell << 26) | (theta << 17) | (phi << 8) | harmonicshell = (address >> 26) & 0x3
theta = (address >> 17) & 0x1FF
phi = (address >> 8) & 0x1FF
harmonic = address & 0xFF
FUNCTION decode(address) -> (shell, theta, phi, harmonic):
ASSERT 0 <= address <= 0x0FFFFFFF
shell = (address SHIFT_RIGHT 26) AND 0x3
theta = (address SHIFT_RIGHT 17) AND 0x1FF
phi = (address SHIFT_RIGHT 8) AND 0x1FF
harmonic = address AND 0xFF
RETURN (shell, theta, phi, harmonic)
def decode_rpp_address(address: int) -> tuple[int, int, int, int]:
"""
Decode a 28-bit RPP address into components.
Args:
address: 28-bit unsigned integer
Returns:
Tuple of (shell, theta, phi, harmonic)
Raises:
ValueError: If address exceeds 28 bits
"""
if not (0 <= address <= 0x0FFFFFFF):
raise ValueError(f"Address must be 0-0x0FFFFFFF, got {hex(address)}")
shell = (address >> 26) & 0x3
theta = (address >> 17) & 0x1FF
phi = (address >> 8) & 0x1FF
harmonic = address & 0xFF
return (shell, theta, phi, harmonic)The following MUST always be true:
- Bounded Range:
0 <= address <= 0x0FFFFFFF - Deterministic Encoding:
encode(decode(x)) == xfor all validx - Deterministic Decoding:
decode(encode(s,t,p,h)) == (s,t,p,h)for all valid inputs - No Reserved Bits: Bits 28-31 are unused and MUST be zero
| Component | Invariant |
|---|---|
| Shell | Always 0-3 (2-bit unsigned) |
| Theta | Always 0-511 (9-bit unsigned) |
| Phi | Always 0-511 (9-bit unsigned) |
| Harmonic | Always 0-255 (8-bit unsigned) |
To convert degrees (0-359) to 9-bit theta:
def degrees_to_theta(degrees: float) -> int:
"""Convert 0-359 degrees to 0-511 theta."""
normalized = degrees % 360
return int(normalized * 511 / 359)
def theta_to_degrees(theta: int) -> float:
"""Convert 0-511 theta to 0-359 degrees."""
return theta * 359 / 511To convert degrees (-90 to +90) to 9-bit phi:
def latitude_to_phi(latitude: float) -> int:
"""Convert -90 to +90 latitude to 0-511 phi."""
normalized = latitude + 90 # 0-180
return int(normalized * 511 / 180)
def phi_to_latitude(phi: int) -> float:
"""Convert 0-511 phi to -90 to +90 latitude."""
return (phi * 180 / 511) - 90| Test Case | Shell | Theta | Phi | Harmonic | Address (Hex) | Address (Dec) |
|---|---|---|---|---|---|---|
| Minimum | 0 | 0 | 0 | 0 | 0x0000000 | 0 |
| Maximum | 3 | 511 | 511 | 255 | 0xFFFFFFF | 268,435,455 |
| Shell max | 3 | 0 | 0 | 0 | 0xC000000 | 201,326,592 |
| Theta max | 0 | 511 | 0 | 0 | 0x3FE0000 | 66,846,720 |
| Phi max | 0 | 0 | 511 | 0 | 0x001FF00 | 130,816 |
| Harmonic max | 0 | 0 | 0 | 255 | 0x00000FF | 255 |
| Description | Shell | Theta | Phi | Harmonic | Address (Hex) |
|---|---|---|---|---|---|
| Hot cache, identity sector | 0 | 45 | 256 | 128 | 0x05B0080 |
| Warm memory, standard | 1 | 100 | 255 | 64 | 0x44CFF40 |
| Cold archive, grounded | 2 | 200 | 50 | 32 | 0x86433220 |
| Frozen meta, abstract | 3 | 450 | 400 | 200 | 0xF8590C8 |
# All test cases MUST pass roundtrip
test_cases = [
(0, 0, 0, 0),
(3, 511, 511, 255),
(1, 256, 256, 128),
(2, 100, 400, 50),
]
for shell, theta, phi, harmonic in test_cases:
encoded = encode_rpp_address(shell, theta, phi, harmonic)
decoded = decode_rpp_address(encoded)
assert decoded == (shell, theta, phi, harmonic), f"Roundtrip failed for {(shell, theta, phi, harmonic)}"The 28-bit address fits in a 32-bit register with 4 bits spare:
┌────────────┬────────────────────────────────┐
│ 4 unused │ 28-bit RPP address │
│ [31:28] │ [27:0] │
└────────────┴────────────────────────────────┘
The upper 4 bits MAY be used for:
- Parity bits
- Protocol version
- Error correction
- Application-specific flags
For SPI transmission, addresses are sent MSB-first in 4 bytes:
Byte 0: [31:24] - Upper 4 bits (unused) + Shell + Theta[8:6]
Byte 1: [23:16] - Theta[5:0] + Phi[8:6]
Byte 2: [15:8] - Phi[5:0] + Harmonic[7:6]
Byte 3: [7:0] - Harmonic[5:0] + padding
module rpp_address_decoder (
input wire [27:0] address,
output wire [1:0] shell,
output wire [8:0] theta,
output wire [8:0] phi,
output wire [7:0] harmonic
);
assign shell = address[27:26];
assign theta = address[25:17];
assign phi = address[16:8];
assign harmonic = address[7:0];
endmodule
module rpp_address_encoder (
input wire [1:0] shell,
input wire [8:0] theta,
input wire [8:0] phi,
input wire [7:0] harmonic,
output wire [27:0] address
);
assign address = {shell, theta, phi, harmonic};
endmodule| Error Condition | Response |
|---|---|
| Address > 0x0FFFFFFF | Reject with INVALID_ADDRESS |
| Encoding overflow | Clamp to maximum or reject |
| Decoding non-28-bit | Mask upper bits or reject |
def validate_address(address: int) -> bool:
"""Return True if address is valid 28-bit RPP address."""
return 0 <= address <= 0x0FFFFFFF| Version | Date | Changes |
|---|---|---|
| 1.0.0 | 2024-12-27 | Initial specification |
An implementation is conforming if it:
- Correctly encodes all valid component combinations
- Correctly decodes all valid addresses
- Passes all test vectors in Section 7
- Rejects or handles invalid inputs per Section 9
For holographic operations requiring higher precision than the 28-bit core format, see SPEC-EXTENDED.md.
The extended format provides:
- 64-bit addressing with 20-bit theta/phi resolution
- Phase angle support for wave interference calculations
- Backward-compatible truncation to 28-bit core addresses
This specification is released under CC BY 4.0. Attribution required.