@synapsor/runner 1.4.121 → 1.4.122

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.
Files changed (36) hide show
  1. package/CHANGELOG.md +26 -0
  2. package/README.md +23 -13
  3. package/dist/cli.d.ts +3 -0
  4. package/dist/cli.d.ts.map +1 -1
  5. package/dist/runner.mjs +2533 -323
  6. package/docs/README.md +1 -0
  7. package/docs/capability-authoring.md +43 -1
  8. package/docs/cloud-cli.md +248 -0
  9. package/docs/cloud-mode.md +88 -6
  10. package/docs/cloud-push.md +22 -5
  11. package/docs/conformance.md +6 -0
  12. package/docs/contract-testing.md +30 -1
  13. package/docs/dsl-reference.md +11 -0
  14. package/docs/hosted-cloud-linked-verification.md +97 -0
  15. package/docs/oss-vs-cloud.md +13 -6
  16. package/docs/release-notes.md +30 -0
  17. package/docs/rfcs/007-trusted-principal-row-scope.md +75 -0
  18. package/docs/runner-bundles.md +24 -0
  19. package/docs/running-a-runner-fleet.md +8 -0
  20. package/docs/security-boundary.md +15 -1
  21. package/examples/runner-fleet/seed/mysql.sql +5 -1
  22. package/examples/runner-fleet/seed/postgres.sql +5 -1
  23. package/examples/support-plan-credit/README.md +8 -6
  24. package/fixtures/dsl/principal-row-scope.synapsor.sql +23 -0
  25. package/fixtures/protocol/MANIFEST.json +10 -10
  26. package/package.json +1 -1
  27. package/schemas/change-set.v1.schema.json +14 -0
  28. package/schemas/change-set.v2.schema.json +14 -0
  29. package/schemas/change-set.v3.schema.json +2 -0
  30. package/schemas/compensation-change-set.v1.schema.json +3 -2
  31. package/schemas/inverse-descriptor.v1.schema.json +2 -0
  32. package/schemas/synapsor.contract-tests.schema.json +11 -1
  33. package/schemas/writeback-job.v1.schema.json +14 -0
  34. package/schemas/writeback-job.v2.schema.json +14 -0
  35. package/schemas/writeback-job.v3.schema.json +2 -0
  36. package/schemas/writeback-job.v4.schema.json +2 -2
package/docs/README.md CHANGED
@@ -142,6 +142,7 @@ no-database demo, wire your database, then read deeper concepts.
142
142
  topology, claim-bound sessions, pools, fleet rate limits, quorum, metrics,
143
143
  dead letters, backup/restore/retention, and kill/recovery evidence.
144
144
  - [Cloud Mode](cloud-mode.md): what stays local and what Cloud-linked mode adds.
145
+ - [Synapsor Cloud CLI](cloud-cli.md): command, credential, entitlement, and Cloud-linked authority reference.
145
146
  - [OSS Runner Vs Synapsor Cloud](oss-vs-cloud.md): detailed product and
146
147
  operational boundary.
147
148
  - [Cloud Push](cloud-push.md): register a validated local contract in the
@@ -84,11 +84,14 @@ synapsor-runner contract bundle ./synapsor.contract.json --out ./synapsor-runner
84
84
  synapsor-runner cloud push ./synapsor.contract.json --dry-run
85
85
  synapsor-runner cloud push ./synapsor.contract.json \
86
86
  --api-url "$SYNAPSOR_CLOUD_BASE_URL" \
87
- --token "$SYNAPSOR_CLOUD_TOKEN" \
88
87
  --workspace "$SYNAPSOR_PROJECT_ID" \
89
88
  --name billing-late-fee
90
89
  ```
91
90
 
91
+ Set `SYNAPSOR_API_KEY` for scoped CI automation or
92
+ `SYNAPSOR_CLOUD_ACCESS_TOKEN` for a signed-in human. Secrets are not accepted
93
+ as command-line flags.
94
+
92
95
  Reference the generated contract from local runner wiring:
93
96
 
94
97
  ```json
@@ -318,6 +321,45 @@ Bad:
318
321
 
319
322
  Runner rejects model-facing trust-scope arguments.
320
323
 
324
+ ### Same-Tenant Principal Row Scope
325
+
326
+ Tenant scope separates organizations. When multiple authenticated users share
327
+ one tenant but should see only rows assigned to them, add a second reviewed
328
+ lock:
329
+
330
+ ```sql
331
+ CREATE AGENT CONTEXT care_session
332
+ BIND hospital_id FROM HTTP_CLAIM hospital_id REQUIRED
333
+ BIND principal FROM HTTP_CLAIM sub REQUIRED
334
+ TENANT BINDING hospital_id
335
+ PRINCIPAL BINDING principal
336
+ END
337
+
338
+ CREATE CAPABILITY care.inspect_assigned_patient
339
+ USING CONTEXT care_session
340
+ SOURCE local_postgres
341
+ ON public.patients
342
+ PRIMARY KEY id
343
+ TENANT KEY hospital_id
344
+ PRINCIPAL SCOPE KEY assigned_to
345
+ LOOKUP patient_id BY id
346
+ ARG patient_id STRING REQUIRED MAX LENGTH 128
347
+ ALLOW READ id, hospital_id, display_name, care_status, updated_at
348
+ KEEP OUT assigned_to, diagnosis_notes
349
+ REQUIRE EVIDENCE
350
+ MAX ROWS 1
351
+ END
352
+ ```
353
+
354
+ Runner generates one parameterized predicate containing both locks. It also
355
+ forces the scope column on reviewed inserts and preserves it through proposals,
356
+ writeback jobs, receipts, replay, and compensation. A same-tenant row assigned
357
+ to another principal has the same public not-found result as an absent or
358
+ cross-tenant row. The scope column may remain kept out of model-visible data.
359
+ Use a separately reviewed tenant-wide capability for supervisors; there is no
360
+ runtime bypass flag. Database RLS and least-privilege roles remain recommended
361
+ defense in depth.
362
+
321
363
  ## Direct SQL Writeback
322
364
 
323
365
  Use direct SQL writeback for reviewed guarded single-row INSERT, UPDATE, or
@@ -0,0 +1,248 @@
1
+ # Synapsor Cloud CLI
2
+
3
+ Use `synapsor-runner` for the local MCP/database boundary. Use `synapsor` from
4
+ `@synapsor/cli` for Cloud administration, shared review, and audit. Linking a
5
+ Runner to Cloud is optional; local-only Runner mode requires no account.
6
+
7
+ ## Credential Boundaries
8
+
9
+ | Credential | Used by | Purpose |
10
+ |---|---|---|
11
+ | Human session | `synapsor`, web UI | Administration and human decisions, subject to role, policy, recent auth, and entitlement |
12
+ | Service API key | `synapsor` or `synapsor-runner cloud push` in CI | Explicit project scopes such as contract push or activity export |
13
+ | Runner token | `synapsor-runner` Cloud protocol | Register, heartbeat, proposal/activity sync, leases, and terminal results |
14
+ | Local MCP HTTP token | MCP client to local Runner | Local transport authentication only |
15
+
16
+ Authentication, project role/scope authorization, and paid feature entitlement
17
+ are independent checks. A valid key can remain authenticated after a billing
18
+ change while paid operations return `payment_required` or
19
+ `feature_not_entitled`. Neither API keys nor Runner tokens bypass plan state.
20
+
21
+ Never put a Cloud secret, database URL, or local MCP token on a CLI argument.
22
+ Use a masked environment variable or a mode-`0600` secret file.
23
+
24
+ ## Command Index
25
+
26
+ ```text
27
+ auth login, logout, whoami, profiles, use, configure-service
28
+ status selected profile, API, project, service health
29
+ entitlements effective hosted features, limits, and blocked reason
30
+ billing plan/payment lifecycle summary
31
+ workspaces list, use
32
+ projects list, show, use
33
+ sources list, show (safe metadata only)
34
+ contracts init, validate, format, inspect, diff, push, list, show,
35
+ history, pull, activate, rollback
36
+ contexts list, show, create, update, remove
37
+ capabilities list, show, create, update, remove, preview
38
+ workflows list, show, create, update, remove, validate
39
+ api-keys list, show, create, rotate, revoke
40
+ runners list, show, create, rotate-token, revoke-token,
41
+ bundle download, doctor
42
+ proposals list, show, decisions, approve, reject
43
+ activity search, show
44
+ evidence show
45
+ receipts show
46
+ replay show, verify
47
+ exports create, status, download
48
+ ```
49
+
50
+ Run `synapsor --help` for the compact index. All local context/capability/
51
+ workflow edits validate the complete canonical contract and use atomic file
52
+ replacement with a backup. Complex definitions can be supplied with
53
+ `--from-file`; the CLI does not invent unsafe defaults for proposal writeback.
54
+
55
+ `synapsor <group> --help` lists that group's real commands, and
56
+ `synapsor <group> <command> --help` shows the checked command syntax. The help
57
+ tree and this index are covered together by the CLI test suite.
58
+
59
+ ## Human Login And Project Selection
60
+
61
+ ```bash
62
+ npm install --global @synapsor/cli
63
+
64
+ synapsor auth login --open
65
+ synapsor auth whoami
66
+ synapsor workspaces list
67
+ synapsor projects list
68
+ synapsor projects use <project-id>
69
+ synapsor status
70
+ synapsor entitlements show
71
+ ```
72
+
73
+ `status` reports authentication, selected project, service health, plan,
74
+ billing lifecycle, effective entitlement, grace deadline, and blocked reason.
75
+ Authentication, project role or service-key scope authorization, and paid
76
+ feature entitlement are separate checks. A valid credential does not bypass
77
+ `payment_required`, `feature_not_entitled`, or `project_inactive`.
78
+
79
+ ## Author A Canonical Contract
80
+
81
+ Contexts, capabilities, and workflows are reviewed parts of one immutable
82
+ canonical contract, not mutable Cloud permission rows. Local edits are atomic,
83
+ fully validated, and followed by a semantic safety diff.
84
+
85
+ ```bash
86
+ synapsor contracts init ./synapsor.contract.json --name support-contract
87
+
88
+ synapsor contexts create trusted_operator \
89
+ --contract ./synapsor.contract.json \
90
+ --from-file ./context.json
91
+
92
+ synapsor capabilities create billing.inspect_invoice \
93
+ --contract ./synapsor.contract.json \
94
+ --from-file ./capability.json
95
+
96
+ synapsor workflows create billing.invoice_review \
97
+ --contract ./synapsor.contract.json \
98
+ --from-file ./workflow.json
99
+
100
+ synapsor contracts validate ./synapsor.contract.json
101
+ synapsor contracts diff ./before.json ./synapsor.contract.json
102
+ synapsor contracts push ./synapsor.contract.json --dry-run
103
+ synapsor contracts push ./synapsor.contract.json
104
+ ```
105
+
106
+ Push creates or reuses an immutable version. It does not silently rewrite an
107
+ existing version. Activation and rollback are separate authorized mutations:
108
+
109
+ ```bash
110
+ synapsor contracts history <contract-id>
111
+ synapsor contracts activate <contract-id>/<version-id> --yes
112
+ synapsor contracts rollback <contract-id>/<older-version-id> --yes
113
+ ```
114
+
115
+ The Runner-centric equivalent remains supported:
116
+
117
+ ```bash
118
+ synapsor-runner cloud push ./synapsor.contract.json
119
+ ```
120
+
121
+ It uses the same canonical validation, digest, endpoint, idempotency, and error
122
+ semantics as `synapsor contracts push`.
123
+
124
+ ## Create And Use A CI API Key
125
+
126
+ Only an authorized human can create, rotate, or revoke keys. The secret is
127
+ returned once and must be written to a protected file; it is never printed by
128
+ normal or JSON output.
129
+
130
+ ```bash
131
+ synapsor api-keys create \
132
+ --name contract-ci \
133
+ --scopes project:read,contracts:read,contracts:write \
134
+ --expires-at 2026-12-31 \
135
+ --secret-file ./.synapsor/contract-ci.key
136
+
137
+ export SYNAPSOR_API_KEY="$(cat ./.synapsor/contract-ci.key)"
138
+ synapsor auth configure-service \
139
+ --profile ci \
140
+ --api-url https://dev-api.synapsor.ai \
141
+ --project <project-id> \
142
+ --credential-env SYNAPSOR_API_KEY
143
+
144
+ synapsor auth whoami --profile ci --json
145
+ synapsor contracts push ./synapsor.contract.json --profile ci
146
+ ```
147
+
148
+ `whoami` reports a service identity, key prefix/ID, scopes, project,
149
+ expiration, and entitlement summary. It never turns the key into a human
150
+ identity. Rotate and revoke through a human profile:
151
+
152
+ ```bash
153
+ synapsor api-keys rotate <key-id> --secret-file ./.synapsor/contract-ci.next.key
154
+ synapsor api-keys revoke <key-id> --yes
155
+ ```
156
+
157
+ After revocation, requests using the old value fail; they do not fall back to a
158
+ local profile or another credential.
159
+
160
+ ## Connect A Customer-Operated Runner
161
+
162
+ Runner tokens are separate, source-scoped machine credentials. Create one and
163
+ store its one-time value without printing it:
164
+
165
+ ```bash
166
+ synapsor runners create \
167
+ --name support-runner \
168
+ --sources <cloud-source-id> \
169
+ --secret-file ./.synapsor/runner.token
170
+
171
+ export SYNAPSOR_RUNNER_TOKEN="$(cat ./.synapsor/runner.token)"
172
+ ```
173
+
174
+ When `--permissions` is omitted, Cloud applies the bounded Runner-protocol
175
+ permission set. Use `--permissions <csv>` to narrow a token further; these
176
+ permissions never authorize human, API-key, contract, or approval operations.
177
+
178
+ The credential-free Runner bundle contains the reviewed connection metadata
179
+ and sample configuration. Supply the Runner token separately:
180
+
181
+ ```bash
182
+ synapsor runners bundle download <contract-id>/<version-id> \
183
+ --source <cloud-source-id> \
184
+ --out ./synapsor-runner-bundle.zip
185
+ synapsor runners doctor <runner-id>
186
+ ```
187
+
188
+ Runner tokens authenticate only registration, heartbeat, proposal/activity
189
+ sync, leases, and terminal results. They are rejected by Cloud administration
190
+ and human-decision routes. Source database URLs and write credentials stay in
191
+ the Runner process environment and never enter the bundle, contract, Cloud
192
+ CLI, or Cloud registry.
193
+
194
+ ## Review And Audit
195
+
196
+ ```bash
197
+ synapsor proposals list --status pending
198
+ synapsor proposals show <proposal-id>
199
+ synapsor proposals approve <proposal-id> --reason "Reviewed evidence" --yes
200
+
201
+ synapsor evidence show <proposal-id>
202
+ synapsor receipts show <proposal-id>
203
+ synapsor replay verify <proposal-id>
204
+ synapsor activity search --lookup <business-id> --json
205
+ ```
206
+
207
+ Proposal approval records Cloud governance state; it never changes the source
208
+ database directly. A trusted Runner must receive an authorized lease and
209
+ recheck the local proposal, exact contract digest, tenant and principal locks,
210
+ allowlists, bounds, conflict/version guard, idempotency, and affected-row rule.
211
+ Service API keys and Runner tokens cannot record human approval.
212
+
213
+ ## Cloud-Linked Runner Authority
214
+
215
+ `governance.mode: cloud_linked` is explicit. Cloud is authoritative for active
216
+ contract versions, human decisions, job leasing, and terminal governance state.
217
+ The local/shared Runner store remains a durable operational spool and local
218
+ evidence/replay ledger; Cloud and the CLI never open or upload its SQLite file.
219
+
220
+ The initial evidence policy is `metadata_only`. Cloud receives bounded proposal
221
+ diffs, safe identities/fingerprints, IDs, counts, and integrity hashes. Source
222
+ rows, evidence payloads, SQL text/parameters, kept-out fields, credentials, and
223
+ local replay payloads remain local.
224
+
225
+ By default a Cloud-linked Runner durably queues proposals during a transient
226
+ Cloud outage. Set `governance.queue_when_unavailable: false` to fail before the
227
+ source read/proposal is created when authenticated Cloud readiness is not
228
+ available. In both modes, no Cloud approval or writeback proceeds offline.
229
+
230
+ Inspect and repair the local operational outbox with Runner, not the Cloud CLI:
231
+
232
+ ```bash
233
+ synapsor-runner doctor --config ./synapsor.runner.json --store ./.synapsor/local.db
234
+ synapsor-runner cloud outbox status --config ./synapsor.runner.json --store ./.synapsor/local.db
235
+ synapsor-runner cloud outbox inspect latest --config ./synapsor.runner.json --store ./.synapsor/local.db
236
+ synapsor-runner cloud outbox reconcile --yes --config ./synapsor.runner.json --store ./.synapsor/local.db
237
+ ```
238
+
239
+ Dead-letter or hash-divergence state requires operator inspection. Runner never
240
+ silently chooses a local copy over Cloud or creates a fake local human approval.
241
+
242
+ ## Pagination And JSON
243
+
244
+ List/search commands accept `--limit`, `--cursor`, and bounded `--all`.
245
+ `--max-items` can lower the aggregate bound; raising it beyond the safe default
246
+ requires `--allow-large-result`. Use `--json` for scripts. Unknown or transient
247
+ failures are not retried as mutations; shared client retries are limited to
248
+ classified safe requests and honor server retry timing.
@@ -15,9 +15,35 @@ Cloud-linked mode is for teams that need a shared control plane:
15
15
  - receipt reporting;
16
16
  - retention and audit visibility.
17
17
 
18
- The local runner still keeps database credentials in your environment. MCP
19
- client config snippets should contain command paths and runner arguments, not
20
- database URLs or write credentials.
18
+ The local Runner still keeps database credentials in your environment. MCP
19
+ client config snippets contain command paths and Runner arguments, not database
20
+ URLs or write credentials.
21
+
22
+ ## Trust Boundary
23
+
24
+ ```text
25
+ agent / MCP client
26
+ -> local Runner semantic tools
27
+ -> local scoped read + evidence
28
+ -> local proposal (source unchanged)
29
+ -> reviewed diff + safe references synced to Cloud
30
+ -> signed-in human approves or rejects in Cloud
31
+ -> source-scoped leased job
32
+ -> local trusted worker rechecks contract + proposal + DB guards
33
+ -> local database write
34
+ -> redacted receipt/activity linkage returned to Cloud
35
+ ```
36
+
37
+ Cloud receives the contract/version/digest, capability, trusted scope
38
+ identifiers, reviewable allowlisted diff, safe evidence/query references,
39
+ decision identity, lease state, and receipt/replay links. Database URLs,
40
+ passwords, handler tokens, private keys, full source rows, and kept-out evidence
41
+ payloads stay local.
42
+
43
+ Maintainers must run the opt-in
44
+ [hosted Cloud-linked verification](./hosted-cloud-linked-verification.md) with a
45
+ packed Runner, disposable Cloud project, and synthetic source before claiming a
46
+ release is Cloud-linked end to end.
21
47
 
22
48
  Push and retrieve the portable contract without moving database credentials
23
49
  into Cloud:
@@ -29,11 +55,67 @@ synapsor-runner cloud push ./synapsor.contract.json \
29
55
  --name support-plan-credit
30
56
  ```
31
57
 
58
+ Use the current design-partner API base:
59
+
60
+ ```bash
61
+ export SYNAPSOR_CLOUD_BASE_URL="https://dev-api.synapsor.ai"
62
+ ```
63
+
64
+ Then create a source-scoped Runner token in **Contract registry -> Connect
65
+ Runner**, download the selected version's bundle, and run:
66
+
67
+ ```bash
68
+ cd ./<downloaded-runner-bundle>
69
+ cp .env.example .env
70
+ # Fill the placeholders in .env, including the one-time Runner token.
71
+ set -a && . ./.env && set +a
72
+
73
+ npx -y -p @synapsor/runner synapsor-runner config validate --config ./synapsor.runner.json
74
+ npx -y -p @synapsor/runner synapsor-runner tools preview --config ./synapsor.runner.json --store ./.synapsor/local.db
75
+ npx -y -p @synapsor/runner synapsor-runner cloud connect --config ./synapsor.cloud.json
76
+ npx -y -p @synapsor/runner synapsor-runner mcp serve --config ./synapsor.runner.json --store ./.synapsor/local.db
77
+ ```
78
+
79
+ Run the trusted worker in a second operator-controlled terminal:
80
+
81
+ ```bash
82
+ set -a && . ./.env && set +a
83
+ npx -y -p @synapsor/runner synapsor-runner runner start --config ./synapsor.runner.json --store ./.synapsor/local.db
84
+ ```
85
+
86
+ For deployment checks or an operator-controlled single claim cycle, use the
87
+ same installed worker with `--once`; it exits after applying at most one
88
+ Cloud-approved job and still rechecks the local contract, proposal, tenant,
89
+ version, bounds, and idempotency guards:
90
+
91
+ ```bash
92
+ npx -y -p @synapsor/runner synapsor-runner runner start --once --config ./synapsor.runner.json --store ./.synapsor/local.db
93
+ ```
94
+
95
+ When a local proposal exists:
96
+
97
+ ```bash
98
+ npx -y -p @synapsor/runner synapsor-runner cloud sync latest --config ./synapsor.cloud.json --store ./.synapsor/local.db
99
+ ```
100
+
32
101
  See [Cloud Push](cloud-push.md) and [Runner Bundles](runner-bundles.md).
33
102
 
34
- Cloud registry storage preserves approval policies but does not, by itself,
35
- mean hosted policy enforcement is enabled. Local Runner enforcement and hosted
36
- Cloud approval enforcement are separate runtime boundaries.
103
+ Cloud approval changes proposal state and creates a claimable job; it does not
104
+ touch the source database directly. If a lease expires, another compatible
105
+ Runner may claim the job, but source and ledger idempotency prevent a duplicate
106
+ effect. Stale row/set guards return a conflict. If the system cannot prove
107
+ whether a source write committed, it records an indeterminate/reconciliation
108
+ state instead of retrying blindly.
109
+
110
+ Runner tokens are scoped to one project, explicit source IDs, and named
111
+ operations. Rotate or revoke them from Connect Runner. Revocation blocks new
112
+ registration, heartbeat, proposal, claim, lease, activity, and result calls.
113
+
114
+ This is a single-node design-partner boundary, not managed Runner hosting,
115
+ multi-region HA, SAML/SCIM, legal hold/WORM retention, or an enterprise SLA.
116
+ Run the explicit hosted integration gate with synthetic staging data before
117
+ depending on a deployment; registry push alone is not proof that registration,
118
+ approval, leasing, and receipt synchronization are live.
37
119
 
38
120
  Run the local smoke for this mode with:
39
121
 
@@ -17,8 +17,8 @@ Dry-run validates and normalizes locally. It performs no network request.
17
17
  ## Push
18
18
 
19
19
  ```bash
20
- export SYNAPSOR_CLOUD_BASE_URL="https://api.synapsor.ai"
21
- export SYNAPSOR_CLOUD_TOKEN="<workspace-scoped-token>"
20
+ export SYNAPSOR_CLOUD_BASE_URL="https://dev-api.synapsor.ai"
21
+ export SYNAPSOR_API_KEY="<contracts-write-service-key>"
22
22
  export SYNAPSOR_WORKSPACE_ID="<workspace-id>"
23
23
 
24
24
  synapsor-runner cloud push ./synapsor.contract.json \
@@ -29,7 +29,9 @@ The response includes the contract id, immutable version id, server-computed
29
29
  digest, summary counts, status, and registry path. Identical normalized content
30
30
  is idempotent; changed content creates the next version.
31
31
 
32
- Tokens are sent in the authorization header and are never part of the contract.
32
+ Use `SYNAPSOR_API_KEY` for scoped CI automation or
33
+ `SYNAPSOR_CLOUD_ACCESS_TOKEN` for an authenticated human session. Credentials
34
+ are sent in the authorization header and are never part of the contract.
33
35
  Database URLs, passwords, private keys, and model-controlled tenant bindings
34
36
  are rejected by server-side validation.
35
37
 
@@ -42,6 +44,11 @@ permission (`403`), missing workspace/API paths (`404`), registry conflicts
42
44
  (`409`), server validation (`422`), and Cloud/network failures. Error output
43
45
  does not echo the bearer token.
44
46
 
47
+ `dev-api.synapsor.ai` is the supported design-partner endpoint. Do not replace
48
+ it with `api.synapsor.ai` unless Synapsor has separately announced and verified
49
+ that hostname. Contract push uses a signed-in workspace/API credential;
50
+ Runner registration and jobs use a separate source-scoped Runner token.
51
+
45
52
  ## Cloud To Local
46
53
 
47
54
  Open **Contract registry** in the workspace, choose a version, and download its
@@ -49,6 +56,16 @@ runner bundle. The ZIP contains the normalized contract, local runner wiring,
49
56
  placeholder environment file, README, and MCP client examples. It contains no
50
57
  live credentials or table rows.
51
58
 
59
+ Choose the Cloud source when downloading because each bundle is source-bound:
60
+
61
+ ```bash
62
+ synapsor runners bundle download <contract-id>/<version-id> \
63
+ --source <cloud-source-id> \
64
+ --out ./synapsor-runner-bundle.zip
65
+ ```
66
+
52
67
  Cloud currently preserves approval policy definitions in the contract and
53
- bundle. Hosted approval-policy enforcement remains a separate Cloud feature;
54
- do not infer it from registry storage alone.
68
+ bundle. Cloud approval is a human-authenticated decision and is not exposed to
69
+ the Runner token or MCP. The local Runner remains responsible for rechecking
70
+ the exact contract digest, proposal hash, tenant, target, allowed fields,
71
+ conflict/version guard, bounds, and one-write/idempotency rules before applying.
@@ -32,6 +32,7 @@ Current fixture groups:
32
32
  - `numeric-bounds`
33
33
  - `bounded-set-threats`
34
34
  - `reversible-change-sets`
35
+ - `principal-row-scope`
35
36
 
36
37
  The fixture set is intentionally small in 0.1. It covers the runner-supported
37
38
  semantic surface first: trusted context, scoped reads, evidence handles,
@@ -54,6 +55,10 @@ compensation proposal, not rollback: apply-time receipts capture only
54
55
  allowlisted inverse data, compensation uses fresh guards and exact members,
55
56
  ambiguous outcomes fail closed pending reconciliation, and hard delete reports
56
57
  a specific best-effort-unavailable reason.
58
+ The principal-row-scope fixture proves that a reviewed owner/assignee column is
59
+ bound to a required trusted principal and AND-composed with tenant scope. Run
60
+ `corepack pnpm test:principal-scope` for the live Postgres/MySQL proof covering
61
+ same-tenant denial and shared-ledger evidence-handle isolation.
57
62
 
58
63
  Additional 0.1 parity coverage currently lives in tests and verification
59
64
  scripts rather than separate `cloud-push/` or `dsl-json-parity/` conformance
@@ -81,6 +86,7 @@ Run:
81
86
  corepack pnpm --filter @synapsor-runner/mcp-server test
82
87
  corepack pnpm test:contract-conformance
83
88
  corepack pnpm test:aggregate-read
89
+ corepack pnpm test:principal-scope
84
90
  ```
85
91
 
86
92
  The spec package also validates every conformance contract:
@@ -36,11 +36,40 @@ A successful run ends with a stable count such as:
36
36
  Summary: 6 passed / 0 failed / 6 total
37
37
  ```
38
38
 
39
- Supported assertions cover valid scoped tools, cross-tenant denial, kept-out
39
+ Supported assertions cover valid scoped tools, cross-tenant denial,
40
+ same-tenant cross-principal denial, kept-out
40
41
  fields, argument constraints, transition guards, set caps, unchanged source
41
42
  state before approval, and the absence of model-facing approval/writeback.
42
43
  Trusted tenant and principal values belong in test setup, not tool arguments.
43
44
 
45
+ Use `cross_principal_deny` to prove both the allowed and denied sides of one
46
+ row lock. The two contexts must use the same tenant and different principals:
47
+
48
+ ```json
49
+ {
50
+ "id": "case-manager-b-cannot-read-a",
51
+ "kind": "cross_principal_deny",
52
+ "capability": "care.inspect_assigned_patient",
53
+ "args": { "patient_id": "PAT-1001" },
54
+ "trusted_context": {
55
+ "tenant_id": "hospital_a",
56
+ "principal": "case_manager_a",
57
+ "provenance": "http_claims"
58
+ },
59
+ "other_trusted_context": {
60
+ "tenant_id": "hospital_a",
61
+ "principal": "case_manager_b",
62
+ "provenance": "http_claims"
63
+ },
64
+ "expected_code": "NOT_FOUND_IN_TENANT"
65
+ }
66
+ ```
67
+
68
+ Live execution first proves the owner can read the row, then requires the other
69
+ principal to receive the generic denial and `RESOURCE_NOT_FOUND` for the
70
+ owner's evidence handle. Run the repository's Postgres/MySQL proof with
71
+ `corepack pnpm test:principal-scope`.
72
+
44
73
  The flagship example includes a working manifest at
45
74
  [`examples/support-plan-credit/synapsor.contract-tests.json`](../examples/support-plan-credit/synapsor.contract-tests.json).
46
75
  Contract tests prove the declared cases, not every possible threat or database
@@ -47,6 +47,7 @@ CREATE CAPABILITY billing.inspect_invoice
47
47
  ON public.invoices
48
48
  PRIMARY KEY id
49
49
  TENANT KEY tenant_id
50
+ PRINCIPAL SCOPE KEY assigned_to
50
51
  CONFLICT GUARD updated_at
51
52
  ...
52
53
  END
@@ -62,8 +63,18 @@ END
62
63
  | `ON schema.table` | Required fixed target. Table/schema are never model inputs. |
63
64
  | `PRIMARY KEY column` | Fixed single-row target key. Defaults to `id` in DSL 0.1. Declare it explicitly. |
64
65
  | `TENANT KEY column` | Required in DSL 0.1. Adds trusted tenant scope to every read/write. |
66
+ | `PRINCIPAL SCOPE KEY column` | Optional tenant-additive row lock. Runner binds this fixed column to the context's required trusted `PRINCIPAL BINDING`; it is never a model argument. |
65
67
  | `CONFLICT GUARD column` | Captures the row-version value for exact guarded writeback. Prefer a monotonic version or native-precision timestamp. |
66
68
 
69
+ `PRINCIPAL SCOPE KEY` means `tenant_key = trusted tenant AND
70
+ principal_scope_key = trusted principal`. It cannot replace tenant scope,
71
+ default to all rows, or be overridden by an argument. The principal binding
72
+ must be required and come from a trusted provider such as `ENVIRONMENT`,
73
+ `HTTP_CLAIM`, `SESSION`, or `CLOUD_SESSION`. For networked multi-user serving,
74
+ use signed HTTP claims. See the complete
75
+ [`principal-row-scope.synapsor.sql`](../fixtures/dsl/principal-row-scope.synapsor.sql)
76
+ example.
77
+
67
78
  ## Arguments and lookup
68
79
 
69
80
  ```sql
@@ -0,0 +1,97 @@
1
+ # Hosted Cloud-Linked Verification
2
+
3
+ This is the manual release gate for the complete OSS Runner and single-node
4
+ Synapsor Cloud boundary. It is intentionally opt-in because it creates Cloud
5
+ records and mutates a synthetic source row.
6
+
7
+ The verifier installs packed or published Cloud CLI and Runner packages in a
8
+ clean temporary directory and proves:
9
+
10
+ - public protocol discovery;
11
+ - packed CLI human `whoami`, secure one-time service-key output, and immediate
12
+ service-key revocation;
13
+ - canonical contract push parity between `synapsor contracts push` and
14
+ `synapsor-runner cloud push` with one immutable version identity;
15
+ - source-scoped Runner token creation, rotation, registration idempotency, and
16
+ heartbeat;
17
+ - credential-free Runner bundle download;
18
+ - scoped MCP read and cross-tenant denial;
19
+ - proposal creation without a source write and automatic durable-outbox
20
+ delivery without a manual `cloud sync` command;
21
+ - authenticated Cloud approval and guarded local writeback through the packed
22
+ Runner's public worker CLI;
23
+ - two registered Runner processes competing for one exclusive job lease;
24
+ - duplicate-claim idempotency, rejection, and stale-version conflict;
25
+ - linked Cloud activity integrity and canonical export;
26
+ - reviewed activation and rollback of a risk-increasing contract version; and
27
+ - immediate Runner-token revocation across doctor, registration, claim, and
28
+ result submission.
29
+
30
+ It never accepts production data. Use a disposable project and a synthetic
31
+ Postgres or MySQL database that can be reset after the run.
32
+
33
+ ## Prerequisites
34
+
35
+ Build the workspace and pack both packages before a pre-publish check:
36
+
37
+ ```bash
38
+ corepack pnpm install
39
+ corepack pnpm build
40
+ corepack pnpm --filter @synapsor/runner pack --pack-destination /tmp
41
+ corepack pnpm --filter @synapsor/cli pack --pack-destination /tmp
42
+ ```
43
+
44
+ Prepare:
45
+
46
+ - a disposable Cloud project and imported synthetic source;
47
+ - an authenticated human session token obtained through the normal browser/
48
+ device login flow;
49
+ - separate least-privilege read and write source URLs;
50
+ - a canonical contract with one scoped read and one proposal capability; and
51
+ - three independent proposal fixture rows: apply, reject, and stale-conflict.
52
+
53
+ Read tokens and database URLs from a secret prompt or secret manager. Do not
54
+ put them in Git, shell history, command-line arguments, or the Runner bundle.
55
+
56
+ ## Run
57
+
58
+ Set the non-secret fixture identifiers and JSON assertions for your synthetic
59
+ database. The exact required variables and their meanings are always available
60
+ without credentials:
61
+
62
+ ```bash
63
+ corepack pnpm verify:hosted-cloud-linked -- --help
64
+ ```
65
+
66
+ Then opt in explicitly and run:
67
+
68
+ ```bash
69
+ export SYNAPSOR_HOSTED_E2E=1
70
+ export SYNAPSOR_E2E_DISPOSABLE_PROJECT=1
71
+ export SYNAPSOR_CLOUD_BASE_URL="https://dev-api.synapsor.ai"
72
+ export SYNAPSOR_RUNNER_PACKAGE_SPEC="/tmp/synapsor-runner-<version>.tgz"
73
+ export SYNAPSOR_CLI_PACKAGE_SPEC="/tmp/synapsor-cli-<version>.tgz"
74
+
75
+ corepack pnpm verify:hosted-cloud-linked
76
+ ```
77
+
78
+ The command refuses to run unless both opt-in flags are present. HTTPS is
79
+ required unless `SYNAPSOR_E2E_ALLOW_HTTP=1` is explicitly set for a local
80
+ control-plane test. The generated Runner token is revoked in a `finally` block,
81
+ and the temporary directory is removed unless
82
+ `SYNAPSOR_E2E_KEEP_TEMP=1` is set for debugging.
83
+
84
+ ## Passing Result
85
+
86
+ A pass prints only a boolean summary with all checks set to `true`. The
87
+ `token_rotated`, `registration_idempotent`, `two_runner_exclusive_claim`,
88
+ `registration_heartbeat`, `proposal_reviewed_metadata`,
89
+ `two_runner_exclusive_claim`, `receipt_replay_linked`, `activity_exported`,
90
+ `contract_governance`, and `revoked_operations_blocked` fields prove those
91
+ additional boundaries explicitly. It does not print bearer tokens, database
92
+ URLs, source rows, or kept-out values. Confirm the synthetic fixture is reset
93
+ after the run before reusing the project.
94
+
95
+ This gate is evidence for the existing single-node design-partner boundary. It
96
+ does not establish multi-region availability, managed Runner hosting, SSO/SCIM,
97
+ legal hold, formal compliance certification, or an enterprise SLA.