Skip to content

0.1.0 release prep: 1.16 floor, four contract-bug fixes, hex.pm docs reconciliation#3

Merged
ivarvong merged 4 commits into
mainfrom
config-tighten-1.16-floor
Jun 11, 2026
Merged

0.1.0 release prep: 1.16 floor, four contract-bug fixes, hex.pm docs reconciliation#3
ivarvong merged 4 commits into
mainfrom
config-tighten-1.16-floor

Conversation

@ivarvong

@ivarvong ivarvong commented Jun 8, 2026

Copy link
Copy Markdown
Owner

Prep for the first Hex release (vfs 0.1.0). The name is confirmed available on hex.pm. Two parts: the floor/config tightening (first three commits), and the must-fix list from a multi-agent release-readiness audit (final commit) — four real contract bugs plus a sweep of every public-facing doc that would have shipped stale to hex.pm.

Lower the Elixir floor to 1.16

  • elixir: "~> 1.18""~> 1.16". The library code uses no 1.17/1.18-only features (no built-in JSON, Duration, Date.shift, etc.).
  • CI gains a real floor lane: Elixir 1.16.3 / OTP 26.2 (1.16 predates OTP 27), alongside 1.18, 1.20-rc, and the consolidation lane.

Tighten mix config

  • Removed application/0 — its extra_applications: [:logger] was dead config; Logger is never used and telemetry auto-starts as a dependency.
  • consolidate_protocols now reads VFS_CONSOLIDATE_PROTOCOLS — CI set that env var but mix.exs ignored it, so the "consolidate=true" lane tested nothing.
  • Removed elixirc_options: [warnings_as_errors: true] — redundant with the check alias and risky for consumers. CI still enforces zero-warnings via mix check.
  • Moved mix vfs.audit / mix vfs.mutate out of the package (lib/mix/tasks/dev/, compiled in dev/test only).
  • def cli re-added for preferred_envs: [check: :test] so a bare mix check works outside MIX_ENV=test (an earlier commit dropped it as "1.17+ only" — Mix.Project.cli/0 is 1.15+, so it's floor-safe; the 1.16 CI lane proves it). mix setup now also installs the pre-commit hook CLAUDE.md promises.

Contract bugs (each locked in by a property in contracts_test.exs, written RED first)

  • Mount-table readdir listed duplicate names — sibling mounts under a shared synthetic parent (/a/b + /a/c) each contributed "a" to readdir("/"). Synthetic children now dedupe at the source.
  • VFS.Memory mkdir violated the :eexist contract for implicit directories and root, and parents: true errored on the second call. Any existing directory is now :eexist; parents: true is an idempotent success no-op (mkdir -p semantics). The stateful-property reference model encoded the old semantics and was corrected with it.
  • Dispatcher errors leaked backend-internal paths in messages:path was rewritten into the user's namespace but the default :message still named the mount-stripped path. New VFS.Error.put_path/2 regenerates the default message on rewrite; custom backend messages are preserved.
  • VFS.Memory.new/1 accepted non-binary seed keys/values, deferring the crash to first read. Both now raise a clear ArgumentError at construction, with adversarial input properties.

Also: VFS.readdir/2's @spec narrowed the protocol's Enumerable.t(String.t()) to a list (the dispatcher's own unbounded branch returns a Stream); the VFS moduledoc claimed telemetry wrapped every public op when four lookups aren't instrumented. Both now match reality.

Public docs / packaging for hex.pm

  • README: real hex install snippet ({:vfs, "~> 0.1.0"}), stated 1.16 floor, relative links replaced with absolute GitHub URLs (they 404 on hexdocs).
  • SPEC.md: explicit dated amendment reconciling the pre-implementation draft with the shipped surface — 10-callback protocol with %VFS.Error{} returns, real capability set, Skeleton/mount-table sketches matching shipped code, grep/glob/cp/mv reframed as consumer-side. Rationale and decision table untouched.
  • CLAUDE.md: 1.16 floor, "9 callbacks" → 10, :mkdir capability documented, fictional Skeleton read_file/2 override corrected, real four-leg CI matrix described.
  • CHANGELOG: stamped 0.1.0 (2026-06-10), duplicate ### Added merged, autolink warnings fixed, the new fixes documented.
  • mix.exs docs config: filter_modules keeps maintainer-only Mix tasks out of hexdocs; VFS.Error/VFS.StreamOptions added to docs groups.

Verification

  • mix check: green from a bare prompt — format, compile -W, credo 0 issues, dialyzer 0 errors, 100.0% line coverage on every file
  • mix test --include integration: 38 doctests, 52 properties, 340 tests, 0 failures
  • mix docs: zero warnings (was 5+)
  • mix vfs.audit: 0 high / 0 medium / 0 low
  • mix hex.build: clean; tarball metadata shows only telemetry ~> 1.3, ~> 1.16

Release note

After merge, publishing is: git tag v0.1.0 && git push --tags && mix hex.publish — the tag must exist for source_ref and the CHANGELOG compare links to resolve.

🤖 Generated with Claude Code

ivarvong and others added 4 commits June 8, 2026 07:43
Release prep for the first Hex publish:

- elixir floor ~> 1.18 -> ~> 1.16; CI gains a real 1.16.3 / OTP 26.2 floor lane
- drop the 1.17-only cli/0 callback (inert on the 1.16 floor)
- remove dead application/0 (Logger is never used; telemetry auto-starts as a dep)
- consolidate_protocols/0 now honors VFS_CONSOLIDATE_PROTOCOLS — the CI
  consolidate lane was a silent no-op before
- drop always-on elixirc_options warnings_as_errors: redundant with the check
  alias and could break a consumer's build on a future-Elixir warning
- move maintainer mix tasks (vfs.audit, vfs.mutate) from lib/ to dev/ so they
  compile in dev/test but never ship into consumers' projects
- stamp CHANGELOG 0.1.0
- gitignore .env (local secrets)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
skip_files still pointed at lib/mix/tasks/; moving the maintainer tasks to dev/ left them counted against the 100% coverage gate, failing coveralls on every lane. Point skip_files at dev/ and add dev/ to formatter inputs. Verified locally: coveralls 100.0%, consolidate lane green.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…docs reconciliation

Code (each property-tested RED→GREEN in contracts_test.exs first):
- dedupe synthetic mountpoint children so mount-table readdir never
  lists duplicate names (mounts at /a/b + /a/c made readdir("/") return
  ["a", "a"])
- VFS.Memory mkdir: :eexist for implicit dirs and root; parents: true is
  an idempotent success no-op over existing directories (mkdir -p);
  reference model updated to match
- new VFS.Error.put_path/2 regenerates the default message when the
  dispatcher rewrites :path into the user's namespace (messages no
  longer name mount-stripped backend-internal paths)
- VFS.Memory.new/1 rejects non-binary seed keys/values at construction
  with a clear ArgumentError instead of crashing at first read
- VFS.readdir/2 spec widened to Enumerable.t(String.t()) to match the
  protocol; VFS moduledoc no longer overclaims telemetry coverage

Docs/packaging for hex.pm:
- README: hex install snippet + 1.16 floor, absolute GitHub links
- SPEC.md: amended to the shipped surface (10-callback protocol,
  %VFS.Error{} returns, real capability set, grep/glob/cp/mv cut)
- CLAUDE.md: 1.16 floor, 10 callbacks, :mkdir capability, real CI
  matrix, corrected Skeleton/read_file guidance
- CHANGELOG: 0.1.0 entry restructured (single Added section), today's
  fixes documented
- mix.exs: filter_modules keeps dev-only Mix tasks out of hexdocs;
  Error/StreamOptions grouped; preferred_envs makes bare `mix check`
  work; `mix setup` installs the promised pre-commit hook

Gates: mix check green (100.0% coverage), 340 tests + integration green,
mix docs warning-free, mix vfs.audit 0/0/0, mix hex.build clean.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@ivarvong ivarvong changed the title chore: prep 0.1.0 — lower Elixir floor to 1.16, tighten mix config 0.1.0 release prep: 1.16 floor, four contract-bug fixes, hex.pm docs reconciliation Jun 10, 2026
@ivarvong ivarvong merged commit ebda41e into main Jun 11, 2026
4 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant