Skip to content

chore(main): release component 1.0.0 - #1

Open
github-actions[bot] wants to merge 1 commit into
mainfrom
release-please--branches--main--components--component
Open

chore(main): release component 1.0.0#1
github-actions[bot] wants to merge 1 commit into
mainfrom
release-please--branches--main--components--component

Conversation

@github-actions

@github-actions github-actions Bot commented Aug 8, 2026

Copy link
Copy Markdown

🤖 I have created a release beep boop

1.0.0 (2026-08-18)

⚠ BREAKING CHANGES

  • a SERVICE declaring no endpoints, or an empty endpoints mapping, is now rejected. No new v directory: no family has been published, git tag -l is empty and the release-please manifest reads 0.0.0, so §3's compatibility guarantee has no released version to run from. ADR 0005 §1 sets out that window and §4 records this decision. The window closes on the first tag.
  • component: bounding containerPort, restricting a PUBLIC endpoint's protocol, constraining endpoint names, and reshaping platformDefault each reject documents that validate today. No v1.0.0 has been published — every family reads 0.0.0 in the release-please manifest and no tag exists — so §3's guarantee has no released version to run from and this lands free. It does not once chore(main): release component 1.0.0 #1/chore(main): release blueprint 1.0.0 #2/chore(main): release listing 1.0.0 #3 merge.

Additions

  • blueprint: specify node compute — the size grammar, the Compute Profile catalog, and the advanced pins (#35) (0a6e4b2)
  • bootstrap the canonical Musher specification repository (e3b8ea5)
  • close the endpoint, environment-variable, and graph-rule specification gaps (#31) (3b7110c)
  • component: define metadata.version semantics and the endpoint block (#27) (02dc6da)
  • execute the semantic phase, and close the conformance debt behind issue #9 (#25) (5be1e0a)
  • fill the spec.md TODOs from implemented behaviour, and settle cycle detection (#13) (be77e19)
  • reconcile the specification/platform divergences, and expose the edge address (#41) (af2dec0)
  • repo: rebuild exact-version schemas from tags, and harden the specification for 1.0.0 (#42) (e840e6d)

Corrections

  • enforce the §2 unknown-property rule below the envelope (#10) (cdc3cc4)

Specification prose

  • component: specify the behaviour when a document uses a field from a newer schema release (#26) (0ce4997)

This PR was generated with Release Please. See documentation.

@github-actions
github-actions Bot force-pushed the release-please--branches--main--components--component branch from 04936de to d7f4089 Compare August 9, 2026 01:23
@github-actions
github-actions Bot requested a review from justinmerrell as a code owner August 9, 2026 01:23
@github-actions
github-actions Bot force-pushed the release-please--branches--main--components--component branch from d7f4089 to 02daa6e Compare August 9, 2026 02:53
@github-actions
github-actions Bot force-pushed the release-please--branches--main--components--component branch from 02daa6e to b7814f5 Compare August 9, 2026 04:42
justinmerrell added a commit that referenced this pull request Aug 9, 2026
…nd issue #9 (#25)

* docs(conformance): ADR 0002, extend the fixture contract to a case tree

Eight of the twenty-four diagnostic codes the three spec.md files declare are
about a document's surroundings rather than its contents — a directory with a
name, a sibling document, a file on disk. A case was one `case.yaml`, so none
of them had a fixture, and they reached `main` as prose with CI green. That is
the failure mode CONTRIBUTING.md ground rule 2 exists to prevent.

GOVERNANCE.md lists "Changing the conformance fixture contract" among the
changes needing an ADR. This is that change.

A case directory MAY now carry a `tree/` instead of a `case.yaml`, with
`metadata.document` naming the file under test inside it. `tree/` is the parent
of the item root rather than the item root itself: ERR_SLUG_MISMATCH tests the
item directory's *name*, so a fixture for it needs a directory that has one.

`case.yaml` is not thereby the legacy form, and the ADR says so. It asserts that
the document has no item root — a real state, per blueprint §3.1, and the one an
API payload arrives in. Making `tree/` the only form would have traded one blind
spot for another.

Symlinks are declared in metadata rather than committed. ERR_PATH_ESCAPE is
reachable only by symlink now that listing §5's grammar makes `..` unspellable,
and a committed link does not survive a checkout without `core.symlinks`, is
invisible in a diff, and would ship inside a release tarball pointing outside
the archive.

The ADR also corrects tools/src/validator.ts, which asserted that the semantic
phase was out of scope "per ADR 0001". ADR 0001 §6 forbids *publishing* a
reference validator and is untouched; §7 describes tools/ as one non-normative
adapter. Implementing more phases inside it publishes nothing. The alternative
was a corpus in which every semantic clause was checked by nothing at all.

Refs: #9
Signed-off-by: Justin Merrell <merrelljustin@gmail.com>

* fix(tools): reject YAML anchors and aliases in the parser phase

Component §7 has said since bootstrap that the parser phase MUST reject anchors
and aliases. Nothing did. `parseDocument` set `uniqueKeys`, `merge: false` and
`strict`, none of which touches an alias — a document spelling `&b` / `*b`
parsed cleanly and the alias expanded.

The parser now walks the tree and rejects both. `maxAliasCount` would have
covered the alias and not the lone anchor, which is inert and rejected anyway:
an author who writes one is reaching for a feature this contract withholds, and
§2 already settled that a field which does nothing is an error rather than a
silence.

Two codes rather than one. `ERR_ANCHOR_OR_ALIAS` is new. `ERR_INVALID_YAML` is
not — `validator.ts` has emitted it since bootstrap and no spec.md declared it,
so a fixture citing it would have been rejected by the runner's own registry
check as an unknown code. Both are now in component §8, and the two say
different things to an author: one means the document is malformed, the other
means it is well-formed and uses something this contract does not have.

Also switches the parser from `parse` to `parseDocument`, which reports every
problem instead of throwing on the first and carries machine-readable error
codes. The previous implementation matched on message text — the one thing this
specification explicitly declares non-normative.

The parser lives in a new document.ts so that semantic.ts can read an item's
other documents without closing an import cycle.

Fail-before evidence: all six anchor/alias cases validate cleanly against
tools/ at be77e19 and fail after. The three malformed-YAML cases are green
beforehand and are the regression pin for the code registration.

This tightens the parser phase — a document with an alias validates today and
will not after. It is free while no tag exists and release PRs #1/#2/#3 are
open; after they merge it is a v2 directory plus a migration note.

Refs: #9
Signed-off-by: Justin Merrell <merrelljustin@gmail.com>

* feat(tools): implement the semantic phase and the case-tree runner

Every semantic clause PR #13 wrote — acyclicity, the floating-tag blocklist,
ERR_CONFLICTING_INPUT_SCHEMA, the media rules — was prose that nothing in CI
ever executed. Five fixtures existed and all five were skipped.

New semantic.ts, split the way the prose splits the rules rather than the way
this runner would find convenient.

An **in-document** rule is decided by reading the document: a floating image
tag, a probe naming an endpoint that is not declared, a `fromRole` naming no
node, a cycle, two screenshots sharing a basename.

An **item-scoped** rule is measured against the item root, and is reported only
when the caller supplies one. That is blueprint §3.1's rule, not a concession:
"an implementation handed a document rather than a directory MUST NOT report any
of them … a diagnostic it cannot substantiate is worse than a silence." It is
also why `check:examples` stays green — `examples/` is not an item root, and its
documents reference `./components/postgres.yaml` and `media/icon.png`, neither
of which exists beside them. PR #13's body flagged that as latent breakage;
this is the shape that makes it not one.

Cycle reporting follows §4.2's canonical form exactly: strongly connected
components, each reported as a closed walk from the lexicographically smallest
node, choosing the smallest successor at each step. Verified stable across the
three key orderings of one three-node cycle — the walk is a property of the
graph, not of the traversal, which is the whole point of pinning it.

conformance.ts gains the ADR 0002 case-tree form: `tree/` materialised to a
scratch directory with its declared symlinks created there, validated with the
item root set to the document's own directory. A case must declare exactly one
of `case.yaml` or `tree/`; declaring both leaves it ambiguous which one the
diagnostics describe.

`IMPLEMENTED_PHASES` gains `semantic`. `capability` stays out — it needs an
account, a region and a quota, which is a server.

Refs: #9
Signed-off-by: Justin Merrell <merrelljustin@gmail.com>

* fix(listing): correct the stale media-path description

`$defs.ListingSpec.description` still told readers that `icon` and
`screenshots[].file` are "paths relative to the listing document" — the exact
wording §5 now singles out as wrong: "`media/` is a stronger rule than 'relative
to the listing document'. That was this section's earlier wording, and it is not
what anything enforces."

PR #13 updated the two per-property descriptions and missed the containing
object's, so the schema contradicted itself and the prose in one file.

Refs: #9
Signed-off-by: Justin Merrell <merrelljustin@gmail.com>

* test(conformance): the item-scoped semantic cases, against ADR 0002

Thirteen new cases covering every diagnostic code that needed a directory to
exist. All are trees; none was expressible before.

blueprint 003–009 take the identity, reference and merge rules one at a time —
slug against the directory name, version against the sibling listing, a
component document nothing references, a reference resolving to nothing, a
reference escaping the item root, a `fromOutput` naming no output of the
component it resolves to, and two nodes declaring one input key with differing
schemas.

Three deserve their reasons stated:

  007  the reference is `../shared/postgres.yaml` and the document it lands on
       exists. A leading `../` is legal spelling — it is how a blueprint reaches
       a sibling directory — so only a containment check on the resolved path
       catches this one.

  009  `api` and `db` both declare `adminPassword`, STRING against INTEGER.
       `api` sorts first, so `api`'s declaration stands and `db`'s is reported.
       The case exists because silent first-wins is defensible until you write
       down which schema the second component's value was validated against.

  011  a three-node cycle written as queue, db, cache. semantic-002 cannot make
       this case: with two nodes, "smallest first" and "first declared" can
       coincide by luck. Here they do not, so an implementation reporting from
       wherever its traversal started produces the wrong walk and fails.

listing 002–005 mirror the identity rules and add the two media rules that need
the filesystem. 005 is the symlink case, declared in metadata rather than
committed per ADR 0002 §3.

blueprint 010 and listing 006 are the positive cases, and they are not padding.
Each satisfies every item-scoped rule of its family at once, which makes them
the regression pin for the class: a careless containment check or a merge rule
that forgets to absorb an identical redeclaration rejects a well-formed item,
and nothing else in the corpus would notice.

`ERR_UNKNOWN_COMPONENT` remains uncovered. It is `capability` — resolving a
published reference needs the catalog, and no phase a client runs may reach the
network.

Refs: #9
Signed-off-by: Justin Merrell <merrelljustin@gmail.com>

* docs(conformance): record coverage as a check rather than a claim

The runner enforced fixture → spec: every code a case declares must exist in a
reachable diagnostics table, at the right phase. Nothing enforced spec →
fixture, which is how ten codes reached `main` untested with CI green.

Two checks close it. Every `ERR_*` row in a family's own diagnostics table must
be exercised by an indexed case or appear in `UNCOVERED` with a reason — after
this branch that list holds one entry. And every case directory on disk must be
named by `cases.json`, since the runner reads the index rather than walking the
tree: an unindexed directory is not a failing fixture, it is an invisible one.

Both were verified by injecting a violation and watching the check fail.

The README's "Coverage status" described a limitation ADR 0002 removes, so it is
rewritten around what is now true: three phases covered, one code uncovered, and
a check that derives the list instead of a paragraph someone has to remember to
update. It also documents the `tree/` form, `document`, and `symlinks`.

CONTRIBUTING gains the obligation this creates: adding a diagnostic code to a
spec.md means adding a case for it.

Refs: #9
Signed-off-by: Justin Merrell <merrelljustin@gmail.com>

---------

Signed-off-by: Justin Merrell <merrelljustin@gmail.com>
@github-actions
github-actions Bot force-pushed the release-please--branches--main--components--component branch from b7814f5 to 1d1cb68 Compare August 9, 2026 05:41
@github-actions
github-actions Bot force-pushed the release-please--branches--main--components--component branch from 1d1cb68 to 9483e3f Compare August 9, 2026 09:25
justinmerrell added a commit that referenced this pull request Aug 9, 2026
…lock (#27)

* feat(component): define metadata.version semantics

Section 4 was a heading and a TODO, while metadata.version was already
load-bearing in three rules: blueprint §4.1 deploys "the referenced
document's own metadata.version", blueprint §3 and listing §3 pin an
item's two halves to each other, and the published reference form
carries its own componentVersion.

Answers the three questions #15 asks.

Monotonicity: each publication MUST carry a version strictly greater
than the highest already published for that component. Gaps are
permitted. The phase is capability, because deciding it needs the
catalog and §7 forbids the earlier phases from reaching the network —
so offline validation is exactly as strict as it was and this is a
minor release rather than a narrowing one.

Reuse: a version is used once. componentVersion: 3 is the whole of what
a published node deploys, and a registry that let 3 mean two documents
would make the pin name nothing. Whether an identical re-submission is
a no-op rather than a publication stays outside this contract, which
orders publications without defining when two YAML files are the same
document.

Relationship to the item: none. The two numbers count different things,
and in the published form one component is deployed by many items at
once. A component release SHOULD be accompanied by an item release,
without a diagnostic — the disagreement is visible only across two
revisions and a validator is handed one.

ERR_VERSION_NOT_MONOTONIC is the family's first capability code, so §8's
closing paragraph no longer says the semantic codes alone are its own.
It can have no fixture for the same reason ERR_UNKNOWN_COMPONENT cannot,
and is recorded in the runner's UNCOVERED list with that reason.

Section 4 also states what metadata carries — version and nothing else,
no slug — which nothing said before.

Refs #15

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Signed-off-by: Justin Merrell <merrelljustin@gmail.com>

* feat(component): define endpoints, and address the public URL per endpoint

Section 5.2 was a heading and a TODO, while the endpoint block was
already constrained from the outside: §5 forbids endpoints on a WORKER,
JOB and CRON, and §5.4 makes readiness REQUIRED for a SERVICE exposing
a PUBLIC endpoint. Answers the three questions #16 asks, and the two
things §5.2 turned out to owe that #16 does not name.

Port range. containerPort is an integer from 1 to 65535, structural.
A port below 1024 is a SHOULD NOT and not a rejection: whether the
container can bind one depends on a capability the runtime grants,
which this document cannot see, and a rule that rejects on a fact it
cannot check is guessing. structural-026 is what keeps that a SHOULD
NOT rather than drifting into a MUST.

Protocol x visibility. A PUBLIC endpoint is published at a URL by
something that speaks the HTTP family, so its protocol MUST be HTTP,
HTTPS, WS or GRPC and a TCP or UDP endpoint MUST be PRIVATE. §5.4 is
the second argument: a probe polls an HTTP path, so a PUBLIC TCP
endpoint would compel a readiness probe it has no way to express.

Multiple PUBLIC endpoints are permitted, and each publishes its own
URL. The consequence is a rule rather than a caveat — anything naming
a public address MUST name the endpoint it means — so platformDefault
becomes an object carrying `source` and `endpoint` rather than a bare
enum. That field had no prose at all before; §6.1 now has it. Note
this is not what #16 assumed: capping PUBLIC at one is not expressible
structurally, since JSON Schema has no keyword that counts mapping
members matching a condition.

Two things §5.2 owed and nothing had paid. "The primary endpoint" was
used by §5.4 and by ComponentProbe.endpoint and defined nowhere; it is
now the sole endpoint, failing that the sole PUBLIC one, failing that
nothing — an error rather than a sort-order tiebreak, because a
tiebreak lets a new endpoint named `api` silently re-point a probe that
already works. And endpoint names were bare mapping keys, so `web.api`
was legal despite being referenced by probes and platform defaults and
becoming a DNS label; they now take the slug grammar blueprint §4.1
quotes.

Three semantic codes, all fixture-covered: ERR_AMBIGUOUS_ENDPOINT,
ERR_ENDPOINT_NOT_PUBLIC, and ERR_UNKNOWN_ENDPOINT broadened past
probes. checkProbeEndpoints becomes checkEndpointReferences, which
walks probes and platform defaults through one resolver.

BREAKING CHANGE: bounding containerPort, restricting a PUBLIC
endpoint's protocol, constraining endpoint names, and reshaping
platformDefault each reject documents that validate today. No v1.0.0
has been published — every family reads 0.0.0 in the release-please
manifest and no tag exists — so §3's guarantee has no released version
to run from and this lands free. It does not once #1/#2/#3 merge.

Refs #16

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Signed-off-by: Justin Merrell <merrelljustin@gmail.com>

---------

Signed-off-by: Justin Merrell <merrelljustin@gmail.com>
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
@github-actions
github-actions Bot force-pushed the release-please--branches--main--components--component branch from 9483e3f to ff9e02e Compare August 9, 2026 10:10
@github-actions
github-actions Bot force-pushed the release-please--branches--main--components--component branch from ff9e02e to d339443 Compare August 11, 2026 11:07
@github-actions
github-actions Bot force-pushed the release-please--branches--main--components--component branch from d339443 to 35956f5 Compare August 17, 2026 00:28
@github-actions
github-actions Bot force-pushed the release-please--branches--main--components--component branch from 35956f5 to d9c5f85 Compare August 17, 2026 03:15
@github-actions
github-actions Bot force-pushed the release-please--branches--main--components--component branch from d9c5f85 to 6c688b5 Compare August 17, 2026 16:38
@github-actions
github-actions Bot force-pushed the release-please--branches--main--components--component branch from 6c688b5 to 965f575 Compare August 18, 2026 00:04
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

0 participants