--- id: STORE-4 family: GR-STORE level: core profiles: [storage-api] posture: normative-target added: "1.0" changed: "1.0" source: https://flowdrop.io/spec/rules/gr-store/store-4 specification: FlowDrop Workflow Specification 1.0-draft licence: CC BY 4.0 --- # STORE-4 — Absent collections default to empty, and an update touches only what it sends *GR-STORE (Part I) · level: core · profiles: storage-api · added in 1.0* An update is partial. What a caller does not send, it does not change, which is what lets an editor save one part of a workflow without holding the whole of it. ## The rule > **Normative.** This is the rule. > > 1. On create, `nodes`, `edges` and `metadata` default to the empty list when absent, and a workflow that declares no `interface` declares no ports. > > 2. On update, a key the request omits is left as stored; `name` is the exception, required on update as on create. > > 3. An `interface` present on update rewrites both port lists from it even when only one side is supplied, so a missing or empty `inputs` or `outputs` clears that side. > > 4. The `metadata` published on read need not be identical to the `metadata` as stored: an implementation may fold envelope fields such as `format` and `schemaVersion` back into it on read. ## What it means An update is partial by default: a key the request does not send is left as stored, which is what lets a caller save one part of a workflow without holding the whole of it in hand. `interface` is the one key where "sent" does not mean "sent in full" — sending it at all rewrites both the inputs and the outputs it describes, even if only one of them is included. A side left out of a present `interface`, or sent as an empty list, is cleared, not left alone. Absent and empty are the same signal there that they are not everywhere else in this rule: absent preserves, present (even partially or emptily) replaces. The `metadata` a caller reads back is not necessarily the `metadata` it would get by reading the stored document directly: an implementation may fold housekeeping fields such as a format marker or a schema version into what it publishes on read, without those fields having been part of what was stored. ## Example Three requests to the same door, none of them touching `interface` the same way. ```http title="A create with no nodes, edges or metadata" verdict="201 stored" POST /api/flowdrop/workflows {"id": "bare_wf", "name": "Bare"} ``` ```http title="An update naming only the name and the nodes" verdict="200 preserved" PUT /api/flowdrop/workflows/{workflow} {"name": "Partial renamed", "nodes": [ … ]} ``` ```http title="An update whose interface is present but empty" verdict="200 cleared" PUT /api/flowdrop/workflows/{workflow} {"name": "Clear", "interface": []} ``` The first leaves `nodes`, `edges` and `metadata` all as empty lists — nothing was sent for them, so there is nothing to default from but empty. The second leaves the edges and metadata a prior request had set untouched, because this request never mentions them. The third is the one that reads like the second but is not: `interface` was sent, so both its sides are rewritten, and an empty list on either side clears it rather than leaving it as it was. ## Related rules - Names: STORE-2, STORE-14 - Referenced by: STORE-14 --- Rule identifiers are permanent and are never renumbered. This specification carries no implementation status: each implementation publishes its own standing against these rules. Licensed CC BY 4.0.