Skip to main content

qualia_core_db/render/
standpoint.rs

1//! Human-Centric observer standpoint — the chosen context and right to perceive
2//! (decoupled from the camera lens; no hardware fingerprinting).
3
4use crate::q_hash;
5use crate::render::telemetry::{
6    ObserverStandpoint, DEONTIC_LANE_BILATERAL, DEONTIC_LANE_COMMONS, FABRIC_VIEWPORT_LOCAL,
7    STANDPOINT_DID, STANDPOINT_EPHEMERAL, STANDPOINT_SPECTATOR, STANDPOINT_VAULT,
8};
9
10/// Cryptographic-quality session nonce for ephemeral standpoint hashing (no fingerprinting).
11#[inline]
12pub fn generate_session_nonce() -> u64 {
13    let mut buf = [0u8; 8];
14    if getrandom::fill(&mut buf).is_err() {
15        let fallback = std::time::SystemTime::now()
16            .duration_since(std::time::UNIX_EPOCH)
17            .map(|d| d.as_nanos() as u64)
18            .unwrap_or(0);
19        buf = fallback.to_le_bytes();
20    }
21    u64::from_le_bytes(buf)
22}
23
24/// Untethered commons spectator — read-only, q = 1.0, ViewportLocal telemetry only.
25#[inline]
26pub fn spectator_default(session_nonce: u64) -> ObserverStandpoint {
27    let hash = q_hash("q42:observer:ephemeral") ^ session_nonce;
28    ObserverStandpoint::new(
29        hash,
30        session_nonce,
31        STANDPOINT_SPECTATOR,
32        1.0,
33        0.5,
34        1.0,
35        DEONTIC_LANE_COMMONS,
36        FABRIC_VIEWPORT_LOCAL,
37    )
38}
39
40/// Ephemeral session upgraded from spectator (still local-only until DID bind).
41#[inline]
42pub fn ephemeral_session(session_nonce: u64) -> ObserverStandpoint {
43    let hash = q_hash("q42:observer:session") ^ session_nonce;
44    ObserverStandpoint::new(
45        hash,
46        session_nonce,
47        STANDPOINT_EPHEMERAL,
48        1.0,
49        0.5,
50        1.0,
51        DEONTIC_LANE_COMMONS,
52        FABRIC_VIEWPORT_LOCAL,
53    )
54}
55
56/// Verified identifier standpoint — fabric gate opens when caller supplies a non-zero DID hash.
57#[inline]
58pub fn identifier_standpoint(
59    did_hash: u64,
60    session_nonce: u64,
61    epistemic_q: f32,
62) -> ObserverStandpoint {
63    ObserverStandpoint::new(
64        did_hash,
65        session_nonce,
66        STANDPOINT_DID,
67        epistemic_q.clamp(0.0, 1.0),
68        0.5,
69        1.0,
70        DEONTIC_LANE_COMMONS,
71        FABRIC_VIEWPORT_LOCAL,
72    )
73}
74
75/// Private vault slice collapse — bilateral lane, narrow epistemic aperture.
76#[inline]
77pub fn vault_standpoint(vault_hash: u64, session_nonce: u64) -> ObserverStandpoint {
78    ObserverStandpoint::new(
79        vault_hash,
80        session_nonce,
81        STANDPOINT_VAULT,
82        0.0,
83        0.5,
84        0.05,
85        DEONTIC_LANE_BILATERAL,
86        FABRIC_VIEWPORT_LOCAL,
87    )
88}
89
90/// Resolve standpoint hash from optional identifier IRI (empty → ephemeral session hash).
91#[inline]
92pub fn resolve_standpoint_hash(
93    standpoint_class: u32,
94    session_nonce: u64,
95    identifier_did: &str,
96) -> u64 {
97    if identifier_did.is_empty() {
98        return match standpoint_class {
99            STANDPOINT_EPHEMERAL => q_hash("q42:observer:session") ^ session_nonce,
100            STANDPOINT_VAULT => q_hash("q42:observer:vault") ^ session_nonce,
101            _ => q_hash("q42:observer:ephemeral") ^ session_nonce,
102        };
103    }
104    q_hash(identifier_did)
105}
106
107#[cfg(test)]
108mod tests {
109    use super::*;
110
111    #[test]
112    fn spectator_hash_is_deterministic_for_nonce() {
113        let a = spectator_default(42);
114        let b = spectator_default(42);
115        assert_eq!(a.standpoint_hash, b.standpoint_hash);
116        assert_eq!(a.standpoint_class, STANDPOINT_SPECTATOR);
117        assert_eq!(a.epistemic_q, 1.0);
118    }
119
120    #[test]
121    fn identifier_standpoint_uses_supplied_hash() {
122        let did = q_hash("did:example:alice");
123        let sp = identifier_standpoint(did, 7, 0.8);
124        assert_eq!(sp.standpoint_hash, did);
125        assert_eq!(sp.standpoint_class, STANDPOINT_DID);
126    }
127}