Repository navigation
Description
Part of #138. Separate object persistence from activity creation and provide the common write operations that #140 and #141 will call.
Currently createObject also stores a Create and adds it to the actor's outbox. A developer must be able to save an object alone, reuse it in an activity, or save an activity together with a new embedded local resource.
Scope
- Implement object-only persistence without creating an unwanted activity or dispatch. Make the distinction between private editor drafts and committed federation resources explicit; draft recovery belongs to Reuse drafts, documents, presets, and recipient sets #144.
- Save an activity that refers to an existing resource or an external IRI, using the shared representation and validator. Do not clone or modify the referenced resource merely because it is selected as a target.
- Save an activity with newly created local objects or nested activity resources as one consistent operation. Apply Define Activity Vocabulary coverage and the shared document contract #149's rules for identity allocation, ownership checks, and publication/outbox behavior when saving new resources.
- Support preparing an Update of an existing local object without rewriting previous activity documents. Implement the agreed rules for when a committed operation updates current state; opening an editor or validating input has no such side effect.
- Roll back all visible resource and relationship changes when validation or persistence fails. Recheck write permissions on the server, including nested local identities.
- Adapt the existing
createObjectpath without silently changing its established behavior for callers. Preserve it through an adapter or provide an explicit migration path with updated callers and documentation.
Completion criteria
- Tests save an object alone, create an activity referencing it, and atomically create a
Createwith a new Note. Nested activity input uses the same common write path. - A failure inside nested creation leaves no orphaned public object, activity, addressing entry, or outbox item. Retrying a failed transaction does not expose a partially saved document.
- Editing current object state leaves earlier activity snapshots intact. References keep their intended identities, and unauthorized cross-instance writes fail through direct API calls too.
- Existing creation tests and callers either continue to work or exercise the documented transition. Saving never schedules an outgoing delivery.
Ownership and starting points
This issue owns shared persistence operations and adaptation of existing creation behavior. #140 and #141 own their new editor-facing mutation shapes and UI; #145 owns dispatch creation, freezing, and delivery. Coordinate the common operation's inputs and failures with those owners before they implement separate write paths.
Inspect packages/graphql/src/object.ts, packages/models/src/resource.ts, and packages/federation/src/object.ts. Verify transaction behavior on both supported database backends where it differs.
Metadata
Metadata
Assignees
Labels
Type
Fields
Priority
Effort
Projects
- StatusShow more project fieldsDone
Activity
Questionas a poll object across persistence and resource reads #155Prepare document previews from trusted server-owned values
Prepare document previews from trusted server-owned values
Prepare document previews from trusted server-owned values
sij411 commentedon Oct 30, 2026
The shared preparation API in #166 exposes the following creation-field contract for integration with #152. This records the handoff here rather than requesting an update to closed #149.
prepareDocument(document, options)accepts a parsed document plus trusted server-reported authority outcomes and server-owned creation values. #152 decides permissions, allocates IDs/timestamps, and chooses whichid,actor,attributedTo,published, orupdatedfields it owns for each creation. These options must not come from editor input; they do not make those fieldsuniversally required on arbitrary documents.
Missing owned values receive proposed additions. Supported null absence receives proposed replacements; explicit null IDs remain invalid under the identifier rule. A matching single value is retained. Conflicting claims receive
server_owned_field_conflict, without silent replacement. Changes prefer the requested existing alias, and array conflicts retain source indexes.Denied outcomes receive
unauthorized_local_identityat the supplied diagnostic location, including[]for an operation-level denial. Authority paths are diagnostic locations, not writable target declarations.Caller configuration is checked before document errors or authority denials stop preparation. Invalid supported-field names, trusted values, duplicate semantic declarations, and missing parents throw
TypeError. When document errors or unsupported contexts/types prevent resolving a target or alias, the API retains document diagnostics rather than guessing a caller mistake.The API preserves input and returns explicit changes with an independent, revalidated preview only when checking completes without errors. It performs no permission queries, remote lookups, allocation, writes, or delivery.
#152 owns preview-to-commit coordination, transaction-time permission rechecks, persistence, and adapting write operations. A successful preparation result is not an authorization token. Commit the server values represented in the approved preview, or obtain a new preview if those values change.
Validate preparation configuration before document-error returns