@synapsor/runner 1.6.2 → 1.6.4
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/AGENTS.md +2 -2
- package/CHANGELOG.md +141 -2
- package/CONTRIBUTING.md +10 -3
- package/README.md +65 -83
- package/SECURITY.md +14 -2
- package/THREAT_MODEL.md +64 -4
- package/dist/authoring.mjs +151 -16
- package/dist/cli.d.ts +31 -3
- package/dist/cli.d.ts.map +1 -1
- package/dist/local-ui.d.ts +145 -1
- package/dist/local-ui.d.ts.map +1 -1
- package/dist/runner.mjs +37488 -19009
- package/dist/runtime.mjs +4056 -235
- package/dist/shadow.mjs +2423 -65
- package/docs/README.md +36 -2
- package/docs/agent-guided-setup.md +239 -0
- package/docs/aggregate-reads.md +14 -5
- package/docs/app-owned-executors.md +5 -6
- package/docs/approval-roles-and-operator-identity.md +353 -0
- package/docs/auto-boundary-and-scoped-explore.md +89 -11
- package/docs/capability-authoring.md +21 -2
- package/docs/client-recipes.md +1 -1
- package/docs/cloud-mode.md +7 -7
- package/docs/conformance.md +6 -3
- package/docs/current-scope.md +32 -2
- package/docs/cursor-plugin.md +3 -3
- package/docs/database-enforced-scope.md +6 -0
- package/docs/dsl-json-parity.md +75 -0
- package/docs/dsl-reference.md +22 -1
- package/docs/fresh-developer-usability.md +155 -80
- package/docs/getting-started-own-database.md +45 -44
- package/docs/guarded-crud-writeback.md +19 -0
- package/docs/guided-onboarding.md +399 -0
- package/docs/human-attention-notifications.md +367 -0
- package/docs/limitations.md +49 -13
- package/docs/local-mode.md +36 -22
- package/docs/mcp-audit.md +14 -14
- package/docs/mcp-client-setup.md +11 -14
- package/docs/mcp-clients.md +1 -1
- package/docs/migrating-to-synapsor-spec.md +42 -0
- package/docs/openai-agents-sdk.md +2 -2
- package/docs/production.md +39 -0
- package/docs/proposal-evidence-freshness.md +7 -7
- package/docs/recipes.md +6 -6
- package/docs/release-notes.md +144 -4
- package/docs/release-policy.md +20 -7
- package/docs/reversible-change-sets.md +1 -1
- package/docs/reviewed-database-views.md +132 -0
- package/docs/reviewed-relationships.md +245 -0
- package/docs/rfcs/006-reviewed-reversible-change-sets.md +1 -1
- package/docs/runner-bundles.md +7 -7
- package/docs/runner-config-reference.md +132 -0
- package/docs/running-a-runner-fleet.md +16 -1
- package/docs/schema-api-candidates.md +1 -1
- package/docs/security-boundary.md +54 -0
- package/docs/store-lifecycle.md +20 -1
- package/docs/supervised-automatic-apply.md +267 -0
- package/docs/troubleshooting-first-run.md +85 -10
- package/docs/use-your-own-database.md +6 -4
- package/docs/workbench-ask.md +279 -0
- package/docs/writeback-executors.md +7 -7
- package/examples/auto-boundary-churn/README.md +1 -1
- package/examples/community-solar-clean-room/README.md +7 -0
- package/examples/community-solar-clean-room/docker-compose.yml +16 -0
- package/examples/community-solar-clean-room/package.json +15 -0
- package/examples/community-solar-clean-room/prisma/schema.prisma +171 -0
- package/examples/community-solar-clean-room/seed/postgres.sql +571 -0
- package/examples/fitflow-guided-onboarding/README.md +43 -0
- package/examples/fitflow-guided-onboarding/app/page.tsx +8 -0
- package/examples/fitflow-guided-onboarding/docker-compose.yml +16 -0
- package/examples/fitflow-guided-onboarding/package.json +18 -0
- package/examples/fitflow-guided-onboarding/prisma/schema.prisma +98 -0
- package/examples/fitflow-guided-onboarding/seed/postgres.sql +401 -0
- package/examples/openai-agents-http/Makefile +1 -1
- package/examples/openai-agents-http/README.md +1 -1
- package/examples/openai-agents-stdio/Makefile +1 -1
- package/examples/openai-agents-stdio/README.md +2 -2
- package/examples/openai-agents-stdio/agent.py +1 -4
- package/examples/operator-oidc/issuer.mjs +188 -0
- package/examples/reference-support-billing-app/README.md +16 -16
- package/examples/retail-clean-room/README.md +7 -0
- package/examples/retail-clean-room/docker-compose.yml +16 -0
- package/examples/retail-clean-room/package.json +9 -0
- package/examples/retail-clean-room/prisma/schema.prisma +239 -0
- package/examples/retail-clean-room/seed/postgres.sql +781 -0
- package/examples/retail-clean-room/view-recipe/average-retained-revenue.synapsor.sql +21 -0
- package/examples/retail-clean-room/view-recipe/synapsor.runner.json +25 -0
- package/examples/support-plan-credit/README.md +6 -2
- package/examples/support-plan-credit/mcp-client-examples/claude-code.sh +1 -4
- package/examples/support-plan-credit/mcp-client-examples/claude-desktop.json +1 -4
- package/examples/support-plan-credit/mcp-client-examples/codex.config.toml +1 -4
- package/examples/support-plan-credit/mcp-client-examples/cursor-global.mcp.json +1 -4
- package/examples/support-plan-credit/mcp-client-examples/cursor-project.mcp.json +1 -4
- package/examples/support-plan-credit/mcp-client-examples/generic-stdio.json +1 -4
- package/examples/support-plan-credit/mcp-client-examples/generic-stdio.mjs +1 -1
- package/examples/support-plan-credit/mcp-client-examples/google-adk.py +1 -1
- package/examples/support-plan-credit/mcp-client-examples/langchain.mjs +1 -1
- package/examples/support-plan-credit/mcp-client-examples/llamaindex.py +1 -1
- package/examples/support-plan-credit/mcp-client-examples/openai-agents-stdio.ts +1 -1
- package/examples/support-plan-credit/mcp-client-examples/vscode.mcp.json +1 -4
- package/fixtures/compatibility/published-1.6.3/manifest.json +76 -0
- package/fixtures/compatibility/published-1.6.3/sources/packages/dsl/examples/aggregate-read.synapsor.sql +21 -0
- package/fixtures/compatibility/published-1.6.3/sources/packages/dsl/examples/billing-late-fee.synapsor.sql +56 -0
- package/fixtures/compatibility/published-1.6.3/sources/packages/dsl/examples/bounded-set-multi-term.synapsor.sql +30 -0
- package/fixtures/compatibility/published-1.6.3/sources/packages/dsl/examples/principal-row-scope.synapsor.sql +23 -0
- package/fixtures/compatibility/published-1.6.3/sources/packages/spec/fixtures/conformance/aggregate-read/contract.json +119 -0
- package/fixtures/compatibility/published-1.6.3/sources/packages/spec/fixtures/conformance/approval-quorum/contract.json +44 -0
- package/fixtures/compatibility/published-1.6.3/sources/packages/spec/fixtures/conformance/bounded-set-threats/contract.json +115 -0
- package/fixtures/compatibility/published-1.6.3/sources/packages/spec/fixtures/conformance/principal-row-scope/contract.json +78 -0
- package/fixtures/compatibility/published-1.6.3/sources/packages/spec/fixtures/conformance/proposal-capability/contract.json +101 -0
- package/fixtures/compatibility/published-1.6.3/sources/packages/spec/fixtures/conformance/reversible-change-sets/contract.json +98 -0
- package/fixtures/compatibility/published-1.6.3/sources/packages/spec/fixtures/valid/basic-read.contract.json +60 -0
- package/llms.txt +10 -5
- package/package.json +11 -3
- package/schemas/schema-candidate-review.schema.json +42 -0
- package/schemas/synapsor.runner.schema.json +227 -4
|
@@ -0,0 +1,367 @@
|
|
|
1
|
+
# Human Attention And Notifications
|
|
2
|
+
|
|
3
|
+
Runner keeps the full lifecycle in its ledger and secured Workbench. External
|
|
4
|
+
notifications are a quiet interruption channel for meaningful human attention,
|
|
5
|
+
not a copy of every state transition.
|
|
6
|
+
|
|
7
|
+
Notifications are additive, local-first, and disabled by default. Runner needs
|
|
8
|
+
no webhook, network connection, Cloud account, or continuously running
|
|
9
|
+
dispatcher for its existing proposal, approval, apply, receipt, and replay
|
|
10
|
+
flows.
|
|
11
|
+
|
|
12
|
+
## Architecture
|
|
13
|
+
|
|
14
|
+
```text
|
|
15
|
+
authoritative ledger transition
|
|
16
|
+
-> immutable attention event in the same store transaction
|
|
17
|
+
-> coalesced Human Attention item
|
|
18
|
+
-> separately operated dispatcher
|
|
19
|
+
-> configured JSONL or signed webhook sink
|
|
20
|
+
-> authenticated human opens Workbench
|
|
21
|
+
-> existing approval/recovery control handles the item
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
An event informs. It never authorizes. A webhook response, delivery receipt,
|
|
25
|
+
inbox acknowledgement, or notification replay cannot activate a capability,
|
|
26
|
+
approve a proposal, apply a write, cancel work, or resolve an unknown database
|
|
27
|
+
outcome.
|
|
28
|
+
|
|
29
|
+
SQLite and shared PostgreSQL runtime stores retain the same event identities,
|
|
30
|
+
attention projection, acknowledgement, and delivery state.
|
|
31
|
+
|
|
32
|
+
## Quiet Default
|
|
33
|
+
|
|
34
|
+
Under the default route, successful activity remains visible in the ledger,
|
|
35
|
+
Workbench timeline, CLI, metrics, and optional digest, but does not interrupt a
|
|
36
|
+
human.
|
|
37
|
+
|
|
38
|
+
No immediate external notification is sent by default for:
|
|
39
|
+
|
|
40
|
+
- proposal creation, policy auto-approval, approval, or queueing;
|
|
41
|
+
- a worker lease or individual retry;
|
|
42
|
+
- successful manual or automatic apply;
|
|
43
|
+
- an isolated conflict that Runner handled safely;
|
|
44
|
+
- planned worker start, pause, resume, drain, or stop;
|
|
45
|
+
- capability activation by the same operator.
|
|
46
|
+
|
|
47
|
+
Immediate delivery defaults to states where timely attention matters:
|
|
48
|
+
|
|
49
|
+
- human approval required;
|
|
50
|
+
- UNKNOWN transaction outcome or reconciliation required;
|
|
51
|
+
- dead-letter work;
|
|
52
|
+
- sustained worker-health failure;
|
|
53
|
+
- queue depth/age crossing an operator threshold;
|
|
54
|
+
- schema drift or stale digest blocking authority;
|
|
55
|
+
- invalidated writer credential posture;
|
|
56
|
+
- critical policy/limit failure;
|
|
57
|
+
- an approved proposal approaching expiry while action is still possible.
|
|
58
|
+
|
|
59
|
+
Informational success events can be sent only through an explicit all-events
|
|
60
|
+
route or periodic digest.
|
|
61
|
+
|
|
62
|
+
## Events And Attention Items
|
|
63
|
+
|
|
64
|
+
Events are immutable audit facts. Attention items are durable incident
|
|
65
|
+
projections over related events.
|
|
66
|
+
|
|
67
|
+
For example, ten proposals requiring the same role can produce ten immutable
|
|
68
|
+
events but one item saying that ten proposals need review. Repeated worker
|
|
69
|
+
failures, queue backlog, or the same schema-drift condition update one item and
|
|
70
|
+
its occurrence count. Retry attempts stay internal until the configured
|
|
71
|
+
attempt/duration threshold is crossed.
|
|
72
|
+
|
|
73
|
+
Attention states are:
|
|
74
|
+
|
|
75
|
+
- `open`;
|
|
76
|
+
- `acknowledged`;
|
|
77
|
+
- `resolved`;
|
|
78
|
+
- `expired`.
|
|
79
|
+
|
|
80
|
+
Acknowledgement means only that a verified operator saw the item. It is not
|
|
81
|
+
approval or resolution.
|
|
82
|
+
|
|
83
|
+
## Configure Sinks
|
|
84
|
+
|
|
85
|
+
This operator-owned config enables one signed webhook and one optional
|
|
86
|
+
development JSONL stream:
|
|
87
|
+
|
|
88
|
+
```json
|
|
89
|
+
{
|
|
90
|
+
"notifications": {
|
|
91
|
+
"enabled": true,
|
|
92
|
+
"workbench_url_env": "SYNAPSOR_WORKBENCH_URL",
|
|
93
|
+
"sinks": [
|
|
94
|
+
{
|
|
95
|
+
"id": "operations",
|
|
96
|
+
"type": "webhook",
|
|
97
|
+
"enabled": true,
|
|
98
|
+
"url_env": "SYNAPSOR_NOTIFY_WEBHOOK_URL",
|
|
99
|
+
"signing_secret_env": "SYNAPSOR_NOTIFY_SIGNING_SECRET",
|
|
100
|
+
"minimum_severity": "warning",
|
|
101
|
+
"events": [
|
|
102
|
+
"proposal.review_required",
|
|
103
|
+
"worker.dead_lettered",
|
|
104
|
+
"worker.unknown_outcome",
|
|
105
|
+
"worker.reconciliation_required",
|
|
106
|
+
"schema.drift_detected"
|
|
107
|
+
],
|
|
108
|
+
"capabilities": ["billing.propose_small_credit"],
|
|
109
|
+
"environments": ["staging", "production"],
|
|
110
|
+
"delivery": "immediate",
|
|
111
|
+
"max_attempts": 5,
|
|
112
|
+
"timeout_ms": 3000,
|
|
113
|
+
"max_response_bytes": 1024,
|
|
114
|
+
"replay_window_seconds": 300,
|
|
115
|
+
"allow_private_destinations": false,
|
|
116
|
+
"recovery_notifications": false,
|
|
117
|
+
"budgets": {
|
|
118
|
+
"per_minute": 10,
|
|
119
|
+
"per_hour": 100,
|
|
120
|
+
"immediate_informational_per_hour": 0,
|
|
121
|
+
"aggregation_window_seconds": 300,
|
|
122
|
+
"cooldown_seconds": 600,
|
|
123
|
+
"max_unresolved_reminders": 3,
|
|
124
|
+
"digest_cadence_minutes": 1440,
|
|
125
|
+
"escalation_delay_seconds": 60,
|
|
126
|
+
"retry_attempt_threshold": 3,
|
|
127
|
+
"degraded_duration_seconds": 120,
|
|
128
|
+
"queue_depth_threshold": 100,
|
|
129
|
+
"queue_age_seconds": 300
|
|
130
|
+
},
|
|
131
|
+
"quiet_hours": {
|
|
132
|
+
"start_utc_hour": 22,
|
|
133
|
+
"end_utc_hour": 7
|
|
134
|
+
}
|
|
135
|
+
},
|
|
136
|
+
{
|
|
137
|
+
"id": "development",
|
|
138
|
+
"type": "jsonl",
|
|
139
|
+
"enabled": false,
|
|
140
|
+
"destination": "stdout",
|
|
141
|
+
"minimum_severity": "informational",
|
|
142
|
+
"delivery": "all"
|
|
143
|
+
}
|
|
144
|
+
]
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
Set values only in the operator environment:
|
|
150
|
+
|
|
151
|
+
```bash
|
|
152
|
+
export SYNAPSOR_WORKBENCH_URL=https://runner-ops.example.internal
|
|
153
|
+
export SYNAPSOR_NOTIFY_WEBHOOK_URL=https://events.example.com/synapsor
|
|
154
|
+
export SYNAPSOR_NOTIFY_SIGNING_SECRET='at-least-32-random-bytes'
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
The config stores environment-variable names, not URLs or secrets. Events never
|
|
158
|
+
contain credentials, database URLs, SQL, source rows, aggregate group results,
|
|
159
|
+
kept-out fields, trusted tenant/principal values, sensitive arguments, or
|
|
160
|
+
authority tokens.
|
|
161
|
+
|
|
162
|
+
## Route By Destination
|
|
163
|
+
|
|
164
|
+
Every sink has its own event, severity, capability, environment, and delivery
|
|
165
|
+
route. A practical split is:
|
|
166
|
+
|
|
167
|
+
| Sink | Route |
|
|
168
|
+
| --- | --- |
|
|
169
|
+
| Workbench | Complete event and attention history |
|
|
170
|
+
| Team chat webhook | Review-required and operational warnings |
|
|
171
|
+
| Incident webhook | UNKNOWN, reconciliation, dead letter, sustained worker failure |
|
|
172
|
+
| Email-provider webhook | Daily digest |
|
|
173
|
+
| Audit webhook | Explicit all-events redacted stream |
|
|
174
|
+
|
|
175
|
+
The ledger and Workbench remain the source of truth.
|
|
176
|
+
|
|
177
|
+
## Operate Without Copying IDs
|
|
178
|
+
|
|
179
|
+
Inspect the highest-priority item:
|
|
180
|
+
|
|
181
|
+
```bash
|
|
182
|
+
synapsor-runner attention list --config ./synapsor.runner.json
|
|
183
|
+
synapsor-runner attention show --config ./synapsor.runner.json
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
Use `attention show <attention_id>` only when selecting a specific item. JSON
|
|
187
|
+
automation is available with `--json`.
|
|
188
|
+
|
|
189
|
+
Acknowledgement is explicit:
|
|
190
|
+
|
|
191
|
+
```bash
|
|
192
|
+
synapsor-runner attention acknowledge --actor alice \
|
|
193
|
+
--config ./synapsor.runner.json
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
Production acknowledgement follows configured verified operator identity and is
|
|
197
|
+
cryptographically bound to the exact item digest and occurrence.
|
|
198
|
+
|
|
199
|
+
Inspect and test delivery:
|
|
200
|
+
|
|
201
|
+
```bash
|
|
202
|
+
synapsor-runner notifications status --config ./synapsor.runner.json
|
|
203
|
+
synapsor-runner notifications test --sink operations \
|
|
204
|
+
--config ./synapsor.runner.json
|
|
205
|
+
synapsor-runner notifications dispatch --sink operations --limit 20 \
|
|
206
|
+
--config ./synapsor.runner.json
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
`notifications test` sends an unmistakable synthetic event containing no
|
|
210
|
+
database or proposal data. Opening Workbench, installing Runner, and starting
|
|
211
|
+
MCP never start outbound delivery.
|
|
212
|
+
|
|
213
|
+
Requeue one dead-letter delivery:
|
|
214
|
+
|
|
215
|
+
```bash
|
|
216
|
+
synapsor-runner notifications replay latest --yes \
|
|
217
|
+
--reason "Webhook repaired and synthetic test passed" \
|
|
218
|
+
--config ./synapsor.runner.json
|
|
219
|
+
```
|
|
220
|
+
|
|
221
|
+
This replays only the immutable redacted notification. It does not replay an
|
|
222
|
+
approval or database mutation. Replay is an operator recovery action and
|
|
223
|
+
requires the configured `signed_key` or `jwt_oidc` identity. Runner binds the
|
|
224
|
+
verified decision to the exact delivery revision and records a redacted
|
|
225
|
+
immutable `notification.replayed` audit event.
|
|
226
|
+
|
|
227
|
+
## Webhook Contract
|
|
228
|
+
|
|
229
|
+
Runner sends a CloudEvents 1.0 structured JSON body with content type
|
|
230
|
+
`application/cloudevents+json`. Important headers are:
|
|
231
|
+
|
|
232
|
+
```text
|
|
233
|
+
X-Synapsor-Event-Id
|
|
234
|
+
X-Synapsor-Timestamp
|
|
235
|
+
X-Synapsor-Signature-Version: v1
|
|
236
|
+
X-Synapsor-Signature: sha256=<hex HMAC>
|
|
237
|
+
```
|
|
238
|
+
|
|
239
|
+
The HMAC-SHA-256 input is the UTF-8 string
|
|
240
|
+
`v1.<timestamp>.<event-id>.<exact-body>`. Receivers must:
|
|
241
|
+
|
|
242
|
+
1. Require signature version `v1`.
|
|
243
|
+
2. Reject timestamps outside the configured replay window.
|
|
244
|
+
3. Verify the HMAC with a timing-safe comparison.
|
|
245
|
+
4. Deduplicate the stable event ID.
|
|
246
|
+
5. Return only a bounded transport acknowledgement.
|
|
247
|
+
|
|
248
|
+
Runner ignores response content. A receiver cannot return a command.
|
|
249
|
+
|
|
250
|
+
A minimal Node receiver can verify the exact bytes before parsing JSON:
|
|
251
|
+
|
|
252
|
+
```js
|
|
253
|
+
import { createHmac, timingSafeEqual } from "node:crypto";
|
|
254
|
+
|
|
255
|
+
export function verifySynapsorWebhook(rawBody, headers, secret, now = Date.now()) {
|
|
256
|
+
const eventId = headers["x-synapsor-event-id"];
|
|
257
|
+
const timestamp = headers["x-synapsor-timestamp"];
|
|
258
|
+
const version = headers["x-synapsor-signature-version"];
|
|
259
|
+
const suppliedHeader = headers["x-synapsor-signature"];
|
|
260
|
+
if (!eventId || !timestamp || version !== "v1" || !suppliedHeader?.startsWith("sha256=")) {
|
|
261
|
+
return false;
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
const timestampSeconds = Number(timestamp);
|
|
265
|
+
const ageMs = Math.abs(now - timestampSeconds * 1000);
|
|
266
|
+
if (!Number.isSafeInteger(timestampSeconds) || ageMs > 300_000) return false;
|
|
267
|
+
|
|
268
|
+
const expected = Buffer.from(
|
|
269
|
+
createHmac("sha256", secret)
|
|
270
|
+
.update(`v1.${timestamp}.${eventId}.${rawBody}`, "utf8")
|
|
271
|
+
.digest("hex"),
|
|
272
|
+
"hex",
|
|
273
|
+
);
|
|
274
|
+
const supplied = Buffer.from(suppliedHeader.slice("sha256=".length), "hex");
|
|
275
|
+
return expected.length === supplied.length && timingSafeEqual(expected, supplied);
|
|
276
|
+
}
|
|
277
|
+
```
|
|
278
|
+
|
|
279
|
+
Read the request as raw UTF-8 bytes for verification; reserializing parsed JSON
|
|
280
|
+
changes the signed body. Store the event ID for at least the replay window and
|
|
281
|
+
reject a duplicate before processing it.
|
|
282
|
+
|
|
283
|
+
The structured body resembles:
|
|
284
|
+
|
|
285
|
+
```json
|
|
286
|
+
{
|
|
287
|
+
"specversion": "1.0",
|
|
288
|
+
"id": "aev_...",
|
|
289
|
+
"type": "ai.synapsor.worker.reconciliation_required",
|
|
290
|
+
"source": "urn:synapsor:runner:production",
|
|
291
|
+
"time": "2026-07-25T00:00:00.000Z",
|
|
292
|
+
"datacontenttype": "application/json",
|
|
293
|
+
"subject": "billing.propose_small_credit",
|
|
294
|
+
"data": {
|
|
295
|
+
"schema_version": "synapsor.notification.v1",
|
|
296
|
+
"severity": "critical",
|
|
297
|
+
"environment": "production",
|
|
298
|
+
"capability": "billing.propose_small_credit",
|
|
299
|
+
"contract_digest": "sha256:...",
|
|
300
|
+
"summary": "A guarded apply needs operator reconciliation.",
|
|
301
|
+
"workbench_url": "https://runner-ops.example.internal/attention/att_..."
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
```
|
|
305
|
+
|
|
306
|
+
The Workbench URL identifies an item but carries no approval or recovery
|
|
307
|
+
authority. The operator must authenticate normally.
|
|
308
|
+
|
|
309
|
+
HTTPS is required by default. Redirects and unsafe loopback, link-local,
|
|
310
|
+
metadata, multicast, unspecified, private, and rebinding destinations are
|
|
311
|
+
refused. Intentional private destinations require both
|
|
312
|
+
`allow_private_destinations: true` and an exact `private_host_allowlist`.
|
|
313
|
+
|
|
314
|
+
## Delivery And Noise Guarantees
|
|
315
|
+
|
|
316
|
+
Delivery is at least once. Sink-specific records use atomic leases, fencing,
|
|
317
|
+
bounded retries, jittered backoff, timeout, maximum attempts, and dead-letter
|
|
318
|
+
state. Repeated delivery cannot repeat proposal authority or source mutation.
|
|
319
|
+
|
|
320
|
+
When a non-critical budget is exhausted, Runner preserves every event, updates
|
|
321
|
+
the Workbench item, and suppresses or batches external messages. Critical events
|
|
322
|
+
bypass ordinary quiet hours and budgets but still coalesce under a separate
|
|
323
|
+
bounded emergency ceiling.
|
|
324
|
+
|
|
325
|
+
Optional digests report redacted counts for proposals, auto-approval, apply,
|
|
326
|
+
review-required work, conflicts, retries, dead letters, limits, queue age, and
|
|
327
|
+
unresolved critical items. They link to authenticated Workbench detail.
|
|
328
|
+
|
|
329
|
+
Recovery messages are off by default. When an incident resolves, Workbench is
|
|
330
|
+
updated; an external recovery message is sent only when that sink explicitly
|
|
331
|
+
enables `recovery_notifications` or the critical-route policy requires it.
|
|
332
|
+
|
|
333
|
+
## Retry And Dead-Letter Runbook
|
|
334
|
+
|
|
335
|
+
1. Run `notifications status --json` and inspect sink health, pending delivery,
|
|
336
|
+
and dead-letter counts.
|
|
337
|
+
2. Open the corresponding Workbench attention item. Confirm the authoritative
|
|
338
|
+
proposal/worker state before changing delivery.
|
|
339
|
+
3. Repair the operator-owned destination, DNS policy, TLS, or secret rotation.
|
|
340
|
+
4. Send `notifications test --sink <id>`; it contains no database data.
|
|
341
|
+
5. Run `notifications dispatch --sink <id> --limit 20` to drain eligible work.
|
|
342
|
+
6. Replay a dead-letter delivery only with
|
|
343
|
+
`notifications replay <delivery_id> --yes --reason "<why replay is safe>"`.
|
|
344
|
+
|
|
345
|
+
Replay preserves the original immutable event ID. It cannot re-run the database
|
|
346
|
+
operation. The exact recovery decision must be verified through the configured
|
|
347
|
+
operator identity. A still-failing sink remains observable and does not rewrite
|
|
348
|
+
the underlying proposal outcome.
|
|
349
|
+
|
|
350
|
+
## Supervised Worker Health Gate
|
|
351
|
+
|
|
352
|
+
An exact supervised-worker capability may list:
|
|
353
|
+
|
|
354
|
+
```json
|
|
355
|
+
{
|
|
356
|
+
"required_attention_sinks": ["operations"]
|
|
357
|
+
}
|
|
358
|
+
```
|
|
359
|
+
|
|
360
|
+
If every required sink is unhealthy or untested, an otherwise eligible
|
|
361
|
+
policy-approved production write remains queued. Workbench explains that
|
|
362
|
+
operator visibility is unavailable. A healthy sink does not approve anything;
|
|
363
|
+
after recovery, the worker still repeats every ordinary digest, policy, scope,
|
|
364
|
+
freshness, limit, credential, lease, and guarded-write check.
|
|
365
|
+
|
|
366
|
+
See [Operator-Supervised Automatic
|
|
367
|
+
Apply](supervised-automatic-apply.md) for the execution boundary.
|
package/docs/limitations.md
CHANGED
|
@@ -1,11 +1,14 @@
|
|
|
1
1
|
# Limitations
|
|
2
2
|
|
|
3
|
-
Synapsor Runner is intentionally narrow.
|
|
4
|
-
whole-application boundary drafting
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
3
|
+
Synapsor Runner is intentionally narrow. It combines deterministic
|
|
4
|
+
whole-application boundary drafting, local authoring-only Explore -> Protect,
|
|
5
|
+
guarded writes, opt-in proposal/evidence freshness, verified operator identity,
|
|
6
|
+
default-off supervised execution, and quiet human-attention delivery. Reviewed
|
|
7
|
+
aggregate paths are limited to proven star/depth-two many-to-one relationships,
|
|
8
|
+
not a general join planner. Optional local Workbench Ask is a client of the
|
|
9
|
+
existing reviewed tools; the complete no-model path remains the default.
|
|
10
|
+
Runner does not become a generic database query tool, Synapsor Cloud, or an
|
|
11
|
+
enterprise SLA.
|
|
9
12
|
|
|
10
13
|
## Supported
|
|
11
14
|
|
|
@@ -15,8 +18,9 @@ or claim an enterprise SLA.
|
|
|
15
18
|
- Optional shared Postgres proposal/evidence/replay runtime store for MCP serving.
|
|
16
19
|
- Asymmetric claim-bound Streamable HTTP sessions and explicit readiness.
|
|
17
20
|
- Native Postgres/MySQL source pools and operational/fleet-wide rate limits.
|
|
18
|
-
- Verified operator approval through CLI
|
|
19
|
-
|
|
21
|
+
- Verified operator approval through CLI or the secured local Workbench,
|
|
22
|
+
optional distinct-reviewer quorum, separate apply authority, and
|
|
23
|
+
proposal-centered lifecycle inspection.
|
|
20
24
|
- Optional live target and explicitly declared supporting-row freshness checks
|
|
21
25
|
before every approval, with immutable proof binding and final transactional
|
|
22
26
|
revalidation for PostgreSQL/MySQL direct SQL writeback.
|
|
@@ -59,10 +63,20 @@ or claim an enterprise SLA.
|
|
|
59
63
|
existing Synapsor definitions. Generated authority starts disabled.
|
|
60
64
|
- Local development/staging Scoped Explore through exactly
|
|
61
65
|
`app.describe_data` and `app.explore_data`, with no SQL-string argument.
|
|
66
|
+
- Optional development/staging loopback Workbench Ask through OpenAI,
|
|
67
|
+
Anthropic, or a configured OpenAI-compatible endpoint. Provider calls use the
|
|
68
|
+
exact active MCP/runtime surface, explicit direct-egress consent, in-memory
|
|
69
|
+
credential/history state, fixed tool/time/size/token bounds, and
|
|
70
|
+
proposal-only write behavior.
|
|
62
71
|
- Reviewed PM-style aggregate Explore with `count`, `count_distinct`, `sum`,
|
|
63
72
|
`avg`, categorical dimensions, fixed time buckets, typed filters, bounded
|
|
64
|
-
top-N,
|
|
65
|
-
and durable
|
|
73
|
+
top-N, up to three reviewed relationship paths of at most two proven
|
|
74
|
+
many-to-one links each, cohort suppression, and durable
|
|
75
|
+
extraction/differencing budgets.
|
|
76
|
+
- Demand-driven operator review for an exact catalog-proven relationship,
|
|
77
|
+
including an explicit missing-row choice for nullable links. The model cannot
|
|
78
|
+
activate a relationship, and every participating relation receives trusted
|
|
79
|
+
tenant/principal scope.
|
|
66
80
|
- Protect This Query to public DSL, canonical JSON, tests, and a disabled named
|
|
67
81
|
capability that survives Explore shutdown after exact-digest activation.
|
|
68
82
|
- Generation-lock drift detection for generated authority. Manually authored
|
|
@@ -75,6 +89,13 @@ or claim an enterprise SLA.
|
|
|
75
89
|
and scoped tamper-evident JSON/Markdown/PDF ledger reports.
|
|
76
90
|
- Off-by-default graduated-trust recommendations that require verified operator
|
|
77
91
|
review and explicit artifact export without activation.
|
|
92
|
+
- Default-off operator-supervised apply for eligible exact-row direct
|
|
93
|
+
`INSERT`/`UPDATE`, requiring both public contract permission and an
|
|
94
|
+
independent deployment allowlist for the exact active digest. It reuses
|
|
95
|
+
guarded apply and preserves legacy `AUTO APPROVE` as manual-apply.
|
|
96
|
+
- Durable redacted human-attention events, a coalesced Workbench inbox,
|
|
97
|
+
no-ID CLI inspection, optional JSONL output, and signed generic HTTPS
|
|
98
|
+
webhooks with quiet routing, budgets, digests, and safe delivery replay.
|
|
78
99
|
|
|
79
100
|
## Runtime Contract
|
|
80
101
|
|
|
@@ -105,16 +126,25 @@ truth for the model-facing tools.
|
|
|
105
126
|
- Inferred compensation for app-owned handlers or external effects.
|
|
106
127
|
- General restoration of hard-deleted rows, cascades, or trigger side effects.
|
|
107
128
|
- Model-callable approval or commit tools.
|
|
129
|
+
- Model-callable worker, notification-routing, acknowledgement, recovery, or
|
|
130
|
+
reconciliation controls.
|
|
108
131
|
- Generic MCP firewall behavior.
|
|
109
132
|
- Prompt-injection prevention.
|
|
110
133
|
- Unbounded/high-throughput or multi-region ledger scale.
|
|
111
134
|
- Managed fleet, SLA, compliance certification, or production support guarantee.
|
|
112
135
|
- Production, shared HTTP, remote, or non-loopback Scoped Explore.
|
|
136
|
+
- Production, shared HTTP, remote, or non-loopback Workbench Ask; model-facing
|
|
137
|
+
provider configuration; Synapsor-relayed provider traffic; durable chat
|
|
138
|
+
history; automatic provider retries; exact monetary spend enforcement; or
|
|
139
|
+
universal compatibility with OpenAI-compatible servers.
|
|
140
|
+
- Automatic supervised execution for hard DELETE, reversible changes, bounded
|
|
141
|
+
sets, app-owned/external effects, or writes without deterministic conflict,
|
|
142
|
+
deduplication, freshness, and receipt authority.
|
|
113
143
|
- Arbitrary aggregate expressions, dynamic identifiers, unrestricted joins,
|
|
114
144
|
many-to-many joins, formulas, window functions, subqueries, `HAVING`,
|
|
115
|
-
user-defined functions, or a statistical privacy guarantee.
|
|
116
|
-
|
|
117
|
-
|
|
145
|
+
user-defined functions, or a statistical privacy guarantee. Runner supports
|
|
146
|
+
only the explicitly reviewed authoring cube described above and fixed
|
|
147
|
+
protected named capabilities produced from it.
|
|
118
148
|
- Automatic policy widening or activation from graduated-trust metrics.
|
|
119
149
|
- Immutable/WORM compliance storage from the local report exporter.
|
|
120
150
|
|
|
@@ -149,6 +179,12 @@ jobs. Mixed-minor v3/v4 rolling compensation is not claimed.
|
|
|
149
179
|
See [Running A Small Runner
|
|
150
180
|
Fleet](running-a-runner-fleet.md).
|
|
151
181
|
|
|
182
|
+
Workbench Ask token accounting uses provider-reported usage. A provider that
|
|
183
|
+
omits or misreports usage cannot provide exact token or monetary enforcement.
|
|
184
|
+
Runner still enforces request/response, tool-result, iteration, history, and
|
|
185
|
+
wall-clock bounds. A provider outage does not disable the no-model composer or
|
|
186
|
+
external MCP path. See [Workbench Ask With Your Model](workbench-ask.md).
|
|
187
|
+
|
|
152
188
|
Use this wording:
|
|
153
189
|
|
|
154
190
|
```text
|
package/docs/local-mode.md
CHANGED
|
@@ -44,13 +44,13 @@ when you do not want to change your host Node version.
|
|
|
44
44
|
Create a starter config without putting credentials in the file:
|
|
45
45
|
|
|
46
46
|
```bash
|
|
47
|
-
npx -y
|
|
47
|
+
npx -y @synapsor/runner init --engine postgres --mode review
|
|
48
48
|
```
|
|
49
49
|
|
|
50
50
|
For MySQL:
|
|
51
51
|
|
|
52
52
|
```bash
|
|
53
|
-
npx -y
|
|
53
|
+
npx -y @synapsor/runner init --engine mysql --mode review --output synapsor.mysql.runner.json
|
|
54
54
|
```
|
|
55
55
|
|
|
56
56
|
The generated config uses environment-variable names for read/write URLs and trusted context. Edit the table, column, and capability names before serving tools.
|
|
@@ -63,8 +63,8 @@ persisted into proposals, evidence, query audit, runner state, or replay.
|
|
|
63
63
|
For a reviewed own-database setup generated from explicit selections, use:
|
|
64
64
|
|
|
65
65
|
```bash
|
|
66
|
-
npx -y
|
|
67
|
-
npx -y
|
|
66
|
+
npx -y @synapsor/runner init --spec onboarding-selection.json --non-interactive
|
|
67
|
+
npx -y @synapsor/runner doctor --config synapsor.runner.json
|
|
68
68
|
```
|
|
69
69
|
|
|
70
70
|
`doctor --config` checks config validation, required environment variables,
|
|
@@ -76,7 +76,7 @@ and the semantic MCP tool boundary without printing credential values.
|
|
|
76
76
|
Use stdio for local MCP clients that launch Synapsor Runner:
|
|
77
77
|
|
|
78
78
|
```bash
|
|
79
|
-
npx -y
|
|
79
|
+
npx -y @synapsor/runner mcp serve \
|
|
80
80
|
--config ./synapsor.runner.json \
|
|
81
81
|
--store ./.synapsor/local.db
|
|
82
82
|
```
|
|
@@ -87,7 +87,7 @@ MCP client:
|
|
|
87
87
|
```bash
|
|
88
88
|
export SYNAPSOR_RUNNER_HTTP_TOKEN="$(node -e 'process.stdout.write(require("node:crypto").randomBytes(32).toString("base64url"))')"
|
|
89
89
|
|
|
90
|
-
npx -y
|
|
90
|
+
npx -y @synapsor/runner mcp serve-streamable-http \
|
|
91
91
|
--config ./synapsor.runner.json \
|
|
92
92
|
--store ./.synapsor/local.db \
|
|
93
93
|
--auth-token-env SYNAPSOR_RUNNER_HTTP_TOKEN
|
|
@@ -131,19 +131,19 @@ If neither is set, the CLI uses:
|
|
|
131
131
|
List proposals:
|
|
132
132
|
|
|
133
133
|
```bash
|
|
134
|
-
npx -y
|
|
134
|
+
npx -y @synapsor/runner proposals list --store ./.synapsor/local.db
|
|
135
135
|
```
|
|
136
136
|
|
|
137
137
|
Show a proposal:
|
|
138
138
|
|
|
139
139
|
```bash
|
|
140
|
-
npx -y
|
|
140
|
+
npx -y @synapsor/runner proposals show wrp_123 --store ./.synapsor/local.db
|
|
141
141
|
```
|
|
142
142
|
|
|
143
143
|
Check a freshness-enabled proposal without copying its id:
|
|
144
144
|
|
|
145
145
|
```bash
|
|
146
|
-
npx -y
|
|
146
|
+
npx -y @synapsor/runner proposals check-freshness latest \
|
|
147
147
|
--config ./synapsor.runner.json \
|
|
148
148
|
--store ./.synapsor/local.db
|
|
149
149
|
```
|
|
@@ -151,13 +151,19 @@ npx -y -p @synapsor/runner synapsor-runner proposals check-freshness latest \
|
|
|
151
151
|
Approve:
|
|
152
152
|
|
|
153
153
|
```bash
|
|
154
|
-
npx -y
|
|
154
|
+
npx -y @synapsor/runner proposals approve wrp_123 \
|
|
155
155
|
--config ./synapsor.runner.json \
|
|
156
156
|
--store ./.synapsor/local.db \
|
|
157
157
|
--actor local_reviewer \
|
|
158
158
|
--yes
|
|
159
159
|
```
|
|
160
160
|
|
|
161
|
+
The `--actor` example is the unverified local-development path. Shared and
|
|
162
|
+
production operation should require `signed_key` or `jwt_oidc`, resolve the
|
|
163
|
+
contract's exact role from verified identity, and authorize apply separately.
|
|
164
|
+
See [Approval Roles And Verified Operator
|
|
165
|
+
Identity](approval-roles-and-operator-identity.md).
|
|
166
|
+
|
|
161
167
|
Before approval, the CLI prints the reviewer-critical proposal details: trusted principal, tenant, target row, primary key, required role, proposal hash/version, allowed columns, conflict guard, evidence bundle/query fingerprint, writeback boundary, source mutation state, and exact before/after diff. Interactive approval still requires typing `yes`; noninteractive scripts must pass `--yes`.
|
|
162
168
|
|
|
163
169
|
When `proposal_freshness` is configured for that capability, approval also
|
|
@@ -171,7 +177,7 @@ revalidates again because source data can change after approval. See
|
|
|
171
177
|
Create a guarded writeback job from an approved proposal:
|
|
172
178
|
|
|
173
179
|
```bash
|
|
174
|
-
npx -y
|
|
180
|
+
npx -y @synapsor/runner proposals writeback-job wrp_123 \
|
|
175
181
|
--store ./.synapsor/local.db \
|
|
176
182
|
--project local \
|
|
177
183
|
--runner local_runner \
|
|
@@ -183,7 +189,7 @@ The generated job uses the public `synapsor.writeback-job.v1` protocol and can b
|
|
|
183
189
|
```bash
|
|
184
190
|
export SYNAPSOR_DATABASE_WRITE_URL="postgresql://writer:<password>@localhost:5432/app"
|
|
185
191
|
SYNAPSOR_ENGINE=postgres \
|
|
186
|
-
npx -y
|
|
192
|
+
npx -y @synapsor/runner apply --job job.json --config synapsor.runner.json --store ./.synapsor/local.db
|
|
187
193
|
```
|
|
188
194
|
|
|
189
195
|
When `--config` is passed, direct SQL writeback reads the writer connection from
|
|
@@ -195,7 +201,7 @@ Passing `--store` records the terminal `synapsor.execution-receipt.v1` locally.
|
|
|
195
201
|
Reject:
|
|
196
202
|
|
|
197
203
|
```bash
|
|
198
|
-
npx -y
|
|
204
|
+
npx -y @synapsor/runner proposals reject wrp_123 \
|
|
199
205
|
--store ./.synapsor/local.db \
|
|
200
206
|
--reason "policy evidence is incomplete" \
|
|
201
207
|
--yes
|
|
@@ -216,7 +222,7 @@ pilot, use [Shadow Studies](shadow-studies.md).
|
|
|
216
222
|
Start a localhost-only review UI:
|
|
217
223
|
|
|
218
224
|
```bash
|
|
219
|
-
npx -y
|
|
225
|
+
npx -y @synapsor/runner ui --config synapsor.runner.json --store ./.synapsor/local.db
|
|
220
226
|
```
|
|
221
227
|
|
|
222
228
|
The UI shows setup summary, semantic tools, proposal states, exact diffs,
|
|
@@ -234,20 +240,20 @@ tools, MCP commit tools, or controls that widen configured tables/columns.
|
|
|
234
240
|
Show replay:
|
|
235
241
|
|
|
236
242
|
```bash
|
|
237
|
-
npx -y
|
|
238
|
-
npx -y
|
|
239
|
-
npx -y
|
|
240
|
-
npx -y
|
|
243
|
+
npx -y @synapsor/runner replay show wrp_123 --store ./.synapsor/local.db
|
|
244
|
+
npx -y @synapsor/runner replay show --proposal wrp_123 --store ./.synapsor/local.db
|
|
245
|
+
npx -y @synapsor/runner replay show --replay replay_wrp_123 --store ./.synapsor/local.db
|
|
246
|
+
npx -y @synapsor/runner replay show --evidence ev_123 --store ./.synapsor/local.db
|
|
241
247
|
```
|
|
242
248
|
|
|
243
249
|
Export replay:
|
|
244
250
|
|
|
245
251
|
```bash
|
|
246
|
-
npx -y
|
|
252
|
+
npx -y @synapsor/runner replay export wrp_123 \
|
|
247
253
|
--store ./.synapsor/local.db \
|
|
248
254
|
--output replay.json
|
|
249
255
|
|
|
250
|
-
npx -y
|
|
256
|
+
npx -y @synapsor/runner replay export --proposal wrp_123 \
|
|
251
257
|
--format markdown \
|
|
252
258
|
--store ./.synapsor/local.db \
|
|
253
259
|
--output replay.md
|
|
@@ -301,6 +307,8 @@ or prune it without touching your source Postgres/MySQL database:
|
|
|
301
307
|
```bash
|
|
302
308
|
synapsor-runner store stats --store ./.synapsor/local.db
|
|
303
309
|
synapsor-runner events tail --store ./.synapsor/local.db
|
|
310
|
+
synapsor-runner attention show --store ./.synapsor/local.db
|
|
311
|
+
synapsor-runner notifications status --store ./.synapsor/local.db
|
|
304
312
|
synapsor-runner events webhook --url http://127.0.0.1:8788/synapsor/events --kind proposal_created --store ./.synapsor/local.db
|
|
305
313
|
synapsor-runner store vacuum --store ./.synapsor/local.db
|
|
306
314
|
synapsor-runner store prune --store ./.synapsor/local.db --older-than 30d --dry-run
|
|
@@ -316,8 +324,14 @@ running local store.
|
|
|
316
324
|
|
|
317
325
|
`events webhook` pushes the same local lifecycle events to a local/dev/staging
|
|
318
326
|
HTTP endpoint, one event envelope per POST. Use it for a review UI, Slack bridge,
|
|
319
|
-
or app-local
|
|
320
|
-
|
|
327
|
+
or app-local compatibility path when polling is awkward. It is not the
|
|
328
|
+
production human-attention dispatcher.
|
|
329
|
+
|
|
330
|
+
For durable coalesced incidents, quiet defaults, budgets/digests, signed HTTPS
|
|
331
|
+
delivery, replay protection, sink health, and the no-ID Workbench inbox, use
|
|
332
|
+
`attention` and `notifications`. See [Human Attention And
|
|
333
|
+
Notifications](human-attention-notifications.md). Neither notification path
|
|
334
|
+
becomes approval or apply authority.
|
|
321
335
|
|
|
322
336
|
`store prune` defaults to dry-run. `store reset` requires `--yes` and removes
|
|
323
337
|
only the local SQLite ledger files. MCP server modes write a small active-store
|