carlos / platform Public

docs: the region HA contracts note records expectSeq, the fenced-source condition for copy retries, and Publish's refusal of replaced and torn files

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Paul Campbell pushed by claude agent, operated by paul@keymail.dev 9b1f6a4df74233d1b42a2322a9c49cfd2c4ee70e parent 3283c78
1 file changed, +33 −8
  • docs/superpowers/notes/2026-10-07-region-ha-contracts.md +33 −8

CI passed — run details

diff --git a/docs/superpowers/notes/2026-10-07-region-ha-contracts.md b/docs/superpowers/notes/2026-10-07-region-ha-contracts.md
index e06ceb98d..a5acba97f 100644
--- a/docs/superpowers/notes/2026-10-07-region-ha-contracts.md
+++ b/docs/superpowers/notes/2026-10-07-region-ha-contracts.md
@@ -28,11 +28,16 @@ Signatures:
func Restore(ctx context.Context, s release.Store, prefix, dir string, origins []string) (Manifest, RestoreStats, error)
func ReadPlatform(ctx context.Context, s release.Store, prefix string, m Manifest, name string, origins []string) ([]byte, error)
func LoadWake(ctx context.Context, s release.Store, prefix string, m Manifest, origins []string) (WakeState, bool, error)
-func CopyManifest(ctx context.Context, s release.Store, fromPrefix, toPrefix string, origins []string) (Manifest, error)
+func CopyManifest(ctx context.Context, s release.Store, fromPrefix, toPrefix string, expectSeq int64, origins []string) (Manifest, error)
var ErrOrigin = errors.New("hostfiles: object origin not admitted")
var ErrManifestExists = errors.New("hostfiles: the target generation already has a manifest")
+var ErrSourceMoved = errors.New("hostfiles: the source manifest is not at the expected seq")
```
+`prefix` must be a clean relative bucket key ending in `/`. Restore,
+ReadPlatform (and so LoadWake), Open and CopyManifest refuse any other
+prefix before reading anything.
+
`origins` is the set of generation prefixes that the caller's pin admits.
nil or empty means the manifest's own prefix only. The set is used exactly
as passed: a caller that passes a set must include the manifest's own
@@ -58,17 +63,32 @@ ReadPlatform and LoadWake apply the same rules to platform items.
CopyManifest reads `fromPrefix`'s manifest and validates every entry
against `origins` (nil means `fromPrefix` alone). A source built by an
earlier copy references earlier generations, so its caller passes the
-whole chain. CopyManifest then writes the same bytes, with the same Seq and
-the same qualified references, to `toPrefix`'s manifest. The write is
-create-only.
-No objects are copied. Errors:
+whole chain. CopyManifest then writes the same manifest (entries and Seq),
+with the same qualified references, to `toPrefix`'s manifest. The write is
+create-only. No objects are copied.
+
+`expectSeq` is the source revision the caller's pin admitted. When it is
+not 0 and the source is at any other Seq, the call returns
+`ErrSourceMoved` and writes nothing, on a first attempt or a retry. 0
+copies whatever the source holds.
+
+Errors:
- an absent source is `os.ErrNotExist`, never an empty copy;
-- a target already holding identical bytes is success, so a retry is safe;
+- a source not at a non-zero `expectSeq` is `ErrSourceMoved`;
+- a target already holding exactly the manifest this call would write is
+ success, so a retry is safe;
- any other target is `ErrManifestExists`, and the target is left as it
was;
- a source equal to the target is refused.
+Retry-safety requires a source that cannot commit between attempts: the
+source generation must be fenced or frozen. The claim's admission provides
+this. Against a live source, a retry can find the target holding an older
+revision. It then reports `ErrManifestExists`, or `ErrSourceMoved` when
+`expectSeq` is set. It never reports success for a revision the caller
+did not admit.
+
The new generation's `Open(toPrefix)` continues the sequence from the
copy. An unchanged file keeps its old-generation reference. A changed file
becomes a new object under `toPrefix`.
@@ -95,8 +115,13 @@ func Publish(ctx context.Context, s release.Store, prefix, dir string, skip func
in the manifest. A file larger than `MaxFileBytes` is recorded as
skipped and listed in `SyncStats.TooLarge`. Anything that is not a
regular file is left out and listed in `SyncStats.NotRegular`.
-- A file that exists but cannot be read is an error, and nothing is
- committed.
+- Publish is an install-time contract: it commits a complete and
+ consistent image or nothing. It returns an error and commits nothing
+ when any file could not be read (`SyncStats.Unreadable`), was replaced
+ between the look and the open (`SyncStats.Retry`), or changed while it
+ was read (`SyncStats.Torn`). The caller stops writers and calls Publish
+ again. Objects uploaded by a refused attempt are referenced by no
+ manifest.
- A prefix that already has a manifest is continued, not replaced. A
repeat with nothing changed returns the same sequence number. If another
writer's manifest appears between Open and Commit, the error is