@miller-tech/uap 2.21.2 → 2.36.1
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/README.md +22 -10
- package/config/model-profiles/qwen38-coder390.json +46 -0
- package/config/model-profiles/qwen38.json +3 -2
- package/config/model-registry.json +110 -0
- package/dist/.tsbuildinfo +1 -1
- package/dist/benchmarks/paired/types.d.ts +2 -2
- package/dist/bin/cli.js +315 -20
- package/dist/bin/cli.js.map +1 -1
- package/dist/cli/attention.d.ts +6 -0
- package/dist/cli/attention.d.ts.map +1 -0
- package/dist/cli/attention.js +115 -0
- package/dist/cli/attention.js.map +1 -0
- package/dist/cli/bench-report.d.ts +82 -0
- package/dist/cli/bench-report.d.ts.map +1 -0
- package/dist/cli/bench-report.js +237 -0
- package/dist/cli/bench-report.js.map +1 -0
- package/dist/cli/clients.d.ts +6 -0
- package/dist/cli/clients.d.ts.map +1 -0
- package/dist/cli/clients.js +142 -0
- package/dist/cli/clients.js.map +1 -0
- package/dist/cli/dashboard-grants.d.ts +26 -0
- package/dist/cli/dashboard-grants.d.ts.map +1 -0
- package/dist/cli/dashboard-grants.js +69 -0
- package/dist/cli/dashboard-grants.js.map +1 -0
- package/dist/cli/dashboard-pace.d.ts +31 -0
- package/dist/cli/dashboard-pace.d.ts.map +1 -0
- package/dist/cli/dashboard-pace.js +42 -0
- package/dist/cli/dashboard-pace.js.map +1 -0
- package/dist/cli/dashboard-session.d.ts +25 -0
- package/dist/cli/dashboard-session.d.ts.map +1 -0
- package/dist/cli/dashboard-session.js +814 -0
- package/dist/cli/dashboard-session.js.map +1 -0
- package/dist/cli/dashboard-types.d.ts +18 -0
- package/dist/cli/dashboard-types.d.ts.map +1 -0
- package/dist/cli/dashboard-types.js +9 -0
- package/dist/cli/dashboard-types.js.map +1 -0
- package/dist/cli/dashboard.d.ts +2 -18
- package/dist/cli/dashboard.d.ts.map +1 -1
- package/dist/cli/dashboard.js +43 -793
- package/dist/cli/dashboard.js.map +1 -1
- package/dist/cli/deliver.d.ts +35 -0
- package/dist/cli/deliver.d.ts.map +1 -1
- package/dist/cli/deliver.js +93 -9
- package/dist/cli/deliver.js.map +1 -1
- package/dist/cli/diff.d.ts +85 -0
- package/dist/cli/diff.d.ts.map +1 -0
- package/dist/cli/diff.js +293 -0
- package/dist/cli/diff.js.map +1 -0
- package/dist/cli/eta.d.ts +35 -0
- package/dist/cli/eta.d.ts.map +1 -0
- package/dist/cli/eta.js +101 -0
- package/dist/cli/eta.js.map +1 -0
- package/dist/cli/handsfree.d.ts +7 -0
- package/dist/cli/handsfree.d.ts.map +1 -1
- package/dist/cli/handsfree.js +27 -0
- package/dist/cli/handsfree.js.map +1 -1
- package/dist/cli/hooks.d.ts.map +1 -1
- package/dist/cli/hooks.js +126 -5
- package/dist/cli/hooks.js.map +1 -1
- package/dist/cli/loops.d.ts +24 -5
- package/dist/cli/loops.d.ts.map +1 -1
- package/dist/cli/loops.js +92 -12
- package/dist/cli/loops.js.map +1 -1
- package/dist/cli/models.d.ts +62 -0
- package/dist/cli/models.d.ts.map +1 -0
- package/dist/cli/models.js +567 -0
- package/dist/cli/models.js.map +1 -0
- package/dist/cli/plan.d.ts +9 -0
- package/dist/cli/plan.d.ts.map +1 -1
- package/dist/cli/plan.js +57 -4
- package/dist/cli/plan.js.map +1 -1
- package/dist/cli/proxy-relay.d.ts +55 -0
- package/dist/cli/proxy-relay.d.ts.map +1 -0
- package/dist/cli/proxy-relay.js +116 -0
- package/dist/cli/proxy-relay.js.map +1 -0
- package/dist/cli/proxy.d.ts +4 -0
- package/dist/cli/proxy.d.ts.map +1 -1
- package/dist/cli/proxy.js +26 -1
- package/dist/cli/proxy.js.map +1 -1
- package/dist/cli/sandbox.d.ts +101 -4
- package/dist/cli/sandbox.d.ts.map +1 -1
- package/dist/cli/sandbox.js +393 -44
- package/dist/cli/sandbox.js.map +1 -1
- package/dist/cli/self.d.ts +13 -0
- package/dist/cli/self.d.ts.map +1 -0
- package/dist/cli/self.js +94 -0
- package/dist/cli/self.js.map +1 -0
- package/dist/cli/systemd-services.d.ts +2 -8
- package/dist/cli/systemd-services.d.ts.map +1 -1
- package/dist/cli/systemd-services.js +5 -20
- package/dist/cli/systemd-services.js.map +1 -1
- package/dist/cli/task.js +1 -1
- package/dist/cli/task.js.map +1 -1
- package/dist/cli/wizard-config.d.ts.map +1 -1
- package/dist/cli/wizard-config.js +31 -2
- package/dist/cli/wizard-config.js.map +1 -1
- package/dist/config/settings-registry.d.ts +1 -1
- package/dist/config/settings-registry.d.ts.map +1 -1
- package/dist/config/settings-registry.js +108 -0
- package/dist/config/settings-registry.js.map +1 -1
- package/dist/coordination/capability-router.js +2 -2
- package/dist/coordination/capability-router.js.map +1 -1
- package/dist/coordination/database.d.ts +13 -0
- package/dist/coordination/database.d.ts.map +1 -1
- package/dist/coordination/database.js +63 -7
- package/dist/coordination/database.js.map +1 -1
- package/dist/coordination/eta-inject.d.ts +32 -0
- package/dist/coordination/eta-inject.d.ts.map +1 -0
- package/dist/coordination/eta-inject.js +64 -0
- package/dist/coordination/eta-inject.js.map +1 -0
- package/dist/coordination/reactor.d.ts.map +1 -1
- package/dist/coordination/reactor.js +14 -0
- package/dist/coordination/reactor.js.map +1 -1
- package/dist/coordination/service.d.ts +18 -8
- package/dist/coordination/service.d.ts.map +1 -1
- package/dist/coordination/service.js +38 -28
- package/dist/coordination/service.js.map +1 -1
- package/dist/dashboard/client-registry.d.ts +163 -0
- package/dist/dashboard/client-registry.d.ts.map +1 -0
- package/dist/dashboard/client-registry.js +549 -0
- package/dist/dashboard/client-registry.js.map +1 -0
- package/dist/dashboard/controls.d.ts.map +1 -1
- package/dist/dashboard/controls.js +33 -4
- package/dist/dashboard/controls.js.map +1 -1
- package/dist/dashboard/data-seeder.d.ts +10 -7
- package/dist/dashboard/data-seeder.d.ts.map +1 -1
- package/dist/dashboard/data-seeder.js +31 -75
- package/dist/dashboard/data-seeder.js.map +1 -1
- package/dist/dashboard/data-service.d.ts +9 -0
- package/dist/dashboard/data-service.d.ts.map +1 -1
- package/dist/dashboard/data-service.js +32 -3
- package/dist/dashboard/data-service.js.map +1 -1
- package/dist/dashboard/placement-routes.d.ts +119 -0
- package/dist/dashboard/placement-routes.d.ts.map +1 -0
- package/dist/dashboard/placement-routes.js +331 -0
- package/dist/dashboard/placement-routes.js.map +1 -0
- package/dist/dashboard/server.d.ts.map +1 -1
- package/dist/dashboard/server.js +408 -2
- package/dist/dashboard/server.js.map +1 -1
- package/dist/delivery/attention.d.ts +130 -0
- package/dist/delivery/attention.d.ts.map +1 -0
- package/dist/delivery/attention.js +341 -0
- package/dist/delivery/attention.js.map +1 -0
- package/dist/delivery/decompose.d.ts +18 -0
- package/dist/delivery/decompose.d.ts.map +1 -1
- package/dist/delivery/decompose.js +22 -1
- package/dist/delivery/decompose.js.map +1 -1
- package/dist/delivery/eta-estimate.d.ts +111 -0
- package/dist/delivery/eta-estimate.d.ts.map +1 -0
- package/dist/delivery/eta-estimate.js +171 -0
- package/dist/delivery/eta-estimate.js.map +1 -0
- package/dist/delivery/eta.d.ts +23 -0
- package/dist/delivery/eta.d.ts.map +1 -0
- package/dist/delivery/eta.js +59 -0
- package/dist/delivery/eta.js.map +1 -0
- package/dist/delivery/orchestrated-mission.d.ts +10 -0
- package/dist/delivery/orchestrated-mission.d.ts.map +1 -1
- package/dist/delivery/orchestrated-mission.js +15 -1
- package/dist/delivery/orchestrated-mission.js.map +1 -1
- package/dist/delivery/plan-check.d.ts +7 -1
- package/dist/delivery/plan-check.d.ts.map +1 -1
- package/dist/delivery/plan-check.js +23 -2
- package/dist/delivery/plan-check.js.map +1 -1
- package/dist/delivery/run-state.d.ts +1 -1
- package/dist/delivery/run-state.d.ts.map +1 -1
- package/dist/delivery/run-state.js +8 -1
- package/dist/delivery/run-state.js.map +1 -1
- package/dist/delivery/task-orchestrator.d.ts +8 -3
- package/dist/delivery/task-orchestrator.d.ts.map +1 -1
- package/dist/delivery/task-orchestrator.js +75 -43
- package/dist/delivery/task-orchestrator.js.map +1 -1
- package/dist/delivery/task-sync.d.ts +21 -0
- package/dist/delivery/task-sync.d.ts.map +1 -1
- package/dist/delivery/task-sync.js +44 -8
- package/dist/delivery/task-sync.js.map +1 -1
- package/dist/delivery/task-workspace.d.ts +3 -3
- package/dist/delivery/task-workspace.js +3 -3
- package/dist/generators/self-card.d.ts +65 -0
- package/dist/generators/self-card.d.ts.map +1 -0
- package/dist/generators/self-card.js +256 -0
- package/dist/generators/self-card.js.map +1 -0
- package/dist/inference/probe.js +1 -1
- package/dist/inference/probe.js.map +1 -1
- package/dist/memory/prepopulate.d.ts.map +1 -1
- package/dist/memory/prepopulate.js +2 -0
- package/dist/memory/prepopulate.js.map +1 -1
- package/dist/models/analytics.d.ts +32 -0
- package/dist/models/analytics.d.ts.map +1 -1
- package/dist/models/analytics.js +68 -5
- package/dist/models/analytics.js.map +1 -1
- package/dist/models/plan-readability.d.ts +55 -0
- package/dist/models/plan-readability.d.ts.map +1 -0
- package/dist/models/plan-readability.js +339 -0
- package/dist/models/plan-readability.js.map +1 -0
- package/dist/placement/admission.d.ts +59 -0
- package/dist/placement/admission.d.ts.map +1 -0
- package/dist/placement/admission.js +197 -0
- package/dist/placement/admission.js.map +1 -0
- package/dist/placement/auto.d.ts +44 -0
- package/dist/placement/auto.d.ts.map +1 -0
- package/dist/placement/auto.js +212 -0
- package/dist/placement/auto.js.map +1 -0
- package/dist/placement/enforce.d.ts +128 -0
- package/dist/placement/enforce.d.ts.map +1 -0
- package/dist/placement/enforce.js +655 -0
- package/dist/placement/enforce.js.map +1 -0
- package/dist/placement/idle.d.ts +50 -0
- package/dist/placement/idle.d.ts.map +1 -0
- package/dist/placement/idle.js +213 -0
- package/dist/placement/idle.js.map +1 -0
- package/dist/placement/ledger.d.ts +323 -0
- package/dist/placement/ledger.d.ts.map +1 -0
- package/dist/placement/ledger.js +263 -0
- package/dist/placement/ledger.js.map +1 -0
- package/dist/placement/preview.d.ts +51 -0
- package/dist/placement/preview.d.ts.map +1 -0
- package/dist/placement/preview.js +61 -0
- package/dist/placement/preview.js.map +1 -0
- package/dist/placement/probes.d.ts +47 -0
- package/dist/placement/probes.d.ts.map +1 -0
- package/dist/placement/probes.js +207 -0
- package/dist/placement/probes.js.map +1 -0
- package/dist/placement/proxy-env.d.ts +21 -0
- package/dist/placement/proxy-env.d.ts.map +1 -0
- package/dist/placement/proxy-env.js +42 -0
- package/dist/placement/proxy-env.js.map +1 -0
- package/dist/placement/registry.d.ts +1038 -0
- package/dist/placement/registry.d.ts.map +1 -0
- package/dist/placement/registry.js +274 -0
- package/dist/placement/registry.js.map +1 -0
- package/dist/policies/liveness.d.ts +6 -8
- package/dist/policies/liveness.d.ts.map +1 -1
- package/dist/policies/liveness.js +6 -25
- package/dist/policies/liveness.js.map +1 -1
- package/dist/policies/sandbox-anchor.d.ts +91 -0
- package/dist/policies/sandbox-anchor.d.ts.map +1 -0
- package/dist/policies/sandbox-anchor.js +187 -0
- package/dist/policies/sandbox-anchor.js.map +1 -0
- package/dist/policies/sandbox-grants.d.ts +131 -0
- package/dist/policies/sandbox-grants.d.ts.map +1 -0
- package/dist/policies/sandbox-grants.js +562 -0
- package/dist/policies/sandbox-grants.js.map +1 -0
- package/dist/state/manifest.d.ts +4 -2
- package/dist/state/manifest.d.ts.map +1 -1
- package/dist/state/manifest.js +32 -16
- package/dist/state/manifest.js.map +1 -1
- package/dist/utils/checkout-root.d.ts +2 -0
- package/dist/utils/checkout-root.d.ts.map +1 -0
- package/dist/utils/checkout-root.js +43 -0
- package/dist/utils/checkout-root.js.map +1 -0
- package/dist/utils/resolve-uap-bin.d.ts +5 -0
- package/dist/utils/resolve-uap-bin.d.ts.map +1 -0
- package/dist/utils/resolve-uap-bin.js +33 -0
- package/dist/utils/resolve-uap-bin.js.map +1 -0
- package/dist/utils/terminal-safe.d.ts +12 -0
- package/dist/utils/terminal-safe.d.ts.map +1 -0
- package/dist/utils/terminal-safe.js +53 -0
- package/dist/utils/terminal-safe.js.map +1 -0
- package/docs/ATTRIBUTION.md +1 -0
- package/docs/DASHBOARD_UPLIFT_SPEC.md +8 -8
- package/docs/INDEX.md +6 -5
- package/docs/architecture/OVERVIEW.md +15 -3
- package/docs/architecture/PROTOCOL.md +7 -1
- package/docs/architecture/adr/0006-operator-directed-model-placement.md +86 -0
- package/docs/architecture/adr/0007-auto-displacement-allowlist-as-standing-consent.md +79 -0
- package/docs/architecture/adr/0008-fleet-clients-link-out.md +92 -0
- package/docs/architecture/adr/0009-completion-triggered-dispatch-and-per-leaf-model-dials.md +71 -0
- package/docs/architecture/adr/0010-attention-queue-and-afk-auto-decider.md +159 -0
- package/docs/architecture/adr/0011-sandbox-grants-and-network-egress-boundary.md +219 -0
- package/docs/architecture/adr/0012-operator-legibility-surfaces.md +175 -0
- package/docs/getting-started/INSTALLATION.md +1 -1
- package/docs/guides/AUTOMATIC_FEATURES.md +8 -0
- package/docs/guides/LOCAL_MODELS.md +1 -1
- package/docs/guides/PROXY.md +2 -1
- package/docs/guides/SANDBOX.md +91 -4
- package/docs/integrations/MCP_ROUTER.md +1 -1
- package/docs/plans/model-performance-proof-options.md +176 -0
- package/docs/reference/API.md +1 -1
- package/docs/reference/CLI.md +169 -4
- package/docs/reference/COMPARISON.md +1 -1
- package/docs/reference/CONFIGURATION.md +12 -3
- package/docs/reference/CONFIGURATION_REFERENCE.md +269 -14
- package/docs/reference/DATABASE_SCHEMA.md +1 -1
- package/docs/reference/FEATURES.md +15 -3
- package/docs/reference/PATTERNS.md +1 -1
- package/docs/reference/PLATFORMS.md +14 -1
- package/docs/specs/operator-model-placement.md +1314 -0
- package/docs/specs/operator-model-placement.review.md +339 -0
- package/package.json +2 -2
- package/scripts/maintenance/publish-npm.sh +23 -11
- package/scripts/version-bump.sh +6 -51
- package/src/policies/enforcers/__pycache__/_common.cpython-311.pyc +0 -0
- package/src/policies/enforcers/__pycache__/expert_review_required.cpython-311.pyc +0 -0
- package/src/policies/enforcers/__pycache__/quality_metrics_gate.cpython-311.pyc +0 -0
- package/src/policies/schemas/policies/mandatory-testing-deployment.md +2 -5
- package/templates/hooks/__pycache__/deliver_autoroute.cpython-311.pyc +0 -0
- package/templates/hooks/session-start.sh +44 -0
- package/tools/agents/UAP/cli.py +14 -3
- package/tools/agents/UAP/paths.py +50 -0
- package/tools/agents/scripts/__pycache__/toolcall_path_normalizer.cpython-311.pyc +0 -0
- package/tools/agents/scripts/anthropic_proxy.py +1386 -99
- package/tools/agents/scripts/toolcall_path_normalizer.py +46 -1
- package/tools/agents/tests/test_anthropic_proxy_streaming.py +29 -6
- package/tools/agents/tests/test_doubling_break.py +64 -5
- package/tools/agents/tests/test_error_loop_break.py +10 -4
- package/tools/agents/tests/test_error_loop_ignores_correctives.py +13 -2
- package/tools/agents/tests/test_lockstep_escalation.py +280 -9
- package/tools/agents/tests/test_path_containment.py +94 -0
- package/tools/agents/tests/test_proxy_unix_socket.py +162 -0
- package/tools/agents/tests/test_signature_quality.py +349 -0
- package/tools/agents/tests/test_uap_compliance.py +11 -1
- package/web/dash/core.js +1 -0
- package/web/dash/tab-clients.js +196 -0
- package/web/dash/tab-models.js +387 -8
- package/web/dash/tab-policies.js +87 -4
- package/web/dash/tabs.js +77 -73
- package/web/dashboard.html +6 -0
- 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/templates/hooks/__pycache__/deliver_autoroute.cpython-312.pyc +0 -0
- package/tools/agents/scripts/__pycache__/toolcall_path_normalizer.cpython-312.pyc +0 -0
- package/web/dash/tab-agents.js +0 -21
- package/web/dash/tab-deliver.js +0 -12
- package/web/dash/tab-memory.js +0 -12
- package/web/dash/tab-orchestration.js +0 -21
- package/web/dash/tab-overview.js +0 -21
- package/web/dash/tab-tasks.js +0 -21
package/dist/state/manifest.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Implementation-State Manifest — a machine-generated snapshot of what this
|
|
3
3
|
* project IS and where its implementation actually stands, derived from
|
|
4
|
-
* ground truth (package.json,
|
|
4
|
+
* ground truth (package.json, git log, git branch, .factory registries)
|
|
5
5
|
* rather than hand-maintained docs that drift.
|
|
6
6
|
*
|
|
7
7
|
* Written to `.uap/state-manifest.json`; the reactor injects a one-line
|
|
@@ -12,6 +12,7 @@
|
|
|
12
12
|
import { execFileSync } from 'child_process';
|
|
13
13
|
import { existsSync, mkdirSync, readFileSync, readdirSync, renameSync, statSync, writeFileSync } from 'fs';
|
|
14
14
|
import { join } from 'path';
|
|
15
|
+
import { termSafeBounded } from '../utils/terminal-safe.js';
|
|
15
16
|
const RECENT_CHANGES = 5;
|
|
16
17
|
/** Digest re-generation threshold: a manifest older than this is stale. */
|
|
17
18
|
const STALE_MS = 24 * 60 * 60 * 1000;
|
|
@@ -35,6 +36,30 @@ function gitBranch(projectRoot) {
|
|
|
35
36
|
return undefined;
|
|
36
37
|
}
|
|
37
38
|
}
|
|
39
|
+
/** Latest commit subjects, newest first — straight from the git log. Commit
|
|
40
|
+
* subjects are contributor-authored (untrusted) text: termSafeBounded strips
|
|
41
|
+
* terminal-control bytes, flattens to one line, and bounds the length, so a
|
|
42
|
+
* hostile subject cannot smuggle escapes or line structure into the digest. */
|
|
43
|
+
function gitSubjects(projectRoot) {
|
|
44
|
+
try {
|
|
45
|
+
const out = execFileSync('git', ['log', '--pretty=%s', '-n', String(RECENT_CHANGES), '--no-merges'], {
|
|
46
|
+
cwd: projectRoot,
|
|
47
|
+
encoding: 'utf-8',
|
|
48
|
+
timeout: 3000,
|
|
49
|
+
stdio: ['ignore', 'pipe', 'ignore'],
|
|
50
|
+
// Never inherit a poisoned GIT_DIR from a hook environment.
|
|
51
|
+
env: { ...process.env, GIT_DIR: undefined, GIT_WORK_TREE: undefined, GIT_INDEX_FILE: undefined },
|
|
52
|
+
});
|
|
53
|
+
return out
|
|
54
|
+
.split('\n')
|
|
55
|
+
.map((line) => termSafeBounded(line, 160))
|
|
56
|
+
.filter(Boolean);
|
|
57
|
+
}
|
|
58
|
+
catch {
|
|
59
|
+
// not a git repo (or git unusable) — manifest still useful without it
|
|
60
|
+
return [];
|
|
61
|
+
}
|
|
62
|
+
}
|
|
38
63
|
function countEntries(dir) {
|
|
39
64
|
try {
|
|
40
65
|
if (!existsSync(dir))
|
|
@@ -59,20 +84,7 @@ export function generateStateManifest(projectRoot) {
|
|
|
59
84
|
}
|
|
60
85
|
const name = typeof pkg.name === 'string' ? pkg.name : 'unknown';
|
|
61
86
|
const version = typeof pkg.version === 'string' ? pkg.version : '0.0.0';
|
|
62
|
-
const recentChanges =
|
|
63
|
-
try {
|
|
64
|
-
const changelog = readFileSync(join(projectRoot, 'CHANGELOG.md'), 'utf-8');
|
|
65
|
-
for (const line of changelog.split('\n')) {
|
|
66
|
-
if (line.startsWith('## ')) {
|
|
67
|
-
recentChanges.push(line.slice(3).trim().slice(0, 160));
|
|
68
|
-
if (recentChanges.length >= RECENT_CHANGES)
|
|
69
|
-
break;
|
|
70
|
-
}
|
|
71
|
-
}
|
|
72
|
-
}
|
|
73
|
-
catch {
|
|
74
|
-
// no changelog — manifest still useful
|
|
75
|
-
}
|
|
87
|
+
const recentChanges = gitSubjects(projectRoot);
|
|
76
88
|
const counts = {};
|
|
77
89
|
const skillCount = countEntries(join(projectRoot, '.factory', 'skills'));
|
|
78
90
|
const droidCount = countEntries(join(projectRoot, '.factory', 'droids'));
|
|
@@ -140,7 +152,11 @@ export function manifestDigest(manifest) {
|
|
|
140
152
|
`${manifest.name} v${manifest.version}${manifest.branch ? ` (branch: ${manifest.branch})` : ''}`,
|
|
141
153
|
];
|
|
142
154
|
if (manifest.recentChanges.length > 0) {
|
|
143
|
-
|
|
155
|
+
// Choke-point defense: on the load path (readOrRefreshManifest) these
|
|
156
|
+
// entries can come from a planted .uap/state-manifest.json — re-strip
|
|
157
|
+
// before the digest reaches a session prompt.
|
|
158
|
+
const subjects = manifest.recentChanges.map((s) => termSafeBounded(s, 160));
|
|
159
|
+
lines.push(`Recently shipped: ${subjects.slice(0, 3).join(' | ')}`.slice(0, 240));
|
|
144
160
|
}
|
|
145
161
|
if (manifest.counts) {
|
|
146
162
|
lines.push(Object.entries(manifest.counts)
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"manifest.js","sourceRoot":"","sources":["../../src/state/manifest.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAC7C,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,YAAY,EAAE,WAAW,EAAE,UAAU,EAAE,QAAQ,EAAE,aAAa,EAAE,MAAM,IAAI,CAAC;AAC3G,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"manifest.js","sourceRoot":"","sources":["../../src/state/manifest.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"checkout-root.d.ts","sourceRoot":"","sources":["../../src/utils/checkout-root.ts"],"names":[],"mappings":"AAoBA,wBAAgB,gBAAgB,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM,CAqB5D"}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The main-checkout root anchor (moved from src/policies/liveness.ts so
|
|
3
|
+
* non-policy state can share it without importing the policies layer).
|
|
4
|
+
*
|
|
5
|
+
* The gate hook strips `/.worktrees/<name>` to find it
|
|
6
|
+
* (${CHECKOUT_ROOT%%/.worktrees/*}); the writers must anchor the same way or
|
|
7
|
+
* a worktree session — the workflow CLAUDE.md MANDATES — writes state and
|
|
8
|
+
* reads it back where other surfaces never look (review should-fix,
|
|
9
|
+
* 2026-07-13; reintroduced as a BLOCKER by the 2026-10-11 attention-queue
|
|
10
|
+
* review: dashboard cwd, hook PROJECT_DIR, and CLI cwd resolved three
|
|
11
|
+
* different queue files). Non-git roots (unit fixtures, tmp dirs) pass
|
|
12
|
+
* through unchanged.
|
|
13
|
+
*/
|
|
14
|
+
import { spawnSync } from 'child_process';
|
|
15
|
+
import { sep } from 'path';
|
|
16
|
+
/** Roots are stable for a process lifetime; callers resolve this on every
|
|
17
|
+
* queue read/write and must not spawn git per call. */
|
|
18
|
+
const cache = new Map();
|
|
19
|
+
export function mainCheckoutRoot(projectRoot) {
|
|
20
|
+
const hit = cache.get(projectRoot);
|
|
21
|
+
if (hit !== undefined)
|
|
22
|
+
return hit;
|
|
23
|
+
let root = projectRoot;
|
|
24
|
+
try {
|
|
25
|
+
const r = spawnSync('git', ['rev-parse', '--show-toplevel'], {
|
|
26
|
+
cwd: projectRoot,
|
|
27
|
+
encoding: 'utf-8',
|
|
28
|
+
});
|
|
29
|
+
if (r.status === 0) {
|
|
30
|
+
const top = (r.stdout ?? '').trim();
|
|
31
|
+
if (top) {
|
|
32
|
+
const i = top.indexOf(`${sep}.worktrees${sep}`);
|
|
33
|
+
root = i === -1 ? top : top.slice(0, i);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
catch {
|
|
38
|
+
root = projectRoot;
|
|
39
|
+
}
|
|
40
|
+
cache.set(projectRoot, root);
|
|
41
|
+
return root;
|
|
42
|
+
}
|
|
43
|
+
//# sourceMappingURL=checkout-root.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"checkout-root.js","sourceRoot":"","sources":["../../src/utils/checkout-root.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AACH,OAAO,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AAC1C,OAAO,EAAE,GAAG,EAAE,MAAM,MAAM,CAAC;AAE3B;wDACwD;AACxD,MAAM,KAAK,GAAG,IAAI,GAAG,EAAkB,CAAC;AAExC,MAAM,UAAU,gBAAgB,CAAC,WAAmB;IAClD,MAAM,GAAG,GAAG,KAAK,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC;IACnC,IAAI,GAAG,KAAK,SAAS;QAAE,OAAO,GAAG,CAAC;IAClC,IAAI,IAAI,GAAG,WAAW,CAAC;IACvB,IAAI,CAAC;QACH,MAAM,CAAC,GAAG,SAAS,CAAC,KAAK,EAAE,CAAC,WAAW,EAAE,iBAAiB,CAAC,EAAE;YAC3D,GAAG,EAAE,WAAW;YAChB,QAAQ,EAAE,OAAO;SAClB,CAAC,CAAC;QACH,IAAI,CAAC,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACnB,MAAM,GAAG,GAAG,CAAC,CAAC,CAAC,MAAM,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC;YACpC,IAAI,GAAG,EAAE,CAAC;gBACR,MAAM,CAAC,GAAG,GAAG,CAAC,OAAO,CAAC,GAAG,GAAG,aAAa,GAAG,EAAE,CAAC,CAAC;gBAChD,IAAI,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;YAC1C,CAAC;QACH,CAAC;IACH,CAAC;IAAC,MAAM,CAAC;QACP,IAAI,GAAG,WAAW,CAAC;IACrB,CAAC;IACD,KAAK,CAAC,GAAG,CAAC,WAAW,EAAE,IAAI,CAAC,CAAC;IAC7B,OAAO,IAAI,CAAC;AACd,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resolve-uap-bin.d.ts","sourceRoot":"","sources":["../../src/utils/resolve-uap-bin.ts"],"names":[],"mappings":"AAeA,wBAAgB,aAAa,IAAI;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,EAAE,CAAA;CAAE,CAclE"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Resolve the uap executable for detached child spawns (deliver launch/resume,
|
|
3
|
+
* fleet dashboard spawn-on-demand).
|
|
4
|
+
*
|
|
5
|
+
* PATH often lacks the npm global bin, and a launch that silently died with
|
|
6
|
+
* ENOENT was a real dash-audit hazard. Resolution order:
|
|
7
|
+
* 1. UAP_BIN env override (operator/debug).
|
|
8
|
+
* 2. This module's own install: <root>/dist/bin/cli.js run with the SAME
|
|
9
|
+
* node binary that runs the dashboard (no PATH, no shell).
|
|
10
|
+
* 3. Bare 'uap' as the last resort (interactive PATH).
|
|
11
|
+
*/
|
|
12
|
+
import { existsSync } from 'fs';
|
|
13
|
+
import { join, dirname } from 'path';
|
|
14
|
+
import { fileURLToPath } from 'url';
|
|
15
|
+
export function resolveUapBin() {
|
|
16
|
+
if (process.env.UAP_BIN)
|
|
17
|
+
return { cmd: process.env.UAP_BIN, preArgs: [] };
|
|
18
|
+
try {
|
|
19
|
+
// ESM: this file is <root>/dist/utils/resolve-uap-bin.js
|
|
20
|
+
const selfUrl = import.meta.url;
|
|
21
|
+
if (selfUrl.startsWith('file:')) {
|
|
22
|
+
const here = fileURLToPath(selfUrl);
|
|
23
|
+
const cli = join(dirname(here), '..', 'bin', 'cli.js');
|
|
24
|
+
if (existsSync(cli))
|
|
25
|
+
return { cmd: process.execPath, preArgs: [cli] };
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
catch {
|
|
29
|
+
/* fall through to PATH */
|
|
30
|
+
}
|
|
31
|
+
return { cmd: 'uap', preArgs: [] };
|
|
32
|
+
}
|
|
33
|
+
//# sourceMappingURL=resolve-uap-bin.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resolve-uap-bin.js","sourceRoot":"","sources":["../../src/utils/resolve-uap-bin.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AACH,OAAO,EAAE,UAAU,EAAE,MAAM,IAAI,CAAC;AAChC,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,MAAM,CAAC;AACrC,OAAO,EAAE,aAAa,EAAE,MAAM,KAAK,CAAC;AAEpC,MAAM,UAAU,aAAa;IAC3B,IAAI,OAAO,CAAC,GAAG,CAAC,OAAO;QAAE,OAAO,EAAE,GAAG,EAAE,OAAO,CAAC,GAAG,CAAC,OAAO,EAAE,OAAO,EAAE,EAAE,EAAE,CAAC;IAC1E,IAAI,CAAC;QACH,yDAAyD;QACzD,MAAM,OAAO,GAAG,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC;QAChC,IAAI,OAAO,CAAC,UAAU,CAAC,OAAO,CAAC,EAAE,CAAC;YAChC,MAAM,IAAI,GAAG,aAAa,CAAC,OAAO,CAAC,CAAC;YACpC,MAAM,GAAG,GAAG,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,QAAQ,CAAC,CAAC;YACvD,IAAI,UAAU,CAAC,GAAG,CAAC;gBAAE,OAAO,EAAE,GAAG,EAAE,OAAO,CAAC,QAAQ,EAAE,OAAO,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC;QACxE,CAAC;IACH,CAAC;IAAC,MAAM,CAAC;QACP,0BAA0B;IAC5B,CAAC;IACD,OAAO,EAAE,GAAG,EAAE,KAAK,EAAE,OAAO,EAAE,EAAE,EAAE,CAAC;AACrC,CAAC"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/** Strip terminal-control bytes (keeps tab/newline/CR). */
|
|
2
|
+
export declare function termSafe(s: string): string;
|
|
3
|
+
/**
|
|
4
|
+
* Same strip, then flatten to ONE line and bound the length — for strings
|
|
5
|
+
* that become prompt text or single-line display fields (model ids, labels).
|
|
6
|
+
* Line breaks are structure a hostile string must not smuggle in: collapsing
|
|
7
|
+
* them to a space keeps the text honest and the shape fixed.
|
|
8
|
+
*/
|
|
9
|
+
export declare function termSafeBounded(s: string, max: number): string;
|
|
10
|
+
/** Strip ANSI escape sequences and every C0/C1 control byte (incl. newline). */
|
|
11
|
+
export declare function stripControlChars(text: string): string;
|
|
12
|
+
//# sourceMappingURL=terminal-safe.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"terminal-safe.d.ts","sourceRoot":"","sources":["../../src/utils/terminal-safe.ts"],"names":[],"mappings":"AAcA,2DAA2D;AAC3D,wBAAgB,QAAQ,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAE1C;AAED;;;;;GAKG;AACH,wBAAgB,eAAe,CAAC,CAAC,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,CAK9D;AAmBD,gFAAgF;AAChF,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAKtD"}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Terminal-safe rendering — strip the C0/C1 control
|
|
3
|
+
* characters that could steer an operator's terminal from data we did not
|
|
4
|
+
* author: JSON report fields, analytics-store model ids, commit subjects.
|
|
5
|
+
*
|
|
6
|
+
* Kept characters: `\t`, `\n`, `\r` (layout, not control); everything else in
|
|
7
|
+
* C0 (U+0000–U+001F), DEL (U+007F), and C1 (U+0080–U+009F) is removed. This
|
|
8
|
+
* is defense-in-depth at ONE choke point, not a trust boundary: the strings
|
|
9
|
+
* it cleans come from repo/store files an operator could equally `cat` — but
|
|
10
|
+
* a UAP surface must not be a better terminal-injection mule than `cat`.
|
|
11
|
+
*/
|
|
12
|
+
// eslint-disable-next-line no-control-regex -- matching control bytes IS this module's job; the regex strips what it matches
|
|
13
|
+
const CONTROL_CHARS = /[\u0000-\u0008\u000B\u000C\u000E-\u001F\u007F-\u009F]/g;
|
|
14
|
+
/** Strip terminal-control bytes (keeps tab/newline/CR). */
|
|
15
|
+
export function termSafe(s) {
|
|
16
|
+
return s.replace(CONTROL_CHARS, '');
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Same strip, then flatten to ONE line and bound the length — for strings
|
|
20
|
+
* that become prompt text or single-line display fields (model ids, labels).
|
|
21
|
+
* Line breaks are structure a hostile string must not smuggle in: collapsing
|
|
22
|
+
* them to a space keeps the text honest and the shape fixed.
|
|
23
|
+
*/
|
|
24
|
+
export function termSafeBounded(s, max) {
|
|
25
|
+
return termSafe(s)
|
|
26
|
+
.replace(/\s+/g, ' ')
|
|
27
|
+
.trim()
|
|
28
|
+
.slice(0, max);
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Sequence-aware strip — the strong form of `termSafe`. Removes whole ANSI
|
|
32
|
+
* OSC sequences (hyperlinks, window-title writes) and CSI sequences (colors,
|
|
33
|
+
* cursor movement) BEFORE deleting the remaining C0/C1 bytes. `termSafe` only
|
|
34
|
+
* deletes bytes, leaving a sequence's payload characters behind (an OSC-52
|
|
35
|
+
* clipboard write defangs to `]52;c;base64…`); this form removes the sequence
|
|
36
|
+
* entire. Unlike `termSafe` it also removes `\t`/`\n`/`\r` — callers that
|
|
37
|
+
* need single-line output or preserved layout must normalize whitespace
|
|
38
|
+
* FIRST, because a newline deleted after normalization cannot glue two
|
|
39
|
+
* words together.
|
|
40
|
+
*/
|
|
41
|
+
/* eslint-disable no-control-regex -- matching control bytes IS this module's job; the regexes strip what they match */
|
|
42
|
+
const OSC_SEQUENCE = /\x1b\][^\x07\x1b]*(?:\x07|\x1b\\)/g;
|
|
43
|
+
const CSI_SEQUENCE = /\x1b\[[0-9;?]*[ -/]*[@-~]/g;
|
|
44
|
+
const ANY_CONTROL_BYTE = /[\x00-\x1f\x7f-\x9f]/g;
|
|
45
|
+
/* eslint-enable no-control-regex */
|
|
46
|
+
/** Strip ANSI escape sequences and every C0/C1 control byte (incl. newline). */
|
|
47
|
+
export function stripControlChars(text) {
|
|
48
|
+
return text
|
|
49
|
+
.replace(OSC_SEQUENCE, '')
|
|
50
|
+
.replace(CSI_SEQUENCE, '')
|
|
51
|
+
.replace(ANY_CONTROL_BYTE, '');
|
|
52
|
+
}
|
|
53
|
+
//# sourceMappingURL=terminal-safe.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"terminal-safe.js","sourceRoot":"","sources":["../../src/utils/terminal-safe.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AACH,6HAA6H;AAC7H,MAAM,aAAa,GAAG,wDAAwD,CAAC;AAE/E,2DAA2D;AAC3D,MAAM,UAAU,QAAQ,CAAC,CAAS;IAChC,OAAO,CAAC,CAAC,OAAO,CAAC,aAAa,EAAE,EAAE,CAAC,CAAC;AACtC,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,eAAe,CAAC,CAAS,EAAE,GAAW;IACpD,OAAO,QAAQ,CAAC,CAAC,CAAC;SACf,OAAO,CAAC,MAAM,EAAE,GAAG,CAAC;SACpB,IAAI,EAAE;SACN,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;AACnB,CAAC;AAED;;;;;;;;;;GAUG;AACH,uHAAuH;AACvH,MAAM,YAAY,GAAG,oCAAoC,CAAC;AAC1D,MAAM,YAAY,GAAG,4BAA4B,CAAC;AAClD,MAAM,gBAAgB,GAAG,uBAAuB,CAAC;AACjD,oCAAoC;AAEpC,gFAAgF;AAChF,MAAM,UAAU,iBAAiB,CAAC,IAAY;IAC5C,OAAO,IAAI;SACR,OAAO,CAAC,YAAY,EAAE,EAAE,CAAC;SACzB,OAAO,CAAC,YAAY,EAAE,EAAE,CAAC;SACzB,OAAO,CAAC,gBAAgB,EAAE,EAAE,CAAC,CAAC;AACnC,CAAC"}
|
package/docs/ATTRIBUTION.md
CHANGED
|
@@ -27,6 +27,7 @@ The full dependency graph lives in `package.json`; these deserve explicit mentio
|
|
|
27
27
|
because UAP embeds, vendors, or builds core workflows around them:
|
|
28
28
|
|
|
29
29
|
- **[llama.cpp](https://github.com/ggml-org/llama.cpp) / ik_llama.cpp** — the local inference backend the whole local-model path (deliver, recipes, slot budgeting) is built against.
|
|
30
|
+
- **[bubblewrap](https://github.com/containers/bubblewrap)** (GNOME) — the unprivileged kernel sandbox (`uap sandbox`) behind the sandboxed delivery path: read-only root mounts, per-session writable holes, and the `--unshare-net` egress cut are all bwrap primitives.
|
|
30
31
|
- **Qwen** (Alibaba) — the local models UAP's local-first delivery pipeline is tuned for and benchmarked with.
|
|
31
32
|
- **[Qdrant](https://qdrant.tech/)** + **nomic-embed-text** — the semantic long-term memory store and its embeddings.
|
|
32
33
|
- **[uPlot](https://github.com/leeoniya/uPlot)** (MIT) — vendored (with license) in `web/vendor/` for the dashboard's charts.
|
|
@@ -26,14 +26,14 @@ web/dash/core.js data layer + app shell: WS/SSE/poll channels, global
|
|
|
26
26
|
api() POST helper, expand/collapse helpers, drill navigation (goAgent(id)).
|
|
27
27
|
web/dash/charts.js uPlot chart + sparkline builders (ported 1:1 from current behaviour).
|
|
28
28
|
web/dash/styles.css all CSS (ported + new tab/drawer/table/control styles), tokens only.
|
|
29
|
-
web/dash/
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
web/dash/tab-
|
|
34
|
-
|
|
35
|
-
web/dash/tab-models.js models
|
|
36
|
-
|
|
29
|
+
web/dash/tabs.js inline tabs: overview (+ service-health strip) / tasks & epics kanban /
|
|
30
|
+
agents / orchestration / deliver / memory. (The six per-tab stub
|
|
31
|
+
files were dead weight — never loaded by dashboard.html — and
|
|
32
|
+
were removed.)
|
|
33
|
+
web/dash/tab-policies.js full policies panel (order/view/duplicate/import/export) +
|
|
34
|
+
compliance + audit + live events.
|
|
35
|
+
web/dash/tab-models.js models & placement: registry, ledger, pending placement
|
|
36
|
+
apply/dismiss, unload, auto-load policy, preview.
|
|
37
37
|
```
|
|
38
38
|
Server change: `server.ts` static handler currently serves `/vendor/`; extend it to ALSO serve
|
|
39
39
|
`/dash/` (same path-traversal guard, content types add `.css`, `.js`).
|
package/docs/INDEX.md
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
# UAP Documentation
|
|
2
2
|
|
|
3
|
-
The complete documentation for the **Universal Agent Protocol** (`@miller-tech/uap`
|
|
3
|
+
The complete documentation for the **Universal Agent Protocol** (`@miller-tech/uap`) — the discipline layer that turns a talented-but-unreliable AI coding agent into a dependable member of your software delivery line. 447 TypeScript modules across 34 subsystems, 530 vitest suites (~6,250 tests) plus a ~1,400-test Python enforcer/proxy suite, 60 top-level CLI commands (~211 registrations including subcommands), 34 executable policy enforcers, 9 supported agent harnesses.
|
|
4
4
|
|
|
5
5
|
> **Reviewing the system?** The reverse-engineered, code-verified reference set lives in
|
|
6
6
|
> [`documentation/`](../documentation/architecture.md): architecture, flows, permissions
|
|
7
7
|
> (incl. trust boundaries and enforcement gaps), variables/secrets, scheduled work, and
|
|
8
8
|
> embedded automation. Start there for an honest map of what's enforced vs. documented.
|
|
9
9
|
|
|
10
|
-
New here?
|
|
10
|
+
New here? Start with the **[Delivery Pipeline tour](guides/DELIVERY_PIPELINE.md)** — it walks the whole factory floor, station by station, showing where agents normally break and what UAP puts in place to catch it, all under one principle: *enforce, don't suggest*. Then grab the [Quickstart](getting-started/QUICKSTART.md).
|
|
11
11
|
|
|
12
12
|
---
|
|
13
13
|
|
|
@@ -79,7 +79,7 @@ Full map: **[The UAP Delivery Pipeline](guides/DELIVERY_PIPELINE.md)**.
|
|
|
79
79
|
| [Self-Harness](design/SELF_HARNESS.md) | Self-improving harness (shipped as `uap self-harness`): autonomous mine→propose→validate loop over a bounded Mod DSL; cross-model transfer, online mining |
|
|
80
80
|
| [LLM Self-Tuning (analysis)](design/LLM_SELF_TUNING_ANALYSIS.md) | The design behind `uap tune`: quality signal, LLM-guided + Gaussian-process flag search, closed-loop validation, model profiles, real-time adaptation |
|
|
81
81
|
| [Product Naming (analysis)](design/PRODUCT_NAMING.md) | UAP rename candidates: availability sweeps (npm/PyPI/domains), AI-space collision checks, railway-theme shortlist, recommendation. No decision committed; availability data is point-in-time |
|
|
82
|
-
| [ADRs](architecture/adr/) | Architecture decision records: [0001 AutoMode risk floor](architecture/adr/0001-automode-risk-floor.md) (Python heuristic scorer ahead of the TS SYS1 head), [0002 Evidence-bound ship](architecture/adr/0002-evidence-bound-ship.md) (gate evidence bound to the candidate SHA) |
|
|
82
|
+
| [ADRs](architecture/adr/) | Architecture decision records: [0001 AutoMode risk floor](architecture/adr/0001-automode-risk-floor.md) (Python heuristic scorer ahead of the TS SYS1 head), [0002 Evidence-bound ship](architecture/adr/0002-evidence-bound-ship.md) (gate evidence bound to the candidate SHA), … [0009 Completion-triggered dispatch + per-leaf model dials](architecture/adr/0009-completion-triggered-dispatch-and-per-leaf-model-dials.md), [0010 Attention queue + AFK auto-decider](architecture/adr/0010-attention-queue-and-afk-auto-decider.md), [0011 Sandbox grants + network egress boundary](architecture/adr/0011-sandbox-grants-and-network-egress-boundary.md), [0012 Operator legibility surfaces](architecture/adr/0012-operator-legibility-surfaces.md) |
|
|
83
83
|
|
|
84
84
|
## Reference
|
|
85
85
|
|
|
@@ -137,11 +137,12 @@ the decision record.
|
|
|
137
137
|
|
|
138
138
|
| Doc | What it covers |
|
|
139
139
|
|---|---|
|
|
140
|
-
| [Deliver hardening plan](plans/deliver-hardening-plan-2026-07-13.md) | The 14-defect
|
|
140
|
+
| [Deliver hardening plan](plans/deliver-hardening-plan-2026-07-13.md) | The 14-defect hardening plan (batches A–D): scoped rollback, declared gates, polyglot execution, config routing, liveness, operator overrides |
|
|
141
141
|
| [Deliver hardening review response](plans/deliver-hardening-review-response-2026-07-13.md) | Parallel-review findings and their dispositions — the rationale behind the root-owned trust model |
|
|
142
142
|
| [Harness engineering uplift](plans/harness-engineering-uplift-2026-07-31.md) | Three-paper analysis of harness variance and what UAP does about it |
|
|
143
143
|
| [K3 UAP uplift validation](plans/k3-uap-uplift-validation.md) | Plan to measure UAP's paired uplift on Kimi K3 by re-running Terminal-Bench 2.1 with Factory Droid as the harness, UAP on vs off |
|
|
144
|
-
| [Qwen3.8 UAP re-test plan](plans/qwen38-uap-retest-plan.md) | Plan to re-run the paired benchmark matrix on the current local Qwen3.8-27B stack
|
|
144
|
+
| [Qwen3.8 UAP re-test plan](plans/qwen38-uap-retest-plan.md) | Plan to re-run the paired benchmark matrix on the current local Qwen3.8-27B stack, replicating the +20pp gate-loop finding and checking the hardened deliver pipeline |
|
|
145
|
+
| [Model-performance proof options](plans/model-performance-proof-options.md) | The benchmark/test menu for demonstrating UAP's benefits with honest numbers: four separately-provable claims, six options (free-first), discrimination status required on every delta |
|
|
145
146
|
| [System-1 uplift plan](plans/system1-uplift-2026-09-18.md) | Approved uplift from the 2026-09-18 ten-source analysis (Jev/Foreman/Fluent/CEK et al): Wave 0 quick wins + Wave 1 System-1 decision layer, local-only classifier trained from UAP telemetry |
|
|
146
147
|
|
|
147
148
|
## Specs & performance
|
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
# UAP Architecture Overview
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
447 TypeScript modules across 34 `src/` subsystems · 530 vitest suites (~6,250 tests, + a ~1,400-test Python enforcer/proxy suite)
|
|
4
|
+
|
|
5
|
+
> **Why it looks like this:** every station exists because a specific failure
|
|
6
|
+
> class shows up there in real agentic delivery — the architecture is the
|
|
7
|
+
> codified countermeasure, station by station.
|
|
4
8
|
|
|
5
9
|
> **Code-verified reference:** this narrative overview is the intent-level floor plan. For
|
|
6
10
|
> the reverse-engineered, implementation-accurate map — including trust boundaries,
|
|
@@ -52,6 +56,14 @@ to the subsystem that guards it. Read this as the conveyor belt your work rides:
|
|
|
52
56
|
| **7. Shipping** — merge & release | regressions, broken CI, skipped version bumps | worktree→PR flow, version/completion gates, CI feedback watcher, never-regress, git-safety |
|
|
53
57
|
| **8. Feedback** — learn from it | same mistake every session | **memory promotion**, pattern RL, session analysis |
|
|
54
58
|
|
|
59
|
+
Three stations are tightened against the failure classes named in
|
|
60
|
+
mtlynch.io's *Why Are Coding Agents So Dumb?*: plan **legibility** (a
|
|
61
|
+
readability gate over plans + the version-pinned **self-knowledge card**),
|
|
62
|
+
**scheduling** (completion-triggered dispatch with per-leaf model dials), and
|
|
63
|
+
**autonomy** (the attention queue + AFK auto-decider: the agent asks instead
|
|
64
|
+
of stopping, and an unattended decision adopts the recorded safe default,
|
|
65
|
+
logged, never silent).
|
|
66
|
+
|
|
55
67
|
Cross-cutting through every station: **policy gates** are the executable rules
|
|
56
68
|
posted at each station, the **MCP Router** keeps the context lean so the belt
|
|
57
69
|
never jams, and UAP runs across **9 harnesses** so the same floor plan applies
|
|
@@ -255,7 +267,7 @@ interpreter-mediated writes), memory-before-plan, MCP-router-first,
|
|
|
255
267
|
and more. Levels: **REQUIRED** blocks, **RECOMMENDED** logs,
|
|
256
268
|
**OPTIONAL** informs.
|
|
257
269
|
|
|
258
|
-
Two trust anchors sit above the policies themselves
|
|
270
|
+
Two trust anchors sit above the policies themselves: the
|
|
259
271
|
**operator-overrides file** (`.uap/operator-overrides.json` — temporary,
|
|
260
272
|
expiring bypasses) and the **liveness cache** (`.uap/policy-liveness.json` —
|
|
261
273
|
for policies that declare liveness requirements, a record that their compliant
|
|
@@ -273,7 +285,7 @@ compound invisibly until the codebase fights every change. This station turns
|
|
|
273
285
|
ten software-quality metrics into a machine-checked budget that can only
|
|
274
286
|
tighten.
|
|
275
287
|
|
|
276
|
-
The quality-metrics gate
|
|
288
|
+
The quality-metrics gate polices cyclomatic/cognitive complexity,
|
|
277
289
|
Halstead difficulty, LOC-per-file, coverage, CRAP, surviving mutants, dead
|
|
278
290
|
code, duplicate blocks, and explicit `any`/`unknown` — deterministically, with
|
|
279
291
|
no LLM in the loop. The built-in scanner (LOC, complexity, any-types) always
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# The UAP Protocol
|
|
2
2
|
|
|
3
|
-
`
|
|
3
|
+
`v2.30.0`
|
|
4
4
|
|
|
5
5
|
> **🏭 Where this fits:** Cross-cutting (the factory rulebook) — with no shared
|
|
6
6
|
> contract, each station's rules are guesswork and your agent slips broken work
|
|
@@ -77,6 +77,12 @@ hook, which MUST:
|
|
|
77
77
|
this in the agent's context.
|
|
78
78
|
2. **Clean stale state.** Deregister dead agents and release abandoned work
|
|
79
79
|
claims so coordination state stays accurate.
|
|
80
|
+
3. **Surface waiting decisions.** Sweep the operator attention queue —
|
|
81
|
+
grace-elapsed asks adopt their recorded safe default (logged on the item,
|
|
82
|
+
never silent); asks with no safe default escalate — then emit a bounded
|
|
83
|
+
block of still-open asks (plus a while-you-were-away summary) into the
|
|
84
|
+
session banner. Item text is rendered with an untrusted-data disclaimer;
|
|
85
|
+
`UAP_ATTENTION_OFF=1` silences the rail end-to-end.
|
|
80
86
|
|
|
81
87
|
The hook is **self-healing and fail-open**: it auto-creates missing
|
|
82
88
|
coordination/memory DBs and never exits non-zero. Its output is advisory
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
# ADR 0006: Operator-directed model placement (registry + ledger + proxy gate)
|
|
2
|
+
|
|
3
|
+
- Status: Accepted
|
|
4
|
+
- Date: 2026-10-08
|
|
5
|
+
- Spec: `docs/specs/operator-model-placement.md`
|
|
6
|
+
|
|
7
|
+
## Context
|
|
8
|
+
|
|
9
|
+
One 24 GiB GPU, seven placeable model configs, one of them resident and filling
|
|
10
|
+
the card (measured 21,812 MiB of 24,576; host RSS 52.9 GiB of 121.7 GiB). Model
|
|
11
|
+
switching today is a hand-run shell script (`~/.config/uap/model-switch.sh`)
|
|
12
|
+
with no drain, no verification, and no rollback. The proxy forwards to a single
|
|
13
|
+
upstream (`LLAMA_CPP_BASE`, one constant, 35 references) and has no model
|
|
14
|
+
lifecycle at all. Requests for a non-resident model either fail or silently get
|
|
15
|
+
rewritten by `_reconcile_wire_model()`.
|
|
16
|
+
|
|
17
|
+
## Decision
|
|
18
|
+
|
|
19
|
+
1. **Two-file registry.** Reviewed defaults in `config/model-registry.json`,
|
|
20
|
+
machine-local measured footprints in `~/.uap/model-registry.json`,
|
|
21
|
+
deep-merged local-over-repo, with per-field provenance reported by
|
|
22
|
+
`uap models validate`. Unknown cost fails closed: an unmeasured config can
|
|
23
|
+
be served if resident but can never be loaded or evicted. The registry
|
|
24
|
+
references the capacity policy rather than restating its numbers (ownership
|
|
25
|
+
table in the spec, §4.1).
|
|
26
|
+
2. **Placement state lives in a versioned, advisory-locked ledger**
|
|
27
|
+
(`~/.uap/placement.json`). The ledger records intent; a live probe records
|
|
28
|
+
fact; when they disagree the probe wins and the disagreement is surfaced.
|
|
29
|
+
3. **Enforcement is TypeScript, hosted on the dashboard server, invoked by the
|
|
30
|
+
Python proxy over loopback HTTP.** No new daemon; one process owns placement
|
|
31
|
+
state, and the TUI and dashboard read the same one. The proxy discovers the
|
|
32
|
+
controller via `PROXY_PLACEMENT_CONTROLLER` emitted by `uap setup`; the
|
|
33
|
+
control surface is loopback-bound regardless of the dashboard `--host`.
|
|
34
|
+
4. **`paused` means weights offloaded and reloaded from disk later** — not the
|
|
35
|
+
proxy's existing save/restore, which checkpoints KV to host RAM and frees no
|
|
36
|
+
VRAM. Where an engine has no reload path, `paused` is display-only and the
|
|
37
|
+
only executable option is `kill`.
|
|
38
|
+
5. **Admission runs in the proxy after wire-model resolution**, default
|
|
39
|
+
`PROXY_PLACEMENT_MODE=off`, gated per entry route (the gate is a function of
|
|
40
|
+
the resolved wire model, not a side effect of one route's rewrite step —
|
|
41
|
+
`_reconcile_wire_model` has exactly one call site). Parked requests get
|
|
42
|
+
`409 model_placement_pending`; the proxy never holds a socket across an
|
|
43
|
+
unbounded operator decision. A swap invalidates the proxy's process-lifetime
|
|
44
|
+
upstream-id cache before any pending request is released.
|
|
45
|
+
6. **Leases and backpressure become target-keyed** with an additive
|
|
46
|
+
`target = 'default'` legacy bucket, preserving the
|
|
47
|
+
delete-then-count-then-insert transaction ordering that makes
|
|
48
|
+
`acquireModelSlot()` safe today. `target` is the placement target identity
|
|
49
|
+
(device + endpoint), never the model name. The migration is guarded by a
|
|
50
|
+
`PRAGMA table_info` probe (the coordination DB has no version marker), on the
|
|
51
|
+
precedent of `src/memory/short-term/schema.ts`.
|
|
52
|
+
|
|
53
|
+
## Consequences
|
|
54
|
+
|
|
55
|
+
Positive: placement decisions become data (`uap doctor`, `uap models validate`)
|
|
56
|
+
instead of prose in profile files; displacement is expressed in MiB rather than
|
|
57
|
+
unit names; the operator sees the victim list before committing, and
|
|
58
|
+
enforcement aborts if the re-derived list differs.
|
|
59
|
+
|
|
60
|
+
Negative: the proxy gains a control-plane dependency on the dashboard process
|
|
61
|
+
(no dashboard means read-only admission and `reason: no_controller`); the
|
|
62
|
+
teardown/start time envelope is unmeasured, so drain and hold timeouts ship as
|
|
63
|
+
conservative defaults labelled unvalidated; the coordination DB gains a table
|
|
64
|
+
rebuild with no version marker, so the migration must be probe-guarded;
|
|
65
|
+
per-target upstream addressing (phase 1.5) is a prerequisite refactor in the
|
|
66
|
+
17k-line proxy and cannot be skipped.
|
|
67
|
+
|
|
68
|
+
Neutral: `uap models` sits next to the existing `uap model` command.
|
|
69
|
+
|
|
70
|
+
## Alternatives Considered
|
|
71
|
+
|
|
72
|
+
- **Enforcement in the proxy (Python).** Rejected: the proxy has no subprocess
|
|
73
|
+
or systemd machinery in 17k lines, and the TS side already owns the units,
|
|
74
|
+
the capacity policy, the lease ledger, and the dashboard.
|
|
75
|
+
- **A dedicated placement daemon.** Rejected: two processes holding placement
|
|
76
|
+
state, and a new thing to supervise on a box that already supervises too
|
|
77
|
+
much.
|
|
78
|
+
- **Derive cost from GGUF file sizes.** Rejected by measurement: 79 GiB on disk
|
|
79
|
+
for a 21.8 GiB GPU footprint, and 15 GiB on disk for a config needing 22+ GiB.
|
|
80
|
+
Disk size is not a proxy for anything.
|
|
81
|
+
- **Use the existing save/restore path for `paused`.** Rejected: it frees no
|
|
82
|
+
VRAM, costs 10-20 s per slot, and may not fit in ~29 GiB of available host
|
|
83
|
+
RAM against a 52.9 GiB resident process.
|
|
84
|
+
- **Advertise a fixed VRAM cost per model.** Rejected: cost is per config and
|
|
85
|
+
drifts with engine build and flags; unmeasured entries are marked
|
|
86
|
+
`unmeasured` rather than guessed.
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
# ADR 0007: Auto-displacement allowlist as standing operator consent
|
|
2
|
+
|
|
3
|
+
- Status: Accepted
|
|
4
|
+
- Date: 2026-10-09
|
|
5
|
+
- Spec: `docs/specs/operator-model-placement.md` §4.4.1, §6 (phase-4 note)
|
|
6
|
+
- Supersedes: none — extends ADR 0006's core invariant ("never evict without
|
|
7
|
+
explicit operator confirmation") to the request-driven case.
|
|
8
|
+
|
|
9
|
+
## Context
|
|
10
|
+
|
|
11
|
+
Placement is request-driven: a gated request that parks because its
|
|
12
|
+
model is not resident can load itself, so the operator stops running
|
|
13
|
+
`uap models apply` by hand (the motivating case: running `ugc-factory`
|
|
14
|
+
end-to-end without manual model switching). The spec's phase table originally
|
|
15
|
+
said phase 4 ships "auto-load alongside; never displacement", and the core
|
|
16
|
+
invariant says an operator confirms every eviction. On this machine
|
|
17
|
+
`load_alongside` has no solutions at all (one config holds 21,812 of 24,576
|
|
18
|
+
MiB), so alongside-only auto mode would auto-load nothing that matters here
|
|
19
|
+
and the operator would keep hand-running swaps for exactly the models they
|
|
20
|
+
already trust.
|
|
21
|
+
|
|
22
|
+
## Decision
|
|
23
|
+
|
|
24
|
+
1. **Non-displacing options auto-enforce whenever the policy is enabled**
|
|
25
|
+
(`~/.uap/placement-auto.json`, opt-in, fail-closed). Reuse needs nothing;
|
|
26
|
+
load-alongside evicts nothing; the budget math already said it fits.
|
|
27
|
+
2. **Displacement auto-enforces only for models on an explicit allowlist**,
|
|
28
|
+
recorded by `uap models auto --allow-displace <model> --yes`. The allowlist
|
|
29
|
+
IS the explicit operator confirmation the core invariant requires:
|
|
30
|
+
- standing, not per-event — the `--yes` gate prints exactly what is being
|
|
31
|
+
consented to ("UNLOADS the current resident(s) — the minimal set that
|
|
32
|
+
makes room, re-evaluated at load time — and loads the requested one
|
|
33
|
+
WITHOUT an operator prompt between them");
|
|
34
|
+
- deliberate — nothing enters it by default, and a bare `--allow-displace`
|
|
35
|
+
without `--yes` records nothing;
|
|
36
|
+
- auditable and revocable — the file is plain JSON in `~/.uap`, per-model
|
|
37
|
+
removal via `--disallow-displace`, whole feature off via `--disable`.
|
|
38
|
+
3. **The consent subject is the model being LOADED, not the victim.** Victims
|
|
39
|
+
are dynamic: enforcement re-derives the minimal eviction set and
|
|
40
|
+
drift-checks it against the live ledger at run time (`enforce.ts`), so a
|
|
41
|
+
static victim list would go stale the moment residents change. The loaded
|
|
42
|
+
model is the stable thing the operator is vouching for.
|
|
43
|
+
4. **Run-shape guards bound the standing consent** (phase-4 parallel review):
|
|
44
|
+
one run per requested model, single-flight machine-wide, a hard concurrency
|
|
45
|
+
cap, a failure cooldown that kills any drain→stop→fail→rollback
|
|
46
|
+
oscillation, TTL extension so the supervised entry outlives its run, and a
|
|
47
|
+
run that never rejects (a ledger-write throw must not kill the dashboard).
|
|
48
|
+
|
|
49
|
+
## Consequences
|
|
50
|
+
|
|
51
|
+
- The operator's machines can swap models unattended, but only for models
|
|
52
|
+
they explicitly named; everything else still parks for a human `apply`.
|
|
53
|
+
- The allowlist must be reviewed like any standing credential: a model on it
|
|
54
|
+
can be loaded by any gated client request while the resident is evicted
|
|
55
|
+
without a prompt. `uap models auto` (status) is the audit surface.
|
|
56
|
+
- "Never displacement" in the phase table was amended to "never displacement
|
|
57
|
+
by default" — the reasoning lives in the spec §6 phase-4 note and here.
|
|
58
|
+
- The proxy stays dumb (reason strings only); the controller remains the
|
|
59
|
+
single decision-maker, and the policy file is the single authority
|
|
60
|
+
(independent of `PROXY_PLACEMENT_MODE`).
|
|
61
|
+
|
|
62
|
+
## Addendum (2026-10-11): idle unload uses the same doctrine
|
|
63
|
+
|
|
64
|
+
Auto-load had no reverse: residents loaded by §4.4.1 held their device until
|
|
65
|
+
a human stopped them. The idle sweep (spec §4.4.2) extends this ADR's
|
|
66
|
+
reasoning to auto-UNLOAD, which is also an unattended change to what runs on
|
|
67
|
+
the machine:
|
|
68
|
+
|
|
69
|
+
- `unload_allow` is standing consent with the same shape as
|
|
70
|
+
`allow_displace`: `uap models auto --allow-unload <model> --yes` (the
|
|
71
|
+
`--yes` gate prints what stops, when), per-model revocation via
|
|
72
|
+
`--disallow-unload`, feature off with no `unload_idle_after_secs` recorded.
|
|
73
|
+
- The consent subject is again the model, not the moment: the clock resets on
|
|
74
|
+
every gated request served, an unwatched resident's clock starts at first
|
|
75
|
+
observation (arming never evicts the already-idle), and unknown endpoint
|
|
76
|
+
state (`ss` unable to answer) is a refusal to unload, never a guess.
|
|
77
|
+
- The stop reuses the operator's full `unloadPlacement` machinery — the
|
|
78
|
+
standing consent covers WHEN, and the drain/in-flight/rollback guards
|
|
79
|
+
still bound it per-event.
|