{
  "$comment": "webGCP conformance fixture WGCP-L0-003 (DNS-layer SVCB discovery) per spec §5.1.1 + §9 — https://webgcp.org/spec/v0.1/. Authored 2026-05-16, runnable against any compliant public DoH resolver.",
  "fixture_id": "WGCP-L0-003",
  "fixture_name": "DNS-layer SVCB discovery at _webgcp.<host>",
  "verifies": [
    "§5.1.1 — SVCB record MUST exist at _webgcp.<host>",
    "§5.1.1 — SvcPriority MUST be > 0 (ServiceMode)",
    "§5.1.1 — TargetName MUST resolve",
    "§5.1.1 — TargetName's /.well-known/webgcp MUST return the implementation's descriptor",
    "decree §XIII.20 — cross-namespace consistency (_webgcp.<host> ↔ webgcp._agents.<host>) when both names are published",
    "decree §XIII.19 — multi-resolver agreement (Cloudflare DoH primary; Google DoH secondary with empirical-divergence caveat)"
  ],
  "preconditions": {
    "implementation_host_declared_in_descriptor": "The implementation MUST declare its conformance hostname(s) in its /.well-known/webgcp descriptor's `endpoints` block.",
    "operator_controls_authoritative_dns": "If the operator does NOT control authoritative DNS at the hostname (e.g., *.web.app, *.firebaseapp.com, *.netlify.app, *.vercel.app, *.github.io), this fixture is expected to fail and the implementation MUST claim `L0-restricted-domain` rather than `L0` per §5.1.1."
  },
  "given": {
    "step_1_dns_query": {
      "method": "DNS lookup or DoH GET",
      "doh_examples": [
        "https://dns.google/resolve?name=_webgcp.<HOST>&type=64",
        "https://cloudflare-dns.com/dns-query?name=_webgcp.<HOST>&type=64"
      ],
      "headers_for_cloudflare_doh": {
        "Accept": "application/dns-json"
      },
      "substitute": {
        "<HOST>": "The implementation's conformance hostname (e.g., `webgcp.org`, `news.example.com`, etc.)."
      }
    },
    "step_2_descriptor_fetch": {
      "method": "HTTPS GET",
      "url_template": "https://<TARGET_NAME>/.well-known/webgcp",
      "where": "<TARGET_NAME> is the SVCB record's TargetName (often equal to <HOST> itself)."
    }
  },
  "expected_response_shape": {
    "step_1_dns": {
      "Status": 0,
      "Answer": [
        {
          "name": "_webgcp.<HOST>.",
          "type": 64,
          "TTL": "INTEGER (300 to 3600 recommended)",
          "data": "ANY_NON_EMPTY_STRING starting with a non-zero priority and a target hostname"
        }
      ]
    },
    "step_2_descriptor": {
      "Content-Type": "application/json",
      "body_keys_present": [
        "spec_version",
        "conformance_level",
        "server_id",
        "endpoints"
      ]
    }
  },
  "assertions": [
    {
      "id": "A01",
      "assert": "step_1_dns.Status == 0 (NOERROR)",
      "verifies": "§5.1.1 — SVCB record MUST exist"
    },
    {
      "id": "A02",
      "assert": "step_1_dns.Answer is non-empty and at least one entry has .type == 64",
      "verifies": "§5.1.1 — record exists at _webgcp.<HOST>"
    },
    {
      "id": "A03",
      "assert": "parsing step_1_dns.Answer[].data, the SvcPriority field MUST be a positive integer (ServiceMode, not AliasMode)",
      "verifies": "§5.1.1 — SvcPriority MUST be > 0"
    },
    {
      "id": "A04",
      "assert": "parsing step_1_dns.Answer[].data, the TargetName field MUST be a non-empty domain name",
      "verifies": "§5.1.1 — TargetName MUST resolve"
    },
    {
      "id": "A05",
      "assert": "step_2_descriptor returns HTTP 200",
      "verifies": "§5.1.1 — /.well-known/webgcp on TargetName MUST serve"
    },
    {
      "id": "A06",
      "assert": "step_2_descriptor.body.spec_version == '0.1'",
      "verifies": "§5.1 — descriptor declares spec version"
    },
    {
      "id": "A07",
      "assert": "step_2_descriptor.body.endpoints is an object and contains at least one URL pointing back at <HOST>",
      "verifies": "§5.1 + §5.1.1 — DNS discovery resolves to the operator's actual endpoints"
    }
  ],
  "negative_assertions": [
    {
      "id": "N01",
      "assert_not": "step_1_dns.Answer entries with .type == 64 having SvcPriority == 0 (AliasMode)",
      "verifies": "§5.1.1 — AliasMode is reserved for v0.2"
    },
    {
      "id": "N02",
      "assert_not": "step_1_dns.Answer entries with .type == 64 having a non-empty SvcParams field",
      "verifies": "§5.1.1 — v0.1 servers SHOULD NOT include SvcParams; the test treats their presence as a soft warning, not a hard fail (this assertion is informational at v0.1, hard at v0.2)"
    }
  ],
  "cross_namespace_verification": {
    "rationale": "Per agentic-engineering-decree.md §XIII.20 + §X 'in DNS' §5: when a host claims L3+ federation, the DNSAID composition name `webgcp._agents.<host>` MUST carry SvcParams byte-equal to (or semantically equivalent to) those at `_webgcp.<host>`. At L0, the DNSAID composition name is SHOULD; its absence does not break conformance. This check runs in two modes: byte-equal at L0+ when both names exist; required-byte-equal at L3+.",
    "decree_failure_mode": "§XIII.20 — Cross-namespace drift: `_webgcp.<host>` and `webgcp._agents.<host>` carrying different SvcParams. Highest-ROI to detect because the failure is invisible until federation is exercised; cheapest to keep wrong if no CI assertion.",
    "names": [
      "_webgcp.<HOST>",
      "webgcp._agents.<HOST>"
    ],
    "assertions": [
      {
        "id": "X01",
        "assert": "IF webgcp._agents.<HOST> resolves to a SVCB record THEN its rdata MUST be byte-equal to (or semantically equivalent across RFC 3597 encoding forms with) the rdata at _webgcp.<HOST>",
        "verifies": "decree §XIII.20 — cross-namespace consistency"
      },
      {
        "id": "X02",
        "assert": "L0 conformance MUST NOT require webgcp._agents.<HOST> to resolve; its NXDOMAIN or empty Answer is conformant at L0–L2",
        "verifies": "§5.1.1 — L0 MUST is the `_webgcp.<host>` namespace; DNSAID composition is L3+ SHOULD"
      }
    ],
    "level_gates": {
      "L0_to_L2": "X01 conditional (only applies if DNSAID composition name is published); X02 is the floor.",
      "L3_plus": "X01 unconditional MUST; X02 no longer applies (composition name is REQUIRED for federation)."
    }
  },
  "multi_resolver_verification": {
    "rationale": "Per agentic-engineering-decree.md §XIII.19: DoH provider divergence is a known failure mode. Two operators querying the same _webgcp.<host> via different DoH endpoints can observe different results when one resolver's SVCB handling is incomplete. Conformance fixtures SHOULD verify via multiple resolvers and surface divergence as a soft warning, not a hard fail at v0.1, until the broader DoH ecosystem's SVCB handling matures.",
    "decree_failure_mode": "§XIII.19 — DoH provider divergence. Mitigation: multi-resolver verification in conformance fixtures.",
    "primary_resolver": {
      "url": "https://cloudflare-dns.com/dns-query",
      "role": "ground truth at v0.1",
      "notes": "Cloudflare DoH has been observed to correctly return SVCB Answers including RFC 3597 generic-encoded rdata."
    },
    "secondary_resolvers": [
      {
        "url": "https://dns.google/resolve",
        "role": "secondary; empirical-divergence caveat applies at v0.1",
        "notes": "Google DoH has been observed to return empty .Answer arrays for SVCB type-64 queries while the record is correctly provisioned at authoritative DNS (verified 2026-05-16 against _webgcp.webgcp.org). Treat empty Answer from Google DoH as INFO (not WARN, not FAIL) at v0.1; re-evaluate at v0.2."
      }
    ],
    "assertions": [
      {
        "id": "M01",
        "assert": "primary_resolver returns a non-empty Answer array containing at least one entry with .type == 64",
        "verifies": "decree §XIII.19 — primary resolver is ground truth; if even Cloudflare returns empty, the record is missing at authoritative DNS"
      },
      {
        "id": "M02",
        "assert": "for each secondary_resolver: IF its Answer is non-empty THEN its .data field MUST be byte-equal to (or semantically equivalent across RFC 3597 encoding forms with) primary_resolver's .data; empty Answer from a secondary resolver is INFO at v0.1 (not WARN, not FAIL)",
        "verifies": "decree §XIII.19 — cross-resolver agreement; informational at v0.1 per the Google DoH empirical caveat; hard at v0.2 once the DoH ecosystem's SVCB handling matures"
      }
    ],
    "level_gates": {
      "v0_1": "M01 hard; M02 soft (empty Answer from a secondary resolver does not fail the fixture).",
      "v0_2": "M01 hard; M02 hard (all listed secondary resolvers MUST return equivalent rdata)."
    }
  },
  "live_verification_examples": {
    "webgcp_org_spec_host_2026_05_16": {
      "host": "webgcp.org",
      "doh_query": "https://cloudflare-dns.com/dns-query?name=_webgcp.webgcp.org&type=64",
      "expected_record": "_webgcp.webgcp.org.  3600  IN  SVCB  1  webgcp.org.",
      "expected_descriptor_at_target": "https://webgcp.org/.well-known/webgcp",
      "status_at_publication": "live 2026-05-16; SVCB record provisioned at Squarespace DNS (TTL 14400); verified via Cloudflare DoH (Google DoH may return empty Answer for SVCB — use Cloudflare as primary verifier per SVCB-AT-SQUARESPACE.md). All 9 assertions (A01-A07 + N01-N02) pass against the live record."
    },
    "the_ai_news_2026_05_16": {
      "host": "the-ai-news.web.app",
      "expected_outcome": "TEST FAILS — host is under Firebase's `.web.app` zone; operator does not control authoritative DNS at this name. Per §5.1.1 restricted-domain caveat, this implementation MUST claim conformance_level: 'L0-restricted-domain' rather than 'L0'."
    }
  },
  "implementation_notes": {
    "doh_recommended": "Tests can run from any environment with HTTPS access — no `dig` or `nslookup` required. Both Google (https://dns.google/resolve) and Cloudflare (https://cloudflare-dns.com/dns-query) expose DoH JSON APIs.",
    "type_64_or_type_name": "Some DoH endpoints accept the type as the numeric `64` or the symbolic `SVCB`. Both should work; the fixture uses `64` for compatibility.",
    "answer_parsing": "The .data field in DoH JSON responses is a textual representation of the SVCB rdata. Parsers MAY use python's `dnspython` library, golang's `miekg/dns`, or hand-roll. The fixture's assertions A03/A04 require extracting SvcPriority + TargetName from this textual form.",
    "rfc_3597_generic_encoding": "DoH resolvers MAY return SVCB rdata in either typed form (`1 webgcp.org.`) or RFC 3597 generic-encoded form (`\\# 14 00 01 06 77 65 62 67 63 70 03 6f 72 67 00`). Both are wire-equivalent. Assertion M02 (cross-resolver agreement) MUST treat these as equivalent when comparing across resolvers; assertion X01 (cross-namespace consistency) MUST treat these as equivalent when comparing across names. Byte-equal string comparison is a sufficient first-pass; structural priority+target comparison is the canonical equivalence check.",
    "reference_runner": "`scripts/check-svcb-consistency.sh` in the canonical catalog (D:\\catalog\\scripts\\) runs A01-A07 + X01-X02 + M01-M02 against any host argument. Default host: `webgcp.org`. Usage: `bash scripts/check-svcb-consistency.sh [host]`. Returns exit 0 (PASS or PASS-with-INFO), exit 1 (cross-namespace mismatch — decree §XIII.20 FAILURE), exit 2 (primary resolver returned empty Answer — record missing), exit 3 (infrastructure error)."
  },
  "spec_pin": {
    "spec_url": "https://webgcp.org/spec/v0.1/",
    "spec_version": "0.1.0-draft.2026-05-16"
  },
  "$status_2026_05_16": "Live. SVCB record provisioned at Squarespace DNS for webgcp.org (TTL 14400). All 13 assertions pass against the live record: 7 positive (A01-A07) + 2 negative (N01-N02) + 2 cross-namespace (X01 conditional, X02 floor) + 2 multi-resolver (M01 hard, M02 soft per v0.1 Google-DoH empirical caveat). Verifiable via DoH: https://cloudflare-dns.com/dns-query?name=_webgcp.webgcp.org&type=64 or via the reference runner `bash scripts/check-svcb-consistency.sh webgcp.org`. The-ai-news.web.app remains L0-restricted-domain per §5.1.1's restricted-domain caveat. Cross-namespace + multi-resolver blocks added 2026-05-16 per agentic-engineering-decree.md §XIII.19 + §XIII.20."
}
