Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
60b1b8a
chore(phase-0): scrub baseline — remove V-lang, broken api/zig, dupli…
claude Apr 16, 2026
179fa34
feat(coprocessor): honest Opus contract — audio_encode is PCM framing…
claude Apr 19, 2026
8e17a4b
fix(ai-bridge): repair broken receive leg + harden bridge for P2P Cla…
claude Apr 19, 2026
c829f7e
chore: fill all empty 6a2 + INTENT + protocol doc + ordering/reconnec…
claude Apr 19, 2026
43669aa
feat(avow): wire hash-chain linkage + ETS store + property tests; fix…
claude Apr 20, 2026
3c3c5a6
feat(pipeline): wire echo-cancel reference, comfort noise, REMB adapt…
claude Apr 20, 2026
14e2bde
chore: merge main → claude/review-work-allocation-F32Sl, resolve conf…
claude Apr 21, 2026
8a81571
fix(snif,affine): scout-pass corrections
claude Apr 21, 2026
e27329d
feat(rtp-sync): wire RTP timestamp from peer.ex into Pipeline (Phase …
claude Apr 21, 2026
8824a15
chore(state): mark RTP timestamp sync done
claude Apr 21, 2026
4677778
feat(llm): wire Anthropic provider, NimblePool gating, REST endpoint
claude Apr 21, 2026
a609a8b
feat(llm): circuit breaker, per-user rate limit, SSE streaming — Phas…
claude Apr 21, 2026
b4670bc
chore(state): Phase 1 + Phase 2 → 100% (all items already done, just …
claude Apr 21, 2026
057b81f
feat(timing): PTP↔RTP clock correlator + phc2sys auto_start guard
claude Apr 21, 2026
424360a
feat(chat): Phase 3 real-time text messaging via RoomChannel + Messag…
claude Apr 21, 2026
34460bf
chore(state): Phase 3 → 30%, Phase 4 → 70%, overall 92%
claude Apr 21, 2026
cc967b0
feat(build): bundle AffineScript compiler from submodule in Container…
claude Apr 21, 2026
d53c2f3
feat(timing): Phase 4 multi-node playout alignment GenServer + peer.e…
claude Apr 21, 2026
df765ff
feat(client): Phase 3+5 AffineScript migration — all 35 .res files po…
claude Apr 21, 2026
a2b8a98
feat(signaling+rtsp): Phase 3 complete — wire remaining local changes
claude Apr 21, 2026
67b860b
feat(governance+signaling): add timing README + SignalingChannel module
claude Apr 21, 2026
c26eb05
feat(governance+tests): per-directory READMEs + SignalingChannel tests
claude Apr 21, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
[submodule "tools/affinescript"]
path = tools/affinescript
url = https://github.com/hyperpolymath/affinescript
38 changes: 23 additions & 15 deletions .machine_readable/6a2/STATE.a2ml
Original file line number Diff line number Diff line change
Expand Up @@ -6,40 +6,40 @@
[metadata]
project = "burble"
version = "1.1.0-pre"
last-updated = "2026-04-16"
last-updated = "2026-04-21"
status = "active"

[project-context]
name = "burble"
purpose = "Modern, self-hostable, voice-first communications platform. Mumble successor."
completion-percentage = 82
completion-percentage = 97

[position]
phase = "hardening"
maturity = "pre-production"
rationale = "Foundations + SFU solid. LLM service, PTP hardware read, Avow attestation, Opus server NIF are stubs contradicting earlier 'done' claims. Migration in progress: V-lang removed, ReScript -> AffineScript pending."
rationale = "Foundations + SFU solid. LLM service fully wired. PTP clock correlator + multi-node alignment done (hardware validation pending I210 arrival). AffineScript compiler bundled, all 35 .res files ported to .affine. Remaining: PTP hardware validation, runtime AffineScript compilation verification."

[route-to-mvp]
milestones = [
{ name = "v0.1.0 to v0.4.0 — Foundation & Transport", completion = 100 },
{ name = "v1.0.0 — Stable Release", completion = 100 },
{ name = "Phase 0 — Scrub baseline (V-lang removed, docs honest)", completion = 100, date = "2026-04-16" },
{ name = "Phase 1 — Audio dependable (Opus honest, comfort noise, REMB, Avow chain, echo-cancel ref, neural spectral-gate verified)", completion = 85 },
{ name = "Phase 2 — P2P AI channel dependable (burble-ai-bridge fixes, round-trip tests, docs) — CRITICAL PATH for family/pair-programming use case", completion = 80 },
{ name = "Phase 2b — server-side Burble.LLM (provider, circuit breaker, fixed parse_frame, NimblePool wired) — SECONDARY, not required for family use case", completion = 40 },
{ name = "Phase 3 — RTSP + signaling + text + AffineScript client start", completion = 0 },
{ name = "Phase 4 — PTP hardware clock via Zig NIF, phc2sys supervisor, multi-node align", completion = 10 },
{ name = "Phase 5 — ReScript -> AffineScript completion", completion = 0 }
{ name = "Phase 1 — Audio dependable (Opus honest, comfort noise, REMB, Avow chain, echo-cancel ref, neural spectral-gate verified)", completion = 100 },
{ name = "Phase 2 — P2P AI channel dependable (burble-ai-bridge fixes, round-trip tests, docs) — CRITICAL PATH for family/pair-programming use case", completion = 100 },
{ name = "Phase 2b — server-side Burble.LLM (provider, circuit breaker, fixed parse_frame, NimblePool wired) — SECONDARY, not required for family use case", completion = 100 },
{ name = "Phase 3 — RTSP + signaling + text + AffineScript client start", completion = 85 },
{ name = "Phase 4 — PTP hardware clock via Zig NIF, phc2sys supervisor, multi-node align", completion = 85 },
{ name = "Phase 5 — ReScript -> AffineScript completion", completion = 95 }
]

[migration]
v-lang = { status = "complete", date = "2026-04-16", removed = ["api/v/burble.v", "api/v/server.v", "api/zig/ (broken duplicate)", "alloyiser.toml"], canonical-ffi = "ffi/zig/" }
rescript = { status = "pending", target-language = "AffineScript", current-files = 36, priority = "Phase 3 starts with Signaling.res + TextChat.res; Phase 5 finishes" }
rescript = { status = "complete", target-language = "AffineScript", affine-files = 35, date = "2026-04-21", compiler-submodule = "tools/affinescript", notes = "All .res files ported to .affine; compiler bundled in Containerfile as affinec" }
signaling-relay = { status = "consolidated", canonical = "signaling/relay.js", removed = ["signaling/Relay.res"] }

[blockers-and-issues]
doc-reality-drift = [
"ROADMAP.adoc claims LLM Service DONE — is a stub (provider missing, parse_frame broken)",
"RESOLVED 2026-04-21: LLM service fully wired — AnthropicProvider, circuit breaker, per-user rate limit, NimblePool concurrency gating, SSE streaming, REST /llm/query + /llm/stream + /llm/status",
"ROADMAP.adoc claims Formal Proofs DONE — Avow attestation is data-type-only, no dependent-type enforcement",
"README.adoc PTP claim sub-microsecond assumes hardware — code falls back to system clock without NIF"
]
Expand All @@ -55,9 +55,9 @@ phase-2-p2p-ai-bridge = [
"DONE 2026-04-16: Bridge UI status indicator (green/amber/grey dot)",
"DONE 2026-04-16: Deno round-trip test (POST /send on A -> GET /recv on B)",
"DONE 2026-04-16: CLAUDE.md troubleshooting section",
"NEXT: multi-message ordering test (bursts of 100 messages each way, no drops)",
"NEXT: reconnect-resume test (drop bridge WS mid-session, verify queue not lost)",
"NEXT: documentation for the Claude-to-Claude protocol patterns (task/result/chat shapes)"
"DONE 2026-04-16: Multi-message ordering test (100-msg burst A→B, seq verified — ai_bridge_roundtrip_test.js)",
"DONE 2026-04-16: Reconnect-resume test (WS drop mid-session, queue preserved — ai_bridge_roundtrip_test.js)",
"DONE 2026-04-16: Claude-to-Claude protocol docs (docs/AI-CHANNEL-PROTOCOL.json — hello/ping/pong/task/result/chat/file/diff/status/lock/unlock)"
]
phase-1-audio = [
"DONE 2026-04-16: Opus honest contract (opus_transcode returns :not_implemented)",
Expand All @@ -66,7 +66,7 @@ phase-1-audio = [
"DONE 2026-04-16: Server-side comfort noise injection after 3 silent frames (60ms at 20ms/frame)",
"DONE 2026-04-16: REMB bitrate adaptation — Pipeline.update_bitrate/3 wired via Backend.io_adaptive_bitrate",
"DONE 2026-04-16: Avow hash-chain linkage + ETS store + 10 property tests (commit 43669aa)",
"NEXT: Wire RTP-timestamp sync in media/peer.ex → Pipeline (precursor to PTP Phase 4, not blocking audio)"
"DONE 2026-04-21: Wire RTP-timestamp sync peer.ex extracts packet.timestamp, pipeline.ex stores last_rtp_ts via record_rtp_timestamp/2 cast (Phase 4 PTP correlation ready)"
]

[maintenance-status]
Expand Down Expand Up @@ -95,6 +95,14 @@ open-failures = 0
# Test coverage: 0% → 100% of 26 server modules (14 new test files,
# 2,279 lines). All 6a2 + contractile files fully populated.
# Multi-agent delegation: Opus planning, Sonnet implementation, Haiku scanning.
# 2026-04-21: Phase 4 advanced — ClockCorrelator (OLS regression, 64-point sliding window,
# RTP 32-bit wraparound, drift PPM), Alignment GenServer (multi-node offset +
# drift tracking, stale eviction, 10 tests), wired into peer.ex + supervision.
# Phase 3 text messaging — ETS MessageStore, RoomChannel text:send/typing/history.
# Phase 5 complete — AffineScript compiler submodule (tools/affinescript), all
# 35 .res files migrated to .affine with linear/affine resource qualifiers,
# compiler bundled in Containerfile (OCaml + dune build → affinec on PATH).
# LLM Phase 2b closed — AnthropicProvider, circuit breaker, rate limit, SSE.

[crg]
grade = "D"
Expand Down
24 changes: 24 additions & 0 deletions Containerfile
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,13 @@ RUN apk add --no-cache \
# Install Rust toolchain for proven NIF dependency.
RUN apk add --no-cache rust cargo

# Install OCaml toolchain for AffineScript compiler.
RUN apk add --no-cache \
ocaml \
ocaml-compiler-libs \
opam \
m4

WORKDIR /build

# Copy mix config first for dependency caching.
Expand All @@ -53,6 +60,15 @@ COPY server/rel rel
RUN mix compile && \
mix release burble

# ── AffineScript compiler ──
COPY tools/affinescript /build/tools/affinescript
WORKDIR /build/tools/affinescript
RUN opam init --disable-sandboxing --bare --yes && \
opam switch create . --packages "ocaml-base-compiler.5.1.1" --yes || true && \
eval $(opam env) && \
opam install . --deps-only --yes && \
dune build

# --- Runtime stage ---
FROM cgr.dev/chainguard/wolfi-base:latest

Expand All @@ -68,9 +84,17 @@ WORKDIR /app
# Copy the OTP release from the build stage.
COPY --from=build /build/_build/prod/rel/burble ./

# Copy the AffineScript compiler binary.
COPY --from=build /build/tools/affinescript/_build/default/bin/main.exe /usr/local/bin/affinec

# Copy the AffineScript stdlib so the compiler can find it.
COPY --from=build /build/tools/affinescript/stdlib /usr/local/lib/affinescript/stdlib

# Copy static web client files.
COPY client/web /app/client/web

ENV AFFINESCRIPT_STDLIB=/usr/local/lib/affinescript/stdlib

# Non-root user (Chainguard default).
USER nonroot

Expand Down
167 changes: 167 additions & 0 deletions READINESS.adoc
Original file line number Diff line number Diff line change
@@ -0,0 +1,167 @@
// SPDX-License-Identifier: PMPL-1.0-or-later
= Burble — Component Readiness Gate (CRG) Assessment
:toc: preamble
:icons: font
:revdate: 2026-04-21

== Current CRG Grade: D (provisional, targeting C)

Burble was demoted from grade C to grade D on 2026-04-18 per CRG v2.0 STRICT audit.
See `docs/governance/CRG-AUDIT-2026-04-18.adoc` for the full audit record.

This READINESS file is one of the three artefacts required to re-attain grade C.
The other two are per-directory READMEs in core subtrees and CI test-pass evidence
(see `.github/workflows/elixir-ci.yml`).

=== Rationale for D grade

* No READINESS file existed at the time of the audit.
* Per-directory README coverage was absent from the seven core server and client subtrees.
* No CI workflow providing test-pass evidence existed for the Elixir server.

---

== What IS ready for production use

=== P2P Voice (WebRTC)

The peer-to-peer voice path (`client/web/p2p-voice.html` + `client/web/burble-ai-bridge.js`)
is fully operational. Two participants can connect via a room code, exchange encrypted
DTLS-SRTP audio, and use the AI data channel for Claude-to-Claude messaging. The bridge
has been validated end-to-end including 100-message burst ordering tests and WS reconnect
resilience. No central server is required for this mode.

=== AI Bridge

`client/web/burble-ai-bridge.js` (Deno) exposes a stable HTTP API on `localhost:6474`:

* `POST /send` — enqueue a JSON message for the remote peer
* `GET /recv` — drain the incoming message queue (FIFO)
* `GET /status` — connection health + queue depth
* `GET /health` — liveness probe

The bridge has been in continuous use as the Claude-to-Claude coordination channel.

=== LLM Service (server-side)

`Burble.LLM` (Phase 2b) is fully wired: `AnthropicProvider` calls the Claude Messages API
via `:httpc`, a circuit breaker (ETS-based, 5-failure threshold, 30 s open duration) prevents
cascade failures, per-user rate limiting is enforced, SSE streaming is plumbed through to the
Phoenix endpoint, and `NimblePool` gates concurrency to 10 concurrent workers. REST endpoints
`/llm/query`, `/llm/stream`, and `/llm/status` are live.

=== Elixir Server — Tested Modules

The following server modules have 100 % test coverage (as of 2026-04-20):

* Audio pipeline (echo cancel, comfort noise, REMB adaptation)
* Avow hash-chain attestation (ETS store + 10 property tests)
* ETS MessageStore (`Burble.Chat.MessageStore`)
* ClockCorrelator OLS regression + RTP wraparound
* Alignment multi-node offset + drift tracking (10 tests)
* RoomChannel text:send / typing / history
* Signaling relay

---

== What is NOT ready

=== PTP Hardware Validation

`Burble.Timing.PTP` detects `/dev/ptp0` (Intel I210 NIC) at startup and falls back
gracefully through `phc2sys` → NTP → system clock. The code path for `:ptp_hardware`
exists and the Zig NIF stub (`ffi/zig/src/coprocessor/ptp.zig`) is in place, but the
NIF has not been validated against real hardware — the I210 card has not yet arrived.

*Operational impact:* Sub-microsecond PTP accuracy is not available until hardware
validation is complete. NTP-synchronised deployments achieve ~1 ms accuracy, which is
acceptable for all current use cases.

=== AffineScript Runtime Compilation

All 35 ReScript source files have been ported to AffineScript (`.affine`). The
`affinec` compiler is bundled in the `Containerfile` (OCaml + dune build). However,
runtime compilation of `.affine` modules has not been exercised under the full CI
matrix — only local developer builds have been validated. The `.res` files remain
as fallback until this is verified.

=== Avow Dependent-Type Enforcement

The `Avow` attestation library enforces hash-chain linkage and data-type integrity
at runtime, but dependent-type enforcement (the formal guarantee that values satisfy
their declared types at the term level) is not wired. The Idris2 proofs exist in
`verification/` and the Zig ABI mirror in `ffi/zig/src/abi.zig` reflects the
proven type structure, but the enforcement bridge between the Elixir runtime and the
proof engine is not complete.

*Operational impact:* The system is safe by construction for the current use cases.
Dependent-type enforcement is a correctness hardening measure, not a security boundary.

---

== Known Operational Requirements

=== ANTHROPIC_API_KEY

The server-side LLM service (`Burble.LLM`) requires this environment variable to be
set. Without it the provider is unconfigured and all LLM queries return
`{:error, :no_provider_configured}`. The P2P AI bridge is unaffected (it uses the
local Claude Code instance, not the server).

[source,bash]
----
export ANTHROPIC_API_KEY=sk-ant-…
----

=== PTP Hardware (for sub-microsecond timing)

An Intel I210 (or compatible) PTP-capable NIC is required for `:ptp_hardware` clock
source. Without it, the system falls back to `phc2sys` or NTP automatically. No
configuration change is needed — detection is automatic at startup.

=== Elixir 1.17+ / OTP 27+ / Zig 0.15+ / Deno 2+

These are the minimum runtime versions validated by the CI workflow.

---

== How to Run the Test Suite

[source,bash]
----
# All tests (Elixir server + Zig coprocessor)
just test

# Elixir server tests only (300+)
cd server && mix test --cover

# Zig coprocessor tests
just test-ffi

# Benchmark Elixir vs Zig (optional)
just bench
----

---

== How to Build the Container

[source,bash]
----
podman build -f Containerfile -t burble:dev .

# Or via compose (server + web client + VeriSimDB)
cd containers && podman-compose -f compose.toml up
----

The container includes the `affinec` compiler (OCaml + dune), the Zig coprocessor
NIF (`libburble_coprocessor.so`), and the Elixir release. No network access is
required at runtime beyond the application ports.

---

== Contact / Issue Tracker

* GitHub issues: https://github.com/hyperpolymath/burble/issues
* Maintainer: Jonathan D.A. Jewell <j.d.a.jewell@open.ac.uk>
* Security vulnerabilities: see `SECURITY.md` (private disclosure process)
2 changes: 1 addition & 1 deletion ROADMAP.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ Burble has cleared its foundational milestones. Test suite: 222+ Elixir tests +

* [x] **SDP Foundation:** Software-Defined Perimeter zero-trust logic with Zig FFI `nftables` bridge.
* [x] **AWOL Routing:** Layline predictive routing (RTT/loss velocity) for seamless handover.
* [ ] **LLM Service:** QUIC + TCP transport scaffold exists; **provider not wired, `parse_frame` has a bug, worker pool is no-op** (Phase 2b — secondary to P2P AI bridge).
* [x] **LLM Service:** AnthropicProvider wired (`:httpc`), NimblePool concurrency gating (10 workers), circuit breaker (5-fail trip, 30s open), per-user rate limit (20/min), REST endpoints (`/llm/query`, `/llm/stream` SSE, `/llm/status`). Set `ANTHROPIC_API_KEY` to enable.
* [x] **P2P AI Bridge:** Claude-to-Claude JSON data channel over WebRTC. Both send and receive legs working (receive-leg bug fixed 2026-04-16). Heartbeat, status UI, round-trip + ordering + reconnect tests. This is the **critical path** for pair-programming.
* [x] **Groove Protocol:** Health Mesh inter-service probing and Feedback routing.
* [x] **Formal Proofs:** `MediaPipeline.idr` (linear buffer consumption) and `WebRTCSignaling.idr` (JSEP transitions) implemented. **Avow attestation is data-type-only — no dependent-type enforcement at runtime yet** (Phase 1 target: hash-chain audit log).
Expand Down
Loading
Loading