docs: propose the S3 object-lock design (per-key version-state tree) - #77
Open
frrist wants to merge 3 commits into
Open
docs: propose the S3 object-lock design (per-key version-state tree)#77frrist wants to merge 3 commits into
frrist wants to merge 3 commits into
Conversation
Object Lock as storage plus sentinel errors: versitygw's controller layer owns all WORM enforcement (auth.CheckObjectAccess), so ingot's backend stores lock state and returns the exact absent-case sentinels. Per-version retention and legal holds live in a per-key version-state tree beside the prev tree: state mutations rewrite only positional blocks (state block, state tree, leaf, top path), so manifests stay immutable and version identity (invariant 5 of the versioning design) holds verbatim, while the state rides the catalog plane and ships to Forge. Stamping and cleanup are atomic with the commits that create and remove versions. The VersionState block is the general home for mutable per-version service state: lock is its first tenant, and the reserved Tags field lets object tagging follow as handlers with no format change. The registry-rows alternative is specified alongside for review; manifest rewrite, inline leaf state, and a parallel bucket tree are rejected in Appendix A. Governance bypass defers to the bucket-policy feature: the controller authorizes bypass off the bucket policy document, so until policies land GOVERNANCE denies exactly like COMPLIANCE. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Three details the implementation run against the versitygw suite pinned differently than first specified: key existence outranks the lock-enabled gate in the §6 check order (GetObjectRetention_non_existing_object runs against a lock-free bucket and expects NoSuchKey, matching posix); the missing-configuration error splits by path, with the spaced variant on the four per-version methods and the NoSpaces variant on all three creation-time header paths; and the controller passes an absent retain-until header as a pointer to the zero time. §11 also records the versioning-disabled-mode exclusion precisely and the versioned-teardown home for lock-enabled-bucket cases from plain-conf groups. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Backwards compatibility is not a requirement at this stage: per the repo's dev-only data posture there is no pre-lock reader to protect, so the State field joins ObjectLeaf under the existing "/objectleaf/0" union key with no compatibility shim. The union's format-revision mechanism stays in reserve for revisions that need loud incompatibility. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
hannahhoward
approved these changes
Aug 12, 2026
hannahhoward
left a comment
Contributor
There was a problem hiding this comment.
LGTM. I did do a fairly close read but I don't see anything I object to. This looks like a very sound design. Thank you versitygw for enforcing the rules for us.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Implementation spec for S3 Object Lock, following the versioning-doc workflow: this PR is the design; the implementation follows as a stacked PR on this branch.
The shape of the feature: versitygw's controller layer owns every WORM decision (
auth.CheckObjectAccessruns before Put/Copy/Delete/Complete reach the backend), so ingot's job is storage plus exact sentinel errors — no enforcement logic on our write or delete paths (§1–§2).The decision to review (§3): where per-version retention and legal holds live.
Proposed: a per-key version-state tree — the leaf gains a
Statesub-tree besidePrev, mappingrevSeqKey(seq)to a smallVersionStateblock. Mutations rewrite only positional blocks, so manifests stay immutable and versioning invariant 5 holds verbatim; the state rides the catalog plane to Forge (the replication/recovery argument); stamping and cleanup are atomic with the commits that create and remove versions. The alternative (registry rows: simpler, SQL-queryable, but post-commit crash windows and catalog-incomplete) is specified alongside; manifest rewrite, inline leaf state, and a parallel bucket tree are rejected in Appendix A.Also of note:
VersionStatereserves aTagsfield now so object tagging (next up) lands as handlers with zero format change; the merge/empty-elision/cleanup rules are written feature-generically (§4.1, §9).GOVERNANCEdenies exactly likeCOMPLIANCE, with a documented same-mode-replacement escape hatch (§10).TestWORMProtectionexclusions (upstream's unversioned-gateway semantics that a versioned ingot bucket can never exhibit), and the XFail rows that flip when this lands.🤖 Generated with Claude Code