@miller-tech/uap 2.16.7 → 2.19.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/config/capacity-policy.json +33 -0
- package/config/model-profiles/qwen38.json +32 -33
- package/dist/.tsbuildinfo +1 -1
- package/dist/bin/cli.js +57 -0
- package/dist/bin/cli.js.map +1 -1
- package/dist/capacity/policy.d.ts +32 -1
- package/dist/capacity/policy.d.ts.map +1 -1
- package/dist/capacity/policy.js +123 -4
- package/dist/capacity/policy.js.map +1 -1
- package/dist/capacity/probe.d.ts +26 -0
- package/dist/capacity/probe.d.ts.map +1 -1
- package/dist/capacity/probe.js +84 -3
- package/dist/capacity/probe.js.map +1 -1
- package/dist/cli/inference.d.ts +4 -0
- package/dist/cli/inference.d.ts.map +1 -1
- package/dist/cli/inference.js +74 -8
- package/dist/cli/inference.js.map +1 -1
- package/dist/cli/merge-gate.d.ts +59 -0
- package/dist/cli/merge-gate.d.ts.map +1 -0
- package/dist/cli/merge-gate.js +238 -0
- package/dist/cli/merge-gate.js.map +1 -0
- package/dist/cli/merge-queue.d.ts +13 -0
- package/dist/cli/merge-queue.d.ts.map +1 -1
- package/dist/cli/merge-queue.js +48 -2
- package/dist/cli/merge-queue.js.map +1 -1
- package/dist/cli/mission.d.ts +25 -0
- package/dist/cli/mission.d.ts.map +1 -0
- package/dist/cli/mission.js +225 -0
- package/dist/cli/mission.js.map +1 -0
- package/dist/cli/orch.d.ts +27 -0
- package/dist/cli/orch.d.ts.map +1 -0
- package/dist/cli/orch.js +70 -0
- package/dist/cli/orch.js.map +1 -0
- package/dist/cli/systemd-services.d.ts.map +1 -1
- package/dist/cli/systemd-services.js +44 -0
- package/dist/cli/systemd-services.js.map +1 -1
- package/dist/delivery/merge-gate.d.ts +168 -0
- package/dist/delivery/merge-gate.d.ts.map +1 -0
- package/dist/delivery/merge-gate.js +309 -0
- package/dist/delivery/merge-gate.js.map +1 -0
- package/dist/inference/analysis.d.ts +69 -3
- package/dist/inference/analysis.d.ts.map +1 -1
- package/dist/inference/analysis.js +123 -7
- package/dist/inference/analysis.js.map +1 -1
- package/dist/inference/probe.d.ts +38 -1
- package/dist/inference/probe.d.ts.map +1 -1
- package/dist/inference/probe.js +303 -30
- package/dist/inference/probe.js.map +1 -1
- package/dist/inference/strata.d.ts +95 -0
- package/dist/inference/strata.d.ts.map +1 -0
- package/dist/inference/strata.js +167 -0
- package/dist/inference/strata.js.map +1 -0
- package/dist/mission/database.d.ts +29 -0
- package/dist/mission/database.d.ts.map +1 -0
- package/dist/mission/database.js +131 -0
- package/dist/mission/database.js.map +1 -0
- package/dist/mission/ledger.d.ts +109 -0
- package/dist/mission/ledger.d.ts.map +1 -0
- package/dist/mission/ledger.js +294 -0
- package/dist/mission/ledger.js.map +1 -0
- package/dist/mission/poll-cycle.d.ts +73 -0
- package/dist/mission/poll-cycle.d.ts.map +1 -0
- package/dist/mission/poll-cycle.js +100 -0
- package/dist/mission/poll-cycle.js.map +1 -0
- package/dist/mission/poll-executor.d.ts +91 -0
- package/dist/mission/poll-executor.d.ts.map +1 -0
- package/dist/mission/poll-executor.js +328 -0
- package/dist/mission/poll-executor.js.map +1 -0
- package/dist/models/types.d.ts.map +1 -1
- package/dist/models/types.js +33 -27
- package/dist/models/types.js.map +1 -1
- package/dist/self-tuning/profiles/qwen38.d.ts +13 -14
- package/dist/self-tuning/profiles/qwen38.d.ts.map +1 -1
- package/dist/self-tuning/profiles/qwen38.js +17 -18
- package/dist/self-tuning/profiles/qwen38.js.map +1 -1
- package/dist/types/mission.d.ts +80 -0
- package/dist/types/mission.d.ts.map +1 -0
- package/dist/types/mission.js +12 -0
- package/dist/types/mission.js.map +1 -0
- package/docs/architecture/adr/0003-mission-orchestrator.md +99 -0
- package/docs/architecture/adr/0004-deterministic-merge-gate.md +127 -0
- package/docs/guides/CAPACITY_POLICY.md +49 -0
- package/docs/guides/INFERENCE_HEALTH.md +65 -8
- package/docs/guides/MISSIONS.md +170 -0
- package/docs/guides/PROXY.md +2 -0
- package/docs/reports/2026-10-02-plane-admin-fail-closed.md +70 -0
- package/docs/reports/2026-10-02-plane-admin-protect-session.md +116 -0
- package/docs/visual/merge-gate.html +404 -0
- package/docs/visual/mission-orchestrator.html +472 -0
- package/package.json +2 -2
- package/src/policies/enforcers/__pycache__/_common.cpython-312.pyc +0 -0
- package/src/policies/enforcers/__pycache__/expert_review_required.cpython-312.pyc +0 -0
- package/src/policies/enforcers/__pycache__/quality_metrics_gate.cpython-312.pyc +0 -0
- package/src/policies/enforcers/plane_admin_protect.py +133 -0
- package/src/policies/schemas/policies/plane-admin-protect.md +55 -0
- package/templates/hooks/__pycache__/deliver_autoroute.cpython-312.pyc +0 -0
- package/templates/hooks/uap-policy-gate.sh +33 -0
- package/tools/agents/scripts/__pycache__/toolcall_path_normalizer.cpython-312.pyc +0 -0
- package/tools/agents/scripts/anthropic_proxy.py +493 -40
- package/tools/agents/tests/test_anthropic_proxy_streaming.py +171 -0
- package/tools/agents/tests/test_gate_failclosed_plane_admin.py +248 -0
- package/tools/agents/tests/test_plane_admin_protect.py +124 -0
- package/tools/agents/tests/test_stream_heartbeat.py +77 -0
|
@@ -0,0 +1,472 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="utf-8">
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
6
|
+
<title>Missions outlive every process — UAP mission orchestrator</title>
|
|
7
|
+
<link rel="icon" href="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Crect x='1' y='1' width='14' height='14' rx='3' fill='%230d1520'/%3E%3Cpath d='M4 11V7l4-3 4 3v4' stroke='%23ffb547' stroke-width='1.6' fill='none'/%3E%3C/svg%3E">
|
|
8
|
+
<link rel="preconnect" href="https://fonts.googleapis.com">
|
|
9
|
+
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
|
10
|
+
<link href="https://fonts.googleapis.com/css2?family=IBM+Plex+Sans:wght@400;600&family=IBM+Plex+Mono:wght@400;600&display=swap" rel="stylesheet">
|
|
11
|
+
<style>
|
|
12
|
+
:root{
|
|
13
|
+
color-scheme: light dark;
|
|
14
|
+
--bg:#0d1520; --surface:#132031; --border:#22324a; --border-bright:#596b87;
|
|
15
|
+
--text:#e3ecf5; --text-dim:#92a6bb; --accent:#ffb547; --ok:#6fd3a0; --warn:#e8d36a;
|
|
16
|
+
--risk:#ff7b6b; --info:#7cc0f0;
|
|
17
|
+
--node-top:#22324a; --lift:rgb(0 0 0/.45); --halo:32%;
|
|
18
|
+
--accent-dim:rgb(255 181 71/.14);
|
|
19
|
+
--t-label:.75rem; --t-small:.875rem; --t-body:1rem; --t-lead:1.25rem;
|
|
20
|
+
--t-h2:1.625rem; --t-h1:clamp(2.25rem,5.5vw,4rem);
|
|
21
|
+
--s-1:.25rem; --s-2:.5rem; --s-3:.75rem; --s-4:1rem; --s-5:1.5rem; --s-6:2rem; --s-7:3rem; --s-8:4.5rem;
|
|
22
|
+
--r-1:4px;
|
|
23
|
+
--ease:cubic-bezier(.16,1,.3,1); --fast:150ms; --med:300ms; --slow:500ms;
|
|
24
|
+
}
|
|
25
|
+
@media (prefers-color-scheme: light){
|
|
26
|
+
:root{
|
|
27
|
+
--bg:#f2f6fa; --surface:#ffffff; --border:#d6e0ea; --border-bright:#818f9e;
|
|
28
|
+
--text:#0f1a26; --text-dim:#4d6074; --accent:#a34700; --ok:#1c7443; --warn:#776300;
|
|
29
|
+
--risk:#b0341e; --info:#145f99;
|
|
30
|
+
--node-top:#ffffff; --lift:rgb(18 22 20/.12); --halo:22%;
|
|
31
|
+
--accent-dim:rgb(163 71 0/.13);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
html{font-size:17px; font-kerning:normal; font-synthesis:none; scroll-behavior:smooth}
|
|
35
|
+
body{margin:0; background:var(--bg); color:var(--text);
|
|
36
|
+
font:400 var(--t-body)/1.55 "IBM Plex Sans",sans-serif;
|
|
37
|
+
-webkit-font-smoothing:antialiased}
|
|
38
|
+
.wrap{max-width:64rem; margin:0 auto; padding:0 var(--s-5)}
|
|
39
|
+
h1,h2{font-weight:600; letter-spacing:-.02em; text-wrap:balance; text-box:trim-both cap alphabetic}
|
|
40
|
+
h1{font-size:var(--t-h1); line-height:1.05; margin:var(--s-3) 0 0}
|
|
41
|
+
h2{font-size:var(--t-h2); line-height:1.15; letter-spacing:-.01em; margin:0; grid-column:4/13}
|
|
42
|
+
p{margin:0 0 var(--s-4); max-width:65ch; text-wrap:pretty}
|
|
43
|
+
.lead{font-size:var(--t-lead); color:var(--text-dim); line-height:1.45; margin:var(--s-4) 0 0; max-width:50ch}
|
|
44
|
+
.lead b{color:var(--text); font-weight:600}
|
|
45
|
+
.mono{font-family:"IBM Plex Mono",monospace}
|
|
46
|
+
code{font-family:"IBM Plex Mono",monospace; font-size:.875em; background:var(--accent-dim); padding:.1em .3em; border-radius:var(--r-1)}
|
|
47
|
+
a{color:var(--accent); text-underline-offset:.2em}
|
|
48
|
+
.kicker{font-family:"IBM Plex Mono",monospace; font-size:var(--t-label); font-weight:600;
|
|
49
|
+
letter-spacing:.08em; text-transform:uppercase; color:var(--text-dim); display:flex; align-items:center; gap:var(--s-3)}
|
|
50
|
+
.kicker::before{content:""; width:2.25rem; height:2px; background:var(--accent)}
|
|
51
|
+
.meta{font-family:"IBM Plex Mono",monospace; font-size:var(--t-small); color:var(--text-dim); margin:var(--s-4) 0 0}
|
|
52
|
+
section{padding:var(--s-8) 0; scroll-margin-top:5rem}
|
|
53
|
+
.swiss{display:grid; grid-template-columns:repeat(12,1fr); gap:var(--s-5); align-items:baseline;
|
|
54
|
+
border-top:1px solid var(--border); padding-top:var(--s-5); margin-bottom:var(--s-5)}
|
|
55
|
+
.swiss .sl{grid-column:1/4; font-family:"IBM Plex Mono",monospace; font-size:var(--t-label);
|
|
56
|
+
font-weight:600; letter-spacing:.08em; text-transform:uppercase; color:var(--text-dim)}
|
|
57
|
+
.body-8{grid-column:4/13; min-width:0}
|
|
58
|
+
@media (max-width:64rem){ .swiss{display:block} h2{margin-top:var(--s-2)} .body-8{display:block} }
|
|
59
|
+
figure{margin:0 0 var(--s-6)}
|
|
60
|
+
.frame{background:var(--bg); border:1px solid var(--border); border-radius:var(--r-1);
|
|
61
|
+
padding:var(--s-5); position:relative; overflow:hidden;
|
|
62
|
+
background-image:
|
|
63
|
+
linear-gradient(var(--border) 1px,transparent 1px),
|
|
64
|
+
linear-gradient(90deg,var(--border) 1px,transparent 1px);
|
|
65
|
+
background-size:24px 24px; background-position:center;
|
|
66
|
+
}
|
|
67
|
+
.frame::before{content:""; position:absolute; inset:0; background:var(--bg); opacity:.85; pointer-events:none}
|
|
68
|
+
.frame > *{position:relative}
|
|
69
|
+
figcaption{font-size:var(--t-body); color:var(--text-dim); margin:var(--s-3) var(--s-1) 0; text-wrap:pretty}
|
|
70
|
+
figcaption .fn{font-family:"IBM Plex Mono",monospace; font-size:var(--t-label); font-weight:600; color:var(--text); margin-right:.5em}
|
|
71
|
+
.scroll{overflow-x:auto; scrollbar-width:thin}
|
|
72
|
+
svg text{font-family:"IBM Plex Mono",monospace}
|
|
73
|
+
svg .ve-svg{display:block; min-width:720px; margin:0 auto}
|
|
74
|
+
.ve-n .sh{fill:url(#ve-node); stroke:var(--border-bright); stroke-width:1.5; rx:6}
|
|
75
|
+
.ve-n text{fill:var(--text); font-size:14px; font-weight:600}
|
|
76
|
+
.ve-n text.sub{fill:var(--text-dim); font-size:12px; font-weight:400}
|
|
77
|
+
.ve-n.is-key .sh{fill:var(--accent-dim); stroke:var(--accent); stroke-width:2}
|
|
78
|
+
.ve-e{fill:none; stroke:var(--text-dim); stroke-width:1.75; marker-end:url(#ve-ah)}
|
|
79
|
+
.ve-e.is-async{stroke-dasharray:6 5}
|
|
80
|
+
.ve-e.is-hot{stroke:var(--accent); stroke-width:2.75; marker-end:url(#ve-ah)}
|
|
81
|
+
.ve-el{font-size:13px; fill:var(--text-dim); paint-order:stroke; stroke:var(--bg); stroke-width:5}
|
|
82
|
+
.ve-el.acc{fill:var(--accent)}
|
|
83
|
+
.store-lid{fill:var(--node-top); stroke:var(--border-bright); stroke-width:1.5}
|
|
84
|
+
[data-ref]{border-bottom:1px dashed var(--border-bright); cursor:default}
|
|
85
|
+
[data-ref]:hover,[data-ref]:focus{color:var(--accent); border-bottom-color:var(--accent); outline:none}
|
|
86
|
+
.kpis{display:flex; flex-wrap:wrap; gap:1px; background:var(--border); border:1px solid var(--border); border-radius:var(--r-1)}
|
|
87
|
+
.kpi{flex:1 1 14rem; background:var(--surface); padding:var(--s-4); min-width:0}
|
|
88
|
+
.kpi .k{font-family:"IBM Plex Mono",monospace; font-size:var(--t-label); font-weight:600; letter-spacing:.08em; text-transform:uppercase; color:var(--text-dim)}
|
|
89
|
+
.kpi .v{font-size:2.75rem; font-weight:600; font-variant-numeric:tabular-nums; letter-spacing:-.04em; line-height:1.1; margin:var(--s-1) 0}
|
|
90
|
+
.kpi .v small{font-size:1rem; color:var(--text-dim); font-weight:400; letter-spacing:0}
|
|
91
|
+
.cards{display:grid; grid-template-columns:repeat(auto-fit,minmax(14.5rem,1fr)); gap:var(--s-4)}
|
|
92
|
+
.card{background:var(--surface); border:1px solid var(--border); border-radius:var(--r-1); padding:var(--s-4); min-width:0}
|
|
93
|
+
.card h3{margin:var(--s-2) 0 var(--s-3); font-size:var(--t-body); font-weight:600}
|
|
94
|
+
.chip{display:inline-flex; align-items:center; gap:.4em; font-family:"IBM Plex Mono",monospace;
|
|
95
|
+
font-size:var(--t-label); font-weight:600; letter-spacing:.04em; border:1px solid currentColor;
|
|
96
|
+
border-radius:var(--r-1); padding:.15em .5em; color:var(--text-dim)}
|
|
97
|
+
.chip.ok{color:var(--ok)} .chip.warn{color:var(--warn)} .chip.risk{color:var(--risk)}
|
|
98
|
+
.chip.info{color:var(--info)} .chip.acc{color:var(--accent)}
|
|
99
|
+
table{border-collapse:collapse; width:100%}
|
|
100
|
+
th{font-family:"IBM Plex Mono",monospace; font-size:var(--t-label); font-weight:600; letter-spacing:.05em;
|
|
101
|
+
text-transform:uppercase; color:var(--text-dim); text-align:left; padding:var(--s-3) var(--s-4); background:var(--surface)}
|
|
102
|
+
td{padding:var(--s-3) var(--s-4); border-top:1px solid var(--border); vertical-align:top}
|
|
103
|
+
td code{background:none; padding:0; font-size:.8125rem}
|
|
104
|
+
.callout{background:var(--surface); border-radius:var(--r-1); padding:var(--s-4); display:flex; gap:var(--s-4); align-items:flex-start}
|
|
105
|
+
nav.toc{position:sticky; top:0; grid-column:1/4; align-self:start; padding:var(--s-5) 0; max-height:100vh; overflow:auto}
|
|
106
|
+
nav.toc a{display:block; color:var(--text-dim); text-decoration:none; font-size:var(--t-small); padding:.35em 0; border-left:2px solid transparent; padding-left:var(--s-4)}
|
|
107
|
+
nav.toc a.on{color:var(--accent); border-left-color:var(--accent)}
|
|
108
|
+
.layout{display:grid; grid-template-columns:repeat(12,1fr); gap:var(--s-5)}
|
|
109
|
+
@media (max-width:1000px){
|
|
110
|
+
nav.toc{position:sticky; top:0; z-index:5; grid-column:1/13; background:var(--bg);
|
|
111
|
+
border-bottom:1px solid var(--border); padding:var(--s-3) 0; margin:calc(-1 * var(--s-5)) calc(-1 * var(--s-5)) 0;
|
|
112
|
+
max-height:none; white-space:nowrap; overflow-x:auto; scrollbar-width:none}
|
|
113
|
+
nav.toc::-webkit-scrollbar{display:none}
|
|
114
|
+
nav.toc a{display:inline-block; border-left:none; padding:.35em .75em}
|
|
115
|
+
nav.toc::after{content:""; position:fixed; inset:auto auto auto 0}
|
|
116
|
+
}
|
|
117
|
+
.ve-steps .parts .part{transition:opacity var(--med) var(--ease), transform var(--med) var(--ease)}
|
|
118
|
+
.ve-steps[data-at="1"] .part[data-s="2"],.ve-steps[data-at="1"] .part[data-s="3"],.ve-steps[data-at="1"] .part[data-s="4"],
|
|
119
|
+
.ve-steps[data-at="2"] .part[data-s="3"],.ve-steps[data-at="2"] .part[data-s="4"],
|
|
120
|
+
.ve-steps[data-at="3"] .part[data-s="4"]{opacity:.12}
|
|
121
|
+
.ve-steps:not([data-at]) .part{opacity:1}
|
|
122
|
+
.ve-player{display:flex; align-items:center; gap:var(--s-3); margin:0 0 var(--s-3); flex-wrap:wrap}
|
|
123
|
+
.ve-player button{font-family:"IBM Plex Mono",monospace; font-size:var(--t-small); background:var(--surface);
|
|
124
|
+
border:1px solid var(--border-bright); color:var(--text); border-radius:var(--r-1); padding:var(--s-2) var(--s-3); cursor:pointer}
|
|
125
|
+
.ve-player button:hover,.ve-player button:focus-visible{border-color:var(--accent); outline:none}
|
|
126
|
+
.ve-player input[type=range]{flex:1 1 12rem}
|
|
127
|
+
.ve-cap{list-style:none; display:flex; gap:var(--s-6); margin:var(--s-3) 0 0; padding:0; font-size:var(--t-small); color:var(--text-dim)}
|
|
128
|
+
.ve-cap li{display:none; max-width:30ch}
|
|
129
|
+
.ve-cap li.on{display:block; color:var(--text)}
|
|
130
|
+
.btn-row{display:flex; gap:var(--s-3); flex-wrap:wrap}
|
|
131
|
+
.foot{font-size:var(--t-small); color:var(--text-dim)}
|
|
132
|
+
details{border:1px solid var(--border); border-radius:var(--r-1); padding:var(--s-3) var(--s-4); background:var(--surface)}
|
|
133
|
+
summary{cursor:pointer; font-family:"IBM Plex Mono",monospace; font-size:var(--t-small); font-weight:600}
|
|
134
|
+
::selection{background:var(--accent-dim)}
|
|
135
|
+
:focus-visible{outline:2px solid var(--accent); outline-offset:2px}
|
|
136
|
+
.js-motion .rise{opacity:0; transform:translateY(1rem)}
|
|
137
|
+
.js-motion .rise.seen{opacity:1; transform:none; transition:opacity var(--slow) var(--ease), transform var(--slow) var(--ease)}
|
|
138
|
+
@media print{ :root{color-scheme:light} body{background:#fff} nav.toc,.ve-player{display:none} .part{opacity:1!important} .frame{background-image:none} }
|
|
139
|
+
</style>
|
|
140
|
+
</head>
|
|
141
|
+
<body>
|
|
142
|
+
<svg width="0" height="0" aria-hidden="true"><defs>
|
|
143
|
+
<marker id="ve-ah" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="7" markerHeight="7" orient="auto-start-reverse"><path d="M0 0L10 5L0 10z" fill="context-stroke"/></marker>
|
|
144
|
+
<linearGradient id="ve-node" x1="0" y1="0" x2="0" y2="1"><stop offset="0" stop-color="var(--node-top)"/><stop offset="1" stop-color="var(--surface)"/></linearGradient>
|
|
145
|
+
</defs></svg>
|
|
146
|
+
|
|
147
|
+
<div class="wrap">
|
|
148
|
+
<header style="padding:var(--s-7) 0 var(--s-6)">
|
|
149
|
+
<div class="kicker">UAP · Mission orchestrator · PR 1 of the Choir uplift</div>
|
|
150
|
+
<h1>A mission outlives every process</h1>
|
|
151
|
+
<p class="lead">A prompt becomes a mission with <b>frozen acceptance criteria</b>. A systemd daemon polls the mission ledger every 300 s and keeps each mission moving — <b>across reboots, crashes, and session teardown</b> — until the criteria are met.</p>
|
|
152
|
+
<p class="meta">uap mission create · uap mission poll · uap-orchestrator.service · v2.17.0</p>
|
|
153
|
+
</header>
|
|
154
|
+
|
|
155
|
+
<div class="layout">
|
|
156
|
+
<nav class="toc" aria-label="Sections"><a href="#model">The model</a><a href="#cycle">One poll cycle</a><a href="#decisions">Decision table</a><a href="#backoff">Backoff</a><a href="#salvage">Struggle & salvage</a><a href="#freeze">Frozen acceptance</a><a href="#state">State on disk</a><a href="#sources">Sources</a></nav>
|
|
157
|
+
<div>
|
|
158
|
+
|
|
159
|
+
<section id="model" class="rise">
|
|
160
|
+
<div class="swiss"><div class="sl">Architecture</div><h2>The daemon owns the loop, not the run</h2></div>
|
|
161
|
+
<p>Deliver runs already survive their tool call, but nothing resumed them after a reboot or relaunched them after a crash. The mission layer fixes that: the <span class="mono" data-ref="ledger" tabindex="0">ledger</span> holds the goal, the <span class="mono" data-ref="daemon" tabindex="0">poll daemon</span> decides, and the <span class="mono" data-ref="run" tabindex="0">deliver run</span> does the work.</p>
|
|
162
|
+
<figure>
|
|
163
|
+
<div class="frame scroll">
|
|
164
|
+
<svg class="ve-svg" viewBox="0 0 960 400" role="img" aria-label="Operator creates a mission in the ledger; the orch poll daemon reads the ledger, launches or resumes a detached deliver run; the run writes its state file; the daemon supervises live runs and posts to the board.">
|
|
165
|
+
<g class="parts">
|
|
166
|
+
<!-- edges -->
|
|
167
|
+
<path class="ve-e" d="M240 105H360"/>
|
|
168
|
+
<text class="ve-el" x="252" y="95">creates + freezes</text>
|
|
169
|
+
<path class="ve-e" d="M600 200V135"/>
|
|
170
|
+
<text class="ve-el" x="612" y="192">writes</text>
|
|
171
|
+
<text class="ve-el" x="612" y="176">checkpoint</text>
|
|
172
|
+
<path class="ve-e" d="M590 250H480"/>
|
|
173
|
+
<text class="ve-el" x="497" y="240">run state + pid</text>
|
|
174
|
+
<path class="ve-e" d="M640 90V135"/>
|
|
175
|
+
<text class="ve-el" x="652" y="112">supervise once</text>
|
|
176
|
+
<path class="ve-e is-async" d="M560 70H400"/>
|
|
177
|
+
<text class="ve-el" x="410" y="60">mission:#N marker</text>
|
|
178
|
+
<!-- hot path: daemon drives the mission -->
|
|
179
|
+
<path class="ve-e is-hot part" data-s="3" d="M420 240V160"/>
|
|
180
|
+
<text class="ve-el acc part" data-s="3" x="432" y="205">launch / resume</text>
|
|
181
|
+
<!-- flow dots route -->
|
|
182
|
+
<path data-flow="poll" data-every="3000" d="M420 160V240H590V200V135H560" fill="none" stroke="none"/>
|
|
183
|
+
<g class="ve-dots" aria-hidden="true"></g>
|
|
184
|
+
<!-- nodes -->
|
|
185
|
+
<g class="ve-n"><rect class="sh" x="60" y="70" width="180" height="70" rx="6"/><text x="150" y="100" text-anchor="middle">operator</text><text class="sub" x="150" y="120" text-anchor="middle">uap mission create</text></g>
|
|
186
|
+
<g class="ve-n part" data-s="1" data-ref="ledger"><rect class="sh" x="360" y="70" width="240" height="70" rx="6"/><text x="480" y="100" text-anchor="middle">missions.db</text><text class="sub" x="480" y="120" text-anchor="middle">frozen acceptance · attempts</text></g>
|
|
187
|
+
<g class="ve-n is-key part" data-s="2" data-ref="daemon"><rect class="sh" x="300" y="240" width="180" height="70" rx="6"/><text x="390" y="270" text-anchor="middle">uap mission poll</text><text class="sub" x="390" y="290" text-anchor="middle">systemd · every 300 s</text></g>
|
|
188
|
+
<g class="ve-n part" data-s="2" data-ref="run"><rect class="sh" x="590" y="135" width="240" height="65" rx="6"/><text x="710" y="163" text-anchor="middle">uap deliver run</text><text class="sub" x="710" y="183" text-anchor="middle">detached · checkpointed</text></g>
|
|
189
|
+
<g class="ve-n part" data-s="4"><rect class="sh" x="590" y="245" width="180" height="55" rx="6"/><text x="680" y="268" text-anchor="middle">coordination</text><text class="sub" x="680" y="286" text-anchor="middle">board · salvage asks</text></g>
|
|
190
|
+
<g class="ve-n part" data-s="4"><rect class="sh" x="60" y="240" width="180" height="55" rx="6"/><text x="150" y="263" text-anchor="middle">salvage gate</text><text class="sub" x="150" y="281" text-anchor="middle">approve / reject</text></g>
|
|
191
|
+
</g>
|
|
192
|
+
</svg>
|
|
193
|
+
</div>
|
|
194
|
+
<figcaption><span class="fn">Fig. 1</span>The poll daemon is the loop clock: it reads the ledger, drives the deliver run, and reports. The run never drives itself.</figcaption>
|
|
195
|
+
</figure>
|
|
196
|
+
<div class="kpis rise">
|
|
197
|
+
<div class="kpi"><div class="k">Poll interval</div><div class="v" data-count="300">0<small> s</small></div><svg width="100" height="24" role="img" aria-label="one tick every 300 seconds"><polyline points="0,18 25,18 25,6 50,6 50,18 75,18 75,6 100,6" fill="none" stroke="var(--info)" stroke-width="1.75" vector-effect="non-scaling-stroke"/></svg></div>
|
|
198
|
+
<div class="kpi"><div class="k">Backoff cap</div><div class="v" data-count="1440">0<small> min</small></div><svg width="100" height="24" role="img" aria-label="backoff doubles to a cap of 1440 minutes"><polyline points="0,20 30,17 55,12 80,4 100,4" fill="none" stroke="var(--warn)" stroke-width="1.75" vector-effect="non-scaling-stroke"/></svg></div>
|
|
199
|
+
<div class="kpi"><div class="k">Struggle threshold</div><div class="v" data-count="3">0<small> fails</small></div><svg width="100" height="24" role="img" aria-label="escalation proposed after 3 failed attempts"><rect x="8" y="8" width="8" height="8" fill="var(--risk)"/><rect x="38" y="8" width="8" height="8" fill="var(--risk)"/><rect x="68" y="8" width="8" height="8" fill="var(--risk)"/></svg></div>
|
|
200
|
+
<div class="kpi"><div class="k">Launch grace</div><div class="v" data-count="10">0<small> min</small></div><svg width="100" height="24" role="img" aria-label="10 minute grace before a launch is retried"><rect x="0" y="10" width="60" height="6" fill="var(--border-bright)"/><rect x="60" y="10" width="40" height="6" fill="var(--accent)"/></svg></div>
|
|
201
|
+
</div>
|
|
202
|
+
</section>
|
|
203
|
+
|
|
204
|
+
<section id="cycle" class="rise">
|
|
205
|
+
<div class="swiss"><div class="sl">Poll cycle</div><h2>Discover, sync, decide, act — every 300 s</h2></div>
|
|
206
|
+
<figure class="ve-steps" data-at="">
|
|
207
|
+
<div class="ve-player">
|
|
208
|
+
<button data-go="-1" type="button">‹ Prev</button>
|
|
209
|
+
<button data-play type="button">Play</button>
|
|
210
|
+
<input type="range" min="1" max="4" value="4" step="1" aria-label="Poll cycle step">
|
|
211
|
+
<button data-go="1" type="button">Next ›</button>
|
|
212
|
+
</div>
|
|
213
|
+
<div class="frame scroll">
|
|
214
|
+
<svg class="ve-svg" viewBox="0 0 960 260" role="img" aria-label="One poll cycle: discover links the run by its mission marker; sync records terminal states as attempts; decide applies the decision table; act supervises, relaunches, or closes.">
|
|
215
|
+
<g class="parts">
|
|
216
|
+
<g class="part" data-s="1"><rect x="20" y="20" width="220" height="40" rx="6" fill="none" stroke="var(--info)" stroke-width="1.5"/><text class="ve-el" x="30" y="42" fill="var(--info)">1 · DISCOVER</text><text class="ve-el" x="30" y="70" fill="var(--text)">run ← [mission:#N] marker</text></g>
|
|
217
|
+
<g class="part" data-s="2"><rect x="260" y="20" width="220" height="40" rx="6" fill="none" stroke="var(--info)" stroke-width="1.5"/><text class="ve-el" x="270" y="42" fill="var(--info)">2 · SYNC</text><text class="ve-el" x="270" y="70" fill="var(--text)">terminal run → attempt rows</text></g>
|
|
218
|
+
<g class="part" data-s="3"><rect x="500" y="20" width="220" height="40" rx="6" fill="none" stroke="var(--info)" stroke-width="1.5"/><text class="ve-el" x="510" y="42" fill="var(--info)">3 · DECIDE</text><text class="ve-el" x="510" y="70" fill="var(--text)">pure decision table</text></g>
|
|
219
|
+
<g class="part" data-s="4"><rect x="740" y="20" width="200" height="40" rx="6" fill="none" stroke="var(--accent)" stroke-width="2"/><text class="ve-el acc" x="750" y="42" fill="var(--accent)">4 · ACT</text><text class="ve-el" x="750" y="70" fill="var(--text)">supervise / relaunch / close</text></g>
|
|
220
|
+
<path class="ve-e part" data-s="2" d="M240 40H260" marker-end="none"/>
|
|
221
|
+
<path class="ve-e part" data-s="3" d="M480 40H500" marker-end="none"/>
|
|
222
|
+
<path class="ve-e part" data-s="4" d="M720 40H740" marker-end="none"/>
|
|
223
|
+
<!-- row 2: detail shapes -->
|
|
224
|
+
<g class="ve-n part" data-s="1"><rect class="sh" x="60" y="120" width="160" height="50" rx="6"/><text x="140" y="142" text-anchor="middle">run-4f2</text><text class="sub" x="140" y="160" text-anchor="middle">any status</text></g>
|
|
225
|
+
<path class="ve-e part" data-s="1" d="M220 145H320"/>
|
|
226
|
+
<g class="ve-n part" data-s="2"><rect class="sh" x="320" y="120" width="160" height="50" rx="6"/><text x="400" y="142" text-anchor="middle">attempts</text><text class="sub" x="400" y="160" text-anchor="middle">idempotent rows</text></g>
|
|
227
|
+
<path class="ve-e part" data-s="3" d="M480 145H600"/>
|
|
228
|
+
<g class="ve-n part is-key" data-s="3"><rect class="sh" x="600" y="120" width="160" height="50" rx="6"/><text x="680" y="142" text-anchor="middle">decision</text><text class="sub" x="680" y="160" text-anchor="middle">5-row table</text></g>
|
|
229
|
+
<path class="ve-e part" data-s="4" d="M760 145H860V95"/>
|
|
230
|
+
<text class="ve-el part" data-s="4" x="800" y="240" fill="var(--text)">a cycle never throws —</text>
|
|
231
|
+
<text class="ve-el part" data-s="4" x="800" y="258" fill="var(--text)">notes, not a dead daemon</text>
|
|
232
|
+
</g>
|
|
233
|
+
</svg>
|
|
234
|
+
</div>
|
|
235
|
+
<ol class="ve-cap">
|
|
236
|
+
<li data-n="1/4">Discover: link the fresh launch's run to its mission by the embedded marker. Any status — a short mission can deliver inside one interval.</li>
|
|
237
|
+
<li data-n="2/4">Sync: terminal run states become attempt rows. A running state whose pid is gone is recorded as interrupted.</li>
|
|
238
|
+
<li data-n="3/4">Decide: the pure decision table picks the actions from the ledger plus the run state.</li>
|
|
239
|
+
<li data-n="4/4">Act: supervise, relaunch, close, or wait — and the cycle survives its own errors.</li>
|
|
240
|
+
</ol>
|
|
241
|
+
<figcaption><span class="fn">Fig. 2</span>One poll cycle in four steps. Step through it.</figcaption>
|
|
242
|
+
</figure>
|
|
243
|
+
</section>
|
|
244
|
+
|
|
245
|
+
<section id="decisions" class="rise">
|
|
246
|
+
<div class="swiss"><div class="sl">Decision table</div><h2>Five run states, five moves</h2></div>
|
|
247
|
+
<p>Each card is the same drawing: the ledger's view of the run, and what the daemon does about it. The changed part carries the case's status color.</p>
|
|
248
|
+
<div class="cards">
|
|
249
|
+
<div class="card"><span class="chip info">◆ no run</span><h3>Launch fresh</h3><svg viewBox="0 0 200 90" width="100%" role="img" aria-label="no run: launch"><rect x="20" y="30" width="60" height="30" rx="4" fill="var(--accent-dim)" stroke="var(--accent)" stroke-width="2"/><text class="ve-el" x="50" y="49" text-anchor="middle" fill="var(--accent)">launch</text><rect x="120" y="30" width="60" height="30" rx="4" fill="none" stroke="var(--border-bright)" stroke-width="1.5" stroke-dasharray="4 4"/><text class="ve-el" x="150" y="49" text-anchor="middle">run</text><path class="ve-e" d="M80 45H118"/></svg><p style="font-size:.8125rem;color:var(--text-dim);margin:0">Within the 10 min grace: wait — the launch is still registering.</p></div>
|
|
250
|
+
<div class="card"><span class="chip ok">● live</span><h3>Supervise once</h3><svg viewBox="0 0 200 90" width="100%" role="img" aria-label="running with live pid: supervise"><rect x="20" y="30" width="60" height="30" rx="4" fill="none" stroke="var(--border-bright)" stroke-width="1.5"/><text class="ve-el" x="50" y="49" text-anchor="middle">run</text><path class="ve-e" d="M80 45H118"/><rect x="120" y="30" width="60" height="30" rx="4" fill="var(--accent-dim)" stroke="var(--accent)" stroke-width="2"/><text class="ve-el" x="150" y="49" text-anchor="middle" fill="var(--accent)">watch</text><circle cx="50" cy="17" r="4" fill="var(--ok)"/></svg><p style="font-size:.8125rem;color:var(--text-dim);margin:0">One <code>runSupervisor</code> cycle. It watches — STOP/RETRY/ESCALATE by policy, never signals.</p></div>
|
|
251
|
+
<div class="card"><span class="chip risk">■ pid gone</span><h3>Mark interrupted, relaunch</h3><svg viewBox="0 0 200 90" width="100%" role="img" aria-label="running with dead pid: record interrupted and relaunch"><rect x="20" y="30" width="60" height="30" rx="4" fill="none" stroke="var(--risk)" stroke-width="1.5"/><text class="ve-el" x="50" y="49" text-anchor="middle" fill="var(--risk)">run?</text><path class="ve-e" d="M80 45H118"/><rect x="120" y="30" width="60" height="30" rx="4" fill="var(--accent-dim)" stroke="var(--accent)" stroke-width="2"/><text class="ve-el" x="150" y="49" text-anchor="middle" fill="var(--accent)">resume</text><path d="M50 12l5 5-5 5" stroke="var(--risk)" stroke-width="1.75" fill="none"/></svg><p style="font-size:.8125rem;color:var(--text-dim);margin:0">A crash that never marked itself. The state file says running; the pid says otherwise.</p></div>
|
|
252
|
+
<div class="card"><span class="chip warn">▲ terminal</span><h3>Salvage, then resume</h3><svg viewBox="0 0 200 90" width="100%" role="img" aria-label="interrupted or failed: salvage proposal then relaunch with backoff"><rect x="20" y="30" width="60" height="30" rx="4" fill="none" stroke="var(--warn)" stroke-width="1.5"/><text class="ve-el" x="50" y="49" text-anchor="middle" fill="var(--warn)">stopped</text><path class="ve-e" d="M80 45H118"/><rect x="120" y="30" width="60" height="30" rx="4" fill="var(--accent-dim)" stroke="var(--accent)" stroke-width="2"/><text class="ve-el" x="150" y="49" text-anchor="middle" fill="var(--accent)">resume</text><text class="ve-el" x="100" y="78" text-anchor="middle">salvage proposal first</text></svg><p style="font-size:.8125rem;color:var(--text-dim);margin:0">First relaunch is immediate. Repeated failures wait: 15, 30, 60 min…</p></div>
|
|
253
|
+
<div class="card"><span class="chip ok">● delivered</span><h3>Close the mission</h3><svg viewBox="0 0 200 90" width="100%" role="img" aria-label="delivered run closes the mission"><rect x="20" y="30" width="60" height="30" rx="4" fill="none" stroke="var(--ok)" stroke-width="1.5"/><text class="ve-el" x="50" y="49" text-anchor="middle" fill="var(--ok)">green</text><path class="ve-e" d="M80 45H118"/><rect x="120" y="30" width="60" height="30" rx="4" fill="var(--accent-dim)" stroke="var(--accent)" stroke-width="2"/><text class="ve-el" x="150" y="49" text-anchor="middle" fill="var(--accent)">closed</text><text class="ve-el" x="100" y="78" text-anchor="middle">board note: delivered</text></svg><p style="font-size:.8125rem;color:var(--text-dim);margin:0">The run converged against the real gates. The mission is done.</p></div>
|
|
254
|
+
</div>
|
|
255
|
+
</section>
|
|
256
|
+
|
|
257
|
+
<section id="backoff" class="rise">
|
|
258
|
+
<div class="swiss"><div class="sl">Backoff</div><h2>First resume is immediate; repeats double</h2></div>
|
|
259
|
+
<p>A clean interruption is the healthy case, not a crash loop, so the first relaunch happens at once. Only <b>repeated</b> failures back off — the same lesson as the systemd start-rate limiter: back off, do not hammer.</p>
|
|
260
|
+
<figure>
|
|
261
|
+
<div class="frame scroll">
|
|
262
|
+
<svg class="ve-svg" viewBox="0 0 960 260" role="img" aria-label="Bar chart: wait before relaunch number 1 is zero minutes, then 15, 30, 60, 120 minutes, doubling to a cap of 1440 minutes.">
|
|
263
|
+
<g class="parts">
|
|
264
|
+
<text class="ve-el" x="40" y="30" fill="var(--text-dim)">minutes waited before relaunch</text>
|
|
265
|
+
<g>
|
|
266
|
+
<rect x="40" y="210" width="120" height="8" fill="var(--accent)"/><text class="ve-el" x="40" y="235">relaunch 1</text><text class="ve-el acc" x="170" y="205" fill="var(--accent)">0 — immediate</text>
|
|
267
|
+
<rect x="240" y="175" width="120" height="43" fill="var(--border-bright)"/><text class="ve-el" x="240" y="235">relaunch 2</text><text class="ve-el" x="370" y="180">15 min</text>
|
|
268
|
+
<rect x="440" y="135" width="120" height="83" fill="var(--border-bright)"/><text class="ve-el" x="440" y="235">relaunch 3</text><text class="ve-el" x="570" y="140">30 min</text>
|
|
269
|
+
<rect x="640" y="75" width="120" height="143" fill="var(--border-bright)"/><text class="ve-el" x="640" y="235">relaunch 4</text><text class="ve-el" x="770" y="80">60 min</text>
|
|
270
|
+
<rect x="840" y="30" width="60" height="188" fill="var(--warn)"/><text class="ve-el" x="812" y="235">…cap</text><text class="ve-el" x="812" y="55" fill="var(--warn)">1440</text>
|
|
271
|
+
</g>
|
|
272
|
+
</g>
|
|
273
|
+
</svg>
|
|
274
|
+
</div>
|
|
275
|
+
<figcaption><span class="fn">Fig. 3</span>Backoff after spent resumes. The cap is one day, so a wedged mission retries daily instead of hammering.</figcaption>
|
|
276
|
+
</figure>
|
|
277
|
+
</section>
|
|
278
|
+
|
|
279
|
+
<section id="salvage" class="rise">
|
|
280
|
+
<div class="swiss"><div class="sl">Struggle & salvage</div><h2>The orchestrator proposes; the overseer rules</h2></div>
|
|
281
|
+
<p>Every failed attempt seeds a <span class="mono" data-ref="ledger" tabindex="0">salvage proposal</span>: what happened, what partial work exists, what to try next. Nothing schedules until a human — or an overseer agent — approves.</p>
|
|
282
|
+
<div class="callout" style="margin-bottom:var(--s-5)"><span class="chip warn">▲ struggling</span><p style="margin:0">Past <b>3 failures</b> on one task, the proposal turns into an escalation ask — posted to the collaboration board, still approval-gated: <code>uap mission salvage approve <id></code>.</p></div>
|
|
283
|
+
<figure>
|
|
284
|
+
<div class="frame scroll">
|
|
285
|
+
<svg class="ve-svg" viewBox="0 0 960 200" role="img" aria-label="Attempt failures accumulate into the struggle metric; at three failures the daemon proposes escalation on the board; approval gates what runs next.">
|
|
286
|
+
<g class="parts">
|
|
287
|
+
<g class="ve-n"><rect class="sh" x="40" y="60" width="200" height="70" rx="6"/><text x="140" y="90" text-anchor="middle">attempt ledger</text><text class="sub" x="140" y="110" text-anchor="middle">fails per task ref</text></g>
|
|
288
|
+
<path class="ve-e" d="M240 95H360"/><text class="ve-el" x="255" y="85">3 fails</text>
|
|
289
|
+
<g class="ve-n"><rect class="sh" x="360" y="60" width="220" height="70" rx="6"/><text x="470" y="90" text-anchor="middle">salvage proposal</text><text class="sub" x="470" y="110" text-anchor="middle">failure + partial work</text></g>
|
|
290
|
+
<path class="ve-e is-async" d="M580 95H700"/><text class="ve-el" x="592" y="85">posts ask</text>
|
|
291
|
+
<g class="ve-n"><rect class="sh" x="700" y="60" width="220" height="70" rx="6"/><text x="810" y="90" text-anchor="middle">board + approval</text><text class="sub" x="810" y="110" text-anchor="middle">escalate / decompose</text></g>
|
|
292
|
+
<path class="ve-e" d="M810 130V175H140V135"/><text class="ve-el" x="430" y="168">approve → next run follows the ruling</text>
|
|
293
|
+
</g>
|
|
294
|
+
</svg>
|
|
295
|
+
</div>
|
|
296
|
+
<figcaption><span class="fn">Fig. 4</span>The Choir split: the daemon drafts follow-ups from failure residue; the overseer decides what actually runs.</figcaption>
|
|
297
|
+
</figure>
|
|
298
|
+
</section>
|
|
299
|
+
|
|
300
|
+
<section id="freeze" class="rise">
|
|
301
|
+
<div class="swiss"><div class="sl">Frozen acceptance</div><h2>"Complete" means the hash matches</h2></div>
|
|
302
|
+
<p>Acceptance criteria are hashed at creation. The criteria travel inside every run instruction, so the acceptance judge grades the frozen text — not a paraphrase. Change requires an explicit replan that records the prior text, hash, and reason.</p>
|
|
303
|
+
<figure>
|
|
304
|
+
<div class="frame scroll">
|
|
305
|
+
<svg class="ve-svg" viewBox="0 0 960 210" role="img" aria-label="Acceptance text is hashed and frozen at mission creation. A replan supersedes it through a recorded revision.">
|
|
306
|
+
<g class="parts">
|
|
307
|
+
<g class="ve-n"><rect class="sh" x="40" y="60" width="240" height="80" rx="6"/><text x="160" y="90" text-anchor="middle">acceptance text</text><text class="sub" x="160" y="110" text-anchor="middle">"tests + tsc pass, no new debt"</text></g>
|
|
308
|
+
<path class="ve-e is-hot" d="M280 100H420"/><text class="ve-el acc" x="292" y="90">sha256 at create</text>
|
|
309
|
+
<g class="ve-n is-key"><rect class="sh" x="420" y="60" width="240" height="80" rx="6"/><text x="540" y="90" text-anchor="middle">frozen hash</text><text class="sub" x="540" y="110" text-anchor="middle">travels in every run</text></g>
|
|
310
|
+
<path class="ve-e is-async" d="M660 100H800"/><text class="ve-el" x="672" y="90">replan only</text>
|
|
311
|
+
<g class="ve-n"><rect class="sh" x="800" y="60" width="120" height="80" rx="6"/><text x="860" y="90" text-anchor="middle">revision</text><text class="sub" x="860" y="110" text-anchor="middle">prior + reason</text></g>
|
|
312
|
+
<path class="ve-e" d="M860 140V185H160V140"/><text class="ve-el" x="450" y="178">supersede recorded — never silent</text>
|
|
313
|
+
</g>
|
|
314
|
+
</svg>
|
|
315
|
+
</div>
|
|
316
|
+
<figcaption><span class="fn">Fig. 5</span>Statement immutability, UAP edition. The merge gate (PR 2) will check this same hash before any merge.</figcaption>
|
|
317
|
+
</figure>
|
|
318
|
+
</section>
|
|
319
|
+
|
|
320
|
+
<section id="state" class="rise">
|
|
321
|
+
<div class="swiss"><div class="sl">State on disk</div><h2>Everything the daemon needs survives a reboot</h2></div>
|
|
322
|
+
<div class="scroll" style="border:1px solid var(--border);border-radius:var(--r-1)">
|
|
323
|
+
<table>
|
|
324
|
+
<thead><tr><th>Store</th><th>Path</th><th>Keeps</th></tr></thead>
|
|
325
|
+
<tbody>
|
|
326
|
+
<tr><td>Mission ledger</td><td><code>.uap/missions.db</code></td><td>Goals, frozen hashes, attempts, salvage, replans (SQLite, WAL)</td></tr>
|
|
327
|
+
<tr><td>Run state</td><td><code>.uap/deliver-runs/<runId>/state.json</code></td><td>Checkpoint, phases, pid — resume picks up at the boundary</td></tr>
|
|
328
|
+
<tr><td>Supervisor</td><td><code>.uap/supervise/<runId>/</code></td><td>Decision state + events</td></tr>
|
|
329
|
+
<tr><td>Orch run logs</td><td><code>.uap/orch-logs/orch-<stamp>.log</code></td><td>Output of daemon-spawned runs</td></tr>
|
|
330
|
+
<tr><td>Stop latch</td><td><code>.uap/deliver-runs/STOP</code></td><td>Cooperative stop; the supervisor uses the same latch</td></tr>
|
|
331
|
+
</tbody>
|
|
332
|
+
</table>
|
|
333
|
+
</div>
|
|
334
|
+
</section>
|
|
335
|
+
|
|
336
|
+
<section id="sources" class="rise">
|
|
337
|
+
<div class="swiss"><div class="sl">Sources</div><h2>Where this lives in the repo</h2></div>
|
|
338
|
+
<ul style="line-height:1.9">
|
|
339
|
+
<li><code>src/mission/ledger.ts</code> — mission ledger service (frozen acceptance, attempts, salvage)</li>
|
|
340
|
+
<li><code>src/mission/poll-cycle.ts</code> — pure decision table (STRUGGLE_THRESHOLD, LAUNCH_GRACE_MS, backoff)</li>
|
|
341
|
+
<li><code>src/mission/poll-executor.ts</code> — seam-injected executor, run discovery, detached spawning</li>
|
|
342
|
+
<li><code>src/cli/mission.ts</code>, <code>src/cli/orch.ts</code> — command surfaces</li>
|
|
343
|
+
<li><code>src/cli/systemd-services.ts</code> — <code>uap-orchestrator.service</code> install</li>
|
|
344
|
+
<li><code>test/mission/</code> — 36 tests over ledger, decision table, executor</li>
|
|
345
|
+
<li><code>docs/guides/MISSIONS.md</code> — the operator guide</li>
|
|
346
|
+
<li>Choir (Weber GeoML, Apache-2.0) — the protocol this uplift borrows its loop-clock and gate ideas from</li>
|
|
347
|
+
</ul>
|
|
348
|
+
</section>
|
|
349
|
+
|
|
350
|
+
</div></div>
|
|
351
|
+
<footer style="border-top:1px solid var(--border);margin-top:var(--s-8);padding:var(--s-6) 0 var(--s-8)">
|
|
352
|
+
<p class="foot">Universal Agent Protocol · mission orchestrator, v2.17.0 · one self-contained file, no build, no JS dependencies.</p>
|
|
353
|
+
</footer>
|
|
354
|
+
</div>
|
|
355
|
+
|
|
356
|
+
<script>
|
|
357
|
+
(function(){
|
|
358
|
+
"use strict";
|
|
359
|
+
var motionOK = !window.matchMedia("(prefers-reduced-motion: reduce)").matches;
|
|
360
|
+
|
|
361
|
+
/* entrance */
|
|
362
|
+
document.documentElement.classList.add("js-motion");
|
|
363
|
+
if (motionOK){
|
|
364
|
+
var io = new IntersectionObserver(function(es){
|
|
365
|
+
es.forEach(function(e){ if(e.isIntersecting){ e.target.classList.add("seen"); io.unobserve(e.target);} });
|
|
366
|
+
}, {threshold:.15});
|
|
367
|
+
document.querySelectorAll(".rise").forEach(function(el){ io.observe(el); });
|
|
368
|
+
} else {
|
|
369
|
+
document.querySelectorAll(".rise").forEach(function(el){ el.classList.add("seen"); });
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
/* count-up */
|
|
373
|
+
document.querySelectorAll("[data-count]").forEach(function(el){
|
|
374
|
+
var target = parseInt(el.getAttribute("data-count"),10), suffix = el.querySelector("small");
|
|
375
|
+
var suffixHTML = suffix ? suffix.outerHTML : "";
|
|
376
|
+
function render(v){ el.firstChild.nodeValue = String(v); }
|
|
377
|
+
if (!motionOK){ render(target); return; }
|
|
378
|
+
var t0 = null;
|
|
379
|
+
new IntersectionObserver(function(es, obs){
|
|
380
|
+
es.forEach(function(e){
|
|
381
|
+
if(!e.isIntersecting) return; obs.unobserve(el);
|
|
382
|
+
requestAnimationFrame(function step(ts){
|
|
383
|
+
if(!t0) t0 = ts;
|
|
384
|
+
var p = Math.min(1,(ts-t0)/900), eased = 1-Math.pow(1-p,3);
|
|
385
|
+
render(Math.round(target*eased));
|
|
386
|
+
if(p<1) requestAnimationFrame(step);
|
|
387
|
+
});
|
|
388
|
+
});
|
|
389
|
+
},{threshold:.4}).observe(el);
|
|
390
|
+
});
|
|
391
|
+
|
|
392
|
+
/* linked highlighting */
|
|
393
|
+
document.querySelectorAll("[data-ref]").forEach(function(el){
|
|
394
|
+
el.addEventListener("mouseenter", on); el.addEventListener("mouseleave", off);
|
|
395
|
+
el.addEventListener("focus", on); el.addEventListener("blur", off);
|
|
396
|
+
});
|
|
397
|
+
function on(){ toggle(this.getAttribute("data-ref"), true); }
|
|
398
|
+
function off(){ toggle(this.getAttribute("data-ref"), false); }
|
|
399
|
+
function toggle(ref, hot){
|
|
400
|
+
document.querySelectorAll("[data-ref='"+ref+"']").forEach(function(el){ el.style.color = hot ? "var(--accent)" : ""; });
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
/* stepper */
|
|
404
|
+
document.querySelectorAll("figure.ve-steps").forEach(function(fig){
|
|
405
|
+
var range = fig.querySelector("input[type=range]"), at = 4;
|
|
406
|
+
var caps = fig.querySelectorAll(".ve-cap li");
|
|
407
|
+
function show(n){
|
|
408
|
+
at = Math.max(1, Math.min(4, n));
|
|
409
|
+
fig.setAttribute("data-at", String(at));
|
|
410
|
+
range.value = String(at);
|
|
411
|
+
caps.forEach(function(li){ li.classList.toggle("on", li.getAttribute("data-n") === at+"/4"); });
|
|
412
|
+
}
|
|
413
|
+
fig.querySelectorAll("[data-go]").forEach(function(b){
|
|
414
|
+
b.addEventListener("click", function(){ show(at + parseInt(b.getAttribute("data-go"),10)); stop(); });
|
|
415
|
+
});
|
|
416
|
+
range.addEventListener("input", function(){ show(parseInt(range.value,10)); stop(); });
|
|
417
|
+
var timer = null;
|
|
418
|
+
var play = fig.querySelector("[data-play]");
|
|
419
|
+
function stop(){ if(timer){ clearInterval(timer); timer=null; play.textContent="Play"; } }
|
|
420
|
+
play.addEventListener("click", function(){
|
|
421
|
+
if (timer){ stop(); return; }
|
|
422
|
+
var next = at >= 4 ? 1 : at+1; show(next);
|
|
423
|
+
timer = setInterval(function(){ if(at>=4){ stop(); return; } show(at+1); }, 2600);
|
|
424
|
+
play.textContent = "Stop";
|
|
425
|
+
});
|
|
426
|
+
});
|
|
427
|
+
|
|
428
|
+
/* scroll spy */
|
|
429
|
+
var links = document.querySelectorAll("nav.toc a");
|
|
430
|
+
var secs = [];
|
|
431
|
+
links.forEach(function(a){ var s = document.querySelector(a.getAttribute("href")); if(s) secs.push([a,s]); });
|
|
432
|
+
if ("IntersectionObserver" in window){
|
|
433
|
+
var spy = new IntersectionObserver(function(es){
|
|
434
|
+
es.forEach(function(e){
|
|
435
|
+
if(!e.isIntersecting) return;
|
|
436
|
+
links.forEach(function(a){ a.classList.remove("on"); });
|
|
437
|
+
var hit = secs.find(function(pair){ return pair[1] === e.target; });
|
|
438
|
+
if (hit){ hit[0].classList.add("on");
|
|
439
|
+
try { history.replaceState(null, "", hit[0].getAttribute("href")); } catch(err) {}
|
|
440
|
+
}
|
|
441
|
+
});
|
|
442
|
+
}, {rootMargin:"-10% 0px -80% 0px"});
|
|
443
|
+
secs.forEach(function(pair){ spy.observe(pair[1]); });
|
|
444
|
+
}
|
|
445
|
+
|
|
446
|
+
/* flow dots (only on screen + motion allowed) */
|
|
447
|
+
if (motionOK){
|
|
448
|
+
document.querySelectorAll("[data-flow]").forEach(function(route){
|
|
449
|
+
var every = parseInt(route.getAttribute("data-every"),10) || 3000;
|
|
450
|
+
var layer = route.closest("svg").querySelector(".ve-dots"); if(!layer) return;
|
|
451
|
+
var visible = false;
|
|
452
|
+
new IntersectionObserver(function(es){ es.forEach(function(e){ visible = e.isIntersecting; }); }).observe(route.closest("figure"));
|
|
453
|
+
var svg = route.closest("svg"), len = route.getTotalLength();
|
|
454
|
+
setInterval(function(){
|
|
455
|
+
if(!visible) return;
|
|
456
|
+
var dot = document.createElementNS("http://www.w3.org/2000/svg","circle");
|
|
457
|
+
dot.setAttribute("r","3.2"); dot.setAttribute("fill","var(--accent)");
|
|
458
|
+
layer.appendChild(dot);
|
|
459
|
+
var t0 = performance.now(), dur = 2200;
|
|
460
|
+
(function anim(now){
|
|
461
|
+
var p = Math.min(1,(now-t0)/dur);
|
|
462
|
+
var pt = route.getPointAtLength(len*p);
|
|
463
|
+
dot.setAttribute("cx",String(pt.x)); dot.setAttribute("cy",String(pt.y));
|
|
464
|
+
if(p<1) requestAnimationFrame(anim); else dot.remove();
|
|
465
|
+
})(t0);
|
|
466
|
+
}, every);
|
|
467
|
+
});
|
|
468
|
+
}
|
|
469
|
+
})();
|
|
470
|
+
</script>
|
|
471
|
+
</body>
|
|
472
|
+
</html>
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@miller-tech/uap",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.19.5",
|
|
4
4
|
"description": "Autonomous AI agent memory system with CLAUDE.md protocol enforcement",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -21,7 +21,7 @@
|
|
|
21
21
|
"start": "node dist/bin/cli.js",
|
|
22
22
|
"test": "vitest",
|
|
23
23
|
"test:ci": "vitest run",
|
|
24
|
-
"test:enforcers": "UAP_PROXY_ENV_AUTOLOAD=0 python3 -m unittest tools.agents.tests.test_enforcement_self_protect tools.agents.tests.test_conditional_destructive_verbs tools.agents.tests.test_live_deliver_kill tools.agents.tests.test_schema_diff_gate tools.agents.tests.test_schema_diff_inline tools.agents.tests.test_stream_telemetry tools.agents.tests.test_project_telemetry_events tools.agents.tests.test_workdir_scope_enforcer tools.agents.tests.test_gate_evidence tools.agents.tests.test_repeat_call_guard tools.agents.tests.test_repeat_guard tools.agents.tests.test_gate_integrity tools.agents.tests.test_gate_failclosed_indirection tools.agents.tests.test_gate_failclosed_schema_diff tools.agents.tests.test_expert_review_pr_scope tools.agents.tests.test_path_containment tools.agents.tests.test_path_normalizer_hardened tools.agents.tests.test_sandbox_tool_strip tools.agents.tests.test_proxy_env_loader tools.agents.tests.test_stream_required_tool tools.agents.tests.test_tool_call_wrapper_profiles tools.agents.tests.test_tool_convert_cache tools.agents.tests.test_doubling_break tools.agents.tests.test_error_loop_ignores_correctives tools.agents.tests.test_anthropic_proxy_tool_arg_types tools.agents.tests.test_anthropic_sse_schema tools.agents.tests.test_attractor_detection tools.agents.tests.test_client_disconnect tools.agents.tests.test_confidence_escalation tools.agents.tests.test_coordination_ban tools.agents.tests.test_coordination_early_ban tools.agents.tests.test_cycle_break_exploration tools.agents.tests.test_deferral_break tools.agents.tests.test_deliver_autoroute tools.agents.tests.test_delivery_enforcement_all_langs tools.agents.tests.test_delivery_enforcement_exemptions tools.agents.tests.test_delivery_enforcement_filepath tools.agents.tests.test_delivery_enforcement_write_complexity tools.agents.tests.test_fastpath_config tools.agents.tests.test_delivery_enforcement_web_and_bash tools.agents.tests.test_disconnect_watcher tools.agents.tests.test_empty_maxtokens_recovery tools.agents.tests.test_empty_tool_loop_break tools.agents.tests.test_enforcer_escape_hatches tools.agents.tests.test_error_loop_break tools.agents.tests.test_finalize_suppression tools.agents.tests.test_malformed_unclosed_think tools.agents.tests.test_mandate_beats_recon tools.agents.tests.test_mandate_deliver tools.agents.tests.test_overflow_truncate_count_tokens tools.agents.tests.test_count_tokens_scale_per_session tools.agents.tests.test_passthrough_oauth tools.agents.tests.test_project_telemetry tools.agents.tests.test_proxy_auth_headers tools.agents.tests.test_prune_preserve_force_write tools.agents.tests.test_recon_deliver_gate tools.agents.tests.test_session_admission tools.agents.tests.test_stream_heartbeat tools.agents.tests.test_stuck_break_reattach tools.agents.tests.test_stuck_break_hard tools.agents.tests.test_turn_count_breaker_periodic tools.agents.tests.test_upstream_chokepoint tools.agents.tests.test_vision_passthrough tools.agents.tests.test_worktree_required tools.agents.tests.test_enforcer_suite_coverage tools.agents.tests.test_validate_plan_gate tools.agents.tests.test_validate_plan_inside_project tools.agents.tests.test_anthropic_proxy_streaming tools.agents.tests.test_non_stream_resp_log tools.agents.tests.test_delivery_enforcement_worktree tools.agents.tests.test_output_token_ceilings tools.agents.tests.test_tool_narrowing_core tools.agents.tests.test_models_context_window tools.agents.tests.test_thinking_template_kwargs tools.agents.tests.test_cycle_break_wait_poll tools.agents.tests.test_upstream_model_aliases tools.agents.tests.test_stream_thinking_deltas tools.agents.tests.test_verbatim_compact tools.agents.tests.test_tool_risk tools.agents.tests.test_lockstep_escalation",
|
|
24
|
+
"test:enforcers": "UAP_PROXY_ENV_AUTOLOAD=0 python3 -m unittest tools.agents.tests.test_enforcement_self_protect tools.agents.tests.test_conditional_destructive_verbs tools.agents.tests.test_live_deliver_kill tools.agents.tests.test_schema_diff_gate tools.agents.tests.test_schema_diff_inline tools.agents.tests.test_stream_telemetry tools.agents.tests.test_project_telemetry_events tools.agents.tests.test_workdir_scope_enforcer tools.agents.tests.test_gate_evidence tools.agents.tests.test_repeat_call_guard tools.agents.tests.test_repeat_guard tools.agents.tests.test_gate_integrity tools.agents.tests.test_gate_failclosed_indirection tools.agents.tests.test_gate_failclosed_schema_diff tools.agents.tests.test_gate_failclosed_plane_admin tools.agents.tests.test_expert_review_pr_scope tools.agents.tests.test_path_containment tools.agents.tests.test_path_normalizer_hardened tools.agents.tests.test_sandbox_tool_strip tools.agents.tests.test_proxy_env_loader tools.agents.tests.test_stream_required_tool tools.agents.tests.test_tool_call_wrapper_profiles tools.agents.tests.test_tool_convert_cache tools.agents.tests.test_doubling_break tools.agents.tests.test_error_loop_ignores_correctives tools.agents.tests.test_anthropic_proxy_tool_arg_types tools.agents.tests.test_anthropic_sse_schema tools.agents.tests.test_attractor_detection tools.agents.tests.test_client_disconnect tools.agents.tests.test_confidence_escalation tools.agents.tests.test_coordination_ban tools.agents.tests.test_coordination_early_ban tools.agents.tests.test_cycle_break_exploration tools.agents.tests.test_deferral_break tools.agents.tests.test_deliver_autoroute tools.agents.tests.test_delivery_enforcement_all_langs tools.agents.tests.test_delivery_enforcement_exemptions tools.agents.tests.test_delivery_enforcement_filepath tools.agents.tests.test_delivery_enforcement_write_complexity tools.agents.tests.test_fastpath_config tools.agents.tests.test_delivery_enforcement_web_and_bash tools.agents.tests.test_disconnect_watcher tools.agents.tests.test_empty_maxtokens_recovery tools.agents.tests.test_empty_tool_loop_break tools.agents.tests.test_enforcer_escape_hatches tools.agents.tests.test_error_loop_break tools.agents.tests.test_finalize_suppression tools.agents.tests.test_malformed_unclosed_think tools.agents.tests.test_mandate_beats_recon tools.agents.tests.test_mandate_deliver tools.agents.tests.test_overflow_truncate_count_tokens tools.agents.tests.test_count_tokens_scale_per_session tools.agents.tests.test_passthrough_oauth tools.agents.tests.test_project_telemetry tools.agents.tests.test_proxy_auth_headers tools.agents.tests.test_prune_preserve_force_write tools.agents.tests.test_recon_deliver_gate tools.agents.tests.test_session_admission tools.agents.tests.test_stream_heartbeat tools.agents.tests.test_stuck_break_reattach tools.agents.tests.test_stuck_break_hard tools.agents.tests.test_turn_count_breaker_periodic tools.agents.tests.test_upstream_chokepoint tools.agents.tests.test_vision_passthrough tools.agents.tests.test_worktree_required tools.agents.tests.test_plane_admin_protect tools.agents.tests.test_enforcer_suite_coverage tools.agents.tests.test_validate_plan_gate tools.agents.tests.test_validate_plan_inside_project tools.agents.tests.test_anthropic_proxy_streaming tools.agents.tests.test_non_stream_resp_log tools.agents.tests.test_delivery_enforcement_worktree tools.agents.tests.test_output_token_ceilings tools.agents.tests.test_tool_narrowing_core tools.agents.tests.test_models_context_window tools.agents.tests.test_thinking_template_kwargs tools.agents.tests.test_cycle_break_wait_poll tools.agents.tests.test_upstream_model_aliases tools.agents.tests.test_stream_thinking_deltas tools.agents.tests.test_verbatim_compact tools.agents.tests.test_tool_risk tools.agents.tests.test_lockstep_escalation",
|
|
25
25
|
"test:coverage": "vitest --coverage",
|
|
26
26
|
"bench": "vitest --config vitest.bench.config.ts",
|
|
27
27
|
"eval:routing": "tsx scripts/eval-routing.ts",
|
|
Binary file
|
|
Binary file
|
|
Binary file
|