loki-mode 11.5.1 → 11.6.0
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/SKILL.md +2 -2
- package/VERSION +1 -1
- package/autonomy/loki +12 -201
- package/autonomy/notification-checker.py +1 -1
- package/dashboard/__init__.py +3 -10
- package/dashboard/control.py +5 -435
- package/docs/ARCHITECTURE.md +1 -2
- package/docs/CLI-CORE-VERBS.md +2 -6
- package/docs/CLI-REFERENCE.md +1 -1
- package/docs/COMPONENTS.md +0 -2
- package/docs/INSTALLATION.md +1 -1
- package/docs/authentication.md +19 -1
- package/docs/dev/release-checklist.md +9 -8
- package/docs/enterprise/security.md +3 -234
- package/docs/v10/ARCHITECT-CUTS.md +304 -0
- package/docs/v10/DECISIONS.md +5 -5
- package/docs/v10/ENGINE.md +735 -299
- package/docs/v10/GUARDS.md +16 -14
- package/docs/v10/GUIDE.md +5 -7
- package/docs/v10/PROGRESS.md +12 -1
- package/docs/v11/MARKET-SLICES.md +1 -5
- package/integrations/openclaw/README.md +20 -0
- package/integrations/vibe-kanban.md +12 -50
- package/loki-ts/dist/loki.js +1183 -1182
- package/mcp/__init__.py +1 -1
- package/mcp/_sdk_loader.py +1 -1
- package/package.json +2 -2
- package/packages/control-plane/dist/server.js +630 -613
- package/plugins/loki-mode/.claude-plugin/plugin.json +1 -1
- package/references/quality-control.md +1 -116
- package/skills/00-index.md +2 -2
- package/skills/artifacts.md +0 -22
- package/skills/production.md +2 -38
- package/web-app/dist/assets/{AdminPage-Cbu3pXL8.js → AdminPage-DhXdJNQk.js} +1 -1
- package/web-app/dist/assets/{Avatar-DGqGGcGx.js → Avatar-ixVj76fM.js} +1 -1
- package/web-app/dist/assets/{Badge-Bhlipt6v.js → Badge-BGMSp22s.js} +1 -1
- package/web-app/dist/assets/{Button-CpN2sO61.js → Button-pYJc32tG.js} +1 -1
- package/web-app/dist/assets/{CockpitPage-BqeDJwdL.js → CockpitPage-C1JBBouA.js} +1 -1
- package/web-app/dist/assets/{ComparePage-DUieA2ba.js → ComparePage-qD0NV4RK.js} +1 -1
- package/web-app/dist/assets/{ErrorBoundary-DTWsYrOm.js → ErrorBoundary-C-yxO58j.js} +1 -1
- package/web-app/dist/assets/{EvidenceReceiptPanel-BU_B9X19.js → EvidenceReceiptPanel-ByPzuE1S.js} +1 -1
- package/web-app/dist/assets/{GitHubIssuesPanel-DEZoLOsP.js → GitHubIssuesPanel-BNv_2BEJ.js} +1 -1
- package/web-app/dist/assets/{GitHubPRsPanel-BEsnrq7Y.js → GitHubPRsPanel-CuLZQ9CS.js} +1 -1
- package/web-app/dist/assets/{HomePage-BoUVuq7h.js → HomePage-CS_FW8Je.js} +2 -2
- package/web-app/dist/assets/{LoginPage-CmOED7vb.js → LoginPage-DwiNf1Wm.js} +1 -1
- package/web-app/dist/assets/{MagicPage-DATZitrZ.js → MagicPage-CmQybLPZ.js} +1 -1
- package/web-app/dist/assets/{MetricsPage-DGL1v0I-.js → MetricsPage-D9ERdpv8.js} +1 -1
- package/web-app/dist/assets/{NotFoundPage-C2WgOjZd.js → NotFoundPage-D9ccgdbF.js} +1 -1
- package/web-app/dist/assets/{ProjectPage-BMi1tepj.js → ProjectPage-B9Jslmgv.js} +3 -3
- package/web-app/dist/assets/{ProjectsPage-vc3y5YPh.js → ProjectsPage-DnU99Go2.js} +1 -1
- package/web-app/dist/assets/{SettingsPage-kbq0Ftvi.js → SettingsPage-DcTyx6wo.js} +1 -1
- package/web-app/dist/assets/{ShowcasePage-Bn6Q8Kbg.js → ShowcasePage-jEY9ghSr.js} +1 -1
- package/web-app/dist/assets/{SystemSettingsPage-Basmhs_b.js → SystemSettingsPage-CSGltW-8.js} +1 -1
- package/web-app/dist/assets/{TeamsPage-BTqOc4TR.js → TeamsPage-gUuJXb9l.js} +1 -1
- package/web-app/dist/assets/{TemplatesPage-2P9002VL.js → TemplatesPage-37Zhe--v.js} +1 -1
- package/web-app/dist/assets/{TerminalOutput-CAoSPBrg.js → TerminalOutput-B09hRwaR.js} +1 -1
- package/web-app/dist/assets/{activity-BcWVWCqU.js → activity-q_4MY9J0.js} +1 -1
- package/web-app/dist/assets/{bell-CYRqqgZ6.js → bell-X8OC_PFP.js} +1 -1
- package/web-app/dist/assets/{bot-CU7gdn3g.js → bot-C-N1PUOD.js} +1 -1
- package/web-app/dist/assets/{check-DLlCpz9V.js → check-B2c76Jmp.js} +1 -1
- package/web-app/dist/assets/{chevron-left-CE9Cb30C.js → chevron-left-BF76YLNw.js} +1 -1
- package/web-app/dist/assets/{circle-alert-uou4bjua.js → circle-alert-AeFKBD8h.js} +1 -1
- package/web-app/dist/assets/{clock-C_dSJcDX.js → clock-CiXRf-FH.js} +1 -1
- package/web-app/dist/assets/{cloud-DZ22ITF6.js → cloud-DKQ8SRJ5.js} +1 -1
- package/web-app/dist/assets/{code-xml-BrJS0hhS.js → code-xml-DEb6jXWP.js} +1 -1
- package/web-app/dist/assets/{database-D2HOmxtl.js → database-6W7e-E9c.js} +1 -1
- package/web-app/dist/assets/{dollar-sign-CQ1vK_6q.js → dollar-sign-Ds2GOuyW.js} +1 -1
- package/web-app/dist/assets/{file-code-corner-w2vpGm5d.js → file-code-corner-CZU0jg52.js} +1 -1
- package/web-app/dist/assets/{file-plus-DlF6wjkD.js → file-plus-DTVYnXCN.js} +1 -1
- package/web-app/dist/assets/{globe-Dy3lBJg1.js → globe-0mUzKYDe.js} +1 -1
- package/web-app/dist/assets/{hammer-C3xIiRXN.js → hammer-BMHZg3YX.js} +1 -1
- package/web-app/dist/assets/{index-4t-_IW2y.js → index-BvOTvjax.js} +3 -3
- package/web-app/dist/assets/{layers-Y8Fs8qXI.js → layers-Df7TdcWB.js} +1 -1
- package/web-app/dist/assets/{loader-circle-CxgN1v4m.js → loader-circle-kPsVfrSY.js} +1 -1
- package/web-app/dist/assets/{lock-DFFNbXDs.js → lock-CXYcbEc5.js} +1 -1
- package/web-app/dist/assets/{package-5e6qCTUg.js → package-Cqhua1ID.js} +1 -1
- package/web-app/dist/assets/{plus-C0Go_ytj.js → plus-lseXhsn-.js} +1 -1
- package/web-app/dist/assets/{refresh-cw-D4i-NW3o.js → refresh-cw-OZriI6gD.js} +1 -1
- package/web-app/dist/assets/{rotate-ccw-YlKkiUW6.js → rotate-ccw-CKCfjPg8.js} +1 -1
- package/web-app/dist/assets/{scroll-text-4qXOHTap.js → scroll-text-DoVyyfKb.js} +1 -1
- package/web-app/dist/assets/{server-BB6zXNp9.js → server-DGy7TflW.js} +1 -1
- package/web-app/dist/assets/{shield-alert-D4tzjB1H.js → shield-alert-BCzRcMXi.js} +1 -1
- package/web-app/dist/assets/{thumbs-up-DZiRwdFj.js → thumbs-up-C_znJd5g.js} +1 -1
- package/web-app/dist/assets/{trash-2-Dv_LkRIK.js → trash-2-BosCbeeA.js} +1 -1
- package/web-app/dist/assets/{trending-down-BJYp9PQe.js → trending-down-CkR5zDkV.js} +1 -1
- package/web-app/dist/assets/{trending-up-BTcXLklK.js → trending-up-DpUIfOH4.js} +1 -1
- package/web-app/dist/assets/{upload-fcHqwOxr.js → upload-CH9aKc8L.js} +1 -1
- package/web-app/dist/assets/{usePolling-BeJYw_4L.js → usePolling-pzxrHJeg.js} +1 -1
- package/web-app/dist/assets/{user-BcDwUCsO.js → user-B7OHa-VQ.js} +1 -1
- package/web-app/dist/index.html +1 -1
- package/dashboard/run.py +0 -63
- package/docs/openclaw-integration.md +0 -52
- package/docs/v10/HANDOFF-NEXT-WEEK.md +0 -40
- package/docs/v10/MORNING-BRIEF-1003.md +0 -25
- package/docs/v10/MORNING-BRIEF.md +0 -52
- package/docs/v10/TODO.md +0 -35
- package/mcp/resources.py +0 -351
- package/mcp/tools.py +0 -200
|
@@ -6,153 +6,9 @@
|
|
|
6
6
|
|
|
7
7
|
Loki Mode's security model follows a defense-in-depth approach. All security features are opt-in via environment variables, with sensible defaults that prioritize safety. When enterprise auth is not configured, the system operates in local-only mode with no network exposure.
|
|
8
8
|
|
|
9
|
-
## Authentication
|
|
9
|
+
## Authentication and Authorization
|
|
10
10
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
The primary authentication method uses bearer tokens prefixed with `loki_`.
|
|
14
|
-
|
|
15
|
-
**Configuration:**
|
|
16
|
-
|
|
17
|
-
```bash
|
|
18
|
-
# Enable token auth for the dashboard/control plane API
|
|
19
|
-
export LOKI_ENTERPRISE_AUTH=true
|
|
20
|
-
```
|
|
21
|
-
|
|
22
|
-
**Token Lifecycle:**
|
|
23
|
-
|
|
24
|
-
```bash
|
|
25
|
-
# Create a new API key
|
|
26
|
-
curl -X POST http://localhost:57374/api/keys \
|
|
27
|
-
-H "Authorization: Bearer $ADMIN_TOKEN" \
|
|
28
|
-
-H "Content-Type: application/json" \
|
|
29
|
-
-d '{"name": "ci-pipeline", "role": "operator"}'
|
|
30
|
-
|
|
31
|
-
# Rotate a key with 24-hour grace period
|
|
32
|
-
curl -X POST http://localhost:57374/api/keys/ci-pipeline/rotate \
|
|
33
|
-
-H "Authorization: Bearer $ADMIN_TOKEN" \
|
|
34
|
-
-H "Content-Type: application/json" \
|
|
35
|
-
-d '{"grace_period_hours": 24}'
|
|
36
|
-
|
|
37
|
-
# Revoke a key
|
|
38
|
-
curl -X DELETE http://localhost:57374/api/keys/ci-pipeline \
|
|
39
|
-
-H "Authorization: Bearer $ADMIN_TOKEN"
|
|
40
|
-
```
|
|
41
|
-
|
|
42
|
-
**SDK Usage:**
|
|
43
|
-
|
|
44
|
-
Python:
|
|
45
|
-
```python
|
|
46
|
-
from loki_mode_sdk import AutonomiClient
|
|
47
|
-
|
|
48
|
-
client = AutonomiClient(
|
|
49
|
-
base_url="http://localhost:57374",
|
|
50
|
-
token="loki_your_token_here"
|
|
51
|
-
)
|
|
52
|
-
```
|
|
53
|
-
|
|
54
|
-
TypeScript:
|
|
55
|
-
```typescript
|
|
56
|
-
import { AutonomiClient } from 'loki-mode-sdk';
|
|
57
|
-
|
|
58
|
-
const client = new AutonomiClient({
|
|
59
|
-
baseUrl: 'http://localhost:57374',
|
|
60
|
-
token: 'loki_your_token_here'
|
|
61
|
-
});
|
|
62
|
-
```
|
|
63
|
-
|
|
64
|
-
### OIDC / SSO Integration
|
|
65
|
-
|
|
66
|
-
For organizations using identity providers (Okta, Auth0, Azure AD), Loki Mode supports OIDC-based authentication.
|
|
67
|
-
|
|
68
|
-
**Configuration:**
|
|
69
|
-
|
|
70
|
-
```bash
|
|
71
|
-
export LOKI_OIDC_ISSUER="https://your-idp.okta.com/oauth2/default"
|
|
72
|
-
export LOKI_OIDC_CLIENT_ID="your-client-id"
|
|
73
|
-
# Optional: audience override (defaults to LOKI_OIDC_CLIENT_ID)
|
|
74
|
-
export LOKI_OIDC_AUDIENCE="your-api-audience"
|
|
75
|
-
```
|
|
76
|
-
|
|
77
|
-
The system validates OIDC bearer tokens (presented as `Authorization: Bearer <jwt>`)
|
|
78
|
-
against the issuer's JWKS endpoint. When PyJWT + cryptography are installed, the
|
|
79
|
-
JWT signature is cryptographically verified (RS256/RS384/RS512) along with the
|
|
80
|
-
issuer, audience, and expiry. Without PyJWT, tokens are rejected unless
|
|
81
|
-
`LOKI_OIDC_SKIP_SIGNATURE_VERIFY=true` is set explicitly (insecure, local testing
|
|
82
|
-
only).
|
|
83
|
-
|
|
84
|
-
**Claims-to-roles mapping:**
|
|
85
|
-
|
|
86
|
-
On a valid token, role/group claims are mapped to the four built-in Loki roles
|
|
87
|
-
(`admin`, `operator`, `viewer`, `auditor`). The resolved role's scopes are then
|
|
88
|
-
enforced through the same scope hierarchy used for API tokens. OIDC users are
|
|
89
|
-
NOT granted full access by default.
|
|
90
|
-
|
|
91
|
-
Recognized claim sources (case-insensitive; values may be a string,
|
|
92
|
-
space-separated string, or list):
|
|
93
|
-
|
|
94
|
-
| Claim | Provider |
|
|
95
|
-
|-------|----------|
|
|
96
|
-
| value of `LOKI_OIDC_ROLES_CLAIM` (supports dotted paths, e.g. `realm_access.roles`) | configurable |
|
|
97
|
-
| `roles` | generic |
|
|
98
|
-
| `groups` | generic |
|
|
99
|
-
| `realm_access.roles` | Keycloak |
|
|
100
|
-
| `cognito:groups` | AWS Cognito |
|
|
101
|
-
|
|
102
|
-
Only claim values that exactly match a built-in role name (`admin`, `operator`,
|
|
103
|
-
`viewer`, `auditor`) grant that role. Arbitrary group names (common in `groups`
|
|
104
|
-
or `cognito:groups`) do not map to a role and fall through to the default.
|
|
105
|
-
|
|
106
|
-
When multiple recognized roles are present, the highest-privilege match wins
|
|
107
|
-
(precedence: `admin` > `operator` > `auditor` > `viewer`).
|
|
108
|
-
|
|
109
|
-
**Default role (when no recognized role claim is present):**
|
|
110
|
-
|
|
111
|
-
```bash
|
|
112
|
-
# Defaults to the least-privileged role (viewer). Never admin.
|
|
113
|
-
export LOKI_OIDC_DEFAULT_ROLE="viewer"
|
|
114
|
-
```
|
|
115
|
-
|
|
116
|
-
If `LOKI_OIDC_DEFAULT_ROLE` is unset or set to an unrecognized value, it falls
|
|
117
|
-
back to `viewer`. The default is never `admin` / full access.
|
|
118
|
-
|
|
119
|
-
## Authorization
|
|
120
|
-
|
|
121
|
-
### Role-Based Access Control
|
|
122
|
-
|
|
123
|
-
Four built-in roles provide scoped access:
|
|
124
|
-
|
|
125
|
-
| Role | Scope | Permissions |
|
|
126
|
-
|------|-------|-------------|
|
|
127
|
-
| `admin` | Full control | Create/delete tenants, manage API keys, configure policies, all operator/viewer/auditor permissions |
|
|
128
|
-
| `operator` | Execution | Start/cancel runs, create/update projects and tasks, read all resources |
|
|
129
|
-
| `viewer` | Read-only | Read projects, runs, tasks, status. No write or delete operations |
|
|
130
|
-
| `auditor` | Audit access | Read audit logs, verify chain integrity, generate compliance reports. No execution permissions |
|
|
131
|
-
|
|
132
|
-
**Scope Hierarchy:**
|
|
133
|
-
|
|
134
|
-
```
|
|
135
|
-
admin > operator > viewer
|
|
136
|
-
admin > auditor
|
|
137
|
-
```
|
|
138
|
-
|
|
139
|
-
Admin inherits all permissions. Operator inherits viewer permissions. Auditor is a separate branch with read-only access to audit data.
|
|
140
|
-
|
|
141
|
-
**API Key Scopes:**
|
|
142
|
-
|
|
143
|
-
API keys are created with a role assignment:
|
|
144
|
-
|
|
145
|
-
```bash
|
|
146
|
-
# Create a viewer key for monitoring dashboards
|
|
147
|
-
curl -X POST http://localhost:57374/api/keys \
|
|
148
|
-
-H "Authorization: Bearer $ADMIN_TOKEN" \
|
|
149
|
-
-d '{"name": "grafana-reader", "role": "viewer"}'
|
|
150
|
-
|
|
151
|
-
# Create an operator key for CI pipelines
|
|
152
|
-
curl -X POST http://localhost:57374/api/keys \
|
|
153
|
-
-H "Authorization: Bearer $ADMIN_TOKEN" \
|
|
154
|
-
-d '{"name": "github-actions", "role": "operator"}'
|
|
155
|
-
```
|
|
11
|
+
Token auth (`LOKI_ENTERPRISE_AUTH`), key rotation with a 24-hour grace period, OIDC/SSO claim mapping and the default viewer role are documented in [authentication.md](../authentication.md). Roles (`admin`, `operator`, `viewer`, `auditor`), scope hierarchy and API key scopes are in [authorization.md](../authorization.md).
|
|
156
12
|
|
|
157
13
|
## API Security
|
|
158
14
|
|
|
@@ -221,94 +77,7 @@ This is a deliberate fail-closed design. Invalid or missing signatures always re
|
|
|
221
77
|
|
|
222
78
|
## Audit Logging
|
|
223
79
|
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
Audit logs use SHA-256 hash chains for tamper evidence. Each entry's hash depends on the previous entry's hash, creating an immutable chain from the genesis record.
|
|
227
|
-
|
|
228
|
-
**JavaScript Audit (Agent Actions):**
|
|
229
|
-
|
|
230
|
-
```
|
|
231
|
-
.loki/audit/audit.jsonl
|
|
232
|
-
```
|
|
233
|
-
|
|
234
|
-
Each entry:
|
|
235
|
-
```json
|
|
236
|
-
{
|
|
237
|
-
"seq": 42,
|
|
238
|
-
"timestamp": "2026-02-21T10:00:00.000Z",
|
|
239
|
-
"who": "agent-1",
|
|
240
|
-
"what": "file_write",
|
|
241
|
-
"where": "src/app.js",
|
|
242
|
-
"why": "implement feature",
|
|
243
|
-
"previousHash": "abc123...",
|
|
244
|
-
"hash": "def456..."
|
|
245
|
-
}
|
|
246
|
-
```
|
|
247
|
-
|
|
248
|
-
**Python Audit (Dashboard API):**
|
|
249
|
-
|
|
250
|
-
```
|
|
251
|
-
~/.loki/dashboard/audit/audit-2026-02-21.jsonl
|
|
252
|
-
```
|
|
253
|
-
|
|
254
|
-
Each entry:
|
|
255
|
-
```json
|
|
256
|
-
{
|
|
257
|
-
"timestamp": "2026-02-21T10:00:00.000Z",
|
|
258
|
-
"action": "create",
|
|
259
|
-
"resource_type": "project",
|
|
260
|
-
"resource_id": "proj-1",
|
|
261
|
-
"user_id": "admin",
|
|
262
|
-
"success": true,
|
|
263
|
-
"_integrity_hash": "abc123..."
|
|
264
|
-
}
|
|
265
|
-
```
|
|
266
|
-
|
|
267
|
-
### Chain Verification
|
|
268
|
-
|
|
269
|
-
JavaScript:
|
|
270
|
-
```javascript
|
|
271
|
-
const audit = require('./src/audit');
|
|
272
|
-
audit.init('/path/to/project');
|
|
273
|
-
const result = audit.verifyChain();
|
|
274
|
-
// { valid: true, entries: 1542, brokenAt: null, error: null }
|
|
275
|
-
```
|
|
276
|
-
|
|
277
|
-
Python:
|
|
278
|
-
```python
|
|
279
|
-
from dashboard.audit import verify_log_integrity
|
|
280
|
-
result = verify_log_integrity("/path/to/audit-2026-02-21.jsonl")
|
|
281
|
-
# {"valid": True, "entries_checked": 1542, "first_tampered_line": None}
|
|
282
|
-
```
|
|
283
|
-
|
|
284
|
-
API:
|
|
285
|
-
```bash
|
|
286
|
-
curl http://localhost:57374/api/audit/verify \
|
|
287
|
-
-H "Authorization: Bearer $TOKEN"
|
|
288
|
-
```
|
|
289
|
-
|
|
290
|
-
### Syslog Forwarding
|
|
291
|
-
|
|
292
|
-
Forward audit events to a centralized syslog server for SIEM integration:
|
|
293
|
-
|
|
294
|
-
```bash
|
|
295
|
-
export LOKI_AUDIT_SYSLOG_HOST="syslog.company.com"
|
|
296
|
-
export LOKI_AUDIT_SYSLOG_PORT="514" # default
|
|
297
|
-
export LOKI_AUDIT_SYSLOG_PROTO="udp" # or "tcp"
|
|
298
|
-
```
|
|
299
|
-
|
|
300
|
-
Security-relevant actions (`delete`, `kill`, `stop`, `login`, `logout`, `create_token`, `revoke_token`) are logged at `WARNING` level. All other actions are logged at `INFO` level.
|
|
301
|
-
|
|
302
|
-
Syslog forwarding is fire-and-forget -- failures never block the main audit write path.
|
|
303
|
-
|
|
304
|
-
### Log Rotation
|
|
305
|
-
|
|
306
|
-
```bash
|
|
307
|
-
export LOKI_AUDIT_MAX_SIZE_MB="10" # Rotate when file exceeds this size
|
|
308
|
-
export LOKI_AUDIT_MAX_FILES="10" # Keep this many rotated files
|
|
309
|
-
```
|
|
310
|
-
|
|
311
|
-
Date-based log files (`audit-YYYY-MM-DD.jsonl`) are automatically rotated when they exceed the size limit. Old files are removed when the count exceeds the maximum.
|
|
80
|
+
Hash-chained audit logs, chain verification, syslog forwarding (`LOKI_AUDIT_SYSLOG_*`) and rotation (`LOKI_AUDIT_MAX_SIZE_MB`, `LOKI_AUDIT_MAX_FILES`) are documented in [audit-logging.md](../audit-logging.md).
|
|
312
81
|
|
|
313
82
|
## Data Residency
|
|
314
83
|
|
|
@@ -1,5 +1,309 @@
|
|
|
1
1
|
|
|
2
2
|
|
|
3
|
+
## 23:00Z cut (E-31..E-40)
|
|
4
|
+
|
|
5
|
+
Every claim below comes from reading main at 84c22568. I edited no files.
|
|
6
|
+
|
|
7
|
+
**What I found that shapes this cut**
|
|
8
|
+
|
|
9
|
+
1. **The engine cannot run from the npm package today.**
|
|
10
|
+
- Root `package.json` `files` ships `loki-ts/dist/` and no `loki-ts/src`. Every source-relative path is therefore dead in an install. These break:
|
|
11
|
+
- `machine.ts:44-55`: `optional()` checks whether `import.meta.dir/stages/<name>.ts` exists. In a bundle that file is never there, so every stage emits `stage.skipped` "module not present".
|
|
12
|
+
- `engine10/cli.ts:54`: the default loader uses a non-literal `import(spec)`.
|
|
13
|
+
- `output.ts:132`: dynamic import of the eta module.
|
|
14
|
+
- `session.ts:137`: spawns `[process.execPath, [import.meta.path, "--engine10-session-child"]]`. In a bundle, `import.meta.path` is `dist/loki.js`.
|
|
15
|
+
- `fetch_issue.ts:32` and `stages/pr.ts:49`: paths built with `new URL("../../../...", import.meta.url)`, which resolve above the package root from dist.
|
|
16
|
+
- `util/paths.ts` already finds `REPO_ROOT` by walking up to `VERSION` + `autonomy/run.sh`, and works from dist. The fix is to reuse it.
|
|
17
|
+
2. **The flip breaks two merged tests.**
|
|
18
|
+
- `tests/test-engine10-dispatch.sh` and `tests/test-engine10-legacy-contract.sh` both assert that an unset `LOKI_ENGINE` routes to legacy.
|
|
19
|
+
- The E-30 alias assertions switch from SKIP to live only when bin/loki matches `^[[:space:]]*legacy\)`.
|
|
20
|
+
3. **The gate chain has a hole.** No row runs the v10 arm over the 29 tasks. EV-4 is raw claude and EV-5 is legacy. E-38 closes this, and it runs the dist build so the gate measures what actually ships.
|
|
21
|
+
4. **Hard limits from existing code:**
|
|
22
|
+
- `loki-ts/src/runner/types.ts:8` has no opencode provider, and `providers.ts` is on the no-edit list. So the only honest opencode path is a clear refusal.
|
|
23
|
+
- `autonomy/loki` is also no-edit, so the deprecation note cannot live in legacy help text.
|
|
24
|
+
- `supervisor.ts` has no `main` yet. Its wiring arrives with E-14, so preflight wiring waits for E-14.
|
|
25
|
+
5. **E-TG's file set is not recorded anywhere.** PROGRESS.md:1255 names it only as a follow-up to E-07 and E-09. E-32 touches `session.ts`, so it depends on E-TG merging.
|
|
26
|
+
|
|
27
|
+
**How the file sets stay separate**
|
|
28
|
+
- **In-flight rows:** no file below appears in any ready, building or review row (E-14..E-29, EV-4, EV-5, EV-6, E-TG).
|
|
29
|
+
- **EV-6:** it keeps `eval/loki10/summarize` and `docs/v10/METRICS.md`. E-33 builds a new generator that EV-6 runs, so the two sets stay apart.
|
|
30
|
+
- **One planned exception:**
|
|
31
|
+
- E-31 changes one marked line in `README.md` and one in `docs/v10/GUIDE.md` (the opt-in line that E-34 writes).
|
|
32
|
+
- E-31 depends on E-34, so the two are never in flight together.
|
|
33
|
+
- The Captain applies that line change in the E-31 merge commit.
|
|
34
|
+
|
|
35
|
+
### E-31: Default flip to v10, with a `LOKI_ENGINE=legacy` override and the `loki legacy` alias
|
|
36
|
+
- **Files:**
|
|
37
|
+
- `bin/loki`
|
|
38
|
+
- `loki-ts/src/engine10/cli.ts` (USAGE text only)
|
|
39
|
+
- `tests/test-engine10-default.sh` (new)
|
|
40
|
+
- `tests/test-engine10-dispatch.sh`
|
|
41
|
+
- `tests/test-engine10-legacy-contract.sh`
|
|
42
|
+
- After E-34 merges: the one marked opt-in line in `README.md` and in `docs/v10/GUIDE.md`
|
|
43
|
+
- **Tier:** HIGH.
|
|
44
|
+
- **Gating:**
|
|
45
|
+
- Build on a branch now.
|
|
46
|
+
- After review, hold the row at `approved`. Merge only when the E-33 marker in `docs/v10/METRICS.md` reads `<!-- loki10-gate: met ... -->`.
|
|
47
|
+
- If the marker does not read met by 03:00Z, the row goes to `parked` and v10.0.0 ships with legacy as the default (D29).
|
|
48
|
+
- The test enforces the gate mechanically: the build goes red if the switch reads v10 while the marker does not read met.
|
|
49
|
+
- **Contents:**
|
|
50
|
+
- **One switch.** A single line in bin/loki, `_loki_engine_default="v10"`, and the v10 block tests `"${LOKI_ENGINE:-$_loki_engine_default}"`.
|
|
51
|
+
- **Override values.**
|
|
52
|
+
- `LOKI_ENGINE=legacy` runs today's route exactly.
|
|
53
|
+
- Any other non-empty value except `v10` exits 2 with a one-line message, so a typo such as `legasy` fails instead of silently picking an engine.
|
|
54
|
+
- **Alias.** A `case "${1:-}" in legacy) shift; export LOKI_ENGINE=legacy ;; esac` arm runs before the v10 block. The export keeps nested calls on legacy.
|
|
55
|
+
- For `loki legacy`, `loki legacy --help`, `-h` or `help`, the arm first prints `autonomy/lib/engine10-legacy-notice.txt` to stderr if that file exists (E-35 owns the text).
|
|
56
|
+
- **Precedence.** `LOKI_LEGACY_BASH=1` still wins over everything.
|
|
57
|
+
- **No bun.**
|
|
58
|
+
- A default v10 selection without bun prints one notice line ("v10 needs bun; running the legacy engine. Set LOKI_ENGINE=legacy to silence") and falls through to legacy.
|
|
59
|
+
- An explicit `LOKI_ENGINE=v10` without bun still exits 1, as today.
|
|
60
|
+
- **Help after the flip.** `loki`, `loki --help` and `loki -h` go to the engine10 USAGE. USAGE ends with `loki legacy <args> run the previous engine (deprecated)`. `--version` stays on the legacy route.
|
|
61
|
+
- **Commands that change meaning.** `status`, `verify` and `dashboard` now mean the v10 commands. The legacy ones are reached through `loki legacy status` and so on.
|
|
62
|
+
- **Wall:** `bash tests/test-engine10-default.sh && bash tests/test-engine10-legacy-contract.sh && bash tests/test-engine10-dispatch.sh`. The output must show 0 failed for all three, and "0 skipped" on the legacy-contract Results line.
|
|
63
|
+
- **Red:** the default test fails because nothing flips the default, and the legacy contract reports 20 SKIP lines.
|
|
64
|
+
- **Green:**
|
|
65
|
+
- With `LOKI_ENGINE` unset, a task routes to engine10.
|
|
66
|
+
- `LOKI_ENGINE=legacy` and `loki legacy <args>` each match all 20 golden routes.
|
|
67
|
+
- `LOKI_LEGACY_BASH` wins.
|
|
68
|
+
- With no bun, the default falls back with a notice and explicit v10 exits 1.
|
|
69
|
+
- `LOKI_ENGINE=legasy` exits 2.
|
|
70
|
+
- `grep -c '_loki_engine_default=' bin/loki` equals 1.
|
|
71
|
+
- Planting a METRICS.md without the met marker turns the default test red.
|
|
72
|
+
- **Deps:** E-30, E-32, E-33, E-34, E-35, E-38, EV-6.
|
|
73
|
+
|
|
74
|
+
### E-32: Packaging, so the engine runs from dist and the npm package
|
|
75
|
+
- **Files:**
|
|
76
|
+
- `loki-ts/src/engine10/registry.ts` (new)
|
|
77
|
+
- `loki-ts/src/cli.ts` (inside the existing engine10 arm only)
|
|
78
|
+
- `loki-ts/src/engine10/machine.ts`
|
|
79
|
+
- `loki-ts/src/engine10/session.ts`
|
|
80
|
+
- `loki-ts/src/engine10/output.ts`
|
|
81
|
+
- `loki-ts/src/engine10/fetch_issue.ts`
|
|
82
|
+
- `loki-ts/src/engine10/stages/pr.ts`
|
|
83
|
+
- `loki-ts/tests/engine10/registry.test.ts` (new)
|
|
84
|
+
- `tests/test-engine10-dist.sh` (new)
|
|
85
|
+
- **Tier:** HIGH. It changes how provider sessions spawn and the path to the credentialed push child.
|
|
86
|
+
- **Contents:**
|
|
87
|
+
- **Registry.** `registry.ts` maps each stage and route module name to a literal lazy import, for example `wall: () => import("./stages/wall.ts")`. Only modules present on disk at build time are listed. Bun bundles literal imports, and loading stays lazy.
|
|
88
|
+
- **Loaders.**
|
|
89
|
+
- `machine.ts` `defaultLoader` and `output.ts`'s eta load go through the registry.
|
|
90
|
+
- The `src/cli.ts` arm passes the registry loader to `runEngine10(rest, load)`. The string `engine10` stays inside that one arm, which `cli.test.ts` asserts.
|
|
91
|
+
- `optional()` stays as the source fallback.
|
|
92
|
+
- **Session child.** `session.ts` spawns the child as `[process.execPath, <bundle or src cli entry>, "engine10", "session"]`, using the `session` route that already exists in the TABLE, instead of `import.meta.path`.
|
|
93
|
+
- **Paths.** `fetch_issue.ts` and `pr.ts` resolve `autonomy/issue-providers.sh` and `autonomy/lib/engine10-push.sh` from `REPO_ROOT` (`util/paths.ts`).
|
|
94
|
+
- **Registration guard.** `registry.test.ts` fails when a module that the stage table or cli TABLE names exists on disk but is not registered. Slices that land after E-32 (wave 2 still building, E-24..E-29) are each one registry line, which the Captain adds at merge.
|
|
95
|
+
- **No writes to `loki-ts/dist/`** (section 14).
|
|
96
|
+
- **The dist test:**
|
|
97
|
+
1. `npm pack` into a temp dir and extract it. The result has no `loki-ts/src`.
|
|
98
|
+
2. `bun build` the current src into `<extract>/loki-ts/dist/loki.js`, simulating the Captain's rebuild.
|
|
99
|
+
3. Run `<extract>/bin/loki` with `LOKI_ENGINE=v10 LOKI_E10_INVOKER=cli LOKI_CLAUDE_CLI=<E-14 stub>` on a copy of the E-14 fixture with `--no-pr`.
|
|
100
|
+
4. Separately, `npm pack --dry-run --json` must list `autonomy/lib/engine10-push.sh`, `autonomy/receipt_jwt.py` and `loki-ts/dist/loki.js`.
|
|
101
|
+
- **Wall:** `bash tests/test-engine10-dist.sh && (cd loki-ts && bun test tests/engine10/registry.test.ts)`.
|
|
102
|
+
- **Red:** the same script on current main shows every stage `stage.skipped` with "module not present", and the session child never starts.
|
|
103
|
+
- **Green:**
|
|
104
|
+
- `events.jsonl` from the extracted package holds `stage.completed` for intake, implement, verify and seal.
|
|
105
|
+
- There are 0 "module not present" skips for landed modules.
|
|
106
|
+
- `receipt.json`, `.loki/engine.json` and an efficiency record exist.
|
|
107
|
+
- The dry-run list contains the three files.
|
|
108
|
+
- **Deps:** E-14, E-TG.
|
|
109
|
+
|
|
110
|
+
### E-33: gate report generator (EV-6)
|
|
111
|
+
- **Files:** `eval/loki10/gate_report.py` (new), `eval/loki10/test-gate-report.sh` (new), `eval/loki10/fixtures/gate/` (new subdir).
|
|
112
|
+
- **Tier:** HIGH. Its marker controls E-31.
|
|
113
|
+
- **Contents:**
|
|
114
|
+
- **Invocation:** `gate_report.py <results.jsonl> --metrics <path> --changelog <path>`. It reuses `harness.summarize_rows`.
|
|
115
|
+
- **Output:**
|
|
116
|
+
- a per-arm table (completed/evaluated, rate, p50 and p90 time to PR, cost per completed task, runs with measured cost);
|
|
117
|
+
- four gate lines, each showing the measured number, the threshold and MET or MISSED;
|
|
118
|
+
- every miss, as task id plus status or reason;
|
|
119
|
+
- null cost rendered as "not measured".
|
|
120
|
+
- **`met` requires all of:**
|
|
121
|
+
- at least 25 evaluated tasks on each arm;
|
|
122
|
+
- the same `model` on every row;
|
|
123
|
+
- v10 completion at or above raw-claude;
|
|
124
|
+
- v10 p50 of 300s or less and p90 of 600s or less;
|
|
125
|
+
- measured cost on both arms, with v10 cost per completed task at or below raw-claude. Null cost counts as MISSED.
|
|
126
|
+
- **Markers:** it writes `<!-- loki10-gate: met|missed n=<N> results_sha256=<sha> -->` and replaces the block between `<!-- loki10-gate:begin -->` and `<!-- loki10-gate:end -->` in both target files, so rerunning is idempotent.
|
|
127
|
+
- **Who writes the real files:** EV-6 runs this on real results and commits METRICS.md and the CHANGELOG block. This slice never touches `summarize` or METRICS.md.
|
|
128
|
+
- **Wall:** `bash eval/loki10/test-gate-report.sh`.
|
|
129
|
+
- **Red:** the file is missing.
|
|
130
|
+
- **Green:**
|
|
131
|
+
- An all-met fixture writes the met marker.
|
|
132
|
+
- A v10 p90 of 660s gives MISSED and lists the slow tasks.
|
|
133
|
+
- Null v10 cost gives MISSED with "not measured".
|
|
134
|
+
- 24 evaluated tasks gives MISSED with "fewer than 25".
|
|
135
|
+
- A model mismatch gives MISSED.
|
|
136
|
+
- A second run leaves exactly one block.
|
|
137
|
+
- **Deps:** EV-1.
|
|
138
|
+
|
|
139
|
+
### E-34: v10 user docs, marked opt-in until the flip
|
|
140
|
+
- **Files:** `README.md` (new quickstart section), `docs/v10/GUIDE.md` (new), `tests/test-engine10-docs.sh` (new).
|
|
141
|
+
- **Tier:** LOW.
|
|
142
|
+
- **Contents:**
|
|
143
|
+
- **Quickstart:** `LOKI_ENGINE=v10 loki "<task>"`, issue refs, and `--no-pr`, `--deep`, and `--provider`.
|
|
144
|
+
- **The 5-line summary,** explained line by line.
|
|
145
|
+
- **NOT PROVEN:** what it means, including the deep checks that are always listed and "not measured" cost.
|
|
146
|
+
- **Receipts:** `receipt.json` and `receipt.md`, `loki verify`, and UNSIGNED.
|
|
147
|
+
- **Provider table:** claude cost is measured. For codex, cline and aider, cost is not measured and kill blocking is not enforced. opencode is not supported and is refused.
|
|
148
|
+
- **After the flip:** `status`, `verify` and `dashboard` change meaning. `loki legacy <args>` and `LOKI_ENGINE=legacy` reach the old engine.
|
|
149
|
+
- **The opt-in line:** one line in each file carries `<!-- loki10-default -->` and reads "Opt-in: set LOKI_ENGINE=v10". E-31 changes that line.
|
|
150
|
+
- **Wall:** `bash tests/test-engine10-docs.sh`.
|
|
151
|
+
- **Red:** GUIDE.md is missing.
|
|
152
|
+
- **Green:**
|
|
153
|
+
- Every command in the guide appears in the engine10 USAGE.
|
|
154
|
+
- The marked line's wording matches bin/loki's current default.
|
|
155
|
+
- README links GUIDE.md.
|
|
156
|
+
- The docs contain no em or en dashes.
|
|
157
|
+
- **Deps:** E-13, E-22.
|
|
158
|
+
|
|
159
|
+
### E-35: Legacy deprecation note, with no removal
|
|
160
|
+
- **Files:** `autonomy/lib/engine10-legacy-notice.txt` (new), `CHANGELOG.md` (a "Deprecated" entry for v10.0.0), `tests/test-engine10-legacy-notice.sh` (new).
|
|
161
|
+
- **Tier:** LOW.
|
|
162
|
+
- **Contents:**
|
|
163
|
+
- The notice runs three lines or fewer. It says the legacy engine is deprecated in v10.0.0 and still fully supported, that nothing is removed in this release, that `LOKI_ENGINE=legacy` pins it, and where the guide lives.
|
|
164
|
+
- The notice avoids `autonomy/loki`, which is on the no-edit list. E-31's `legacy)` arm prints the file for help invocations only.
|
|
165
|
+
- The CHANGELOG entry states the same facts and says no removal date is set.
|
|
166
|
+
- **Wall:** `bash tests/test-engine10-legacy-notice.sh`.
|
|
167
|
+
- **Red:** the file is missing.
|
|
168
|
+
- **Green:**
|
|
169
|
+
- The notice exists and has 3 lines or fewer.
|
|
170
|
+
- It contains "LOKI_ENGINE=legacy" and does not contain "removed in".
|
|
171
|
+
- The CHANGELOG has a Deprecated entry that names `loki legacy`.
|
|
172
|
+
- Once E-31 is present, `loki legacy --help` stderr contains the first notice line. Until then that assertion prints SKIP.
|
|
173
|
+
- **Deps:** none (the file must exist before E-31 merges).
|
|
174
|
+
|
|
175
|
+
### E-36: First-run preflight with clear errors
|
|
176
|
+
- **Files:** `loki-ts/src/engine10/preflight.ts` (new), `loki-ts/tests/engine10/preflight.test.ts` (new), `loki-ts/src/engine10/supervisor.ts` (one call at the start of `main`, before the marker or branch).
|
|
177
|
+
- **Tier:** MEDIUM.
|
|
178
|
+
- **Checks:** each failure prints one line with a fix hint and exits 2 before any branch or event log exists.
|
|
179
|
+
- **Not a repo:** the current directory is not a git work tree.
|
|
180
|
+
- **Git identity:** `user.name` or `user.email` is unset, which would make the commit fail.
|
|
181
|
+
- **Provider CLI:** the provider's CLI is not on PATH (`LOKI_CLAUDE_CLI`, `LOKI_CODEX_CLI` and so on are honored).
|
|
182
|
+
- **Unsupported provider:** `--provider opencode`, or any other unknown name, gets: "the v10 engine has no opencode invoker yet; use LOKI_ENGINE=legacy loki start --provider opencode".
|
|
183
|
+
- **Host guard:** an inherited `LOKI_HOST_GUARD=1` with a non-claude provider would throw at `providers.ts:63`, so preflight explains it first.
|
|
184
|
+
- **GitHub CLI:** when origin is on github.com and `--no-pr` is absent, missing `gh` or a failing `gh auth status` gets a hint to use `--no-pr`. A non-GitHub origin or `--no-pr` skips the check, so the eval's local bare remote is unaffected.
|
|
185
|
+
- **Warnings (not fatal):** `python3 -I` without `cryptography`, or no signing key, prints "receipts will be UNSIGNED".
|
|
186
|
+
- **bun:** bin/loki already checks for bun.
|
|
187
|
+
- **Wall:** `cd loki-ts && bun test tests/engine10/preflight.test.ts`.
|
|
188
|
+
- **Red:** the file is missing.
|
|
189
|
+
- **Green:**
|
|
190
|
+
- Each fatal case gives exit 2, its exact line, and no `.loki/runs` dir.
|
|
191
|
+
- Missing cryptography warns and continues.
|
|
192
|
+
- `--no-pr` skips the gh check.
|
|
193
|
+
- **Deps:** E-14.
|
|
194
|
+
|
|
195
|
+
### E-37: Non-claude provider paths through session.ts, with honest cost
|
|
196
|
+
- **Files:** `loki-ts/tests/engine10/providers.test.ts` (new), `loki-ts/tests/engine10/fixtures/providers/` (new: stub codex, cline and aider CLIs).
|
|
197
|
+
- **Tier:** MEDIUM.
|
|
198
|
+
- **Contents:**
|
|
199
|
+
- Runs the supervisor end to end with `--provider codex`, `cline` and `aider` through their stubs (`LOKI_CODEX_CLI`, `LOKI_CLINE_CLI`, `LOKI_AIDER_CLI`) and `--no-pr`.
|
|
200
|
+
- This slice has no source files. Any red it finds becomes its own fix slice.
|
|
201
|
+
- **Wall:** `cd loki-ts && bun test tests/engine10/providers.test.ts`.
|
|
202
|
+
- **Red:** the file is missing.
|
|
203
|
+
- **Green, for each non-claude provider:**
|
|
204
|
+
- The run reaches seal.
|
|
205
|
+
- The `cost` event has `usd: null` with tokens kept.
|
|
206
|
+
- `cost-summary.py --json` reports `fully_measured` false.
|
|
207
|
+
- The Cost line reads "not measured" and never "$0.00".
|
|
208
|
+
- The receipt's `not_proven` holds "kill blocking not enforced".
|
|
209
|
+
- With `LOKI_MODEL_OVERRIDE` set, it also holds "model override not applied".
|
|
210
|
+
- The session child env has no `LOKI_HOST_GUARD`.
|
|
211
|
+
- `--provider opencode` exits 2 with the E-36 line.
|
|
212
|
+
- **Deps:** E-14, E-36.
|
|
213
|
+
|
|
214
|
+
### E-38: v10 arm gate run, with the legacy arm pinned
|
|
215
|
+
- **Files:** `eval/loki10/harness.py` (the legacy arm sets `env["LOKI_ENGINE"]="legacy"`), `eval/loki10/test-harness.sh` (one new leg).
|
|
216
|
+
- **Tier:** HIGH.
|
|
217
|
+
- **Contents:**
|
|
218
|
+
- Pinning the legacy arm keeps EV-5 results unchanged after the flip.
|
|
219
|
+
- The v10 arm runs `--all` over the 29 tasks using the dist build from E-32 (`LOKI_TS_ENTRY` pointing at the rebuilt bundle), so the gate measures what ships.
|
|
220
|
+
- Results stay under the gitignored `eval/loki10/results/`.
|
|
221
|
+
- **Wall:** `bash eval/loki10/test-harness.sh && eval/loki10/run.sh --arm v10 --all`. The results must hold 29 rows, none `arm_unavailable`, and each row must carry `model`, `time_to_pr_s` and `cost_usd` (a number or null).
|
|
222
|
+
- **Red:** the new leg fails because the legacy arm env has no `LOKI_ENGINE`, and no v10 results exist.
|
|
223
|
+
- **Green:** the leg asserts `LOKI_ENGINE=legacy` on the legacy arm and `v10` on the v10 arm, and the 29-row v10 results file exists.
|
|
224
|
+
- **Deps:** EV-1, E-32, E-36.
|
|
225
|
+
|
|
226
|
+
### E-39: Interrupt end to end (resume removed in A-113)
|
|
227
|
+
- **Files:** `loki-ts/tests/engine10/resume_e2e.test.ts` (new), `loki-ts/tests/engine10/fixtures/resume/` (new).
|
|
228
|
+
- **Tier:** MEDIUM.
|
|
229
|
+
- **Wall:** `cd loki-ts && bun test tests/engine10/resume_e2e.test.ts`.
|
|
230
|
+
- **Red:** the file is missing.
|
|
231
|
+
- **Green:**
|
|
232
|
+
- SIGINT during a sleeping implement stub exits 130. The session process group is gone and there is no `run.completed`.
|
|
233
|
+
- (Removed in A-113: `--resume` no longer exists; `loki --resume` exits 2 with "start a new run".)
|
|
234
|
+
- `seq` keeps increasing, and there is no second `stage.started` for intake.
|
|
235
|
+
- `.loki/engine.json` still names the same run.
|
|
236
|
+
- Changing the origin between runs refuses the push.
|
|
237
|
+
- **Deps:** E-14.
|
|
238
|
+
|
|
239
|
+
### E-40: Live PR smoke on a sandbox GitHub repo
|
|
240
|
+
- **Files:** `tests/test-engine10-live-pr.sh` (new).
|
|
241
|
+
- **Tier:** HIGH (credentialed).
|
|
242
|
+
- **Contents:**
|
|
243
|
+
- Runs one real small task from the E-32 dist layout against `LOKI_E10_LIVE_REPO`.
|
|
244
|
+
- Without the variable it prints SKIP and exits 0. SKIP never counts as done; the Wall command sets the variable.
|
|
245
|
+
- **Wall:** `LOKI_E10_LIVE_REPO=<owner>/<sandbox> bash tests/test-engine10-live-pr.sh`. The output must show:
|
|
246
|
+
- a PR URL;
|
|
247
|
+
- `gh pr view --json isDraft` agreeing with the verdict;
|
|
248
|
+
- the `loki/deep-verify` status context through `gh api`;
|
|
249
|
+
- `loki verify <run>` exiting 0, or UNSIGNED stated;
|
|
250
|
+
- a second run of the same task reporting `existing: true` with the same URL.
|
|
251
|
+
- **Red:** the file is missing.
|
|
252
|
+
- **Green:** all five assertions hold against the sandbox repo.
|
|
253
|
+
- **Deps:** E-23, E-32, E-36.
|
|
254
|
+
|
|
255
|
+
### Recovery of an interrupted run
|
|
256
|
+
|
|
257
|
+
Code: `resumeMain`, `findInterrupted`, `resumePublish`, `startRecovery` in `loki-ts/src/util/run_outputs.ts`, `phaseOf` in `events.ts`, `runOwnerAlive` in `util/run_pid.ts`, the push-skip in `autonomy/lib/engine10-push.sh`, `loki resume` in `autonomy/loki`. Tests: the RECOVERY block in `loki-ts/tests/engine10/pr.test.ts` and the recovery block in `tests/test-engine10-push.sh`.
|
|
258
|
+
|
|
259
|
+
An interrupted run has an `events.jsonl` with neither `run.completed` nor `pr.opened`, and a `run.pid` that does not name a live process with the recorded start time. A run owned by a live supervisor is never resumed. The phase comes from the event log only (`phaseOf`):
|
|
260
|
+
|
|
261
|
+
| Phase | Meaning | Recoverable |
|
|
262
|
+
|-----------|-------------------------------------------------------------|-------------|
|
|
263
|
+
| implement | no `stage.completed` for implement | No (reported) |
|
|
264
|
+
| verify | implement completed, no `receipt.sealed` | No (reported) |
|
|
265
|
+
| publish | `receipt.sealed` present, no `pr.opened` or `run.completed` | Yes |
|
|
266
|
+
| done | `pr.opened` or `run.completed` present | Nothing to do |
|
|
267
|
+
|
|
268
|
+
`loki resume [run-id]`, and `loki start "<same task>"` when the newest interrupted run is in the publish phase, its recorded intake task equals the new task and `--no-pr` is absent, resume the publish phase and print `resumed phase: publish (run <id>); receipt reused; PR <url>`.
|
|
269
|
+
|
|
270
|
+
- The sealed receipt is reused: no second `receipt.json`, no second `receipt.sealed` event. Resume never reseals.
|
|
271
|
+
- Events appended: `run.resumed`, `pr.opened`, `run.completed` (with `resumed: true` and the not-proven note "publish phase resumed after an interruption"), then the log seal.
|
|
272
|
+
- Push is skipped when the remote branch is already at the local commit (GitHub: `gh api .../git/ref/heads/<branch>`; local bare origin: `git ls-remote`). A newer commit is a new revision and is pushed.
|
|
273
|
+
- PR creation checks `gh pr list --head <branch> --state open` first and reuses an open PR, so any number of publish attempts yields one PR.
|
|
274
|
+
|
|
275
|
+
For implement and verify, `loki resume` prints the phase, whether branch `loki/<run-id>` holds preserved work, and exits 4. `loki start` prints a one-line note and starts a new run. `LOKI_NO_RESUME=1` disables the `loki start` check.
|
|
276
|
+
|
|
277
|
+
Exit codes of `loki-ts engine10 resume`: 0 resumed, 3 no interrupted run, 4 phase reported but not auto-resumable, 5 publish attempted and failed (the run stays resumable), 2 not in a git repository or no origin.
|
|
278
|
+
|
|
279
|
+
Honest limits:
|
|
280
|
+
- implement and verify keep stage outputs in the worker's memory; the stage machine cannot skip completed stages. Work committed on `loki/<run-id>` is preserved but the run is not continued.
|
|
281
|
+
- A crash between `gh pr create` returning and `pr.opened` being recorded is recovered by the open-PR lookup, provided GitHub lists the PR by then.
|
|
282
|
+
- A crash after the commit status call but before `run.completed` sets the same status again.
|
|
283
|
+
- GitLab origins (`engine10-push-gitlab.sh`) are unchanged; push-skip and PR reuse are verified for the GitHub and local-bare paths only.
|
|
284
|
+
- The legacy bash loop (`autonomy/run.sh`) keeps its own iteration-level resume.
|
|
285
|
+
- Deep verify (a detached child spawned after `pr.opened`) is not re-spawned on resume.
|
|
286
|
+
|
|
287
|
+
### BOARD rows
|
|
288
|
+
|
|
289
|
+
The notes start with the requested "Source: ENGINE.md 23:00Z cut." and then add dependencies, following the 21:50Z rows. If you want the notes to be only that sentence, drop the dependency part.
|
|
290
|
+
|
|
291
|
+
| id | title | files | tier | wall check | status | notes |
|
|
292
|
+
|---|---|---|---|---|---|---|
|
|
293
|
+
| E-31 | Default flip to v10 with LOKI_ENGINE=legacy override and the loki legacy alias (merge held until the gate marker reads met) | bin/loki, loki-ts/src/engine10/cli.ts (USAGE only), tests/test-engine10-default.sh, tests/test-engine10-dispatch.sh, tests/test-engine10-legacy-contract.sh, README.md and docs/v10/GUIDE.md (marked opt-in line only, after E-34) | HIGH | bash tests/test-engine10-default.sh && bash tests/test-engine10-legacy-contract.sh && bash tests/test-engine10-dispatch.sh (0 failed; legacy contract 0 skipped) | ready@2026-09-27T23:00Z | Source: ENGINE.md 23:00Z cut. Held at approved until the METRICS.md loki10-gate marker reads met; parked if not met by 03:00Z. Depends on E-30, E-32, E-33, E-34, E-35, E-38, EV-6. |
|
|
294
|
+
| E-32 | Packaging: engine runs from dist and the npm package (static registry, session child via cli route, REPO_ROOT paths) | loki-ts/src/engine10/registry.ts, loki-ts/src/cli.ts (engine10 arm only), loki-ts/src/engine10/machine.ts, loki-ts/src/engine10/session.ts, loki-ts/src/engine10/output.ts, loki-ts/src/engine10/fetch_issue.ts, loki-ts/src/engine10/stages/pr.ts, loki-ts/tests/engine10/registry.test.ts, tests/test-engine10-dist.sh | HIGH | bash tests/test-engine10-dist.sh && (cd loki-ts && bun test tests/engine10/registry.test.ts) | ready@2026-09-27T23:00Z | Source: ENGINE.md 23:00Z cut. Later engine slices add one registry line at merge. Depends on E-14, E-TG. |
|
|
295
|
+
| E-33 | Gate report generator: METRICS.md and CHANGELOG blocks with every gate number, misses and the loki10-gate marker | eval/loki10/gate_report.py, eval/loki10/test-gate-report.sh, eval/loki10/fixtures/gate/ | HIGH | bash eval/loki10/test-gate-report.sh | ready@2026-09-27T23:00Z | Source: ENGINE.md 23:00Z cut. EV-6 runs it on real results and commits METRICS.md. Depends on EV-1. |
|
|
296
|
+
| E-34 | v10 user docs: README quickstart and docs/v10/GUIDE.md (5-line summary, NOT PROVEN, receipts), opt-in until the flip | README.md, docs/v10/GUIDE.md, tests/test-engine10-docs.sh | LOW | bash tests/test-engine10-docs.sh | ready@2026-09-27T23:00Z | Source: ENGINE.md 23:00Z cut. Depends on E-13, E-22. |
|
|
297
|
+
| E-35 | Legacy engine deprecation note for loki legacy help and CHANGELOG (no removal) | autonomy/lib/engine10-legacy-notice.txt, CHANGELOG.md, tests/test-engine10-legacy-notice.sh | LOW | bash tests/test-engine10-legacy-notice.sh | ready@2026-09-27T23:00Z | Source: ENGINE.md 23:00Z cut. Depends on none; lands before E-31. |
|
|
298
|
+
| E-36 | First-run preflight: repo, git identity, provider CLI, opencode refusal, host guard, gh auth, UNSIGNED warning | loki-ts/src/engine10/preflight.ts, loki-ts/tests/engine10/preflight.test.ts, loki-ts/src/engine10/supervisor.ts (one call in main) | MEDIUM | cd loki-ts && bun test tests/engine10/preflight.test.ts | ready@2026-09-27T23:00Z | Source: ENGINE.md 23:00Z cut. Depends on E-14. |
|
|
299
|
+
| E-37 | Non-claude provider paths (codex, cline, aider) through session.ts with cost not measured and NOT PROVEN entries | loki-ts/tests/engine10/providers.test.ts, loki-ts/tests/engine10/fixtures/providers/ | MEDIUM | cd loki-ts && bun test tests/engine10/providers.test.ts | ready@2026-09-27T23:00Z | Source: ENGINE.md 23:00Z cut. Test only; a red becomes its own slice. Depends on E-14, E-36. |
|
|
300
|
+
| E-38 | v10 arm gate run over the 29 tasks from dist; legacy arm pinned to LOKI_ENGINE=legacy | eval/loki10/harness.py (legacy arm env), eval/loki10/test-harness.sh (one leg) | HIGH | bash eval/loki10/test-harness.sh && eval/loki10/run.sh --arm v10 --all (29 rows, none arm_unavailable) | ready@2026-09-27T23:00Z | Source: ENGINE.md 23:00Z cut. The missing third arm for the gate. Depends on EV-1, E-32, E-36. |
|
|
301
|
+
| E-39 | Interrupt and resume end to end (SIGINT, no orphan, resume to seal on the same run) | loki-ts/tests/engine10/resume_e2e.test.ts, loki-ts/tests/engine10/fixtures/resume/ | MEDIUM | cd loki-ts && bun test tests/engine10/resume_e2e.test.ts | ready@2026-09-27T23:00Z | Source: ENGINE.md 23:00Z cut. Depends on E-14. |
|
|
302
|
+
| E-40 | Live PR smoke on a sandbox GitHub repo from the dist layout | tests/test-engine10-live-pr.sh | HIGH | LOKI_E10_LIVE_REPO=<owner>/<sandbox> bash tests/test-engine10-live-pr.sh | ready@2026-09-27T23:00Z | Source: ENGINE.md 23:00Z cut. SKIP without the variable does not count as done. Depends on E-23, E-32, E-36. |
|
|
303
|
+
|
|
304
|
+
**Critical path to the flip:** E-14 and E-TG → E-32 → E-36 → E-38 → EV-6 (runs E-33) → E-31. E-34 and E-35 must merge before E-31. E-37, E-39 and E-40 can run in parallel once their dependencies land.
|
|
305
|
+
|
|
306
|
+
|
|
3
307
|
## 20:59Z cut (S-214..S-233)
|
|
4
308
|
|
|
5
309
|
**Checked before cutting.** All reads are on main at 04af133a.
|
package/docs/v10/DECISIONS.md
CHANGED
|
@@ -176,7 +176,7 @@ One entry per decision: context, choice, why, how to reverse. Newest last.
|
|
|
176
176
|
- Reverse: never skip the pre-push gate under any circumstance, even for a confirmed pre-existing failure; investigate and fix BACKLOG 21 first. Not chosen now because BACKLOG 21 is explicitly host-environment-scoped (macOS 27 seatbelt behavior), out of scope for this turn's release-blocking work, and already tracked with its own backlog entry for a dedicated investigation.
|
|
177
177
|
- **Resolved 2026-09-27 (S-61, merged 46bd86a1):** the dedicated investigation this decision promised found a genuine root cause, not a platform-unfixable gap. On macOS 27.0, `sandbox-exec`'s `(deny network-bind (local tcp "*:PORT"))` silently fails to match an actual bind (the confined process could bind the "denied" port); `tcp4` denies it correctly. Verified via direct `sandbox-exec` reproduction outside the test/Python entirely, ruled out rule-ordering as a cause, and confirmed the real production gate (`smoke_probe_host_seatbelt`) already failed CLOSED before this fix -- it correctly refused to advertise confinement rather than silently exposing a hole, so this was an availability/test-accuracy bug, not a live security exposure. 37/37 tests in the file pass post-fix; the specific test used as this decision's basis now genuinely passes. This retires the D24 skip pattern going forward -- a future recurrence of this exact test failing would be a new regression, not the same accepted pre-existing gap, and should be investigated fresh rather than reflexively skipped under this same D24 precedent.
|
|
178
178
|
|
|
179
|
-
## D25. 2026-09-27: founder directive -- release-train model replaces push-per-merge, first train ships without waiting on S-18
|
|
179
|
+
## D25. 2026-09-27: founder directive -- release-train model replaces push-per-merge, first train ships without waiting on S-18 (SUPERSEDED by D96: every approved slice is a release; no trains, no batching. The Train cycle script scripts/train-cycle.sh stays live)
|
|
180
180
|
|
|
181
181
|
- Context: the founder identified, correctly, that the swarm's own operating pattern (push to main roughly every 20 minutes, `cancel-in-progress: true` on the Tests workflow, a 26-34 minute real Tests runtime) was self-inflicted CI churn: 10 of the last 12 Tests runs were cancelled by the swarm's own subsequent pushes landing mid-run, not by any real code defect. Only 2 releases shipped in 24h against 139 unreleased commits. This independently confirms and generalizes what this session's own drift audits (turns 102, 120, 132, 138, 144) had already been finding piecemeal (each individual cancellation investigated and disclosed, but never addressed at the systemic level: the push cadence itself).
|
|
182
182
|
- Choice, per the founder's explicit directive, six parts:
|
|
@@ -418,7 +418,7 @@ Loki's definition: "autonomous software factory that runs with the knowledge of
|
|
|
418
418
|
|
|
419
419
|
## D52 (founder, relayed 03:25Z) and overnight mandate (03:40Z): least tokens, fastest release
|
|
420
420
|
1. Target about 10x less plan usage per merged slice and per release, measured from `claude -p "/usage"`. Haiku for mechanical work, sonnet to build, opus only for moat or latest-moving reviews; `model:` set explicitly on every agent; small briefs with file paths; read line ranges, not whole files; agent returns of 10 lines or fewer; fresh agent per slice; the lead session hands off at about 120k context.
|
|
421
|
-
2. Overnight until about 11:00Z: sprint to 04:35Z, then pace (D39 amendment). Priority: release flow, D48 rows plus the 04:35Z report, D51 Phase A ready to test (LOKI MORNING TEST in PROGRESS), D50 lift baseline then harness slices, docs, then D51 Phase B/C as budget allows.
|
|
421
|
+
2. Overnight until about 11:00Z: sprint to 04:35Z, then pace (D39 amendment). Priority: release flow, D48 rows plus the 04:35Z report, D51 Phase A ready to test (LOKI MORNING TEST in PROGRESS), D50 lift baseline then harness slices, docs, then D51 Phase B/C as budget allows. a morning brief (60 lines or fewer, since removed) at 10:30Z, honest about what is not done.
|
|
422
422
|
|
|
423
423
|
## D53 (founder delegation "do what's best, don't ask me anything", ruled by autonomi-dev-dc, relayed 12:39Z; reversible): spec-required test updates
|
|
424
424
|
1. An existing assertion may be changed, and the run may be VERIFIED, only when all of these hold, each checked deterministically (never by model judgement): (a) the new expected value appears verbatim as a string or number literal in the task, issue or spec text; (b) the edit changes only that literal in an existing assertion, with no assertion removed, no skip, xfail or .only added, no tolerance or comparator loosened and no other line changed (the D50-F2r classifier decides; any doubt means weakened); (c) the Wall checks, written without the implementation, and the project's other tests pass.
|
|
@@ -481,10 +481,10 @@ Loki's definition: "autonomous software factory that runs with the knowledge of
|
|
|
481
481
|
4. D57 Wave 2 deletions continue only as part of basic 1.
|
|
482
482
|
|
|
483
483
|
## D59: two-hour finish, then stop until next week (founder, 2026-10-01 18:10Z, override 18:14Z)
|
|
484
|
-
Founder: "complete all loki mode work faster ... everything complete in two hours with least tokens used and highest code push and releases ... even if means no testing". Override given directly at 18:14Z: until 20:10Z, merge and release without waiting for Tests, Bun Parity, Coverage or Security Audit. Kept: rollback of `latest` by dist-tag if Post-Release Smoke shows `npm i -g loki-mode` or `loki --version` broken. Each release's CI result is recorded in docs/v10/
|
|
484
|
+
Founder: "complete all loki mode work faster ... everything complete in two hours with least tokens used and highest code push and releases ... even if means no testing". Override given directly at 18:14Z: until 20:10Z, merge and release without waiting for Tests, Bun Parity, Coverage or Security Audit. Kept: rollback of `latest` by dist-tag if Post-Release Smoke shows `npm i -g loki-mode` or `loki --version` broken. Each release's CI result is recorded in docs/v10/PROGRESS.md (section 'Release CI results, 10.6.x'). Order: 10.6.0, W1-ROUTE, D58-SCOPE, LEAK3, CP-RELAND, D57 W1 docs, one real-repo gate run against latest. Target 19:15Z, hard stop 20:10Z, then no agents, loops or crons until next week. Workflow-level gates (release.yml required-ci, pre-push secret scan) are not edited.
|
|
485
485
|
|
|
486
486
|
## D60: one-hour user-impact sprint (founder via the autonomi-dev session, 2026-10-02 22:45Z)
|
|
487
|
-
Ends the D59 pause early for this sprint only. Five slices, released as soon as each is green: (1) `loki start` runs Loki 10, after porting moat P9 to the v10 issue path and re-landing b2e3afc43; (2) the dashboard opens the port it bound (LEAK3, with test-ui-bare-loki fixed); (3) an evidence-rich PR body (INTEL-3); (4) the shipped GitHub Action runs `loki owner/repo#N`, plus a documented nightly `loki backlog` cron; (5) a visible cost cap (INTEL-2) in the v10 start line. CI gates are unchanged: Tests, Bun Parity, Coverage and Security Audit must be green before a release, plus the two-leg promote. Anything red at about minute 50 is dropped. Report at minute 60, then stop per
|
|
487
|
+
Ends the D59 pause early for this sprint only. Five slices, released as soon as each is green: (1) `loki start` runs Loki 10, after porting moat P9 to the v10 issue path and re-landing b2e3afc43; (2) the dashboard opens the port it bound (LEAK3, with test-ui-bare-loki fixed); (3) an evidence-rich PR body (INTEL-3); (4) the shipped GitHub Action runs `loki owner/repo#N`, plus a documented nightly `loki backlog` cron; (5) a visible cost cap (INTEL-2) in the v10 start line. CI gates are unchanged: Tests, Bun Parity, Coverage and Security Audit must be green before a release, plus the two-leg promote. Anything red at about minute 50 is dropped. Report at minute 60, then stop per the D59 handoff (see docs/v10/PROGRESS.md).
|
|
488
488
|
|
|
489
489
|
## D61: speed for users (founder via the autonomi-dev session, 2026-10-02 22:50Z)
|
|
490
490
|
A product feature, not a build-process change: `loki "small task"` should finish in seconds, at or below raw Claude Code time and tokens. `loki "big task"` and `loki backlog` should decide by themselves whether the work splits, run the units in parallel worktrees on the user's machine, merge, test once and open one PR, using no more tokens than one sequential session, visible live and with no flags. Design only for now: docs/v10/D61-SPEED.md (an opus architect). Builders start after D60 and after the founder's go. Every target is measured on an eval arm and published in METRICS, losses included.
|
|
@@ -521,7 +521,7 @@ The D61 decomposer (125 lines) does not fit: engine10 core is at 4,993 of its 5,
|
|
|
521
521
|
- Goal: every D63 item released to npm latest with flags ON and documented. An item whose opus D12 review has not passed ships flags-off and is named in the handoff.
|
|
522
522
|
- The per-hour governor pace is lifted for 12 hours. The only usage floor is 85% of the week on live /usage (03:01Z reading: 46%). Builders scale with CI and machine load. train-cycle runs every 10 to 15 minutes; red slices are dropped, never held.
|
|
523
523
|
- Unchanged: CI gates (no waivers), no stored credentials read (real-model E2E legs stay parked), P9 rerun once in full with the new diagnostics, never added to pending.txt.
|
|
524
|
-
- Every release carries a CHANGELOG sentence, README and docs in the same slice, and a version report to the peer.
|
|
524
|
+
- Every release carries a CHANGELOG sentence, README and docs in the same slice, and a version report to the peer. a morning brief (since removed) is written at 14:30Z (60 lines max).
|
|
525
525
|
|
|
526
526
|
## D69: no founder waits (founder, about 03:05Z 2026-10-03, relayed by autonomi-dev-76)
|
|
527
527
|
- Founder's words: "lokimode session should never prompt me or wait for me for anything ... complete all work with chief of staff and software factory it is".
|