build(agent): weasel-1#856f80 iteration
This commit is contained in:
parent
81bfb5aa92
commit
85eb8e024b
|
|
@ -0,0 +1,59 @@
|
||||||
|
"""DTN custody header and simple custody policy helpers.
|
||||||
|
|
||||||
|
This module provides a minimal CustodyHeader dataclass used by DTN custody
|
||||||
|
holders to make decisions about storing/transferring PlanDelta payloads.
|
||||||
|
It also exposes a small helper that decides whether to accept custody based
|
||||||
|
on priority, remaining lifetime, and a node reputation score.
|
||||||
|
|
||||||
|
The implementation is intentionally small and deterministic for unit testing.
|
||||||
|
"""
|
||||||
|
from dataclasses import dataclass, field
|
||||||
|
from typing import List
|
||||||
|
import time
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class CustodyHeader:
|
||||||
|
delta_id: str
|
||||||
|
created_at: float = field(default_factory=time.time)
|
||||||
|
lifetime_secs: int = 3600 # how long the custody is expected to be valid
|
||||||
|
custody_chain: List[str] = field(default_factory=list)
|
||||||
|
priority_key: int = 0 # combined urgency/impact key (0..127)
|
||||||
|
|
||||||
|
def is_expired(self, now: float = None) -> bool:
|
||||||
|
if now is None:
|
||||||
|
now = time.time()
|
||||||
|
return now > (self.created_at + self.lifetime_secs)
|
||||||
|
|
||||||
|
def add_holder(self, node_id: str):
|
||||||
|
# append to custody chain (no dedupe to keep deterministic append-only)
|
||||||
|
self.custody_chain.append(node_id)
|
||||||
|
|
||||||
|
|
||||||
|
def should_accept_custody(header: CustodyHeader, node_reputation: float, min_reputation: float = 0.2) -> bool:
|
||||||
|
"""Decide whether a node should accept custody for a delta.
|
||||||
|
|
||||||
|
Decision factors (simple heuristic):
|
||||||
|
- If the header is already expired, refuse custody.
|
||||||
|
- Prefer accepting higher priority_key values.
|
||||||
|
- Gate acceptance by a minimum reputation threshold.
|
||||||
|
|
||||||
|
Returns True if the node should accept custody.
|
||||||
|
"""
|
||||||
|
if header.is_expired():
|
||||||
|
return False
|
||||||
|
|
||||||
|
# Enforce a minimum reputation gate: nodes below min_reputation refuse custody
|
||||||
|
if node_reputation < min_reputation:
|
||||||
|
return False
|
||||||
|
|
||||||
|
# decode urgency and impact from priority_key (urgency<<4)|impact
|
||||||
|
urgency = (header.priority_key >> 4) & 0x07
|
||||||
|
impact = header.priority_key & 0x0F
|
||||||
|
|
||||||
|
# compute a simple desirability score
|
||||||
|
score = urgency * 2 + impact + (node_reputation * 4)
|
||||||
|
|
||||||
|
# threshold depends on min_reputation; higher min_reputation raises bar
|
||||||
|
threshold = 5.0 + (1.0 - min_reputation) * 3.0
|
||||||
|
return score >= threshold
|
||||||
|
|
@ -0,0 +1,19 @@
|
||||||
|
from gravityweave.dtn import CustodyHeader, should_accept_custody
|
||||||
|
import time
|
||||||
|
|
||||||
|
|
||||||
|
def test_custody_header_and_expiry():
|
||||||
|
h = CustodyHeader(delta_id="d1", lifetime_secs=1)
|
||||||
|
assert not h.is_expired()
|
||||||
|
# wait for expiry
|
||||||
|
time.sleep(1.1)
|
||||||
|
assert h.is_expired()
|
||||||
|
|
||||||
|
|
||||||
|
def test_should_accept_custody():
|
||||||
|
# fresh header with medium priority
|
||||||
|
h = CustodyHeader(delta_id="d2", lifetime_secs=60, priority_key=(2 << 4) | 8)
|
||||||
|
# low reputation should often reject
|
||||||
|
assert not should_accept_custody(h, node_reputation=0.0, min_reputation=0.2)
|
||||||
|
# decent reputation should accept
|
||||||
|
assert should_accept_custody(h, node_reputation=0.8, min_reputation=0.2)
|
||||||
Loading…
Reference in New Issue