lsp-max 26.7.3

Law-state LSP runtime: max LSP 3.18 coverage, process-mining conformance, receipt-chain admission
Documentation
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
# lsp-max Architecture

## Overview

**lsp-max** is a "law-state runtime projected through LSP" — a five-layer stack that enforces protocol-backed invariants at every boundary. Unlike plain tower-lsp (which is LSP *servers* for humans), lsp-max is LSP *for agents*, with the repository itself speaking back to agents through bounded receipts, conformance vectors, repair intents, and gate enforcement.

The five-layer model is **law-state as the load-bearing abstraction**:

```
Layer 5: Autonomic LSP Mesh (conformance, admission gates, repair)
Layer 4: Knowledge Hooks (composition, routing, capability tracking)
Layer 3: Law-State Runtime (typestate, phases, receipts, SHA256 chains)
Layer 2: Local LSP State Surface (LanguageServer trait, poll_ready, stdio/TCP)
Layer 1: Actuation Grammar (clap-noun-verb CLI: noun=filename, verb=action)
```

Each layer enforces invariants that make the next layer's claims trustworthy. No layer is passive; all are law-bearing.

---

## Layer 1: Actuation Grammar — clap-noun-verb CLI

**Crate**: `crates/lsp-max-cli`

**Entry point**: `main.rs` → `clap_noun_verb::run()`

### Purpose

The actuation grammar is the interface between agents and the law-state runtime. It is a **noun/verb command grammar** where:

- **Nouns** are filenames in `crates/lsp-max-cli/src/nouns/` (e.g., `server.rs`, `conformance.rs`, `state.rs`, `diagnostics.rs`)
- **Verbs** are `#[verb]` attributes on public methods within those nouns
- **Actions** are bounded and routed through the runtime's hook and receipt system

### Key Design

```rust
// Example: crates/lsp-max-cli/src/nouns/server.rs
#[verb]
pub async fn start(&self, host: String, port: u16) -> Result<ServerDetails> {
    // Fetch current mesh state, check gates, route through hooks, emit receipt
}
```

Each command:
1. Reads the current server state from the persistent mesh (JSON or embedded database)
2. Evaluates law gates (`gate.rs`) to determine if the action is lawful
3. Dispatches the action through the autonomic mesh (Layer 3)
4. Emits a receipt binding the action, its outcome, and the next state
5. Returns a result or error to the agent

### Invariant: Deterministic Actuation

**No state mutations occur without a receipt.**

- Mutations are staged in `Staging` before the `MutationGate` admits them
- The gate checks `Λ_CD(action)` — whether the action satisfies all law axes
- Only after gate admission is the mutation written to the persistent mesh
- The receipt binds: `action_id → outcome → next_state → SHA256(state_transition)`

### Nouns (Actuation Surface)

- **`server.rs`** — Lifecycle: `start`, `stop`, `reload`, `query`
- **`state.rs`** — Inspection: `state` (instance phase, conformance, diagnostics count)
- **`diagnostics.rs`** — Diagnostic manipulation: `diagnose`, `clear`, `run`, `list`
- **`conformance.rs`** — Conformance queries: `score`, `vector`, `delta`
- **`snapshot.rs`** — Snapshotting: `snapshot`, `restore`
- **`agent.rs`** — Agent integration: route analysis bundles, bound actions
- **`workspace.rs`** — Workspace inspection: list instances, query composition
- **`metamodel.rs`** — LSP 3.18 spec inspection: capabilities, methods, transcripts

### File Structure Invariant

Files stay ≤500 LOC; split into submodules matching the noun name:

```
crates/lsp-max-cli/src/nouns/
├── server.rs         (domain structs + service tier + verb handlers)
├── server/
│   ├── mod.rs        (impl details, private types)
│   └── ...
└── ...
```

---

## Layer 2: Local LSP State Surface

**Crates**: `src/` (root), `crates/lsp-max-client`

**Key types**: `LanguageServer` trait, `LspService`, `Server`, `Client`

### Purpose

Layer 2 is the **LSP protocol transport and method routing layer**. It handles:

1. **Transport**: stdio, TCP, loopback (in-process testing)
2. **Method registration**: via `LanguageServer` trait and `#[async_trait]`
3. **State machine**: `State` enum (Uninitialized → Initializing → Initialized → ShutDown → Exited)
4. **Lifecycle coordination**: `poll_ready`, request/response correlation, cancellation
5. **Message framing**: JSON-RPC 2.0 codec (Content-Length headers, async frames)

### Key Structures

#### LanguageServer Trait

```rust
#[lsp_max::async_trait]
pub trait LanguageServer {
    async fn initialize(&self, params: InitializeParams) -> Result<InitializeResult>;
    async fn initialized(&self, params: InitializedParams);
    async fn shutdown(&self) -> Result<()>;
    // ... 100+ standard LSP methods
    // ... custom max/* methods via router
}
```

The trait is object-safe; servers are boxed as `Box<dyn LanguageServer>`.

#### LspService

```rust
pub struct LspService<S: LanguageServer> {
    inner: layers::CatchUnwindService<Router<S, ExitedError>>,
    state: Arc<ServerState>,
}

impl<S: LanguageServer> Service<Request> for LspService<S> {
    fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
        // Returns Pending until initialization completes.
        // After Exited, returns Err(ExitedError).
    }

    fn call(&mut self, req: Request) -> Self::Future {
        // Routes req through method dispatch, returns future of Option<Response>
    }
}
```

**Key invariant**: `poll_ready` returns `Poll::Pending` while `State == Initializing`; the service cannot serve requests until the server finishes initialization.

#### Server (Transport Multiplexer)

```rust
pub struct Server<I, O, L = ClientSocket> {
    stdin: I,
    stdout: O,
    loopback: L,
    max_concurrency: usize,
}

impl<I, O, L> Server<I, O, L> {
    pub async fn serve<T: Service<Request>>(self, mut service: T) -> Result<(), T::Error> {
        // 1. Frame stdin via LanguageServerCodec (Content-Length headers)
        // 2. Multiplex N concurrent requests via buffer_unordered
        // 3. Route responses back through stdout frames
        // 4. Detect service exit via probe_exited and exit state
    }
}
```

The server is **transport-agnostic** — it works with any `AsyncRead`/`AsyncWrite`, including loopback channels for tests.

### Data Flow (Receive Path)

```
[Client] 
  ↓ (JSON-RPC 2.0 frame)
stdin → FramedRead::decode(Content-Length header + body)
  ↓
Server::serve() → LanguageServerCodec::decode()
  ↓
Request (method, params, id)
  ↓
Service::call(req)
  ↓
LanguageServer method dispatch (via Router)
  ↓
Handler method (async, on the backend struct)
```

### Data Flow (Send Path)

```
Handler returns Result<T>
  ↓
to_value(T) → serde_json::Value
  ↓
Response { id, result/error }
  ↓
Service returns Option<Response>
  ↓
Server::serve() queues Response
  ↓
FramedWrite::encode(Content-Length header + body)
  ↓
stdout → [Client]
```

### Invariants

1. **poll_ready is gating**: A service cannot receive requests until initialization succeeds.
2. **State is monotonic**: Uninitialized → Initializing → Initialized → ShutDown → Exited (no back-edges).
3. **stdout is for framing only**: No debug prints, logs, or diagnostic output on stdout — use `eprintln!` or `tracing` (stderr) instead.
4. **Method not found is silent**: `$/unknownMethod` errors are filtered and converted to `None` before returning.

---

## Layer 3: Law-State Runtime

**Crates**: `lsp-max-runtime`, `lsp-max-protocol`

**Key types**: `AutonomicMesh`, `MaxDiagnostic`, `ConformanceVector`, `Receipt`, `TypestateKernel`

### Purpose

Layer 3 is the **proof system and state machine**. It:

1. **Enforces law invariants** through gate evaluation (`Λ_CD`)
2. **Tracks phases** via a typestate machine (Uninitialized, Initializing, Initialized, ShutDown, Exited)
3. **Records transitions** with SHA256-signed receipts binding (from_state → action → to_state)
4. **Maintains conformance deltas** as a ring-buffer log for `max/conformanceDelta` polling
5. **Routes diagnostics and repairs** through a composable hook system

### The Autonomic Mesh

```rust
pub struct AutonomicMesh {
    instances: HashMap<InstanceId, LspInstance>,
    hooks: Vec<Box<dyn Hook>>,
    events: Vec<HookEvent>,  // Ring buffer, capped at 1000 entries
    conformance_delta_log: VecDeque<ConformanceDeltaEntry>,
}

impl AutonomicMesh {
    pub fn dispatch_rpc(
        &mut self,
        instance_id: &str,
        method: &str,
        params: Value,
    ) -> Result<Value, String> {
        // 1. Create HookEvent from (method, params)
        // 2. Dispatch through hook chain
        // 3. Apply MeshActions returned by hooks
        // 4. Update instance state (diagnostics, receipts, phase)
        // 5. Return result or error
    }

    pub fn register_hook(&mut self, hook: Box<dyn Hook>) {
        self.hooks.push(hook);
    }
}
```

### Hook System (Composition Filter Pipeline)

Hooks intercept method calls and emit actions:

```rust
pub trait Hook: Send + Sync {
    fn name(&self) -> &'static str;
    fn descriptor(&self) -> HookDescriptor;
    
    fn on_event(&self, event: &HookEvent) -> Vec<MeshAction>;
}

pub enum MeshAction {
    RegisterDiagnostic(MaxDiagnostic),
    ClearDiagnostic(String),           // diagnostic_id
    TransitionPhase(LspPhase),
    EmitReceipt(Receipt),
    UpdateConformanceScore(f64),
}
```

### Standard Hooks (Built During Mesh Construction)

1. **`IntakeDiagnosticHook`** — Routes `max/diagnostic` calls into the registry
2. **`IntakeClearHook`** — Routes `max/clear` calls to remove diagnostics
3. **`CustomerRequestClassifierHook`** — Categorizes method calls (request, notification, custom)
4. **`PolicyEvaluationHook`** — Evaluates gate conditions; emits phase transitions
5. **`ReceiptRoutingHook`** — Binds transitions to SHA256-signed receipts
6. **`OcelProcessHook`** — (Optional) Event-sourced process mining via wasm4pm

### Receipt Structure

```rust
pub struct Receipt {
    pub receipt_id: String,               // "rcpt-sha256-digest"
    pub timestamp: String,                // RFC-3339
    pub from_phase: LspPhase,
    pub to_phase: LspPhase,
    pub action_id: String,                // The admitted action
    pub law_axes_consulted: Vec<LawAxis>, // law_intake_validation, law_admissibility, ...
    pub digest: String,                   // SHA256(JSON canonical form)
    pub chain_link: Option<String>,       // Previous receipt digest (forms a chain)
}
```

Receipts are **immutable and append-only**. They form an ordered chain: each receipt's `chain_link` points to the previous receipt's digest, creating a tamper-evident log.

### Typestate Machine

```rust
pub struct TypestateKernel<Phase: crate::Law> {
    data: Phase::Data,
}

// Witness types for each phase
pub struct Uninitialized;
pub struct Initializing;
pub struct Initialized;
pub struct ShutDown;
pub struct Exited;

// Law trait encoding transitions
pub trait Law: Sized {
    type Data: Send + Sync;
    // Allowed transitions: Initializing, Initialized, ShutDown, Exited
    fn transition(self, action: Action) -> Result<NextPhase, Error>;
}
```

The typestate machine is **compile-time proof that only valid phase transitions are possible**. Invalid transitions (e.g., Exited → Initialized) cannot be expressed.

### ConformanceVector

```rust
pub struct ConformanceVector {
    pub admitted: Vec<LawAxis>,           // Law axes that are satisfied
    pub refused: Vec<LawAxis>,            // Law axes that are violated (Error severity)
    pub unknown: Vec<LawAxis>,            // Law axes that are incomplete
    pub score: Option<f64>,               // 100.0 * |admitted| / (|admitted| + |refused|)
    pub strict_mode: bool,                // Fail on Unknown
}
```

**Invariant**: `Unknown` never collapses into `Admitted` or `Refused`. When a law axis cannot be evaluated, it remains `Unknown` — this signals a gap, not success.

### Global Registry

```rust
pub struct ServerRegistry {
    pub client_capabilities: Option<ClientCapabilities>,
    pub server_capabilities: Option<ServerCapabilities>,
    pub diagnostics: HashMap<String, MaxDiagnostic>,      // diagnostic_id → diagnostic
    pub repair_plans: HashMap<String, Vec<MaxCodeAction>>, // uri → repair actions
    pub gates: HashMap<String, bool>,
    pub receipts: HashMap<String, Receipt>,
    pub snapshots: HashMap<String, SnapshotRecord>,
    pub current_state: State,
    pub action_seq: u64,                  // Monotonic, increments on every release
    pub conformance_delta_log: VecDeque<ConformanceDeltaEntry>,
}

pub static REGISTRY: OnceLock<Mutex<ServerRegistry>> = OnceLock::new();
pub static MESH: OnceLock<Mutex<AutonomicMesh>> = OnceLock::new();
```

Both are **global singletons** initialized on first access. A future RFC proposes replacing these with per-connection `ServerSession<S>` to enable true multi-tenancy.

### Invariants

1. **Receipts are immutable**: Once emitted, a receipt cannot be modified or deleted.
2. **Chain is tamper-evident**: Each receipt links to its predecessor's SHA256 digest. A missing or invalid link signals tampering.
3. **Diagnostics are transient**: They live in `registry.diagnostics` and can be cleared, but cleared IDs are tracked in `cleared_diagnostics` to prevent re-admission of the same issue.
4. **State transitions require gates**: Before transitioning phases, `accept_gates(registry, gates)` must return true.
5. **Conformance deltas are ordered**: The `conformance_delta_log` is ordered by `seq` (action sequence number). Polling clients provide a `since_seq` cursor; results are all entries `> since_seq`.

---

## Layer 4: Knowledge Hooks — Composition and Routing

**Crate**: `src/composition/`

**Key modules**: `routing.rs`, `capability_tracker.rs`, `merge.rs`, `upstream.rs`, `edit_gate.rs`, `server.rs`

### Purpose

Layer 4 is the **multi-server composition and knowledge inference layer**. It:

1. **Discovers and merges capabilities** from N child LSP servers
2. **Routes methods** to the appropriate tier (Primary, Secondary, DiagnosticsOnly)
3. **Merges responses** (e.g., hovers, completions, diagnostics) with deduplication
4. **Tracks document versions** to enforce causality (a document edit must reference a known version)
5. **Guards mutations** via `TransactionEditGate` — a WorkspaceEdit is admitted only if all text positions can be validated against known document versions

### Composition Tier System

```rust
pub enum ChildTier {
    Primary,           // Hover, completion, definition: use only primary
    Secondary,         // Fallback if primary fails
    DiagnosticsOnly,   // Emit diagnostics but not code actions or hovers
}

pub struct ChildServer {
    id: String,
    tier: ChildTier,
    process_handle: Child,
    connected: bool,
    capabilities: ServerCapabilities,
}
```

**Routing invariant**:

```
textDocument/hover, definition, completion → Primary only (FirstSuccess)
textDocument/publishDiagnostics              → All tiers (FanAll, REFUSED_BY_LAW survives merge)
unknown methods                              → Primary only (conservative)
```

### Capability Merging

```rust
pub struct CapabilityTracker {
    primary_caps: ServerCapabilities,
    secondary_caps: Vec<ServerCapabilities>,
    diagnostics_only_caps: Vec<ServerCapabilities>,
}

impl CapabilityTracker {
    pub fn merged_capabilities(&self) -> ServerCapabilities {
        // Intersection for hover_provider, completion_provider (primary wins)
        // Union for diagnostics, formatting
        // ExcludedMethods for DiagnosticsOnly servers
    }
    
    pub fn supports(&self, method: &str) -> bool {
        // Does merged capability set include this method?
    }
}
```

### Document Version Tracking

```rust
pub struct DocumentVersionTracker {
    versions: HashMap<Url, i32>,  // Document URI → current version
}

impl DocumentVersionTracker {
    pub fn on_did_open(&mut self, uri: Url, version: i32) {
        self.versions.insert(uri, version);
    }
    
    pub fn on_did_change(&mut self, uri: Url, version: i32) {
        // Only update if version > current version (monotonic)
    }
    
    pub fn check_position(&self, uri: &Url, version: i32) -> VersionCheckResult {
        // Known, Ahead, or Behind (for WorkspaceEdit validation)
    }
}
```

### Transaction Edit Gate

```rust
pub struct TransactionEditGate {
    doc_versions: DocumentVersionTracker,
}

pub enum EditGateOutcome {
    Admitted,
    Refused(String),  // "position (5, 10) is ahead of known version 2"
}

impl TransactionEditGate {
    pub fn validate_workspace_edit(
        &self,
        edit: &WorkspaceEdit,
    ) -> EditGateOutcome {
        // For each TextDocumentEdit:
        // - Extract URI and all (line, character) tuples
        // - Check against doc_versions
        // - Reject if any position is ahead of known version
        // - Reject if any range spans multiple unknown documents
    }
}
```

### Response Merging

```rust
pub fn merge_hovers_with_attribution(
    hovers: Vec<(ServerId, Option<Hover>)>,
) -> Option<Hover> {
    // Primary hover wins; if absent, take secondary; DiagnosticsOnly excluded
    // Source is attributed: response includes [comment: "from server_id"]
}

pub fn merge_workspace_edits(
    edits: Vec<(ServerId, WorkspaceEdit)>,
) -> WorkspaceEdit {
    // Dedup by URI; coalesce edits to the same range
    // Reject if version markers conflict
}
```

### Invariants

1. **Primary is authority**: For hovers/completions, primary server's response is used; secondary is fallback.
2. **Version causality**: A document cannot be edited at a position newer than the known version.
3. **Merges are conservative**: If a merge would require conflicting information (e.g., two servers disagree on range boundaries), the merge is refused.
4. **DiagnosticsOnly is read-only**: These servers can emit diagnostics but cannot influence code actions or hovers.

---

## Layer 5: Autonomic LSP Mesh — Conformance and Gates

**Crates**: `crates/lsp-max-compositor`, `examples/anti-llm-cheat-lsp`

**Key types**: `CompositorClient`, `MergeContext`, `GateFile`, `CompositorReceipt`, `Λ_CD` predicate

### Purpose

Layer 5 is the **autonomic mesh layer** — the "law-state runtime projected through LSP." It:

1. **Spawns and reaps child LSP processes** with process monitoring and exit watchers
2. **Fans out client requests** to all child servers in parallel
3. **Merges diagnostics** with ANDON signal handling (Red/Yellow/Green based on conformance)
4. **Emits conformance vectors** tracking admitted vs. refused law axes
5. **Enforces admission gates** via the `Λ_CD` predicate (no shell/file action while ANDON is set)
6. **Detects violations** (plain tower-lsp, victory language, fake receipts) via anti-llm-cheat-lsp canary

### Compositor Architecture

```rust
pub struct CompositorClient {
    config: CompositorConfig,
    children: HashMap<ServerId, PersistentUpstream>,
    merge_context: MergeContext,
    gate_file: GateFile,
}

impl CompositorClient {
    pub async fn initialize(&mut self) -> Result<()> {
        // 1. Load lsp-max.toml (or default config)
        // 2. Spawn child processes for each server entry
        // 3. Connect to each child via stdio LSP
        // 4. Exchange initialize/initialized
        // 5. Merge capabilities
        // 6. Return merged capabilities to client
    }

    pub async fn on_request(
        &mut self,
        method: &str,
        params: Value,
    ) -> Result<Value> {
        // 1. Route method based on tier and capability
        // 2. Send to child(ren) in parallel
        // 3. Merge responses
        // 4. Check ANDON gate
        // 5. Emit receipt
        // 6. Return result
    }

    pub async fn on_notification(&mut self, method: &str, params: Value) -> Result<()> {
        // Fan-out to all children; collect, check ANDON, emit receipt
    }
}
```

### Diagnostic Buffer and Flush Coordinator

```rust
pub struct DiagnosticBuffer {
    // DashMap<Uri, Vec<(ServerId, Diagnostic)>>
    // Non-destructive deposits: deposit(uri, server_id, diag) appends
    // flush() atomically returns and clears all entries
}

pub struct FlushCoordinator {
    // Debounce buffer: 100ms (or quorum-triggered)
    // Emits CompositorReceipt after each flush
}

pub struct CompositorReceipt {
    pub timestamp: String,
    pub prefixes_fingerprint: String,  // FNV-1a hash of ANDON prefix set
    pub has_andon_block: bool,         // Any REFUSED_BY_LAW present?
    pub child_evidence: Vec<ChildEvidence>, // Links to per-child receipts
}
```

### ANDON Gate (Λ_CD^runtime)

```rust
pub struct GateFile {
    // Path: $XDG_RUNTIME_DIR/lsp-max-gate-{fnv1a(cwd):016x}
    // Content: b"0" (clear) or b"1" (BLOCKED)
}

impl GateFile {
    pub fn check(&self) -> Result<()> {
        // Read one byte; return error if b"1"
        // Used by PreToolUse hook: lsp-max-cli gate check before every Bash/Edit/Write
    }

    pub fn set_andon(&self) -> Result<()> {
        // Write b"1" when first ANDON-class diagnostic appears
        // Used by compositor after diagnostic merge
    }

    pub fn clear_andon(&self) -> Result<()> {
        // Write b"0" when no ANDON-class diagnostics remain
    }
}
```

**Λ_CD predicate**:

```
Λ_CD(action) = Λ(action) ∧ ¬∃ d ∈ D_t : d.law_id ∈ A ∧ d.severity = Error

Where:
- Λ(action): agent's base admissibility (receipts, no victory language, no forbidden implications)
- D_t: active diagnostics at time t
- A: constrained set of law axes (WASM4PM-*, ANTI-LLM-*, GGEN-*)
- d.severity = Error: only Error-level violations block; Warning/Hint do not
```

**Enforcement**:

- **Parent session**: `.claude/settings.json` has a `PreToolUse` hook that runs `lsp-max-cli gate check` before every Bash/Edit/Write tool call
- **Exit code 0**: Gate is clear; tool proceeds
- **Exit code 1**: ANDON is set; tool is blocked until gate clears
- **Subagent sessions**: Structurally isolated from parent hooks (not a configuration error, a structural gap)

### Anti-LLM-Cheat Canary

```rust
// examples/anti-llm-cheat-lsp/src/main.rs
pub struct AntiLlmCheatLsp {
    // Runs on lsp-max (does NOT depend on plain tower-lsp)
    // Detects and emits diagnostics for:
    // - Plain tower-lsp references (ANTI-LLM-SURFACE-001)
    // - Fake authorities (ANTI-LLM-AUTH-002)
    // - Fake receipts (ANTI-LLM-RECEIPT-*) 
    // - Fake routes (ANTI-LLM-ROUTE-001)
    // - Victory language (ANTI-LLM-CLAIM-*)
    // - Version violations (ANTI-LLM-VERSION-*)
}

// Detector stack:
// 1. Raw text scan (grep-based)
// 2. Tree-sitter AST scan (Cargo.toml, Rust code)
// 3. Cargo dependency graph scan
// 4. Markdown/agent report scan
// 5. JSON-RPC transcript scan
// 6. Receipt validator (SHA256, boundary markers, checkpoint closure)
// 7. Route evidence checker (CodeAction → clap-noun-verb → Receipt)
// 8. Claim vs. proof checker
// 9. Emit LSP diagnostics + virtual documents
```

**Self-sealing law**:

```
lsp-max hosts anti-llm-cheat-lsp
anti-llm-cheat-lsp detects tower-lsp
therefore lsp-max cannot silently regress to tower-lsp
```

### Invariants

1. **Diagnostics are ordered and immutable**: Emitted in a single `textDocument/publishDiagnostics` per flush; cannot be reordered after emission.
2. **ANDON blocks shell actions**: While any ANDON-class diagnostic is present, the gate file is b"1" and all Bash/Edit/Write calls are blocked.
3. **Receipts are causal**: `CompositorReceipt` links to child receipts; the merged verdict is traceable to per-child evidence.
4. **Merges are non-destructive**: Diagnostic deduplication never discards REFUSED_BY_LAW codes; they survive the merge and trigger ANDON.

---

## Data Flow: Request → Receipt

An example trace of a single LSP request through all five layers:

### Scenario
Agent calls `lsp-max-cli conformance score --instance-id LSP_1`

### Layer 1: Actuation Grammar
```
[clap-noun-verb parser]
  ↓
"conformance score" → conformance::ScoreParams { instance_id: "LSP_1" }
  ↓
ServerService::score(instance_id)  [in crates/lsp-max-cli/src/nouns/conformance.rs]
  ↓
Read mesh.json from disk
```

### Layer 2: Local LSP State Surface
```
Load ServerRegistry from global REGISTRY singleton
  ↓
Query: registry.current_state, registry.diagnostics, registry.action_seq
  ↓
(No transport here — CLI works directly with in-process registry)
```

### Layer 3: Law-State Runtime
```
Create ConformanceVector from registry.diagnostics
  ↓
admitted = count of non-Error diagnostics
refused = count of Error-severity diagnostics
unknown = 0 (all law axes are known)
  ↓
score = 100.0 * admitted / (admitted + refused)
  ↓
Emit MeshAction::UpdateConformanceScore(score)
  ↓
Hook chain processes action, updates registry.conformance_delta_log
  ↓
Emit Receipt { action_id: "conformance-score-query", from_phase, to_phase, digest }
```

### Layer 4: Composition Knowledge (N/A for this example)
```
(Composition only applies if a CompositorClient is present)
(For direct registry queries, no composition occurs)
```

### Layer 5: Autonomic Mesh (ANDON Check)
```
If ANDON gate is set: refuse the query, emit ANDON error
  ↓
Otherwise: return conformance_vector + receipt
```

### Return to Agent
```
conformance score = 85.5
admitted = 17
refused = 3
unknown = 0
receipt_id = "rcpt-sha256-abc123..."
chain_link = "rcpt-sha256-previous..."
```

---

## Architectural Invariants and Laws

### I1. Layered Isolation

Each layer is isolated from layers > 2 positions away:

```
Layer 5 can call Layer 3 (diagnostics, gates)
Layer 5 cannot directly mutate Layer 2 (that goes through Layer 3)
Layer 3 can call Layer 2 (state machine, service lifecycle)
Layer 3 cannot directly call Layer 1 (actions route through Layer 2)
```

### I2. Receipt Binding

**No state mutation without a receipt.**

Every action that changes server state must:
1. Originate from Layer 1 (actuation grammar)
2. Pass through Layer 3 (law gates)
3. Be recorded in a Receipt (Layer 3)
4. Be linked in a SHA256 chain (Layer 3)
5. Be reflected in conformance deltas (Layer 3)

### I3. Monotonic State and Phase

The LSP state machine is **monotonic** — only forward transitions are allowed:

```
Uninitialized → Initializing → Initialized → ShutDown → Exited
                    ↓              ↓
                (can block here)  (can block here)
```

No state is ever re-entered. This is **enforced at compile time** via the typestate machine.

### I4. Diagnostics vs. Actions

- **Diagnostics** are **observations** emitted by Layer 3 and collected by Layer 5 (read-only)
- **Actions** are **mutations** initiated by Layer 1 and gated by Layer 3 (write-only, receipt-binding required)

Forbidden implication: `LSP observation ⇒ mutation authority`

### I5. Law Axes Are Not Collapsed

A `ConformanceVector` carries three disjoint sets: `admitted`, `refused`, `unknown`.

- `admitted` means the axis is satisfied with a receipt
- `refused` means the axis is violated (Error-severity diagnostic)
- `unknown` means the axis cannot be evaluated (incomplete data, missing receipt, or precondition not met)

**Invariant**: `unknown` is never coerced into `admitted` or `refused`. To "clear" an `unknown` axis, a receipt must be obtained; otherwise it remains `unknown` indefinitely.

### I6. LSP is Read-Only by Default

The LSP may **emit**:

```
diagnostics
hovers
code action intents
inline completions
virtual documents
command tooltips
failset summaries
protocol traces
```

It must **not directly mutate files**. Future mutations route only through:

```
CodeAction
  ↓
clap-noun-verb admission
  ↓
PackActionIntent
  ↓
PackPlan
  ↓
Staging
  ↓
MutationGate  [checks Λ_CD(action)]
  ↓
Receipt
```

### I7. Composition is Non-Destructive

When merging responses from N child servers, the merge is **non-destructive**:

- Diagnostic merge preserves all REFUSED_BY_LAW codes
- Response merge dedupes by value, not by source
- Capability merge takes intersection (hover, completion) or union (diagnostics)

---

## Testing and Verification

### Integration Tests

Tests live in `tests/` at the workspace root and in per-crate `tests/` directories.

```bash
cargo test --test test_lsp318_capabilities    # Root integration test
cargo test -p anti-llm-cheat-lsp --test dogfood  # Example crate dogfood suite
cargo test -p lsp-max-compositor               # Compositor tests
```

### Dogfood Tests

Dogfood tests are **negative-control tests** that verify the framework detects its own violations:

```rust
#[test]
fn test_gc004b_no_tower_lsp_lock() {
    // Verify that if plain tower-lsp were re-introduced, the canary detects it
    // This test fails if the detection logic is broken
}

#[test]
fn test_receipt_chain_integrity() {
    // Emit actions, verify chain links are correct, SHA256 digests match
}
```

### Conformance Scoring

Every LSP 3.18 feature row requires:

- **Positive transcript**: Raw JSON-RPC messages showing the feature working
- **Negative control**: A case where the feature is refused, with receipt proof
- **Receipt**: SHA256-signed proof that the feature was tested and passed/refused

Status values:

```
SUPPORTED_WITH_TRANSCRIPT
REFUSED_BY_LAW_WITH_RECEIPT
BLOCKED
```

Never: "probably supported", "implied", "covered by normal LSP", "not relevant", "not tested".

---

## Debugging and Troubleshooting

### WASM4PM Build Failures

**Symptom**: `cargo build` fails with "unresolved import `wasm4pm_compat`"

**Check**: Verify sibling checkouts:

```bash
ls ../wasm4pm ../wasm4pm-compat ../lsp-types-max
```

All three must be present in the parent directory (path dependencies).

### Reception Validation Failures

**Symptom**: Diagnostic `ANTI-LLM-CHEAT-LSP-RECEIPT-INVALID` or SHA256 chain mismatch

**Check**: Verify receipt artifact chain:

```bash
scripts/validate-receipt-chain.sh <receipt-path>
```

Look for boundary markers (`-----BEGIN RECEIPT-----`), valid SHA256 digests, and checkpoint closure.

### Conformance Score Anomalies

**Symptom**: A feature row shows low conformance despite code changes

**Check**: Trace admission law axes:

```bash
cargo test test_conformance_vector -- --nocapture
cargo test -p lsp-max-protocol test_law_axis_admission -- --nocapture
```

Identify which law axis is refusing admission (missing transcript, negative control, or unsigned receipt).

### Tower-LSP Reference Detection

**Symptom**: Clippy or `dx-verify` fails with "forbidden: plain tower-lsp reference"

**Check**: Run compliance scanner:

```bash
scripts/check-law-compliance.sh
```

Fix any matches by renaming to `lsp-max` or wrapping in negative-control fixtures.

### Gate State Inspection

**Symptom**: ANDON gate is set, blocking Bash commands

**Check**: Query gate state:

```bash
lsp-max-cli gate check    # Exit 0 = clear; exit 1 = set
lsp-max-cli gate list     # List active WASM4PM-* / GGEN-* diagnostics
```

Resolve all listed diagnostics to clear the ANDON signal.

---

## Crate Dependency Graph

```
crates/lsp-max-cli
  ↓ (depends on)
  lsp-max-protocol
  ↓ (depends on)
  lsp-max-runtime
  ↓ (depends on)
  lsp-max-macros
  ↓ (depends on)
  lsp_types_max  [sibling: ../lsp-types-max]

crates/lsp-max-compositor
  ↓
  lsp-max-protocol, lsp-max-runtime, lsp_types_max

src/ [root]
  ↓
  lsp-max-protocol, lsp-max-runtime, lsp_types_max, lsp-max-macros

examples/anti-llm-cheat-lsp
  ↓
  lsp-max (root crate)
  lsp-max-protocol, lsp-max-runtime

crates/lsp-max-adapters/
  ↓
  lsp-max, lsp-max-protocol
```

---

## Future Directions (RFCs)

### RFC-1: D_t PUSH Injection

**Status**: CANDIDATE

Extend `lsp-max-cli gate check` with `--format=agent-context` flag. When exit 1 (BLOCKED), stdout emits a structured JSON block:

```json
{
  "active_andon_codes": ["WASM4PM-001", "ANTI-LLM-002"],
  "governing_axes": ["wasm4pm", "anti_llm"],
  "available_repairs": [...],
  "since_seq": 42
}
```

The PreToolUse hook injects this as a `<gate-context>` system-reminder block, giving agents full visibility into the governing diagnostic set.

### RFC-2: Per-Connection State

**Status**: OPEN

Replace global `REGISTRY` and `MESH` singletons with a per-connection `ServerSession<S>` struct threaded through the Tower layer as an Extension. Enables true multi-tenancy: N concurrent LSP connections each have isolated D_t, conformance_delta_log, action_seq, and GateFile.

### RFC-3: Event-Sourced D_t Log

**Status**: OPEN

Replace mutable HashMap dispatch with an append-only lock-free ring buffer (65536 entries). Hooks become pure `(LawEvent) -> Vec<MeshAction>` functions. Live D_t is a materialized view maintained by a background tailer. Enables causal replay and D_t addressability.

---

## See Also

- **`AGENTS.md`** — The project constitution; laws are enforced by tooling
- **`CLAUDE.md`** — Development guidance and DX commands
- **`README.md`** — High-level overview
- **`ROADMAP.md`** — Future features and timeline