From 4322a7b75d7016fe70daf0e0b15e3d1b38b27b3c Mon Sep 17 00:00:00 2001 From: sneak Date: Mon, 5 Oct 2026 23:21:13 +0000 Subject: [PATCH] Drop atime from the format spec and pin the file entry fields (closes #158) 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 --- docs/FORMAT.md | 4 ---- mfer/mf_test.go | 24 ++++++++++++++++++++++++ 2 files changed, 24 insertions(+), 4 deletions(-) diff --git a/docs/FORMAT.md b/docs/FORMAT.md index 6ff067c..44e8e7c 100644 --- a/docs/FORMAT.md +++ b/docs/FORMAT.md @@ -78,9 +78,6 @@ Each file entry contains: | `mtime` | 302 | Timestamp (optional) | Modification time | | `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 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** - `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 byte-identical `.mf` files (assuming file contents and metadata have not diff --git a/mfer/mf_test.go b/mfer/mf_test.go index f481176..ac20ef0 100644 --- a/mfer/mf_test.go +++ b/mfer/mf_test.go @@ -8,6 +8,8 @@ import ( "testing" "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` @@ -27,3 +29,25 @@ func TestGeneratedCodeMatchesProto(t *testing.T) { "mfer/mf.proto has changed since mfer/mf.pb.go was generated "+ "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) +}