diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml index 550bd37..60ad5d1 100644 --- a/.github/workflows/docs.yml +++ b/.github/workflows/docs.yml @@ -31,6 +31,7 @@ jobs: - run: python3 scripts/export_compatibility.py --check - run: python3 scripts/export_profile.py --check - run: python3 scripts/check_links.py + - run: python3 scripts/check_ecosystem_discovery.py - run: bash scripts/check_start.sh lint-workflows: diff --git a/.github/workflows/ecosystem-drift.yml b/.github/workflows/ecosystem-drift.yml new file mode 100644 index 0000000..748555f --- /dev/null +++ b/.github/workflows/ecosystem-drift.yml @@ -0,0 +1,27 @@ +name: Ecosystem drift + +on: + schedule: + - cron: "17 3 * * *" + workflow_dispatch: + +permissions: + contents: read + +concurrency: + group: ecosystem-public-discovery + cancel-in-progress: false + +jobs: + public-discovery: + runs-on: ubuntu-latest + timeout-minutes: 10 + steps: + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + persist-credentials: false + - uses: astral-sh/setup-uv@c771a70e6277c0a99b617c7a806ffedaca235ff9 # v9.0.0 + with: + python-version: "3.13" + enable-cache: false + - run: python3 scripts/check_ecosystem_discovery.py diff --git a/compatibility.json b/compatibility.json index 1c410e5..f1b68d3 100644 --- a/compatibility.json +++ b/compatibility.json @@ -1,7 +1,7 @@ { "as_of": "2026-07-30", "golden_runtime": { - "lock_sha256": "82fa8313483ca0412ba389e5ca610f47ea943a153c8ca5210cb881981d9a129e", + "lock_sha256": "4502453286edffcee72b1025f7e2f1c81c596cd4bf6734b9c8c52cd4622b6b61", "node": "24", "platform_packages": [ { @@ -41,7 +41,7 @@ "golden": true, "name": "hayate", "role": "Core framework and native ASGI, Workers, and Lambda adapters", - "version": "0.15.2" + "version": "0.15.3" }, { "evidence": [ @@ -52,16 +52,18 @@ "golden": false, "name": "hayate-auth", "role": "Sessions, API keys, OAuth clients, and authorization server", - "version": "0.10.4" + "version": "0.10.5" }, { "evidence": [ + "fetch_ci", + "fetch_release", "ecosystem_full" ], "golden": false, "name": "hayate-fetch", "role": "Portable WHATWG-style outbound fetch", - "version": "0.1.3" + "version": "0.1.4" }, { "evidence": [ @@ -85,17 +87,19 @@ "golden": true, "name": "hayate-openapi", "role": "OpenAPI 3.1, Scalar, and generated zero-runtime TypeScript clients", - "version": "0.8.1" + "version": "0.8.2" }, { "evidence": [ "golden_app", + "sql_ci", + "sql_release", "foliomcp_ci" ], "golden": true, "name": "hayate-sql", "role": "Migration-checked SQL contracts and typed query facades", - "version": "0.1.1" + "version": "0.1.2" }, { "evidence": [ @@ -161,44 +165,54 @@ "schema_version": 1, "sources": { "auth_ci": { - "commit": "938751d0f225def770d6ae47e1da3da40829c8d1", - "label": "hayate-auth 0.10.4 main CI", - "url": "https://github.com/hayatepy/hayate-auth/actions/runs/30498321148" + "commit": "4189e735844a06377e9aa7eea2a731d09e500449", + "label": "hayate-auth 0.10.5 main CI", + "url": "https://github.com/hayatepy/hayate-auth/actions/runs/30506737850" }, "auth_release": { - "commit": "938751d0f225def770d6ae47e1da3da40829c8d1", - "label": "hayate-auth 0.10.4 release provenance", - "url": "https://github.com/hayatepy/hayate-auth/actions/runs/30498396435" + "commit": "4189e735844a06377e9aa7eea2a731d09e500449", + "label": "hayate-auth 0.10.5 release provenance", + "url": "https://github.com/hayatepy/hayate-auth/actions/runs/30506830212" }, "auth_security": { - "commit": "938751d0f225def770d6ae47e1da3da40829c8d1", - "label": "hayate-auth 0.10.4 security profiles", - "url": "https://github.com/hayatepy/hayate-auth/actions/runs/30498321150" + "commit": "4189e735844a06377e9aa7eea2a731d09e500449", + "label": "hayate-auth 0.10.5 security profiles", + "url": "https://github.com/hayatepy/hayate-auth/actions/runs/30506737869" }, "core_ci": { - "commit": "8cb27385cbc2655e531c37bdcdb45b1309c3a392", - "label": "Hayate 0.15.2 main CI", - "url": "https://github.com/hayatepy/hayate/actions/runs/30501131371" + "commit": "a1821a27a83a2406c491338a397b489856db15de", + "label": "Hayate 0.15.3 main CI", + "url": "https://github.com/hayatepy/hayate/actions/runs/30506644119" }, "core_release": { - "commit": "8cb27385cbc2655e531c37bdcdb45b1309c3a392", - "label": "Hayate 0.15.2 release provenance", - "url": "https://github.com/hayatepy/hayate/actions/runs/30501262533" + "commit": "a1821a27a83a2406c491338a397b489856db15de", + "label": "Hayate 0.15.3 release provenance", + "url": "https://github.com/hayatepy/hayate/actions/runs/30506830778" }, "ecosystem_full": { "commit": "64dfb96f2397685c9fe017382855749f445d3697", - "label": "Hayate 0.15.2 downstream full compatibility CI", + "label": "Hayate 0.15.2 downstream full compatibility CI (runtime-equivalent to metadata-only 0.15.3)", "url": "https://github.com/hayatepy/hayate/actions/runs/30501023744" }, + "fetch_ci": { + "commit": "c684291e0fcc1067d9cf4548370c50fb68678a67", + "label": "hayate-fetch 0.1.4 main CI", + "url": "https://github.com/hayatepy/hayate-fetch/actions/runs/30506644434" + }, + "fetch_release": { + "commit": "c684291e0fcc1067d9cf4548370c50fb68678a67", + "label": "hayate-fetch 0.1.4 release provenance", + "url": "https://github.com/hayatepy/hayate-fetch/actions/runs/30506781911" + }, "foliomcp_ci": { "commit": "a4d110efc223b5774278b21512e176f64f93d525", "label": "FolioMCP production Workerd CI (private downstream evidence)", "visibility": "private" }, "golden_app": { - "commit": "87e8e907c769ffc5ff24926470eb1ec7641f63b5", + "commit": "381c071f108e29b16eae6b19b7f870a4fc3f18a9", "label": "golden-app release lock main CI", - "url": "https://github.com/hayatepy/golden-app/actions/runs/30504943669" + "url": "https://github.com/hayatepy/golden-app/actions/runs/30507749113" }, "mcp_ci": { "commit": "249b2df4bc41a0603e168b22c53815e31d2d5711", @@ -211,19 +225,19 @@ "url": "https://github.com/hayatepy/hayate-mcp/actions/runs/30504320516" }, "openapi_ci": { - "commit": "2ed34215ec3dd5ebd0a0780f7b7903f0b3492a78", - "label": "hayate-openapi 0.8.1 main CI and TypeScript interoperability", - "url": "https://github.com/hayatepy/hayate-openapi/actions/runs/30487122341" + "commit": "1247f16e13faf1cd8b9f507c4715e44bb1ec03be", + "label": "hayate-openapi 0.8.2 main CI and TypeScript interoperability", + "url": "https://github.com/hayatepy/hayate-openapi/actions/runs/30506643960" }, "openapi_release": { - "commit": "2ed34215ec3dd5ebd0a0780f7b7903f0b3492a78", - "label": "hayate-openapi 0.8.1 release provenance", - "url": "https://github.com/hayatepy/hayate-openapi/actions/runs/30487193584" + "commit": "1247f16e13faf1cd8b9f507c4715e44bb1ec03be", + "label": "hayate-openapi 0.8.2 release provenance", + "url": "https://github.com/hayatepy/hayate-openapi/actions/runs/30506784156" }, "scaffold_ci": { - "commit": "8bcca24bbd43854c05a6467d26b675c20a89b63e", + "commit": "884b2b82dd9c64026d00deecd6afac3200a9baa5", "label": "create-hayate 0.13.2 main CI and feature matrix", - "url": "https://github.com/hayatepy/create-hayate/actions/runs/30502494267" + "url": "https://github.com/hayatepy/create-hayate/actions/runs/30506646209" }, "scaffold_matrix": { "artifact_sha256": "f207dcd979c695508c4bf672432848e5469ebf4ab1b58b0f2c4fecb8e004af05", @@ -235,6 +249,16 @@ "commit": "8bcca24bbd43854c05a6467d26b675c20a89b63e", "label": "create-hayate 0.13.2 release provenance", "url": "https://github.com/hayatepy/create-hayate/actions/runs/30502570222" + }, + "sql_ci": { + "commit": "4e84db1ab3a7683239f288fb1bae64afa3007303", + "label": "hayate-sql 0.1.2 main CI", + "url": "https://github.com/hayatepy/hayate-sql/actions/runs/30506643955" + }, + "sql_release": { + "commit": "4e84db1ab3a7683239f288fb1bae64afa3007303", + "label": "hayate-sql 0.1.2 release provenance", + "url": "https://github.com/hayatepy/hayate-sql/actions/runs/30506782424" } } } diff --git a/data/ecosystem.toml b/data/ecosystem.toml index 435dbd9..d92eba3 100644 --- a/data/ecosystem.toml +++ b/data/ecosystem.toml @@ -14,23 +14,33 @@ capabilities_path = "benchmarks/competitive/capabilities.json" [sources.golden_app] label = "golden-app release lock main CI" -url = "https://github.com/hayatepy/golden-app/actions/runs/30504943669" -commit = "87e8e907c769ffc5ff24926470eb1ec7641f63b5" +url = "https://github.com/hayatepy/golden-app/actions/runs/30507749113" +commit = "381c071f108e29b16eae6b19b7f870a4fc3f18a9" [sources.auth_ci] -label = "hayate-auth 0.10.4 main CI" -url = "https://github.com/hayatepy/hayate-auth/actions/runs/30498321148" -commit = "938751d0f225def770d6ae47e1da3da40829c8d1" +label = "hayate-auth 0.10.5 main CI" +url = "https://github.com/hayatepy/hayate-auth/actions/runs/30506737850" +commit = "4189e735844a06377e9aa7eea2a731d09e500449" [sources.auth_security] -label = "hayate-auth 0.10.4 security profiles" -url = "https://github.com/hayatepy/hayate-auth/actions/runs/30498321150" -commit = "938751d0f225def770d6ae47e1da3da40829c8d1" +label = "hayate-auth 0.10.5 security profiles" +url = "https://github.com/hayatepy/hayate-auth/actions/runs/30506737869" +commit = "4189e735844a06377e9aa7eea2a731d09e500449" [sources.auth_release] -label = "hayate-auth 0.10.4 release provenance" -url = "https://github.com/hayatepy/hayate-auth/actions/runs/30498396435" -commit = "938751d0f225def770d6ae47e1da3da40829c8d1" +label = "hayate-auth 0.10.5 release provenance" +url = "https://github.com/hayatepy/hayate-auth/actions/runs/30506830212" +commit = "4189e735844a06377e9aa7eea2a731d09e500449" + +[sources.fetch_ci] +label = "hayate-fetch 0.1.4 main CI" +url = "https://github.com/hayatepy/hayate-fetch/actions/runs/30506644434" +commit = "c684291e0fcc1067d9cf4548370c50fb68678a67" + +[sources.fetch_release] +label = "hayate-fetch 0.1.4 release provenance" +url = "https://github.com/hayatepy/hayate-fetch/actions/runs/30506781911" +commit = "c684291e0fcc1067d9cf4548370c50fb68678a67" [sources.mcp_ci] label = "hayate-mcp 0.12.1 main CI and MCP 2026-07-28 conformance" @@ -43,14 +53,24 @@ url = "https://github.com/hayatepy/hayate-mcp/actions/runs/30504320516" commit = "249b2df4bc41a0603e168b22c53815e31d2d5711" [sources.openapi_ci] -label = "hayate-openapi 0.8.1 main CI and TypeScript interoperability" -url = "https://github.com/hayatepy/hayate-openapi/actions/runs/30487122341" -commit = "2ed34215ec3dd5ebd0a0780f7b7903f0b3492a78" +label = "hayate-openapi 0.8.2 main CI and TypeScript interoperability" +url = "https://github.com/hayatepy/hayate-openapi/actions/runs/30506643960" +commit = "1247f16e13faf1cd8b9f507c4715e44bb1ec03be" [sources.openapi_release] -label = "hayate-openapi 0.8.1 release provenance" -url = "https://github.com/hayatepy/hayate-openapi/actions/runs/30487193584" -commit = "2ed34215ec3dd5ebd0a0780f7b7903f0b3492a78" +label = "hayate-openapi 0.8.2 release provenance" +url = "https://github.com/hayatepy/hayate-openapi/actions/runs/30506784156" +commit = "1247f16e13faf1cd8b9f507c4715e44bb1ec03be" + +[sources.sql_ci] +label = "hayate-sql 0.1.2 main CI" +url = "https://github.com/hayatepy/hayate-sql/actions/runs/30506643955" +commit = "4e84db1ab3a7683239f288fb1bae64afa3007303" + +[sources.sql_release] +label = "hayate-sql 0.1.2 release provenance" +url = "https://github.com/hayatepy/hayate-sql/actions/runs/30506782424" +commit = "4e84db1ab3a7683239f288fb1bae64afa3007303" [sources.foliomcp_ci] label = "FolioMCP production Workerd CI (private downstream evidence)" @@ -58,24 +78,24 @@ commit = "a4d110efc223b5774278b21512e176f64f93d525" visibility = "private" [sources.ecosystem_full] -label = "Hayate 0.15.2 downstream full compatibility CI" +label = "Hayate 0.15.2 downstream full compatibility CI (runtime-equivalent to metadata-only 0.15.3)" url = "https://github.com/hayatepy/hayate/actions/runs/30501023744" commit = "64dfb96f2397685c9fe017382855749f445d3697" [sources.core_ci] -label = "Hayate 0.15.2 main CI" -url = "https://github.com/hayatepy/hayate/actions/runs/30501131371" -commit = "8cb27385cbc2655e531c37bdcdb45b1309c3a392" +label = "Hayate 0.15.3 main CI" +url = "https://github.com/hayatepy/hayate/actions/runs/30506644119" +commit = "a1821a27a83a2406c491338a397b489856db15de" [sources.core_release] -label = "Hayate 0.15.2 release provenance" -url = "https://github.com/hayatepy/hayate/actions/runs/30501262533" -commit = "8cb27385cbc2655e531c37bdcdb45b1309c3a392" +label = "Hayate 0.15.3 release provenance" +url = "https://github.com/hayatepy/hayate/actions/runs/30506830778" +commit = "a1821a27a83a2406c491338a397b489856db15de" [sources.scaffold_ci] label = "create-hayate 0.13.2 main CI and feature matrix" -url = "https://github.com/hayatepy/create-hayate/actions/runs/30502494267" -commit = "8bcca24bbd43854c05a6467d26b675c20a89b63e" +url = "https://github.com/hayatepy/create-hayate/actions/runs/30506646209" +commit = "884b2b82dd9c64026d00deecd6afac3200a9baa5" [sources.scaffold_matrix] label = "create-hayate 0.13.2 frontend smoke matrix (10/10)" @@ -90,24 +110,24 @@ commit = "8bcca24bbd43854c05a6467d26b675c20a89b63e" [[packages]] name = "hayate" -version = "0.15.2" +version = "0.15.3" role = "Core framework and native ASGI, Workers, and Lambda adapters" golden = true evidence = ["golden_app", "ecosystem_full", "core_ci", "core_release"] [[packages]] name = "hayate-auth" -version = "0.10.4" +version = "0.10.5" role = "Sessions, API keys, OAuth clients, and authorization server" golden = false evidence = ["auth_ci", "auth_security", "auth_release"] [[packages]] name = "hayate-fetch" -version = "0.1.3" +version = "0.1.4" role = "Portable WHATWG-style outbound fetch" golden = false -evidence = ["ecosystem_full"] +evidence = ["fetch_ci", "fetch_release", "ecosystem_full"] [[packages]] name = "hayate-mcp" @@ -118,17 +138,17 @@ evidence = ["golden_app", "mcp_ci", "mcp_release", "foliomcp_ci"] [[packages]] name = "hayate-openapi" -version = "0.8.1" +version = "0.8.2" role = "OpenAPI 3.1, Scalar, and generated zero-runtime TypeScript clients" golden = true evidence = ["golden_app", "openapi_ci", "openapi_release", "foliomcp_ci"] [[packages]] name = "hayate-sql" -version = "0.1.1" +version = "0.1.2" role = "Migration-checked SQL contracts and typed query facades" golden = true -evidence = ["golden_app", "foliomcp_ci"] +evidence = ["golden_app", "sql_ci", "sql_release", "foliomcp_ci"] [[packages]] name = "create-hayate" diff --git a/data/public-discovery.toml b/data/public-discovery.toml new file mode 100644 index 0000000..5bf1112 --- /dev/null +++ b/data/public-discovery.toml @@ -0,0 +1,45 @@ +schema_version = 1 +minimum_scaffold_version = "0.13.2" +canonical_home = "https://hayatepy.dev/" +canonical_compatibility = "https://hayatepy.dev/evidence/compatibility/" +superseded_prefixes = [ + "https://hayatepy.github.io/", + "https://github.com/hayatepy/.github/blob/main/docs/START.md", + "https://github.com/hayatepy/.github/blob/main/docs/COMPATIBILITY.md", +] + +[[repositories]] +name = "hayate" +homepage = "https://hayatepy.dev/" + +[[repositories]] +name = "create-hayate" +homepage = "https://hayatepy.dev/get-started/first-app/" + +[[repositories]] +name = "hayate-admin" +homepage = "https://hayatepy.dev/ecosystem/#hayate-admin" + +[[repositories]] +name = "hayate-auth" +homepage = "https://hayatepy.dev/ecosystem/#hayate-auth" + +[[repositories]] +name = "hayate-fetch" +homepage = "https://hayatepy.dev/ecosystem/#hayate-fetch" + +[[repositories]] +name = "hayate-htmx" +homepage = "https://hayatepy.dev/ecosystem/#hayate-htmx" + +[[repositories]] +name = "hayate-mcp" +homepage = "https://hayatepy.dev/ecosystem/#hayate-mcp" + +[[repositories]] +name = "hayate-openapi" +homepage = "https://hayatepy.dev/ecosystem/#hayate-openapi" + +[[repositories]] +name = "hayate-sql" +homepage = "https://hayatepy.dev/ecosystem/#hayate-sql" diff --git a/docs/COMPATIBILITY.md b/docs/COMPATIBILITY.md index 8476928..726b25a 100644 --- a/docs/COMPATIBILITY.md +++ b/docs/COMPATIBILITY.md @@ -8,23 +8,23 @@ passing CI evidence. Do not edit it manually. The evidence snapshot is dated | Package | Version | Role | Production golden app | Evidence | |---|---:|---|---|---| -| [`hayate`](https://github.com/hayatepy/hayate) | `0.15.2` | Core framework and native ASGI, Workers, and Lambda adapters | yes | [golden-app release lock main CI](https://github.com/hayatepy/golden-app/actions/runs/30504943669), [Hayate 0.15.2 downstream full compatibility CI](https://github.com/hayatepy/hayate/actions/runs/30501023744), [Hayate 0.15.2 main CI](https://github.com/hayatepy/hayate/actions/runs/30501131371), [Hayate 0.15.2 release provenance](https://github.com/hayatepy/hayate/actions/runs/30501262533) | -| [`hayate-auth`](https://github.com/hayatepy/hayate-auth) | `0.10.4` | Sessions, API keys, OAuth clients, and authorization server | downstream gate | [hayate-auth 0.10.4 main CI](https://github.com/hayatepy/hayate-auth/actions/runs/30498321148), [hayate-auth 0.10.4 security profiles](https://github.com/hayatepy/hayate-auth/actions/runs/30498321150), [hayate-auth 0.10.4 release provenance](https://github.com/hayatepy/hayate-auth/actions/runs/30498396435) | -| [`hayate-fetch`](https://github.com/hayatepy/hayate-fetch) | `0.1.3` | Portable WHATWG-style outbound fetch | downstream gate | [Hayate 0.15.2 downstream full compatibility CI](https://github.com/hayatepy/hayate/actions/runs/30501023744) | -| [`hayate-mcp`](https://github.com/hayatepy/hayate-mcp) | `0.12.1` | MCP transport, tools, context, and OAuth resource server | yes | [golden-app release lock main CI](https://github.com/hayatepy/golden-app/actions/runs/30504943669), [hayate-mcp 0.12.1 main CI and MCP 2026-07-28 conformance](https://github.com/hayatepy/hayate-mcp/actions/runs/30504249052), [hayate-mcp 0.12.1 release provenance](https://github.com/hayatepy/hayate-mcp/actions/runs/30504320516), FolioMCP production Workerd CI (private downstream evidence) at `a4d110efc223` | -| [`hayate-openapi`](https://github.com/hayatepy/hayate-openapi) | `0.8.1` | OpenAPI 3.1, Scalar, and generated zero-runtime TypeScript clients | yes | [golden-app release lock main CI](https://github.com/hayatepy/golden-app/actions/runs/30504943669), [hayate-openapi 0.8.1 main CI and TypeScript interoperability](https://github.com/hayatepy/hayate-openapi/actions/runs/30487122341), [hayate-openapi 0.8.1 release provenance](https://github.com/hayatepy/hayate-openapi/actions/runs/30487193584), FolioMCP production Workerd CI (private downstream evidence) at `a4d110efc223` | -| [`hayate-sql`](https://github.com/hayatepy/hayate-sql) | `0.1.1` | Migration-checked SQL contracts and typed query facades | yes | [golden-app release lock main CI](https://github.com/hayatepy/golden-app/actions/runs/30504943669), FolioMCP production Workerd CI (private downstream evidence) at `a4d110efc223` | -| [`create-hayate`](https://github.com/hayatepy/create-hayate) | `0.13.2` | Composable applications with drift-checked first-party TypeScript clients | yes | [golden-app release lock main CI](https://github.com/hayatepy/golden-app/actions/runs/30504943669), [create-hayate 0.13.2 main CI and feature matrix](https://github.com/hayatepy/create-hayate/actions/runs/30502494267), [create-hayate 0.13.2 frontend smoke matrix (10/10)](https://github.com/hayatepy/create-hayate/actions/runs/30502309672), [create-hayate 0.13.2 release provenance](https://github.com/hayatepy/create-hayate/actions/runs/30502570222) | +| [`hayate`](https://github.com/hayatepy/hayate) | `0.15.3` | Core framework and native ASGI, Workers, and Lambda adapters | yes | [golden-app release lock main CI](https://github.com/hayatepy/golden-app/actions/runs/30507749113), [Hayate 0.15.2 downstream full compatibility CI (runtime-equivalent to metadata-only 0.15.3)](https://github.com/hayatepy/hayate/actions/runs/30501023744), [Hayate 0.15.3 main CI](https://github.com/hayatepy/hayate/actions/runs/30506644119), [Hayate 0.15.3 release provenance](https://github.com/hayatepy/hayate/actions/runs/30506830778) | +| [`hayate-auth`](https://github.com/hayatepy/hayate-auth) | `0.10.5` | Sessions, API keys, OAuth clients, and authorization server | downstream gate | [hayate-auth 0.10.5 main CI](https://github.com/hayatepy/hayate-auth/actions/runs/30506737850), [hayate-auth 0.10.5 security profiles](https://github.com/hayatepy/hayate-auth/actions/runs/30506737869), [hayate-auth 0.10.5 release provenance](https://github.com/hayatepy/hayate-auth/actions/runs/30506830212) | +| [`hayate-fetch`](https://github.com/hayatepy/hayate-fetch) | `0.1.4` | Portable WHATWG-style outbound fetch | downstream gate | [hayate-fetch 0.1.4 main CI](https://github.com/hayatepy/hayate-fetch/actions/runs/30506644434), [hayate-fetch 0.1.4 release provenance](https://github.com/hayatepy/hayate-fetch/actions/runs/30506781911), [Hayate 0.15.2 downstream full compatibility CI (runtime-equivalent to metadata-only 0.15.3)](https://github.com/hayatepy/hayate/actions/runs/30501023744) | +| [`hayate-mcp`](https://github.com/hayatepy/hayate-mcp) | `0.12.1` | MCP transport, tools, context, and OAuth resource server | yes | [golden-app release lock main CI](https://github.com/hayatepy/golden-app/actions/runs/30507749113), [hayate-mcp 0.12.1 main CI and MCP 2026-07-28 conformance](https://github.com/hayatepy/hayate-mcp/actions/runs/30504249052), [hayate-mcp 0.12.1 release provenance](https://github.com/hayatepy/hayate-mcp/actions/runs/30504320516), FolioMCP production Workerd CI (private downstream evidence) at `a4d110efc223` | +| [`hayate-openapi`](https://github.com/hayatepy/hayate-openapi) | `0.8.2` | OpenAPI 3.1, Scalar, and generated zero-runtime TypeScript clients | yes | [golden-app release lock main CI](https://github.com/hayatepy/golden-app/actions/runs/30507749113), [hayate-openapi 0.8.2 main CI and TypeScript interoperability](https://github.com/hayatepy/hayate-openapi/actions/runs/30506643960), [hayate-openapi 0.8.2 release provenance](https://github.com/hayatepy/hayate-openapi/actions/runs/30506784156), FolioMCP production Workerd CI (private downstream evidence) at `a4d110efc223` | +| [`hayate-sql`](https://github.com/hayatepy/hayate-sql) | `0.1.2` | Migration-checked SQL contracts and typed query facades | yes | [golden-app release lock main CI](https://github.com/hayatepy/golden-app/actions/runs/30507749113), [hayate-sql 0.1.2 main CI](https://github.com/hayatepy/hayate-sql/actions/runs/30506643955), [hayate-sql 0.1.2 release provenance](https://github.com/hayatepy/hayate-sql/actions/runs/30506782424), FolioMCP production Workerd CI (private downstream evidence) at `a4d110efc223` | +| [`create-hayate`](https://github.com/hayatepy/create-hayate) | `0.13.2` | Composable applications with drift-checked first-party TypeScript clients | yes | [golden-app release lock main CI](https://github.com/hayatepy/golden-app/actions/runs/30507749113), [create-hayate 0.13.2 main CI and feature matrix](https://github.com/hayatepy/create-hayate/actions/runs/30506646209), [create-hayate 0.13.2 frontend smoke matrix (10/10)](https://github.com/hayatepy/create-hayate/actions/runs/30502309672), [create-hayate 0.13.2 release provenance](https://github.com/hayatepy/create-hayate/actions/runs/30502570222) | ## Runtime contracts | Runtime | Executed or supported contract | Status | Evidence | |---|---|---|---| -| Direct | Pure application requests with local SQLite | Golden path | [golden-app release lock main CI](https://github.com/hayatepy/golden-app/actions/runs/30504943669) | -| ASGI | Real Uvicorn process with SQLite | Golden path | [golden-app release lock main CI](https://github.com/hayatepy/golden-app/actions/runs/30504943669) | -| Cloudflare Workers class | Real workerd, D1, RPC-capable WorkerEntrypoint, and class handlers | Golden default | [golden-app release lock main CI](https://github.com/hayatepy/golden-app/actions/runs/30504943669), [Hayate 0.15.2 downstream full compatibility CI](https://github.com/hayatepy/hayate/actions/runs/30501023744), FolioMCP production Workerd CI (private downstream evidence) at `a4d110efc223` | -| Cloudflare Workers global | Global fetch export without RPC or scheduled class handlers | HTTP-only compatibility mode | [golden-app release lock main CI](https://github.com/hayatepy/golden-app/actions/runs/30504943669) | -| AWS Lambda | API Gateway v2 and Function URL buffering plus native response streaming | Core native adapters; outside the golden production flow | [Hayate 0.15.2 main CI](https://github.com/hayatepy/hayate/actions/runs/30501131371) | +| Direct | Pure application requests with local SQLite | Golden path | [golden-app release lock main CI](https://github.com/hayatepy/golden-app/actions/runs/30507749113) | +| ASGI | Real Uvicorn process with SQLite | Golden path | [golden-app release lock main CI](https://github.com/hayatepy/golden-app/actions/runs/30507749113) | +| Cloudflare Workers class | Real workerd, D1, RPC-capable WorkerEntrypoint, and class handlers | Golden default | [golden-app release lock main CI](https://github.com/hayatepy/golden-app/actions/runs/30507749113), [Hayate 0.15.2 downstream full compatibility CI (runtime-equivalent to metadata-only 0.15.3)](https://github.com/hayatepy/hayate/actions/runs/30501023744), FolioMCP production Workerd CI (private downstream evidence) at `a4d110efc223` | +| Cloudflare Workers global | Global fetch export without RPC or scheduled class handlers | HTTP-only compatibility mode | [golden-app release lock main CI](https://github.com/hayatepy/golden-app/actions/runs/30507749113) | +| AWS Lambda | API Gateway v2 and Function URL buffering plus native response streaming | Core native adapters; outside the golden production flow | [Hayate 0.15.3 main CI](https://github.com/hayatepy/hayate/actions/runs/30506644119) | ASGI is a deployment adapter, not a Cloudflare requirement. The Workers class entrypoint is the feature-complete default. The global entrypoint is HTTP-only @@ -49,23 +49,27 @@ and does not imply named RPC or scheduled class-handler support. | `workers-py` | `1.15.0` | | `workers-runtime-sdk` | `1.6.3` | -Golden lock SHA-256: `82fa8313483ca0412ba389e5ca610f47ea943a153c8ca5210cb881981d9a129e` +Golden lock SHA-256: `4502453286edffcee72b1025f7e2f1c81c596cd4bf6734b9c8c52cd4622b6b61` ## Evidence sources -- [golden-app release lock main CI](https://github.com/hayatepy/golden-app/actions/runs/30504943669) at `87e8e907c769ffc5ff24926470eb1ec7641f63b5` -- [hayate-auth 0.10.4 main CI](https://github.com/hayatepy/hayate-auth/actions/runs/30498321148) at `938751d0f225def770d6ae47e1da3da40829c8d1` -- [hayate-auth 0.10.4 security profiles](https://github.com/hayatepy/hayate-auth/actions/runs/30498321150) at `938751d0f225def770d6ae47e1da3da40829c8d1` -- [hayate-auth 0.10.4 release provenance](https://github.com/hayatepy/hayate-auth/actions/runs/30498396435) at `938751d0f225def770d6ae47e1da3da40829c8d1` +- [golden-app release lock main CI](https://github.com/hayatepy/golden-app/actions/runs/30507749113) at `381c071f108e29b16eae6b19b7f870a4fc3f18a9` +- [hayate-auth 0.10.5 main CI](https://github.com/hayatepy/hayate-auth/actions/runs/30506737850) at `4189e735844a06377e9aa7eea2a731d09e500449` +- [hayate-auth 0.10.5 security profiles](https://github.com/hayatepy/hayate-auth/actions/runs/30506737869) at `4189e735844a06377e9aa7eea2a731d09e500449` +- [hayate-auth 0.10.5 release provenance](https://github.com/hayatepy/hayate-auth/actions/runs/30506830212) at `4189e735844a06377e9aa7eea2a731d09e500449` +- [hayate-fetch 0.1.4 main CI](https://github.com/hayatepy/hayate-fetch/actions/runs/30506644434) at `c684291e0fcc1067d9cf4548370c50fb68678a67` +- [hayate-fetch 0.1.4 release provenance](https://github.com/hayatepy/hayate-fetch/actions/runs/30506781911) at `c684291e0fcc1067d9cf4548370c50fb68678a67` - [hayate-mcp 0.12.1 main CI and MCP 2026-07-28 conformance](https://github.com/hayatepy/hayate-mcp/actions/runs/30504249052) at `249b2df4bc41a0603e168b22c53815e31d2d5711` - [hayate-mcp 0.12.1 release provenance](https://github.com/hayatepy/hayate-mcp/actions/runs/30504320516) at `249b2df4bc41a0603e168b22c53815e31d2d5711` -- [hayate-openapi 0.8.1 main CI and TypeScript interoperability](https://github.com/hayatepy/hayate-openapi/actions/runs/30487122341) at `2ed34215ec3dd5ebd0a0780f7b7903f0b3492a78` -- [hayate-openapi 0.8.1 release provenance](https://github.com/hayatepy/hayate-openapi/actions/runs/30487193584) at `2ed34215ec3dd5ebd0a0780f7b7903f0b3492a78` +- [hayate-openapi 0.8.2 main CI and TypeScript interoperability](https://github.com/hayatepy/hayate-openapi/actions/runs/30506643960) at `1247f16e13faf1cd8b9f507c4715e44bb1ec03be` +- [hayate-openapi 0.8.2 release provenance](https://github.com/hayatepy/hayate-openapi/actions/runs/30506784156) at `1247f16e13faf1cd8b9f507c4715e44bb1ec03be` +- [hayate-sql 0.1.2 main CI](https://github.com/hayatepy/hayate-sql/actions/runs/30506643955) at `4e84db1ab3a7683239f288fb1bae64afa3007303` +- [hayate-sql 0.1.2 release provenance](https://github.com/hayatepy/hayate-sql/actions/runs/30506782424) at `4e84db1ab3a7683239f288fb1bae64afa3007303` - FolioMCP production Workerd CI (private downstream evidence) at `a4d110efc223b5774278b21512e176f64f93d525` -- [Hayate 0.15.2 downstream full compatibility CI](https://github.com/hayatepy/hayate/actions/runs/30501023744) at `64dfb96f2397685c9fe017382855749f445d3697` -- [Hayate 0.15.2 main CI](https://github.com/hayatepy/hayate/actions/runs/30501131371) at `8cb27385cbc2655e531c37bdcdb45b1309c3a392` -- [Hayate 0.15.2 release provenance](https://github.com/hayatepy/hayate/actions/runs/30501262533) at `8cb27385cbc2655e531c37bdcdb45b1309c3a392` -- [create-hayate 0.13.2 main CI and feature matrix](https://github.com/hayatepy/create-hayate/actions/runs/30502494267) at `8bcca24bbd43854c05a6467d26b675c20a89b63e` +- [Hayate 0.15.2 downstream full compatibility CI (runtime-equivalent to metadata-only 0.15.3)](https://github.com/hayatepy/hayate/actions/runs/30501023744) at `64dfb96f2397685c9fe017382855749f445d3697` +- [Hayate 0.15.3 main CI](https://github.com/hayatepy/hayate/actions/runs/30506644119) at `a1821a27a83a2406c491338a397b489856db15de` +- [Hayate 0.15.3 release provenance](https://github.com/hayatepy/hayate/actions/runs/30506830778) at `a1821a27a83a2406c491338a397b489856db15de` +- [create-hayate 0.13.2 main CI and feature matrix](https://github.com/hayatepy/create-hayate/actions/runs/30506646209) at `884b2b82dd9c64026d00deecd6afac3200a9baa5` - [create-hayate 0.13.2 frontend smoke matrix (10/10)](https://github.com/hayatepy/create-hayate/actions/runs/30502309672) at `2e3d091b903d7a649ab5f03f4fbf058f4e27d0fa`; aggregate evidence SHA-256 `f207dcd979c695508c4bf672432848e5469ebf4ab1b58b0f2c4fecb8e004af05` - [create-hayate 0.13.2 release provenance](https://github.com/hayatepy/create-hayate/actions/runs/30502570222) at `8bcca24bbd43854c05a6467d26b675c20a89b63e` diff --git a/evidence/golden-app-compatibility.json b/evidence/golden-app-compatibility.json index 022c1c9..401fe6a 100644 --- a/evidence/golden-app-compatibility.json +++ b/evidence/golden-app-compatibility.json @@ -1,6 +1,6 @@ { "generated_by": "create-hayate 0.13.2", - "lock_sha256": "82fa8313483ca0412ba389e5ca610f47ea943a153c8ca5210cb881981d9a129e", + "lock_sha256": "4502453286edffcee72b1025f7e2f1c81c596cd4bf6734b9c8c52cd4622b6b61", "mcp_revision": "2026-07-28", "node": "24", "packages": [ @@ -16,14 +16,14 @@ "package": "hayate", "role": "Application core and runtime adapters", "source": "uv.lock", - "version": "0.15.2" + "version": "0.15.3" }, { "commit": null, "package": "hayate-openapi", "role": "OpenAPI 3.1, Scalar, and zero-runtime TypeScript client", "source": "uv.lock", - "version": "0.8.1" + "version": "0.8.2" }, { "commit": null, @@ -37,7 +37,7 @@ "package": "hayate-sql", "role": "Checked SQL and database adapters", "source": "uv.lock", - "version": "0.1.1" + "version": "0.1.2" }, { "commit": null, diff --git a/scripts/check_ecosystem_discovery.py b/scripts/check_ecosystem_discovery.py new file mode 100644 index 0000000..e054244 --- /dev/null +++ b/scripts/check_ecosystem_discovery.py @@ -0,0 +1,158 @@ +#!/usr/bin/env python3 +"""Check public discovery contracts across every Hayate family repository.""" + +from __future__ import annotations + +import io +import re +import sys +import tarfile +import time +import tomllib +import urllib.request +from pathlib import Path, PurePosixPath +from typing import Any + +ROOT = Path(__file__).resolve().parents[1] +CONTRACT_PATH = ROOT / "data" / "public-discovery.toml" +OWNER = "hayatepy" +SCAFFOLD_PIN = re.compile(r"\bcreate-hayate==(?P\d+(?:\.\d+)+)\b") +PUBLIC_SUFFIXES = {".md", ".txt"} + + +def _version(value: str) -> tuple[int, ...]: + return tuple(int(part) for part in value.split(".")) + + +def _is_public_source(path: PurePosixPath) -> bool: + if path.name == "CHANGELOG.md": + return False + if len(path.parts) == 1: + return path.suffix in PUBLIC_SUFFIXES or path.name == "pyproject.toml" + return path.parts[0] in {"docs", "profile"} and path.suffix in PUBLIC_SUFFIXES + + +def validate_repository( + repository: dict[str, Any], + sources: dict[str, str], + contract: dict[str, Any], +) -> list[str]: + """Return actionable contract violations for one repository snapshot.""" + failures: list[str] = [] + name = str(repository["name"]) + readme = sources.get("README.md") + project_text = sources.get("pyproject.toml") + if readme is None: + failures.append(f"{name}: README.md is missing from the default branch") + else: + for key in ("canonical_home", "canonical_compatibility"): + expected = str(contract[key]) + if expected not in readme: + failures.append(f"{name}: README.md omits {expected}") + if project_text is None: + failures.append(f"{name}: pyproject.toml is missing from the default branch") + else: + try: + project = tomllib.loads(project_text)["project"] + actual_homepage = project["urls"]["Homepage"] + except (KeyError, tomllib.TOMLDecodeError): + failures.append(f"{name}: pyproject.toml has no valid project.urls.Homepage") + else: + expected_homepage = repository["homepage"] + if actual_homepage != expected_homepage: + failures.append( + f"{name}: Homepage is {actual_homepage!r}, expected {expected_homepage!r}" + ) + + minimum_scaffold = _version(str(contract["minimum_scaffold_version"])) + for path, text in sorted(sources.items()): + for superseded in contract["superseded_prefixes"]: + if superseded in text: + failures.append(f"{name}:{path}: superseded public URL: {superseded}") + for match in SCAFFOLD_PIN.finditer(text): + found = match.group("version") + if _version(found) < minimum_scaffold: + failures.append( + f"{name}:{path}: create-hayate=={found} is older than " + f"{contract['minimum_scaffold_version']}" + ) + return failures + + +def _download_archive(repository: str) -> bytes: + url = f"https://api.github.com/repos/{OWNER}/{repository}/tarball/main" + request = urllib.request.Request( + url, + headers={ + "Accept": "application/vnd.github+json", + "User-Agent": "hayatepy-public-discovery-gate/1", + "X-GitHub-Api-Version": "2022-11-28", + }, + ) + last_error: Exception | None = None + for attempt in range(3): + try: + with urllib.request.urlopen(request, timeout=60) as response: + return response.read() + except Exception as exc: # pragma: no cover - exercised only by network failure + last_error = exc + if attempt < 2: + time.sleep(2**attempt) + raise RuntimeError(f"could not fetch {OWNER}/{repository}@main: {last_error}") + + +def _public_sources(archive: bytes) -> tuple[str, dict[str, str]]: + sources: dict[str, str] = {} + commit = "unknown" + with tarfile.open(fileobj=io.BytesIO(archive), mode="r:gz") as snapshot: + for member in snapshot.getmembers(): + if not member.isfile(): + continue + parts = PurePosixPath(member.name).parts + if len(parts) < 2: + continue + root, *relative_parts = parts + if "-" in root: + commit = root.rsplit("-", 1)[-1] + relative = PurePosixPath(*relative_parts) + if not _is_public_source(relative): + continue + extracted = snapshot.extractfile(member) + if extracted is None: + continue + try: + sources[str(relative)] = extracted.read().decode("utf-8") + except UnicodeDecodeError: + continue + return commit, sources + + +def main() -> int: + with CONTRACT_PATH.open("rb") as source: + contract = tomllib.load(source) + if contract.get("schema_version") != 1: + print("unsupported public-discovery contract schema", file=sys.stderr) + return 2 + + failures: list[str] = [] + checked: list[str] = [] + for repository in contract["repositories"]: + name = str(repository["name"]) + try: + commit, sources = _public_sources(_download_archive(name)) + except RuntimeError as exc: + failures.append(str(exc)) + continue + failures.extend(validate_repository(repository, sources, contract)) + checked.append(f"{name}@{commit}") + + if failures: + print("\n".join(failures), file=sys.stderr) + return 1 + print(f"public discovery verified across {len(checked)} repositories") + print("\n".join(checked)) + return 0 + + +if __name__ == "__main__": + raise SystemExit(main()) diff --git a/tests/test_ecosystem_discovery.py b/tests/test_ecosystem_discovery.py new file mode 100644 index 0000000..df63e91 --- /dev/null +++ b/tests/test_ecosystem_discovery.py @@ -0,0 +1,86 @@ +from __future__ import annotations + +import sys +import unittest +from pathlib import Path + +sys.path.insert(0, str(Path(__file__).resolve().parents[1] / "scripts")) + +import check_ecosystem_discovery + +CONTRACT = { + "canonical_home": "https://hayatepy.dev/", + "canonical_compatibility": "https://hayatepy.dev/evidence/compatibility/", + "minimum_scaffold_version": "0.13.2", + "superseded_prefixes": [ + "https://hayatepy.github.io/", + "https://github.com/hayatepy/.github/blob/main/docs/START.md", + ], +} +REPOSITORY = { + "name": "hayate-example", + "homepage": "https://hayatepy.dev/ecosystem/#hayate-example", +} + + +def sources() -> dict[str, str]: + return { + "README.md": ( + "[Start](https://hayatepy.dev/)\n" + "[Compatibility](https://hayatepy.dev/evidence/compatibility/)\n" + "`create-hayate==0.13.2`\n" + ), + "pyproject.toml": """ +[project] +name = "hayate-example" +[project.urls] +Homepage = "https://hayatepy.dev/ecosystem/#hayate-example" +""", + } + + +class EcosystemDiscoveryTests(unittest.TestCase): + def test_accepts_the_canonical_contract(self) -> None: + self.assertEqual( + check_ecosystem_discovery.validate_repository( + REPOSITORY, + sources(), + CONTRACT, + ), + [], + ) + + def test_rejects_superseded_links_and_scaffold_pins(self) -> None: + changed = sources() + changed["docs/START.md"] = ( + "https://github.com/hayatepy/.github/blob/main/docs/START.md\n" + "create-hayate==0.13.1\n" + ) + + failures = check_ecosystem_discovery.validate_repository( + REPOSITORY, + changed, + CONTRACT, + ) + + self.assertTrue(any("superseded public URL" in failure for failure in failures)) + self.assertTrue(any("older than 0.13.2" in failure for failure in failures)) + + def test_rejects_homepage_drift(self) -> None: + changed = sources() + changed["pyproject.toml"] = changed["pyproject.toml"].replace( + "https://hayatepy.dev/ecosystem/#hayate-example", + "https://github.com/hayatepy/hayate-example", + ) + + failures = check_ecosystem_discovery.validate_repository( + REPOSITORY, + changed, + CONTRACT, + ) + + self.assertTrue(any("Homepage is" in failure for failure in failures)) + + +if __name__ == "__main__": + unittest.main()