Skip to content

ci(accounts): the declared host-interface versions are held to the pinned conformance suite - #1292

Merged
antoinetoussaint-byte merged 2 commits into
mainfrom
issue-1291-accounts-run-the-host-interface-conformance-harness-as
Nov 3, 2026
Merged

antoinetoussaint-byte merged 2 commits into
mainfrom
issue-1291-accounts-run-the-host-interface-conformance-harness-as

Conversation

@antoinetoussaint-byte

@antoinetoussaint-byte antoinetoussaint-byte commented Nov 3, 2026 •

Copy link
Copy Markdown
Contributor

Closes #1291.

What main already had, verified before changing anything

The issue was written against a tree older than main. Two of its three premises had landed before it was filed:

  • The harness already gates CI. host-interface-conformance (.github/workflows/ci.yml, job name "Host interface conformance (authority main)") is a required context and a release-gates dependency since feat(accounts): the host interfaces are decided by the shared authority core #1257 (27 Oct). It runs scripts/ci/host-interface-conformance-main.sh, which boots the Postgres test store through the Codefly SDK and runs go test -run '^TestAccountsPassesTheHostInterfaceConformanceSuite$' ./pkg/adapters, with no continue-on-error. The last two runs on main (c54a1c8, 2c2aa81) are green.
  • Admission keys are already served. feat(accounts): the hop registers its admission key; Keys publishes it (authority 0.3.3) #1256 (26 Oct) added RegisterAdmissionKey, Keys.admission_keys with purpose hop-admission, the per-instance pin and the two-minute lease, over Postgres rows (hop_admission_keys, migrations 55 and 58), and the harness fixture already carries HopCredential (host_interface_conformance_test.go:362). HOST_INTERFACE.md already states the pin is durable in Postgres and shared across replicas, which is the point the issue asked to be stated.
  • The pin was already at authority main. go.mod pinned conformance, authority-core and authority-client at dea37afac9ad, which is codefly-dev/authority main today (0 commits between). delivery and resources sat two days behind at f82a98e093ef, with an empty diff between the two revisions for those directories.

What was missing is the second done-means item: nothing held "declares codefly.dev/authority@0.3.5" to "passes the suite of a revision that publishes 0.3.5". This PR adds that gate, and fixes what running the harness surfaced.

The declaration gate

module-package verify-host-interfaces (module/tools/modulepackage/host_interfaces.go, unit tests beside it) reads, per service that declares implements: in module/module.codefly.yaml:

  • the authority revision its go.mod pins, from the pseudo-versions of every direct github.com/codefly-dev/authority/libraries/*/go requirement: they must be pseudo-versions and must all abbreviate one commit, because the suite, the core it decides with and the client are run together;
  • interfaces/<name>/interface.codefly.yaml at that commit, from a directory the caller provides;
  • the opening section of the service's HOST_INTERFACE.md.

It fails on: a declared version above the published one (a claim no suite proved); a declared version in another major.minor than the published one (a 0.4.0 declaration under a pin publishing 0.5.0 ran no 0.4.0 suite); an interface the pin does not publish; libraries pinned at two revisions, or replaced or excluded in go.mod (the shape authority's own services use to point at local directories, which would make the require line name nothing that runs); a version that is not semver; a document naming another version than the manifest, or none. A declared patch below the published one, within the same major.minor, is a notice, never a failure: the pin may move to run a newer patch's suite before the declaration follows, and the declaration never moves first. Gate output over the real tree at dea37afac9ad:

accounts: host interfaces declared by ../services/accounts/code/go.mod, held to authority dea37afac9ad (authority-client, authority-core, conformance, delivery, resources)
  codefly.dev/artifact         declared 0.1.0    published 0.1.0    ok
  codefly.dev/authority        declared 0.3.5    published 0.3.5    ok
  codefly.dev/composition      declared 0.2.0    published 0.2.0    ok
  codefly.dev/installation     declared 0.4.0    published 0.4.0    ok
  codefly.dev/session          declared 0.2.1    published 0.2.1    ok

Where it runs. In host-interface-conformance, before the suite and before any re-pin: the script already clones authority main (blobless, bare). It resolves the pin's full commit id in that clone (git rev-parse --verify --quiet <pin>^{commit}); only a pin main does not contain falls back to the module cache's origin record (go mod download -json … | Origin.Hash, no network once cached) and is fetched by that id (git fetch --filter=blob:none origin <sha>, which GitHub serves for any reachable commit), and the job is red only when both fail. It then extracts interfaces/ with git archive and runs the gate with --revision <sha> so the tree it read is held to the go.mod pin. The network-free half (one revision in go.mod, the document agreeing with the manifest) also runs as a module/tools test in the module-package job.

Why not offline through Go. The brief preferred an offline check. The authority repo root is nominally a Go module whose zip would carry interfaces/, but proxy.golang.org does not serve it: @v/<pseudo>.info, @latest and older pseudo-versions all answer 404, @v/list is empty, and sum.golang.org has no entry, so a direct fetch fails "verifying go.mod" too (the nested libraries/*/go modules are served). Pinning by tag is not available either: authority carries two tags, neither on the conformance library or the interfaces. Reading the manifests from git at the pinned commit, inside the one job that already has authority network access, is therefore the real check rather than a copy of it. An offline alternative that belongs to authority is noted under follow-ons.

Other changes

  • module/module.codefly.yaml: codefly.dev/session@0.2.0 → 0.2.1. accounts already fills FixturePerson.organization_display_name (the 0.2.1 addition, authority Preserve consumer module agent declarations (#44) #45) and passes the session cases of the 0.2.1 suite at the pin; without the bump the new gate reports an under-declaration on day one. 0.2.1 is additive and consumers require ranges (>=0.2.0 <0.3.0), so no consumer is refused.
  • go.mod: delivery and resources move from f82a98e093ef to dea37afac9ad, the revision the other three already pin. The diff between the two revisions under those directories is empty; the move makes the pin one commit, which the gate now requires and the CI script's re-pin already assumed.
  • pkg/business/audit_registry.go: the first harness run logged audit payload failed registry validation event_type=saas.platform.hop_admission_key_published … no registered field "instance". The durable emitter writes the row and silently drops the whole payload in that case. The field is now declared (required: a credential naming no pod is refused before anything is published), and TestTheHopsRegisteredKeyIsPublishedApartFromTheWorkContextKeys runs business.ValidatePayload over the recorded entry so the declaration cannot drift again. The second harness run logs no validation warning.
  • HOST_INTERFACE.md: the opening sentence named installation@0.3.0 and session@0.2.0 while the manifest declared 0.4.0 and (now) 0.2.1, and omitted artifact; it now names the five declared versions and is held to the manifest by the gate. Proof gains the gate and the recorded tally below.
  • RELEASE_GATES.md, AGENTS.md, the job comment in ci.yml: the gate is documented where the job is; the job's setup-go cache now also keys on module/tools/go.sum.
  • module/tools/go.mod: golang.org/x/mod becomes a direct dependency (it was already in the graph); core's resources.LoadModuleFromDir reads the declarations, so the gate parses implements exactly as the CLI does.

Conformance tally

Authority dea37afac9ad (its main on 2026-10-30), from module/services/accounts/code:

GOWORK=off go test -count=1 -timeout 30m -run '^TestAccountsPassesTheHostInterfaceConformanceSuite$' -v ./pkg/adapters
run 1 (pins as on main) run 2 (this PR's pins and audit declaration)
top-level test PASS, 69 s PASS, 74 s
cases one level under the test 94 passed 94 passed
subtests at every depth 294 passed 294 passed
failed / skipped 0 / 0 0 / 0
audit payload validation warnings 1 (instance) 0

The admission-key case ("only the hop registers an admission key, published apart from the Work Context keys") is among the passes. No new red line, so the gap list (HOST_INTERFACE.md "Not yet") gains nothing.

Classification

Every change is a fix at the owner: the gate lives in module/tools beside the package contract and runs in the job that owns authority access; the audit field is declared in the event catalog that owns payload schemas; the declaration bump and the pin move are manifest facts backed by the suite. No hack, no stopgap, no continue-on-error, no loosened case.

Reused: the existing job, script and blobless clone; core's module loader; Masterminds/semver and golang.org/x/mod already in module/tools' graph; the cmd/module-package subcommand shape. Deliberately not built: a second clone, a GitHub API call, a download of the authority root module, a hand-written reader of module.codefly.yaml.

Verified, and not

  • Verified locally: the harness twice (tally above); scripts/ci/host-interface-conformance-main.sh end to end (clone, fetch by id, gate, suite) (exit 0: main identical to the pin, the gate green for the five interfaces, the suite green in 74 s, and no working-tree churn from the re-pin); go test ./... in module/tools; node --test scripts/ci/release-gates.test.mjs scripts/ci/ci-performance.test.mjs (125 pass); the admission-key unit tests; node module/tools/naming-gate.mjs check.
  • Not verified here: the job on a GitHub-hosted runner (this PR's own CI run is that verification); module-verify.mjs and the Codefly quality phase, which CI runs.

Follow-ons, not filed

🤖 Generated with Claude Code

…nned conformance suite

module.codefly.yaml declares what accounts implements and go.mod pins the
codefly-dev/authority revision whose shared suite accounts' tests run; nothing
held the two together. `module-package verify-host-interfaces` now reads
interfaces/<name>/interface.codefly.yaml at the pinned commit (fetched by its
full id in the conformance job, which already clones authority) and refuses a
declared version above the published one, an interface the pin does not
publish, authority libraries pinned at two revisions, or a HOST_INTERFACE.md
naming another version. A declared version below the published one is a
notice, so the pin can move before the declaration and never the reverse.

Running the harness at the pin surfaced an undeclared `instance` key on the
hop_admission_key_published audit payload, which the durable emitter drops with
a warning; it is declared and held by the admission unit test. session is
declared at 0.2.1, the version whose suite accounts passes; delivery and
resources move to the revision the other authority libraries pin (empty diff).

Tally at authority dea37afac9ad: 94 cases, 294 subtests, 0 failed, 0 skipped.

Closes #1291.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…ite is red, and a replaced authority library is refused

Review findings on #1292: a declared version below the published one was a
notice whatever its minor, yet a 0.4.0 declaration under a pin publishing 0.5.0
ran no 0.4.0 suite; only a patch below within the same major.minor is now a
notice, every other mismatch fails. ReadAuthorityPin read the require lines
alone, so a replace or exclude of an authority library (the shape authority's
own services use to point at local directories) left the pin naming nothing
that runs; both are refused, read with the strict modfile.Parse, since ParseLax
drops those directives. The conformance script resolves the pinned commit in
the clone it already has and falls back to the module cache's origin record,
and the fetch by full id, only for a pin main does not contain.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@antoinetoussaint-byte
antoinetoussaint-byte added this pull request to the merge queue Nov 3, 2026
Merged via the queue into main with commit 1655e83 Nov 3, 2026
25 of 26 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.

accounts: run the host-interface conformance harness as a CI gate at the declared interface version, and serve admission keys

1 participant