@synapsor/runner 1.6.3 → 1.6.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +2 -2
- package/CHANGELOG.md +94 -8
- package/CONTRIBUTING.md +10 -3
- package/README.md +90 -109
- package/SECURITY.md +7 -3
- package/THREAT_MODEL.md +37 -0
- package/dist/authoring.mjs +98 -13
- package/dist/cli.d.ts +12 -1
- package/dist/cli.d.ts.map +1 -1
- package/dist/local-ui.d.ts +60 -0
- package/dist/local-ui.d.ts.map +1 -1
- package/dist/runner.mjs +7688 -2227
- package/dist/runtime.mjs +528 -51
- package/docs/README.md +14 -0
- package/docs/agent-guided-setup.md +13 -11
- package/docs/aggregate-reads.md +14 -5
- package/docs/app-owned-executors.md +5 -6
- package/docs/auto-boundary-and-scoped-explore.md +70 -14
- package/docs/capability-authoring.md +2 -2
- package/docs/client-recipes.md +41 -12
- package/docs/cloud-mode.md +7 -7
- package/docs/conformance.md +6 -3
- package/docs/current-scope.md +13 -2
- package/docs/cursor-plugin.md +3 -3
- package/docs/database-enforced-scope.md +6 -0
- package/docs/dsl-reference.md +12 -1
- package/docs/fresh-developer-usability.md +6 -6
- package/docs/getting-started-own-database.md +52 -50
- package/docs/guided-onboarding.md +104 -34
- package/docs/host-compatibility.md +24 -11
- package/docs/limitations.md +34 -14
- package/docs/local-mode.md +20 -20
- package/docs/mcp-audit.md +14 -14
- package/docs/mcp-client-setup.md +26 -14
- package/docs/mcp-clients.md +47 -11
- package/docs/migrating-to-synapsor-spec.md +5 -1
- package/docs/openai-agents-sdk.md +2 -2
- package/docs/proposal-evidence-freshness.md +7 -7
- package/docs/recipes.md +6 -6
- package/docs/release-notes.md +100 -10
- 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/schema-api-candidates.md +1 -1
- package/docs/security-boundary.md +30 -0
- package/docs/troubleshooting-first-run.md +63 -19
- 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 +2 -2
- 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/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/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 +9 -2
package/docs/release-notes.md
CHANGED
|
@@ -4,18 +4,111 @@ These notes track public Synapsor Runner behavior. Starting with `1.0.0`, the
|
|
|
4
4
|
documented production-loop compatibility line uses the untagged stable package:
|
|
5
5
|
|
|
6
6
|
```bash
|
|
7
|
-
npx -y
|
|
7
|
+
npx -y @synapsor/runner demo --quick
|
|
8
8
|
```
|
|
9
9
|
|
|
10
10
|
The OSS runner command is `synapsor-runner`. The `synapsor` command is reserved
|
|
11
11
|
for the Synapsor Cloud CLI.
|
|
12
12
|
|
|
13
|
-
## 1.6.
|
|
13
|
+
## 1.6.5 (prepared, not published)
|
|
14
|
+
|
|
15
|
+
### Managed Claude Code and VS Code project MCP installs
|
|
16
|
+
|
|
17
|
+
- The same reviewed, backup-producing project lifecycle previously available
|
|
18
|
+
for Cursor now manages Claude Code `.mcp.json` and VS Code
|
|
19
|
+
`.vscode/mcp.json`.
|
|
20
|
+
- Install previews preserve unrelated project settings, pin the exact Runner
|
|
21
|
+
version, write no credentials or trusted scope, and refuse unowned or
|
|
22
|
+
tampered `synapsor` entries. Reinstall is idempotent and uninstall removes
|
|
23
|
+
only Runner's intact entry.
|
|
24
|
+
- VS Code JSONC comments and trailing commas survive install and uninstall.
|
|
25
|
+
`mcp status <client> --project --check-launch` validates the generated
|
|
26
|
+
command against the exact reviewed MCP tool list.
|
|
27
|
+
- README, Workbench, onboarding, host recipes, and `doctor` now present Cursor,
|
|
28
|
+
Claude Code, and VS Code as peer project clients. Existing Cursor commands
|
|
29
|
+
and configuration remain compatible.
|
|
30
|
+
|
|
31
|
+
Prepared package versions: `@synapsor/runner@1.6.5` and
|
|
32
|
+
`synapsor-runner@1.6.5`. Spec 1.7.0 and DSL 1.7.0 are unchanged. No package is
|
|
33
|
+
published by this change.
|
|
34
|
+
|
|
35
|
+
## 1.6.4 (published 2026-07-25)
|
|
36
|
+
|
|
37
|
+
### Review-correct onboarding and reviewed relationship paths
|
|
38
|
+
|
|
39
|
+
- Generated-boundary review now uses dependency-scoped invalidation and stale
|
|
40
|
+
revision checks. Editing one resource does not erase unrelated human
|
|
41
|
+
decisions, while stale browser state cannot overwrite a newer review.
|
|
42
|
+
- Workbench starts with a small useful resource pack, explains current agent
|
|
43
|
+
authority and source-change status in plain language, keeps advanced
|
|
44
|
+
permissions behind progressive disclosure, and preserves one recommended
|
|
45
|
+
next action. Project resume and nested config discovery retain existing work.
|
|
46
|
+
- A fresh `npx -y @synapsor/runner start` can accept the database URL through a
|
|
47
|
+
hidden terminal prompt, or load only a selected `DATABASE_URL` from an
|
|
48
|
+
explicitly confirmed local environment file. In the conservative local
|
|
49
|
+
development fast lane, at most two plain questions and one recorded
|
|
50
|
+
digest-bound human gesture lead to a real read without exporting the URL,
|
|
51
|
+
editing generated files, or weakening staging/production review.
|
|
52
|
+
- Deterministic classification is more conservative across unfamiliar domains.
|
|
53
|
+
Database, Prisma, Drizzle, OpenAPI, and existing Synapsor evidence can improve
|
|
54
|
+
names and structure but cannot grant authority or resolve ambiguous trusted
|
|
55
|
+
scope.
|
|
56
|
+
- Protected aggregate reads may contain up to three activated reviewed
|
|
57
|
+
relationship paths. Each path has one or two catalog-proven many-to-one
|
|
58
|
+
links with fan-out one. The model can select an activated path by name but
|
|
59
|
+
cannot provide a table, key, join type, or activation decision.
|
|
60
|
+
- A question needing an inactive proven path fails closed and stages that exact
|
|
61
|
+
path for operator review. Optional links require an explicit missing-row
|
|
62
|
+
choice because excluding versus retaining an unmatched counted row can change
|
|
63
|
+
totals. The reviewed choice and structural proof are digest-bound.
|
|
64
|
+
- Scope is enforced independently on every relation. Cohort suppression runs
|
|
65
|
+
after final grouping. One-to-many, many-to-many, ambiguous, stale, over-depth,
|
|
66
|
+
and model-improvised joins remain refused; complex formulas and relationship
|
|
67
|
+
graphs use reviewed database views.
|
|
68
|
+
- Packed Community Solar and Retail clean-room journeys and live
|
|
69
|
+
PostgreSQL/MySQL relationship gates cover unfamiliar-domain onboarding,
|
|
70
|
+
PM-style analysis, demand-driven review, nullable semantics, drift,
|
|
71
|
+
suppression, scope, and deliberate fan-out rejection.
|
|
72
|
+
- Workbench now offers an optional local **Ask with your model** client over the
|
|
73
|
+
exact active MCP/runtime tools. OpenAI, Anthropic, and custom
|
|
74
|
+
OpenAI-compatible adapters use explicit digest-bound direct-egress consent,
|
|
75
|
+
in-memory credentials/history, bounded tool loops, escaped provider prose,
|
|
76
|
+
and proposal-only writes. The no-model composer remains the default.
|
|
77
|
+
- Remote provider requests use fixed official origins or an operator-selected
|
|
78
|
+
HTTPS custom origin, refuse redirects, validate and pin DNS on every
|
|
79
|
+
connection, block private/special/metadata targets, redact errors, and
|
|
80
|
+
support Node 22's multi-address lookup contract. Plain HTTP remains
|
|
81
|
+
loopback-only.
|
|
82
|
+
- Both packed clean-room domains now pass the real Ask UI. The Retail journey
|
|
83
|
+
shows a kept-out-field refusal; Community Solar shows a source-unchanged
|
|
84
|
+
proposal. An owner-authorized live OpenAI `gpt-5-mini` acceptance run used
|
|
85
|
+
the same official-MCP path, matched its aggregate result, and passed exact-key
|
|
86
|
+
project/ledger/browser/output/evidence scans. Anthropic and generic
|
|
87
|
+
compatible claims are limited to the documented tested protocol matrix.
|
|
88
|
+
- Human-facing commands now use the shortest true form: direct `npx` for first
|
|
89
|
+
acquisition and `synapsor-runner <command>` after installation. The optional
|
|
90
|
+
unscoped `synapsor-runner` npm package contains no runtime or authority logic;
|
|
91
|
+
it delegates to the exact matching scoped Runner version. Existing explicit
|
|
92
|
+
package, pinned, CI, and machine-readable invocations remain compatible.
|
|
93
|
+
- Generated DSL previews use one local, escaped, copy-exact syntax highlighter
|
|
94
|
+
in light and dark themes with no CDN or unsafe HTML fallback. Activity and
|
|
95
|
+
human review details use the full Workbench width instead of a compressed
|
|
96
|
+
side column, including mobile layouts.
|
|
97
|
+
- Existing hand-authored and published `1.6.3` projects do not need the new
|
|
98
|
+
relationship fields, generation review, or Workbench. Legacy contracts keep
|
|
99
|
+
their exact normalized bytes/digests and existing tool lists remain
|
|
100
|
+
unchanged unless the feature is adopted.
|
|
101
|
+
|
|
102
|
+
Published package versions: `@synapsor/runner@1.6.4`,
|
|
103
|
+
`@synapsor/spec@1.7.0`, `@synapsor/dsl@1.7.0`, and the optional
|
|
104
|
+
`synapsor-runner@1.6.4` command alias.
|
|
105
|
+
|
|
106
|
+
## 1.6.3 (published 2026-07-24)
|
|
14
107
|
|
|
15
108
|
### Guided adoption without weaker authority
|
|
16
109
|
|
|
17
110
|
- A fresh interactive
|
|
18
|
-
`npx -y @synapsor/runner
|
|
111
|
+
`npx -y @synapsor/runner start --from-env DATABASE_URL` now drives one
|
|
19
112
|
resumable metadata-inspection, review-by-exception, exact-digest activation,
|
|
20
113
|
first safe read, and MCP setup journey. It requires no account, model key,
|
|
21
114
|
Cloud control plane, global install, or manual project files.
|
|
@@ -65,14 +158,11 @@ for the Synapsor Cloud CLI.
|
|
|
65
158
|
advance to `1.6.0` while preserving old contract normalization, digests, and
|
|
66
159
|
generated-lock support.
|
|
67
160
|
|
|
68
|
-
|
|
161
|
+
Published package versions: `@synapsor/runner@1.6.3`,
|
|
69
162
|
`@synapsor/spec@1.6.0`, and `@synapsor/dsl@1.6.0`.
|
|
70
|
-
No package is published by this change.
|
|
71
163
|
|
|
72
|
-
The pre-release clean-install gate
|
|
73
|
-
Spec 1.6.0
|
|
74
|
-
Runner dependency check with
|
|
75
|
-
`VERIFY_PACKED_RUNNER_USE_LOCAL_SPEC=0 ./scripts/verify-packed-runner.sh`.
|
|
164
|
+
The pre-release clean-install gate used the locally packed public Spec until
|
|
165
|
+
Spec 1.6.0 reached npm, then returned to the registry-only dependency proof.
|
|
76
166
|
|
|
77
167
|
## 1.6.2 (published 2026-07-23)
|
|
78
168
|
|
|
@@ -705,7 +795,7 @@ not change and must not be republished for this release.
|
|
|
705
795
|
### Public npm DX
|
|
706
796
|
|
|
707
797
|
- Prepares the spec-ready Runner package for the normal untagged npm path so
|
|
708
|
-
developers can use `npx -y
|
|
798
|
+
developers can use `npx -y @synapsor/runner ...` without
|
|
709
799
|
knowing about the temporary `next` release-candidate tag.
|
|
710
800
|
- Keeps the same contract/spec functionality as `0.1.2`; this is a release
|
|
711
801
|
hygiene patch for public install and README/package-page verification.
|
package/docs/release-policy.md
CHANGED
|
@@ -7,7 +7,7 @@ shared runtime-store deployment are part of the documented compatibility
|
|
|
7
7
|
surface. Use the stable package for normal installs:
|
|
8
8
|
|
|
9
9
|
```bash
|
|
10
|
-
npx -y
|
|
10
|
+
npx -y @synapsor/runner demo --quick
|
|
11
11
|
npm install -g @synapsor/runner
|
|
12
12
|
```
|
|
13
13
|
|
|
@@ -38,9 +38,10 @@ Alpha releases must keep the safety boundary intact:
|
|
|
38
38
|
- no generic model-generated INSERT/DELETE/UPSERT/DDL/multi-row SQL;
|
|
39
39
|
- proposal-first write path stays explicit.
|
|
40
40
|
|
|
41
|
-
## Stable Expectations
|
|
41
|
+
## Stable Release Expectations
|
|
42
42
|
|
|
43
|
-
|
|
43
|
+
Every stable release must preserve the safety boundary and should be tagged
|
|
44
|
+
only after:
|
|
44
45
|
|
|
45
46
|
- npm README commands match the published package;
|
|
46
47
|
- `synapsor-runner demo --quick` works from a clean directory;
|
|
@@ -62,7 +63,7 @@ A stable `0.1.0` release should only be tagged after:
|
|
|
62
63
|
- there are no known docs/code mismatches around transport, credentials,
|
|
63
64
|
receipt tables, or handler expectations.
|
|
64
65
|
|
|
65
|
-
## 1.0 Stability Gate
|
|
66
|
+
## Historical 1.0 Stability Gate
|
|
66
67
|
|
|
67
68
|
Do not tag `1.0.0` only because the package is useful. `1.0.0` is the public
|
|
68
69
|
semver contract for the Runner production approval loop, and it should be cut
|
|
@@ -89,7 +90,7 @@ versioning. Breaking changes require a new major version, except for security
|
|
|
89
90
|
fixes that close a vulnerability while preserving the safest possible
|
|
90
91
|
compatibility path.
|
|
91
92
|
|
|
92
|
-
## 1.1 Fleet Gate
|
|
93
|
+
## Historical 1.1 Fleet Gate
|
|
93
94
|
|
|
94
95
|
Do not publish `1.1.0` until all 1.0 gates remain green and the local synthetic
|
|
95
96
|
fleet verifier proves:
|
|
@@ -167,15 +168,27 @@ Before publishing any release:
|
|
|
167
168
|
./scripts/verify-release-gate.sh
|
|
168
169
|
```
|
|
169
170
|
|
|
171
|
+
For a coordinated Spec/DSL/Runner release, publish in dependency order:
|
|
172
|
+
|
|
173
|
+
1. `@synapsor/spec`;
|
|
174
|
+
2. `@synapsor/dsl`;
|
|
175
|
+
3. `@synapsor/runner`;
|
|
176
|
+
4. the optional `synapsor-runner` command alias, when prepared.
|
|
177
|
+
|
|
178
|
+
The alias must have the same version as the scoped Runner and depend on that
|
|
179
|
+
exact registry version. It contains no independent runtime or authority logic.
|
|
180
|
+
Run `corepack pnpm verify:packed-runner-alias` before publishing it, and do not
|
|
181
|
+
publish it until the matching scoped Runner is visible on npm.
|
|
182
|
+
|
|
170
183
|
After publishing an alpha prerelease:
|
|
171
184
|
|
|
172
185
|
```bash
|
|
173
|
-
VERIFY_PUBLISHED_ALPHA=1 ./scripts/verify-release-gate.sh
|
|
186
|
+
VERIFY_PUBLISHED_ALPHA=1 ./scripts/verify-release-gate.sh <prerelease-version>
|
|
174
187
|
```
|
|
175
188
|
|
|
176
189
|
After publishing/promoting stable `latest`, verify the stable channel from a
|
|
177
190
|
clean temporary directory:
|
|
178
191
|
|
|
179
192
|
```bash
|
|
180
|
-
./scripts/verify-published-stable.sh
|
|
193
|
+
./scripts/verify-published-stable.sh <stable-version>
|
|
181
194
|
```
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Reviewed Reversible Change Sets
|
|
2
2
|
|
|
3
|
-
Synapsor Runner
|
|
3
|
+
Synapsor Runner can capture a bounded inverse for an opt-in direct database
|
|
4
4
|
write. This is **reviewed compensation**, not rollback or database time travel.
|
|
5
5
|
|
|
6
6
|
The operator flow is deliberately two separate approval loops:
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
# Reviewed Database Views For Derived Measures
|
|
2
|
+
|
|
3
|
+
Scoped Explore deliberately has no formula or expression language. The model
|
|
4
|
+
cannot invent ratios, arithmetic, functions, subqueries, or joins. When a
|
|
5
|
+
useful measure needs reviewed database logic, put that logic in a
|
|
6
|
+
database-owned view and expose only the resulting typed column through a named
|
|
7
|
+
Synapsor capability.
|
|
8
|
+
|
|
9
|
+
The authority split is:
|
|
10
|
+
|
|
11
|
+
```text
|
|
12
|
+
Database owner reviews formula, joins, cardinality, and base-table scope
|
|
13
|
+
-> view publishes a small typed row shape
|
|
14
|
+
-> contract author reviews the view columns and fixed predicate
|
|
15
|
+
-> Runner applies trusted scope and the named aggregate
|
|
16
|
+
-> model receives one scalar, never SQL or member rows
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
This is an explicit escape hatch, not automatic generation. Auto Boundary
|
|
20
|
+
blocks a view whose row identity cannot be proven from catalog metadata. Review
|
|
21
|
+
the view definition, scope, uniqueness, and grants before hand-authoring a
|
|
22
|
+
capability.
|
|
23
|
+
|
|
24
|
+
## PostgreSQL Hardened Pattern
|
|
25
|
+
|
|
26
|
+
Use a `security_invoker` view so PostgreSQL checks permissions and row-level
|
|
27
|
+
security (RLS) as the Runner read role, not as the view owner. A
|
|
28
|
+
`security_barrier` also prevents unsafe predicate movement across the view
|
|
29
|
+
boundary.
|
|
30
|
+
|
|
31
|
+
The retail clean-room fixture defines this reviewed ratio:
|
|
32
|
+
|
|
33
|
+
```sql
|
|
34
|
+
CREATE VIEW public.reviewed_order_performance
|
|
35
|
+
WITH (security_barrier = true, security_invoker = true) AS
|
|
36
|
+
SELECT
|
|
37
|
+
orders.id AS order_id,
|
|
38
|
+
orders.merchant_id,
|
|
39
|
+
orders.assigned_manager_id,
|
|
40
|
+
orders.region_id,
|
|
41
|
+
ROUND(
|
|
42
|
+
(orders.net_revenue_cents::numeric /
|
|
43
|
+
NULLIF(orders.gross_revenue_cents, 0)) * 10000
|
|
44
|
+
)::integer AS net_revenue_retention_basis_points
|
|
45
|
+
FROM public.orders;
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
The formula is fixed in a reviewed database migration. The model sees only
|
|
49
|
+
`net_revenue_retention_basis_points`. It cannot change the numerator,
|
|
50
|
+
denominator, scale, or source relation.
|
|
51
|
+
|
|
52
|
+
For `database_scope.mode = "postgres_rls"`, Runner accepts a read view only
|
|
53
|
+
when all of these checks pass:
|
|
54
|
+
|
|
55
|
+
- the target is a normal PostgreSQL view used for `SELECT`;
|
|
56
|
+
- both `security_invoker=true` and `security_barrier=true` are present;
|
|
57
|
+
- the Runner role is not the view owner, a superuser, or `BYPASSRLS`;
|
|
58
|
+
- every referenced table or nested view can be resolved from the catalog;
|
|
59
|
+
- every referenced base table independently passes the existing FORCE RLS,
|
|
60
|
+
role, policy-operation, and trusted-setting checks;
|
|
61
|
+
- every nested view passes the same view checks.
|
|
62
|
+
|
|
63
|
+
An ordinary owner-rights view, an unverifiable dependency, a missing RLS
|
|
64
|
+
setting, or any non-read operation fails closed before MCP serving.
|
|
65
|
+
|
|
66
|
+
## Named Aggregate
|
|
67
|
+
|
|
68
|
+
The public DSL fixes the trusted scope, formula output, region, aggregate, and
|
|
69
|
+
minimum cohort:
|
|
70
|
+
|
|
71
|
+
```sql
|
|
72
|
+
CREATE AGENT CONTEXT retail_analytics_context
|
|
73
|
+
BIND tenant_id FROM ENVIRONMENT SYNAPSOR_TENANT_ID REQUIRED
|
|
74
|
+
BIND principal FROM ENVIRONMENT SYNAPSOR_PRINCIPAL REQUIRED
|
|
75
|
+
TENANT BINDING tenant_id
|
|
76
|
+
PRINCIPAL BINDING principal
|
|
77
|
+
END
|
|
78
|
+
|
|
79
|
+
CREATE CAPABILITY retail.average_net_revenue_retention_pacific
|
|
80
|
+
DESCRIPTION 'Return the privacy-suppressed average net-to-gross revenue retention rate for Pacific orders assigned to the trusted manager.'
|
|
81
|
+
RETURNS HINT 'Returns one scalar average in basis points or a suppression result; never order rows.'
|
|
82
|
+
USING CONTEXT retail_analytics_context
|
|
83
|
+
SOURCE retail_postgres
|
|
84
|
+
ON public.reviewed_order_performance
|
|
85
|
+
PRIMARY KEY order_id
|
|
86
|
+
TENANT KEY merchant_id
|
|
87
|
+
PRINCIPAL SCOPE KEY assigned_manager_id
|
|
88
|
+
AGGREGATE READ AVG net_revenue_retention_basis_points
|
|
89
|
+
SELECT WHERE region_id = 'region-pacific'
|
|
90
|
+
MIN GROUP SIZE 5
|
|
91
|
+
REQUIRE EVIDENCE
|
|
92
|
+
END
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
Validate, compile, validate the Runner config, and serve:
|
|
96
|
+
|
|
97
|
+
```bash
|
|
98
|
+
npx -y @synapsor/runner dsl validate \
|
|
99
|
+
./average-retained-revenue.synapsor.sql --strict
|
|
100
|
+
|
|
101
|
+
npx -y @synapsor/runner dsl compile \
|
|
102
|
+
./average-retained-revenue.synapsor.sql \
|
|
103
|
+
--out ./average-retained-revenue.contract.json \
|
|
104
|
+
--strict
|
|
105
|
+
|
|
106
|
+
npx -y @synapsor/runner config validate \
|
|
107
|
+
--config ./synapsor.runner.json
|
|
108
|
+
|
|
109
|
+
npx -y @synapsor/runner mcp serve \
|
|
110
|
+
--config ./synapsor.runner.json
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
The runnable packaged recipe is under
|
|
114
|
+
`examples/retail-clean-room/view-recipe/`. Its clean-room gate proves that the
|
|
115
|
+
result is exactly `9000` basis points for the trusted fixture scope, includes
|
|
116
|
+
no member rows, and does not change the source database.
|
|
117
|
+
|
|
118
|
+
## Review Checklist
|
|
119
|
+
|
|
120
|
+
1. Prove the view has one intended row per counted entity.
|
|
121
|
+
2. Prove joins cannot multiply rows or silently double-count values.
|
|
122
|
+
3. Apply tenant and, where required, principal scope to every base relation.
|
|
123
|
+
4. Keep sensitive source columns out of the view output.
|
|
124
|
+
5. Grant the Runner role only `SELECT` on the view and required base objects.
|
|
125
|
+
6. Test same-tenant other-principal and cross-tenant denial.
|
|
126
|
+
7. Test zero denominators, nulls, rounding, and numeric overflow.
|
|
127
|
+
8. Keep cohort suppression and result limits in the Synapsor capability.
|
|
128
|
+
9. Treat a changed view definition as reviewed authority drift.
|
|
129
|
+
|
|
130
|
+
For complex or ambiguous calculations, keep the capability disabled until the
|
|
131
|
+
database migration, contract, and expected results have all been reviewed
|
|
132
|
+
together.
|
|
@@ -0,0 +1,245 @@
|
|
|
1
|
+
# Reviewed Relationship Paths
|
|
2
|
+
|
|
3
|
+
Synapsor Runner can answer bounded aggregate questions across related tables
|
|
4
|
+
without exposing a general join planner or SQL. The relationship is authority:
|
|
5
|
+
Runner proposes it from database catalog evidence, a human reviews it, and the
|
|
6
|
+
activated boundary fixes its exact path and semantics.
|
|
7
|
+
|
|
8
|
+
This feature is part of local, development/staging-only Scoped Explore.
|
|
9
|
+
Production receives only named capabilities created through Protect This Query.
|
|
10
|
+
|
|
11
|
+
## The Safety Rule
|
|
12
|
+
|
|
13
|
+
A model may select an already activated relationship **by name**. It cannot
|
|
14
|
+
provide a table name, join key, join type, relationship path, or SQL fragment.
|
|
15
|
+
|
|
16
|
+
Runner accepts only:
|
|
17
|
+
|
|
18
|
+
- one to three relationship paths in a protected capability;
|
|
19
|
+
- one or two links per path;
|
|
20
|
+
- inspected foreign-key links whose target key is unique;
|
|
21
|
+
- `many_to_one` cardinality with `max_fan_out: 1`;
|
|
22
|
+
- trusted tenant and, where configured, principal scope on every relation;
|
|
23
|
+
- an explicit human choice for missing related rows.
|
|
24
|
+
|
|
25
|
+
Runner refuses:
|
|
26
|
+
|
|
27
|
+
- one-to-many and many-to-many paths;
|
|
28
|
+
- relationships inferred only from similar column names;
|
|
29
|
+
- ambiguous or unproven cardinality;
|
|
30
|
+
- more than two links in one path;
|
|
31
|
+
- a plan using more than three reviewed paths;
|
|
32
|
+
- a relationship whose catalog proof or generation lock is stale;
|
|
33
|
+
- a related table whose trusted scope cannot be enforced;
|
|
34
|
+
- formulas, derived measures, free-form joins, and model-selected identifiers.
|
|
35
|
+
|
|
36
|
+
These limits permit reviewed star-style analysis. For example, a sales fact can
|
|
37
|
+
group by an activated store path and an activated category path without
|
|
38
|
+
multiplying the counted sales rows.
|
|
39
|
+
|
|
40
|
+
## Why Fan-Out Matters
|
|
41
|
+
|
|
42
|
+
Suppose one `sales_facts` row points to one store. Joining the store cannot
|
|
43
|
+
create more sales rows, so the relationship is many-to-one and has a maximum
|
|
44
|
+
fan-out of one.
|
|
45
|
+
|
|
46
|
+
By contrast, joining a sale to all of its line items can turn one sale into
|
|
47
|
+
several rows. A naive `SUM(sales_facts.amount_cents)` would then overstate
|
|
48
|
+
revenue. Runner refuses that one-to-many path instead of silently returning a
|
|
49
|
+
plausible but wrong number.
|
|
50
|
+
|
|
51
|
+
## Demand-Driven Review
|
|
52
|
+
|
|
53
|
+
Auto Boundary may discover more proven relationships than a developer needs.
|
|
54
|
+
They are not all activated automatically.
|
|
55
|
+
|
|
56
|
+
The intended flow is:
|
|
57
|
+
|
|
58
|
+
1. Activate the small starter boundary.
|
|
59
|
+
2. Ask a bounded aggregate question.
|
|
60
|
+
3. If the question needs an inactive but catalog-proven path, Runner refuses the
|
|
61
|
+
plan and identifies the exact path and proof.
|
|
62
|
+
4. Workbench shows that one relationship for operator review.
|
|
63
|
+
5. The operator chooses missing-row semantics when required and activates the
|
|
64
|
+
exact new boundary digest.
|
|
65
|
+
6. Retry the original question.
|
|
66
|
+
|
|
67
|
+
The model cannot trigger step 5. Adding the path creates new authority, so it is
|
|
68
|
+
an operator-plane action with a new digest. Existing unrelated confirmations
|
|
69
|
+
remain valid; only dependent review state is invalidated.
|
|
70
|
+
|
|
71
|
+
## Nullable Links
|
|
72
|
+
|
|
73
|
+
An optional foreign key requires an explicit business decision:
|
|
74
|
+
|
|
75
|
+
- `UNMATCHED EXCLUDE`: omit a counted row when its related record is missing;
|
|
76
|
+
- `UNMATCHED KEEP NULL`: keep the counted row and return an empty/null group
|
|
77
|
+
value for the missing relationship.
|
|
78
|
+
|
|
79
|
+
This is not cosmetic. The choice can change totals and cohort sizes, so Runner
|
|
80
|
+
does not silently choose it. The decision is stored in the canonical contract
|
|
81
|
+
and bound into its digest.
|
|
82
|
+
|
|
83
|
+
## DSL Syntax
|
|
84
|
+
|
|
85
|
+
The SQL-like Domain-Specific Language (DSL) supports a legacy one-hop form and
|
|
86
|
+
the additive path form. Existing legacy contracts retain their canonical bytes
|
|
87
|
+
and digest.
|
|
88
|
+
|
|
89
|
+
Legacy one-hop form:
|
|
90
|
+
|
|
91
|
+
```sql
|
|
92
|
+
PROTECTED RELATIONSHIP store
|
|
93
|
+
ON store_id
|
|
94
|
+
REFERENCES public.stores.id
|
|
95
|
+
PRIMARY KEY id
|
|
96
|
+
TENANT KEY tenant_id
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
Reviewed path form:
|
|
100
|
+
|
|
101
|
+
```sql
|
|
102
|
+
PROTECTED RELATIONSHIP store LINK 1
|
|
103
|
+
ON store_id
|
|
104
|
+
REFERENCES public.stores.id
|
|
105
|
+
PRIMARY KEY id
|
|
106
|
+
TENANT KEY tenant_id
|
|
107
|
+
UNMATCHED EXCLUDE
|
|
108
|
+
|
|
109
|
+
PROTECTED RELATIONSHIP category LINK 1
|
|
110
|
+
ON product_id
|
|
111
|
+
REFERENCES public.products.id
|
|
112
|
+
PRIMARY KEY id
|
|
113
|
+
TENANT KEY tenant_id
|
|
114
|
+
UNMATCHED KEEP NULL
|
|
115
|
+
|
|
116
|
+
PROTECTED RELATIONSHIP category LINK 2
|
|
117
|
+
ON category_id
|
|
118
|
+
REFERENCES public.categories.id
|
|
119
|
+
PRIMARY KEY id
|
|
120
|
+
TENANT KEY tenant_id
|
|
121
|
+
UNMATCHED EXCLUDE
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
In that example:
|
|
125
|
+
|
|
126
|
+
- `store` and `category` are user-defined path names;
|
|
127
|
+
- `LINK 1` and `LINK 2` are DSL keywords and ordered link numbers;
|
|
128
|
+
- `store_id`, `product_id`, and `category_id` are inspected local keys;
|
|
129
|
+
- `public.stores.id`, `public.products.id`, and `public.categories.id` are
|
|
130
|
+
fixed reviewed targets;
|
|
131
|
+
- `PRIMARY KEY`, `TENANT KEY`, `UNMATCHED EXCLUDE`, and
|
|
132
|
+
`UNMATCHED KEEP NULL` are DSL syntax;
|
|
133
|
+
- the two `category` declarations form one depth-two path.
|
|
134
|
+
|
|
135
|
+
Link declarations for one path must be contiguous and ordered. A protected read
|
|
136
|
+
cannot mix the legacy form with the path form.
|
|
137
|
+
|
|
138
|
+
## Canonical Contract
|
|
139
|
+
|
|
140
|
+
The path form compiles to public, language-neutral JSON:
|
|
141
|
+
|
|
142
|
+
```json
|
|
143
|
+
{
|
|
144
|
+
"protected_read": {
|
|
145
|
+
"mode": "aggregate",
|
|
146
|
+
"relationships": [
|
|
147
|
+
{
|
|
148
|
+
"name": "category",
|
|
149
|
+
"links": [
|
|
150
|
+
{
|
|
151
|
+
"local_key": "product_id",
|
|
152
|
+
"schema": "public",
|
|
153
|
+
"table": "products",
|
|
154
|
+
"target_key": "id",
|
|
155
|
+
"primary_key": "id",
|
|
156
|
+
"tenant_key": "tenant_id",
|
|
157
|
+
"cardinality": "many_to_one",
|
|
158
|
+
"max_fan_out": 1,
|
|
159
|
+
"unmatched_rows": "keep_null"
|
|
160
|
+
},
|
|
161
|
+
{
|
|
162
|
+
"local_key": "category_id",
|
|
163
|
+
"schema": "public",
|
|
164
|
+
"table": "categories",
|
|
165
|
+
"target_key": "id",
|
|
166
|
+
"primary_key": "id",
|
|
167
|
+
"tenant_key": "tenant_id",
|
|
168
|
+
"cardinality": "many_to_one",
|
|
169
|
+
"max_fan_out": 1,
|
|
170
|
+
"unmatched_rows": "exclude"
|
|
171
|
+
}
|
|
172
|
+
]
|
|
173
|
+
}
|
|
174
|
+
]
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
Measures, dimensions, time buckets, and fixed predicates refer to the reviewed
|
|
180
|
+
path name. The canonical Spec is not a generic SQL or analytics Abstract Syntax
|
|
181
|
+
Tree (AST); it represents fixed reviewed authority.
|
|
182
|
+
|
|
183
|
+
## Scope And Privacy
|
|
184
|
+
|
|
185
|
+
For every participating relation, Runner injects trusted tenant and configured
|
|
186
|
+
principal predicates outside model arguments. Scope on only the starting table
|
|
187
|
+
is insufficient.
|
|
188
|
+
|
|
189
|
+
Aggregate privacy controls continue to apply after relationships are added:
|
|
190
|
+
|
|
191
|
+
- minimum cohort suppression;
|
|
192
|
+
- maximum groups and response size;
|
|
193
|
+
- query, rate, extraction, and differencing budgets;
|
|
194
|
+
- fixed reviewed dimensions and measures;
|
|
195
|
+
- no pagination that bypasses the group bound.
|
|
196
|
+
|
|
197
|
+
Adding dimensions can make cohorts smaller, so suppression is evaluated on the
|
|
198
|
+
final grouped result. A relationship does not weaken kept-out fields: kept-out
|
|
199
|
+
fields cannot be selected, filtered, grouped, sorted, joined, or counted
|
|
200
|
+
distinctly.
|
|
201
|
+
|
|
202
|
+
## Protect For Production
|
|
203
|
+
|
|
204
|
+
Protect This Query freezes the exact reviewed paths, measures, dimensions,
|
|
205
|
+
filters, ordering, limits, scope, and privacy controls into a disabled named
|
|
206
|
+
capability. A human activates its exact digest. Scoped Explore can then be
|
|
207
|
+
disabled; the protected capability remains available.
|
|
208
|
+
|
|
209
|
+
Production does not advertise broad Explore tools and does not permit the model
|
|
210
|
+
to add relationship authority.
|
|
211
|
+
|
|
212
|
+
## When A View Is Better
|
|
213
|
+
|
|
214
|
+
Runner intentionally does not support:
|
|
215
|
+
|
|
216
|
+
- arbitrary relationship graphs;
|
|
217
|
+
- many-to-many analytics;
|
|
218
|
+
- derived formulas such as `revenue / capacity`;
|
|
219
|
+
- model-defined expressions;
|
|
220
|
+
- general-purpose join planning.
|
|
221
|
+
|
|
222
|
+
For those cases, create a database view that computes the reviewed business
|
|
223
|
+
meaning, grant Runner's reader access only to the safe projected columns, and
|
|
224
|
+
inspect the view as a new resource. See [Reviewed Database
|
|
225
|
+
Views](reviewed-database-views.md).
|
|
226
|
+
|
|
227
|
+
This keeps business formulas and complex joins under ordinary database and code
|
|
228
|
+
review while preserving Synapsor's field, scope, budget, proposal, and audit
|
|
229
|
+
boundary.
|
|
230
|
+
|
|
231
|
+
## Verification
|
|
232
|
+
|
|
233
|
+
The repository release gates exercise:
|
|
234
|
+
|
|
235
|
+
```bash
|
|
236
|
+
corepack pnpm test:reviewed-relationships
|
|
237
|
+
corepack pnpm test:auto-boundary-explore:packed
|
|
238
|
+
corepack pnpm test:clean-room:community-solar
|
|
239
|
+
corepack pnpm test:clean-room:retail
|
|
240
|
+
```
|
|
241
|
+
|
|
242
|
+
The live PostgreSQL and MySQL relationship test proves direct star paths,
|
|
243
|
+
depth-two paths, both nullable-link choices, demand-driven activation, drift
|
|
244
|
+
refusal, per-relation tenant/principal scope, suppression, and rejection of a
|
|
245
|
+
deliberately wrong fan-out relationship.
|
package/docs/runner-bundles.md
CHANGED
|
@@ -41,11 +41,11 @@ cd ./synapsor-runner-bundle
|
|
|
41
41
|
cp .env.example .env
|
|
42
42
|
set -a && . ./.env && set +a
|
|
43
43
|
|
|
44
|
-
npx -y
|
|
45
|
-
npx -y
|
|
46
|
-
npx -y
|
|
47
|
-
npx -y
|
|
48
|
-
npx -y
|
|
44
|
+
npx -y @synapsor/runner contract validate ./synapsor.contract.json
|
|
45
|
+
npx -y @synapsor/runner config validate --config ./synapsor.runner.json
|
|
46
|
+
npx -y @synapsor/runner tools preview --config ./synapsor.runner.json --store ./.synapsor/local.db
|
|
47
|
+
npx -y @synapsor/runner cloud connect --config ./synapsor.cloud.json
|
|
48
|
+
npx -y @synapsor/runner mcp serve --config ./synapsor.runner.json --store ./.synapsor/local.db
|
|
49
49
|
```
|
|
50
50
|
|
|
51
51
|
For proposal contracts, run the trusted worker in a separate
|
|
@@ -53,14 +53,14 @@ operator-controlled terminal:
|
|
|
53
53
|
|
|
54
54
|
```bash
|
|
55
55
|
set -a && . ./.env && set +a
|
|
56
|
-
npx -y
|
|
56
|
+
npx -y @synapsor/runner start --config ./synapsor.runner.json --store ./.synapsor/local.db
|
|
57
57
|
```
|
|
58
58
|
|
|
59
59
|
After an MCP tool creates a local proposal, sync its reviewed diff and safe
|
|
60
60
|
references to Cloud:
|
|
61
61
|
|
|
62
62
|
```bash
|
|
63
|
-
npx -y
|
|
63
|
+
npx -y @synapsor/runner cloud sync latest \
|
|
64
64
|
--config ./synapsor.cloud.json \
|
|
65
65
|
--store ./.synapsor/local.db
|
|
66
66
|
```
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Reviewed Candidates From Prisma, Drizzle, And OpenAPI
|
|
2
2
|
|
|
3
|
-
Runner 1.6.
|
|
3
|
+
Runner 1.6.4 uses these same bounded static parsers as evidence in the
|
|
4
4
|
whole-application [Auto Boundary](auto-boundary-and-scoped-explore.md) flow.
|
|
5
5
|
The database catalog remains authoritative for database structure; Prisma,
|
|
6
6
|
Drizzle, OpenAPI, and existing Synapsor definitions contribute deterministic
|