diff --git a/.github/workflows/sync.yml b/.github/workflows/sync.yml index 20ec04a..960f8fc 100644 --- a/.github/workflows/sync.yml +++ b/.github/workflows/sync.yml @@ -36,7 +36,9 @@ jobs: echo "any=false" >> "$GITHUB_OUTPUT" else echo "any=true" >> "$GITHUB_OUTPUT" - echo "versions=$(git diff --name-only -- data | grep '\.json\.gz$' | sed 's#data/##; s#/# v#; s#\.json\.gz##' | paste -sd', ' -)" >> "$GITHUB_OUTPUT" + # `v` only where there is a version to prefix: an untagged source is + # dated, and `v2026-09-01` names a tag that does not exist. + echo "versions=$(git diff --name-only -- data | grep '\.json\.gz$' | sed -E 's#^data/##; s#\.json\.gz$##; s#/([0-9]+\.[0-9]+)# v\1#; s#/# #' | paste -sd', ' -)" >> "$GITHUB_OUTPUT" fi # Build first: the MCP worker tests read dist/. The tests assert against diff --git a/README.md b/README.md index d60d7f7..5e4c3a4 100644 --- a/README.md +++ b/README.md @@ -53,7 +53,9 @@ bun run build `bun run ingest --force` re-normalizes every tracked release. It should produce a byte-identical `data/` — snapshots are fully sorted and gzipped at a fixed level precisely so that "the file -changed" is a reliable signal that upstream moved. +changed" is a reliable signal that upstream moved. For an untagged source it re-walks the history +from the floor and drops the existing snapshots first, because which commits produce a distinct +model is exactly what a changed normalizer changes. ## The GenAI registry is untagged @@ -62,9 +64,27 @@ tags, a towncrier CHANGELOG reading only "Unreleased", and `stability: developme itself. Waiting for a tag would mean tracking nothing while the attributes are already in production use. -So it is tracked from `main`, versioned by commit date (`2026-09-03`) with the short SHA kept as the -tag, and labelled unreleased everywhere it appears. Snapshots are written only when the *normalized -model* changes, not when the branch moves — otherwise `data/` would grow by the calendar. +So its history is the commits themselves. Every commit touching `model/` is normalized, versioned +by commit date (`2026-09-01`) with the short SHA kept as the tag, and labelled unreleased +everywhere it appears. Two rules keep that proportional to real change: + +- A commit is kept only when the **differ** finds something in it. Most do not — a Weaver bump, a + link pin, a reflowed brief — and gating on the normalized bytes instead would be stricter than + the diff and publish release pages listing no changes at all. +- Upstream merges several model changes on a busy day, so the second one that day takes + `2026-05-05.2`. The suffix sorts after the bare date, and without it the second commit would + overwrite the first snapshot. + +The walk floors at `ebe3d1f`, the commit that made this a repository of its own. One commit earlier +the filtered history still carries the 52 `aws.*` attributes the split dropped, so crossing that +boundary would report 52 removals the project never made. Everything older is already covered by +the tagged semantic-conventions snapshots, which carried `gen_ai.*` until v1.44.0 deprecated it in +place. + +Because the registry is `development` throughout, nothing in it can rank `breaking` — see +[Severity](#severity). Its editorial commits are also kept off the front page and the RSS feed: a +reworded brief on an untagged branch is not news, and forty of them in a row would bury every +tagged release. The consequence worth knowing: ~59 attributes exist in **both** registries — deprecated "Moved to..." stubs in semantic-conventions, live definitions in GenAI. Anything answering "is this @@ -143,9 +163,9 @@ matching asset (`/mcp`, 404s). Asset paths are served on `www` too, with every p ## Data -Snapshots start at semconv v1.30.0, specification v1.42.0 and OTLP v1.4.0. Earlier releases used -schemas and layouts different enough that diffing across them would report changes the projects -never made. +Snapshots start at semconv v1.30.0, specification v1.42.0, OTLP v1.4.0 and GenAI `ebe3d1f` +(2026-05-05). Earlier releases used schemas and layouts different enough that diffing across them +would report changes the projects never made. ## Licence diff --git a/bun.lock b/bun.lock index 4687533..0c420d7 100644 --- a/bun.lock +++ b/bun.lock @@ -15,6 +15,7 @@ "yaml": "^2.8.1", }, "devDependencies": { + "@astrojs/check": "^0.9.10", "@cloudflare/workers-types": "^5.20260903.1", "@types/bun": "^1.3.11", "typescript": "^5.9.3", @@ -23,6 +24,10 @@ }, }, "packages": { + "@astrojs/check": ["@astrojs/check@0.9.10", "", { "dependencies": { "@astrojs/language-server": "^2.16.7", "chokidar": "^4.0.3", "kleur": "^4.1.5", "yargs": "^18.0.0" }, "peerDependencies": { "typescript": "^5.0.0 || ^6.0.0" }, "bin": { "astro-check": "./bin/astro-check.js" } }, "sha512-zgx/UQMozdjOa3bOxjgeCFdtpE3c9rRX6xHwa+2QXvy8z8Akifu2AtubHyv/zzC2znO8dl8fFWL4K+Ba9kS8HQ=="], + + "@astrojs/compiler": ["@astrojs/compiler@2.13.1", "", {}, "sha512-f3FN83d2G/v32ipNClRKgYv30onQlMZX1vCeZMjPsMMPl1mDpmbl0+N5BYo4S/ofzqJyS5hvwacEo0CCVDn/Qg=="], + "@astrojs/compiler-binding": ["@astrojs/compiler-binding@0.4.0", "", { "optionalDependencies": { "@astrojs/compiler-binding-darwin-arm64": "0.4.0", "@astrojs/compiler-binding-darwin-x64": "0.4.0", "@astrojs/compiler-binding-linux-arm64-gnu": "0.4.0", "@astrojs/compiler-binding-linux-arm64-musl": "0.4.0", "@astrojs/compiler-binding-linux-x64-gnu": "0.4.0", "@astrojs/compiler-binding-linux-x64-musl": "0.4.0", "@astrojs/compiler-binding-wasm32-wasi": "0.4.0", "@astrojs/compiler-binding-win32-arm64-msvc": "0.4.0", "@astrojs/compiler-binding-win32-x64-msvc": "0.4.0" } }, "sha512-x2RjDUuWfwLNtc3mjAdSRInwqh/rqbLar9cm/5FOMbHvmYZB7yfKewzSclAxWjIZsypJDXv1lhaP2WG+P8TK3g=="], "@astrojs/compiler-binding-darwin-arm64": ["@astrojs/compiler-binding-darwin-arm64@0.4.0", "", { "os": "darwin", "cpu": "arm64" }, "sha512-ZVUwHundaQyFNjE6uoa0usaC0WOCitDCLS/4mdb4rOiJXwVUuKJBMxI5WMzXLWmamsXtK/Z//ifLXvV5Yeh4Hw=="], @@ -47,6 +52,8 @@ "@astrojs/internal-helpers": ["@astrojs/internal-helpers@0.11.0", "", { "dependencies": { "@types/hast": "^3.0.4", "@types/mdast": "^4.0.4", "js-yaml": "^4.3.0", "picomatch": "^4.0.4", "retext-smartypants": "^6.2.0", "shiki": "^4.0.2", "smol-toml": "^1.6.0", "unified": "^11.0.5" } }, "sha512-3rzxJ+xbo0+8YyqOzLziIN32wmsHdCjEVz2sGOpRxJ+Ben/KiLph4ItxBy1abEL+E8fkRzqjg0rfXmaHJGw9JA=="], + "@astrojs/language-server": ["@astrojs/language-server@2.16.16", "", { "dependencies": { "@astrojs/compiler": "^2.13.1", "@astrojs/yaml2ts": "^0.2.4", "@jridgewell/sourcemap-codec": "^1.5.5", "@volar/kit": "~2.4.28", "@volar/language-core": "~2.4.28", "@volar/language-server": "~2.4.28", "@volar/language-service": "~2.4.28", "muggle-string": "^0.4.1", "tinyglobby": "^0.2.16", "volar-service-css": "0.0.71", "volar-service-emmet": "0.0.71", "volar-service-html": "0.0.71", "volar-service-prettier": "0.0.71", "volar-service-typescript": "0.0.71", "volar-service-typescript-twoslash-queries": "0.0.71", "volar-service-yaml": "0.0.71", "vscode-html-languageservice": "^5.6.2", "vscode-uri": "^3.1.0" }, "peerDependencies": { "prettier": "^3.0.0", "prettier-plugin-astro": ">=0.11.0" }, "optionalPeers": ["prettier", "prettier-plugin-astro"], "bin": { "astro-ls": "./bin/nodeServer.js" } }, "sha512-KuS17AOOqH/M5mHXPmKvtp8L+NNteARC7Xjf395+9R9dtJOBndqdStwU4V+OKzYZpgZ+hliV13knzx/oMtFl7Q=="], + "@astrojs/markdown-satteri": ["@astrojs/markdown-satteri@0.4.0", "", { "dependencies": { "@astrojs/internal-helpers": "0.11.0", "@astrojs/prism": "4.0.2", "github-slugger": "^2.0.0", "satteri": "^0.10.3" } }, "sha512-wykOOW9KsUVcZweOpY/CeXpdKcCKZy6fQbdcteWFuI75+sQCiqxYM7VKsGa5b+aGl3cYQscFY37rsbbyal5MRw=="], "@astrojs/prism": ["@astrojs/prism@4.0.2", "", { "dependencies": { "prismjs": "^1.30.0" } }, "sha512-KTivpmnz6lDsC6o9H4+DNm2SrE/GHzw8cNAvEJwAvUT+eoaEnn/4NtbDNfRRaxaJHdp15gf+tfHAWiXR4wB3BA=="], @@ -55,6 +62,8 @@ "@astrojs/telemetry": ["@astrojs/telemetry@3.3.3", "", { "dependencies": { "ci-info": "^4.4.0", "dset": "^3.1.4", "is-docker": "^4.0.0", "package-manager-detector": "^1.6.0" } }, "sha512-C1TLn5sPJr0x4vk56piHWKbnqlEB8BKyte5Y45V02U+D7BGO5eMqZDH5aPjnkXQWJggvmsTXxH03QMZ9NgWLzQ=="], + "@astrojs/yaml2ts": ["@astrojs/yaml2ts@0.2.4", "", { "dependencies": { "yaml": "^2.8.3" } }, "sha512-8oddpOae35pJsXPQXhTkM0ypfKPskVsh2bCxRtbf7e+/Epw2nReakFYpLKjZMEr75CsoF203PMnCocpfz0s69A=="], + "@babel/helper-string-parser": ["@babel/helper-string-parser@7.29.7", "", {}, "sha512-Pb5ijPrZ89GDH8223L4UP8i6QApWxs04RbPQJTeWDV0/keR2E36MeKnyr6LYmUUvqRRI+Iv87SuF1W6ErINzYw=="], "@babel/helper-validator-identifier": ["@babel/helper-validator-identifier@7.29.7", "", {}, "sha512-qehxGkRj55h/ff8EMaJ+cYhyaKlHIxqYDn682wQD7RNp9UujOQsHog2uS0r2vzr4pW+sXf90NeeayjcNaX3fFg=="], @@ -121,6 +130,20 @@ "@effect/workflow": ["@effect/workflow@0.19.1", "", { "peerDependencies": { "@effect/experimental": "^0.61.1", "@effect/platform": "^0.97.1", "@effect/rpc": "^0.76.2", "effect": "^3.22.1" } }, "sha512-irU6ddHdIxYOhv0cJiJTk2AUxRmPYjRJ5JdB5UCvpJC4vLCyR2XyKspiCNDiEX1aSGPhVWEXhVMWXR1cErMS3A=="], + "@emmetio/abbreviation": ["@emmetio/abbreviation@2.3.3", "", { "dependencies": { "@emmetio/scanner": "^1.0.4" } }, "sha512-mgv58UrU3rh4YgbE/TzgLQwJ3pFsHHhCLqY20aJq+9comytTXUDNGG/SMtSeMJdkpxgXSXunBGLD8Boka3JyVA=="], + + "@emmetio/css-abbreviation": ["@emmetio/css-abbreviation@2.1.8", "", { "dependencies": { "@emmetio/scanner": "^1.0.4" } }, "sha512-s9yjhJ6saOO/uk1V74eifykk2CBYi01STTK3WlXWGOepyKa23ymJ053+DNQjpFcy1ingpaO7AxCcwLvHFY9tuw=="], + + "@emmetio/css-parser": ["@emmetio/css-parser@0.4.1", "", { "dependencies": { "@emmetio/stream-reader": "^2.2.0", "@emmetio/stream-reader-utils": "^0.1.0" } }, "sha512-2bC6m0MV/voF4CTZiAbG5MWKbq5EBmDPKu9Sb7s7nVcEzNQlrZP6mFFFlIaISM8X6514H9shWMme1fCm8cWAfQ=="], + + "@emmetio/html-matcher": ["@emmetio/html-matcher@1.3.0", "", { "dependencies": { "@emmetio/scanner": "^1.0.0" } }, "sha512-NTbsvppE5eVyBMuyGfVu2CRrLvo7J4YHb6t9sBFLyY03WYhXET37qA4zOYUjBWFCRHO7pS1B9khERtY0f5JXPQ=="], + + "@emmetio/scanner": ["@emmetio/scanner@1.0.4", "", {}, "sha512-IqRuJtQff7YHHBk4G8YZ45uB9BaAGcwQeVzgj/zj8/UdOhtQpEIupUhSk8dys6spFIWVZVeK20CzGEnqR5SbqA=="], + + "@emmetio/stream-reader": ["@emmetio/stream-reader@2.2.0", "", {}, "sha512-fXVXEyFA5Yv3M3n8sUGT7+fvecGrZP4k6FnWWMSZVQf69kAq0LLpaBQLGcPR30m3zMmKYhECP4k/ZkzvhEW5kw=="], + + "@emmetio/stream-reader-utils": ["@emmetio/stream-reader-utils@0.1.0", "", {}, "sha512-ZsZ2I9Vzso3Ho/pjZFsmmZ++FWeEd/txqybHTm4OgaZzdS8V9V/YYWQwg5TC38Z7uLWUV1vavpLLbjJtKubR1A=="], + "@emnapi/core": ["@emnapi/core@1.11.1", "", { "dependencies": { "@emnapi/wasi-threads": "1.2.2", "tslib": "^2.4.0" } }, "sha512-RSvbQmHzdKzNsLYa/wHrbc3KN4sYLKAdPZxqiM2HATqv/SBk2/ENSHpvXGaLOMcsAyz0poEGqkmmKYG3OWiJEQ=="], "@emnapi/runtime": ["@emnapi/runtime@1.11.3", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-Xz4Tpyki7XyrpbUK1jR1AhdAdaXyhhY4lZ3neLodmhpuWfy2PAQN5B46sAiU4liOXGLkHypn/qU+jvfWSCYYLA=="], @@ -399,8 +422,34 @@ "@ungap/structured-clone": ["@ungap/structured-clone@1.4.0", "", {}, "sha512-1mEZtMKPM09vDmQt5y7YvmN2+DFTP7Tg0EWXdic8/C6VRnpb33e4ghisCIE3WZjsE2N8mf+QV1Zqh7ZFYLWInQ=="], + "@volar/kit": ["@volar/kit@2.4.28", "", { "dependencies": { "@volar/language-service": "2.4.28", "@volar/typescript": "2.4.28", "typesafe-path": "^0.2.2", "vscode-languageserver-textdocument": "^1.0.11", "vscode-uri": "^3.0.8" }, "peerDependencies": { "typescript": "*" } }, "sha512-cKX4vK9dtZvDRaAzeoUdaAJEew6IdxHNCRrdp5Kvcl6zZOqb6jTOfk3kXkIkG3T7oTFXguEMt5+9ptyqYR84Pg=="], + + "@volar/language-core": ["@volar/language-core@2.4.28", "", { "dependencies": { "@volar/source-map": "2.4.28" } }, "sha512-w4qhIJ8ZSitgLAkVay6AbcnC7gP3glYM3fYwKV3srj8m494E3xtrCv6E+bWviiK/8hs6e6t1ij1s2Endql7vzQ=="], + + "@volar/language-server": ["@volar/language-server@2.4.28", "", { "dependencies": { "@volar/language-core": "2.4.28", "@volar/language-service": "2.4.28", "@volar/typescript": "2.4.28", "path-browserify": "^1.0.1", "request-light": "^0.7.0", "vscode-languageserver": "^9.0.1", "vscode-languageserver-protocol": "^3.17.5", "vscode-languageserver-textdocument": "^1.0.11", "vscode-uri": "^3.0.8" } }, "sha512-NqcLnE5gERKuS4PUFwlhMxf6vqYo7hXtbMFbViXcbVkbZ905AIVWhnSo0ZNBC2V127H1/2zP7RvVOVnyITFfBw=="], + + "@volar/language-service": ["@volar/language-service@2.4.28", "", { "dependencies": { "@volar/language-core": "2.4.28", "vscode-languageserver-protocol": "^3.17.5", "vscode-languageserver-textdocument": "^1.0.11", "vscode-uri": "^3.0.8" } }, "sha512-Rh/wYCZJrI5vCwMk9xyw/Z+MsWxlJY1rmMZPsxUoJKfzIRjS/NF1NmnuEcrMbEVGja00aVpCsInJfixQTMdvLw=="], + + "@volar/source-map": ["@volar/source-map@2.4.28", "", {}, "sha512-yX2BDBqJkRXfKw8my8VarTyjv48QwxdJtvRgUpNE5erCsgEUdI2DsLbpa+rOQVAJYshY99szEcRDmyHbF10ggQ=="], + + "@volar/typescript": ["@volar/typescript@2.4.28", "", { "dependencies": { "@volar/language-core": "2.4.28", "path-browserify": "^1.0.1", "vscode-uri": "^3.0.8" } }, "sha512-Ja6yvWrbis2QtN4ClAKreeUZPVYMARDYZl9LMEv1iQ1QdepB6wn0jTRxA9MftYmYa4DQ4k/DaSZpFPUfxl8giw=="], + + "@vscode/emmet-helper": ["@vscode/emmet-helper@2.11.0", "", { "dependencies": { "emmet": "^2.4.3", "jsonc-parser": "^2.3.0", "vscode-languageserver-textdocument": "^1.0.1", "vscode-languageserver-types": "^3.15.1", "vscode-uri": "^3.0.8" } }, "sha512-QLxjQR3imPZPQltfbWRnHU6JecWTF1QSWhx3GAKQpslx7y3Dp6sIIXhKjiUJ/BR9FX8PVthjr9PD6pNwOJfAzw=="], + + "@vscode/l10n": ["@vscode/l10n@0.0.18", "", {}, "sha512-KYSIHVmslkaCDyw013pphY+d7x1qV8IZupYfeIfzNA+nsaWHbn5uPuQRvdRFsa9zFzGeudPuoGoZ1Op4jrJXIQ=="], + + "ajv": ["ajv@8.20.0", "", { "dependencies": { "fast-deep-equal": "^3.1.3", "fast-uri": "^3.0.1", "json-schema-traverse": "^1.0.0", "require-from-string": "^2.0.2" } }, "sha512-Thbli+OlOj+iMPYFBVBfJ3OmCAnaSyNn4M1vz9T6Gka5Jt9ba/HIR56joy65tY6kx/FCF5VXNB819Y7/GUrBGA=="], + + "ajv-draft-04": ["ajv-draft-04@1.0.0", "", { "peerDependencies": { "ajv": "^8.5.0" }, "optionalPeers": ["ajv"] }, "sha512-mv00Te6nmYbRp5DCwclxtt7yV/joXJPGS7nM+97GdxvuttCOfgI3K4U25zboyeX0O+myI8ERluxQe5wljMmVIw=="], + + "ajv-i18n": ["ajv-i18n@4.2.0", "", { "peerDependencies": { "ajv": "^8.0.0-beta.0" } }, "sha512-v/ei2UkCEeuKNXh8RToiFsUclmU+G57LO1Oo22OagNMENIw+Yb8eMwvHu7Vn9fmkjJyv6XclhJ8TbuigSglPkg=="], + "am-i-vibing": ["am-i-vibing@0.4.0", "", { "dependencies": { "process-ancestry": "^0.1.0" }, "bin": { "am-i-vibing": "dist/cli.mjs" } }, "sha512-MxT4XZL7pzLHpuvhDKdMaQHMGGkJDLluKBLsbstn+8wv9sWcFT6h+0ve9qkml95amVTZtZV83gQe2hY+ojgHLg=="], + "ansi-regex": ["ansi-regex@6.3.0", "", {}, "sha512-WpDfL7NO6j7tH88IDBNVdUJxDh9nmCteAVW9dsep846XdwF4naCBK+/tGLX3KJgcpgMRXCFlTM2hKGoK9FsdrQ=="], + + "ansi-styles": ["ansi-styles@6.2.3", "", {}, "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg=="], + "anymatch": ["anymatch@3.1.3", "", { "dependencies": { "normalize-path": "^3.0.0", "picomatch": "^2.0.4" } }, "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw=="], "arg": ["arg@5.0.2", "", {}, "sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg=="], @@ -427,10 +476,12 @@ "character-entities-legacy": ["character-entities-legacy@3.0.0", "", {}, "sha512-RpPp0asT/6ufRm//AJVwpViZbGM/MkjQFxJccQRHmISF/22NBtsHqAWmL+/pmkPWoIUJdWyeVleTl1wydHATVQ=="], - "chokidar": ["chokidar@5.0.0", "", { "dependencies": { "readdirp": "^5.0.0" } }, "sha512-TQMmc3w+5AxjpL8iIiwebF73dRDF4fBIieAqGn9RGCWaEVwQ6Fb2cGe31Yns0RRIzii5goJ1Y7xbMwo1TxMplw=="], + "chokidar": ["chokidar@4.0.3", "", { "dependencies": { "readdirp": "^4.0.1" } }, "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA=="], "ci-info": ["ci-info@4.4.0", "", {}, "sha512-77PSwercCZU2Fc4sX94eF8k8Pxte6JAwL4/ICZLFjJLqegs7kCuAsqqj/70NQF6TvDpgFjkubQB2FW2ZZddvQg=="], + "cliui": ["cliui@9.0.1", "", { "dependencies": { "string-width": "^7.2.0", "strip-ansi": "^7.1.0", "wrap-ansi": "^9.0.0" } }, "sha512-k7ndgKhwoQveBL+/1tqGJYNz097I7WOvwbmmU2AR5+magtbjPWQTS1C5vzGkBC8Ym8UWRzfKUzUUqFLypY4Q+w=="], + "clsx": ["clsx@2.1.1", "", {}, "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA=="], "comma-separated-tokens": ["comma-separated-tokens@2.0.3", "", {}, "sha512-Fu4hJdvzeylCfQPp9SGWidpzrMs7tTrlu6Vb8XGaRGck8QSNZJJp538Wrb60Lax4fPwR64ViY468OIUTbRlGZg=="], @@ -479,6 +530,10 @@ "effect": ["effect@3.22.1", "", { "dependencies": { "@standard-schema/spec": "^1.0.0", "fast-check": "^3.23.1" } }, "sha512-TNoXushmPOBAjJlthF5d2QwnX2xBPEtcNJr5XKNKbRLbDvBcOYkXlYDfvGfSA0zriwLFuCll5MDtNMAdZL17PQ=="], + "emmet": ["emmet@2.4.11", "", { "dependencies": { "@emmetio/abbreviation": "^2.3.3", "@emmetio/css-abbreviation": "^2.1.8" } }, "sha512-23QPJB3moh/U9sT4rQzGgeyyGIrcM+GH5uVYg2C6wZIxAIJq7Ng3QLT79tl8FUwDXhyq9SusfknOrofAKqvgyQ=="], + + "emoji-regex": ["emoji-regex@10.6.0", "", {}, "sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A=="], + "enhanced-resolve": ["enhanced-resolve@5.24.5", "", { "dependencies": { "graceful-fs": "^4.2.4", "tapable": "^2.3.3" } }, "sha512-L1l8TNvomm6UVW5B253AGxQagSQr+vGwhMlrrfRS2qmhx46AMpMVJKQYLvWYbysTMY8VoicOvzHzoHMbyzB+4A=="], "entities": ["entities@4.5.0", "", {}, "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw=="], @@ -489,16 +544,22 @@ "esbuild": ["esbuild@0.28.1", "", { "optionalDependencies": { "@esbuild/aix-ppc64": "0.28.1", "@esbuild/android-arm": "0.28.1", "@esbuild/android-arm64": "0.28.1", "@esbuild/android-x64": "0.28.1", "@esbuild/darwin-arm64": "0.28.1", "@esbuild/darwin-x64": "0.28.1", "@esbuild/freebsd-arm64": "0.28.1", "@esbuild/freebsd-x64": "0.28.1", "@esbuild/linux-arm": "0.28.1", "@esbuild/linux-arm64": "0.28.1", "@esbuild/linux-ia32": "0.28.1", "@esbuild/linux-loong64": "0.28.1", "@esbuild/linux-mips64el": "0.28.1", "@esbuild/linux-ppc64": "0.28.1", "@esbuild/linux-riscv64": "0.28.1", "@esbuild/linux-s390x": "0.28.1", "@esbuild/linux-x64": "0.28.1", "@esbuild/netbsd-arm64": "0.28.1", "@esbuild/netbsd-x64": "0.28.1", "@esbuild/openbsd-arm64": "0.28.1", "@esbuild/openbsd-x64": "0.28.1", "@esbuild/openharmony-arm64": "0.28.1", "@esbuild/sunos-x64": "0.28.1", "@esbuild/win32-arm64": "0.28.1", "@esbuild/win32-ia32": "0.28.1", "@esbuild/win32-x64": "0.28.1" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-HrJrvZv5ayxBzPfwphOoNzkzOIIlifzk0KJrGK2c8R4+LKpMtpYLQeUdjnwjWv/LZlkH2laZk+4w78pi99D4Vw=="], + "escalade": ["escalade@3.2.0", "", {}, "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA=="], + "eventemitter3": ["eventemitter3@5.0.4", "", {}, "sha512-mlsTRyGaPBjPedk6Bvw+aqbsXDtoAyAzm5MO7JgU+yVRyMQ5O8bD4Kcci7BS85f93veegeCPkL8R4GLClnjLFw=="], "extend": ["extend@3.0.2", "", {}, "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g=="], "fast-check": ["fast-check@3.23.2", "", { "dependencies": { "pure-rand": "^6.1.0" } }, "sha512-h5+1OzzfCC3Ef7VbtKdcv7zsstUQwUDlYpUTvjeUsJAssPgLn7QzbboPtL5ro04Mq0rPOsMzl7q5hIbRs2wD1A=="], + "fast-deep-equal": ["fast-deep-equal@3.1.3", "", {}, "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q=="], + "fast-string-truncated-width": ["fast-string-truncated-width@3.0.3", "", {}, "sha512-0jjjIEL6+0jag3l2XWWizO64/aZVtpiGE3t0Zgqxv0DPuxiMjvB3M24fCyhZUO4KomJQPj3LTSUnDP3GpdwC0g=="], "fast-string-width": ["fast-string-width@3.0.2", "", { "dependencies": { "fast-string-truncated-width": "^3.0.2" } }, "sha512-gX8LrtNEI5hq8DVUfRQMbr5lpaS4nMIWV+7XEbXk2b8kiQIizgnlr12B4dA3ZEx3308ze0O4Q1R+cHts8kyUJg=="], + "fast-uri": ["fast-uri@3.1.7", "", {}, "sha512-dOvZVzjdZdz7phd9v6jCbwxrBW3fK6n8Rc0CtdmM4bumzMnxywBYhuph6J819RRw/ku+rLbelwfMunktuzVVHg=="], + "fast-wrap-ansi": ["fast-wrap-ansi@0.2.2", "", { "dependencies": { "fast-string-width": "^3.0.2" } }, "sha512-7F2Fl+TjRSenLqlU3UjSH0iyqopqoZIu7eZVpEirP2g1GtWa2G/ecEmBdgz31+Mxr+ELclgg6sokpSFIQiZ02Q=="], "fdir": ["fdir@6.5.0", "", { "peerDependencies": { "picomatch": "^3 || ^4" }, "optionalPeers": ["picomatch"] }, "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg=="], @@ -515,6 +576,10 @@ "fsevents": ["fsevents@2.3.3", "", { "os": "darwin" }, "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw=="], + "get-caller-file": ["get-caller-file@2.0.5", "", {}, "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg=="], + + "get-east-asian-width": ["get-east-asian-width@1.6.0", "", {}, "sha512-QRbvDIbx6YklUe6RxeTeleMR0yv3cYH6PsPZHcnVn7xv7zO1BHN8r0XETu8n6Ye3Q+ahtSarc3WgtNWmehIBfA=="], + "get-tsconfig": ["get-tsconfig@5.0.0-beta.4", "", { "dependencies": { "resolve-pkg-maps": "^1.0.0" } }, "sha512-7nF7C9fIPFEMHgEMEfgIlO9wDdZ8CyHw27rWciFZfHvHDReIiPhsYuzPRXsfvBCqFy1l8RRyyWV7QLM+ZhUJsQ=="], "github-slugger": ["github-slugger@2.0.0", "", {}, "sha512-IaOQ9puYtjrkq7Y0Ygl9KDZnrf/aiUJYUpVf89y8kyaxbRG7Y1SrX/jaumrv81vc61+kiMempujsM3Yw7w5qcw=="], @@ -547,6 +612,8 @@ "js-yaml": ["js-yaml@4.3.2", "", { "dependencies": { "argparse": "^2.0.1" }, "bin": { "js-yaml": "bin/js-yaml.js" } }, "sha512-SFNOvSJ+Dgf/9An904Yx+CgSlIPCkIpao4qo51lpee25TIRejdH3rhR4EZMGoNx3/TP3O+wzWuiTFl4sqbltzA=="], + "json-schema-traverse": ["json-schema-traverse@1.0.0", "", {}, "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug=="], + "jsonc-parser": ["jsonc-parser@3.3.1", "", {}, "sha512-HUgH65KyejrUFPvHFPbqOY0rsFip3Bo5wb4ngvdi1EpCYWUQDC5V+Y7mZws+DLkr4M//zQJoanu1SP+87Dv1oQ=="], "kleur": ["kleur@4.1.5", "", {}, "sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ=="], @@ -605,6 +672,8 @@ "msgpackr-extract": ["msgpackr-extract@3.0.4", "", { "dependencies": { "node-gyp-build-optional-packages": "5.2.2" }, "optionalDependencies": { "@msgpackr-extract/msgpackr-extract-darwin-arm64": "3.0.4", "@msgpackr-extract/msgpackr-extract-darwin-x64": "3.0.4", "@msgpackr-extract/msgpackr-extract-linux-arm": "3.0.4", "@msgpackr-extract/msgpackr-extract-linux-arm64": "3.0.4", "@msgpackr-extract/msgpackr-extract-linux-x64": "3.0.4", "@msgpackr-extract/msgpackr-extract-win32-x64": "3.0.4" }, "bin": { "download-msgpackr-prebuilds": "bin/download-prebuilds.js" } }, "sha512-4kmO/MdyUIkLIvTPr8VHLil4AtoKIoniWPIEk5+CDy0xnWC84azhSFmuJ7PxZdsYtiP5kEeQsORAVIeMgxT+Hw=="], + "muggle-string": ["muggle-string@0.4.1", "", {}, "sha512-VNTrAak/KhO2i8dqqnqnAHOa3cYBwXEZe9h+D5h/1ZqFSTEFHdM65lR7RoIqq3tBBYavsOXV84NoHXZ0AkPyqQ=="], + "multipasta": ["multipasta@0.2.8", "", {}, "sha512-ZPWuMKyv0cSO29f7hozp+k6+crZbQijV8ipMvxNxRf2SwtYGTX1ZX89Kd20VV4H9Znonx+EQn+iy1wGQsJ+b+Q=="], "nanoid": ["nanoid@3.3.18", "", { "bin": { "nanoid": "bin/nanoid.cjs" } }, "sha512-DTg4MJbGMWkfi6VZFdNt2/caMbQy4Ou+Op/hJQvGEWcnVfoA1QA+xzRKAzw9jD6+GVOOeYr/mIcuDSdug6F6+w=="], @@ -643,6 +712,8 @@ "package-manager-detector": ["package-manager-detector@1.8.0", "", {}, "sha512-yQA4H19AmPEoMUeavPMDIe1higySl/gH/yaQrkT/s07Qp+7pp2hYz30N3z2l5BkjVkF9Ow6o0wjJamm2y7Sn0A=="], + "path-browserify": ["path-browserify@1.0.1", "", {}, "sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g=="], + "path-to-regexp": ["path-to-regexp@6.3.0", "", {}, "sha512-Yhpw4T9C6hPpgPeA28us07OJeqZ5EzQTkbfwuhsUg0c237RomFoETJgmp2sa3F/41gfLE6G5cqcYwznmeEeOlQ=="], "pathe": ["pathe@2.0.3", "", {}, "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w=="], @@ -655,6 +726,8 @@ "postcss": ["postcss@8.5.27", "", { "dependencies": { "nanoid": "^3.3.18", "picocolors": "^1.1.1", "source-map-js": "^1.2.1" } }, "sha512-79Iho8QeYyooJ8e9lCRyTVlyTAkS/kXBYKff6TMzS3kEWGQ8Ds5UEtXpGrSUDLUWok6QTvxeYy0GO8fopHnaSA=="], + "prettier": ["prettier@3.9.6", "", { "bin": { "prettier": "bin/prettier.cjs" } }, "sha512-OpN0zzVdiaiAhxpuuj5efpIS4sY9j7bY6uR5mnj5yPzGkdkjNKSJeUThPb60Jw29QuAZgA4o+/iB49kFiaBX6g=="], + "prismjs": ["prismjs@1.30.0", "", {}, "sha512-DEvV2ZF2r2/63V+tK8hQvrR2ZGn10srHbXviTlcv7Kpzw8jWiNTqbVgjO3IY8RxrrOUF8VPMQQFysYYYv0YZxw=="], "process-ancestry": ["process-ancestry@0.1.0", "", {}, "sha512-tGqJW/UnclpYASFcM6Xh8D8l/BMtaQ9+CSG0vlJSJTcdMM4lDRv4c6H0Pdcsfted+bVczdYSfk2fdukg2gQkZg=="], @@ -665,7 +738,7 @@ "radix3": ["radix3@1.1.2", "", {}, "sha512-b484I/7b8rDEdSDKckSSBA8knMpcdsXudlE/LNL639wFoHKwLbEkQFZHWEYwDC0wa0FKUcCY+GAF73Z7wxNVFA=="], - "readdirp": ["readdirp@5.1.1", "", {}, "sha512-Kko+Y5XQ6fM+Ce3dq3m9YGxnacYZYl9cA1wZjaF3Vbry2L3i1qVg8+CAgNPsXRArPMUMCaOR7oa9Nqntc43JKA=="], + "readdirp": ["readdirp@4.1.2", "", {}, "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg=="], "regex": ["regex@6.1.0", "", { "dependencies": { "regex-utilities": "^2.3.0" } }, "sha512-6VwtthbV4o/7+OaAF9I5L5V3llLEsoPyq9P1JVXkedTP33c7MfCG0/5NOPcSJn0TzXcG9YUrR0gQSWioew3LDg=="], @@ -673,6 +746,10 @@ "regex-utilities": ["regex-utilities@2.3.0", "", {}, "sha512-8VhliFJAWRaUiVvREIiW2NXXTmHs4vMNnSzuJVhscgmGav3g9VDxLrQndI3dZZVVdp0ZO/5v0xmX516/7M9cng=="], + "request-light": ["request-light@0.7.0", "", {}, "sha512-lMbBMrDoxgsyO+yB3sDcrDuX85yYt7sS8BfQd11jtbW/z5ZWgLZRcEGLsLoYw7I0WSUGQBs8CC8ScIxkTX1+6Q=="], + + "require-from-string": ["require-from-string@2.0.2", "", {}, "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw=="], + "resolve-pkg-maps": ["resolve-pkg-maps@1.0.0", "", {}, "sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw=="], "retext-smartypants": ["retext-smartypants@6.2.0", "", { "dependencies": { "@types/nlcst": "^2.0.0", "nlcst-to-string": "^4.0.0", "unist-util-visit": "^5.0.0" } }, "sha512-kk0jOU7+zGv//kfjXEBjdIryL1Acl4i9XNkHxtM7Tm5lFiCog576fjNC9hjoR7LTKQ0DsPWy09JummSsH1uqfQ=="], @@ -699,8 +776,12 @@ "space-separated-tokens": ["space-separated-tokens@2.0.2", "", {}, "sha512-PEGlAwrG8yXGXRjW32fGbg66JAlOAwbObuqVoJpv/mRgoWDQfgH1wDPvtzWyUSNAXBGSk8h755YDbbcEy3SH2Q=="], + "string-width": ["string-width@8.2.2", "", { "dependencies": { "get-east-asian-width": "^1.5.0", "strip-ansi": "^7.1.2" } }, "sha512-GaPUh5gfdrYzqeVNZvUfT23vYYxXzKYidUcnMtJg/3rxRV63EFZy3k6xfKlmfeJD0176lnUV/Usr3XcwSvFzpg=="], + "stringify-entities": ["stringify-entities@4.0.4", "", { "dependencies": { "character-entities-html4": "^2.0.0", "character-entities-legacy": "^3.0.0" } }, "sha512-IwfBptatlO+QCJUo19AqvrPNqlVMpW9YEL2LIVY+Rpv2qsjCGxaDLNRgeGsQWJhfItebuJhsGSLjaBbNSQ+ieg=="], + "strip-ansi": ["strip-ansi@7.2.0", "", { "dependencies": { "ansi-regex": "^6.2.2" } }, "sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w=="], + "supports-color": ["supports-color@10.2.2", "", {}, "sha512-SS+jx45GF1QjgEXQx4NJZV9ImqmO2NPz5FNsIHrsDjh2YsHnawpan7SNQ1o8NuhrbHZy9AZhIoCUiCeaW/C80g=="], "svgo": ["svgo@4.1.0", "", { "dependencies": { "commander": "^11.1.0", "css-select": "^6.0.0", "css-tree": "^3.0.1", "css-what": "^7.0.0", "csso": "^5.0.5", "picocolors": "^1.1.1", "sax": "1.6.1" }, "bin": { "svgo": "bin/svgo.js" } }, "sha512-bkxnTg1kSU0guhIBmibA6UUhrQmPVA1XsQLN+ylCd+UWzbnLkySOcXpyk1mrl05f+pcaCx2eHb+sp6BgMZWX+Q=="], @@ -723,8 +804,12 @@ "tslib": ["tslib@2.8.1", "", {}, "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="], + "typesafe-path": ["typesafe-path@0.2.2", "", {}, "sha512-OJabfkAg1WLZSqJAJ0Z6Sdt3utnbzr/jh+NAHoyWHJe8CMSy79Gm085094M9nvTPy22KzTVn5Zq5mbapCI/hPA=="], + "typescript": ["typescript@5.9.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw=="], + "typescript-auto-import-cache": ["typescript-auto-import-cache@0.3.6", "", { "dependencies": { "semver": "^7.3.8" } }, "sha512-RpuHXrknHdVdK7wv/8ug3Fr0WNsNi5l5aB8MYYuXhq2UH5lnEB1htJ1smhtD5VeCsGr2p8mUDtd83LCQDFVgjQ=="], + "ufo": ["ufo@1.6.4", "", {}, "sha512-JFNbkD1Svwe0KvGi8GOeLcP4kAWQ609twvCdcHxq1oSL8svv39ZuSvajcD8B+5D0eL4+s1Is2D/O6KN3qcTeRA=="], "ultrahtml": ["ultrahtml@1.7.0", "", {}, "sha512-2xRd0VHoAQE4M+vF/DvFFB7pUV0ZxTW1TLi7lHQWnF/Sb5TPeEUV/l+hxcNnGO00ZXGnR0voCMmYRKQf+rvJ2g=="], @@ -763,16 +848,58 @@ "vitefu": ["vitefu@1.1.3", "", { "peerDependencies": { "vite": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0" }, "optionalPeers": ["vite"] }, "sha512-ub4okH7Z5KLjb6hDyjqrGXqWtWvoYdU3IGm/NorpgHncKoLTCfRIbvlhBm7r0YstIaQRYlp4yEbFqDcKSzXSSg=="], + "volar-service-css": ["volar-service-css@0.0.71", "", { "dependencies": { "vscode-css-languageservice": "^6.3.0", "vscode-languageserver-textdocument": "^1.0.11", "vscode-uri": "^3.0.8" }, "peerDependencies": { "@volar/language-service": "~2.4.0" }, "optionalPeers": ["@volar/language-service"] }, "sha512-wRRFt9BpjMKCazcgOh67MSjUjiWUCAh99DyYSDIOTuxaRjEtDC7PpB0k1Y1wbJIW/pVtMUSVbpPo3UGSm0Byxw=="], + + "volar-service-emmet": ["volar-service-emmet@0.0.71", "", { "dependencies": { "@emmetio/css-parser": "^0.4.1", "@emmetio/html-matcher": "^1.3.0", "@vscode/emmet-helper": "^2.9.3", "vscode-uri": "^3.0.8" }, "peerDependencies": { "@volar/language-service": "~2.4.0" }, "optionalPeers": ["@volar/language-service"] }, "sha512-zqjzt6bN95e3CUstBm0PBFAJnrfz0ZAARka87fart46/gNCLLuP3Vujy8V/J8HEziTFLnfkgIASLFYPUhonJcA=="], + + "volar-service-html": ["volar-service-html@0.0.71", "", { "dependencies": { "vscode-html-languageservice": "^5.3.0", "vscode-languageserver-textdocument": "^1.0.11", "vscode-uri": "^3.0.8" }, "peerDependencies": { "@volar/language-service": "~2.4.0" }, "optionalPeers": ["@volar/language-service"] }, "sha512-e8tHPhgQ7ooLfudAEIku+kgd9pWkq3SSz8RbnQDI1+Eb8wbenkLGHqoirLqz5ORLV6wIMr2Iv08RWBG5eOcgpw=="], + + "volar-service-prettier": ["volar-service-prettier@0.0.71", "", { "dependencies": { "vscode-uri": "^3.0.8" }, "peerDependencies": { "@volar/language-service": "~2.4.0", "prettier": "^2.2 || ^3.0" }, "optionalPeers": ["@volar/language-service", "prettier"] }, "sha512-Rz7JVH3qD108UCdmIEiZvOBNljMt2nLFdbN8AXcDfn7xD9F5I2aCIsDVqBbXw21PsnxG0b7MfwtNF+zPS/NKUg=="], + + "volar-service-typescript": ["volar-service-typescript@0.0.71", "", { "dependencies": { "path-browserify": "^1.0.1", "semver": "^7.6.2", "typescript-auto-import-cache": "^0.3.5", "vscode-languageserver-textdocument": "^1.0.11", "vscode-nls": "^5.2.0", "vscode-uri": "^3.0.8" }, "peerDependencies": { "@volar/language-service": "~2.4.0" }, "optionalPeers": ["@volar/language-service"] }, "sha512-yTtM/BVT6hoyEYnDtaCyAtNhdNeS/mhTTABlBOdw3NNiRBUin3IznFJpgfjer4c6RYopiPjjQjc9VFhxVl1mLw=="], + + "volar-service-typescript-twoslash-queries": ["volar-service-typescript-twoslash-queries@0.0.71", "", { "dependencies": { "vscode-uri": "^3.0.8" }, "peerDependencies": { "@volar/language-service": "~2.4.0" }, "optionalPeers": ["@volar/language-service"] }, "sha512-9K2k72s4n7rV9s4bX0MyjbX9iBribvKZbBJKuEmTCZfeWJXs6Yh7bGpY4eoc7UufAjvpheBqwyZCOIPBvxCv0A=="], + + "volar-service-yaml": ["volar-service-yaml@0.0.71", "", { "dependencies": { "vscode-uri": "^3.0.8", "yaml-language-server": "~1.23.0" }, "peerDependencies": { "@volar/language-service": "~2.4.0" }, "optionalPeers": ["@volar/language-service"] }, "sha512-qYGWGuVpUTnZGu5P/CR4KLK4aIR8RrcVnmfZ2eRcj9q/I8VZCoC5yy9FtEvfNvnDp4MU17yhdJcvpQPIqhJS2Q=="], + + "vscode-css-languageservice": ["vscode-css-languageservice@6.3.10", "", { "dependencies": { "@vscode/l10n": "^0.0.18", "vscode-languageserver-textdocument": "^1.0.12", "vscode-languageserver-types": "3.17.5", "vscode-uri": "^3.1.0" } }, "sha512-eq5N9Er3fC4vA9zd9EFhyBG90wtCCuXgRSpAndaOgXMh1Wgep5lBgRIeDgjZBW9pa+332yC9+49cZMW8jcL3MA=="], + + "vscode-html-languageservice": ["vscode-html-languageservice@5.6.2", "", { "dependencies": { "@vscode/l10n": "^0.0.18", "vscode-languageserver-textdocument": "^1.0.12", "vscode-languageserver-types": "^3.17.5", "vscode-uri": "^3.1.0" } }, "sha512-ulCrSnFnfQ16YzvwnYUgEbUEl/ZG7u2eV27YhvLObSHKkb8fw1Z9cgsnUwjTEeDIdJDoTDTDpxuhQwoenoLNMg=="], + + "vscode-json-languageservice": ["vscode-json-languageservice@4.1.8", "", { "dependencies": { "jsonc-parser": "^3.0.0", "vscode-languageserver-textdocument": "^1.0.1", "vscode-languageserver-types": "^3.16.0", "vscode-nls": "^5.0.0", "vscode-uri": "^3.0.2" } }, "sha512-0vSpg6Xd9hfV+eZAaYN63xVVMOTmJ4GgHxXnkLCh+9RsQBkWKIghzLhW2B9ebfG+LQQg8uLtsQ2aUKjTgE+QOg=="], + + "vscode-jsonrpc": ["vscode-jsonrpc@9.0.2", "", {}, "sha512-SbQSV9yRemARxeXw6LU5sS6Zq0e9/DgCCX5yelH263ZQWukbTk8EF8fjTrr1dziasf4GwlJbvTwFnTrnQFWZXQ=="], + + "vscode-languageserver": ["vscode-languageserver@9.0.1", "", { "dependencies": { "vscode-languageserver-protocol": "3.17.5" }, "bin": { "installServerIntoExtension": "bin/installServerIntoExtension" } }, "sha512-woByF3PDpkHFUreUa7Hos7+pUWdeWMXRd26+ZX2A8cFx6v/JPTtd4/uN0/jB6XQHYaOlHbio03NTHCqrgG5n7g=="], + + "vscode-languageserver-protocol": ["vscode-languageserver-protocol@3.18.3", "", { "dependencies": { "vscode-jsonrpc": "9.0.2", "vscode-languageserver-types": "3.18.3" } }, "sha512-DF49+WeV5py4zO5hhobp60jjsDSK0lAqA0OuKBLBvp423HPWQcCbhZz3JgyfIewsEz2f8U+X75xNIFHdiXZm2w=="], + + "vscode-languageserver-textdocument": ["vscode-languageserver-textdocument@1.0.14", "", {}, "sha512-EQyqJMi552E4ZTf46izQ4Fj6XquqxCySR3J5ZSD1SisMf6RfpeOWHxGBE8Gr6V0/3GHIGdAzDn8F8+1nTGCnoQ=="], + + "vscode-languageserver-types": ["vscode-languageserver-types@3.18.3", "", {}, "sha512-XIlzJ7Qp/jzSI1ds7/FwPAWrPeTZA7pAtlW4hdJ1J6xXWJL6dR9QYnDhJOdLzdKhUQ5Mm6mvUMw+3DcOQQasPw=="], + + "vscode-nls": ["vscode-nls@5.2.0", "", {}, "sha512-RAaHx7B14ZU04EU31pT+rKz2/zSl7xMsfIZuo8pd+KZO6PXtQmpevpq3vxvWNcrGbdmhM/rr5Uw5Mz+NBfhVng=="], + + "vscode-uri": ["vscode-uri@3.2.0", "", {}, "sha512-m2gXo3bn0G1kT9InzMf07fTbqMbGtyckj3bH5ktLO+1Ssv+yiATZ4dhwaQv9UZWxJh6E9IFGnQyjgWVDWVBDrg=="], + "workerd": ["workerd@1.20260831.1", "", { "optionalDependencies": { "@cloudflare/workerd-darwin-64": "1.20260831.1", "@cloudflare/workerd-darwin-arm64": "1.20260831.1", "@cloudflare/workerd-linux-64": "1.20260831.1", "@cloudflare/workerd-linux-arm64": "1.20260831.1", "@cloudflare/workerd-windows-64": "1.20260831.1" }, "bin": { "workerd": "bin/workerd" } }, "sha512-A2LwrkBel/FnKABPfeBAMiL6v70+rugnunqQRfWsWZjlhsTZoBScWUVunMy/xLCGLjWCQL2zp39AVR6aO0jurQ=="], "wrangler": ["wrangler@4.128.0", "", { "dependencies": { "@cloudflare/kv-asset-handler": "0.5.0", "@cloudflare/unenv-preset": "2.16.1", "blake3-wasm": "2.1.5", "esbuild": "0.28.1", "miniflare": "5.20260831.0-alpha", "path-to-regexp": "6.3.0", "unenv": "2.0.0-rc.24", "workerd": "1.20260831.1" }, "optionalDependencies": { "fsevents": "2.3.3" }, "peerDependencies": { "@cloudflare/workers-types": "^5.20260831.1" }, "optionalPeers": ["@cloudflare/workers-types"], "bin": { "wrangler": "bin/wrangler.js", "wrangler2": "bin/wrangler.js", "cf-wrangler": "bin/cf-wrangler.js" } }, "sha512-jNXy9e8/pbx8iqTzXPiuflnitKJZoAfEUSUUDLW87bwyeMvJ7kb3yQMSbxEcfNdfHqJW38KRcKaLljOYV4N/4w=="], + "wrap-ansi": ["wrap-ansi@9.0.2", "", { "dependencies": { "ansi-styles": "^6.2.1", "string-width": "^7.0.0", "strip-ansi": "^7.1.0" } }, "sha512-42AtmgqjV+X1VpdOfyTGOYRi0/zsoLqtXQckTmqTeybT+BDIbM/Guxo7x3pE2vtpr1ok6xRqM9OpBe+Jyoqyww=="], + "ws": ["ws@8.21.0", "", { "peerDependencies": { "bufferutil": "^4.0.1", "utf-8-validate": ">=5.0.2" }, "optionalPeers": ["bufferutil", "utf-8-validate"] }, "sha512-Vsp28b7DRcimFQvrqu2Wek3z1iYxDCWqHYB8Qsnk/S4RfaCQzPGPyBNuVjJV3cd6UiKtUtp6sNM77gWvzcCH+g=="], "xxhash-wasm": ["xxhash-wasm@1.1.0", "", {}, "sha512-147y/6YNh+tlp6nd/2pWq38i9h6mz/EuQ6njIrmW8D1BS5nCqs0P6DG+m6zTGnNz5I+uhZ0SHxBs9BsPrwcKDA=="], + "y18n": ["y18n@5.0.8", "", {}, "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA=="], + "yaml": ["yaml@2.9.0", "", { "bin": { "yaml": "bin.mjs" } }, "sha512-2AvhNX3mb8zd6Zy7INTtSpl1F15HW6Wnqj0srWlkKLcpYl/gMIMJiyuGq2KeI2YFxUPjdlB+3Lc10seMLtL4cA=="], + "yaml-language-server": ["yaml-language-server@1.23.0", "", { "dependencies": { "@vscode/l10n": "^0.0.18", "ajv": "^8.17.1", "ajv-draft-04": "^1.0.0", "ajv-i18n": "^4.2.0", "prettier": "^3.8.1", "request-light": "^0.5.7", "vscode-json-languageservice": "4.1.8", "vscode-languageserver": "^9.0.0", "vscode-languageserver-textdocument": "^1.0.1", "vscode-languageserver-types": "^3.16.0", "vscode-uri": "^3.0.2", "yaml": "2.8.3" }, "bin": { "yaml-language-server": "bin/yaml-language-server" } }, "sha512-3qVyCOexLCWw06PQa5kRPwvMWMZ/eZeCRWUvgD6a0OkqL/4iCnxy2WumbWifa937Uo5xhyWJ0uxlU39ljhNh7A=="], + + "yargs": ["yargs@18.1.0", "", { "dependencies": { "cliui": "^9.0.1", "escalade": "^3.1.1", "get-caller-file": "^2.0.5", "string-width": "^8.2.1", "y18n": "^5.0.5", "yargs-parser": "^22.0.0" } }, "sha512-2rAgRKu54VsHkqI0/tYkmluGXHD4KW7yZoycuqDQ15QOTnc2VVfy0nN/1eMhnQLO00A+dwtK20xuCnc1YGeUyg=="], + "yargs-parser": ["yargs-parser@22.0.0", "", {}, "sha512-rwu/ClNdSMpkSrUb+d6BRsSkLUq1fmfsY6TOpYzTwvwkg1/NRG85KBy3kq++A8LKQwX6lsu+aWad+2khvuXrqw=="], "yocto-queue": ["yocto-queue@1.2.2", "", {}, "sha512-4LCcse/U2MHZ63HAJVE+v71o7yOdIe4cZ70Wpf8D/IyjDKYQLV5GD46B+hSTjJsvV5PztjvHoU580EftxjDZFQ=="], @@ -807,10 +934,14 @@ "@tailwindcss/oxide-wasm32-wasi/tslib": ["tslib@2.8.1", "", { "bundled": true }, "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="], + "@vscode/emmet-helper/jsonc-parser": ["jsonc-parser@2.3.1", "", {}, "sha512-H8jvkz1O50L3dMZCsLqiuB2tA7muqbSg1AtGEkN0leAqGjsUzDJir3Zwr02BhqdcITPg3ei3mZ+HjMocAknhhg=="], + "anymatch/picomatch": ["picomatch@2.3.2", "", {}, "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA=="], "astro/esbuild": ["esbuild@0.28.2", "", { "optionalDependencies": { "@esbuild/aix-ppc64": "0.28.2", "@esbuild/android-arm": "0.28.2", "@esbuild/android-arm64": "0.28.2", "@esbuild/android-x64": "0.28.2", "@esbuild/darwin-arm64": "0.28.2", "@esbuild/darwin-x64": "0.28.2", "@esbuild/freebsd-arm64": "0.28.2", "@esbuild/freebsd-x64": "0.28.2", "@esbuild/linux-arm": "0.28.2", "@esbuild/linux-arm64": "0.28.2", "@esbuild/linux-ia32": "0.28.2", "@esbuild/linux-loong64": "0.28.2", "@esbuild/linux-mips64el": "0.28.2", "@esbuild/linux-ppc64": "0.28.2", "@esbuild/linux-riscv64": "0.28.2", "@esbuild/linux-s390x": "0.28.2", "@esbuild/linux-x64": "0.28.2", "@esbuild/netbsd-arm64": "0.28.2", "@esbuild/netbsd-x64": "0.28.2", "@esbuild/openbsd-arm64": "0.28.2", "@esbuild/openbsd-x64": "0.28.2", "@esbuild/openharmony-arm64": "0.28.2", "@esbuild/sunos-x64": "0.28.2", "@esbuild/win32-arm64": "0.28.2", "@esbuild/win32-ia32": "0.28.2", "@esbuild/win32-x64": "0.28.2" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-HKVLS8dvII+xoKW9kmqxbRKrnWEXfJJr/FZhhJmiqIB0e053QNYFqOBouTMO/k5sID4MvCiUCvv8b9M4h32wIA=="], + "cliui/string-width": ["string-width@7.2.0", "", { "dependencies": { "emoji-regex": "^10.3.0", "get-east-asian-width": "^1.0.0", "strip-ansi": "^7.1.0" } }, "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ=="], + "csso/css-tree": ["css-tree@2.2.1", "", { "dependencies": { "mdn-data": "2.0.28", "source-map-js": "^1.0.1" } }, "sha512-OA0mILzGc1kCOCSJerOeqDxDQ4HOh+G8NbOJFOTgOCzpw7fCBubk0fEyxp8AgOL/jvLgYA/uV0cMbe43ElF1JA=="], "miniflare/sharp": ["sharp@0.35.2", "", { "dependencies": { "@img/colour": "^1.1.0", "detect-libc": "^2.1.2", "semver": "^7.8.4" }, "optionalDependencies": { "@img/sharp-darwin-arm64": "0.35.2", "@img/sharp-darwin-x64": "0.35.2", "@img/sharp-freebsd-wasm32": "0.35.2", "@img/sharp-libvips-darwin-arm64": "1.3.1", "@img/sharp-libvips-darwin-x64": "1.3.1", "@img/sharp-libvips-linux-arm": "1.3.1", "@img/sharp-libvips-linux-arm64": "1.3.1", "@img/sharp-libvips-linux-ppc64": "1.3.1", "@img/sharp-libvips-linux-riscv64": "1.3.1", "@img/sharp-libvips-linux-s390x": "1.3.1", "@img/sharp-libvips-linux-x64": "1.3.1", "@img/sharp-libvips-linuxmusl-arm64": "1.3.1", "@img/sharp-libvips-linuxmusl-x64": "1.3.1", "@img/sharp-linux-arm": "0.35.2", "@img/sharp-linux-arm64": "0.35.2", "@img/sharp-linux-ppc64": "0.35.2", "@img/sharp-linux-riscv64": "0.35.2", "@img/sharp-linux-s390x": "0.35.2", "@img/sharp-linux-x64": "0.35.2", "@img/sharp-linuxmusl-arm64": "0.35.2", "@img/sharp-linuxmusl-x64": "0.35.2", "@img/sharp-webcontainers-wasm32": "0.35.2", "@img/sharp-win32-arm64": "0.35.2", "@img/sharp-win32-ia32": "0.35.2", "@img/sharp-win32-x64": "0.35.2" } }, "sha512-FVtFjtBCMiJS6yb5CX7Sop45WFMpeGw6oRKuJnXYgf/f1ms/D7LE/ZUSNxnW7rZ/dbslQWYkoqFHGPaDBtaK4w=="], @@ -819,8 +950,20 @@ "unifont/undici": ["undici@8.10.1", "", {}, "sha512-YQ3WlbqjYMmNpdvDH64jAgLjxuAR9+649calDWhbshYaeQGO2bR4nI94ORJmwI3J9YhoKQnpyGOK+0zlWS5N5Q=="], + "unstorage/chokidar": ["chokidar@5.0.0", "", { "dependencies": { "readdirp": "^5.0.0" } }, "sha512-TQMmc3w+5AxjpL8iIiwebF73dRDF4fBIieAqGn9RGCWaEVwQ6Fb2cGe31Yns0RRIzii5goJ1Y7xbMwo1TxMplw=="], + "vite/lightningcss": ["lightningcss@1.33.0", "", { "dependencies": { "detect-libc": "^2.0.3" }, "optionalDependencies": { "lightningcss-android-arm64": "1.33.0", "lightningcss-darwin-arm64": "1.33.0", "lightningcss-darwin-x64": "1.33.0", "lightningcss-freebsd-x64": "1.33.0", "lightningcss-linux-arm-gnueabihf": "1.33.0", "lightningcss-linux-arm64-gnu": "1.33.0", "lightningcss-linux-arm64-musl": "1.33.0", "lightningcss-linux-x64-gnu": "1.33.0", "lightningcss-linux-x64-musl": "1.33.0", "lightningcss-win32-arm64-msvc": "1.33.0", "lightningcss-win32-x64-msvc": "1.33.0" } }, "sha512-WkUDrojuJs0xkgGf2udWxa3yGBRxPtxUkB79i6aCZLRgc7PM8fZe9TosfPDcvEpQZbuFASnHYmRLBLUbmLOIIA=="], + "vscode-css-languageservice/vscode-languageserver-types": ["vscode-languageserver-types@3.17.5", "", {}, "sha512-Ld1VelNuX9pdF39h2Hgaeb5hEZM2Z3jUrrMgWQAu82jMtZp7p3vJT3BzToKtZI7NgQssZje5o0zryOrhQvzQAg=="], + + "vscode-languageserver/vscode-languageserver-protocol": ["vscode-languageserver-protocol@3.17.5", "", { "dependencies": { "vscode-jsonrpc": "8.2.0", "vscode-languageserver-types": "3.17.5" } }, "sha512-mb1bvRJN8SVznADSGWM9u/b07H7Ecg0I3OgXDuLdn307rl/J3A9YD6/eYOssqhecL27hK1IPZAsaqh00i/Jljg=="], + + "wrap-ansi/string-width": ["string-width@7.2.0", "", { "dependencies": { "emoji-regex": "^10.3.0", "get-east-asian-width": "^1.0.0", "strip-ansi": "^7.1.0" } }, "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ=="], + + "yaml-language-server/request-light": ["request-light@0.5.8", "", {}, "sha512-3Zjgh+8b5fhRJBQZoy+zbVKpAQGLyka0MPgW3zruTF4dFFJ8Fqcfu9YsAvi/rvdcaTeWG3MkbZv4WKxAn/84Lg=="], + + "yaml-language-server/yaml": ["yaml@2.8.3", "", { "bin": { "yaml": "bin.mjs" } }, "sha512-AvbaCLOO2Otw/lW5bmh9d/WEdcDFdQp2Z2ZUH3pX9U2ihyUY0nvLv7J6TrWowklRGPYbB/IuIMfYgxaCPg5Bpg=="], + "youch/cookie": ["cookie@1.1.1", "", {}, "sha512-ei8Aos7ja0weRpFzJnEA9UHJ/7XQmqglbRwnf2ATjcB9Wq874VKH9kfjjirM6UhU2/E5fFYadylyhFldcqSidQ=="], "astro/esbuild/@esbuild/aix-ppc64": ["@esbuild/aix-ppc64@0.28.2", "", { "os": "aix", "cpu": "ppc64" }, "sha512-XExcO+dvLKvVtNTibSTBej1NCAbaGhWn9Ww1ZPx80qsahhPFe/8jgWP0IchNe0F3HwkU7n8ejhH8bjonqht8mQ=="], @@ -929,6 +1072,8 @@ "sitemap/@types/node/undici-types": ["undici-types@7.18.2", "", {}, "sha512-AsuCzffGHJybSaRrmr5eHr81mwJU3kjw6M+uprWvCXiNeN9SOGwQ3Jn8jb8m3Z6izVgknn1R0FTCEAP2QrLY/w=="], + "unstorage/chokidar/readdirp": ["readdirp@5.1.1", "", {}, "sha512-Kko+Y5XQ6fM+Ce3dq3m9YGxnacYZYl9cA1wZjaF3Vbry2L3i1qVg8+CAgNPsXRArPMUMCaOR7oa9Nqntc43JKA=="], + "vite/lightningcss/lightningcss-android-arm64": ["lightningcss-android-arm64@1.33.0", "", { "os": "android", "cpu": "arm64" }, "sha512-gEpRTalKdosp4Bb8qWtc2iOgE5SeIHlpS1up9bFq2wAyYhl1UdTObYiHe98zEM9SQvSoqQZ1IQD0JNpg3Ml5pg=="], "vite/lightningcss/lightningcss-darwin-arm64": ["lightningcss-darwin-arm64@1.33.0", "", { "os": "darwin", "cpu": "arm64" }, "sha512-Sciaz8eenNTKn9b3t7+xr0ipTp9YxKQY4npwQ3mrRuL0BAVHBLyZxofhaKBAVtzmtRZ/zTyo0/to4B1uWG/Djg=="], @@ -951,6 +1096,10 @@ "vite/lightningcss/lightningcss-win32-x64-msvc": ["lightningcss-win32-x64-msvc@1.33.0", "", { "os": "win32", "cpu": "x64" }, "sha512-OlEICDx/Xl0FqSp4bry8zFnCvGpig3Gl4gCquvYwHuqJKEC1+n9NgDniFvqHGmMv1ZkqDJrDqKKSykTDX+ehuA=="], + "vscode-languageserver/vscode-languageserver-protocol/vscode-jsonrpc": ["vscode-jsonrpc@8.2.0", "", {}, "sha512-C+r0eKJUIfiDIfwJhria30+TYWPtuHJXHtI7J0YlOmKAo7ogxP20T0zxB7HZQIFhIyvoBPwWskjxrvAtfjyZfA=="], + + "vscode-languageserver/vscode-languageserver-protocol/vscode-languageserver-types": ["vscode-languageserver-types@3.17.5", "", {}, "sha512-Ld1VelNuX9pdF39h2Hgaeb5hEZM2Z3jUrrMgWQAu82jMtZp7p3vJT3BzToKtZI7NgQssZje5o0zryOrhQvzQAg=="], + "miniflare/sharp/@img/sharp-freebsd-wasm32/@img/sharp-wasm32": ["@img/sharp-wasm32@0.35.2", "", { "dependencies": { "@emnapi/runtime": "^1.11.1" } }, "sha512-Mrv4JQNYVQ94xH+jzZ9r+gowleN8mv2FTgKT+PI6bx5C0G8TdNYndu161pg2i7uoBwxy2ImPMHrJOM2LZef7Bw=="], "miniflare/sharp/@img/sharp-webcontainers-wasm32/@img/sharp-wasm32": ["@img/sharp-wasm32@0.35.2", "", { "dependencies": { "@emnapi/runtime": "^1.11.1" } }, "sha512-Mrv4JQNYVQ94xH+jzZ9r+gowleN8mv2FTgKT+PI6bx5C0G8TdNYndu161pg2i7uoBwxy2ImPMHrJOM2LZef7Bw=="], diff --git a/data/genai/2026-05-05.2.json.gz b/data/genai/2026-05-05.2.json.gz new file mode 100644 index 0000000..464c31c Binary files /dev/null and b/data/genai/2026-05-05.2.json.gz differ diff --git a/data/genai/2026-05-05.3.json.gz b/data/genai/2026-05-05.3.json.gz new file mode 100644 index 0000000..5ec2f82 Binary files /dev/null and b/data/genai/2026-05-05.3.json.gz differ diff --git a/data/genai/2026-05-05.4.json.gz b/data/genai/2026-05-05.4.json.gz new file mode 100644 index 0000000..deddc30 Binary files /dev/null and b/data/genai/2026-05-05.4.json.gz differ diff --git a/data/genai/2026-05-05.json.gz b/data/genai/2026-05-05.json.gz new file mode 100644 index 0000000..7da9f97 Binary files /dev/null and b/data/genai/2026-05-05.json.gz differ diff --git a/data/genai/2026-05-08.json.gz b/data/genai/2026-05-08.json.gz new file mode 100644 index 0000000..7b7f00f Binary files /dev/null and b/data/genai/2026-05-08.json.gz differ diff --git a/data/genai/2026-05-11.2.json.gz b/data/genai/2026-05-11.2.json.gz new file mode 100644 index 0000000..f206cbf Binary files /dev/null and b/data/genai/2026-05-11.2.json.gz differ diff --git a/data/genai/2026-05-11.json.gz b/data/genai/2026-05-11.json.gz new file mode 100644 index 0000000..beb1f7c Binary files /dev/null and b/data/genai/2026-05-11.json.gz differ diff --git a/data/genai/2026-05-16.json.gz b/data/genai/2026-05-16.json.gz new file mode 100644 index 0000000..9f4685b Binary files /dev/null and b/data/genai/2026-05-16.json.gz differ diff --git a/data/genai/2026-05-18.json.gz b/data/genai/2026-05-18.json.gz new file mode 100644 index 0000000..754b923 Binary files /dev/null and b/data/genai/2026-05-18.json.gz differ diff --git a/data/genai/2026-05-19.json.gz b/data/genai/2026-05-19.json.gz new file mode 100644 index 0000000..8614e91 Binary files /dev/null and b/data/genai/2026-05-19.json.gz differ diff --git a/data/genai/2026-05-26.json.gz b/data/genai/2026-05-26.json.gz new file mode 100644 index 0000000..1e093ab Binary files /dev/null and b/data/genai/2026-05-26.json.gz differ diff --git a/data/genai/2026-06-04.2.json.gz b/data/genai/2026-06-04.2.json.gz new file mode 100644 index 0000000..2eff3b8 Binary files /dev/null and b/data/genai/2026-06-04.2.json.gz differ diff --git a/data/genai/2026-06-04.json.gz b/data/genai/2026-06-04.json.gz new file mode 100644 index 0000000..f9c8ce2 Binary files /dev/null and b/data/genai/2026-06-04.json.gz differ diff --git a/data/genai/2026-06-05.json.gz b/data/genai/2026-06-05.json.gz new file mode 100644 index 0000000..8940b56 Binary files /dev/null and b/data/genai/2026-06-05.json.gz differ diff --git a/data/genai/2026-06-08.json.gz b/data/genai/2026-06-08.json.gz new file mode 100644 index 0000000..a770573 Binary files /dev/null and b/data/genai/2026-06-08.json.gz differ diff --git a/data/genai/2026-06-10.json.gz b/data/genai/2026-06-10.json.gz new file mode 100644 index 0000000..76c438f Binary files /dev/null and b/data/genai/2026-06-10.json.gz differ diff --git a/data/genai/2026-06-17.2.json.gz b/data/genai/2026-06-17.2.json.gz new file mode 100644 index 0000000..9e74eff Binary files /dev/null and b/data/genai/2026-06-17.2.json.gz differ diff --git a/data/genai/2026-06-17.json.gz b/data/genai/2026-06-17.json.gz new file mode 100644 index 0000000..298c13e Binary files /dev/null and b/data/genai/2026-06-17.json.gz differ diff --git a/data/genai/2026-06-18.2.json.gz b/data/genai/2026-06-18.2.json.gz new file mode 100644 index 0000000..e5ea226 Binary files /dev/null and b/data/genai/2026-06-18.2.json.gz differ diff --git a/data/genai/2026-06-18.json.gz b/data/genai/2026-06-18.json.gz new file mode 100644 index 0000000..0a6d818 Binary files /dev/null and b/data/genai/2026-06-18.json.gz differ diff --git a/data/genai/2026-06-19.json.gz b/data/genai/2026-06-19.json.gz new file mode 100644 index 0000000..8edac6d Binary files /dev/null and b/data/genai/2026-06-19.json.gz differ diff --git a/data/genai/2026-06-23.json.gz b/data/genai/2026-06-23.json.gz new file mode 100644 index 0000000..c46f9b8 Binary files /dev/null and b/data/genai/2026-06-23.json.gz differ diff --git a/data/genai/2026-06-24.json.gz b/data/genai/2026-06-24.json.gz new file mode 100644 index 0000000..9215110 Binary files /dev/null and b/data/genai/2026-06-24.json.gz differ diff --git a/data/genai/2026-06-25.2.json.gz b/data/genai/2026-06-25.2.json.gz new file mode 100644 index 0000000..2584961 Binary files /dev/null and b/data/genai/2026-06-25.2.json.gz differ diff --git a/data/genai/2026-06-25.json.gz b/data/genai/2026-06-25.json.gz new file mode 100644 index 0000000..1be00be Binary files /dev/null and b/data/genai/2026-06-25.json.gz differ diff --git a/data/genai/2026-07-08.json.gz b/data/genai/2026-07-08.json.gz new file mode 100644 index 0000000..dacafca Binary files /dev/null and b/data/genai/2026-07-08.json.gz differ diff --git a/data/genai/2026-07-16.json.gz b/data/genai/2026-07-16.json.gz new file mode 100644 index 0000000..fbb0055 Binary files /dev/null and b/data/genai/2026-07-16.json.gz differ diff --git a/data/genai/2026-07-23.json.gz b/data/genai/2026-07-23.json.gz new file mode 100644 index 0000000..0233601 Binary files /dev/null and b/data/genai/2026-07-23.json.gz differ diff --git a/data/genai/2026-07-28.json.gz b/data/genai/2026-07-28.json.gz new file mode 100644 index 0000000..7086c21 Binary files /dev/null and b/data/genai/2026-07-28.json.gz differ diff --git a/data/genai/2026-07-31.json.gz b/data/genai/2026-07-31.json.gz new file mode 100644 index 0000000..1ecad24 Binary files /dev/null and b/data/genai/2026-07-31.json.gz differ diff --git a/data/genai/2026-08-01.json.gz b/data/genai/2026-08-01.json.gz new file mode 100644 index 0000000..872cc85 Binary files /dev/null and b/data/genai/2026-08-01.json.gz differ diff --git a/data/genai/2026-08-04.json.gz b/data/genai/2026-08-04.json.gz new file mode 100644 index 0000000..2024345 Binary files /dev/null and b/data/genai/2026-08-04.json.gz differ diff --git a/data/genai/2026-08-05.2.json.gz b/data/genai/2026-08-05.2.json.gz new file mode 100644 index 0000000..d848a71 Binary files /dev/null and b/data/genai/2026-08-05.2.json.gz differ diff --git a/data/genai/2026-08-05.json.gz b/data/genai/2026-08-05.json.gz new file mode 100644 index 0000000..57d2af7 Binary files /dev/null and b/data/genai/2026-08-05.json.gz differ diff --git a/data/genai/2026-08-06.json.gz b/data/genai/2026-08-06.json.gz new file mode 100644 index 0000000..efdd328 Binary files /dev/null and b/data/genai/2026-08-06.json.gz differ diff --git a/data/genai/2026-08-07.json.gz b/data/genai/2026-08-07.json.gz new file mode 100644 index 0000000..e2a8552 Binary files /dev/null and b/data/genai/2026-08-07.json.gz differ diff --git a/data/genai/2026-08-10.json.gz b/data/genai/2026-08-10.json.gz new file mode 100644 index 0000000..8e920f9 Binary files /dev/null and b/data/genai/2026-08-10.json.gz differ diff --git a/data/genai/2026-08-20.json.gz b/data/genai/2026-08-20.json.gz new file mode 100644 index 0000000..c3784c5 Binary files /dev/null and b/data/genai/2026-08-20.json.gz differ diff --git a/data/genai/2026-08-27.json.gz b/data/genai/2026-08-27.json.gz new file mode 100644 index 0000000..8d22557 Binary files /dev/null and b/data/genai/2026-08-27.json.gz differ diff --git a/data/genai/2026-09-01.json.gz b/data/genai/2026-09-01.json.gz new file mode 100644 index 0000000..d1599ce Binary files /dev/null and b/data/genai/2026-09-01.json.gz differ diff --git a/data/genai/2026-09-03.json.gz b/data/genai/2026-09-03.json.gz deleted file mode 100644 index e266eb7..0000000 Binary files a/data/genai/2026-09-03.json.gz and /dev/null differ diff --git a/data/index.json b/data/index.json index 5cec8a2..138e8f6 100644 --- a/data/index.json +++ b/data/index.json @@ -1,13 +1,37 @@ { - "generatedAt": "2026-09-03T01:31:41Z", + "generatedAt": "2026-09-01T00:13:46Z", "releases": [ { "source": "genai", - "tag": "fee465d", - "version": "2026-09-03", - "publishedAt": "2026-09-03T01:31:41Z", - "url": "https://github.com/open-telemetry/semantic-conventions-genai/commits/main", - "body": "" + "tag": "5ca9052", + "version": "2026-09-01", + "publishedAt": "2026-09-01T00:13:46Z", + "url": "https://github.com/open-telemetry/semantic-conventions-genai/commit/5ca9052bc796ef1e497200b1d558fd87a201f335", + "body": "gen-ai: deprecate per-message finish reason (#363)" + }, + { + "source": "genai", + "tag": "5f5ae69", + "version": "2026-08-27", + "publishedAt": "2026-08-27T01:47:30Z", + "url": "https://github.com/open-telemetry/semantic-conventions-genai/commit/5f5ae69e52464c56eea4389fb793c2690caaea78", + "body": "Remove cache token usage attributes from internal agent spans (#469)" + }, + { + "source": "genai", + "tag": "8a3767d", + "version": "2026-08-20", + "publishedAt": "2026-08-20T03:23:01Z", + "url": "https://github.com/open-telemetry/semantic-conventions-genai/commit/8a3767d6c5d09bc0917722720973c0c44182d960", + "body": "Add span/event attributes for usage breakdown per modality / cache / phases (#440)" + }, + { + "source": "genai", + "tag": "8d3e4a0", + "version": "2026-08-10", + "publishedAt": "2026-08-10T23:51:20Z", + "url": "https://github.com/open-telemetry/semantic-conventions-genai/commit/8d3e4a0f3c34a46f6edb9c71e8666e02e6bf3958", + "body": "Clarify workflow span criteria and add reference scenarios for langchain and openai agents (#354)" }, { "source": "spec", @@ -17,6 +41,38 @@ "url": "https://github.com/open-telemetry/opentelemetry-specification/releases/tag/v1.60.0", "body": "### Resource\r\n\r\n- Add Entity support to the Resource SDK specification.\r\n ([#5201](https://github.com/open-telemetry/opentelemetry-specification/pull/5201))\r\n\r\n### Entities\r\n\r\n- Add Entity specification.\r\n ([#5201](https://github.com/open-telemetry/opentelemetry-specification/pull/5201))\r\n\r\n### OpenTelemetry Protocol\r\n\r\n- Add max request / response size options to list of OTLP exporter configuration options.\r\n ([#5235](https://github.com/open-telemetry/opentelemetry-specification/pull/5235))\r\n\r\n### Compatibility\r\n\r\n- Clarify the interaction between Prometheus content negotiation and translation\r\n strategy.\r\n ([#5134](https://github.com/open-telemetry/opentelemetry-specification/pull/5134))\r\n- Stabilize sections of Prometheus Metrics Exporter.\r\n - Stabilize Target section.\r\n ([#5221](https://github.com/open-telemetry/opentelemetry-specification/pull/5221))\r\n\r\n### OTEPs\r\n\r\n- Thread Context: Sharing Thread-Level Information with the OpenTelemetry eBPF Profiler.\r\n ([#4947](https://github.com/open-telemetry/opentelemetry-specification/pull/4947))\r\n\r\n## New Contributors\r\n* @scottgerring made their first contribution in https://github.com/open-telemetry/opentelemetry-specification/pull/4947" }, + { + "source": "genai", + "tag": "8c1b98a", + "version": "2026-08-07", + "publishedAt": "2026-08-07T01:49:41Z", + "url": "https://github.com/open-telemetry/semantic-conventions-genai/commit/8c1b98a376e91d422726ccf33bef051fd9ce4b25", + "body": "Allow conversation ID on workflow spans (#410)" + }, + { + "source": "genai", + "tag": "04702bc", + "version": "2026-08-06", + "publishedAt": "2026-08-06T22:38:29Z", + "url": "https://github.com/open-telemetry/semantic-conventions-genai/commit/04702bce2223048826235e717427afb646bd9de2", + "body": "Warn that gen_ai.tool.description and gen_ai.tool.definitions may contain sensitive information (#431)" + }, + { + "source": "genai", + "tag": "4a39b6e", + "version": "2026-08-05.2", + "publishedAt": "2026-08-05T14:12:06Z", + "url": "https://github.com/open-telemetry/semantic-conventions-genai/commit/4a39b6ef1363fab57bc40e18c82abb32cc89ebcd", + "body": "Keep upstream doc links pinned to the version in `model/manifest.yaml` (#435)" + }, + { + "source": "genai", + "tag": "11658bb", + "version": "2026-08-05", + "publishedAt": "2026-08-05T03:25:00Z", + "url": "https://github.com/open-telemetry/semantic-conventions-genai/commit/11658bba3eb02448618ddf1fc52789a3fc2937cc", + "body": "Rename gen_ai.workflow.duration to gen_ai.invoke_workflow.duration (#341)" + }, { "source": "semconv", "tag": "v1.44.0", @@ -25,6 +81,46 @@ "url": "https://github.com/open-telemetry/semantic-conventions/releases/tag/v1.44.0", "body": "### 🛑 Breaking changes 🛑\r\n\r\n- `browser`: Reworked the `browser.web_vital` event - moved `name`/`value`/`delta`/`id` from the event body to `browser.web_vital.*` attributes, and added new attributes per current instrumentation. ([#3401](https://github.com/open-telemetry/semantic-conventions/issues/3401))\r\n- `k8s`: Rename `k8s.node.memory.paging.faults`, `k8s.pod.memory.paging.faults` and `container.memory.paging.faults` metrics by dropping the `memory` namespace segment.\r\n ([#3805](https://github.com/open-telemetry/semantic-conventions/issues/3805))\r\n Renamed metrics:\r\n - k8s.pod.memory.paging.faults -> k8s.pod.paging.faults\r\n - k8s.node.memory.paging.faults -> k8s.node.paging.faults\r\n - container.memory.paging.faults -> container.paging.faults\r\n- `k8s`: Change {container, k8s.pod, k8s.node}.memory.usage to updowncounter ([#3889](https://github.com/open-telemetry/semantic-conventions/issues/3889))\r\n\r\n### 💡 Enhancements 💡\r\n\r\n- `cloud`: Add Scaleway Cloud to cloud.provider and scaleway_cloud_compute to cloud.platform ([#2773](https://github.com/open-telemetry/semantic-conventions/issues/2773))\r\n- `db`: Clarify `db.query.parameter.` semantics around sensitive data handling.\r\n ([#3831](https://github.com/open-telemetry/semantic-conventions/issues/3831))\r\n- `faas`: The general FaaS attributes are now defined on the FaaS spans that use them, so each span documents its full attribute set. ([#3905](https://github.com/open-telemetry/semantic-conventions/issues/3905))\r\n- `host`: Update the recommendations to use full path to commands when collecting `host.id` attribute value.\r\n ([#3896](https://github.com/open-telemetry/semantic-conventions/issues/3896))\r\n- `hw`: Per-component `hw.errors` and `hw.status` metrics now document the full set of component-specific attributes (e.g. `hw.model`, `hw.vendor`) alongside the generic ones.\r\n ([#3808](https://github.com/open-telemetry/semantic-conventions/issues/3808))\r\n- `k8s`: Add `k8s.node.filesystem.inode.count` and `k8s.node.filesystem.inode.free` metrics to track Kubernetes node root filesystem inode capacity and usage. ([#3858](https://github.com/open-telemetry/semantic-conventions/issues/3858))\r\n- `k8s`: Promote a selection of container and K8s memory metrics to release_candidate ([#3882](https://github.com/open-telemetry/semantic-conventions/issues/3882))\r\n The following metrics are being promoted to release_candidate:\r\n - container.memory.usage\r\n - container.memory.available\r\n - container.memory.rss\r\n - container.memory.working_set\r\n - k8s.pod.memory.usage\r\n - k8s.pod.memory.available\r\n - k8s.pod.memory.rss\r\n - k8s.pod.memory.working_set\r\n - k8s.node.memory.usage\r\n - k8s.node.memory.available\r\n - k8s.node.memory.rss\r\n - k8s.node.memory.working_set\r\n\r\n- `k8s`: Clarify how `cpu.usage` is calculated for K8s and container entities. ([#2418](https://github.com/open-telemetry/semantic-conventions/issues/2418))\r\n CPU usage is measured in cores/CPUs and is calculated based on the formula:\r\n `usageCores = (cpuTimeEnd - cpuTimeStart) / elapsedSeconds`\r\n This PR improves the description making it aligned with the corresponding\r\n system and process metrics.\r\n\r\n- `messaging`: Add `messaging.kafka.cluster.id` attribute identifying the Kafka cluster a client is connected to, and reference it from Kafka spans. ([#32](https://github.com/open-telemetry/semantic-conventions/issues/32))\r\n- `messaging`: Define a span per messaging operation type (create, send, receive, process, settle) and refine them for each messaging system. ([#3904](https://github.com/open-telemetry/semantic-conventions/issues/3904))\r\n- `network`: Promote `network.interface.name` attribute to `release_candidate` ([#3953](https://github.com/open-telemetry/semantic-conventions/issues/3953))\r\n- `otel`: Clarify that `otel.sdk.processor.span.processed` and `otel.sdk.processor.log.processed` are recorded when the processor passes items to the exporter, not when an item is accepted into a queue or when the export operation completes, and that the export outcome does not affect these metrics.\r\n ([#3902](https://github.com/open-telemetry/semantic-conventions/issues/3902))\r\n- `process`: Add process.disk.operations, process.memory.utilization, and process.signals_pending metrics ([#3937](https://github.com/open-telemetry/semantic-conventions/issues/3937))\r\n Process namespace has been made release candidate. During migration of process metrics to release\r\n candidate in hostmetrics receiver, it was discovered that the following process metrics were not\r\n present in process semantic conventions: process.disk.operations, process.memory.utilization,\r\n and process.signals_pending.\r\n\r\n- `server, client, source, destination`: The descriptions of the `server`, `client`, `source`, and `destination` attribute groups are now documented in [General attributes](https://github.com/open-telemetry/semantic-conventions/blob/main/docs/general/attributes.md) instead of the attribute registry pages.\r\n ([#3935](https://github.com/open-telemetry/semantic-conventions/issues/3935))\r\n- `system`: Add `system.process.limit` metric representing the maximum number of concurrent tasks/threads allowed by the operating system. ([#3859](https://github.com/open-telemetry/semantic-conventions/issues/3859))\r\n\r\n### 🧰 Bug fixes 🧰\r\n\r\n- `otel`: Clarify that `already_shutdown` on `otel.sdk.processor.span.processed` and `otel.sdk.processor.log.processed` is a value-only requirement for the `error.type` attribute: whether and when a processor drops records because it has already been shut down is governed by the SDK specification, not by this metric.\r\n ([#3957](https://github.com/open-telemetry/semantic-conventions/issues/3957))\r\n- `rpc`: Fix wording in `server.address` note to say \"reverse DNS lookup\" instead of \"reverse proxy lookup\".\r\n ([#3871](https://github.com/open-telemetry/semantic-conventions/issues/3871))\r\n- `rpc`: Remove tracing-only `rpc.method_original` guidance from the shared `rpc.method` definition.\r\n ([#3872](https://github.com/open-telemetry/semantic-conventions/issues/3872))\r\n\r\n## New Contributors\r\n* @Jaegeonyoon made their first contribution in https://github.com/open-telemetry/semantic-conventions/pull/3843\r\n* @shashank-reddy-nr made their first contribution in https://github.com/open-telemetry/semantic-conventions/pull/3819\r\n* @lachmatt made their first contribution in https://github.com/open-telemetry/semantic-conventions/pull/3896\r\n* @jaredDlewis made their first contribution in https://github.com/open-telemetry/semantic-conventions/pull/3851\r\n\r\n**Full Changelog**: https://github.com/open-telemetry/semantic-conventions/compare/v1.43.0...v1.44.0" }, + { + "source": "genai", + "tag": "683c745", + "version": "2026-08-04", + "publishedAt": "2026-08-04T15:43:04Z", + "url": "https://github.com/open-telemetry/semantic-conventions-genai/commit/683c74506292a4c0ad1c772982e7d51e6128ba5d", + "body": "MCP server status: don't set to errors for client errors (#404)" + }, + { + "source": "genai", + "tag": "8484f22", + "version": "2026-08-01", + "publishedAt": "2026-08-01T19:15:02Z", + "url": "https://github.com/open-telemetry/semantic-conventions-genai/commit/8484f22ff8069267f37cb1be54bcebbf1972b682", + "body": "weaver 0.25.0: remove now unnecessary workarounds (#400)" + }, + { + "source": "genai", + "tag": "683d28d", + "version": "2026-07-31", + "publishedAt": "2026-07-31T20:35:26Z", + "url": "https://github.com/open-telemetry/semantic-conventions-genai/commit/683d28da9fc8e5fc87a7d64200ac88799b9202c2", + "body": "gen-ai: add fetch_response operation and span (#353)" + }, + { + "source": "genai", + "tag": "3cfb9e6", + "version": "2026-07-28", + "publishedAt": "2026-07-28T16:51:32Z", + "url": "https://github.com/open-telemetry/semantic-conventions-genai/commit/3cfb9e6e2344a337f9378e2bfdfd8ed9e1f20ca2", + "body": "#344 Make retrieval document id and score optional (#396)" + }, + { + "source": "genai", + "tag": "712c94f", + "version": "2026-07-23", + "publishedAt": "2026-07-23T17:05:41Z", + "url": "https://github.com/open-telemetry/semantic-conventions-genai/commit/712c94fe6f6a165ee0b93d9687286357eb335c7e", + "body": "Add new sem conv request attribute `gen_ai.request.previous_response.id` (#372)" + }, { "source": "proto", "tag": "v1.11.0", @@ -33,6 +129,14 @@ "url": "https://github.com/open-telemetry/opentelemetry-proto/releases/tag/v1.11.0", "body": "## What's Changed\r\n### Added\r\n- docs: add request size limitation for HTTP body and gRPC messages. https://github.com/open-telemetry/opentelemetry-proto/pull/782\r\n- docs: add response size limitation for HTTP body and gRPC messages. https://github.com/open-telemetry/opentelemetry-proto/pull/781, https://github.com/open-telemetry/opentelemetry-proto/pull/800, https://github.com/open-telemetry/opentelemetry-proto/pull/801, https://github.com/open-telemetry/opentelemetry-proto/pull/802\r\n- processcontext: add ProcessContext message described in [OTEP 4719](https://github.com/open-telemetry/opentelemetry-specification/blob/main/oteps/profiles/4719-process-ctx.md). https://github.com/open-telemetry/opentelemetry-proto/pull/783\r\n\r\n### Fixed\r\n- docs: clarify that Retry-After header value can be an HTTP-date. https://github.com/open-telemetry/opentelemetry-proto/pull/806\r\n\r\n\r\n## New Contributors\r\n* @liwa-datev made their first contribution in https://github.com/open-telemetry/opentelemetry-proto/pull/758\r\n* @ivoanjo made their first contribution in https://github.com/open-telemetry/opentelemetry-proto/pull/783\r\n* @vascoccorreia made their first contribution in https://github.com/open-telemetry/opentelemetry-proto/pull/824\r\n\r\n**Full Changelog**: https://github.com/open-telemetry/opentelemetry-proto/compare/v1.10.0...v1.11.0" }, + { + "source": "genai", + "tag": "33b7f9d", + "version": "2026-07-16", + "publishedAt": "2026-07-16T20:51:57Z", + "url": "https://github.com/open-telemetry/semantic-conventions-genai/commit/33b7f9da9ade6162d4a5c16247d0bc6ad5f8b469", + "body": "Replace gen_ai.agent.steps with per-invocation call-count metrics (#336)" + }, { "source": "spec", "tag": "v1.59.0", @@ -41,6 +145,14 @@ "url": "https://github.com/open-telemetry/opentelemetry-specification/releases/tag/v1.59.0", "body": "### Context\r\n\r\n- Clarify that environment variable propagation operational guidance is\r\n non-normative and should be documented by language implementations.\r\n ([#5165](https://github.com/open-telemetry/opentelemetry-specification/pull/5165))\r\n- Clean up implementation guidelines for environment variable propagation\r\n carriers.\r\n ([#5166](https://github.com/open-telemetry/opentelemetry-specification/pull/5166))\r\n- Remove caching behavior suggestions for environment variable propagation\r\n carrier implementations.\r\n ([#5179](https://github.com/open-telemetry/opentelemetry-specification/pull/5179))\r\n- Mark \"Environment Variables as Context Propagation Carriers\" as Release\r\n Candidate.\r\n ([#5142](https://github.com/open-telemetry/opentelemetry-specification/pull/5142))\r\n\r\n### Traces\r\n\r\n- Amend the description of Composite/Composable samplers.\r\n ([#5161](https://github.com/open-telemetry/opentelemetry-specification/pull/5161))\r\n\r\n### Logs\r\n\r\n- Add ETW (Event Tracing for Windows) example mapping to the logs data\r\n model appendix, including the ETW level to `SeverityNumber` mapping.\r\n ([#5159](https://github.com/open-telemetry/opentelemetry-specification/pull/5159))\r\n\r\n### Profiles\r\n\r\n- Add Profiles data model (data-model.md).\r\n ([#4965](https://github.com/open-telemetry/opentelemetry-specification/pull/4965))\r\n\r\n### Supplementary Guidelines\r\n\r\n- Add non-normative supplementary guidelines for SDK self-observability.\r\n ([#5135](https://github.com/open-telemetry/opentelemetry-specification/pull/5135))\r\n\r\n### OTEPs\r\n\r\n- Add OTEP proposing a central OpenTelemetry benchmarks repository.\r\n ([#5118](https://github.com/open-telemetry/opentelemetry-specification/pull/5118))\r\n- Introduce Policies into the specification.\r\n ([#4738](https://github.com/open-telemetry/opentelemetry-specification/pull/4738))\r\n\r\n## New Contributors\r\n* @swashtek made their first contribution in https://github.com/open-telemetry/opentelemetry-specification/pull/5159\r\n* @oindrilakha12-ui made their first contribution in https://github.com/open-telemetry/opentelemetry-specification/pull/5194\r\n" }, + { + "source": "genai", + "tag": "953dd22", + "version": "2026-07-08", + "publishedAt": "2026-07-08T20:29:36Z", + "url": "https://github.com/open-telemetry/semantic-conventions-genai/commit/953dd22e3cecd3a397d742c349d2435d59c8b771", + "body": "[chore] Add signal requirement level to yaml and jinja templates (#340)" + }, { "source": "semconv", "tag": "v1.43.0", @@ -49,6 +161,38 @@ "url": "https://github.com/open-telemetry/semantic-conventions/releases/tag/v1.43.0", "body": "### 🚩 Deprecations 🚩\r\n\r\n- `docs`: Add a generic signal requirement level document and deprecate the metric-specific one.\r\n ([#3810](https://github.com/open-telemetry/semantic-conventions/issues/3810), [#3278](https://github.com/open-telemetry/semantic-conventions/issues/3278))\r\n\r\n### 💡 Enhancements 💡\r\n\r\n- `azure`: Add `azure.resource_group.name` attribute for the name of the Azure resource group the resource belongs to and document that `cloud.account.id` maps to the Azure subscription ID. ([#3697](https://github.com/open-telemetry/semantic-conventions/issues/3697), [#3708](https://github.com/open-telemetry/semantic-conventions/issues/3708))\r\n- `cicd`: Promote CI/CD span, metric, log, attribute, and entity conventions to `release_candidate` ([#3674](https://github.com/open-telemetry/semantic-conventions/issues/3674), [#3675](https://github.com/open-telemetry/semantic-conventions/issues/3675), [#3677](https://github.com/open-telemetry/semantic-conventions/issues/3677))\r\n- `db`: Clarify `db.operation.batch.size` semantics for database batch operations, including multi-operand operations, parameterized operation batch APIs, and empty batches.\r\n ([#3811](https://github.com/open-telemetry/semantic-conventions/issues/3811))\r\n- `db`: Promote Oracle Database connection attributes to release candidate so the RC `db.oracledb.client` span does not reference lower-stability attributes. ([#3753](https://github.com/open-telemetry/semantic-conventions/issues/3753))\r\n- `disk, network, system`: Promote disk.io.direction, network.io.direction, and system.paging.fault.type attributes to RC ([#3796](https://github.com/open-telemetry/semantic-conventions/issues/3796))\r\n The `network.io.direction` brief was updated based on review feedback to clarify that\r\n it describes traffic at the observing interface boundary and is not intended to represent\r\n logical connection or network flow direction.\r\n \r\n- `otel`: Clarify that the `otel.span.sampling_result` attribute of `otel.sdk.span.live` can only take values `RECORD_ONLY` and `RECORD_AND_SAMPLE`, not `DROP`, since the metric does not count non-recording spans.\r\n ([#3782](https://github.com/open-telemetry/semantic-conventions/issues/3782))\r\n- `process`: Promote process metrics and entity to release_candidate ([#3041](https://github.com/open-telemetry/semantic-conventions/issues/3041))\r\n- `rpc`: Clarify how to populate `server.address` and `server.port` for Dubbo consumers using service discovery. ([#3408](https://github.com/open-telemetry/semantic-conventions/issues/3408))\r\n- `schema`: Add registry manifest. ([#3824](https://github.com/open-telemetry/semantic-conventions/issues/3824))\r\n- `telemetry`: Add `kotlin` as a value for the `telemetry.sdk.language` attribute. ([#3552](https://github.com/open-telemetry/semantic-conventions/issues/3552))\r\n- `vcs`: Promote VCS attribute, entity, and metric conventions to `release_candidate` ([#3676](https://github.com/open-telemetry/semantic-conventions/issues/3676))\r\n\r\n### 🧰 Bug fixes 🧰\r\n\r\n- `db`: Align Oracle Database `db.query.text` guidance with other SQL database conventions. ([#3790](https://github.com/open-telemetry/semantic-conventions/issues/3790))\r\n Parameterized query text is now recommended to be collected by default, while\r\n query parameter values remain opt-in.\r\n\r\n## New Contributors\r\n* @kathiehuang made their first contribution in https://github.com/open-telemetry/semantic-conventions/pull/3722\r\n\r\n**Full Changelog**: https://github.com/open-telemetry/semantic-conventions/compare/v1.42.0...v1.43.0" }, + { + "source": "genai", + "tag": "791c341", + "version": "2026-06-25.2", + "publishedAt": "2026-06-25T19:20:11Z", + "url": "https://github.com/open-telemetry/semantic-conventions-genai/commit/791c341968d4d14cdc4d26f5c59fe690a7fcba5b", + "body": "Add json-schema annotation for complex attributes, render boilerplate note in templates (#330)" + }, + { + "source": "genai", + "tag": "4812692", + "version": "2026-06-25", + "publishedAt": "2026-06-25T19:19:06Z", + "url": "https://github.com/open-telemetry/semantic-conventions-genai/commit/48126929c29206df00303d37d761e9c3e8e8c9af", + "body": "Align attributes between invoke_agent.internal and execute_tool spans and metrics (#322)" + }, + { + "source": "genai", + "tag": "e853ef1", + "version": "2026-06-24", + "publishedAt": "2026-06-24T20:33:54Z", + "url": "https://github.com/open-telemetry/semantic-conventions-genai/commit/e853ef127cb37f310b5b8de81fb648f149243746", + "body": "Clarify that gen_ai.invoke_agent.duration is about in-proc / internal span (#321)" + }, + { + "source": "genai", + "tag": "0183a25", + "version": "2026-06-23", + "publishedAt": "2026-06-23T14:43:58Z", + "url": "https://github.com/open-telemetry/semantic-conventions-genai/commit/0183a25b3d6970d993fd3e77b0471b8d518efe83", + "body": "Add prompt versioning and variable support to GenAI attributes (#179)" + }, { "source": "spec", "tag": "v1.58.0", @@ -57,6 +201,46 @@ "url": "https://github.com/open-telemetry/opentelemetry-specification/releases/tag/v1.58.0", "body": "### Context\r\n\r\n- Clarify that environment variable propagation carriers normalize requested\r\n keys, carrier keys, and returned keys.\r\n ([#5102](https://github.com/open-telemetry/opentelemetry-specification/pull/5102))\r\n- Specify that environment variable propagation carriers only read and return\r\n normalized environment variable names.\r\n ([#5144](https://github.com/open-telemetry/opentelemetry-specification/pull/5144))\r\n- Specify that an empty environment variable propagation name is non-normalized\r\n and normalizes to `_`.\r\n ([#5163](https://github.com/open-telemetry/opentelemetry-specification/pull/5163))\r\n\r\n### Profiles\r\n\r\n- Remove duplicate information from and extend Profiles documentation (README.md, pprof.md).\r\n ([#4932](https://github.com/open-telemetry/opentelemetry-specification/pull/4932))\r\n\r\n### Entities\r\n\r\n- Add specification for communicating entity information as structured log events.\r\n ([#4836](https://github.com/open-telemetry/opentelemetry-specification/pull/4836))\r\n\r\n### Common\r\n\r\n- Add an in-development [SDK self-observability](specification/self-observability.md)\r\n section, referenced from the Tracing, Metrics, and Logs SDK specs.\r\n ([#5087](https://github.com/open-telemetry/opentelemetry-specification/pull/5087))\r\n- Clarify non-OTLP representation guidance for nested `AnyValue` values in\r\n arrays and maps.\r\n ([#5053](https://github.com/open-telemetry/opentelemetry-specification/pull/5053))\r\n- Add in-development guidance recommending a JSON object as the string\r\n representation for an attribute in non-OTLP protocols.\r\n ([#5028](https://github.com/open-telemetry/opentelemetry-specification/pull/5028))\r\n- Add in-development guidance recommending a JSON object as the string\r\n representation for an attribute collection in non-OTLP protocols.\r\n ([#5110](https://github.com/open-telemetry/opentelemetry-specification/pull/5110))\r\n\r\n### Compatibility\r\n\r\n- Deprecate OpenCensus compatibility requirements in the specification.\r\n ([#5138](https://github.com/open-telemetry/opentelemetry-specification/pull/5138))\r\n- Stabilize sections of Prometheus Metrics Exporter.\r\n - Clarify resource attributes configuration.\r\n ([#5084](https://github.com/open-telemetry/opentelemetry-specification/pull/5084))\r\n - Stabilize the conversion of OTLP Summaries into Prometheus Summaries.\r\n ([#5107](https://github.com/open-telemetry/opentelemetry-specification/pull/5107))\r\n - Stabilize client libs section.\r\n ([#5106](https://github.com/open-telemetry/opentelemetry-specification/pull/5106))\r\n - Stabilize Prometheus Metrics Exporter default aggregation configuration.\r\n ([#5113](https://github.com/open-telemetry/opentelemetry-specification/pull/5113))\r\n- Stabilize sections of Prometheus and OpenMetrics Compatibility.\r\n - Stabilize OpenTelemetry Histogram to Prometheus Histogram transformation.\r\n ([#5091](https://github.com/open-telemetry/opentelemetry-specification/pull/5091))\r\n- Add optional OpenTelemetry Histogram to Prometheus Native Histogram with Custom Buckets transformation.\r\n ([#5091](https://github.com/open-telemetry/opentelemetry-specification/pull/5091))\r\n\r\n### SDK Configuration\r\n\r\n- Add link to declarative config IdGenerator type\r\n ([#5133](https://github.com/open-telemetry/opentelemetry-specification/pull/5133))\r\n\r\n### OTEPs\r\n\r\n- Context-scoped Attributes.\r\n ([#4931](https://github.com/open-telemetry/opentelemetry-specification/pull/4931))\r\n\r\n## New Contributors\r\n* @itssaharsh made their first contribution in https://github.com/open-telemetry/opentelemetry-specification/pull/5112\r\n* @christos68k made their first contribution in https://github.com/open-telemetry/opentelemetry-specification/pull/4932\r\n* @Krishnachaitanyakc made their first contribution in https://github.com/open-telemetry/opentelemetry-specification/pull/5138\r\n" }, + { + "source": "genai", + "tag": "6967795", + "version": "2026-06-19", + "publishedAt": "2026-06-19T21:34:17Z", + "url": "https://github.com/open-telemetry/semantic-conventions-genai/commit/6967795c5ceeb77357ca4f3dfc9a512496fb9a11", + "body": "Fix tool_call_response example field name (result -> response) (#323)" + }, + { + "source": "genai", + "tag": "65884d0", + "version": "2026-06-18.2", + "publishedAt": "2026-06-18T22:21:04Z", + "url": "https://github.com/open-telemetry/semantic-conventions-genai/commit/65884d0cb148d19214c1d865e24a0c3784432de8", + "body": "Add gen_ai.invoke_agent.duration and gen_ai.execute_tool.duration metrics (#201)" + }, + { + "source": "genai", + "tag": "93de98a", + "version": "2026-06-18", + "publishedAt": "2026-06-18T05:04:12Z", + "url": "https://github.com/open-telemetry/semantic-conventions-genai/commit/93de98a5b1298ee6708c76ca87cb389861689732", + "body": "Add `gen_ai.request.reasoning.level` attribute (#258)" + }, + { + "source": "genai", + "tag": "c032e24", + "version": "2026-06-17.2", + "publishedAt": "2026-06-17T18:24:50Z", + "url": "https://github.com/open-telemetry/semantic-conventions-genai/commit/c032e2404edb6fce3f7929b93d50f1e6ab665875", + "body": "semconv for compaction (#162)" + }, + { + "source": "genai", + "tag": "126e72f", + "version": "2026-06-17", + "publishedAt": "2026-06-17T17:56:56Z", + "url": "https://github.com/open-telemetry/semantic-conventions-genai/commit/126e72f670b2c4e7aef0af4bcbc735f791154665", + "body": "Remove gen_ai.provider.name from internal agent spans (#289)" + }, { "source": "semconv", "tag": "v1.42.0", @@ -65,6 +249,54 @@ "url": "https://github.com/open-telemetry/semantic-conventions/releases/tag/v1.42.0", "body": "## 📣 Highlights 📣\r\n\r\n* **Generative AI Migration:** All `gen_ai.*` attributes, metrics, events, and spans have been deprecated and moved to the dedicated [OpenTelemetry GenAI Semantic Conventions Repository](https://github.com/open-telemetry/semantic-conventions-genai). ([#3696](https://github.com/open-telemetry/semantic-conventions/issues/3696))\r\n* **Graduations to Stable:** A core selection of Kubernetes and container registry resource attributes have officially graduated to `stable` status. ([#3382](https://github.com/open-telemetry/semantic-conventions/issues/3382))\r\n* **Promotions to Release Candidate:** Several conventions advanced to `release_candidate`, including `cpu.mode` ([#3694](https://github.com/open-telemetry/semantic-conventions/issues/3694)), process attributes ([#3041](https://github.com/open-telemetry/semantic-conventions/issues/3041)), and core CPU time metrics (`k8s.pod.cpu.time`, `k8s.node.cpu.time`, and `container.cpu.time`) ([#3001](https://github.com/open-telemetry/semantic-conventions/issues/3001)).\r\n\r\n## Changelog\r\n\r\n### 🛑 Breaking changes 🛑\r\n\r\n- `gen-ai`: Move Generative AI semantic conventions to a dedicated repository. ([#3696](https://github.com/open-telemetry/semantic-conventions/issues/3696))\r\n All `gen_ai.*` attributes, metrics, events, and spans previously defined under\r\n `model/gen-ai/`, `model/openai/`, and `model/mcp/` (and documented under\r\n `docs/gen-ai/`) are deprecated in this repository and have moved to the\r\n [OpenTelemetry GenAI semantic conventions repository](https://github.com/open-telemetry/semantic-conventions-genai).\r\n \r\n Instrumentations following the new repository's conventions should refer to\r\n it for the corresponding `schema_url` to use.\r\n \r\n- `http`: Change `network.peer.address` attribute requirement level from Recommended to Opt-In on the `http.client.open_connections` and `http.client.connection.duration` metrics. ([#3279](https://github.com/open-telemetry/semantic-conventions/issues/3279))\r\n `network.peer.address` is typically high-cardinality (one time series per remote IP)\r\n and causes unbounded growth of metric streams over the lifetime of the process when\r\n exported with cumulative temporality (always the case for `http.client.open_connections`\r\n since it is an UpDownCounter, and possible for `http.client.connection.duration` when\r\n the histogram is configured for cumulative). Operators that need this attribute can\r\n still opt-in.\r\n \r\n- `v8js`: Rename `v8js.memory.heap.limit` to `v8js.memory.heap.space.size` (per-space pre-allocated size from `v8.getHeapSpaceStatistics()`),\r\nand add a new `v8js.memory.heap.limit` UpDownCounter representing the absolute heap size limit from `v8.getHeapStatistics().heap_size_limit`\r\n(controlled by `--max-old-space-size` or V8 defaults).\r\n ([#3476](https://github.com/open-telemetry/semantic-conventions/issues/3476))\r\n\r\n### 🚀 New components 🚀\r\n\r\n- `browser`: Introduce `browser.document.url.full` attribute and `browser.document` entity to capture the absolute URL of the current browser document. ([#174](https://github.com/open-telemetry/semantic-conventions/issues/174))\r\n The `browser.document` entity is introduced as a separate entity from `browser` because\r\n the browser runtime attributes (brands, platform, language) are immutable for the SDK\r\n lifetime, while the document URL changes on every navigation. The new attribute follows\r\n RFC3986 and has `Recommended` requirement level at `Development` stability.\r\n \r\n### 💡 Enhancements 💡\r\n\r\n- `app`: Defines a basic crash of an end-user facing app that requires a minimal amount of information. ([#3448](https://github.com/open-telemetry/semantic-conventions/issues/3448))\r\n- `cpu`: Promote `cpu.mode` attribute and its enum members to `release_candidate` ([#3694](https://github.com/open-telemetry/semantic-conventions/issues/3694))\r\n- `docs`: Add guidance for defining events in semantic conventions. ([#1855](https://github.com/open-telemetry/semantic-conventions/issues/1855))\r\n- `docs`: Don't allow signal definition to reference attributes with lower stability than the signal itself (unless they are opt-in).\r\n ([#3752](https://github.com/open-telemetry/semantic-conventions/issues/3752))\r\n- `gcp`: Add GCE instance labels as resource attributes. ([#2617](https://github.com/open-telemetry/semantic-conventions/issues/2617))\r\n- `k8s`: Promote `k8s.pod.cpu.time`, `k8s.node.cpu.time` and `container.cpu.time` metrics to `release_candidate` ([#3001](https://github.com/open-telemetry/semantic-conventions/issues/3001))\r\n- `k8s`: Add metric `k8s.container.ephemeral_storage.usage` to track ephemeral storage usage by containers. ([#3681](https://github.com/open-telemetry/semantic-conventions/issues/3681))\r\n This metric includes an attribute `k8s.container.ephemeral_storage.fs_type` to distinguish between `rootfs` and `logs` usage.\r\n \r\n- `k8s`: Promote a selection of k8s and container registry attributes to `stable` ([#3382](https://github.com/open-telemetry/semantic-conventions/issues/3382))\r\n- `otel`: Clarify semantics of SDK exporter metrics when the exporter performs retries: an export operation is considered finished only after the final attempt has concluded, items are counted exactly once per operation, and `otel.sdk.exporter.operation.duration` records one observation per operation covering all attempts and backoff. Also drop a spurious `error.type` note from the `*.inflight` metrics, which do not carry an `error.type` attribute.\r\n ([#3770](https://github.com/open-telemetry/semantic-conventions/issues/3770))\r\n- `otel`: Reserve `already_shutdown` as a value for `error.type` on the `otel.sdk.processor.span.processed` and `otel.sdk.processor.log.processed` metrics, used when a processor drops items because it has already been shut down.\r\n ([#3710](https://github.com/open-telemetry/semantic-conventions/issues/3710))\r\n- `process`: Promote process attributes to release_candidate ([#3041](https://github.com/open-telemetry/semantic-conventions/issues/3041))\r\n- `profile`: Extend the list of known frame types with a value for LuaJIT ([#3707](https://github.com/open-telemetry/semantic-conventions/issues/3707))\r\n- `service`: Mark `service.criticality` attribute as alpha. ([#2986](https://github.com/open-telemetry/semantic-conventions/issues/2986))\r\n The `service.criticality` attribute and its allowed values (`critical`, `high`, `medium`, `low`)\r\n are now in alpha status.\r\n \r\n- `system, file`: Add support for filesystem lock counts ([#3611](https://github.com/open-telemetry/semantic-conventions/issues/3611))\r\n- `v8js`: Update `v8js.gc.duration` metric to match bucket boundaries used by Node.js instrumentation. ([#3761](https://github.com/open-telemetry/semantic-conventions/issues/3761))\r\n\r\n### 🧰 Bug fixes 🧰\r\n\r\n- `browser`: remove the condition to include `user_agent.original` attribute in browser resource ([#3738](https://github.com/open-telemetry/semantic-conventions/issues/3738))\r\n- `cicd`: Consistent spelling of \"CI/CD\" throughout the CICD registry. ([#3634](https://github.com/open-telemetry/semantic-conventions/issues/3634))\r\n- `container`: Remove kernel from cpu.mode enum and clarify container cpu states ([#3700](https://github.com/open-telemetry/semantic-conventions/issues/3700))\r\n- `k8s`: Exclude `k8s.container.cpu.limit_utilization` and `k8s.container.cpu.request_utilization` metrics from code generation ([#3711](https://github.com/open-telemetry/semantic-conventions/issues/3711), [#3705](https://github.com/open-telemetry/semantic-conventions/issues/3705))\r\n\r\n\r\n## New Contributors\r\n* @mquentin made their first contribution in https://github.com/open-telemetry/semantic-conventions/pull/3633\r\n* @Hronom made their first contribution in https://github.com/open-telemetry/semantic-conventions/pull/3481\r\n* @Dipanshusinghh made their first contribution in https://github.com/open-telemetry/semantic-conventions/pull/3739\r\n* @mcollina made their first contribution in https://github.com/open-telemetry/semantic-conventions/pull/3761\r\n* @david-luna made their first contribution in https://github.com/open-telemetry/semantic-conventions/pull/3738\r\n* @Ayushi-12 made their first contribution in https://github.com/open-telemetry/semantic-conventions/pull/3781\r\n\r\n**Full Changelog**: https://github.com/open-telemetry/semantic-conventions/compare/v1.41.0...v1.42.0" }, + { + "source": "genai", + "tag": "cc93175", + "version": "2026-06-10", + "publishedAt": "2026-06-10T00:13:36Z", + "url": "https://github.com/open-telemetry/semantic-conventions-genai/commit/cc93175d71451b50cda11505a28af529a7b72244", + "body": "Limit gen_ai.agent.id to stable / static identifiers (#242)" + }, + { + "source": "genai", + "tag": "4ab2021", + "version": "2026-06-08", + "publishedAt": "2026-06-08T18:35:48Z", + "url": "https://github.com/open-telemetry/semantic-conventions-genai/commit/4ab2021c86018a2610ad8cc039fa3db2c4a4066a", + "body": "Clarify that billed token counts should be reported for Cohere usage (#211)" + }, + { + "source": "genai", + "tag": "60c5e5b", + "version": "2026-06-05", + "publishedAt": "2026-06-05T18:12:28Z", + "url": "https://github.com/open-telemetry/semantic-conventions-genai/commit/60c5e5b50607f9c9516ae02e8b04409a031a1db0", + "body": "Generalize gen_ai.provider.name description (#212)" + }, + { + "source": "genai", + "tag": "c8e9288", + "version": "2026-06-04.2", + "publishedAt": "2026-06-04T14:40:49Z", + "url": "https://github.com/open-telemetry/semantic-conventions-genai/commit/c8e928825be59b601d9f6336bba1a5c51f5f721c", + "body": "Change `gen_ai.request.top_k` type to int and split out `gen_ai.retrieval.top_k` (#217)" + }, + { + "source": "genai", + "tag": "c47252b", + "version": "2026-06-04", + "publishedAt": "2026-06-04T14:21:57Z", + "url": "https://github.com/open-telemetry/semantic-conventions-genai/commit/c47252b8048d4286095ebdad7a68b8c57eb822e9", + "body": "Relax gen_ai.provider.name on gen_ai.client.operation.duration to Conditionally Required (#214)" + }, + { + "source": "genai", + "tag": "8554a35", + "version": "2026-05-26", + "publishedAt": "2026-05-26T19:21:25Z", + "url": "https://github.com/open-telemetry/semantic-conventions-genai/commit/8554a35da2375c9afe9cdbfd626afd2f3582f620", + "body": "chore: add moonshot_ai, minimax, z_ai to well-known values (#99)" + }, { "source": "spec", "tag": "v1.57.0", @@ -73,6 +305,30 @@ "url": "https://github.com/open-telemetry/opentelemetry-specification/releases/tag/v1.57.0", "body": "### Metrics\r\n\r\n- Add in-development `Bind` API to synchronous instruments.\r\n ([#5050](https://github.com/open-telemetry/opentelemetry-specification/pull/5050))\r\n- Clarify that View-provided metric stream `name` is not subject to instrument\r\n name syntax validation.\r\n ([#5094](https://github.com/open-telemetry/opentelemetry-specification/pull/5094))\r\n\r\n### Common\r\n\r\n- Define the Core packages term.\r\n ([#5046](https://github.com/open-telemetry/opentelemetry-specification/pull/5046))\r\n- Rework contributing guide to reflect current process.\r\n ([#5072](https://github.com/open-telemetry/opentelemetry-specification/pull/5072))\r\n\r\n### Compatibility\r\n\r\n- Stabilize sections of Prometheus and OpenMetrics Compatibility.\r\n - Stabilize translation of labels prefixed with `otel_scope_` to OTLP Instrumentation Scope.\r\n ([#5004](https://github.com/open-telemetry/opentelemetry-specification/pull/5004))\r\n - Stabilize OpenTelemetry Gauge and Sum to Prometheus transformations.\r\n ([#5034](https://github.com/open-telemetry/opentelemetry-specification/pull/5034))\r\n - Stabilize OpenTelemetry Instrumentation Scope to Prometheus labels transformation.\r\n ([#5052](https://github.com/open-telemetry/opentelemetry-specification/pull/5052))\r\n- Stabilize sections of Prometheus Metrics Exporter.\r\n - Stabilize temporality.\r\n ([#5024](https://github.com/open-telemetry/opentelemetry-specification/pull/5024))\r\n - Stabilize version and format.\r\n ([#5083](https://github.com/open-telemetry/opentelemetry-specification/pull/5083))\r\n - Stabilize port configuration.\r\n ([#5026](https://github.com/open-telemetry/opentelemetry-specification/pull/5026))\r\n - Stabilize `scope_info_enabled` configuration.\r\n ([#5056](https://github.com/open-telemetry/opentelemetry-specification/pull/5056))\r\n- Change Prometheus Metric Exporter config property recommended names\r\n (`without_scope_info` -> `scope_info_enabled`, `without_target_info` -> `target_info_enabled`,\r\n `with_resource_constant_labels` -> `resource_constant_labels`)\r\n ([#5071](https://github.com/open-telemetry/opentelemetry-specification/pull/5071))\r\n- Clarify that OTel SDKs should not use unofficial Prometheus clients.\r\n ([#5082](https://github.com/open-telemetry/opentelemetry-specification/pull/5082))\r\n\r\n### OTEPs\r\n\r\n- Add OTEP for Semantic Convention Schema v2 with support for multiple convention\r\n registries and resolved schema format\r\n ([#4815](https://github.com/open-telemetry/opentelemetry-specification/pull/4815))" }, + { + "source": "genai", + "tag": "be551f8", + "version": "2026-05-19", + "publishedAt": "2026-05-19T16:31:21Z", + "url": "https://github.com/open-telemetry/semantic-conventions-genai/commit/be551f816a53c893e9af7234bf30394d01876dd1", + "body": "Add GenAI memory operation conventions (#140)" + }, + { + "source": "genai", + "tag": "0bcb478", + "version": "2026-05-18", + "publishedAt": "2026-05-18T20:41:15Z", + "url": "https://github.com/open-telemetry/semantic-conventions-genai/commit/0bcb478696640451ab799f718298cf79a2d9a598", + "body": "Remove pre-release deprecated conventions (#167)" + }, + { + "source": "genai", + "tag": "8508fbf", + "version": "2026-05-16", + "publishedAt": "2026-05-16T22:13:57Z", + "url": "https://github.com/open-telemetry/semantic-conventions-genai/commit/8508fbfa5189ae50c7e95aa2fcd90c5c4998cbc7", + "body": "fix(mcp): add tool.call.arguments and tool.call.result to server span (#136)" + }, { "source": "semconv", "tag": "v1.41.1", @@ -81,6 +337,62 @@ "url": "https://github.com/open-telemetry/semantic-conventions/releases/tag/v1.41.1", "body": "## What's Changed\r\n* Exclude `k8s.container.cpu.limit_utilization` and `k8s.container.cpu.request_utilization` metrics from code generation (https://github.com/open-telemetry/semantic-conventions/issues/3711)\r\n\r\n\r\n**Full Changelog**: https://github.com/open-telemetry/semantic-conventions/compare/v1.41.0...v1.41.1" }, + { + "source": "genai", + "tag": "debdd77", + "version": "2026-05-11.2", + "publishedAt": "2026-05-11T18:03:15Z", + "url": "https://github.com/open-telemetry/semantic-conventions-genai/commit/debdd770b8c0da9c814a495d55a1f678b5d34e4c", + "body": "Add workflow duration metric (#126)" + }, + { + "source": "genai", + "tag": "d886ba6", + "version": "2026-05-11", + "publishedAt": "2026-05-11T02:47:47Z", + "url": "https://github.com/open-telemetry/semantic-conventions-genai/commit/d886ba674f225eff14829e8046ded54e08d9f282", + "body": "gen-ai: add plan operation for agent planning spans (#97)" + }, + { + "source": "genai", + "tag": "a49a1a3", + "version": "2026-05-08", + "publishedAt": "2026-05-08T19:11:59Z", + "url": "https://github.com/open-telemetry/semantic-conventions-genai/commit/a49a1a336bd23add59476ab9507e255a94a6e08b", + "body": "Add `agent.name` sampling (#107)" + }, + { + "source": "genai", + "tag": "fd074ca", + "version": "2026-05-05.3", + "publishedAt": "2026-05-05T04:02:12Z", + "url": "https://github.com/open-telemetry/semantic-conventions-genai/commit/fd074ca60142b45576cf5b99933e6d00c5511f13", + "body": "Simplify Weaver schema v2 model" + }, + { + "source": "genai", + "tag": "773a3fd", + "version": "2026-05-05.4", + "publishedAt": "2026-05-05T04:02:12Z", + "url": "https://github.com/open-telemetry/semantic-conventions-genai/commit/773a3fd9be56f15fa75af07e67e01e79f97e492e", + "body": "Preserve gen_ai.output.type refinement notes" + }, + { + "source": "genai", + "tag": "ebe3d1f", + "version": "2026-05-05", + "publishedAt": "2026-05-05T03:53:12Z", + "url": "https://github.com/open-telemetry/semantic-conventions-genai/commit/ebe3d1fb9fdda3398099e11ef91c4c490912f88d", + "body": "Prepare standalone GenAI semantic conventions repo" + }, + { + "source": "genai", + "tag": "07bbdbe", + "version": "2026-05-05.2", + "publishedAt": "2026-05-05T03:53:12Z", + "url": "https://github.com/open-telemetry/semantic-conventions-genai/commit/07bbdbe4cc49df064953d73d052d165e6c3bbb4a", + "body": "Convert GenAI semantic conventions to Weaver schema v2" + }, { "source": "semconv", "tag": "v1.41.0", diff --git a/data/semconv/1.30.0.json.gz b/data/semconv/1.30.0.json.gz index bb3687b..0a4cba0 100644 Binary files a/data/semconv/1.30.0.json.gz and b/data/semconv/1.30.0.json.gz differ diff --git a/data/semconv/1.31.0.json.gz b/data/semconv/1.31.0.json.gz index 4084fe7..168ddae 100644 Binary files a/data/semconv/1.31.0.json.gz and b/data/semconv/1.31.0.json.gz differ diff --git a/data/semconv/1.32.0.json.gz b/data/semconv/1.32.0.json.gz index 3282f25..1d6b28e 100644 Binary files a/data/semconv/1.32.0.json.gz and b/data/semconv/1.32.0.json.gz differ diff --git a/data/semconv/1.33.0.json.gz b/data/semconv/1.33.0.json.gz index e779e85..aee60e0 100644 Binary files a/data/semconv/1.33.0.json.gz and b/data/semconv/1.33.0.json.gz differ diff --git a/data/semconv/1.34.0.json.gz b/data/semconv/1.34.0.json.gz index fa49dd7..77bd803 100644 Binary files a/data/semconv/1.34.0.json.gz and b/data/semconv/1.34.0.json.gz differ diff --git a/data/semconv/1.35.0.json.gz b/data/semconv/1.35.0.json.gz index ebf5990..7c77d99 100644 Binary files a/data/semconv/1.35.0.json.gz and b/data/semconv/1.35.0.json.gz differ diff --git a/data/semconv/1.36.0.json.gz b/data/semconv/1.36.0.json.gz index 0c06d68..f84103c 100644 Binary files a/data/semconv/1.36.0.json.gz and b/data/semconv/1.36.0.json.gz differ diff --git a/data/semconv/1.37.0.json.gz b/data/semconv/1.37.0.json.gz index 333e2cf..f68396b 100644 Binary files a/data/semconv/1.37.0.json.gz and b/data/semconv/1.37.0.json.gz differ diff --git a/data/semconv/1.38.0.json.gz b/data/semconv/1.38.0.json.gz index 53c27aa..64363c9 100644 Binary files a/data/semconv/1.38.0.json.gz and b/data/semconv/1.38.0.json.gz differ diff --git a/data/semconv/1.39.0.json.gz b/data/semconv/1.39.0.json.gz index b9a9c59..8a08104 100644 Binary files a/data/semconv/1.39.0.json.gz and b/data/semconv/1.39.0.json.gz differ diff --git a/data/semconv/1.40.0.json.gz b/data/semconv/1.40.0.json.gz index 448b404..32f4902 100644 Binary files a/data/semconv/1.40.0.json.gz and b/data/semconv/1.40.0.json.gz differ diff --git a/data/semconv/1.41.0.json.gz b/data/semconv/1.41.0.json.gz index 26c051c..5edd2cd 100644 Binary files a/data/semconv/1.41.0.json.gz and b/data/semconv/1.41.0.json.gz differ diff --git a/data/semconv/1.41.1.json.gz b/data/semconv/1.41.1.json.gz index 78ac518..0aa316c 100644 Binary files a/data/semconv/1.41.1.json.gz and b/data/semconv/1.41.1.json.gz differ diff --git a/data/semconv/1.42.0.json.gz b/data/semconv/1.42.0.json.gz index 74dca58..80bb5d5 100644 Binary files a/data/semconv/1.42.0.json.gz and b/data/semconv/1.42.0.json.gz differ diff --git a/data/semconv/1.43.0.json.gz b/data/semconv/1.43.0.json.gz index 64b79a6..02f9a6a 100644 Binary files a/data/semconv/1.43.0.json.gz and b/data/semconv/1.43.0.json.gz differ diff --git a/data/semconv/1.44.0.json.gz b/data/semconv/1.44.0.json.gz index 06fb17b..1b75d87 100644 Binary files a/data/semconv/1.44.0.json.gz and b/data/semconv/1.44.0.json.gz differ diff --git a/package.json b/package.json index a182adb..0d847bd 100644 --- a/package.json +++ b/package.json @@ -5,7 +5,7 @@ "scripts": { "ingest": "bun run src/ingest/main.ts", "test": "bun test", - "typecheck": "tsc --noEmit", + "typecheck": "tsc --noEmit && astro check", "dev": "astro dev --port 4321", "build": "astro build", "preview": "astro preview --port 4321", @@ -24,6 +24,7 @@ "yaml": "^2.8.1" }, "devDependencies": { + "@astrojs/check": "^0.9.10", "@cloudflare/workers-types": "^5.20260903.1", "@types/bun": "^1.3.11", "typescript": "^5.9.3", diff --git a/site/lib/format.ts b/site/lib/format.ts index d1fc876..ccf3911 100644 --- a/site/lib/format.ts +++ b/site/lib/format.ts @@ -88,6 +88,7 @@ const KIND_LABEL: Record = { "brief-changed": "wording", "note-changed": "guidance", "examples-changed": "examples", + "usage-changed": "usage", "first-seen": "added", "requirement-added": "new rule", "requirement-removed": "rule dropped", diff --git a/site/pages/about.astro b/site/pages/about.astro index 531dd06..7bbdd16 100644 --- a/site/pages/about.astro +++ b/site/pages/about.astro @@ -43,7 +43,10 @@ const data = await catalog() The GenAI conventions are the same registry model in a separate repository, split out of the conventions in v1.44.0. That repository has never cut a release — no tags, a changelog reading only "Unreleased" — so it is tracked from its default branch, - dated rather than versioned, and marked unreleased everywhere it appears. + dated rather than versioned, and marked unreleased everywhere it appears. Its history is the + commits themselves: every commit touching the model tree is normalized, and the ones that + leave the model unchanged — a tooling bump, a link pin — are dropped rather than + published as a release with nothing in it.

The split leaves roughly 59 attributes in both registries at once: deprecated @@ -91,8 +94,12 @@ const data = await catalog()

  • History starts at semantic conventions v{data.semconv.versions.at(-1)}, specification v{data.spec.versions.at(-1)} and OTLP v{data.proto.versions.at(-1)}. Anything described as - first seen there may be much older. The GenAI registry has no history at all yet — - tracking began {data.genai.versions.at(-1)}. + first seen there may be much older. The GenAI registry is walked commit by commit from + {" "}{data.genai.versions.at(-1)}, the point at which it became a repository of its own; + one commit earlier its filtered history still carries the 52 aws.* attributes the split dropped, and reading across that boundary would report 52 removals + the project never made.
  • Specification changes are tracked as requirements, not as prose diffs. A paragraph rewritten diff --git a/site/pages/diff.astro b/site/pages/diff.astro index 22c45dc..467fd1a 100644 --- a/site/pages/diff.astro +++ b/site/pages/diff.astro @@ -75,6 +75,9 @@ const defaults = Object.fromEntries( const summary = document.getElementById("summary") as HTMLElement const out = document.getElementById("out") as HTMLElement + /** Mirrors `versionLabel`: a dated, untagged source has no `v` to prefix. */ + const label = (version: string) => (version.includes("-") ? version : `v${version}`) + const versions = JSON.parse(form.dataset["versions"] ?? "{}") as Record const defaults = JSON.parse(form.dataset["defaults"] ?? "{}") as Record @@ -85,7 +88,7 @@ const defaults = Object.fromEntries( function fillVersions(preferred?: { from: string; to: string }) { const list = versions[sourceSelect.value] ?? [] for (const select of [fromSelect, toSelect]) { - select.innerHTML = list.map((v) => ``).join("") + select.innerHTML = list.map((v) => ``).join("") } const fallback = defaults[sourceSelect.value] ?? { from: list[0] ?? "", to: list.at(-1) ?? "" } fromSelect.value = preferred?.from && list.includes(preferred.from) ? preferred.from : fallback.from @@ -132,7 +135,7 @@ const defaults = Object.fromEntries( // naming rather than a 404. const list = versions[source] ?? [] if (list.indexOf(from) > list.indexOf(to)) { - summary.textContent = `v${from} is newer than v${to} — swap them to see what changed.` + summary.textContent = `${label(from)} is newer than ${label(to)} — swap them to see what changed.` out.innerHTML = "" return } @@ -144,7 +147,7 @@ const defaults = Object.fromEntries( if (!diff) { const response = await fetch(`/api/diff/${key}.json`) if (!response.ok) { - summary.textContent = `No diff available for v${from} to v${to}.` + summary.textContent = `No diff available for ${label(from)} to ${label(to)}.` out.innerHTML = "" return } diff --git a/site/pages/feed.xml.ts b/site/pages/feed.xml.ts index a7043a3..e3bf4a9 100644 --- a/site/pages/feed.xml.ts +++ b/site/pages/feed.xml.ts @@ -1,5 +1,6 @@ import type { APIRoute } from "astro" -import { catalog, SOURCE_LABEL } from "../../src/model/catalog.ts" +import { catalog, SOURCE_LABEL, UNRELEASED } from "../../src/model/catalog.ts" +import { versionLabel } from "../lib/format.ts" import { SITE } from "../lib/site.ts" const escape = (s: string) => @@ -9,27 +10,33 @@ export const GET: APIRoute = async ({ site }) => { const data = await catalog() const origin = site?.origin ?? SITE.origin - const items = data.feed.map(({ source, version, diff, release }) => { - const significant = diff.changes.filter((c) => c.severity !== "informational") - const lines = significant - .slice(0, 30) - .map((c) => `${c.severity.toUpperCase()} · ${c.entity} ${c.kind} · ${c.id} — ${c.detail}`) - const body = [ - `${diff.counts.breaking} breaking, ${diff.counts.notable} notable, ${diff.counts.informational} editorial changes since v${diff.from}.`, - ...lines, - significant.length > 30 ? `…and ${significant.length - 30} more.` : "", - ] - .filter(Boolean) - .join("\n") + const items = data.feed + .filter( + // Same rule as the front page: a subscriber wants releases and the + // commits that changed something, not every wording fix on a branch. + ({ source, diff }) => !UNRELEASED[source] || diff.changes.some((c) => c.severity !== "informational"), + ) + .map(({ source, version, diff, release }) => { + const significant = diff.changes.filter((c) => c.severity !== "informational") + const lines = significant + .slice(0, 30) + .map((c) => `${c.severity.toUpperCase()} · ${c.entity} ${c.kind} · ${c.id} — ${c.detail}`) + const body = [ + `${diff.counts.breaking} breaking, ${diff.counts.notable} notable, ${diff.counts.informational} editorial changes since ${versionLabel(diff.from)}.`, + ...lines, + significant.length > 30 ? `…and ${significant.length - 30} more.` : "", + ] + .filter(Boolean) + .join("\n") - return ` - ${SOURCE_LABEL[source]} v${version} — ${diff.counts.breaking} breaking, ${diff.counts.notable} notable + return ` + ${SOURCE_LABEL[source]} ${versionLabel(version)} — ${diff.counts.breaking} breaking, ${diff.counts.notable} notable ${origin}/releases/${source}/${version} ${origin}/releases/${source}/${version} ${new Date(release?.publishedAt ?? Date.now()).toUTCString()} ${escape(body)} ` - }) + }) const xml = ` diff --git a/site/pages/index.astro b/site/pages/index.astro index 10afc27..3e6ab12 100644 --- a/site/pages/index.astro +++ b/site/pages/index.astro @@ -8,7 +8,7 @@ import { formatDate, severityClass, versionLabel } from "../lib/format.ts" import { SITE } from "../lib/site.ts" const data = await catalog() -const linkable = new Set(data.attributes.map((a) => a.id)) +const linkable = data.linkableAttributes const requirements = data.spec.latest.sections.reduce((n, section) => n + section.normative.length, 0) @@ -49,10 +49,18 @@ const domains = buildDomains(data).map((domain) => ({ signals: domain.metrics.length + domain.spans.length + domain.events.length + domain.entities.length, })) -const feed = data.feed.map((entry) => ({ - ...entry, - significant: entry.diff.changes.filter((c) => c.severity !== "informational"), -})) +/** + * An untagged source moves by commit rather than by release, so its editorial + * churn — a reworded brief, a new example — is not front-page news, and forty + * consecutive rows of it would bury every tagged release under the fold. Those + * entries keep their own page and stay reachable from the neighbouring ones. + */ +const feed = data.feed + .map((entry) => ({ + ...entry, + significant: entry.diff.changes.filter((c) => c.severity !== "informational"), + })) + .filter((entry) => !UNRELEASED[entry.source] || entry.significant.length > 0) --- @@ -158,10 +166,12 @@ const feed = data.feed.map((entry) => ({ {significant.length > 6 ? `All ${significant.length} notable changes` - : `Full diff from v${diff.from}`} + : `Full diff from ${versionLabel(diff.from)}`} {diff.counts.informational > 0 && ` + ${diff.counts.informational} editorial`} - {release && Upstream release notes} + {release && ( + {UNRELEASED[source] ? "Upstream commit" : "Upstream release notes"} + )}

    )) diff --git a/site/pages/releases/[source]/[version].astro b/site/pages/releases/[source]/[version].astro index dcfb931..9521b1f 100644 --- a/site/pages/releases/[source]/[version].astro +++ b/site/pages/releases/[source]/[version].astro @@ -2,7 +2,7 @@ import ChangeList from "../../../components/ChangeList.astro" import Pill from "../../../components/Pill.astro" import Shell from "../../../layouts/Shell.astro" -import { catalog, SOURCES, SOURCE_LABEL } from "../../../../src/model/catalog.ts" +import { catalog, SOURCES, SOURCE_LABEL, UNRELEASED } from "../../../../src/model/catalog.ts" import type { Severity } from "../../../../src/model/change.ts" import type { SourceId } from "../../../../src/model/types.ts" import { formatDate, SEVERITY_LABEL, severityClass, versionLabel } from "../../../lib/format.ts" @@ -19,7 +19,14 @@ const data = await catalog() const catalogue = data.source(source) const release = catalogue.release(diff.to) -const linkable = new Set(data.attributes.map((a) => a.id)) +/** + * What upstream calls this snapshot. A tagged source's release tag is `v1.44.0`, + * but an untagged one is dated — `v2026-09-01` names no ref, and every deep link + * built from it 404s. The commit SHA the record carries is the tree the snapshot + * was actually read from. + */ +const upstreamTag = release?.tag ?? `v${diff.to}` +const linkable = data.linkableAttributes const index = catalogue.diffs.findIndex((d) => d.to === diff.to) const newer = index > 0 ? catalogue.diffs[index - 1] : undefined const older = catalogue.diffs[index + 1] @@ -32,6 +39,10 @@ const BREAKING_BLURB: Record = { semconv: "Changes to definitions the project had already marked stable or release candidate.", spec: "Requirements added to, removed from, or restrengthened in a document marked Stable.", proto: "Changes to a released wire definition. Development packages are ranked notable instead.", + // Never rendered in practice: the GenAI registry is development throughout, so + // nothing in it can rank breaking. Kept so the promise is written down rather + // than implied by an absent key. + genai: "Changes to definitions already marked stable or release candidate.", } /** @@ -41,25 +52,38 @@ const BREAKING_BLURB: Record = { * because they enumerate the same renames our own diff already lists, and the * trailing issue references are noise at this size. */ -const upstreamBullets = (release?.body ?? "") - .split("\n") - .filter((line) => line.startsWith("- ")) - .map((line) => - line - .slice(2) - .replace(/\[([^\]]+)\]\([^)]*\)/g, "$1") - .replace(/\s*\(#\d+\)\s*$/, "") - .replace(/`/g, "") - .replace(/\s+/g, " ") - .trim(), - ) +const clean = (line: string) => + line + .replace(/\[([^\]]+)\]\([^)]*\)/g, "$1") + .replace(/\s*\(#\d+\)\s*$/, "") + .replace(/`/g, "") + .replace(/\s+/g, " ") + .trim() + +const body = release?.body ?? "" + +/** + * An untagged source has no release notes to lift from: its record carries the + * commit subject instead, which is the one sentence its author wrote about the + * change and worth the same box. + */ +const untagged = UNRELEASED[source] === true + +const upstreamBullets = ( + untagged + ? [clean(body)] + : body + .split("\n") + .filter((line) => line.startsWith("- ")) + .map((line) => clean(line.slice(2))) +) .filter((line) => line.length > 0) .slice(0, 10) --- @@ -93,7 +117,7 @@ const upstreamBullets = (release?.body ?? "") upstreamBullets.length > 0 && (

    - From the upstream release notes + {untagged ? "From the upstream commit" : "From the upstream release notes"}

      {upstreamBullets.map((line) => ( @@ -102,7 +126,7 @@ const upstreamBullets = (release?.body ?? "")
    {release && (

    - Read the full release notes + {untagged ? "Read the commit" : "Read the full release notes"}

    )}
    @@ -120,7 +144,7 @@ const upstreamBullets = (release?.body ?? "")

    {BREAKING_BLURB[source]}

    )}
    - +
    )) diff --git a/src/ingest/github.ts b/src/ingest/github.ts index 23798a3..e0e2fd2 100644 --- a/src/ingest/github.ts +++ b/src/ingest/github.ts @@ -24,8 +24,28 @@ export const REPOS: Record = { * for a tag would mean tracking nothing, and the attributes are already in * production use — so the branch is tracked, dated rather than versioned, and * labelled as unreleased everywhere it appears. + * + * `path` is the only tree the normalizer reads, so a commit that does not touch + * it cannot change the model: filtering on it turns thousands of documentation + * commits into the few dozen worth normalizing. + * + * `floor` is the horizon, and it is not cosmetic. The repository was created by + * filtering the semantic-conventions history, so one commit below `ebe3d1f` + * ("Prepare standalone GenAI semantic conventions repo") the tree still carries + * the 52 `aws.*` attributes the standalone repo dropped. Walking across that + * boundary would report 52 removals the project never made. Everything older is + * already covered by the tagged semantic-conventions snapshots, which carried + * `gen_ai.*` until v1.44.0 deprecated it in place. */ -export const UNTAGGED: Partial> = { genai: "main" } +export interface UntaggedSource { + readonly branch: string + readonly path: string + readonly floor: string +} + +export const UNTAGGED: Partial> = { + genai: { branch: "main", path: "model", floor: "ebe3d1f" }, +} /** * Unauthenticated GitHub is 60 requests/hour, which a full backfill blows through @@ -87,41 +107,75 @@ export const listReleases = (source: SourceId): Effect.Effect => +export const listCommits = (source: SourceId, untagged: UntaggedSource): Effect.Effect => Effect.gen(function* () { const repo = REPOS[source] const client = yield* HttpClient.HttpClient - const response = yield* client - .execute( - HttpClientRequest.get(`https://api.github.com/repos/${repo}/commits/${branch}`).pipe( - HttpClientRequest.setHeaders(authHeaders()), - ), + const out: ReleaseRecord[] = [] + let reachedFloor = false + + for (let page = 1; page <= 10 && !reachedFloor; page++) { + const response = yield* client + .execute( + HttpClientRequest.get(`https://api.github.com/repos/${repo}/commits`).pipe( + HttpClientRequest.setHeaders(authHeaders()), + HttpClientRequest.setUrlParams({ + sha: untagged.branch, + path: untagged.path, + per_page: "100", + page: String(page), + }), + ), + ) + .pipe(Effect.retry(retry)) + + // biome-ignore lint: GitHub's commit shape, narrowed immediately below. + const body = (yield* response.json) as any[] + if (!Array.isArray(body) || body.length === 0) break + + for (const c of body) { + const sha = String(c.sha) + const tag = sha.slice(0, 7) + const date = String(c.commit?.committer?.date ?? c.commit?.author?.date ?? "") + if (!date) return yield* Effect.fail(new UpstreamError({ repo, detail: `commit ${tag} has no date` })) + + out.push({ + source, + tag, + // Dated, not versioned: there is nothing to version against. + version: date.slice(0, 10), + publishedAt: date, + url: `https://github.com/${repo}/commit/${sha}`, + body: String(c.commit?.message ?? "").split("\n")[0] ?? "", + }) + + if (sha.startsWith(untagged.floor)) { + reachedFloor = true + break + } + } + if (body.length < 100) break + } + + if (!reachedFloor) { + return yield* Effect.fail( + new UpstreamError({ repo, detail: `floor commit ${untagged.floor} not reached within 10 pages of ${untagged.path}` }), ) - .pipe(Effect.retry(retry)) - - // biome-ignore lint: GitHub's commit shape, narrowed immediately below. - const commit = (yield* response.json) as any - const sha = String(commit.sha) - const date = String(commit.commit?.committer?.date ?? commit.commit?.author?.date) - if (!sha || !date) return yield* Effect.fail(new UpstreamError({ repo, detail: `no head commit on ${branch}` })) - - return { - source, - tag: sha.slice(0, 7), - // Dated, not versioned: there is nothing to version against. - version: date.slice(0, 10), - publishedAt: date, - url: `https://github.com/${repo}/commits/${branch}`, - body: "", } + + return out.reverse() }).pipe( Effect.provide(FetchHttpClient.layer), Effect.mapError((cause) => - cause instanceof UpstreamError ? cause : new UpstreamError({ repo: REPOS[source], detail: "head lookup failed", cause }), + cause instanceof UpstreamError ? cause : new UpstreamError({ repo: REPOS[source], detail: "commit listing failed", cause }), ), ) @@ -132,7 +186,7 @@ export const headOfBranch = (source: SourceId, branch: string): Effect.Effect => Effect.gen(function* () { const repo = REPOS[source] - // A 40-char hex tag is a commit from an untagged source, not a release. + // A hex tag is a commit from an untagged source, not a release. const ref = /^[0-9a-f]{7,40}$/.test(tag) ? tag : `refs/tags/${tag}` const url = `https://codeload.github.com/${repo}/tar.gz/${ref}` const dir = `${into}/${source}-${tag}` diff --git a/src/ingest/main.ts b/src/ingest/main.ts index 726b518..d407f32 100644 --- a/src/ingest/main.ts +++ b/src/ingest/main.ts @@ -1,77 +1,148 @@ import { Effect } from "effect" -import type { ReleaseRecord, SourceId } from "../model/types.ts" -import { fetchTag, headOfBranch, listReleases, UNTAGGED } from "./github.ts" +import { diffProto } from "../model/diff-proto.ts" +import { diffSpec } from "../model/diff-spec.ts" +import { diffSemconv } from "../model/diff.ts" +import type { ReleaseRecord, Snapshot, SourceId } from "../model/types.ts" +import { fetchTag, listCommits, listReleases, UNTAGGED } from "./github.ts" import { normalizeProto } from "./proto.ts" import { normalizeSemconv } from "./semconv.ts" import { normalizeSpec } from "./spec.ts" -import { compareVersions, hasSnapshot, listSnapshots, readSnapshot, writeIndex, writeSnapshot } from "./store.ts" +import { + clearSnapshots, + compareVersions, + hasSnapshot, + listSnapshots, + readSnapshot, + writeIndex, + writeSnapshot, +} from "./store.ts" /** * Backfill floors. Older releases use a model schema different enough that * normalizing them would produce misleading diffs — better to have a hard, - * documented horizon than a subtly wrong one. + * documented horizon than a subtly wrong one. Untagged sources carry their own + * floor as a commit SHA; see `UNTAGGED`. */ const FLOOR: Partial> = { semconv: "1.30.0", spec: "1.42.0", proto: "1.4.0" } const CACHE = "/tmp/otel-spec-tracker" +// biome-ignore lint: each differ is typed to its own snapshot; the map is not. +const DIFFERS = { semconv: diffSemconv, genai: diffSemconv, spec: diffSpec, proto: diffProto } as unknown as Record< + SourceId, + (a: any, b: any) => { changes: readonly unknown[] } +> + +const normalize = (source: SourceId, root: string, meta: { tag: string; version: string; publishedAt: string }) => + Effect.promise(async () => { + switch (source) { + case "genai": + case "semconv": { + const snapshot = { ...(await normalizeSemconv(root, meta)), source } + return { + snapshot: snapshot as Snapshot, + summary: `${snapshot.attributes.length} attributes, ${snapshot.metrics.length} metrics, ${snapshot.signals.length} signals`, + } + } + case "spec": { + const snapshot = await normalizeSpec(root, meta) + const statements = snapshot.sections.reduce((n, section) => n + section.normative.length, 0) + return { + snapshot: snapshot as Snapshot, + summary: `${snapshot.documents.length} documents, ${snapshot.sections.length} sections, ${statements} requirements`, + } + } + case "proto": { + const snapshot = await normalizeProto(root, meta) + const statements = snapshot.sections.reduce((n, section) => n + section.normative.length, 0) + return { snapshot: snapshot as Snapshot, summary: `${snapshot.messages.length} messages, ${statements} protocol requirements` } + } + } + }) + const ingest = (source: SourceId, release: ReleaseRecord) => Effect.gen(function* () { const root = yield* fetchTag(source, release.tag, CACHE) const meta = { tag: release.tag, version: release.version, publishedAt: release.publishedAt } + const { snapshot, summary } = yield* normalize(source, root, meta) - const { snapshot, summary } = yield* Effect.promise(async () => { - switch (source) { - case "genai": - case "semconv": { - const s = { ...(await normalizeSemconv(root, meta)), source } - return { - snapshot: s, - summary: `${s.attributes.length} attributes, ${s.metrics.length} metrics, ${s.signals.length} signals`, - } - } - case "spec": { - const s = await normalizeSpec(root, meta) - const statements = s.sections.reduce((n, section) => n + section.normative.length, 0) - return { - snapshot: s, - summary: `${s.documents.length} documents, ${s.sections.length} sections, ${statements} requirements`, - } - } - case "proto": { - const s = await normalizeProto(root, meta) - const statements = s.sections.reduce((n, section) => n + section.normative.length, 0) - return { - snapshot: s, - summary: `${s.messages.length} messages, ${statements} protocol requirements`, - } - } - } - }) + yield* Effect.promise(() => writeSnapshot(snapshot)) + yield* Effect.log(`${source} ${release.version} (${release.tag}): ${summary}`) + }) + +/** + * Walks an untagged source's commit history, keeping the commits that actually + * moved the model. + * + * Two things make this different from ingesting a tagged release. The first is + * that most commits change nothing a reader cares about — a Weaver bump, a link + * pin, a reflowed brief — so a candidate is kept only when the differ finds + * something in it. Comparing normalized JSON instead would be stricter than the + * differ and publish release pages listing no changes at all. + * + * The second is versioning. A commit is dated, not numbered, and upstream + * merges several model changes on a busy day; the second of them takes + * `2026-05-05.2` so it neither overwrites the first snapshot nor claims its + * version. The suffix sorts after the bare date under `compareVersions`, which + * splits on both separators. + */ +const ingestUntagged = (source: SourceId, commits: readonly ReleaseRecord[], force: boolean) => + Effect.gen(function* () { + const differ = DIFFERS[source] + const kept: ReleaseRecord[] = [] + + const onDisk = yield* Effect.promise(() => listSnapshots(source)) + let previous: Snapshot | undefined = onDisk[0] ? yield* Effect.promise(() => readSnapshot(source, onDisk[0] as string)) : undefined + + const taken = new Set(onDisk) + const versionFor = (date: string) => { + if (!taken.has(date)) return date + for (let n = 2; ; n++) if (!taken.has(`${date}.${n}`)) return `${date}.${n}` + } /** - * An untagged source is re-read from its branch on every run, so most days - * produce a snapshot identical to the last one. Comparing content — not - * dates — is what keeps `data/` proportional to real change rather than to - * the calendar. + * The walk always starts at the floor, so the daily run would otherwise + * re-fetch four dozen trees to reach the two commits that are new. The + * newest snapshot names the commit it came from, and everything up to and + * including that commit was decided on an earlier run. + * + * Deliberately the commit's position rather than its date: two commits + * pushed together carry the same committer timestamp — `ebe3d1f` and + * `07bbdbe` do — and a date watermark would skip the second of them for + * good. The timestamp is only the fallback for a snapshot whose commit is + * no longer in the window at all. */ - if (UNTAGGED[source]) { - const previous = (yield* Effect.promise(() => listSnapshots(source)))[0] - if (previous) { - const before = yield* Effect.promise(() => readSnapshot(source, previous)) - const identical = (a: object, b: object) => - JSON.stringify({ ...a, version: "", tag: "", publishedAt: "" }) === - JSON.stringify({ ...b, version: "", tag: "", publishedAt: "" }) - if (identical(before, snapshot)) { - yield* Effect.log(`${source}: no model change since ${previous}`) - return false - } + const resumeAt = previous ? commits.findIndex((c) => c.tag === previous?.tag) : -1 + + for (const [position, commit] of commits.entries()) { + if (!force && previous) { + if (resumeAt >= 0 ? position <= resumeAt : commit.publishedAt <= previous.publishedAt) continue } + + const root = yield* fetchTag(source, commit.tag, CACHE) + const { snapshot, summary } = yield* normalize(source, root, { + tag: commit.tag, + version: commit.version, + publishedAt: commit.publishedAt, + }) + yield* Effect.promise(() => Bun.$`rm -rf ${root}`.quiet()) + + if (previous && differ(previous, snapshot).changes.length === 0) { + yield* Effect.log(`${source}: ${commit.version} (${commit.tag}) leaves the model unchanged`) + continue + } + + const version = versionFor(commit.version) + taken.add(version) + const written = { ...snapshot, version } + yield* Effect.promise(() => writeSnapshot(written)) + yield* Effect.log(`${source} ${version} (${commit.tag}): ${summary}`) + + previous = written + kept.push({ ...commit, version }) } - yield* Effect.promise(() => writeSnapshot(snapshot)) - yield* Effect.log(`${source} ${release.version} (${release.tag}): ${summary}`) - return true + return kept }) const program = Effect.gen(function* () { @@ -80,17 +151,26 @@ const program = Effect.gen(function* () { const sources: SourceId[] = (only.length > 0 ? only : ["semconv", "spec", "proto", "genai"]) as SourceId[] const allReleases: ReleaseRecord[] = [] + const rewalked: SourceId[] = [] for (const source of sources) { - const branch = UNTAGGED[source] - - if (branch) { - const head = yield* headOfBranch(source, branch) - yield* Effect.log(`${source}: untagged, tracking ${branch} at ${head.tag} (${head.version})`) - const wrote = yield* ingest(source, head) - // Only record the pseudo-release when its snapshot was actually kept, - // or the index would claim a version that has no data behind it. - if (wrote) allReleases.push(head) + const untagged = UNTAGGED[source] + + if (untagged) { + const commits = yield* listCommits(source, untagged) + yield* Effect.log( + `${source}: untagged, ${commits.length} commits touching ${untagged.path} since ${untagged.floor} on ${untagged.branch}`, + ) + // A forced re-walk re-derives the whole history, so the old snapshots go + // first: which commits produce a distinct model is exactly what a changed + // normalizer changes. + if (force) { + yield* Effect.promise(() => clearSnapshots(source)) + rewalked.push(source) + } + // Only commits whose snapshot was kept are recorded, or the index would + // claim versions that have no data behind them. + allReleases.push(...(yield* ingestUntagged(source, commits, force))) continue } @@ -105,7 +185,7 @@ const program = Effect.gen(function* () { } } - yield* Effect.promise(() => writeIndex(allReleases)) + yield* Effect.promise(() => writeIndex(allReleases, rewalked)) yield* Effect.log("index written") }) diff --git a/src/ingest/semconv.ts b/src/ingest/semconv.ts index 3187ace..c6495eb 100644 --- a/src/ingest/semconv.ts +++ b/src/ingest/semconv.ts @@ -250,7 +250,19 @@ export async function normalizeSemconv( const refs = resolveRefs(group.id) const attributeIds = [...new Set(refs.map((r) => text(r.ref)).filter(Boolean))].sort() - for (const ref of refs) { + /** + * A group can reference the same attribute twice: once inherited through + * `ref_group` / `extends`, once in its own list to override the inherited + * requirement level. `resolveRefs` returns inherited refs first, so the + * last occurrence is the effective one — and collapsing to it is what + * makes the override visible. Keeping both wrote `gen_ai.provider.name` as + * required *and* conditionally required on the same metric, and left a + * relaxation upstream announced in a commit subject invisible to the diff. + */ + const effective = new Map() + for (const ref of refs) effective.set(text(ref.ref), ref) + + for (const ref of effective.values()) { const target = attributes.get(text(ref.ref)) if (!target) continue target.usedBy.push({ diff --git a/src/ingest/store.ts b/src/ingest/store.ts index 197a7b3..49db480 100644 --- a/src/ingest/store.ts +++ b/src/ingest/store.ts @@ -1,4 +1,4 @@ -import { mkdir, readdir, readFile, writeFile } from "node:fs/promises" +import { mkdir, readdir, readFile, rm, writeFile } from "node:fs/promises" import { dirname } from "node:path" import { gunzipSync, gzipSync } from "node:zlib" import type { DataIndex, ReleaseRecord, SemconvSnapshot, Snapshot, SourceId } from "../model/types.ts" @@ -94,13 +94,33 @@ export async function readIndex(): Promise { * Merges new release records into the index. `generatedAt` deliberately tracks * the newest release rather than wall-clock time - a re-run that finds nothing * new must not produce a diff. + * + * `replace` drops a source's existing records first, for the one case where + * merging is wrong: a forced re-walk of an untagged source decides afresh which + * commits produce a distinct model, so a commit that no longer does must leave + * the index rather than linger as a release with no snapshot behind it. */ -export async function writeIndex(releases: readonly ReleaseRecord[]): Promise { +export async function writeIndex(releases: readonly ReleaseRecord[], replace: readonly SourceId[] = []): Promise { + const dropped = new Set(replace) const merged = new Map() - for (const r of [...(await readIndex()).releases, ...releases]) merged.set(`${r.source}@${r.tag}`, r) + for (const r of [...(await readIndex()).releases, ...releases]) { + if (dropped.has(r.source) && !releases.includes(r)) continue + merged.set(`${r.source}@${r.tag}`, r) + } const sorted = [...merged.values()].sort( (a, b) => b.publishedAt.localeCompare(a.publishedAt) || a.source.localeCompare(b.source), ) const index: DataIndex = { generatedAt: sorted[0]?.publishedAt ?? new Date(0).toISOString(), releases: sorted } await writeFileEnsuringDir(INDEX_PATH, `${JSON.stringify(index, null, "\t")}\n`) } + +/** + * Drops every snapshot of one source. Only `ingest --force` on an untagged + * source calls this: that walk re-derives both the set of snapshots and their + * version numbers from upstream, so leaving the old files in place could strand + * a snapshot whose commit no longer produces a distinct model — and the catalog + * reads whatever is on disk, not whatever the index lists. + */ +export async function clearSnapshots(source: SourceId): Promise { + await rm(`${DATA_ROOT}${source}`, { recursive: true, force: true }) +} diff --git a/src/model/catalog.ts b/src/model/catalog.ts index b32fcef..874661b 100644 --- a/src/model/catalog.ts +++ b/src/model/catalog.ts @@ -100,6 +100,13 @@ export interface Catalog { * what tells a page that a dead-looking attribute is alive elsewhere. */ readonly genaiLive: ReadonlyMap + /** + * Attribute ids that have a page: the current semantic conventions plus the + * current GenAI registry. A change list linking anything else points at a + * route that was never built — which is easy to do now that the GenAI history + * reaches back to attributes the registry has since dropped. + */ + readonly linkableAttributes: ReadonlySet readonly namespaces: readonly { readonly name: string; readonly count: number }[] } @@ -220,6 +227,11 @@ async function build(): Promise { if (!attribute.deprecated) genaiLive.set(attribute.id, attribute) } + const linkableAttributes = new Set([ + ...semconv.latest.attributes.map((a) => a.id), + ...genai.latest.attributes.map((a) => a.id), + ]) + const renames = new Map() for (const attribute of semconv.latest.attributes) { if (attribute.deprecated?.renamedTo) renames.set(attribute.id, attribute.deprecated.renamedTo) @@ -243,6 +255,7 @@ async function build(): Promise { lifecycle, renames, genaiLive, + linkableAttributes, namespaces: [...namespaceCounts.entries()] .map(([name, count]) => ({ name, count })) .sort((a, b) => a.name.localeCompare(b.name)), diff --git a/src/model/change.ts b/src/model/change.ts index 33a437b..eeded4a 100644 --- a/src/model/change.ts +++ b/src/model/change.ts @@ -26,6 +26,8 @@ export type ChangeKind = | "brief-changed" | "note-changed" | "examples-changed" + /** An attribute started or stopped being referenced by a signal or metric. */ + | "usage-changed" // Specification prose | "requirement-added" | "requirement-removed" @@ -109,6 +111,7 @@ export const KIND_ORDER: ChangeKind[] = [ "requirement-reworded", "requirement-moved", "enum-members-changed", + "usage-changed", "undeprecated", "added", "field-added", diff --git a/src/model/diff.test.ts b/src/model/diff.test.ts index 6d93ba3..9e5fe5b 100644 --- a/src/model/diff.test.ts +++ b/src/model/diff.test.ts @@ -1,6 +1,7 @@ import { describe, expect, test } from "bun:test" -import { readSemconv } from "../ingest/store.ts" +import { listSnapshots, readSemconv, readSnapshot } from "../ingest/store.ts" import { diffSemconv } from "./diff.ts" +import type { SemconvSnapshot } from "./types.ts" /** * These run against the committed snapshots rather than hand-written fixtures. @@ -111,3 +112,78 @@ describe("diff invariants", () => { } }) }) + +/** + * The GenAI registry is walked commit by commit, which is a different failure + * mode from a tagged source: a normalizer that misses a field, or a gate that + * keeps the wrong commits, shows up as a run of release pages saying nothing. + */ +const genaiVersions = (await listSnapshots("genai")).reverse() +const genai = await Promise.all(genaiVersions.map((version) => readSnapshot("genai", version))) + +describe("the GenAI commit history", () => { + test("starts at the commit that made it a repository of its own", () => { + const oldest = genai[0] as SemconvSnapshot + expect(oldest.tag).toBe("ebe3d1f") + // One commit earlier the filtered history still carries the aws.* tree the + // split dropped; crossing it fabricates 52 removals. + expect(oldest.attributes.some((a) => a.namespace === "aws")).toBe(false) + }) + + test("every kept commit changed something", () => { + for (let i = 1; i < genai.length; i++) { + const diff = diffSemconv(genai[i - 1] as SemconvSnapshot, genai[i] as SemconvSnapshot) + expect(diff.changes.length, `${diff.from} -> ${diff.to} is an empty release page`).toBeGreaterThan(0) + } + }) + + test("same-day commits get their own version rather than overwriting", () => { + const sameDay = genaiVersions.filter((v) => v.includes(".")) + expect(sameDay.length).toBeGreaterThan(0) + expect(new Set(genai.map((s) => s.tag)).size).toBe(genai.length) + // Suffixed or not, the walk stays in commit order. Not strictly increasing: + // commits pushed together share a committer timestamp, which is why the + // ingest resumes from a commit rather than from a date. + for (let i = 1; i < genai.length; i++) { + expect((genai[i] as SemconvSnapshot).publishedAt >= (genai[i - 1] as SemconvSnapshot).publishedAt).toBe(true) + } + }) + + test("nothing ranks breaking, because the registry is development throughout", () => { + for (let i = 1; i < genai.length; i++) { + const diff = diffSemconv(genai[i - 1] as SemconvSnapshot, genai[i] as SemconvSnapshot) + expect(diff.counts.breaking, `${diff.from} -> ${diff.to}`).toBe(0) + } + }) +}) + +describe("requirement levels on signals", () => { + /** + * Upstream: "Relax gen_ai.provider.name on gen_ai.client.operation.duration to + * Conditionally Required" — a commit whose entire content lives in `usedBy`. + * Before the differ read it, this landed as a release page with nothing on it. + */ + test("catches a level relaxed on one signal", async () => { + const before = await readSnapshot("genai", "2026-05-26") + const after = await readSnapshot("genai", "2026-06-04") + const change = diffSemconv(before, after).changes.find( + (c) => c.id === "gen_ai.provider.name" && c.kind === "requirement-level-changed", + ) + expect(change?.detail).toContain("gen_ai.client.operation.duration") + expect(change?.from).toBe("required") + expect(change?.to).toBe("conditionally_required") + }) + + /** + * A group can reference an attribute twice — inherited through `ref_group`, + * then again in its own list to override the level. Keeping both wrote the + * attribute as required *and* conditionally required on the same signal, and + * hid every override from the diff. + */ + test("a group references an attribute at exactly one level", () => { + for (const attribute of v144.attributes) { + const groups = attribute.usedBy.map((u) => u.groupId) + expect(new Set(groups).size, `${attribute.id} is referenced twice by one group`).toBe(groups.length) + } + }) +}) diff --git a/src/model/diff.ts b/src/model/diff.ts index 84539fa..9c295e0 100644 --- a/src/model/diff.ts +++ b/src/model/diff.ts @@ -155,6 +155,102 @@ function diffCommon(entity: EntityKind, before: Map, after: Map< return changes } +/** + * Which signals reference an attribute, and how strongly. `usedBy` is the only + * place the model records that `gen_ai.provider.name` is `required` on a span + * and `conditionally_required` on a metric, and both halves of that move — + * relaxing an existing reference, or adding one to a signal that did not have + * it — are changes to what an instrumentation has to emit. + * + * Diffed per attribute rather than per usage, and reported as one change + * naming the first signal: an attribute referenced by thirty groups whose level + * was relaxed once should be one line in the feed, not thirty. + */ +const usageLevels = (a: Attribute) => new Map(a.usedBy.map((u) => [u.signalName ?? u.groupId, u.requirementLevel] as const)) + +/** `conditionally_required` -> `conditionally required`, for prose. */ +const levelLabel = (level: string) => level.replace(/_/g, " ") + +const REQUIREMENT_RANK: Record = { + opt_in: 0, + recommended: 1, + conditionally_required: 2, + required: 3, +} + +const demanded = (level: string) => (REQUIREMENT_RANK[level] ?? 1) >= 2 + +/** `a and b` / `a, b and 3 others`, so one change can name what it covers. */ +const listSignals = (signals: readonly string[]) => { + const [first, second] = signals + if (signals.length === 1) return `\`${first}\`` + if (signals.length === 2) return `\`${first}\` and \`${second}\`` + return `\`${first}\`, \`${second}\` and ${signals.length - 2} other${signals.length === 3 ? "" : "s"}` +} + +function diffUsage(before: Attribute, after: Attribute): Change[] { + const from = usageLevels(before) + const to = usageLevels(after) + const changes: Change[] = [] + + const moved: { signal: string; from: string; to: string }[] = [] + const added: string[] = [] + for (const [signal, level] of to) { + const was = from.get(signal) + if (was === undefined) added.push(signal) + else if (was !== level) moved.push({ signal, from: was, to: level }) + } + const removed = [...from.keys()].filter((signal) => !to.has(signal)) + + if (moved.length > 0) { + const first = moved[0] as { signal: string; from: string; to: string } + const strengthened = moved.some(({ from: f, to: t }) => (REQUIREMENT_RANK[t] ?? 1) > (REQUIREMENT_RANK[f] ?? 1)) + changes.push({ + kind: "requirement-level-changed", + /** + * A stable attribute newly demanded by a signal is work for every + * instrumentation of it, so it ranks with the lifecycle events. It is + * not `breaking`: nothing already emitted stops being valid, which is + * the line the rest of this differ draws. + */ + severity: strengthened && isStable(after.stability) ? "notable" : "informational", + entity: "attribute", + id: after.id, + stability: after.stability, + detail: `On ${listSignals(moved.map((m) => m.signal))}: ${levelLabel(first.from)} to ${levelLabel(first.to)}.`, + from: first.from, + to: first.to, + }) + } + + if (added.length > 0) { + const obligation = added.some((signal) => demanded(to.get(signal) as string)) + changes.push({ + kind: "usage-changed", + severity: obligation && isStable(after.stability) ? "notable" : "informational", + entity: "attribute", + id: after.id, + stability: after.stability, + detail: `Now referenced by ${listSignals(added)} (${levelLabel(to.get(added[0] as string) as string)}).`, + }) + } + + if (removed.length > 0) { + changes.push({ + kind: "usage-changed", + // Dropping a reference asks nothing new of anyone; the attribute itself + // is untouched, and a removal of the *definition* is reported elsewhere. + severity: "informational", + entity: "attribute", + id: after.id, + stability: after.stability, + detail: `No longer referenced by ${listSignals(removed)}.`, + }) + } + + return changes +} + const enumKey = (a: Attribute) => (a.enumMembers ?? []) .map((m) => `${m.id}=${m.value}`) @@ -202,6 +298,7 @@ export function diffSemconv(before: SemconvSnapshot, after: SemconvSnapshot): Se detail: `Enum members changed (${b.enumMembers?.length ?? 0} to ${a.enumMembers?.length ?? 0}).`, }) } + changes.push(...diffUsage(b, a)) if (a.examples.join(" ") !== b.examples.join(" ")) { changes.push({ kind: "examples-changed",