;;; spiral-client.lsp — demonstrate envelope teleport across two nodes. ;;; ;;; Flow: ;;; 1. Seed node A with EML theorems 1..3 ;;; 2. Seed node B with EML theorems 3..5 (theorem 3 overlaps) ;;; 3. Pre-spiral: A has 3 hashes, B has 3 hashes, 1 in common ;;; 4. Spiral A→B: B pulls A's envelope and merges ;;; 5. Spiral B→A: A pulls B's envelope and merges ;;; 6. Post-spiral: both nodes hold the union (5 unique hashes each) ;;; ;;; Proves that independent caches converge with one round-trip per ;;; direction. N nodes in a mesh converge after N-1 spiral passes. ;;; ;;; Usage (start both nodes first): ;;; python3 lumbda.py --fast examples/spiral-client.lsp (define *host* "127.0.0.1") (define *port-a* 9086) (define *port-b* 9087) ;;; ─── Canonical serializer ────────────────────────────────── (define (atom->string v) (cond ((number? v) (number->string v)) ((symbol? v) (symbol->string v)) ((null? v) "()") ((pair? v) (string-append "(" (list->str v) ")")) (else "?"))) (define (list->str lst) (cond ((null? lst) "") ((null? (cdr lst)) (atom->string (car lst))) (else (string-append (atom->string (car lst)) " " (list->str (cdr lst)))))) ;;; ─── Wire helpers ────────────────────────────────────────── (define (request port str) (let ((sock (tcp-connect *host* port))) (if sock (begin (tcp-send sock str) (let ((resp (tcp-recv sock 65536))) (tcp-close sock) (if resp resp "NO-RESPONSE"))) "NO-CONNECT"))) (define (prove port lhs rhs) (request port (string-append "(" (atom->string lhs) " " (atom->string rhs) ")"))) (define (parse-envelope resp) (let ((form (read-from-string resp))) (if (and (pair? form) (eqv? (car form) 'envelope) (pair? (cdr form))) (car (cdr form)) '()))) (define (count-list form n) (if (pair? form) (count-list (cdr form) (+ n 1)) n)) (define (envelope-of port) (parse-envelope (request port "(envelope)"))) (define (hashes->string lst acc) (if (null? lst) acc (hashes->string (cdr lst) (string-append acc (number->string (car lst)) " ")))) (define (merge-into port hashes) (request port (string-append "(merge (" (hashes->string hashes "") "))"))) ;;; ─── Report helpers ──────────────────────────────────────── (define (report-sizes label) (let ((a (envelope-of *port-a*)) (b (envelope-of *port-b*))) (display label) (display " A=") (display (count-list a 0)) (display " B=") (display (count-list b 0)) (newline))) ;;; ─── Run ─────────────────────────────────────────────────── (display "spiral demo across nodes A:") (display *port-a*) (display " and B:") (display *port-b*) (newline) (newline) (display "seeding node A (theorems 1..3)") (newline) (prove *port-a* '(eml ?x 1) '(exp ?x)) (prove *port-a* '(eml 1 1) '(exp 1)) (prove *port-a* '(eml 1 (eml (eml 1 ?x) 1)) '(ln ?x)) (display "seeding node B (theorems 3..5 — overlap on #3)") (newline) (prove *port-b* '(eml 1 (eml (eml 1 ?x) 1)) '(ln ?x)) (prove *port-b* '(eml 1 (eml (eml 1 1) 1)) 0) (prove *port-b* '(eml (ln ?a) (exp ?b)) '(- ?a ?b)) (newline) (report-sizes "pre-spiral ") (display "spiral A → B (B pulls A's envelope and merges)") (newline) (display " B: ") (display (merge-into *port-b* (envelope-of *port-a*))) (display "spiral B → A (A pulls B's envelope and merges)") (newline) (display " A: ") (display (merge-into *port-a* (envelope-of *port-b*))) (newline) (report-sizes "post-spiral ") (newline) (display "done") (newline)