v0.15.0
Added
-
kac validatesays when an import has fallen behind what its source publishes.kac restorekeeps the version
aconsumes:entry locked for as long as the range still admits it, which is what makes a restore reproducible and
is also how a corpus sits on a version nobody meant it to sit on. Sovalidateasks each source what it holds now,
once per run, and reports three new checks against.corpus.yaml.import-behindis a warning: a newer version sits inside the declared range, andkac restoretakes it.
import-cappedis information: a newer version is published and the range holds it back, which is a decision
the corpus already made.import-unreachableis information too, for a source this run could not ask, so a lock
reads as unchecked rather than as current. None of the three fails the build, because failing on somebody else's
release would turn every downstream red the day a governance corpus ships.A source answering with no versions at all reports as unreachable rather than as current, because a registry
answers a private feed's anonymous reader exactly as it answers a package nobody has published. A corpus with no
consumes:block reads no source and builds no client, and every other check still reads the working tree alone. -
A third severity,
info.kac validatecounts it in its summary line and in--json, where
summary.infosis new, andkac checkstallies it apart from the warnings. Neither a warning nor an info changes
the exit code. A check declaresseverity: infoin.schema/_checks.yaml.docs/design/checks.mdcovers it. -
A corpus says who it is, and
packandbundlestop inventing it. Four new keys in.corpus.yaml:
display-name,description,licenseandauthor.kac exportcarries them in a newaboutblock,kac pack
writes them into the package a registry lists, andkac bundlewrites them into the plugin manifest somebody
installs.A plugin's identity is now generated rather than copied.
name,version,displayName,description,
author,homepage,repository,licenseandkeywordsare all written from the corpus, and a key the corpus
declared nothing for is removed rather than left standing.authoris the exception, filed under the corpus's own
name where it named nobody, because the format asks for one andclaude plugin validate --strictfails a manifest
carrying none..plugin/.claude-plugin/plugin.jsonkeeps only what the
corpus declares:metadata.corpusRootandmetadata.components, plus any key this tool has never heard of. A
manifest copied from a template no longer publishes under the template author's name, licence and repository.keywordsare the types the export carried, so a plugin never advertises a type its corpus declined.kac new
writes the four keys bare, because a value supplied there would be inherited rather than chosen. -
kac exportnames the two keys that address a part. Each type's manifest entry gainsrecordKeyand
partKey, naming which key of a part line says which record it belongs to and which part of that record it is. A
type names its own keys, so a consumer holding a corpus with a type it never adopted had no way to read them and had
to assume a spelling. Both are absent where the type keeps no parts, aspartsFileis.docs/design/export.md
covers it. -
kac validateresolves a reference across a corpus boundary. A citation carrying a producer's shortcode, as
eng:pol-VURM.TIMEBOX, resolves against the exportkac restoreunpacked under.imports/. It is read in prose and
in a field declaring aref:, soimplements: eng:pol-VURM.TIMEBOXnames one clause rather than a whole policy, and
both halves are held to existing. Local records and imported ones go through one lookup, so a corpus is not judged
more loosely for having imported the record it cites.Each side keeps its own spelling. A record the reading corpus holds is cited bare, one it imported carries the
shortcode, and writing either the other way is refused naming the spelling to write.A new
import-restoredcheck fails a corpus declaring an import that is not on disk, and nameskac restore. Every
citation into that shortcode then stays quiet, so a run that has not restored reports one line rather than one per
reference.docs/cli/validate.mddocuments both. -
kac restorefetches the corpora a corpus declares it consumes. A newconsumes:block in.corpus.yamlnames
each producing corpus, the shortcode it is cited by, the version range it is wanted at and the source it comes from.
restoreresolves each range, fetches the packagekac packsealed, and unpacks it under.imports/<shortcode>/,
which the template now gitignores. The version each range resolved to is written back onto its own entry, so
.corpus.yamlstays the one description of what a corpus is.A
source:names a registry's service index or a folder of packages. A folder holds the same sealed package a
registry serves, so a corpus consuming a sibling in its own repository needs no registry, no token and no release. A
path is relative to the corpus declaring it, asupstream.urlis.A range says
1.2.0or^1.2.0and nothing else, and a caret never takes a prerelease. A lock the range still
admits is taken without asking the registry, so two restores of an unchanged descriptor write the same bytes. A run
says what it fetched, at which version, and which corpora were already current.A shortcode two entries both claim is refused naming both, as is a corpus two entries both consume, as is a package
whose own manifest is cited by a different shortcode from the one declared.KAC_REGISTRY_TOKENin the environment
carries a bearer token for a private feed.docs/cli/restore.mddocuments the verb, anddocs/corpus-descriptor.md
the block.