artdag: DAG wire serialization — portable record form + integrity + 13 tests
Some checks failed
Test, Build, and Deploy / test-build-deploy (push) Failing after 50s
Some checks failed
Test, Build, and Deploy / test-build-deploy (push) Failing after 50s
serialize.sx emits a topo-ordered (id op inputs params commutative) record list that survives write/read (string-keyed node dicts do not; empty inputs read back as nil and are normalized). wire->dag reconstructs a runnable dag by content-id; wire-verify recomputes ids to reject tampering. dag->string/string->dag for text transport. serialize 13/13, total 128/128. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
62
lib/artdag/serialize.sx
Normal file
62
lib/artdag/serialize.sx
Normal file
@@ -0,0 +1,62 @@
|
||||
; lib/artdag/serialize.sx — portable wire form for whole DAGs, so a peer can
|
||||
; receive and run a graph it did not author. The form is a topo-ordered list of
|
||||
; node records (id op inputs params commutative) — plain lists with keyword-keyed
|
||||
; param dicts, which survive write/read (unlike string-keyed node dicts). The id
|
||||
; is the content-id, so the form is self-verifying. Depends on dag.sx.
|
||||
|
||||
(define
|
||||
artdag/node->record
|
||||
(fn
|
||||
(dag id)
|
||||
(let
|
||||
((n (artdag/dag-get dag id)))
|
||||
(list
|
||||
id
|
||||
(artdag/node-op n)
|
||||
(artdag/node-inputs n)
|
||||
(artdag/node-params n)
|
||||
(get n :commutative)))))
|
||||
|
||||
; dag -> list of records, in topological order.
|
||||
(define
|
||||
artdag/dag->wire
|
||||
(fn
|
||||
(dag)
|
||||
(map (fn (id) (artdag/node->record dag id)) (artdag/dag-order dag))))
|
||||
|
||||
; an empty input list reads back as nil; normalize it.
|
||||
(define
|
||||
artdag/-rec-inputs
|
||||
(fn (rec) (let ((i (nth rec 2))) (if (nil? i) (list) i))))
|
||||
|
||||
(define artdag/-rec->node (fn (rec) {:inputs (artdag/-rec-inputs rec) :commutative (nth rec 4) :op (nth rec 1) :params (nth rec 3)}))
|
||||
|
||||
; records -> dag. Local author names are not part of the wire form; the receiver
|
||||
; works by content-id. :names is left empty.
|
||||
(define
|
||||
artdag/wire->dag
|
||||
(fn
|
||||
(records)
|
||||
(reduce
|
||||
(fn (dag rec) (let ((id (nth rec 0))) {:names (get dag :names) :order (concat (get dag :order) (list id)) :ok true :nodes (assoc (get dag :nodes) id (artdag/-rec->node rec))}))
|
||||
{:names {} :order (list) :ok true :nodes {}}
|
||||
records)))
|
||||
|
||||
; integrity: each record's id must equal the content-id recomputed from its spec.
|
||||
(define
|
||||
artdag/wire-verify
|
||||
(fn
|
||||
(records)
|
||||
(every?
|
||||
(fn
|
||||
(rec)
|
||||
(= (nth rec 0) (artdag/content-id (artdag/-rec->node rec))))
|
||||
records)))
|
||||
|
||||
; string transport.
|
||||
(define
|
||||
artdag/dag->string
|
||||
(fn (dag) (write-to-string (artdag/dag->wire dag))))
|
||||
(define
|
||||
artdag/string->dag
|
||||
(fn (s) (artdag/wire->dag (read (open-input-string s)))))
|
||||
Reference in New Issue
Block a user