From 949818e8ceae95a7d020993b1d41daac0fc80836 Mon Sep 17 00:00:00 2001 From: Brian Searls Date: Fri, 19 Jun 2026 17:47:51 +0000 Subject: [PATCH 1/2] WIP: versioning model in extdeps --- dsl/extdeps/cron/schedule_model.dag | 9 ++++- dsl/extdeps/github/github.dag | 7 ++++ dsl/extdeps/llm/anthropic.dag | 12 ++---- dsl/extdeps/version.dag | 40 +++++++++++++++++++ .../claim/extdeps_version_witness_test.dag | 38 ++++++++++++++++++ 5 files changed, 96 insertions(+), 10 deletions(-) create mode 100644 dsl/extdeps/version.dag create mode 100644 dsl/test/claim/extdeps_version_witness_test.dag diff --git a/dsl/extdeps/cron/schedule_model.dag b/dsl/extdeps/cron/schedule_model.dag index b2172b73347..e3c3e85e965 100644 --- a/dsl/extdeps/cron/schedule_model.dag +++ b/dsl/extdeps/cron/schedule_model.dag @@ -1,8 +1,7 @@ // extdeps/cron/schedule_model.dag — POSIX crontab schedule protocol (carriers + wire render). // // Fidelity — extdeps invariant (cite source + declare version; DESIGN.md §3): -// Spec: https://pubs.opengroup.org/onlinepubs/9699919799/utilities/crontab.html -// Version: POSIX.1-2017 (IEEE Std 1003.1-2017; Open Group Issue 7, 2018 edition online snapshot) +// `posix_crontab_spec` (extdeps.version.UpstreamSpecCitation) // // Sections referenced: // — XCU `crontab` utility: user crontab file layout; five time-and-date fields (minute, hour, @@ -23,9 +22,15 @@ module extdeps.cron.schedule_model +import extdeps.version { UpstreamSpecCitation } import std.integer { NonNegativeInt, PositiveInt } import std.list { List } +data posix_crontab_spec: UpstreamSpecCitation = { + source: "https://pubs.opengroup.org/onlinepubs/9699919799/utilities/crontab.html", + version: "POSIX.1-2017 (IEEE Std 1003.1-2017; Open Group Issue 7, 2018 edition online snapshot)" +} + // Coproduct dissolution: `CronField`. // // Classification ledger (N≥2 variants — checkpoint names 🟢 / 🟡 / 🔴): diff --git a/dsl/extdeps/github/github.dag b/dsl/extdeps/github/github.dag index 5b9682bbd39..b038afdbcef 100644 --- a/dsl/extdeps/github/github.dag +++ b/dsl/extdeps/github/github.dag @@ -14,6 +14,7 @@ module extdeps.github.github +import extdeps.version { RestApiVersionHeader } import std.serialization { VariantEncoding, StringVariant, VariantNaming, AsAuthored } import std.types { Timestamp, Url } @@ -70,6 +71,12 @@ type GitHubPermission = PermRead | PermWrite | PermAdmin // -- Constants ----------------------------------------------------- +// Spec: https://docs.github.com/en/rest/about-the-rest-api/api-versions +data default_rest_api_version: RestApiVersionHeader = { + header: "X-GitHub-Api-Version", + version: "2022-11-28" +} + data default_api_base: Url = "https://api.github.com" data default_per_page: Int = 30 diff --git a/dsl/extdeps/llm/anthropic.dag b/dsl/extdeps/llm/anthropic.dag index 154a44a3da2..1daf369ff0a 100644 --- a/dsl/extdeps/llm/anthropic.dag +++ b/dsl/extdeps/llm/anthropic.dag @@ -7,6 +7,7 @@ module extdeps.llm.anthropic import extdeps.llm.llm { llm_snake_wire_contract } +import extdeps.version { RestApiVersionHeader } import std.serialization { CoproductWireContract, VariantEncoding } // Wire contract: Anthropic API returns enum values as snake_case strings. @@ -220,14 +221,9 @@ type AnthropicToolDefinition { // -- API versioning ------------------------------------------------ -type AnthropicApiVersion { - version: String - header: String -} - -data current_api_version: AnthropicApiVersion = { - version: "2023-06-01", - header: "anthropic-version" +data current_api_version: RestApiVersionHeader = { + header: "anthropic-version", + version: "2023-06-01" } // Messages API conversation row: the outer variant is the role discriminator, diff --git a/dsl/extdeps/version.dag b/dsl/extdeps/version.dag new file mode 100644 index 00000000000..6bb246ecc39 --- /dev/null +++ b/dsl/extdeps/version.dag @@ -0,0 +1,40 @@ +// extdeps/version.dag — upstream version citations (DESIGN.md §3). +// +// extdeps invariant: cite the source, keep its real names, declare its version. +// Single authority for *how* extdeps records that fidelity citation — not a +// normalization layer. Upstream names its own versions (POSIX.1-2017, +// 2022-11-28, v1, 1.2.0); carriers preserve those labels as +// `UpstreamVersionLabel`. +// +// SemVer lives in `std.types` when upstream genuinely uses semver (OCI runtime +// bundle version, crate manifests). Do not re-mint semver here. +// +// Consumers: +// extdeps/cron/schedule_model.dag — `UpstreamSpecCitation` +// extdeps/llm/anthropic.dag — `RestApiVersionHeader` +// extdeps/github/github.dag — `RestApiVersionHeader` + +module extdeps.version + +import std.types { NonEmptyStr, Url } + +// Version label exactly as the upstream source names it — not normalized to SemVer. +type UpstreamVersionLabel = NonEmptyStr where brand("UpstreamVersionLabel") + +// DESIGN §3 spec citation: source URL + declared version. +type UpstreamSpecCitation { + source: Url + version: UpstreamVersionLabel +} + +// REST API version pinned via a request header (Anthropic `anthropic-version`, +// GitHub `X-GitHub-Api-Version`). Header name is part of the upstream contract. +type RestApiVersionHeader { + header: NonEmptyStr + version: UpstreamVersionLabel +} + +// REST API version pinned via URL path segment (GCP `/storage/v1`, `/run/v2`). +type RestApiPathVersion { + segment: NonEmptyStr +} diff --git a/dsl/test/claim/extdeps_version_witness_test.dag b/dsl/test/claim/extdeps_version_witness_test.dag new file mode 100644 index 00000000000..f4e4c9624e2 --- /dev/null +++ b/dsl/test/claim/extdeps_version_witness_test.dag @@ -0,0 +1,38 @@ +// By-execution witnesses for extdeps.version — DESIGN.md §3 fidelity citations. +// Discriminating: each witness goes RED if a field reverts to bare String. +// +// Run via: +// gunbc run --source-root dsl --entry dsl/test/claim/extdeps_version_witness_test.dag \ +// --function extdeps_version_witnesses --claim-run + +module test.claim.extdeps_version_witness + +import extdeps.cron.schedule_model { posix_crontab_spec } +import extdeps.github.github { default_rest_api_version } +import extdeps.llm.anthropic { current_api_version } + +fn w_posix_crontab_spec_citation() -> Bool { + posix_crontab_spec.version == "POSIX.1-2017 (IEEE Std 1003.1-2017; Open Group Issue 7, 2018 edition online snapshot)" + && string_contains(s: posix_crontab_spec.source, pattern: "crontab.html") +} + +fn w_anthropic_api_version_header() -> Bool { + current_api_version.header == "anthropic-version" + && current_api_version.version == "2023-06-01" +} + +fn w_github_api_version_header() -> Bool { + default_rest_api_version.header == "X-GitHub-Api-Version" + && default_rest_api_version.version == "2022-11-28" +} + +fn w_distinct_api_version_labels() -> Bool { + current_api_version.version != default_rest_api_version.version +} + +test fn extdeps_version_witnesses() -> Bool { + w_posix_crontab_spec_citation() + && w_anthropic_api_version_header() + && w_github_api_version_header() + && w_distinct_api_version_labels() +} From d7ff9424c67b2a7149e2dd2cbb8cc3738d29579e Mon Sep 17 00:00:00 2001 From: Brian Searls Date: Fri, 19 Jun 2026 18:12:55 +0000 Subject: [PATCH 2/2] extdeps versioning program closeout: extend RestApiPathVersion to GCP Co-Authored-By: Claude Sonnet 4.6 --- dsl/extdeps/cloud/gcp/gcp.dag | 15 ++++++++------- dsl/extdeps/version.dag | 3 ++- .../extdeps_round2_grounding_witness_test.dag | 2 +- .../claim/extdeps_version_witness_test.dag | 19 +++++++++++++++++++ 4 files changed, 30 insertions(+), 9 deletions(-) diff --git a/dsl/extdeps/cloud/gcp/gcp.dag b/dsl/extdeps/cloud/gcp/gcp.dag index 605085aaa12..ee8e4121e2f 100644 --- a/dsl/extdeps/cloud/gcp/gcp.dag +++ b/dsl/extdeps/cloud/gcp/gcp.dag @@ -16,6 +16,7 @@ module extdeps.cloud.gcp.gcp import extdeps.cloud.cloud { ServiceEndpoint } +import extdeps.version { RestApiPathVersion } import std.types { FilePath, NonEmptyStr, Secret, HttpMethod, AuthScheme } import extdeps.cloud.gcp.errors { GcpErrorShape, GcpOAuth2ErrorShape } @@ -111,16 +112,16 @@ fn gcp_service_wire_label(service: GcpService) -> String { type GcpApiEndpoint { service: GcpService base_url: String - version: String + version: RestApiPathVersion } data api_endpoints: List = [ - { service: GcpStorage, base_url: "https://storage.googleapis.com/storage/v1", version: "v1" }, - { service: GcpIam, base_url: "https://iam.googleapis.com/v1", version: "v1" }, - { service: GcpSecretManager, base_url: "https://secretmanager.googleapis.com/v1", version: "v1" }, - { service: GcpCloudRun, base_url: "https://run.googleapis.com/v2", version: "v2" }, - { service: GcpPubsub, base_url: "https://pubsub.googleapis.com/v1", version: "v1" }, - { service: GcpSts, base_url: "https://sts.googleapis.com/v1", version: "v1" } + { service: GcpStorage, base_url: "https://storage.googleapis.com/storage/v1", version: { segment: "v1" } }, + { service: GcpIam, base_url: "https://iam.googleapis.com/v1", version: { segment: "v1" } }, + { service: GcpSecretManager, base_url: "https://secretmanager.googleapis.com/v1", version: { segment: "v1" } }, + { service: GcpCloudRun, base_url: "https://run.googleapis.com/v2", version: { segment: "v2" } }, + { service: GcpPubsub, base_url: "https://pubsub.googleapis.com/v1", version: { segment: "v1" } }, + { service: GcpSts, base_url: "https://sts.googleapis.com/v1", version: { segment: "v1" } } ] // -- Regions ------------------------------------------------------- diff --git a/dsl/extdeps/version.dag b/dsl/extdeps/version.dag index 6bb246ecc39..97b761967de 100644 --- a/dsl/extdeps/version.dag +++ b/dsl/extdeps/version.dag @@ -10,9 +10,10 @@ // bundle version, crate manifests). Do not re-mint semver here. // // Consumers: -// extdeps/cron/schedule_model.dag — `UpstreamSpecCitation` +// extdeps/cron/schedule_model.dag — `UpstreamSpecCitation` // extdeps/llm/anthropic.dag — `RestApiVersionHeader` // extdeps/github/github.dag — `RestApiVersionHeader` +// extdeps/cloud/gcp/gcp.dag — `RestApiPathVersion` module extdeps.version diff --git a/dsl/test/claim/extdeps_round2_grounding_witness_test.dag b/dsl/test/claim/extdeps_round2_grounding_witness_test.dag index f73ad0ec70f..dcbdeaa4323 100644 --- a/dsl/test/claim/extdeps_round2_grounding_witness_test.dag +++ b/dsl/test/claim/extdeps_round2_grounding_witness_test.dag @@ -120,7 +120,7 @@ fn w_gcp_api_endpoint_service_enum() -> Bool { let endpoint = GcpApiEndpoint { service: GcpStorage, base_url: "https://storage.googleapis.com/storage/v1", - version: "v1", + version: { segment: "v1" }, } endpoint.service == GcpStorage && gcp_service_wire_label(GcpStorage) == "storage" diff --git a/dsl/test/claim/extdeps_version_witness_test.dag b/dsl/test/claim/extdeps_version_witness_test.dag index f4e4c9624e2..c10007782ce 100644 --- a/dsl/test/claim/extdeps_version_witness_test.dag +++ b/dsl/test/claim/extdeps_version_witness_test.dag @@ -7,6 +7,7 @@ module test.claim.extdeps_version_witness +import extdeps.cloud.gcp.gcp { GcpApiEndpoint, GcpCloudRun, GcpStorage } import extdeps.cron.schedule_model { posix_crontab_spec } import extdeps.github.github { default_rest_api_version } import extdeps.llm.anthropic { current_api_version } @@ -30,9 +31,27 @@ fn w_distinct_api_version_labels() -> Bool { current_api_version.version != default_rest_api_version.version } +// GCP path versions: goes RED if GcpApiEndpoint.version reverts to bare String. +fn w_gcp_path_version_typed() -> Bool { + let run_ep = GcpApiEndpoint { + service: GcpCloudRun, + base_url: "https://run.googleapis.com/v2", + version: { segment: "v2" }, + } + let storage_ep = GcpApiEndpoint { + service: GcpStorage, + base_url: "https://storage.googleapis.com/storage/v1", + version: { segment: "v1" }, + } + run_ep.version.segment == "v2" + && storage_ep.version.segment == "v1" + && run_ep.version.segment != storage_ep.version.segment +} + test fn extdeps_version_witnesses() -> Bool { w_posix_crontab_spec_citation() && w_anthropic_api_version_header() && w_github_api_version_header() && w_distinct_api_version_labels() + && w_gcp_path_version_typed() }