DECISION: public API surface and determinism defaults for 1.0 #83

Open
opened 2026-08-09 03:44:35 +02:00 by clawbot · 0 comments
Collaborator

Owner decisions required. The remaining questions from the README 1.0
roadmap, minus the ones already resolved by the code.

Two of the original questions are moot and need no answer: question 12
(consolidate scanner/checker) is already done — internal/scanner/ and
internal/checker/ no longer exist. Question 14 (module path) is tracked
separately as #79.


11. Should manifests be deterministic by default? Determinism means:
sort entries by path, omit createdAt, no atime. Sorting is already
unconditional (mfer/builder.go:285-287). A --seed flag exists for
deterministic UUIDs and an --include-timestamps flag already exists.

So the real remaining question is narrow: should createdAt and timestamps
be off by default with opt-in, or on by default with opt-out?

Recommendation: deterministic by default, timestamps opt-in via the
existing --include-timestamps flag. Reproducibility is a stated project
goal, and defaults are what almost everyone gets. A user who wants
timestamps knows they want them; a user who wants reproducibility
generally does not know they need to ask. This is a user-visible behavior
change to mfer gen, which is exactly the kind of thing to do before 1.0
rather than after.

13. Export the manifest type, or define an interface? The type is
unexported with exported constructors (NewManifestFromReader,
NewManifestFromFile). Consumers cannot write var m *mfer.manifest, so
they cannot store a loaded manifest in their own struct fields — which makes
this genuinely unusable as a library for anything non-trivial.

Recommendation: define an exported interface rather than exporting the
concrete struct. An interface pins the contract you intend to support and
leaves the internals free to change after 1.0; exporting the struct
freezes every field. Given the whole point of this repo is to be a
reference implementation others build on, the API surface should be the
smallest thing that is actually usable.

Whichever way this goes, it must be settled before the tag — this is the
single most consequential API decision in the milestone, because it is the
one that cannot be relaxed later without a major version.


Definition of done

  • Both questions answered inline in a comment here.
  • Each answer becomes a tracked implementation issue.
  • The API decision is reflected in the README Design section (#75) so
    consumers can see the intended usage shape.

Please answer and reassign to clawbot.

Owner decisions required. The remaining questions from the README 1.0 roadmap, minus the ones already resolved by the code. Two of the original questions are moot and need no answer: question 12 (consolidate scanner/checker) is already done — `internal/scanner/` and `internal/checker/` no longer exist. Question 14 (module path) is tracked separately as #79. --- **11. Should manifests be deterministic by default?** Determinism means: sort entries by path, omit `createdAt`, no `atime`. Sorting is already unconditional (`mfer/builder.go:285-287`). A `--seed` flag exists for deterministic UUIDs and an `--include-timestamps` flag already exists. So the real remaining question is narrow: should `createdAt` and timestamps be **off** by default with opt-in, or **on** by default with opt-out? > _Recommendation:_ deterministic by default, timestamps opt-in via the > existing `--include-timestamps` flag. Reproducibility is a stated project > goal, and defaults are what almost everyone gets. A user who wants > timestamps knows they want them; a user who wants reproducibility > generally does not know they need to ask. This is a user-visible behavior > change to `mfer gen`, which is exactly the kind of thing to do before 1.0 > rather than after. **13. Export the `manifest` type, or define an interface?** The type is unexported with exported constructors (`NewManifestFromReader`, `NewManifestFromFile`). Consumers cannot write `var m *mfer.manifest`, so they cannot store a loaded manifest in their own struct fields — which makes this genuinely unusable as a library for anything non-trivial. > _Recommendation:_ define an exported interface rather than exporting the > concrete struct. An interface pins the contract you intend to support and > leaves the internals free to change after 1.0; exporting the struct > freezes every field. Given the whole point of this repo is to be a > reference implementation others build on, the API surface should be the > smallest thing that is actually usable. > > Whichever way this goes, it must be settled before the tag — this is the > single most consequential API decision in the milestone, because it is the > one that cannot be relaxed later without a major version. --- ## Definition of done - Both questions answered inline in a comment here. - Each answer becomes a tracked implementation issue. - The API decision is reflected in the README `Design` section (#75) so consumers can see the intended usage shape. Please answer and reassign to `clawbot`.
clawbot added this to the 1.0.0 milestone 2026-08-09 03:44:35 +02:00
sneak was assigned by clawbot 2026-08-09 03:44:35 +02:00
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: sneak/mfer#83