package gates import ( "os" "path/filepath" "regexp" "testing" "textmachine/platform/internal/httpapi" ) // canonPath is the ratified API contract, from this package's directory. It is outside the zone on // purpose: the contract belongs to `docs/` and this zone only serves it. const canonPath = zoneRoot + "/../docs/architecture/14-api-contract/openapi.yaml" // The constant a deployment announces itself with must be the version the ratified canon carries. // // Every other test of this constant compares the WIRE to the constant, which is self-consistent and // passes at any value — the class PD-1 names. This is the only check with an independent second // source, and it is the reason the constant went two ratifications without moving: `0.3.0` was // served while `0.4.0` was the canon, so a client generated against what the deployment ANNOUNCES // would have refused the shapes it actually returns (while the major is `0`, a differing minor // carries breaking changes by design — canon §Versioning). // // It reads the canon rather than a copy of the number: a gate that holds a second copy of the fact // is one more place to forget. func TestTheAnnouncedContractVersionIsTheOneTheCanonRatified(t *testing.T) { src, err := os.ReadFile(filepath.Join(canonPath)) if err != nil { // Not skipped. A missing canon leaves this constant with no check at all except a human // noticing, which is exactly what failed twice. t.Fatalf("the ratified canon could not be read, so the served contract version has nothing to be checked against: %v", err) } // `info.version` and not any other `version:` in the document: the file carries several. m := regexp.MustCompile(`(?m)^info:\n(?:[ \t]+.*\n)*?[ \t]+version: (\S+)`).FindSubmatch(src) if m == nil { t.Fatal("the canon carries no info.version: this gate reads the wrong document or the wrong shape") } if got, want := httpapi.ContractVersion, string(m[1]); got != want { t.Errorf("this build announces contract %s and the ratified canon is %s; the constant is raised in the same change as the code that implements a minor, never afterwards", got, want) } }