A Graft backup retains the complete logical artifact store: payloads, revisions, selections, and every historical decision. It also includes valid orphan content. If the application has approved exclusions, use a replacement plan first. Neither operation changes the source.
The backup directory contains a canonical bundle.json
descriptor and an objects/ store. It is closed only after
every listed object has been copied and verified. Closure does not
promise filesystem flushes, a completed PostgreSQL transaction, or
permission to serve the contents.
Retain the identity separately
The application supplies an opaque scope and generation. They may identify an authenticated Reader’s artifact generation, but Graft does not interpret them or authenticate the Reader. Store the returned receipt in the application’s independent registry, along with the authority needed to decide whether the generation remains eligible for restore.
##
## Attaching package: 'graft'
## The following object is masked from 'package:base':
##
## Recall
source_path <- tempfile("source-")
backup_path <- tempfile("backup-")
source <- graft_store(source_path, create = TRUE)
evidence <- graft_save(
source, "Synthetic observation", id = "evidence", media_type = "text/plain"
)
report <- graft_save(
source, "An interpretation", id = "report", media_type = "text/plain",
dependencies = evidence
)
accepted <- graft_accept(
source, report, stream = "report-review", key = "review-1", expected = NULL,
actor = "synthetic-reviewer",
reason = "Evidence inspected", purpose = "research"
)
receipt <- graft_backup(
source, backup_path, scope = "synthetic-reader", generation = "generation-1"
)
receipt$format## [1] "graft-artifact-backup/1"
receipt$scope## [1] "synthetic-reader"
receipt$generation## [1] "generation-1"
The receipt binds the exact descriptor digest, scope, generation, and
complete manifest digest. It records identity; it is not a signature or
authorization token. Do not obtain expected by reading the
bundle being restored. Doing so would let the bundle choose its own
expected identity. Keep both bundles and receipts private; artifact
metadata and even linkable digests can disclose sensitive
information.
Verify before restoring
An application first reads its current independent registry and checks that the requested generation is eligible for the authenticated caller. It then supplies the stored receipt to verification or restore. This synthetic example keeps the receipt in memory and does not implement a durable registry.
identical(graft_verify_backup(backup_path, expected = receipt), receipt)## [1] TRUE
restore_path <- tempfile("restored-")
restored <- graft_store(restore_path, create = TRUE)
manifest <- graft_restore(backup_path, restored, expected = receipt)
identical(manifest$id, receipt$manifest)## [1] TRUE
graft_read(restored, report)@data## [1] "An interpretation"
identical(graft_history(restored, "report-review")[[1L]], accepted)## [1] TRUE
Verification rejects unsupported formats, altered descriptors, unexpected files, symbolic links, nonregular files, invalid histories, missing dependencies, and checksum mismatches. It compares every receipt field and inventories the complete store. Restore runs this check before writing target objects. It requires an empty target, then verifies the bundle again and the complete restored image before returning its manifest.
Caller arguments bound object count, total stored bytes, selection
and decision metadata, and descriptor size. The descriptor defaults to
at most 4 MiB; the store defaults to 10,000 objects and 64 MiB total.
Payload and revision limits come from the source or target store handle.
Standalone verification also exposes max_bytes and
max_revision_bytes. The bundle cannot supply these bounds.
A local inventory checks the object count and total bytes as it lists
each directory and stops at the first bound exceeded, but it still reads
each directory’s names at once.
A receipt from another scope or generation cannot certify this bundle, even if the artifact bytes are identical. An old bundle and its matching old receipt remain mechanically restorable. The application’s independent registry must deny retired generations, including after loading an old database backup. A bundle checksum cannot tell Graft that the registry was rolled back.
Recover an interrupted operation
Before starting, register the backup destination and its staging
parent with the application. The destination parent must already exist,
and paths must not contain .. parent-traversal components.
Graft creates a sibling staging directory. It renames that directory to
the absent destination only after verifying the complete image. It
refuses to overwrite an existing destination and cleans up its own
staging directory after ordinary errors. Process termination can leave
staging behind; the application must inventory and dispose of it
separately. Register the restore target before writing to it.
Fence writers and keep the directories trusted throughout the operation. Place a backup outside the source store and a restore target outside the bundle. Repeated verification does not create a concurrent filesystem snapshot. Do not expose a partially restored target. After a failure, quarantine it and retry with a fresh empty target. Graft never deletes existing destinations or source stores.
With PostgreSQL, use an application-owned transaction and a consistent order for scope locks. A backup can capture rows visible in that transaction before commit, so its receipt does not prove that the source transaction committed. A successful restore remains pending until the target transaction commits. Verify a committed, reopened candidate before publication. Filesystem and database operations do not form a distributed transaction.
Remaining recovery work
Closed bundle verification covers one step of the protocol. Durable independent generation retirement, write fencing, atomic publication, registry crash recovery, and deployment-specific retention and disposal remain tracked in Graft #86 and Rill #106. The Forget rollout gate remains open. These synthetic mechanics do not prove physical secure erasure or production recovery after power loss.
