Repository navigation
Expand file tree
/
Copy pathMakefile
More file actions
1477 lines (1175 loc) · 168 KB
/
Copy pathMakefile
File metadata and controls
1477 lines (1175 loc) · 168 KB
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
# Makefile — agentic IDE harness (omp-based, Option A)
#
# Conventions:
# make test -> all tests (Bun harness + sidecar smoke)
# make demo-00 -> increment 0 demo (proves fail-closed on day one)
# make demo-<id> -> per-increment runnable proof
#
# The harness is TypeScript on Bun. The only Python is scanner-sidecar/,
# managed by uv. See CLAUDE.md and DECISIONS.md.
SHELL := /bin/bash
.DEFAULT_GOAL := help
BUN := bun
UV := uv
SIDECAR_DIR := scanner-sidecar
PY := $(UV) run --project $(SIDECAR_DIR) python
# ---------------------------------------------------------------------------
# Setup
# ---------------------------------------------------------------------------
.PHONY: install
install: install-harness install-desktop install-sidecar install-hooks ## Install harness + desktop + sidecar deps + git hooks
.PHONY: install-hooks
install-hooks: ## Point git at .githooks/ so the pre-commit license-header hook runs
git config core.hooksPath .githooks
@echo "✓ core.hooksPath -> .githooks (pre-commit applies BUSL-1.1 headers to staged source)"
.PHONY: install-harness
install-harness: ## Install Bun/TypeScript harness deps
$(BUN) install
.PHONY: install-desktop
install-desktop: ## Install desktop deps. Load-bearing for the symbol graph: desktop pins typescript 6 (the runtime compiler API), while the root pin is the TS 7 Go CLI whose package root exports only version fields. Without this install, loadTs() finds no usable compiler and P-KG-SYM.1 builds empty graphs (CI installs desktop deps; make install must match).
cd desktop && $(BUN) install
.PHONY: install-sidecar
install-sidecar: ## Create/sync the pinned Python sidecar venv
cd $(SIDECAR_DIR) && $(UV) sync
# ---------------------------------------------------------------------------
# Tests
# ---------------------------------------------------------------------------
.PHONY: test
test: test-harness test-sidecar ## Run all tests
# The gate's scope is defined by EXCLUSION, never by positional patterns. `bun test desktop harness`
# reads like a directory scope and is not one: bun treats positional args as SUBSTRING matches against
# the whole path, so adding `tools` also selects every vendor/oh-my-pi/**/tools/** file. Measured on this
# repo: exclusion-only 357 files / 11 fail, versus `bun test desktop harness tools` 486 files / 125 fail.
# Each exclusion is a tree whose tests are not this gate's to run:
# desktop/release/** GENERATED. A packaged copy of this repo, so it double-counts every test in it.
# vendor/** NOT OURS: oh-my-pi's own suite. Gitignored (.gitignore:13), but bun walks it
# regardless. Including it reports 1659 files / 942 fail, which is why the
# documented gate had never once reproduced the numbers PROGRESS.md quotes.
# lucidaddon_audit/** OURS, but 11 independently-installed packages with their own package.json that
# `make install` does not prepare, so its 51 files fail on missing deps (ajv and
# friends) rather than on anything real. Use `make test-audit` after installing
# them. Excluded LOUDLY here rather than silently omitted by a hand-typed scope.
# See ADR-0303.
TEST_IGNORES := --path-ignore-patterns='desktop/release/**' --path-ignore-patterns='vendor/**' --path-ignore-patterns='lucidaddon_audit/**'
.PHONY: test-harness
test-harness: ## Bun test suite over first-party code (357 files). TEST_IGNORES above is load-bearing.
$(BUN) test $(TEST_IGNORES)
.PHONY: test-audit
test-audit: ## lucidaddon_audit/ (51 files, 11 packages). NOT part of `make test`: needs its own installs first.
cd lucidaddon_audit && $(BUN) test
.PHONY: test-sidecar
test-sidecar: ## Sidecar smoke test: one request in, well-formed response out
$(PY) -m pytest -q $(SIDECAR_DIR)/tests || \
(echo "sidecar tests failed" && exit 1)
# ---------------------------------------------------------------------------
# Increment 0 demo
# 1. headless omp round-trip via the echo provider (no network/keys)
# 2. scanner sidecar: clean string + zero-width-injected string
# 3. FAIL-CLOSED PROOF: kill the sidecar mid-call, assert the gate blocks
# ---------------------------------------------------------------------------
.PHONY: demo-00
demo-00: ## Increment 0: omp echo round-trip + scanner + fail-closed proof
@echo "== [1/3] omp echo-provider round-trip =="
$(BUN) run harness/scripts/demo00_omp_echo.ts
@echo "== [2/3] scanner clean vs poisoned =="
$(BUN) run harness/scripts/demo00_scanner.ts
@echo "== [3/3] FAIL-CLOSED: kill sidecar mid-call, expect BLOCK =="
$(BUN) run harness/scripts/demo00_failclosed.ts
@echo "== demo-00 OK =="
# The fail-closed proof is ALSO a permanent test, not just a demo.
# It lives in the harness suite so it can never silently regress.
.PHONY: test-failclosed
test-failclosed: ## Standalone run of the fail-closed regression test
$(BUN) test harness/security/gate.failclosed.test.ts
# ---------------------------------------------------------------------------
# Placeholders for later increments (fill in as you build)
# ---------------------------------------------------------------------------
.PHONY: demo-01
demo-01: ## Boundary contracts: emit events + ToolResult round-trip
$(BUN) run harness/scripts/demo01_contracts.ts
.PHONY: demo-02
demo-02: ## Cache-optimized prompt assembly: prefix bytes identical across tasks
$(BUN) run harness/scripts/demo02_prefix_hash.ts
.PHONY: demo-P2.1
demo-P2.1: ## P2.1: scan adversarial fixtures; each finding fires, clean corpus is FP-free
$(PY) $(SIDECAR_DIR)/demo_p2_1.py
.PHONY: demo-P2.3
demo-P2.3: ## P2.3: ingest a poisoned artifact -> artifact/scan/findings/sanitized rows
$(BUN) run harness/scripts/demo03_ingest.ts
.PHONY: demo-P2.4
demo-P2.4: ## P2.4: poisoned tool call blocked by the omp pre-hook + approval workflow
$(BUN) run harness/scripts/demo04_quarantine_hook.ts
.PHONY: demo-P3.1
demo-P3.1: ## P3.1: verification engine; security scan is a fail-closed completion precondition
$(BUN) run harness/scripts/demo05_verification.ts
.PHONY: demo-P3.2
demo-P3.2: ## P3.2: ingest telemetry JSONL into DuckDB (idempotent) + sample security queries
$(BUN) run harness/scripts/demo06_telemetry_ingest.ts
.PHONY: demo-P4.1
demo-P4.1: ## P4.1: memory layers (working/archive/semantic) + state artifacts
$(BUN) run harness/scripts/demo07_memory.ts
.PHONY: demo-P4.2
demo-P4.2: ## P4.2: security-aware compaction (summaries from sanitized; raw preserved)
$(BUN) run harness/scripts/demo08_compaction.ts
.PHONY: demo-P4.3
demo-P4.3: ## P4.3: semantic-promotion gate blocks suspicious-source promotions (keystone #2)
$(BUN) run harness/scripts/demo09_promotion_gate.ts
.PHONY: demo-P5.1
demo-P5.1: ## P5.1: parent/child run lineage + subagent dispatch with per-run scan lineage
$(BUN) run harness/scripts/demo10_lineage.ts
.PHONY: demo-P5.2
demo-P5.2: ## P5.2: sandbox profiles auto-downgrade + read-only security-review subagent
$(BUN) run harness/scripts/demo11_sandbox.ts
.PHONY: demo-P6.1
demo-P6.1: ## P6.1: remote-runner gate scans payload before dispatch; routes suspicious to review
$(BUN) run harness/scripts/demo12_remote_gate.ts
.PHONY: demo-P6.2
demo-P6.2: ## P6.2: safe export (MD/CSV/JSON); raw never rendered by default; export audited
$(BUN) run harness/scripts/demo13_safe_export.ts
.PHONY: demo-P7.1
demo-P7.1: ## P7.1: materialize the six security dashboard views to safe CSVs
$(BUN) run harness/scripts/demo14_dashboards.ts
.PHONY: demo-P7.2
demo-P7.2: ## P7.2: replay run tree/timeline + benchmark cache-hit per prompt-prefix version
$(BUN) run harness/scripts/demo15_replay_bench.ts
.PHONY: demo-P-LOC.1
demo-P-LOC.1: ## P-LOC.1: AI-LOC attribution — count AI-authored lines per model/repo/identity
$(BUN) run harness/scripts/demo16_ai_loc.ts
.PHONY: demo-ADR9A
demo-ADR9A: ## ADR-0009 Phase A: recall prior-session facts into a new session (suspicious never recalled)
$(BUN) run harness/scripts/demo17_recall.ts
.PHONY: demo-P-CODE.1
demo-P-CODE.1: ## P-CODE.1 (ADR-0030): git workspace diffstat this month + fail-closed omit of non-git dirs
$(BUN) run harness/scripts/demo_pcode1.ts
.PHONY: demo-P-TPS.1
demo-P-TPS.1: ## P-TPS.1 (ADR-0044): streaming output-token readout — output-only, prompt-excluded, provider-reconciled
$(BUN) run harness/scripts/demo_ptps1.ts
.PHONY: demo-P-SKILL.1
demo-P-SKILL.1: ## P-SKILL.1 (ADR-0045): gated skill import — clean .md writes to .omp/skills/, poisoned blocks at the gate
$(BUN) run harness/scripts/demo_pskill1.ts
.PHONY: demo-P-SKILL.4
demo-P-SKILL.4: ## P-SKILL.4 (ADR-0097): the Agent Skill directory - classify roots/trust, fail-closed re-scan locks a flagged skill, remove confined to project/user (immutable .agents refused)
$(BUN) run harness/scripts/demo_pskill4.ts
.PHONY: demo-P-SKILLREG.1
demo-P-SKILLREG.1: ## P-SKILLREG.1 (ADR-0098): the enterprise skills registry READER - Ed25519 verify + fail-closed scan-gate on install; unsigned/untrusted-key/poisoned blocked, clean installs as an untrusted registry row
$(BUN) run harness/scripts/demo_pskillreg1.ts
.PHONY: demo-P-SKILL.5
demo-P-SKILL.5: ## P-SKILL.5 (ADR-0101): Skill Studio - analyze recent work into candidate skills, codify each through the fail-closed gate (clean writes, poisoned blocks); analyze writes nothing
$(BUN) run harness/scripts/demo_pskill5.ts
.PHONY: demo-P-SKILLREG.2
demo-P-SKILLREG.2: ## P-SKILLREG.2 (ADR-0102): the skill publish seam - sign + publish a codified skill to the Local Skills Registry (remote target no-ops fail-safe), then round-trip it back through the reader into a registry row
$(BUN) run harness/scripts/demo_pskillreg2.ts
.PHONY: demo-P-KB.1
demo-P-KB.1: ## P-KB.1 (ADR-0099): the compiled KB - a clean doc compiles into a page graph, a poisoned source is quarantined (never compiled), a poisoned derived page is re-scanned + quarantined (never stored)
$(BUN) run harness/scripts/demo_pkb1.ts
.PHONY: demo-P-KB.2
demo-P-KB.2: ## P-KB.2 (ADR-0100): the hybrid retrieval router (vector | compiled | both, delimited + cited) + the kept-in-sync generator (idempotent re-ingest, contradiction-flagged, prior page retained)
$(BUN) run harness/scripts/demo_pkb2.ts
.PHONY: demo-P-KB.2b
demo-P-KB.2b: ## P-KB.2b (ADR-0099/0100 desktop): the desktop compiled-KB surface - ingest compiles into the process store, retrieve returns cited delimited hits, graph exposes pages+links, poisoned source quarantined
$(BUN) run desktop/scripts/demo_p_kb_1.ts
.PHONY: demo-P-GOAL.9
demo-P-GOAL.9: ## P-GOAL.9 (ADR-0054): /goal After-Action Report — tool calls/LOC/errors/websites graphs + stall guard
$(BUN) run harness/scripts/demo_pgoal9.ts
.PHONY: demo-P-GOAL.10
demo-P-GOAL.10: ## P-GOAL.10 (ADR-0055): /goal cross-run evaluation ledger — success rate, avg iters, failure breakdown
$(BUN) run harness/scripts/demo_pgoal10.ts
.PHONY: demo-P-GOAL.11
demo-P-GOAL.11: ## P-GOAL.11 (ADR-0056): /goal live spend meter + budget kill switch — halts an unattended run at a $ cap
$(BUN) run harness/scripts/demo_pgoal11.ts
.PHONY: demo-P-GOAL.12
demo-P-GOAL.12: ## P-GOAL.12 (ADR-0057): Pre-Flight Audit — readiness L0→L3, history awareness, interview, Loop Design report
$(BUN) run harness/scripts/demo_pgoal12.ts
.PHONY: demo-P-RAG.1
demo-P-RAG.1: ## P-RAG.1 (ADR-0058): local knowledge spine — scan-gated ingest, fail-closed block, offline cosine retrieval, delimited injection
$(BUN) run harness/scripts/demo_prag1.ts
.PHONY: demo-P-RAG.1b
demo-P-RAG.1b: ## P-RAG.1b (ADR-0063): real bge-small embedder — SEMANTIC retrieval (zero shared words), still scan-gated + delimited
$(BUN) run harness/scripts/demo_prag1b.ts
.PHONY: demo-P-RAG.1c
demo-P-RAG.1c: ## P-RAG.1c (ADR-0064): PDF -> text through the SAME scan gate — semantic retrieval from a PDF, corrupt PDF fails closed
$(BUN) run harness/scripts/demo_prag1c.ts
.PHONY: demo-P-BRIEF.1
demo-P-BRIEF.1: ## P-BRIEF.1 (ADR-0070): Executive Engineering Update from the repo's DECISIONS/PROGRESS — written brief + two-host podcast script, air-gap clean
$(BUN) run harness/scripts/demo_pbrief1.ts
.PHONY: demo-P-BRIEF.2
demo-P-BRIEF.2: ## P-BRIEF.2 (ADR-0071): the exec-update script → one WAV via the OpenAI-compatible (Kokoro) TTS backend; mock transport offline, LUCID_TTS_BASE_URL for live
$(BUN) run harness/scripts/demo_pbrief2.ts
.PHONY: demo-P-STT.1
demo-P-STT.1: ## P-STT.1 (ADR-0073): mic audio → text via the OpenAI-compatible (local Whisper) STT backend; mock transport offline, LUCID_STT_BASE_URL for live
$(BUN) run harness/scripts/demo_pstt1.ts
.PHONY: demo-P-ASKSAGE.1
demo-P-ASKSAGE.1: ## P-ASKSAGE.1 (ADR-0059): AskSage tool-loop diagnostics + tolerant extraction — wrapped replies recovered, empty turns flagged
$(BUN) run harness/scripts/demo_paskage1.ts
.PHONY: demo-B-KG.1
demo-B-KG.1: ## B-KG.1 (#112/#113/#114): KG interaction polish — large graph fits on open, idle CPU halts, forget is instant + snapshot-safe
$(BUN) run desktop/scripts/demo_b_kg_1.ts
.PHONY: demo-P-KG-REL.1
demo-P-KG-REL.1: ## P-KG-REL.1 (#109/ADR-0075): manual relate — authored edge lands in the store + persists; drag/multi-select interaction logic
$(BUN) run desktop/scripts/demo_p_kg_rel_1.ts
.PHONY: demo-B-KG.2
demo-B-KG.2: ## B-KG.2 (#115): export location is recoverable — persistent toast + Open folder / Copy path
$(BUN) run desktop/scripts/demo_b_kg_2.ts
.PHONY: demo-P-ENT.1
demo-P-ENT.1: ## P-ENT.1 (ADR-0068): enterprise managed-policy override — set + lock exec/egress/model knobs via GPO/MDM, only ever tightening, fail-safe to unmanaged
$(BUN) run harness/scripts/demo_pent1.ts
.PHONY: demo-P-KG-INGEST.1
demo-P-KG-INGEST.1: ## P-KG-INGEST.1 (#110/ADR-0076): non-blocking background ingest — progress countdown, fail-safe cancel, single-flight job
$(BUN) run desktop/scripts/demo_p_kg_ingest_1.ts
.PHONY: demo-P-KG-INGEST.1b
demo-P-KG-INGEST.1b: ## P-KG-INGEST.1b (#110/ADR-0076): group the throwaway "Extract DURABLE facts…" ingest sessions out of the chat list
$(BUN) run desktop/scripts/demo_p_kg_ingest_1b.ts
.PHONY: demo-P-VAULT-HINT.1
demo-P-VAULT-HINT.1: ## P-VAULT-HINT.1 (#111/ADR-0077): locked vault → content-free existence hint (agent offers to unlock; never decrypts)
$(BUN) run desktop/scripts/demo_p_vault_hint_1.ts
.PHONY: demo-P-KG-REL.2
demo-P-KG-REL.2: ## P-KG-REL.2 (#122/ADR-0078): custom relation labels — typed label round-trips through the store; blank defaults to "related"
$(BUN) run desktop/scripts/demo_p_kg_rel_2.ts
.PHONY: demo-P-KG-INGEST.2
demo-P-KG-INGEST.2: ## P-KG-INGEST.2 (#123/ADR-0079): bulk-clear ingest sessions — workspace-scoped, real chats survive, idempotent
$(BUN) run desktop/scripts/demo_p_kg_ingest_2.ts
.PHONY: demo-P-VAULT-HINT.2
demo-P-VAULT-HINT.2: ## P-VAULT-HINT.2 (#124/ADR-0080): fact count in the locked-vault hint — in-memory at lock, never on disk, never content
$(BUN) run desktop/scripts/demo_p_vault_hint_2.ts
.PHONY: demo-P-KG-INGEST.3
demo-P-KG-INGEST.3: ## P-KG-INGEST.3 (#125/ADR-0081): chat preempts a back-to-back ingest loop via the ChatGate (yields, then resumes)
$(BUN) run desktop/scripts/demo_p_kg_ingest_3.ts
.PHONY: demo-P-KG-REL.3
demo-P-KG-REL.3: ## P-KG-REL.3 (#130/ADR-0082): remove a relationship — optimistic edge removal + store.removeLink persists (only the targeted edge)
$(BUN) run desktop/scripts/demo_p_kg_rel_3.ts
.PHONY: demo-P-KG-SEARCH.1
demo-P-KG-SEARCH.1: ## P-KG-SEARCH.1 (#132/ADR-0083): find a node — case-insensitive substring matcher feeding highlight + center
$(BUN) run desktop/scripts/demo_p_kg_search_1.ts
.PHONY: demo-P-PERF.1
demo-P-PERF.1: ## P-PERF.1 (#134/ADR-0084): instant cached session list + transcripts (SWR) — paint cache, refresh, re-render only if changed; LRU-capped
$(BUN) run desktop/scripts/demo_p_perf_1.ts
.PHONY: demo-P-KG-INGEST.4
demo-P-KG-INGEST.4: ## P-KG-INGEST.4 (#136/ADR-0085): true ingest concurrency — dedicated util omp connection; fail-safe fallback; routing contract
$(BUN) run desktop/scripts/demo_p_kg_ingest_4.ts
.PHONY: demo-P-ABOUT.1
demo-P-ABOUT.1: ## P-ABOUT.1 (ADR-0087): About panel — single-sourced app version (v1.8.7), LUCID + TechLead 187 + BUSL-1.1 licensing, animated rail glyph
$(BUN) run desktop/scripts/demo_p_about_1.ts
.PHONY: demo-P-EXEC.1
demo-P-EXEC.1: ## P-EXEC.1 (ADR-0066): per-action exec approval — classifier (safe/risky/catastrophic), prompt interactive + block unattended, standing allows, managed denylist
$(BUN) run desktop/scripts/demo_p_exec_1.ts
.PHONY: demo-P-GOAL.13
demo-P-GOAL.13: ## P-GOAL.13 (ADR-0067): unattended loop Speed↔Risk dial — graded tiers T0-T4, loopVerdict (T4 always blocks, unset=safest), managed ceiling, AAR Blocks section
$(BUN) run desktop/scripts/demo_p_goal_13.ts
.PHONY: demo-P-ENT.2
demo-P-ENT.2: ## P-ENT.2 (ADR-0069): OCSF security audit export — each source → valid OCSF Detection Finding, fail-safe dispatcher (dead sink never blocks a turn)
$(BUN) run desktop/scripts/demo_p_ent_2.ts
.PHONY: demo-P-ROLE.1
demo-P-ROLE.1: ## P-ROLE.1 (ADR-0088): role-based onboarding — closed role set, fail-safe normalize (unknown->developer), calm per-role default landing surface, cosmetic-only (gate untouched)
$(BUN) run desktop/scripts/demo_p_role_1.ts
.PHONY: demo-P-ROLE.1b
demo-P-ROLE.1b: ## P-ROLE.1b (ADR-0089): first-run guided walkthrough — tailored per-role coachmark tour (opens on composer, closes on closer, no dangling targets), Back/Next/Skip card, replay-guard
$(BUN) run desktop/scripts/demo_p_role_1b.ts
.PHONY: demo-P-AVATAR.1
demo-P-AVATAR.1: ## P-AVATAR.1 (ADR-0251): the LUCID Agent role + immersive stage - closed role set grows by one behavioral role, bespoke no-rail tour, animated glyph, and the stylesheet hides both rails + inspector under .immersive
$(BUN) run desktop/scripts/demo_p_avatar_1.ts
.PHONY: demo-P-MASCOT.1
demo-P-MASCOT.1: ## P-MASCOT.1 (ADR-0251 pivot): LUCID the ninja mascot - frame-grid integrity (dims + palette), state machine priorities (victory on landed work), working-activity rotation, and beat-timeline frame picks
$(BUN) run desktop/scripts/demo_p_mascot_1.ts
.PHONY: demo-P-MASCOT.2
demo-P-MASCOT.2: ## P-MASCOT.2: the prompt-bar parkour mini ninja - route order (run/climb/sneak/pause/drop/rest), lane geometry, the silent-drop clip contract, gravity easing, direction alternation
$(BUN) run desktop/scripts/demo_p_mascot_2.ts
.PHONY: demo-P-MASCOT.4
demo-P-MASCOT.4: demo-P-MASCOT.1 demo-P-MASCOT.2 ## Themed palettes, expressive eyes, new activities, Regular/Max tiers, the run-only arcade, and shared LUCID points
$(BUN) test ./desktop/renderer/mascot.test.ts ./desktop/renderer/mascot_game.test.ts ./desktop/renderer/agent_flow.test.ts ./desktop/renderer/trivia.test.ts
$(BUN) run desktop/scripts/demo_p_avatar_4.ts
.PHONY: demo-P-MASCOT.5
demo-P-MASCOT.5: demo-P-MASCOT.4 ## Arcade-parity prompt-bar runner (2x sprite, no-slip stride) + the game cabinet (Shuriken range, Kata memory, Rooftop stack) + titlebar/panel mis-click guards
$(BUN) test ./desktop/renderer/mascot_runner.test.ts ./desktop/renderer/mascot_minigames.test.ts
$(BUN) run desktop/scripts/demo_p_mascot_5.ts
.PHONY: demo-P-SEASON.1
demo-P-SEASON.1: ## P-SEASON.1 (ADR-0525): U.S. holiday + event-month special themes - the calendar (nth weekdays, Easter, year-spanning windows, peak-day precedence), 16 special palettes held to the token contract, 16 animated backdrops valid at any t/size/season, 21 mascot acts + costumes, flush eye band, 16-beat no-slip gait, hover hop + click leap
$(BUN) test ./desktop/renderer/seasons.test.ts ./desktop/renderer/theme.test.ts ./desktop/renderer/scenes/scenes_paint.test.ts ./desktop/renderer/mascot_season.test.ts ./desktop/renderer/mascot.test.ts ./desktop/renderer/mascot_runner.test.ts ./desktop/renderer/boot_cinematic.test.ts
.PHONY: demo-P-MODEL.10
demo-P-MODEL.10: ## P-MODEL.10 (ADR-0526): omp 18.18.6 with Claude Fable 5.2 / Mythos 5.2 - six packages pinned together, NativeJudge migration, R-07 at 92 ids, 8/40 USD per Mtok version-anchored price row, 1M windows, picker cards, frozen prefix still byte-stable
$(BUN) test $(TEST_IGNORES) harness/prompt/prefix_compaction.test.ts harness/omp/provider_catalog.test.ts harness/omp/judgment_extension.test.ts desktop/model_pricing.test.ts desktop/renderer/model_families.test.ts desktop/packaged_boot.test.ts
$(BUN) run harness/scripts/demo02_prefix_hash.ts
.PHONY: demo-P-BOOTPERF.1
demo-P-BOOTPERF.1: ## P-BOOTPERF.1 (ADR-0527): the renderer's boot burst never blocks the engine's event loop - async sessions/usage/code-activity/compaction-policy/omp probe, cached workspace bar, self-healing Reconnect button (a dead engine keeps it)
$(BUN) test $(TEST_IGNORES) desktop/omp_bin.test.ts desktop/renderer/turn_restore.test.ts desktop/sessions_index.test.ts desktop/sessions_ingest.test.ts harness/usage_ledger.test.ts harness/code_activity.test.ts
$(BUN) run desktop/scripts/demo_p_perf_4.ts
$(BUN) run harness/scripts/demo_pcode1.ts
.PHONY: demo-P-FLEET.FIT1
demo-P-FLEET.FIT1: ## P-FLEET.FIT1 (ADR-0528): fleet lanes autofit the dock in both directions at equal sizes (on by default, header toggle), refit on resize/spawn/close, a card-edge drag shares the rest equally, double-click resets
$(BUN) test $(TEST_IGNORES) desktop/renderer/lane_layout.test.ts
.PHONY: demo-P-PUSH.PAR1
demo-P-PUSH.PAR1: ## P-PUSH.PAR1 (ADR-0529): staged-chip copy menu (right-click / long-press) + Push now runs the prompt in a parallel lane on its own git worktree (main-checkout mapping, unique <source>-push-<n> names, preamble, dequeue only on acceptance, text-guarded remove, no-repo steer fallback)
$(BUN) test $(TEST_IGNORES) desktop/renderer/queue_model.test.ts desktop/renderer/ctxmenu.test.ts desktop/lane_worktree.test.ts desktop/fleet_lanes.test.ts
.PHONY: demo-P-PRIVAI.1
demo-P-PRIVAI.1: ## P-PRIVAI.1 (ADR-0530): the DGX Loader is now the Private AI Platform - the renderer bundle carries "Import from the Private AI Platform" and no "DGX Loader", while the /^dgx-loader\b/i enclave attestation regex and the dgx-avatar/dgx-cad/dgx-vision provider ids stay
$(BUN) run desktop/scripts/demo_p_privai_1.ts
$(BUN) test $(TEST_IGNORES) desktop/creator_probe.test.ts desktop/creator_mailbox.test.ts desktop/creator_registry.test.ts desktop/cui_policy.test.ts
.PHONY: demo-P-RUNTIME-PY.1
demo-P-RUNTIME-PY.1: ## P-RUNTIME-PY.1 (ADR-0548): the bundled CPython moves to python-build-standalone 20261026 (3.12.16, OpenSSL 3.5.9); fetch-runtimes runs it and refuses a tree that is not PY_VERSION or whose OpenSSL is below PY_OPENSSL_MIN
$(BUN) test $(TEST_IGNORES) desktop/build/python_floor.test.ts
cd desktop && $(BUN) run build/fetch-runtimes.ts
.PHONY: demo-P-AVATAR.4
demo-P-AVATAR.4: ## P-AVATAR.4 (ADR-0251): the LUCID Agent enter flow - fast-model preference order (Terra > Sonnet 5 > Flash, no pointless switch), one-gap-at-a-time readiness (provider > tts > stt), the one-time KG offer, exit model restoration
$(BUN) run desktop/scripts/demo_p_avatar_4.ts
.PHONY: demo-P-AVATAR.5
demo-P-AVATAR.5: ## P-AVATAR.5 (ADR-0251): voice tool approval - keyword-strict grammar (sentences never match), danger class demands the literal word after a spoken repeat-back, widening grants unreachable by voice, deny always easy
$(BUN) run desktop/scripts/demo_p_avatar_5.ts
.PHONY: demo-P-AVATAR.6
demo-P-AVATAR.6: ## P-AVATAR.6 (ADR-0251): the boot cinematic - real-signal stage lines, min-beat + hard-cap done gate (config-gated; voice/models never hold boot), ninja sprint choreography
$(BUN) run desktop/scripts/demo_p_avatar_6.ts
.PHONY: demo-P-REMOTE.12
demo-P-REMOTE.12: ## P-REMOTE.12 (ADR-0251): PWA push-to-talk - fail-closed PromptAudio validator (shape/mime/size/base64, both ends), audio-only guest prompts, additive frame compatibility
$(BUN) run desktop/scripts/demo_p_remote_12.ts
.PHONY: demo-P-REMOTE.13
demo-P-REMOTE.13: ## P-REMOTE.13 (ADR-0251): the invisible hourly reconnect - grace-window presentation (young flap = Live, real outage surfaces, terminal never masked); the 60-min cap + hourly re-verify stay
$(BUN) run desktop/scripts/demo_p_remote_13.ts
.PHONY: demo-P-REMOTE.16
demo-P-REMOTE.16: ## P-REMOTE.16 (ADR-0431): the phone resumes with exactly what it missed - REAL gated relay + host + socket + guest + viewer + history. Fresh join gets rich seq turns (thinking, edit with code, ok/elapsed, +/-); the diff drilldown renders with hostile code escaped; on-device history round-trips, rejects another room, stores nothing under CUI; an unlock with since=2 receives only seq 3 + the in-flight seq 4 and merges without duplicates; a planned pre-cap rotation re-hellos, replays nothing, keeps the guest live; a short-absence probe is answered by the relay pong
$(BUN) run harness/scripts/demo_premote16.ts
$(BUN) test $(TEST_IGNORES) desktop/collab/turn_journal.test.ts desktop/collab/host.test.ts desktop/collab/guest.test.ts desktop/collab/pwa_view.test.ts desktop/collab/pwa_history.test.ts desktop/collab/relay_client.test.ts desktop/collab/relay_server.test.ts
.PHONY: demo-P-GOVCUI.1
demo-P-GOVCUI.1: ## P-GOVCUI.1: first-run Government/CUI step - asks once if the user is a Government/GovCon user handling CUI; a "yes" walks a novice into the CUI-safe posture (AskSage gov gateway in LOCKDOWN) with the CIV routing endpoint PREFILLED + step-by-step token instructions. Pure core: decideGovOnboarding (ask/skip/auto-enable, exactly once; org-forced routing auto-enables) + planGovSetup (with a key -> CIV persisted + lockdown ON; no key -> endpoint prefilled but lockdown NEVER flipped, since a keyless lockdown leaves no gov model and the backend fail-closes)
$(BUN) run harness/scripts/demo_pgovcui1.ts
demo-P-NETDIAG.1: ## P-NETDIAG.1 (ADR-0090): in-app OAuth localhost-callback watcher - netstat/lsof parse, keeps loopback + all-interface listeners, flags a new callback-port listener as the bind-or-not evidence, read-only diagnostics (no gate verdict)
$(BUN) run desktop/scripts/demo_p_netdiag_1.ts
demo-P-TOOLFAIL.1: ## P-TOOLFAIL.1 (ADR-0093): honest failed/rejected tool-call chip - distinguishes ran-and-errored (failed) from did-not-run (rejected/unavailable), surfaces omp's own message, never implies a security denial
$(BUN) run desktop/scripts/demo_p_toolfail_1.ts
demo-P-EGRESS.2: ## P-EGRESS.2 (ADR-0094): a local-file browser open is labeled a local-file open (open-once/block, no host pin) not a website visit, http(s) egress unchanged, and the no-listener block is audited (folds in P-ENT.3)
$(BUN) run desktop/scripts/demo_p_egress_2.ts
demo-P-LOC.3: ## P-LOC.3 (ADR-0095): the AI-authored code ledger is discoverable (command-palette entry) and never silently vanishes (always rendered when a session is active, with an explicit empty state)
$(BUN) run desktop/scripts/demo_p_loc_3.ts
.PHONY: demo-P-LOC.4
demo-P-LOC.4: ## P-LOC.4 (ADR-0211): AI-authored lines reach the UI again - the gate holds agent_obs.duckdb read-write for the whole session, so the desktop's READ_ONLY aiLocSummary() lock-failed -> null -> "none yet" despite rows in the DB. Fix (mirrors turns/security/latency logs): the desktop appends every edit to a GUI-owned JSONL it can read live (same linediff count as the chat chip); the dashboard aggregates that lock-free. Proves count (write/edit/patch) + record (no-op on 0 lines) + read/aggregate roll-up + empty-null
$(BUN) run desktop/scripts/demo_p_loc_4.ts
.PHONY: demo-P-LOC.5
demo-P-LOC.5: ## P-LOC.5 (ADR-0451): completion-only AI-LOC from real gated omp tools, canonical edit previews, actual diff counts
$(BUN) run desktop/scripts/demo_p_loc_5.ts
demo-P-PREVIEW.1: ## P-PREVIEW.1 (ADR-0096): in-app browser preview - resolver renders local files the agent builds, gates remote (egress, P-PREVIEW.3), blocks the ambiguous; panel + screenshot-to-chat seam
$(BUN) run desktop/scripts/demo_p_preview_1.ts
demo-P-PREVIEW.2: ## P-PREVIEW.2 (ADR-0096): auto-surface the agent's freshly-written app - a write/edit of a previewable file (.html/.svg) lights up the Preview panel; reads + non-page writes never do
$(BUN) run desktop/scripts/demo_p_preview_2.ts
demo-P-PREVIEW.3: ## P-PREVIEW.3 (ADR-0096): hardened preview sandbox - opaque-origin <iframe> (scripts on, same-origin off), no escape tokens, all powerful features denied
$(BUN) run desktop/scripts/demo_p_preview_3.ts
demo-P-PREVIEW.3b: ## P-PREVIEW.3b (ADR-0096): a remote URL previews only through the egress gate - loads iff egress-approved AND https, opaque-origin; else stays gated (agent requests via egress flow)
$(BUN) run desktop/scripts/demo_p_preview_3b.ts
demo-P-PREVIEW.3a: ## P-PREVIEW.3a (ADR-0096): agent-invoked preview_open tool (read-tier, real TSchema) - registration never breaks omp, execute gates local .html/.svg, acp_backend drives the panel off the call title (live omp+Electron verifies invocation)
$(BUN) run desktop/scripts/demo_p_preview_3a.ts
demo-P-ENT.4: ## P-ENT.4 (ADR-0069): every per-action gate denial is auditable + attributed - explicit "denied by you" vs "fail-closed (turn ended / no response)"; closes the silent fail-closed-timeout gap
$(BUN) run desktop/scripts/demo_p_ent_4.ts
demo-P-GATE-DIAG.1: ## P-GATE-DIAG.1 (ADR-0066/0062): dev-mode diagnostics recording the interactive-check inputs + decision for every exec/egress permission request (Logs → Exec / egress gate decisions) — reveals WHY a tool was auto-denied with no prompt
$(BUN) run desktop/scripts/demo_p_gate_diag_1.ts
demo-P-PREVIEW.4: ## P-PREVIEW.4 (ADR-0096): RENDER local files in Preview via served-content + iframe srcdoc (Chromium blocks file:// from an http origin, so iframe.src=file:// never rendered)
$(BUN) run desktop/scripts/demo_p_preview_4.ts
demo-P-PREVIEW.4b: ## P-PREVIEW.4b (ADR-0096): serve the preview with its OWN per-frame CSP (iframe.src, not srcdoc) so the app's inline scripts RUN - a srcdoc frame inherits script-src 'self' and blocked them; connect-src 'none' still blocks egress
$(BUN) run desktop/scripts/demo_p_preview_4b.ts
demo-P-PREVIEW.3a-shot: ## P-PREVIEW.3a-shot (ADR-0096): the agent SEES its own UI - renderer caches a preview PNG, the preview_screenshot tool fetches it as ImageContent (read-tier); every failure path degrades to text
$(BUN) run desktop/scripts/demo_p_preview_3a_shot.ts
demo-P-PREVIEW.4c: ## P-PREVIEW.4c (ADR-0096): MULTI-FILE apps render by inlining their own relative css/js/img/fonts (link→style, script src→inline, img/url→data:) under the SAME frame CSP; remote/traversal refs refused
$(BUN) run desktop/scripts/demo_p_preview_4c.ts
.PHONY: demo-P-CHAT.1
demo-P-CHAT.1: ## P-CHAT.1 (ADR-0104): inline expandable code preview for tool steps - writes syntax-highlighted (Monaco), edits as green/red line diffs; proves the pure diff logic
$(BUN) run desktop/scripts/demo_p_chat_1.ts
.PHONY: demo-P-FS.1
demo-P-FS.1: ## P-FS.1 (ADR-0103): full-tree workspace folder browser - browse above home to the FS root / drives, with an optional managed workspaceRoots confinement
$(BUN) run desktop/scripts/demo_p_fs_1.ts
.PHONY: demo-P-FS.2
demo-P-FS.2: ## P-FS.2 (ADR-0253/0254): the browser build opens the REAL OS folder dialog through the local backend (modern Explorer picker, marker-anchored parse, escaped/argv-passed titles, cancel never re-prompts) + the frozen data-integration steer (prefix v10) routes prompt-stuffed datasets to MCP / RAG / secure vendor connections
$(BUN) test desktop/native_dialog.test.ts harness/prompt/assembler.test.ts
.PHONY: demo-P-NETWL.1
demo-P-NETWL.1: ## P-NETWL.1 (ADR-0106): curated network whitelist (domain wildcards + IP CIDR, internal/external, trust scopes) auto-allows egress under the managed ceiling; OS-encrypted credential vault fail-closes with no plaintext
$(BUN) run desktop/scripts/demo_p_netwl_1.ts
.PHONY: demo-P-NETWL.3
demo-P-NETWL.3: ## P-NETWL.3 (ADR-0106): enforce project/loop trust scopes + per-loop call budget (first N auto-allow, then block), all under the managed ceiling
$(BUN) run desktop/scripts/demo_p_netwl_3.ts
.PHONY: demo-P-KEYS.2
demo-P-KEYS.2: ## P-KEYS.2 (ADR-0107): credential rotation visibility (age/due/expiry, non-secret) + manual rotate-in-place (same ref, fail-closed)
$(BUN) run desktop/scripts/demo_p_keys_2.ts
.PHONY: demo-P-PERF.2
demo-P-PERF.2: ## P-PERF.2 (ADR-0129): power/spec-aware perf tiers — battery→calm capped graph, low battery→viz paused (agent access untouched), poll backoff, user override
$(BUN) run desktop/scripts/demo_p_perf_2.ts
.PHONY: demo-P-PERF.3
demo-P-PERF.3: ## P-PERF.3 (ADR-0130): KG layout continuity — re-open is a static paint (0 sim frames), refresh nestles newcomers, cold open exits on energy, positions never touch disk
$(BUN) run desktop/scripts/demo_p_perf_3.ts
.PHONY: demo-P-PERF.4
demo-P-PERF.4: ## P-PERF.4 (ADR-0131): incremental session index (warm polls parse nothing) + tail-first transcript pages + AC-only prefetch gate
$(BUN) run desktop/scripts/demo_p_perf_4.ts
.PHONY: demo-P-SETTINGS.1
demo-P-SETTINGS.1: ## P-SETTINGS.1 (ADR-0439): settings are never silently wiped - atomic temp+fsync+rename save with a last-good .bak; a corrupt file is kept aside and restored from the backup, never read as an empty profile. Real processes: 25 hard kills of a saving writer, a concurrent reader never sees a torn file, the 2026-10-05 0-byte file keeps the Windows sandbox opt-out
$(BUN) run desktop/scripts/demo_p_settings_1.ts
$(BUN) test $(TEST_IGNORES) desktop/settings_store_atomic.test.ts
.PHONY: demo-P-PERF.5
demo-P-PERF.5: ## P-PERF.5 (ADR-0132): switch hygiene - optimistic model switch, debounced lastModel write-behind (read-your-writes), memoized settings load, memoized picker
$(BUN) run desktop/scripts/demo_p_perf_5.ts
.PHONY: demo-P-NETWL.5
demo-P-NETWL.5: ## P-NETWL.5 (ADR-0108): egress posture — allow-all + web-search toggles; whitelist enforces only when allow-all is off; still prompts for public IPs / foreign TLDs; managed clamp
$(BUN) run desktop/scripts/demo_p_netwl_5.ts
.PHONY: demo-P-AGENT.1
demo-P-AGENT.1: ## P-AGENT.1 (ADR-0133): Agent Spec — a valid v1 DAG round-trips through DuckDB (migration 0010); a cyclic/invalid spec is refused fail-closed and never persisted
$(BUN) run harness/scripts/demo_p_agent_1.ts
.PHONY: demo-P-AGENT.3
demo-P-AGENT.3: ## P-AGENT.3 (ADR-0133): the compiler buildAgent(spec) -> AgentBundle (system prompt + generated omp allow-list extension + manifest); the emitted extension enforces the allow-list; invalid spec refused
$(BUN) run harness/scripts/demo_p_agent_3.ts
.PHONY: demo-P-AGENT.5
demo-P-AGENT.5: ## P-AGENT.5 (ADR-0133): untrusted-spec quarantine gate vs the real scanner — imported/poisoned specs are quarantined + blocked from auto-running; only a clean local spec is trusted + runnable
$(BUN) run harness/scripts/demo_p_agent_5.ts
.PHONY: demo-P-AGENT.6
demo-P-AGENT.6: ## P-AGENT.6 (ADR-0133): enterprise export — package a compiled agent portably for electron/web/cloud with a tamper-evident content digest; verifyExport catches modification
$(BUN) run harness/scripts/demo_p_agent_6.ts
.PHONY: demo-P-AGENT.4-live
demo-P-AGENT.4-live: ## P-AGENT.4-live (ADR-0133): run a BUILT agent on a REAL Claude model (Haiku). NEEDS a model + network — NOT part of `make test`. Proves the agent runs + follows its compiled spec, AND its allow-list extension hard-blocks disallowed tools.
$(BUN) run harness/scripts/demo_p_agent_4_live.ts
$(BUN) run harness/scripts/demo_p_agent_4_live_enforce.ts
.PHONY: demo-P-AGENT.8.1
demo-P-AGENT.8.1: ## P-AGENT.8.1 (ADR-0134): secret guardrail — agents DECLARE credential names (SecretRef); a secret VALUE embedded in a spec is refused at compile + save (secrets belong in the vault)
$(BUN) run harness/scripts/demo_p_agent_8_1.ts
.PHONY: demo-P-AGENTFW.1
demo-P-AGENTFW.1: ## P-AGENTFW.1 (ADR-0147): agent-firewall MCP \u2014 scans both directions vs a remote ACP agent (hermes/openclaw); quarantines poisoned replies, neutralizes delimiter breakout, blocks outbound hidden vectors, fails closed when the scanner dies
$(BUN) run harness/scripts/demo_pagentfw1.ts
.PHONY: demo-P-FLEET.1
demo-P-FLEET.1: ## P-FLEET.1 (ADR-0268): async job handles through the agent-firewall - dispatch/job_status/cancel + bounded-wait prompt over ONE gated path; fan-out across connections, serialization within one, fail-closed per job, deadline cleanup, idempotent retries
$(BUN) run harness/scripts/demo_pfleet1.ts
.PHONY: demo-P-FLEET.L1
demo-P-FLEET.L1: ## P-FLEET.L1 (guard evolved by P-FLEET.L2): local lanes - concurrent gated headless LUCID agents under the sustained-pressure guard (a burst is free, a held line is not), fail-closed approvals (needs-approval glow), cancel/stop hygiene, metadata-only fleet status for the master agent
$(BUN) run harness/scripts/demo_pfleetl1.ts
.PHONY: creator-backend-plan
creator-backend-plan: ## Print the exact commands the Creator-backend setup would run against a remote GPU host, executing NOTHING (pass your host: make creator-backend-plan HOST=gpu-box USER=me). Then drop --dry-run to do it for real.
$(BUN) run tools/creator-backend/setup-backend.ts --host $(or $(HOST),gpu-box) $(if $(USER_AT),--user $(USER_AT),) --dry-run
.PHONY: verify-creator-comfy
verify-creator-comfy: ## CREATOR-1/IMG verification: drives the REAL product code (probe -> capability attestation -> upload -> substitute -> submit -> poll -> read back -> store) against a ComfyUI-shaped fixture, so the whole path is provable with no ComfyUI, no GPU and no network. Point it at your own server with: bun run harness/scripts/verify_creator_comfy.ts --url http://host:8188 --workflow ./graph.json
$(BUN) run harness/scripts/verify_creator_comfy.ts
.PHONY: demo-CREATOR-5
demo-CREATOR-5: ## CREATOR-5 (ADR-0289): the mixer - N takes played AT ONCE and summed to one file, where two layers are the EXACT arithmetic sum at every frame, the same graph renders byte-identical audio twice, and a track silenced by mute, by another track's solo, or by a muted bus contributes exactly nothing (byte-identical to the same graph with that track REMOVED, with the reason named). Clip x track x bus x master levels multiply to a predicted sample, fades and envelopes are half their level at their midpoints, equal-power pan holds total power at 1, and a hot mix REPORTS its true peak and every clipped sample instead of quietly normalizing: headroom is applied only when the caller asks and the exact gain comes back. A missing source and a rate mismatch are refused by name, an edited CREATOR-2 timeline lifts onto a mix track, and a saved mix is a NEW remix naming every input while its inputs keep every byte. A library holding nothing decodable claims NO format at all, which the pane's shape gate accepts as honest while refusing half a format, and the render answer is pinned key for key: every measurement present (clipped 0 included), the headroom factor only when it was asked for, and a refusal carrying its reason and nothing it never measured
$(BUN) run harness/scripts/demo_creator5.ts
.PHONY: demo-CREATOR-3
demo-CREATOR-3: ## CREATOR-3 (ADR-0287): the video and 3D pipelines, end to end. A capability no LIVE probe attested is refused before one byte leaves the machine (and an expired probe attests nothing, so staleness refuses through the same gate); a governor refusal is a written-down `refused` job quoting the percent and the duration it held; a workflow with an unfilled placeholder is never submitted. An artifact's type comes from its own MAGIC BYTES, so a server claiming video/mp4 while sending PNG has its output refused by name and stores nothing. THE SCAN GATE IS FAIL-CLOSED: a dead scanner, a quarantining finding, or a malformed verdict each BLOCK the artifact before it touches the disk, and the job says which. Video and 3D outputs are read by output key and extension (an animated webp is a video, not a still), the /ws stream is telemetry that cannot hang, revive, or corrupt a render (a foreign prompt id, a truncated binary frame and a silent socket are all proven harmless), frame capture is reproducible or reports which of the two ways it lied, Blender runs as a fixed argv with no shell and quotes its own failing line, and a model manifest stays a claim until the probe agrees. Four sections run the REAL product code against a REAL server process over real HTTP and a real websocket
$(BUN) run harness/scripts/demo_creator3.ts
.PHONY: demo-CREATOR-2
demo-CREATOR-2: ## CREATOR-2 (ADR-0286): the follow-along audio editor - alignment DERIVED from the take's own energy is labeled derived and capped below vendor confidence with the reason shown verbatim, a deleted word closes the timeline by exactly its span (and the render's byte length follows), a dragged span re-orders audio without creating or destroying a sample, and a re-rendered span changes ONLY the bytes inside it (the audio before and after comes back byte for byte), with undo re-rendering to the original file, a deterministic render, and a missing source refused BY NAME instead of substituted with silence
$(BUN) run harness/scripts/demo_creator2.ts
.PHONY: demo-CREATOR-1
demo-CREATOR-1: ## CREATOR-1 (ADR-0292): capability PROBES (ComfyUI from its installed nodes, ElevenLabs from its documented model flags, a user-run service proves reachability and admits nothing more, a desktop app proves it is on disk) that turn registry `configured` into a truthful `ready` and EXPIRE, plus the durable job ledger - legal transitions only, the governor's measurement recorded per job, a refusal written down with its reason, and a cancel that is a request until the runner confirms
$(BUN) run harness/scripts/demo_creator1.ts
.PHONY: demo-CREATOR-IMG
demo-CREATOR-IMG: ## CREATOR-IMG (ADR-0291): sprite sheets, animated GIFs, and memes encoded INSIDE LUCID (valid PNG chunks, an LZW stream that decodes back to its own indices, text that always fits), a model dropdown that is a live probe of the user's own ComfyUI install, a workflow with an unfilled placeholder REFUSED rather than guessed, and artifacts that carry the prompt/model/sha256 that produced them
$(BUN) run harness/scripts/demo_creator_img.ts
.PHONY: demo-CREATOR-0
demo-CREATOR-0: ## CREATOR-0 (ADR-0279..0284, ADR-0304): the Creator flavor - a second LUCID on its own identity/port/data root, Creator Mode gated to that build with AGENT security semantics, an honest integration registry (Suno generation is bring-your-own-endpoint, ElevenLabs Studio editing is vendor-app-only), evidence-based CPU/GPU admission where unknown is never idle, a local track library (listen/review/remix/re-prompt) that needs no provider API, and a release channel that cannot be crossed with Agent's in either direction (Creator updates from its own fixed-URL feed, and no Creator release can move the repo pointer Agent's installed base resolves through)
$(BUN) run harness/scripts/demo_creator0.ts
.PHONY: demo-P-FLEET.L2
demo-P-FLEET.L2: ## P-FLEET.L2 (ADR-0273): UNLIMITED lanes gated only by SUSTAINED pressure (90% held 30s - a burst never refuses, a blind sample never counts as load, no evidence fails open), lanes spawned from real GitHub/GitLab/Azure DevOps remotes via the OS folder dialog, per-HOST credentials in the OS-encrypted vault (scoped ref -> env round-trip, never offered cross-host, rides an Authorization header not the URL, redacted from errors), and the minimized status-bar snapshot (one colored dot + count per lane state, needs-approval first)
$(BUN) run harness/scripts/demo_pfleetl2.ts
.PHONY: demo-P-FLEET.L3
demo-P-FLEET.L3: ## P-FLEET.L3 (ADR-0274): lane FIDELITY - a write/edit tool call's authored code crosses the lane wire as a structured payload (P-CHAT.1 rawInput contract, path resolved against the LANE's cwd) so cards render real diff chips; pasted images ride as ACP image blocks exactly like the master chat (replay memory keeps the COUNT, never the base64); and staged prompts wait in a capped manager-owned FIFO per lane (reorder/remove, drained in order when idle, refused loudly at 8, never crossed into a busy lane)
$(BUN) run harness/scripts/demo_pfleetl3.ts
.PHONY: demo-P-FLEET.L4
demo-P-FLEET.L4: ## P-FLEET.L4 (ADR-0274): lanes that SURVIVE - no lane turn clock (a mid-turn child crash lands error in milliseconds, event-driven, never a 600s deadline), error is a recoverable state (Retry re-sends the last prompt, Respawn revives IN PLACE on the same lane id with the transcript carried - capability-gated session/load when the agent offers it, delimited-transcript preamble otherwise), fail-closed survives recovery (an ask open at death dies as a DENY and the revived lane RE-ASKS a human), and a user-stopped lane is refused by prompt but revived by explicit respawn with memory intact
$(BUN) run harness/scripts/demo_pfleetl4.ts
.PHONY: demo-P-FLEET.L5
demo-P-FLEET.L5: ## P-FLEET.L5 (ADR-0274): histories + the reviewable TIMELINE - every lane spawn/recovery NAMES its omp session in a durable JSONL ledger (~/.omp/lucid-fleet-lanes.jsonl), so the .jsonl histories omp already persists become attributable; one timeline surface merges master chats + lane sessions + kg-ingest throwaways across EVERY workspace, newest first, lanes labeled with their names (latest ledger record wins); a stopped lane's transcript still opens (review is an index over existing files, never a second recording); torn ledger lines skip and a missing ledger degrades labels, never the surface
$(BUN) run harness/scripts/demo_pfleetl5.ts
.PHONY: demo-P-AOS.1
demo-P-AOS.1: ## P-AOS.1 (ADR-0452): one standing fleet goal (AOS-1) with a mandatory budget, a heartbeat any observer reads as alive / late / dead, stalled spokes reaped, spend since the start blocking at the cap, human-verified criteria achieving the goal, durable across restarts.
$(BUN) run harness/scripts/demo_paos1.ts
$(BUN) test $(TEST_IGNORES) desktop/aos.test.ts desktop/fleet_goal.test.ts
.PHONY: demo-P-AOS.2
demo-P-AOS.2: ## P-AOS.2 (ADR-0453): tasks under the fleet goal - a deliverable and a check required, the heartbeat dispatches one task per spoke in dependency order, command checks verified in a separate fail-closed turn, retries with the reason up to the limit, human review completes a task, restart never strands one mid-turn.
$(BUN) run harness/scripts/demo_paos2.ts
$(BUN) test $(TEST_IGNORES) desktop/aos.test.ts desktop/fleet_goal.test.ts
.PHONY: demo-P-STEPTEXT.1
demo-P-STEPTEXT.1: ## P-STEPTEXT.1: narration resumed after a tool call starts a new paragraph (master + lanes, stream and saved answer), the answer's tool chips interleave between the steps again, and a subagent row names a looping model ("model output degenerated") instead of painting "!!!!", with a scout's structured yield shown as its final step.
$(BUN) run harness/scripts/demo_psteptext1.ts
.PHONY: demo-P-FLEET.L7
demo-P-FLEET.L7: ## P-FLEET.L7: lane tool-call FIDELITY + a transcript that survives its own stream - a code-less call (bash/read/search) now carries the bounded, code-stripped rawInput so "the command used" is drillable (before L7 the chevron had literally nothing to open), an edit still carries `code` and never a duplicate `input`, hasBody and laneChipBody agree BY CONSTRUCTION so a dead chevron is impossible, a lane chip DELEGATES kind/detail/diffstat to the same answer_chips.toolChip the master composer uses (the two surfaces cannot disagree), ids are monotone and never reused (the precondition for patching DOM instead of the innerHTML-per-token rebuild that destroyed mid-stream text selection and slammed every open tool call shut), an oversized command or diff is clipped AND SAYS SO, and the lane forwards omp's MEASURED context/window/cost while inventing no output figure
$(BUN) run harness/scripts/demo_pfleetl7.ts
.PHONY: demo-P-FLEET.L8
demo-P-FLEET.L8: ## P-FLEET.L8: promote a fleet lane into the MAIN composer and pull it back - promotion is an ATTACH, not a handoff (the lane's omp child, ACP session id, cwd, and model are byte-identical before and after), which is the only design that works MID-TURN and makes demote instant; a `working` lane promotes with NO refusal because switching on the fly is the ask, while stopped/error refuse naming respawn and an UNKNOWN status refuses fail-closed; exactly one lane may hold the composer (a second promote releases the first); promote and demote each write a durable ledger line naming the lane, folder, MODEL AT THAT MOMENT, and turns carried, so a stretch driven from the main chat is never indistinguishable from lane work; and the composer is seeded from the lane's transcript with tool bookkeeping folded to one note and the prose byte-preserved
$(BUN) run harness/scripts/demo_pfleetl8.ts
.PHONY: demo-P-FLEET.L10
demo-P-FLEET.L10: demo-P-FLEET.L8 ## P-FLEET.L10 (runs with P-FLEET.L8): DISMISS a lane so its card leaves the grid. `stop` only PARKED a lane (transcript readable, respawnable in place) and nothing removed it from the map, so a finished lane held a grid column until the whole app restarted. The close button is now a two-step gesture: stop, then dismiss, because one click must never be able to destroy work in flight - a mid-turn dismissal is REFUSED with the fix named. Dismissing a PROMOTED lane releases the composer first, or the main composer strands on a lane id that no longer resolves and every later prompt fails with "unknown lane". Dismissal is idempotent, drops the in-memory transcript, and the lane's durable ledger line SURVIVES, so a dismissed lane is still labeled and openable on the timeline (P-FLEET.L5: review is an index over files omp already persists, never a second recording)
.PHONY: demo-P-HEALTH.1
demo-P-HEALTH.1: ## P-HEALTH.1: the harness watches its OWN sessions so a stalled long run never needs the whole app restarted - the ok/quiet/probe/recover ladder with inclusive thresholds, an idle session always ok, and the LOAD-BEARING refusal: an OPEN TOOL CALL caps the verdict at `quiet` at 3min, 7min, 30min, and 10 HOURS (ADR-0263 deleted the wall-clock cutoff because it killed exactly the turns worth running, and nothing here reintroduces one), with only a DEAD child overriding because that is evidence rather than a guess; bounded attempts mean no nag loop and no respawn loop (past the budget it SAYS it stopped trying), any real activity restores the budget, an unreadable clock authorizes nothing (NaN/Infinity/negative all yield ok even with a dead child), the probe is an operator note that asks for status AND says to continue so it can never read as a stop order, and LIVE a real lane keeps its id/turns/transcript while a lane the USER stopped is never auto-revived
$(BUN) run harness/scripts/demo_phealth1.ts
.PHONY: demo-P-HEALTH.2
demo-P-HEALTH.2: demo-P-HEALTH.1 ## P-HEALTH.2 (runs with P-HEALTH.1): a recovered session now RESUMES THE RUN the recovery interrupted. P-HEALTH.1's `recover` reloads the same session id so the conversation survives, but dropping the omp child rejects the in-flight session/prompt, so the turn printed "[agent unavailable]" and settled: the session was healthy again and the WORK was gone, with nothing telling the user which, so they still had to notice the stall and re-ask. The run is now re-sent on the recovered session with a short operator note (do NOT start over, re-read and verify any file you were part-way through writing) and the user is told plainly that the stalled session is restarting and picking up where it left off. The refusals are the design: a user STOP is never resumed (Stop means stop), one mark authorizes exactly ONE resume so a repeat failure cannot reuse it, a session that failed to reload is never resumed rather than talking to a phantom, and the budget is per RUN and NOT refilled by activity - so wedge/resume/wedge/resume/wedge STOPS and says the work so far is saved, even though that same activity deliberately refills the health episode's own probe/recover budget.
$(BUN) run harness/scripts/demo_phealth2.ts
.PHONY: demo-P-HEALTH.3
demo-P-HEALTH.3: demo-P-HEALTH.2 ## P-HEALTH.3: a model writing a large tool call is not a stall. omp's ACP mapper drops toolcall_start/toolcall_delta, so a long write reached the desktop as minutes of silence with no tool call open and the watchdog probed ("Status?") and then cancelled and respawned a healthy session (incident 20260930T022224Z-mlnj). harness/omp/stream_beat_extension.ts posts a throttled beat carrying the omp session id while arguments stream; the engine credits it only to the master turn or busy lane with that id (no id, no beat). A successful self-heal no longer leaves chat chips; only a run that did not continue on its own (needsUser) does.
$(BUN) test $(TEST_IGNORES) harness/omp/stream_beat_extension.test.ts desktop/health_watch.test.ts
.PHONY: demo-P-TOKENS.1
demo-P-TOKENS.1: ## P-TOKENS.1 / P-FLEET.L9: the token-spend accounting behind the fleet card's context-fill chip (the composer popover it was first built for was removed at the user's request, ADR-0315; the module stays because each lane card folds its own usage and reads meterBadge for the value and the escalation thresholds) - the central assertion is NEGATIVE: omp reports only context fill, window, and cost, so a metric that never arrived reads "not reported", never a plausible $0.00 or 0 tokens a user would budget against. A REPORTED zero renders $0.00 and stays measured because a reported zero is a fact while an unreported one is an invention; every output row is unmeasured with a hint containing "estimate"; per-call context delta is ATTRIBUTION that says so when unbracketed rather than showing 0; 70 calls keep the newest 60 and no reducer mutates its input. Plus the geometry: dragging a card's BOTTOM edge DOWN grows it (the grip follows the cursor, cards top-anchored so the row holds still), the dock's north edge keeps its BOTTOM edge pinned even once height pins at the minimum, 7 corrupt saved layouts degrade to empty without throwing, and resizeShape composes with share_dock's viewport clamp
$(BUN) run harness/scripts/demo_ptokens1.ts
.PHONY: demo-P-MCP-GATE.1
demo-P-MCP-GATE.1: ## P-MCP-GATE.1 (ADR-0148): in-process MCP tool_result gate — poisoned MCP result withheld, clean result delimited+labeled untrusted, LOCAL tool results untouched (source-scoped), fail-closed
$(BUN) run harness/scripts/demo_pmcpgate1.ts
.PHONY: demo-P-LOCAL.1
demo-P-LOCAL.1: ## P-LOCAL.1 (ADR-0135): Local Providers — declare a self-hosted / custom OpenAI-compatible LLM (Ollama, llama.cpp, vLLM, DGX-over-VPN); validate fail-closed, emit the omp --config overlay (secret from the vault, skipped if absent), persist WITHOUT the secret
$(BUN) run desktop/scripts/demo_p_local_1.ts
.PHONY: demo-P-VISION.1
demo-P-VISION.1: ## P-VISION.1 (ADR-0136): paste/drop a screenshot into the prompt bar — validate fail-closed (image-only, size/count caps), emit an omp image content block (base64, prefix stripped), and render a thumbnail strip that never interpolates the data URL (XSS-safe)
$(BUN) run desktop/scripts/demo_p_vision_1.ts
.PHONY: demo-P-PROV.1
demo-P-PROV.1: ## P-PROV.1 (ADR-0210): first-party enterprise providers - exposes omp-native Azure OpenAI (key + AZURE_OPENAI_* config), GitHub Copilot OAuth (device-flow broker; the Business/Enterprise "easy button" + a GHE-domain prompt), and Google Vertex AI = Gemini Enterprise (GOOGLE_CLOUD_API_KEY or ADC: project+location+credentials), and adds GOOGLE_CLOUD_PROJECT to the Gemini card - the missing env without which omp aborts Workspace/Enterprise Gemini OAuth. Extra fields ride the same setKey->env->omp seam as the primary key (no new storage); proves the descriptors + secret-masked/non-secret-echoed field reporting
$(BUN) run desktop/scripts/demo_p_prov_1.ts
.PHONY: demo-P-IMG.1
demo-P-IMG.1: ## P-IMG.1 (ADR-0208): generated/tool images inside the chat reply - lifts image content blocks OUT of an (UNTRUSTED) tool result through the strict image-data-URL gate (ACP-wrapped AND bare omp blocks; SVG/non-base64/oversized dropped fail-closed, count capped), renders them inline via the safe img.src-property idiom with a Download (safe filename, no traversal) and a "Send to preview" that builds a self-contained, CSP-safe wrapper (data: URI, no <script>) so the markup canvas + Screenshot->chat let the user iterate. Pure core verified here; the app.ts render + preview route are typechecked
$(BUN) run desktop/scripts/demo_p_img_1.ts
.PHONY: demo-P-NVIM.1
demo-P-NVIM.1: ## P-NVIM.1 (ADR-0150): Neovim + terminal integration — `lucid tui` is the gated command minus `acp` (gate first, policy, passthru last), fail-closes (dead scanner ⇒ no spawn), and the Neovim plugin's pure helpers pass headless nvim
$(BUN) run harness/scripts/demo_pnvim1.ts
.PHONY: demo-P-NVIM.6
demo-P-NVIM.6: ## P-NVIM.6: the `lucid kb` knowledge-graph viewer behind :LucidKb — seeds a temp KG, then proves kbList/kbPages/kbShow/kbSearch + runKb (list|pages|show|search, --json vs text, exit codes) read the shared ~/.omp registry; the neovim pure helpers ride the headless spec (demo-P-NVIM.1)
$(BUN) run harness/scripts/demo_pnvim6.ts
.PHONY: demo-P-THEME.1
demo-P-THEME.1: ## P-THEME.1 (ADR-0160): the LUCID skin for gated terminals — themes/lucid.json resolves, session_start provisions (idempotent) + setTheme("lucid"), fail-OPEN cosmetics never weaken fail-CLOSED, and the theme -e rides behind the gate -e
$(BUN) run harness/scripts/demo_ptheme1.ts
.PHONY: pwa-build
pwa-build: ## P-REMOTE.3 (ADR-0226/0227): bundle the phone guest PWA (tools/remote-pwa) into a static site under dist/
$(BUN) run tools/remote-pwa/build.ts
.PHONY: demo-P-BRAND.1
demo-P-BRAND.1: ## P-BRAND.1 (issue #314): the LUCID TUI welcome — lucid_tui.config.yml suppresses omp's welcome (startup.quiet), renderWelcomeLines names LUCID never omp, LUCID_WELCOME=off restores omp's box, fail-OPEN cosmetics never weaken fail-CLOSED, and the welcome -e rides behind the gate + theme -e with the --config overlay
$(BUN) run harness/scripts/demo_pbrand1.ts
.PHONY: nvim-plugin-split
nvim-plugin-split: ## Split extensions/neovim -> the standalone `lucid.nvim` branch (add PUSH=1 to force-push to origin)
@sha=$$(git subtree split --prefix=extensions/neovim HEAD); \
echo "lucid.nvim split -> $$sha"; \
if [ "$(PUSH)" = "1" ]; then git push -f origin "$$sha:refs/heads/lucid.nvim"; else echo "(dry run — add PUSH=1 to publish; CI does this on every master push)"; fi
.PHONY: demo-P-PREVIEW.6a
demo-P-PREVIEW.6a: ## P-PREVIEW.6a (ADR-0153): the agent reviews its work live in the preview — a preview tool-call (screenshot/open/inspect/action) maps to a user-facing label that glows the panel + shows a "reviewing/testing" pill; non-preview tools never trigger it
$(BUN) run desktop/scripts/demo_p_preview_6a.ts
.PHONY: demo-P-PREVIEW.6b
demo-P-PREVIEW.6b: ## P-PREVIEW.6b (ADR-0153): the agent READS the live preview DOM — a held tool→server→renderer→iframe relay + a READ-ONLY postMessage bridge injected into the sandboxed preview (no eval/mutation), fail-closed on timeout
$(BUN) run desktop/scripts/demo_p_preview_6b.ts
.PHONY: demo-P-PREVIEW.6c
demo-P-PREVIEW.6c: ## P-PREVIEW.6c (ADR-0153): the agent CLICKS/TYPES in the live preview by CSS selector — structured actions through the same relay + bridge (fixed allowlist click/type/focus/scroll; still no eval/innerHTML)
$(BUN) run desktop/scripts/demo_p_preview_6c.ts
.PHONY: demo-P-DESIGN.1
demo-P-DESIGN.1: ## P-DESIGN.1 (ADR-0154): the agent honors a workspace DESIGN.md — read + wrapped as a <design-invariants> block and re-delivered in the user-turn preamble EVERY turn (never the frozen prefix); no DESIGN.md → no block
$(BUN) run desktop/scripts/demo_p_design_1.ts
.PHONY: demo-P-MARKET.1c
demo-P-MARKET.1c: ## P-MARKET.1c (ADR-0446): live Role KG Pack title layout at desktop and narrow widths (the plugin modal it also covered was retired by ADR-0461); set LUCID_DEMO_CDP_URL and LUCID_DEMO_URL for an isolated QA browser and engine
$(BUN) run desktop/scripts/demo_p_market_1c.mjs
.PHONY: demo-P-FIGMA.1
demo-P-FIGMA.1: ## P-FIGMA.1 (ADR-0154): /figma — parse a Figma file URL → key, walk the doc → top frames (capped), build a design-board HTML with frames inlined as PNG data URLs (names escaped, only data:image src) for the sandboxed preview
$(BUN) run desktop/scripts/demo_p_figma_1.ts
.PHONY: demo-P-FIGMA.2
demo-P-FIGMA.2: ## P-FIGMA.2 (ADR-0154): after /figma import, a guided step — review the design / open-or-build DESIGN.md; an agent write to DESIGN.md is detected (no false positives) → `design-available` pops it out in the IDE, then it's honored as standing guidance
$(BUN) run desktop/scripts/demo_p_figma_2.ts
.PHONY: demo-P-SANDBOX.1
demo-P-SANDBOX.1: ## P-SANDBOX.1 (ADR-0157): the runtime execution boundary — sandbox seam (bwrap/noop), canNetwork/canExec caps ENFORCED at the omp spawn (suspicious-chain downgrade = real --unshare-net), managed require-isolation fail-closes, disclosed passthrough elsewhere
$(BUN) run harness/scripts/demo_p_sandbox_1.ts
.PHONY: demo-P-SANDBOX.2
demo-P-SANDBOX.2: ## P-SANDBOX.2 (ADR-0166, ADR-0445): mediated subprocess egress: a loopback DNS + HTTP proxy (CONNECT tunnels and absolute-form plain-HTTP forwards) decided by the agent's own egressDecisionDetailed brain (only allow passes; prompt/foreign-ccTLD/IP-literal/unparseable/thrown all DENY). Live: denied gethostbyname → REFUSED, upstream never contacted; allowed → forwarded; a denied plain-HTTP request → 403, target never dialed; allowed → streamed. Proxy dead ⇒ egress denied but local exec still runs; wired at the omp spawn (HTTP(S)_PROXY + resolv.conf steer)
$(BUN) run harness/scripts/demo_p_sandbox_2.ts
.PHONY: demo-P-SANDBOX.3
demo-P-SANDBOX.3: ## P-SANDBOX.3 (ADR-0167): the mediated-egress audit trail — a BLOCKED subprocess reach-out becomes one canonical `egress` SecurityEvent (block/high) on the audit/OCSF pipeline (P-REPORT.10 precedent; no new EventName, no approvable live-block); deduped by host so a looping exfil can't flood the SIEM; allowed reach-outs emit nothing; auditing never weakens the fail-closed guarantee (throwing sink swallowed, dead proxy still denies)
$(BUN) run harness/scripts/demo_p_sandbox_3.ts
.PHONY: demo-P-SANDBOX.4
demo-P-SANDBOX.4: ## P-SANDBOX.4 (ADR-0168): the macOS Seatbelt backend — real runtime containment on macOS via `sandbox-exec`. Declared caps enforced (network-off denies ALL network + cuts DNS via mDNSResponder); mediated egress CONFINED TO LOOPBACK so a raw-IP socket ignoring HTTP_PROXY is kernel-denied (bwrap only drops it); require-isolation fail-closed on macOS-without-sandbox-exec + Windows. Windows AppContainer (native) + Linux slirp raw-socket forwarding are named follow-ups
$(BUN) run harness/scripts/demo_p_sandbox_4.ts
.PHONY: demo-P-SANDBOX.5
demo-P-SANDBOX.5: ## P-SANDBOX.5 (ADR-0169): the runtime-execution boundary made VISIBLE in the Security panel — a GUI-owned store of the live posture (bwrap/Seatbelt/disclosed/fail-closed-blocked) + a bounded newest-first ring of refused subprocess reach-outs; a PURE panel builder rendering green/amber/red posture (auto-opens when NOT isolated), escaping hostile host/reason text; the egress audit sink feeds one deduped panel row per refused host
$(BUN) run desktop/scripts/demo_p_sandbox_5.ts
.PHONY: demo-P-SANDBOX.6
demo-P-SANDBOX.6: ## P-SANDBOX.6 (ADR-0172): the Windows AppContainer backend SEAM — a first-party `lucid-appcontainer <flags> -- <argv>` helper that fits the wrap→{cmd,args,env} contract (no OS argv-wrapper exists for AppContainer). Flag contract mirrors bwrap/Seatbelt's 3 network states (network-off → --deny-network; mediated → --loopback-only + HTTP(S)_PROXY, raw-IP sockets WFP-denied; no-proxy → fail-closed --deny-network); resolveBackend selects it when the helper is on PATH, else discloses; require-isolation fail-closed without it. The native helper itself ships in P-SANDBOX.7
$(BUN) run harness/scripts/demo_p_sandbox_6.ts
.PHONY: demo-P-SANDBOX.7
demo-P-SANDBOX.7: ## P-SANDBOX.7 (ADR-0173): the native Windows AppContainer helper (bun-compiled TS+FFI). Parser fail-closes on malformed flags; main() refuses (non-zero) wherever it cannot contain (never a passthrough); LIVE on Windows a benign child runs but a networked child is BLOCKED (a no-capability AppContainer has no network); off-Windows it correctly refuses
$(BUN) run harness/scripts/demo_p_sandbox_7.ts
.PHONY: demo-P-SANDBOX.7b
demo-P-SANDBOX.7b: ## P-SANDBOX.7b (ADR-0174): mediated --loopback-only for the AppContainer helper - the empty-caps container has NO direct internet (verified live: curl → http_code=000) and a one-time ADMIN loopback exemption (--register-loopback via CheckNetIsolation) lets it reach ONLY the loopback proxy; the no-internet guarantee holds with or without the exemption; off-Windows every mode fail-closes
$(BUN) run harness/scripts/demo_p_sandbox_7b.ts
.PHONY: demo-P-SANDBOX.9
demo-P-SANDBOX.9: ## P-SANDBOX.9 (ADR-0386): a green AppContainer pill means a working chat - the helper hands its std handles to the contained omp (ACP rides stdio), the container is granted the repo + bun runtime (rx) and ~/.omp (rw, TEMP inside), PI_PROXY steers omp inference at the mediating proxy, --register-loopback creates the profile first, and the probe is a stdio round trip
$(BUN) run harness/scripts/demo_p_sandbox_9.ts
.PHONY: demo-P-SANDBOX.10
demo-P-SANDBOX.10: ## P-SANDBOX.10 (ADR-0387): the AppContainer pill needs the REAL runtime to boot - bundled bun 1.3.14 -> 1.4.2 (1.3.14 cannot start a script in the container, no ACL fixes it), the engine probes the contained omp --version through the same wrap before committing (passthrough with the reason otherwise), and a Windows CI smoke runs the real contained omp on the bundled bun
$(BUN) run harness/scripts/demo_p_sandbox_10.ts
.PHONY: demo-P-SANDBOX.12
demo-P-SANDBOX.12: ## P-SANDBOX.12 (ADR-0390): the Security panel's Windows sandbox switch - Off is a per-user LUCID setting (no admin, honored at the next spawn), On registers the loopback exemption behind UAC only when missing, Remove from Windows unregisters it, managed require-isolation locks the switch (note, no button)
$(BUN) run harness/scripts/demo_p_sandbox_12.ts
.PHONY: demo-P-SANDBOX.13
demo-P-SANDBOX.13: ## P-SANDBOX.13 (ADR-0391): Add folder (read-only / read-write) from the Security panel - the ENGINE opens the native Explorer picker and grants only the pick (no caller can name a path), too-broad picks refused, audited, and the panel lists user folders (revocable) plus LUCID's always-allowed runtime folders
$(BUN) run harness/scripts/demo_p_sandbox_13.ts
.PHONY: demo-P-SANDBOX.14
demo-P-SANDBOX.14: ## P-SANDBOX.14 (ADR-0394): enterprise policy for the Windows sandbox - SandboxAllowUserOff=0 keeps the switch on, SandboxReadFolders / SandboxReadWriteFolders apply admin folders at every contained spawn (bounded like a user pick, %VAR% expanded), SandboxLockFolders stops user and agent folder adds (revoke still works)
$(BUN) run harness/scripts/demo_p_sandbox_14.ts
.PHONY: demo-P-SANDBOX.15
demo-P-SANDBOX.15: ## P-SANDBOX.15 (ADR-0396): the omp child gets its own AGENT token (accepted only on the routes it calls, never on approve / the sandbox switch / Add folder), no longer inherits LUCID_MAIN_TOKEN, and under Electron the served HTML carries no token (the window gets it from main over IPC)
$(BUN) run harness/scripts/demo_p_sandbox_15.ts
.PHONY: demo-P-SANDBOX.16
demo-P-SANDBOX.16: ## P-SANDBOX.16 (ADR-0397): the agent finds git wherever it was installed (host PATH first, then Git for Windows, MinGit, scoop, Chocolatey, winget, GitHub Desktop) - the root is granted rx to the AppContainer, its cmd dir goes first on the agent's PATH, and the Security panel lists it
$(BUN) run harness/scripts/demo_p_sandbox_16.ts
.PHONY: demo-P-SANDBOX.17
demo-P-SANDBOX.17: ## P-SANDBOX.17 (ADR-0399): the contained agent's git runs on the host through a broker - subcommand/option allowlist, workspace-confined paths, allowlisted repo config held open (share modes) from check to use, forced no-hooks/https-only overrides, network via the egress proxy; git.cmd shim round trip
$(BUN) run harness/scripts/demo_p_sandbox_17.ts
.PHONY: build-appcontainer
build-appcontainer: ## P-SANDBOX.7: cross-compile the native lucid-appcontainer.exe helper (bun build --compile, Windows x64) into bin/ (ships via the `repo` extraResources; resolveBackend probes <repo>/bin first, PATH second)
$(BUN) build tools/appcontainer/lucid_appcontainer.ts --compile --target=bun-windows-x64 --outfile bin/lucid-appcontainer.exe
.PHONY: demo-P-REPORT.9
demo-P-REPORT.9: ## P-REPORT.9 (ADR-0162): multi-repo remote fetch + PR aggregation for the Engineering Report — remote-URL parse (GitHub vs not), commits aggregated across branches (deduped) + line totals, the Cross-repo activity annex, fail-soft on a failed fetch (local refs still shown), PRs skipped with a reason on non-GitHub/unauthed remotes, and untrusted commit/PR text neutralized (no HTML/fence breakout)
$(BUN) run desktop/scripts/demo_p_report_9.ts
.PHONY: demo-P-TOOLFAIL.2
demo-P-TOOLFAIL.2: ## P-TOOLFAIL.2 (ADR-0163): failed tool calls collapse into a red toolbox badge, click expands the Tool Call Actions list (command attempted + full error); never a security surface
$(BUN) run desktop/scripts/demo_p_toolfail_2.ts
.PHONY: demo-P-REPORT.10
demo-P-REPORT.10: ## P-REPORT.10 (ADR-0164): a formal SecurityEvent per fetch/PR reach-out — the report collector's first-party git fetch / gh PR list (which bypass the agent gate) each emit a canonical egress/allow SecurityEvent (OCSF/SIEM), metadata-only (host, no credential), skipped PR lists emit nothing, proven live+offline via a local bare-origin fetch through the real dispatcher
$(BUN) run desktop/scripts/demo_p_report_10.ts
.PHONY: demo-P-FAV.1
demo-P-FAV.1: ## P-FAV.1 (ADR-0165): model-picker favorite stars - star a model to pin it into a Favorites section at the top of the picker; catalog order preserved, corrupted storage degrades safely, stale stars survive provider reconnects
$(BUN) run desktop/scripts/demo_p_fav_1.ts
.PHONY: demo-P-PROV.2
demo-P-PROV.2: ## P-PROV.2: the Provider Hub - a dedicated popup listing every provider omp offers (names only); new open-weight providers (Qwen OAuth+key, GLM/MiniMax key) join Kimi behind the typed ACKNOWLEDGE gate, which emits NO non-U.S. provider until acknowledged
$(BUN) run desktop/scripts/demo_p_prov_2.ts
.PHONY: demo-P-LOCAL.4
demo-P-LOCAL.4: ## P-LOCAL.4: one-click local-model presets (Laguna 2.1 Poolside, Gemma 4, Qwen 3.8, +) that build ONE Local Provider fronting many models behind a single secured NGINX endpoint, through the existing P-LOCAL.3 add/validate/vault path
$(BUN) run desktop/scripts/demo_p_local_4.ts
.PHONY: demo-P-LOCAL.5
demo-P-LOCAL.5: ## P-LOCAL.5: GLM-5.3-Flash on a self-hosted vLLM box - a preset chip now carries its curated metadata (context window, reasoning, vision) all the way into the omp model entry instead of silently falling back to 8192/no-reasoning, plus a closed, sanitized per-model `compat` so a LAN reasoning model gets the chat-template wire shape omp cannot infer from its hostname; matched on the id the box ACTUALLY serves (`zai-org/GLM-5.3-Flash-FP8`), and asserted through the store + runtime overlay that really writes models.yml, not just the in-memory draft
$(BUN) run desktop/scripts/demo_p_local_5.ts
.PHONY: demo-P-LOCAL.6
demo-P-LOCAL.6: ## P-LOCAL.6: endpoint model discovery - ask `GET <baseUrl>/models` (the list omp's own discovery reads) so a model's real id and real context window come from the server instead of the catalog's editorial guess, against a REAL vLLM-shaped fixture incl. its 401; the catalog keeps only what /models cannot report (reasoning/vision/compat), an unauthenticated probe reports authRequired rather than ever putting a key on the engine's HTTP surface, and an empty answer never wipes a saved provider
$(BUN) run desktop/scripts/demo_p_local_6.ts
.PHONY: demo-P-STT.2
demo-P-STT.2: ## P-STT.2: guided on-device Whisper - hardware-capability gate (run only where it fits), model catalog + install/serve plan, whisper.cpp binary resolution, and the download-with-integrity flow (all pure/injected; no network, no binary)
$(BUN) run desktop/scripts/demo_p_stt_2.ts
.PHONY: demo-P-STT.6
demo-P-STT.6: ## P-STT.6 (ADR-0255): Whisper model housekeeping - the picker offers tiny/base/small only (medium/large proved slow + buggy through the local server), grays out tiers the hardware can't run (reason shown, never hidden), lists every downloaded model with its real on-disk size + a Remove button (legacy medium/large installs reclaim disk; the running tier is refused until stopped), and the recommendation/summary clamp to the offered set
$(BUN) test desktop/whisper_install.test.ts desktop/whisper_runtime.test.ts
.PHONY: demo-P-SECACK.1
demo-P-SECACK.1: ## P-SECACK.1 (ADR-0170): reviewed security rows leave the active view - GUI-owned ack ledger (releases NOTHING, audit kept), findings-seen watermark counts only new findings, and the right-click Cut/Copy/Paste menu for the prompt bar (no Cut/Copy on password fields)
$(BUN) run desktop/scripts/demo_p_secack_1.ts
.PHONY: demo-P-RESUME.1
demo-P-RESUME.1: ## P-RESUME.1 (ADR-0171): a resumed session keeps its thinking + tool-call + tool-failure history - per-session lucid-steps sidecar (omp's transcript untouched), turn anchors only move forward, quarantines not duplicated, hostile text escaped, corrupt sidecar degrades safely
$(BUN) run desktop/scripts/demo_p_resume_1.ts
.PHONY: demo-P-CTX.1
demo-P-CTX.1: ## P-CTX.1 (ADR-0350): the prompt-audit - a REAL per-block token breakdown of the assembled request, offline (echo model, in-memory sessions, MCP off), with omp's OWN counters as the parity anchor; sections sum exactly (residuals are differences), extension tools attributed by set difference, absences declared never fabricated
$(BUN) run harness/scripts/demo_pctx1.ts
.PHONY: prompt-audit
prompt-audit: ## Measure the assembled request's non-message baseline on THIS repo (same script as demo-P-CTX.1; flags: --json --window N --target N --detail N --no-extensions --live-discovery)
$(BUN) run harness/scripts/demo_pctx1.ts --detail 12
.PHONY: demo-P-TEST.W1
demo-P-TEST.W1: ## P-TEST.W1 (ADR-0351): the gate is honestly green on Windows - the 8 environmental fails fixed at their true source: auth_status isolated from the machine's persisted settings (LUCID_GUI_SETTINGS_FILE seam), fs_browse real-FS tests inject the HOST platform (posix semantics stay via fully-synthetic deps), lucid_acp asset assertions separator-agnostic
$(BUN) test $(TEST_IGNORES) desktop/auth_status.test.ts desktop/fs_browse.test.ts harness/launcher/lucid_acp.test.ts
.PHONY: dashboards
dashboards: ## Materialize dashboard CSVs from a DuckDB into observable/docs/data (DB=path)
$(BUN) run harness/scripts/materialize_dashboards.ts $(DB) observable/docs/data
# ---------------------------------------------------------------------------
# KG Packs (ADR-0207): headless pack builder
# ---------------------------------------------------------------------------
.PHONY: kg-pack
kg-pack: ## Build one KG pack headlessly, e.g. `make kg-pack ROLE=bd` (see `bun tools/build_kg_pack.ts --help` for keys/flags). Extra flags via FLAGS=, e.g. FLAGS="--limit 5"
$(BUN) run tools/build_kg_pack.ts $(ROLE) $(FLAGS)
.PHONY: kg-pack-all
kg-pack-all: ## Build every KG pack in the catalog, sequentially (long — one model call per conversation)
$(BUN) run tools/build_kg_pack.ts --all $(FLAGS)
# ---------------------------------------------------------------------------
# Hygiene
# ---------------------------------------------------------------------------
.PHONY: typecheck
typecheck: ## TS typecheck (no emit); tools/typecheck.ts also works from a checkout on a network share
$(BUN) tools/typecheck.ts
.PHONY: license-headers
license-headers: ## Apply the BUSL-1.1 SPDX header to first-party source (idempotent)
$(BUN) run tools/license_headers.ts
.PHONY: license-check
license-check: ## Fail if any first-party source file is missing the BUSL-1.1 header (CI guard)
$(BUN) run tools/license_headers.ts --check
EVIDENCE_OUT ?= compliance-evidence
.PHONY: compliance-evidence
compliance-evidence: ## P-COMPLY.1 (ADR-0479): NIST SP 800-171 r3 host evidence -> $(EVIDENCE_OUT)/evidence.json + evidence.md (read-only)
$(BUN) run tools/compliance/evidence.ts --out $(EVIDENCE_OUT)
.PHONY: compliance-matrix
compliance-matrix: ## P-COMPLY.1: re-render docs/compliance/control-matrix-r3.md from the CSV
$(BUN) run tools/compliance/matrix.ts
.PHONY: clean
clean: ## Remove build/test artifacts (keeps committed source + DBs)
rm -rf node_modules/.cache .bun 2>/dev/null || true
find . -name "__pycache__" -type d -prune -exec rm -rf {} + 2>/dev/null || true
.PHONY: help
help: ## Show this help
@grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) \
| awk 'BEGIN {FS = ":.*?## "}; {printf " \033[36m%-18s\033[0m %s\n", $$1, $$2}'
.PHONY: demo-P-TRIV.1
demo-P-TRIV.1: ## P-TRIV.1 (ADR-0174): the Trivia Wire - a word-game ticker in the status bar's idle gap; seed bank valid + varied, no repeats until the bank empties, streak scoring capped at x3, corrupt/throwing storage degrades safely, streaming-only visibility, hostile question text renders as text (never markup)
$(BUN) run harness/scripts/demo_ptriv1.ts
.PHONY: demo-P-TRIV.2
demo-P-TRIV.2: ## P-TRIV.2 (ADR-0175): role-aware Trivia Wire - executive→GovCon (M&A/opportunities/federal priorities), manager→CMMI-DEV L3 + PM, security→CMMC + RMF, developer/none→general; banks valid + domain-confined + duplicate-free; idle engagement wakes the ticker on an empty composer only when past sessions or an unlocked KG exist
$(BUN) run harness/scripts/demo_ptriv2.ts
.PHONY: demo-P-TRIV.3
demo-P-TRIV.3: ## P-TRIV.3 (ADR-0176): 100-question dev/security/manager banks + 50 executive - and the executive INTEL WIRE: curated defense/intel RSS fetched first-party (host-only egress audit), scan-gated FAIL-CLOSED (findings or a dead scanner drop the batch), fail-quiet offline, rendered as escaped text between questions
$(BUN) run harness/scripts/demo_ptriv3.ts
.PHONY: demo-P-PREVIEW.7
demo-P-PREVIEW.7: ## P-PREVIEW.7 (ADR-0179): the silent-white preview explained + runnable - the injected bridge posts a one-shot health report (empty body + bounded errors); Electron apps detect evidence-based (fail-false for plain pages); launch plan prefers the app's own electron, falls back to PATH, null otherwise; non-Electron paths never plan a launch
$(BUN) run harness/scripts/demo_ppreview7.ts
.PHONY: demo-P-TASK.5
demo-P-TASK.5: ## P-TASK.5 (ADR-0180): live subagent activity - the delegation card opens each subtask (generated name, live now-line, thinking/tool/text steps tailed from omp's per-subtask transcripts); read-only + path-confined + corrupt-tolerant + bounded; never-delegated sessions fail-quiet
$(BUN) run harness/scripts/demo_ptask5.ts
.PHONY: demo-P-TASK.6
demo-P-TASK.6: ## P-TASK.6 (ADR-0398): the delegation card for omp 18's task tool (per-item agent, task/name) - detected again, scoped to its runs by name, live until its BACKGROUND runs finish, with a green-neon clipboard whose lines write in and out
$(BUN) run harness/scripts/demo_p_task_6.ts
.PHONY: demo-P-VOICE.8
demo-P-VOICE.8: ## P-VOICE.8 (ADR-0400): the read-aloud checkboxes mean what the user clicked - one rule shared by the engine store and every control (auto-speak off clears conversation for good), clicks apply before the engine answers, older answers never overwrite newer clicks, and the LUCID Agent stage respects a user's own setting
$(BUN) run harness/scripts/demo_p_voice_8.ts
.PHONY: demo-P-FLEET.L20
demo-P-FLEET.L20: ## P-FLEET.L20 (ADR-0402): close a spoke from where it is shown - an X on the orbit node (beside click-to-open) and on the takeover banner (beside Switch), the grid's two-step (a live spoke stops, a stopped one dismisses), one pure function deciding the step, label and tip
$(BUN) run desktop/scripts/demo_p_fleet_l20.ts
.PHONY: demo-P-PROGRESS.1
demo-P-PROGRESS.1: ## P-PROGRESS.1 (ADR-0409, amended): workers say what they are doing (every tool step opens on its doing line, arguments and outcome) and a dead agent process shows one line with an in-place restart; turns on one folder take turns in order, and a waiter is told whom it waits for and its place in line (no estimates, no ETAs by default; P-PROGRESS.3 makes them opt-in)
$(BUN) run harness/scripts/demo_p_progress_1.ts
.PHONY: demo-P-SCROLL.1
demo-P-SCROLL.1: ## P-SCROLL.1 (ADR-0405): the chat follows new output until the reader scrolls up (a fast burst no longer releases it); a spoke switch lands on the newest message or, by preference, where the reader left off; the attached spoke's live turn renders in arrival order; a new spoke opens on the last spoke's model
$(BUN) run harness/scripts/demo_p_scroll_1.ts
.PHONY: demo-P-REPO.1
demo-P-REPO.1: ## P-REPO.1 (ADR-0406): every session names the repo it works on and where its commits go (git's own push rules, no token in the view), taken from the files the session edits when its folder holds several repos; a spoke is started by picking a repo (local checkouts or the user's GitHub repos) instead of typing a URL
$(BUN) run desktop/scripts/demo_p_repo_1.ts
.PHONY: demo-P-PROGRESS.2
demo-P-PROGRESS.2: ## P-PROGRESS.2 (ADR-0408, amended): the activity window folds calls under 5 s into one summary line and failed, repeated or empty calls into "processing", so only long calls keep a row (with elapsed time); no ETA or estimate on any worker, subagent run or the prompt by default (P-PROGRESS.3 makes them opt-in)
$(BUN) run harness/scripts/demo_p_progress_2.ts
.PHONY: demo-P-PROGRESS.3
demo-P-PROGRESS.3: ## P-PROGRESS.3 (ADR-0412): the beta.10 quiet footer stays the default; the progress detail (per turn with Details, or always with Settings > Working status > Full detail) and the experimental time estimate are opt-ins; estimate off means no number on any surface, and on never shows the "ETA estimating" placeholder; a green progress ring (on by default) sits beside the one line, empty without history, red only when the process is gone
$(BUN) run harness/scripts/demo_p_progress_3.ts
.PHONY: demo-P-PROGRESS.4
demo-P-PROGRESS.4: ## P-PROGRESS.4 (ADR-0413): the turn ETA replayed against finished turns (a synthetic corpus and, read-only, this machine's latency ledger); prints the P-PROGRESS.1 baseline and the current estimator (time left given the time already run) side by side, median error and share within +/-30%, and fails unless the current one wins on the synthetic corpus
$(BUN) run harness/scripts/eta_backtest.ts --check
.PHONY: demo-P-LIVENESS.1
demo-P-LIVENESS.1: ## P-LIVENESS.1 (ADR-0418): an open tool call is judged on evidence (its processes' CPU and disk counters, process churn, subagent transcript writes), marked "likely stuck" after 5 min of none (12 min with a live subagent), and stopped only by the user's Stop command, which ends just the processes that call started
$(BUN) run harness/scripts/demo_p_liveness_1.ts
.PHONY: demo-P-NETSTAT.1
demo-P-NETSTAT.1: ## P-NETSTAT.1 (ADR-0423): a status-bar network indicator with provider latency; a turn that died on the network or on omp's startup handshake gets a stand-by card that resends once the link is stable, instead of blaming the model; outage toasts are held in the indicator's popover, security notices never are
$(BUN) run harness/scripts/demo_p_netstat_1.ts
.PHONY: demo-P-SANDBOX.18
demo-P-SANDBOX.18: ## P-SANDBOX.18 (ADR-0424): the AppContainer helper skips a grant already on disk instead of re-walking every file under it (23 s per spawn on this repo), so the contained agent answers initialize in time and respawns work; a contained handshake failure names the sandbox and never offers a model switch
$(BUN) run harness/scripts/demo_p_sandbox_18.ts
.PHONY: demo-P-GAME.1
demo-P-GAME.1: ## P-GAME.1: original offline games pass the Preview gate and exercise win/loss/replay from their inline scripts
$(BUN) test desktop/arcade_games.test.ts
$(BUN) run desktop/scripts/demo_p_game_1.mjs
.PHONY: demo-P-GAME.7
demo-P-GAME.7: ## P-GAME.7: Chroma Cadence joins the arcade. Proves the Preview gate, then plays whole seeded songs headless: a player 40 ms late reads as ~40 ms late, the results offer that sync, and the retry with it applied is all PERFECT; pause freezes the track, the count-in holds it, the drained meter fails the song
$(BUN) test desktop/arcade_games.test.ts
$(BUN) run desktop/scripts/demo_p_game_1.mjs
.PHONY: demo-P-GAME.8
demo-P-GAME.8: ## P-GAME.8: Gravity Gambit joins the arcade. Proves the Preview gate, then drives it headless: a landscape panel stays landscape, a 400x720 panel turns the course (scale 0.38 vs 0.25) and a pull-down sling on the turned screen aims at the wormhole; recall, crash, pause; then every sector is solved with the flight's own integrator and flown into the wormhole (sector 5 was unwinnable before this), debrief, replay
$(BUN) test desktop/arcade_games.test.ts
$(BUN) run desktop/scripts/demo_p_game_1.mjs
.PHONY: demo-P-GAME.9
demo-P-GAME.9: ## P-GAME.9: Silent Fathom joins the arcade. Proves the Preview gate, then drives it headless at 400x720: the view zooms out (0.65) so the sub sees as far as it is heard, the cave is black until a ping lights its walls, the ping cooldown holds, thrust is loud and silence settles, pause freezes the abyss; the autopilot (BFS path, hull-wide line of sight) surfaces through all 5 zones while leviathans hear it; with the hull unlocked it dies with the cause on the card; dive again restarts at zone 1
$(BUN) test desktop/arcade_games.test.ts
$(BUN) run desktop/scripts/demo_p_game_1.mjs
.PHONY: demo-P-GAME.10
demo-P-GAME.10: ## P-GAME.10: Skyhook joins the arcade. Proves the Preview gate, then drives it headless at 400x720: the view zooms out (0.5) so anchors in rope reach are on screen, holding Space latches and letting go flings forward into a FLOW chain, pause freezes the run, restart from pause; every anchor hangs within rope reach of its floor and a player idle on the floor can still latch (both were lost runs before the playability fix); the autopilot carries a seeded run past 2000 m; an idle player is then caught by the Cascade; the best distance carries to the menu
$(BUN) test desktop/arcade_games.test.ts
$(BUN) run desktop/scripts/demo_p_game_1.mjs