@fitzzero/quickdraw-skills 5.0.0 → 5.0.1

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fitzzero/quickdraw-skills",
3
- "version": "5.0.0",
3
+ "version": "5.0.1",
4
4
  "description": "Agent rules and skills for quickdraw 5.0 apps, linked into .claude/ by the quickdraw-skills command",
5
5
  "keywords": [
6
6
  "agents",
@@ -88,7 +88,7 @@ compile time.
88
88
  | `members({ model, entry, user, level, levels? })` | a membership table row |
89
89
  | `inherit({ from: projectContract, via: "projectId" })` | the level on the parent row in another service |
90
90
  | `anyOf(policyA, policyB)` | the highest level any of them gives |
91
- | `resolver({ levelsFor, where? })` | your code, one batched read for all ids |
91
+ | `resolver({ levelsFor, where?, reads })` | your code, one batched read for all ids |
92
92
  | `everyone("Read")` | every signed-in user, on every row; no read |
93
93
 
94
94
  - `entry` forms need a policy and `scope` forms a `model`; a service without
@@ -100,6 +100,17 @@ compile time.
100
100
  `anyOf(owner("id"), everyone("Read"))`, never a hand-written `resolver`
101
101
  answering `Read` for every id: `rowless: true` covers one method, not
102
102
  subscriptions.
103
+ - A `resolver` declares what its levels depend on, or nothing re-checks it
104
+ and a removed member keeps their live rows:
105
+ `reads: { columns: ["visibility"], memberships: [{ model: "teamMember", entry: "projectId", user: "userId", level: "role" }] }`
106
+ (columns of the service's model; membership tables as `members` takes
107
+ them, `entry` holding this service's row id). Tracked writes to them then
108
+ revoke and re-check as for the other policies, and `tools.rows(ids)` reads
109
+ the declared columns. `reads: "none"` only when nothing a tracked write
110
+ changes can change a level (the principal's grants alone). Without either
111
+ the server warns `[quickdraw:resolver-without-reads]` and a strict test
112
+ app fails to start. A level from another service's row is `inherit`'s
113
+ job, alone or in `anyOf`.
103
114
  - Lookups are batched per call: checking 60 ids costs what one does.
104
115
  `createServer({ access: { cacheMs } })` keeps them across calls; tracked
105
116
  writes to the columns and tables a policy reads evict them.
@@ -186,6 +186,11 @@ Contract halves come from `@fitzzero/quickdraw-core`, handlers from
186
186
  - `sharing.contract({ mode: "acl" | "members" })` with `sharing.handlers(project)`,
187
187
  on a service whose policy has a `jsonAcl` or `members`.
188
188
  - `admin.contract({ entity })` with `admin.handlers(task)` (`{ service: "Admin" }` by default).
189
+ Name what an admin may change with `editable: ["title", "status"]` (on
190
+ `admin.contract` too, so the input schemas and MCP tools name only those):
191
+ every other field is read-only, and a write naming one is `VALIDATION`.
192
+ Without it the kit writes every field it shows but `id` and the
193
+ timestamps, owner and foreign-key columns included.
189
194
  On a users service, `admin.handlers(user, { grants: true })` lets the admin
190
195
  screen edit `serviceAccess` through `adminUpdate` (service-wide Admins
191
196
  only); never hand-write a `setServiceAccess` method for it. `adminMeta`
@@ -122,9 +122,10 @@ test that caused it (an oversized reply fails an in-process `app.as(...)`
122
122
  call; over a socket or HTTP the reply was already sent, so it is logged, not
123
123
  thrown). Warnings outside its calls (an `ambient-write` while seeding) are
124
124
  logged, and `app.close()` ends it. `tiered-field-in-output` (a method's own
125
- output schema declares a tiered field, at any depth) is thrown by
126
- `createTestApp` itself: answer `"entity"` from that method rather than
127
- turning strictness off.
125
+ output schema declares a tiered field, at any depth) and
126
+ `resolver-without-reads` (a `resolver` policy declares no `reads`) are
127
+ thrown by `createTestApp` itself: answer `"entity"` from that method, or
128
+ declare the resolver's `reads`, rather than turning strictness off.
128
129
  Turn it on for service suites.
129
130
  `createRecordingSink()` passed as `flushSink` records what each flush wrote.
130
131