Add Fleet Torrent erasure extension with shard DHT and gossip.
Some checks failed
CI Docker Mining Proof / Linux agent hashrate proof (push) Has been cancelled
Some checks failed
CI Docker Mining Proof / Linux agent hashrate proof (push) Has been cancelled
Content-addressed shard DHT on seeder agents with subnet_primary_seeder election, cross-subnet fleet_torrent_gossip, BGP swarm magnets, C2 torrent manifest, and k-of-n peer fetch with C2 fallback.
This commit is contained in:
172
server/internal/db/oath_ledger.go
Normal file
172
server/internal/db/oath_ledger.go
Normal file
@@ -0,0 +1,172 @@
|
||||
package db
|
||||
|
||||
import (
|
||||
"crypto/sha256"
|
||||
"encoding/hex"
|
||||
"encoding/json"
|
||||
"time"
|
||||
)
|
||||
|
||||
// Oath action types — immutable accountability rows.
|
||||
const (
|
||||
OathSpreadTierEscalation = "spread_tier_escalation"
|
||||
OathGraft = "graft"
|
||||
OathForkMerge = "fork_merge"
|
||||
OathStrainCardPlay = "strain_card_play"
|
||||
OathCourtL4Decision = "court_l4_decision"
|
||||
OathSpreadAttempt = "spread_attempt"
|
||||
OathStrainHospice = "strain_hospice"
|
||||
)
|
||||
|
||||
// Oath outcomes.
|
||||
const (
|
||||
OathOutcomeSuccess = "success"
|
||||
OathOutcomeFail = "fail"
|
||||
OathOutcomePending = "pending"
|
||||
)
|
||||
|
||||
// OathLedgerEntry is one immutable operator / AI council accountability row.
|
||||
type OathLedgerEntry struct {
|
||||
ID int64 `json:"id"`
|
||||
Timestamp string `json:"timestamp"`
|
||||
Actor string `json:"actor"`
|
||||
ActionType string `json:"action_type"`
|
||||
AgentID string `json:"agent_id"`
|
||||
Strain string `json:"strain"`
|
||||
WhyHash string `json:"why_hash"`
|
||||
Outcome string `json:"outcome"`
|
||||
PayloadJSON json.RawMessage `json:"payload_json"`
|
||||
}
|
||||
|
||||
func (d *Database) ensureOathLedgerTable() error {
|
||||
_, err := d.Exec(`CREATE TABLE IF NOT EXISTS oath_ledger (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
timestamp DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
actor TEXT NOT NULL DEFAULT '',
|
||||
action_type TEXT NOT NULL,
|
||||
agent_id TEXT NOT NULL DEFAULT '',
|
||||
strain TEXT NOT NULL DEFAULT '',
|
||||
why_hash TEXT NOT NULL DEFAULT '',
|
||||
outcome TEXT NOT NULL DEFAULT 'pending',
|
||||
payload_json TEXT NOT NULL DEFAULT '{}'
|
||||
)`)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, _ = d.Exec(`CREATE INDEX IF NOT EXISTS idx_oath_ledger_ts ON oath_ledger(timestamp)`)
|
||||
_, _ = d.Exec(`CREATE INDEX IF NOT EXISTS idx_oath_ledger_action ON oath_ledger(action_type)`)
|
||||
return nil
|
||||
}
|
||||
|
||||
// HashWhyJSON returns SHA256 hex of JSON-encoded source evidence (autopsy / court transcript).
|
||||
func HashWhyJSON(source interface{}) string {
|
||||
if source == nil {
|
||||
return ""
|
||||
}
|
||||
raw, err := json.Marshal(source)
|
||||
if err != nil {
|
||||
raw = []byte("{}")
|
||||
}
|
||||
sum := sha256.Sum256(raw)
|
||||
return hex.EncodeToString(sum[:])
|
||||
}
|
||||
|
||||
func marshalOathPayload(payload interface{}) []byte {
|
||||
if payload == nil {
|
||||
return []byte("{}")
|
||||
}
|
||||
switch v := payload.(type) {
|
||||
case json.RawMessage:
|
||||
if len(v) == 0 {
|
||||
return []byte("{}")
|
||||
}
|
||||
return v
|
||||
case map[string]interface{}:
|
||||
raw, err := json.Marshal(v)
|
||||
if err != nil {
|
||||
return []byte("{}")
|
||||
}
|
||||
return raw
|
||||
default:
|
||||
raw, err := json.Marshal(payload)
|
||||
if err != nil {
|
||||
return []byte("{}")
|
||||
}
|
||||
return raw
|
||||
}
|
||||
}
|
||||
|
||||
// InsertOathLedger appends one immutable accountability row.
|
||||
func (d *Database) InsertOathLedger(actor, actionType, agentID, strain, whyHash, outcome string, payload interface{}) (*OathLedgerEntry, error) {
|
||||
if d == nil {
|
||||
return nil, nil
|
||||
}
|
||||
if err := d.ensureOathLedgerTable(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if outcome == "" {
|
||||
outcome = OathOutcomePending
|
||||
}
|
||||
payloadJSON := marshalOathPayload(payload)
|
||||
ts := time.Now().UTC()
|
||||
res, err := d.Exec(
|
||||
`INSERT INTO oath_ledger (timestamp, actor, action_type, agent_id, strain, why_hash, outcome, payload_json)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?)`,
|
||||
ts, actor, actionType, agentID, strain, whyHash, outcome, string(payloadJSON),
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
id, _ := res.LastInsertId()
|
||||
return &OathLedgerEntry{
|
||||
ID: id,
|
||||
Timestamp: ts.Format(time.RFC3339),
|
||||
Actor: actor,
|
||||
ActionType: actionType,
|
||||
AgentID: agentID,
|
||||
Strain: strain,
|
||||
WhyHash: whyHash,
|
||||
Outcome: outcome,
|
||||
PayloadJSON: json.RawMessage(payloadJSON),
|
||||
}, nil
|
||||
}
|
||||
|
||||
// ListOathLedger returns recent rows newest-first.
|
||||
func (d *Database) ListOathLedger(limit int) ([]OathLedgerEntry, error) {
|
||||
if d == nil {
|
||||
return nil, nil
|
||||
}
|
||||
if err := d.ensureOathLedgerTable(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if limit <= 0 {
|
||||
limit = 100
|
||||
}
|
||||
if limit > 500 {
|
||||
limit = 500
|
||||
}
|
||||
rows, err := d.Query(
|
||||
`SELECT id, timestamp, actor, action_type, agent_id, strain, why_hash, outcome, payload_json
|
||||
FROM oath_ledger ORDER BY id DESC LIMIT ?`,
|
||||
limit,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
var out []OathLedgerEntry
|
||||
for rows.Next() {
|
||||
var e OathLedgerEntry
|
||||
var ts time.Time
|
||||
var payloadStr string
|
||||
if err := rows.Scan(&e.ID, &ts, &e.Actor, &e.ActionType, &e.AgentID, &e.Strain, &e.WhyHash, &e.Outcome, &payloadStr); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
e.Timestamp = ts.UTC().Format(time.RFC3339)
|
||||
if payloadStr != "" {
|
||||
e.PayloadJSON = json.RawMessage(payloadStr)
|
||||
}
|
||||
out = append(out, e)
|
||||
}
|
||||
return out, rows.Err()
|
||||
}
|
||||
54
server/internal/db/oath_ledger_test.go
Normal file
54
server/internal/db/oath_ledger_test.go
Normal file
@@ -0,0 +1,54 @@
|
||||
package db
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestOathLedgerRoundTrip(t *testing.T) {
|
||||
d, err := New(t.TempDir())
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer d.Close()
|
||||
|
||||
why := map[string]string{"tier": "dns_txt", "lane": "spread"}
|
||||
hash := HashWhyJSON(why)
|
||||
entry, err := d.InsertOathLedger(
|
||||
"operator", OathSpreadTierEscalation, "agent-1", "#aabbcc", hash, OathOutcomeSuccess,
|
||||
map[string]string{"command_type": "reorder_tiers"},
|
||||
)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if entry == nil || entry.ID == 0 {
|
||||
t.Fatalf("expected inserted entry, got %+v", entry)
|
||||
}
|
||||
if entry.WhyHash != hash {
|
||||
t.Fatalf("why_hash = %q want %q", entry.WhyHash, hash)
|
||||
}
|
||||
|
||||
rows, err := d.ListOathLedger(10)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if len(rows) != 1 {
|
||||
t.Fatalf("rows = %+v", rows)
|
||||
}
|
||||
if rows[0].ActionType != OathSpreadTierEscalation || rows[0].Actor != "operator" {
|
||||
t.Fatalf("unexpected row: %+v", rows[0])
|
||||
}
|
||||
}
|
||||
|
||||
func TestHashWhyJSONStable(t *testing.T) {
|
||||
src := map[string]interface{}{"verdict": "retry spread", "clearance": 4}
|
||||
h1 := HashWhyJSON(src)
|
||||
h2 := HashWhyJSON(src)
|
||||
if h1 == "" || h1 != h2 {
|
||||
t.Fatalf("hash unstable: %q %q", h1, h2)
|
||||
}
|
||||
if len(h1) != 64 {
|
||||
t.Fatalf("expected sha256 hex length 64, got %d", len(h1))
|
||||
}
|
||||
_, _ = json.Marshal(src)
|
||||
}
|
||||
Reference in New Issue
Block a user