@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,279 @@
|
|
|
1
|
+
# Workbench Ask With Your Model
|
|
2
|
+
|
|
3
|
+
Workbench Ask is an optional local client for the reviewed Synapsor tools that
|
|
4
|
+
already exist. It lets a developer ask a plain-language question through
|
|
5
|
+
OpenAI, Anthropic, or an explicitly configured OpenAI-compatible endpoint
|
|
6
|
+
without installing an external MCP host first.
|
|
7
|
+
|
|
8
|
+
Ask does not generate or activate authority. It does not replace the no-model
|
|
9
|
+
Workbench composer, which remains the default onboarding path and requires no
|
|
10
|
+
model API key.
|
|
11
|
+
|
|
12
|
+
```text
|
|
13
|
+
human activates a reviewed boundary or named capability
|
|
14
|
+
-> Workbench lists that exact model-facing tool surface
|
|
15
|
+
-> human selects a provider and acknowledges direct data egress
|
|
16
|
+
-> provider may request one of those reviewed tools
|
|
17
|
+
-> Runner executes the request through the normal MCP/runtime path
|
|
18
|
+
-> provider receives the bounded reviewed result
|
|
19
|
+
-> Workbench renders provider prose as untrusted output
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
The model cannot activate a boundary, Protect a query, approve or apply a
|
|
23
|
+
proposal, control a worker, acknowledge attention, reconcile an outcome, or
|
|
24
|
+
change provider configuration.
|
|
25
|
+
|
|
26
|
+
## Availability
|
|
27
|
+
|
|
28
|
+
Ask appears only when all of these conditions hold:
|
|
29
|
+
|
|
30
|
+
- Workbench is authenticated and bound to loopback;
|
|
31
|
+
- the deployment profile is explicitly `development` or `staging`;
|
|
32
|
+
- at least one reviewed model-facing tool is available;
|
|
33
|
+
- generated authority and its generation lock are current when applicable.
|
|
34
|
+
|
|
35
|
+
It is absent from production, missing/unknown profiles, non-loopback
|
|
36
|
+
Workbench, shared remote HTTP, and model-facing MCP configuration. An MCP
|
|
37
|
+
request cannot enable Ask or select its provider.
|
|
38
|
+
|
|
39
|
+
While Scoped Explore is active, Ask may use:
|
|
40
|
+
|
|
41
|
+
```text
|
|
42
|
+
app.describe_data
|
|
43
|
+
app.explore_data
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
After Explore is disabled, Ask may use only the activated named capabilities
|
|
47
|
+
in `synapsor.runner.json`, such as:
|
|
48
|
+
|
|
49
|
+
```text
|
|
50
|
+
analytics.weekly_revenue_by_store
|
|
51
|
+
retail.propose_order_fulfillment
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
The panel displays the exact tool names and an Ask authority digest. That digest
|
|
55
|
+
binds the tool surface, runtime config, deployment profile, and active
|
|
56
|
+
exploration digest when one exists. A material authority change invalidates
|
|
57
|
+
egress consent before another provider call.
|
|
58
|
+
|
|
59
|
+
## Start Without A Model
|
|
60
|
+
|
|
61
|
+
Begin with the normal one-command staging path:
|
|
62
|
+
|
|
63
|
+
```bash
|
|
64
|
+
export SYNAPSOR_TENANT_ID='<reviewed tenant>'
|
|
65
|
+
export SYNAPSOR_PRINCIPAL='<reviewed principal>'
|
|
66
|
+
npx -y @synapsor/runner start
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
Paste the SELECT-only database URL into Runner's hidden terminal prompt, or
|
|
70
|
+
explicitly consent to loading only `DATABASE_URL` from a recognized project
|
|
71
|
+
environment file. For an intentionally exported automation path, use
|
|
72
|
+
`start --from-env DATABASE_URL`.
|
|
73
|
+
|
|
74
|
+
Review and activate the boundary, then run the first safe read or aggregate in
|
|
75
|
+
Workbench. At this point the complete no-model path is already working.
|
|
76
|
+
|
|
77
|
+
Open **Analyze**, then **Ask with your model**. Workbench shows:
|
|
78
|
+
|
|
79
|
+
- the reviewed tools the provider may request;
|
|
80
|
+
- the current boundary/authority digest;
|
|
81
|
+
- provider, model, origin, and credential source;
|
|
82
|
+
- that approved visible results may go directly to the provider;
|
|
83
|
+
- that Synapsor does not relay the request;
|
|
84
|
+
- that the source database is unchanged by a read or proposal call.
|
|
85
|
+
|
|
86
|
+
## Provider Credentials
|
|
87
|
+
|
|
88
|
+
Workbench Ask does not load provider keys from `.env` files. Instant database
|
|
89
|
+
onboarding may separately read only a selected `DATABASE_URL` after explicit
|
|
90
|
+
human consent. Export a provider key in the same shell that starts Runner:
|
|
91
|
+
|
|
92
|
+
```bash
|
|
93
|
+
export OPENAI_API_KEY='<provider key>'
|
|
94
|
+
npx -y @synapsor/runner start
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
Provide the database URL through the same hidden/consented path above. If
|
|
98
|
+
Runner is already running, use the masked Workbench key field instead of
|
|
99
|
+
restarting only to add a provider key.
|
|
100
|
+
|
|
101
|
+
In Workbench select:
|
|
102
|
+
|
|
103
|
+
```text
|
|
104
|
+
Provider: OpenAI
|
|
105
|
+
Credential: Read an environment variable
|
|
106
|
+
Environment variable name: OPENAI_API_KEY
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
The browser sends only the environment variable name. The value stays in the
|
|
110
|
+
local Runner process and is not returned to the browser.
|
|
111
|
+
|
|
112
|
+
Alternatively, paste a key into the masked Workbench field. Runner holds that
|
|
113
|
+
value only in server memory for the current local session and clears the field
|
|
114
|
+
after configuration. Do not paste credentials into an agent chat.
|
|
115
|
+
|
|
116
|
+
Keys and authorization headers are not written to:
|
|
117
|
+
|
|
118
|
+
- generated DSL, JSON, locks, or config;
|
|
119
|
+
- the SQLite/shared ledger, evidence, receipts, or replay;
|
|
120
|
+
- browser local/session storage;
|
|
121
|
+
- logs, screenshots, telemetry, or command-line arguments.
|
|
122
|
+
|
|
123
|
+
Select **Clear** to cancel an active request, remove in-memory provider
|
|
124
|
+
configuration, and discard bounded conversation history. Stopping Workbench
|
|
125
|
+
also clears it.
|
|
126
|
+
|
|
127
|
+
## Direct Egress
|
|
128
|
+
|
|
129
|
+
Before the first call, Workbench requires this provider-specific decision:
|
|
130
|
+
|
|
131
|
+
```text
|
|
132
|
+
Your reviewed visible data may be sent directly to this provider using your
|
|
133
|
+
credential. Synapsor does not receive it. Fields kept out by the active
|
|
134
|
+
boundary are unavailable to this model.
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
Consent is bound to the provider, model, endpoint origin, and current Ask
|
|
138
|
+
authority digest. Changing any of those requires a new acknowledgement.
|
|
139
|
+
Consent does not activate or widen database authority.
|
|
140
|
+
|
|
141
|
+
The question, reviewed tool definitions, and bounded tool results go directly
|
|
142
|
+
from local Runner to the selected provider. A tool result can contain reviewed
|
|
143
|
+
source values, so use a provider and data-handling policy appropriate for that
|
|
144
|
+
data. Kept-out fields are unavailable to selection, filtering, grouping,
|
|
145
|
+
sorting, joins, or returned results.
|
|
146
|
+
|
|
147
|
+
Runner does not persist the conversation, provider response, or returned tool
|
|
148
|
+
rows by default. Existing normalized query audit still records the boundary
|
|
149
|
+
digest, keyed plan/literal fingerprints, suppression decision, timing, and
|
|
150
|
+
result size without storing result values or trusted tenant/principal values.
|
|
151
|
+
An operator-created screenshot or external provider may retain data under its
|
|
152
|
+
own policy; Runner cannot erase those external copies.
|
|
153
|
+
|
|
154
|
+
## Authority And Proposal Behavior
|
|
155
|
+
|
|
156
|
+
Provider tool calls use the official MCP SDK and the same canonical runtime as
|
|
157
|
+
an external client:
|
|
158
|
+
|
|
159
|
+
- typed argument validation;
|
|
160
|
+
- trusted tenant/principal injection outside model arguments;
|
|
161
|
+
- read-only transaction enforcement for Scoped Explore;
|
|
162
|
+
- field, relationship, suppression, extraction, and differencing limits;
|
|
163
|
+
- proposal construction and exact active contract digest;
|
|
164
|
+
- the same error envelope and source-change state.
|
|
165
|
+
|
|
166
|
+
Provider prose, tool names, arguments, and response metadata remain untrusted.
|
|
167
|
+
An unknown or operator-plane tool is refused. A malformed or oversized
|
|
168
|
+
request, repeated tool loop, changed authority, timeout, or provider failure
|
|
169
|
+
stops safely.
|
|
170
|
+
|
|
171
|
+
A reviewed write tool may create an inert proposal:
|
|
172
|
+
|
|
173
|
+
```text
|
|
174
|
+
Proposal only
|
|
175
|
+
The source database did not change.
|
|
176
|
+
The model cannot approve or apply this proposal.
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
The human continues through the separate Workbench/CLI operator workflow.
|
|
180
|
+
Ask never receives approval or commit tools.
|
|
181
|
+
|
|
182
|
+
## Endpoint Security
|
|
183
|
+
|
|
184
|
+
Official providers use fixed endpoints:
|
|
185
|
+
|
|
186
|
+
```text
|
|
187
|
+
OpenAI: https://api.openai.com/v1/chat/completions
|
|
188
|
+
Anthropic: https://api.anthropic.com/v1/messages
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
Use **Custom OpenAI-compatible** for another endpoint. Remote custom endpoints
|
|
192
|
+
must use HTTPS. Plain HTTP is accepted only for an explicit loopback endpoint,
|
|
193
|
+
for example:
|
|
194
|
+
|
|
195
|
+
```text
|
|
196
|
+
http://127.0.0.1:11434/v1
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
Runner:
|
|
200
|
+
|
|
201
|
+
- rejects URL credentials, fragments, and query parameters;
|
|
202
|
+
- disables redirects and never forwards a key across one;
|
|
203
|
+
- resolves and validates DNS for every connection;
|
|
204
|
+
- pins the connection to the validated address while retaining TLS hostname
|
|
205
|
+
verification;
|
|
206
|
+
- blocks private, link-local, multicast, unspecified, metadata, and other
|
|
207
|
+
special destinations for remote mode;
|
|
208
|
+
- permits custom local mode only on loopback;
|
|
209
|
+
- bounds request/response bytes, tool schemas/results, tool calls, iterations,
|
|
210
|
+
history, time, and reported tokens.
|
|
211
|
+
|
|
212
|
+
No URL, model, header, or destination comes from model output.
|
|
213
|
+
|
|
214
|
+
## Fixed Session Bounds
|
|
215
|
+
|
|
216
|
+
The current release enforces:
|
|
217
|
+
|
|
218
|
+
| Item | Bound |
|
|
219
|
+
| --- | ---: |
|
|
220
|
+
| Question | 4,000 characters |
|
|
221
|
+
| Model identifier | 128 characters |
|
|
222
|
+
| Provider request | 256 KiB |
|
|
223
|
+
| Provider response | 1 MiB |
|
|
224
|
+
| Tool schema surface | 128 KiB and 64 tools |
|
|
225
|
+
| One tool result | 128 KiB |
|
|
226
|
+
| Tool calls | 4 per provider response, 8 per turn |
|
|
227
|
+
| Tool-loop iterations | 6 |
|
|
228
|
+
| Conversation history | 4 completed turns, 16 KiB |
|
|
229
|
+
| Final answer | 16 KiB |
|
|
230
|
+
| Provider request timeout | 30 seconds |
|
|
231
|
+
| Reported session token usage | 50,000 tokens |
|
|
232
|
+
|
|
233
|
+
One Workbench Ask session runs one request at a time. Runner does not
|
|
234
|
+
automatically retry provider calls in this release. A developer may retry a
|
|
235
|
+
known safe failure from the UI; every retry begins with current authority
|
|
236
|
+
validation. Token accounting depends on usage reported by the provider and is
|
|
237
|
+
not a monetary spend guarantee.
|
|
238
|
+
|
|
239
|
+
## Tested Provider Matrix
|
|
240
|
+
|
|
241
|
+
Status as of the prepared 1.6.4 source:
|
|
242
|
+
|
|
243
|
+
| Provider surface | Verification | Claim |
|
|
244
|
+
| --- | --- | --- |
|
|
245
|
+
| OpenAI `gpt-5-mini` | Live packed-Workbench run against real local PostgreSQL on 2026-07-25 | Live tested |
|
|
246
|
+
| Anthropic Messages/tool-use protocol | Deterministic mock server, normal/refusal/error paths | Protocol tested; no live Anthropic account run |
|
|
247
|
+
| Custom OpenAI-compatible loopback | Real local HTTP server plus deterministic tool/refusal/proposal paths | Tested against the documented Chat Completions subset |
|
|
248
|
+
| Ollama or another named compatible server | Not installed in the release environment | Unknown until tested; compatibility is not implied by the label |
|
|
249
|
+
|
|
250
|
+
The live OpenAI run used `app.describe_data` and `app.explore_data`, matched the
|
|
251
|
+
official MCP aggregate result, changed no source rows, and passed exact-key
|
|
252
|
+
artifact scans. See
|
|
253
|
+
`development/runner-1.6.4-community-solar-results.json`.
|
|
254
|
+
|
|
255
|
+
## Troubleshooting
|
|
256
|
+
|
|
257
|
+
**Ask is missing:** confirm loopback Workbench, an explicit development/staging
|
|
258
|
+
profile, and at least one active reviewed tool. Production intentionally omits
|
|
259
|
+
Ask.
|
|
260
|
+
|
|
261
|
+
**Key required:** export the named variable in the process that launches
|
|
262
|
+
Runner, or use the session-only masked paste. Runner does not load `.env`.
|
|
263
|
+
|
|
264
|
+
**Authority changed:** inspect the new tool/digest summary and acknowledge
|
|
265
|
+
egress again. Do not bypass the check.
|
|
266
|
+
|
|
267
|
+
**Provider unavailable:** the reviewed boundary and no-model composer remain
|
|
268
|
+
usable. Check provider status, local DNS/TLS, key validity, and model access.
|
|
269
|
+
Runner returns a redacted failure and does not retry automatically.
|
|
270
|
+
|
|
271
|
+
**Custom endpoint refused:** use HTTPS remotely or an exact loopback HTTP URL.
|
|
272
|
+
Private network and metadata endpoints are intentionally blocked.
|
|
273
|
+
|
|
274
|
+
**Provider answers without a tool:** Runner refuses to present prose as a
|
|
275
|
+
database answer until at least one reviewed Synapsor tool succeeds or returns a
|
|
276
|
+
reviewed refusal.
|
|
277
|
+
|
|
278
|
+
**Proposal did not commit:** that is correct. Open the separate operator
|
|
279
|
+
workflow to review, approve, and guardedly apply it.
|
|
@@ -59,9 +59,9 @@ It does not claim distributed exactly-once. See
|
|
|
59
59
|
Use the helper commands before enabling direct SQL writeback:
|
|
60
60
|
|
|
61
61
|
```bash
|
|
62
|
-
npx -y
|
|
63
|
-
npx -y
|
|
64
|
-
npx -y
|
|
62
|
+
npx -y @synapsor/runner writeback doctor --config ./synapsor.runner.json
|
|
63
|
+
npx -y @synapsor/runner writeback migration --engine postgres
|
|
64
|
+
npx -y @synapsor/runner writeback grants --engine postgres --writer-role app_writer
|
|
65
65
|
```
|
|
66
66
|
|
|
67
67
|
`writeback doctor --check-db` connects with the configured writer credential and
|
|
@@ -106,7 +106,7 @@ literal values.
|
|
|
106
106
|
Run after approval:
|
|
107
107
|
|
|
108
108
|
```bash
|
|
109
|
-
npx -y
|
|
109
|
+
npx -y @synapsor/runner apply \
|
|
110
110
|
--proposal wrp_123 \
|
|
111
111
|
--config ./synapsor.runner.json \
|
|
112
112
|
--store ./.synapsor/local.db
|
|
@@ -199,13 +199,13 @@ handler receipt.
|
|
|
199
199
|
Or generate one into your app:
|
|
200
200
|
|
|
201
201
|
```bash
|
|
202
|
-
npx -y
|
|
202
|
+
npx -y @synapsor/runner handler template node-fastify \
|
|
203
203
|
--output ./synapsor-writeback-handler.mjs
|
|
204
204
|
|
|
205
|
-
npx -y
|
|
205
|
+
npx -y @synapsor/runner handler template python-fastapi \
|
|
206
206
|
--output ./synapsor_writeback_handler.py
|
|
207
207
|
|
|
208
|
-
npx -y
|
|
208
|
+
npx -y @synapsor/runner handler template command \
|
|
209
209
|
--output ./synapsor-command-handler.mjs
|
|
210
210
|
```
|
|
211
211
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Auto Boundary Churn Fixture
|
|
2
2
|
|
|
3
|
-
This synthetic staging fixture is the
|
|
3
|
+
This synthetic staging fixture is the original Runner 1.6.0 focused path:
|
|
4
4
|
PostgreSQL, Next.js, Prisma, Cursor-compatible local MCP, and the local
|
|
5
5
|
Workbench.
|
|
6
6
|
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
# Community Solar Clean-Room Fixture
|
|
2
|
+
|
|
3
|
+
This synthetic PostgreSQL and Prisma application exists only for the Runner
|
|
4
|
+
1.6.4 clean-room adoption gate. It contains no production data or credentials.
|
|
5
|
+
|
|
6
|
+
The measured journey starts from a copied packed artifact and this fixture in a
|
|
7
|
+
new temporary directory. Synapsor artifacts are not pre-generated.
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
services:
|
|
2
|
+
postgres:
|
|
3
|
+
image: postgres:16
|
|
4
|
+
environment:
|
|
5
|
+
POSTGRES_DB: community_solar
|
|
6
|
+
POSTGRES_USER: solar_admin
|
|
7
|
+
POSTGRES_PASSWORD: solar_admin_password
|
|
8
|
+
ports:
|
|
9
|
+
- "127.0.0.1:55464:5432"
|
|
10
|
+
healthcheck:
|
|
11
|
+
test: ["CMD-SHELL", "test \"$(psql -U solar_admin -d community_solar -tAc \"SELECT pg_postmaster_start_time() > initialized_at FROM public.synapsor_fixture_ready LIMIT 1\" 2>/dev/null | xargs)\" = t"]
|
|
12
|
+
interval: 1s
|
|
13
|
+
timeout: 3s
|
|
14
|
+
retries: 60
|
|
15
|
+
volumes:
|
|
16
|
+
- ./seed/postgres.sql:/docker-entrypoint-initdb.d/001-schema.sql:ro
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "synapsor-community-solar-clean-room",
|
|
3
|
+
"version": "0.0.0",
|
|
4
|
+
"private": true,
|
|
5
|
+
"dependencies": {
|
|
6
|
+
"@prisma/client": "^6.0.0",
|
|
7
|
+
"next": "^15.0.0",
|
|
8
|
+
"react": "^19.0.0",
|
|
9
|
+
"react-dom": "^19.0.0"
|
|
10
|
+
},
|
|
11
|
+
"devDependencies": {
|
|
12
|
+
"prisma": "^6.0.0",
|
|
13
|
+
"typescript": "^5.8.0"
|
|
14
|
+
}
|
|
15
|
+
}
|
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
generator client {
|
|
2
|
+
provider = "prisma-client-js"
|
|
3
|
+
}
|
|
4
|
+
|
|
5
|
+
datasource db {
|
|
6
|
+
provider = "postgresql"
|
|
7
|
+
url = env("DATABASE_URL")
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
model Cooperative {
|
|
11
|
+
id String @id
|
|
12
|
+
name String
|
|
13
|
+
regions Region[]
|
|
14
|
+
teams TechnicianTeam[]
|
|
15
|
+
technicians Technician[]
|
|
16
|
+
sites SolarSite[]
|
|
17
|
+
models InverterModel[]
|
|
18
|
+
workOrders WorkOrder[]
|
|
19
|
+
incidents Incident[]
|
|
20
|
+
|
|
21
|
+
@@map("cooperatives")
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
model Region {
|
|
25
|
+
id String @id
|
|
26
|
+
cooperativeId String @map("cooperative_id")
|
|
27
|
+
name String
|
|
28
|
+
climateZone String @map("climate_zone")
|
|
29
|
+
cooperative Cooperative @relation(fields: [cooperativeId], references: [id])
|
|
30
|
+
sites SolarSite[]
|
|
31
|
+
workOrders WorkOrder[]
|
|
32
|
+
incidents Incident[]
|
|
33
|
+
|
|
34
|
+
@@unique([cooperativeId, name])
|
|
35
|
+
@@map("regions")
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
model TechnicianTeam {
|
|
39
|
+
id String @id
|
|
40
|
+
cooperativeId String @map("cooperative_id")
|
|
41
|
+
name String
|
|
42
|
+
cooperative Cooperative @relation(fields: [cooperativeId], references: [id])
|
|
43
|
+
technicians Technician[]
|
|
44
|
+
workOrders WorkOrder[]
|
|
45
|
+
|
|
46
|
+
@@unique([cooperativeId, name])
|
|
47
|
+
@@map("technician_teams")
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
model Technician {
|
|
51
|
+
id String @id
|
|
52
|
+
cooperativeId String @map("cooperative_id")
|
|
53
|
+
teamId String @map("team_id")
|
|
54
|
+
displayName String @map("display_name")
|
|
55
|
+
privateNotes String @map("private_technician_notes")
|
|
56
|
+
cooperative Cooperative @relation(fields: [cooperativeId], references: [id])
|
|
57
|
+
team TechnicianTeam @relation(fields: [teamId], references: [id])
|
|
58
|
+
workOrders WorkOrder[]
|
|
59
|
+
|
|
60
|
+
@@map("technicians")
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
model SolarSite {
|
|
64
|
+
id String @id
|
|
65
|
+
cooperativeId String @map("cooperative_id")
|
|
66
|
+
regionId String @map("region_id")
|
|
67
|
+
name String
|
|
68
|
+
siteGroup String @map("site_group")
|
|
69
|
+
cooperative Cooperative @relation(fields: [cooperativeId], references: [id])
|
|
70
|
+
region Region @relation(fields: [regionId], references: [id])
|
|
71
|
+
inverters Inverter[]
|
|
72
|
+
workOrders WorkOrder[]
|
|
73
|
+
incidents Incident[]
|
|
74
|
+
|
|
75
|
+
@@unique([cooperativeId, name])
|
|
76
|
+
@@map("solar_sites")
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
model InverterModel {
|
|
80
|
+
id String @id
|
|
81
|
+
cooperativeId String @map("cooperative_id")
|
|
82
|
+
manufacturer String
|
|
83
|
+
modelName String @map("model_name")
|
|
84
|
+
cooperative Cooperative @relation(fields: [cooperativeId], references: [id])
|
|
85
|
+
inverters Inverter[]
|
|
86
|
+
workOrders WorkOrder[]
|
|
87
|
+
incidents Incident[]
|
|
88
|
+
|
|
89
|
+
@@unique([cooperativeId, manufacturer, modelName])
|
|
90
|
+
@@map("inverter_models")
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
model Inverter {
|
|
94
|
+
id String @id
|
|
95
|
+
cooperativeId String @map("cooperative_id")
|
|
96
|
+
siteId String @map("site_id")
|
|
97
|
+
inverterModelId String @map("inverter_model_id")
|
|
98
|
+
serialNumber String @map("serial_number")
|
|
99
|
+
accessToken String @map("access_token")
|
|
100
|
+
panelPosition String @map("panel_position")
|
|
101
|
+
site SolarSite @relation(fields: [siteId], references: [id])
|
|
102
|
+
model InverterModel @relation(fields: [inverterModelId], references: [id])
|
|
103
|
+
|
|
104
|
+
@@unique([cooperativeId, serialNumber])
|
|
105
|
+
@@map("inverters")
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
model FaultCategory {
|
|
109
|
+
id String @id
|
|
110
|
+
cooperativeId String @map("cooperative_id")
|
|
111
|
+
name String
|
|
112
|
+
severity String
|
|
113
|
+
incidents Incident[]
|
|
114
|
+
workOrders WorkOrder[]
|
|
115
|
+
|
|
116
|
+
@@unique([cooperativeId, name])
|
|
117
|
+
@@map("fault_categories")
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
model WorkOrder {
|
|
121
|
+
id String @id
|
|
122
|
+
cooperativeId String @map("cooperative_id")
|
|
123
|
+
siteId String @map("site_id")
|
|
124
|
+
regionId String @map("region_id")
|
|
125
|
+
inverterModelId String @map("inverter_model_id")
|
|
126
|
+
faultCategoryId String @map("fault_category_id")
|
|
127
|
+
assignedTechnicianId String @map("assigned_technician_id")
|
|
128
|
+
technicianTeamId String @map("technician_team_id")
|
|
129
|
+
status String
|
|
130
|
+
openedAt DateTime @map("opened_at") @db.Timestamptz(6)
|
|
131
|
+
completedAt DateTime? @map("completed_at") @db.Timestamptz(6)
|
|
132
|
+
downtimeMinutes Int @map("downtime_minutes")
|
|
133
|
+
repairDurationMinutes Int @map("repair_duration_minutes")
|
|
134
|
+
estimatedEnergyLossWh Int @map("estimated_energy_loss_wh")
|
|
135
|
+
lostRevenueCents Int @map("lost_revenue_cents")
|
|
136
|
+
inspectionFailed Boolean @map("inspection_failed")
|
|
137
|
+
version Int
|
|
138
|
+
privateTechnicianNotes String @map("private_technician_notes")
|
|
139
|
+
cooperative Cooperative @relation(fields: [cooperativeId], references: [id])
|
|
140
|
+
site SolarSite @relation(fields: [siteId], references: [id])
|
|
141
|
+
region Region @relation(fields: [regionId], references: [id])
|
|
142
|
+
inverterModel InverterModel @relation(fields: [inverterModelId], references: [id])
|
|
143
|
+
faultCategory FaultCategory @relation(fields: [faultCategoryId], references: [id])
|
|
144
|
+
assignedTechnician Technician @relation(fields: [assignedTechnicianId], references: [id])
|
|
145
|
+
technicianTeam TechnicianTeam @relation(fields: [technicianTeamId], references: [id])
|
|
146
|
+
|
|
147
|
+
@@index([cooperativeId, assignedTechnicianId, openedAt])
|
|
148
|
+
@@map("work_orders")
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
model Incident {
|
|
152
|
+
id String @id
|
|
153
|
+
cooperativeId String @map("cooperative_id")
|
|
154
|
+
siteId String @map("site_id")
|
|
155
|
+
regionId String @map("region_id")
|
|
156
|
+
inverterModelId String @map("inverter_model_id")
|
|
157
|
+
faultCategoryId String @map("fault_category_id")
|
|
158
|
+
status String
|
|
159
|
+
occurredAt DateTime @map("occurred_at") @db.Timestamptz(6)
|
|
160
|
+
resolvedAt DateTime? @map("resolved_at") @db.Timestamptz(6)
|
|
161
|
+
downtimeMinutes Int @map("downtime_minutes")
|
|
162
|
+
estimatedEnergyLossWh Int @map("estimated_energy_loss_wh")
|
|
163
|
+
cooperative Cooperative @relation(fields: [cooperativeId], references: [id])
|
|
164
|
+
site SolarSite @relation(fields: [siteId], references: [id])
|
|
165
|
+
region Region @relation(fields: [regionId], references: [id])
|
|
166
|
+
inverterModel InverterModel @relation(fields: [inverterModelId], references: [id])
|
|
167
|
+
faultCategory FaultCategory @relation(fields: [faultCategoryId], references: [id])
|
|
168
|
+
|
|
169
|
+
@@index([cooperativeId, occurredAt])
|
|
170
|
+
@@map("incidents")
|
|
171
|
+
}
|