1 Commits
Author SHA1 Message Date
sneak 181e1486cf Drop atime from the format spec and pin the file entry fields (closes #158)
check / check (push) Failing after 3s
atime left mf.proto earlier and nothing reads or writes it, but
docs/FORMAT.md still narrated its removal and listed it among the
determinism rules. The spec now describes the file entry by its fields
only.

A new test compares the MFFilePath message descriptor against the
fields the spec lists, by name and number, so a field added to or
removed from the proto without a matching spec change fails the build.

Model: opus-5-5
2026-10-05 23:23:43 +00:00
2 changed files with 25 additions and 4 deletions
-4
View File
@@ -78,9 +78,6 @@ Each file entry contains:
| `mtime` | 302 | Timestamp (optional) | Modification time | | `mtime` | 302 | Timestamp (optional) | Modification time |
| `ctime` | 303 | Timestamp (optional) | Change time (inode metadata change) | | `ctime` | 303 | Timestamp (optional) | Change time (inode metadata change) |
Field 304 (`atime`) has been removed from the specification. Access time is
volatile and non-deterministic; it is not useful for integrity verification.
## Path Rules ## Path Rules
All `path` values must satisfy these invariants: All `path` values must satisfy these invariants:
@@ -130,7 +127,6 @@ By default, manifests are generated deterministically:
- File entries are sorted by `path` in **lexicographic byte order** - File entries are sorted by `path` in **lexicographic byte order**
- `createdAt` is omitted unless explicitly requested - `createdAt` is omitted unless explicitly requested
- `atime` is never included (field removed from schema)
This ensures that two independent runs over the same directory tree produce This ensures that two independent runs over the same directory tree produce
byte-identical `.mf` files (assuming file contents and metadata have not byte-identical `.mf` files (assuming file contents and metadata have not
+25
View File
@@ -8,6 +8,8 @@ import (
"testing" "testing"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
"google.golang.org/protobuf/reflect/protoreflect"
"sneak.berlin/go/mfer/mfer"
) )
// mf.pb.go is generated from mf.proto and committed. `make generate` // mf.pb.go is generated from mf.proto and committed. `make generate`
@@ -27,3 +29,26 @@ func TestGeneratedCodeMatchesProto(t *testing.T) {
"mfer/mf.proto has changed since mfer/mf.pb.go was generated "+ "mfer/mf.proto has changed since mfer/mf.pb.go was generated "+
"from it: run `make generate` and commit the result") "from it: run `make generate` and commit the result")
} }
// A file entry has exactly the fields docs/FORMAT.md lists for MFFilePath.
func TestFileEntryFieldsMatchSpec(t *testing.T) {
t.Parallel()
want := map[string]protoreflect.FieldNumber{
"path": 1,
"size": 2,
"hashes": 3,
"mimeType": 301,
"mtime": 302,
"ctime": 303,
}
got := map[string]protoreflect.FieldNumber{}
fields := (&mfer.MFFilePath{}).ProtoReflect().Descriptor().Fields()
for i := range fields.Len() {
got[string(fields.Get(i).Name())] = fields.Get(i).Number()
}
require.Equal(t, want, got)
}