Zester v0.6.5
Added
-
Family parameter components (Amendment A1, spec §13). The
file.*
family's canonical parameters are now declared ONCE in embeddable family
components —makedirs,mode,user/groupownership, andsource—
and members embed them; the schema declaration, canonical usage text, and
runtime behavior contract are all shared, per the approved family-scoped
contract model. The framework gains member-supplied dimensions
(memberdefault/memberrequiredtag options +modschema.WithDefault/
WithRequired): the mode component fixes name/type/semantics while
file.managedsupplies 0644 andfile.directory0755; the source
component fixes everything but requiredness (file.copyrequires it).
Every field is stamped with its declaring type, and the vocabulary gate
gains a COMPONENT RATCHET: once a family component exists for a key, a
private redeclaration in any member — even byte-identical — fails CI. -
Paired-family components (A1 step 7).
ssh_auth.*(the user/config
target pair),host.*(the config/path hosts-file selector),cron.*
(the user/command entry identity), andpkg.*(refresh, with
member-supplied defaults:pkg.installedfalse,pkg.latesttrue —
behavior unchanged) now declare their canonical parameters once in family
components.git.*'s shared keys (branch/rev/force) stay member-declared:
their per-operation semantics genuinely differ, and the gate keeps their
contract signatures aligned. The pkg refresh vocabulary-ratchet entry is
retired — the in-family exception table is down to the single
maintainer-blessed permanent (file.line's action-selectormode). -
Canonical
file.*makedirsruntime contract, enforced by a shared
behavior suite. All six members (managed,copy,directory,
recurse,symlink,touch) now implement ONE contract:makedirs
governs missing PARENTS of the target only (created at 0755 when true);
when false, a missing parent fails BOTH Check and Apply with an error
naming the parent and themakedirs: trueremedy — no partial creation,
and Revert never removes created parents. A four-case behavior suite
(false/true × parents present/missing) runs against every embedding member. -
pathalias unified across the whole file family. All 13file.*
modules now acceptpathas an alias of their primary — previously 7 did
and 6 (absent, append, blockreplace, directory, recurse, symlink) rejected
it under strict params (or, on blockreplace, deliberately ignored it), so
- path: /srv/wwwworked onfile.managedbut failed onfile.directory.
Pinned by three-universe contract fixtures per module; blockreplace's old
"path is not an alias" pin is retired by this change. -
Family form for the doc surfaces (Salt parity).
zester '<target>' sys.doc ssh_authand the offlinezester doc ssh_authnow render every
documentedssh_auth.*module as one document (sorted, shared
RenderTextAllshape on both surfaces) instead of erroring
no documentation for "ssh_auth". Works for any family —file,pkg,
facts(dispatch specials included);--jsonreturns an array for a
family. Family names also joinzester doc's did-you-mean suggestions and
shell completion. -
Parameter vocabulary gate. A conformance test
(TestParameterVocabularyConsistency) now compares every parameter key —
canonical names and aliases — across ALL state and exec modules and fails
when the same key carries different schemas ("modemust always behave the
same"). The fleet passes with exactly three documented Salt-parity
exceptions (modein file.line = action selector;gidin group.present =
numeric-only create id;textin test.echo = scalar echo string), each
justified in the exception table, which also refuses stale entries. The
developing guide documents the rule. REWORKED to the family-scoped
two-tier form per the approved Amendment A1 (spec §13): the contract
boundary is (module kind, family, parameter name) — within one family the
full contract is compared (shape, aliases, primary, requiredness,
default), across families only the value shape (the same spelling may
legitimately mean different things in unrelated families). Alias keys are
first-class: the gate caughtdir_modemeaning an alias-of-mode on
file.directory but a standalone parameter on file.recurse. In-family
divergences are pinned as migration-ratchet entries the family-component
tranches delete. Exceptions are participant-pinned:
the exception covers only the known divergence, so a NEW module reusing an
excepted key (e.g. a thirdmodeshape) still fails until the pin is
deliberately updated. Dual-surface modules (cmd.run) now carry their
"also reachable as an execution module" header in the OFFLINE docs too —
the embedded docdata gains the same AlsoExecmod overlay live sys.doc
renders, and the docdata↔live parity test covers it.
Changed
- Family-oriented package layout (A1 step 8).
pkg/state/modulesis now
one package per module family (modules/file/,modules/cron/, …; package
namesfilemod,cronmod, …), each holding its members, its parameter
components (components.go), its behavior suites, its contract fixtures,
and its registration rows; shared plumbing lives inmodules/regdef
(registration types +MustSpec) andmodules/internal/famshared
(cross-family helpers). The aggregatorpkg/state/moduleskeeps its import
path and public API (RegisterAll, the dispatch specials) unchanged — no
consumer changes; file history follows the moves.
Fixed
-
makedirs: trueno longer accepts a regular file at the parent path, and
non-ENOENTStatfailures are surfaced instead of masked. The Apply-side
parent-creation arm returned success wheneverStat(parent)succeeded —
without checking it was a directory — and fell through toMkdirAllon ANY
stat error, hiding permission/I-O/provider failures behind a creation
attempt. It now succeeds only for an existing directory, reports a clear
not-a-directory error for a file, creates only on a genuine not-exist, and
wraps every other stat error untouched. Two new arms in the shared family
behavior suite pin both cases per member (regular-file parent; injected
non-ENOENT stat failure via the fake's new fault injection). -
makedirsCheck semantics re-ruled (Salt-aligned). A missing parent
withmakedirsunset no longer fails Check: dry runs do not materialize
changes from earlier required states, so a correctly ordered tree (a
directory state creating the parent, a file state writing into it with
require) must dry-run clean — Check now reports a would-change whose
detail names the missing parent and the remedy. Apply retains the strict
canonical contract: a parent still missing when the operation actually runs
fails without partial creation. Pinned by the ordered-tree dry-run,
ordered-tree apply, and standalone strict-apply cases in the family
behavior suite; BD-9's wording updated. (Also fixed en route: the exectest
fake's Chmod wiped file-TYPE bits, silently un-directorying entries.) -
A1 final-verification round.
file.directory's documentation was
drift-corrected (it still described the pre-fix inertmakedirs; the
published page contradicted its own parameter table) and the five other
members' Check effects now document the missing-parent failure; the fix is
minted as BD-9 in the spec and each member's Divergences. The makedirs
helpers nowCleanthe target path first (a trailing-slash target no
longer gates on itself) and report a parent that exists as a regular file
with a clear not-a-directory error.pkg.*'srefreshwas
UN-componentized: its two members genuinely differ in phase coverage and
error semantics (installed: Apply-only, fatal; latest: Check+Apply,
warn-only), so per §13 it is member-declared with a permanent pinned
exception — the git.* precedent. Gate hardening: the component ratchet now
fires for single-embedder components (a member defecting from a 2-member
component was previously invisible); member-supplied dimensions are only
legal on embedded component fields; untagged pointer-to-struct embeds are
compile errors (previously silently dropped the whole component); the
declaring-type stamp gained direct tests; same-signature keys with
per-member runtime meanings (dir_mode) are declared in a participant-
pinned meaning-variance registry. The behavior suite now asserts the 0755
creation mode, that errors name the missing parent, revert-never-removes-
parents, trailing-slash handling, and pins suite completeness against the
live embedder set. -
file.directorymakedirswas accepted but inert — deliberate
compatibility fix (A1). The module previously always created the full
parent chain (MkdirAll), silently masking typos in deep paths, and
ignored the flag. It now follows the canonical contract: a missing parent
withoutmakedirs: truefails Check and Apply. Behavioral difference from
0.6.0, maintainer-ruled; pinned by the shared behavior suite and the
makedirs contract fixtures across YAML/CLI/msgpack. -
The other five
makedirsmembers failed missing-parent cases with raw
OS errors and reported phantom applicable changes in Check. All now fail
both phases with the canonical contract error.file.recursepreviously
created missing parents withdir_modeinstead of the canonical 0755. -
file.directory'sdir_modeis now a standalone parameter (was an
alias ofmode): decode lands on its own field and the mode fallback
(mode wins;dir_modefills in whenmodeis undeclared) moved to the
builder — behavior is byte-identical to the alias era, pinned by
TestFileDirectoryDirModeFallbackand updated contract fixtures; its
contract signature now matchesfile.recurse'sdir_mode, retiring that
vocabulary-ratchet entry (along with thesourceone).