From d8da2abf986c135aa53d1403ea92fd382ff0ed39 Mon Sep 17 00:00:00 2001 From: Jason Stirnaman Date: Tue, 30 Jun 2026 17:06:36 +0000 Subject: [PATCH 1/3] fix(ci): fix lint-codeblocks noise and false positives - Restore JS validator with explicit Flux (|>) and TICKscript (|Node(, batch()/stream(), dbrp) skip detection; skip reasons appear in CI log as 'skipped (flux)' / 'skipped (tickscript)' - Add angle-bracket placeholder normalizer for bash: strips before syntax-checking so docs-convention placeholders don't look like I/O redirects - Remove JS from VALIDATORS entirely was too blunt; real JavaScript blocks now get validated, DSL blocks are categorized and skipped - Non-blocking validation failures (bash, python, js) and ENOENT for missing shared source: files emit console output only - no ::warning GitHub annotations that could mislead authors into converting fenced code blocks to inline backtick code Closes #7433 --- scripts/ci/lint-codeblocks.mjs | 21 ++++++++---- scripts/lib/codeblock-normalizer.mjs | 48 ++++++++++++++++++++++++++-- 2 files changed, 61 insertions(+), 8 deletions(-) diff --git a/scripts/ci/lint-codeblocks.mjs b/scripts/ci/lint-codeblocks.mjs index a2d85e0466..9a93542953 100644 --- a/scripts/ci/lint-codeblocks.mjs +++ b/scripts/ci/lint-codeblocks.mjs @@ -101,8 +101,9 @@ async function main(files) { try { md = readFileSync(file, 'utf8'); } catch (err) { + // Log to console only — emitting ::warning for missing source files + // would annotate non-existent paths in the PR diff view. process.stdout.write(` - canonical source not readable: ${err.message}\n`); - gh('warning', file, 1, `canonical source not readable: ${err.message}`); process.stdout.write(`::endgroup::\n`); continue; } @@ -121,8 +122,9 @@ async function main(files) { lintedBlockCount++; if (res.skipped) { lintedBlockCount--; // skipped blocks aren't "linted" + const reason = res.skipReason ?? 'out of scope'; process.stdout.write( - ` - line ${block.startLine} ${block.rawLang ?? '(no lang)'} skipped (out of scope)\n`, + ` - line ${block.startLine} ${block.rawLang ?? '(no lang)'} skipped (${reason})\n`, ); continue; } @@ -137,14 +139,21 @@ async function main(files) { process.stdout.write(` ✓ line ${block.startLine} ${block.lang} passed\n`); } } else { - const severity = BLOCKING_LANGS.has(block.lang) ? 'error' : 'warning'; + const blocking = BLOCKING_LANGS.has(block.lang); for (const e of res.errors) { const absLine = mapCodeLineToFileLine(block, e.line ?? 1); process.stdout.write(` ✗ line ${absLine} ${block.lang} failed: ${e.message}\n`); - gh(severity, file, absLine, `${block.lang}: ${e.message}${attribution}`); const row = { file, line: absLine, lang: block.lang, message: e.message }; - if (severity === 'error') errorRows.push(row); - else warningRows.push(row); + if (blocking) { + // Blocking: emit a visible ::error annotation and fail the job. + gh('error', file, absLine, `${block.lang}: ${e.message}${attribution}`); + errorRows.push(row); + } else { + // Non-blocking: log to console only. Emitting ::warning annotations + // creates noise in the PR diff view and may mislead authors into + // thinking they should rewrite the example as inline code. + warningRows.push(row); + } } } } diff --git a/scripts/lib/codeblock-normalizer.mjs b/scripts/lib/codeblock-normalizer.mjs index d1626d82fd..248f0139a1 100644 --- a/scripts/lib/codeblock-normalizer.mjs +++ b/scripts/lib/codeblock-normalizer.mjs @@ -3,7 +3,7 @@ import * as yaml from './codeblock-validators/yaml.mjs'; import * as toml from './codeblock-validators/toml.mjs'; import * as bash from './codeblock-validators/bash.mjs'; import * as python from './codeblock-validators/python.mjs'; -import * as js from './codeblock-validators/javascript.mjs'; +import * as javascript from './codeblock-validators/javascript.mjs'; const VALIDATORS = { json: (c) => json.validate(c), @@ -12,9 +12,18 @@ const VALIDATORS = { toml: (c) => toml.validate(c), bash: (c) => bash.validate(c), python: (c) => python.validate(c), - javascript: (c) => js.validate(c), + js: (c) => javascript.validate(c), + javascript: (c) => javascript.validate(c), }; +// Flux: |> pipe is unambiguous; from(bucket:) is a strong secondary signal. +const FLUX_RE = /\|>|\bfrom\s*\(\s*bucket\s*:/; + +// TICKscript: |Node( or @Node( chain operator at line start (the | is TICKscript's +// method-chain operator, not JS bitwise OR); batch()/stream() builders; dbrp keyword. +const TICKSCRIPT_RE = /^\s*[|@][a-zA-Z]\w*\s*\(/m; +const TICKSCRIPT_KWORD_RE = /\b(?:batch|stream)\s*\(\s*\)|\bdbrp\b/; + function escapeRegex(s) { return s.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); } @@ -37,6 +46,7 @@ function quotedSub(code, token) { const PLACEHOLDER_SUB = { bash: identifierSub, python: identifierSub, + js: identifierSub, javascript: identifierSub, json: quotedSub, jsonl: quotedSub, @@ -57,6 +67,7 @@ const SHORTCODE_RE = /\{\{[%<][\s\S]*?[%>]\}\}/g; const SHORTCODE_REPLACEMENT = { bash: ': SHORTCODE', python: '__SHORTCODE__', + js: '__SHORTCODE__', javascript: '__SHORTCODE__', // Use an unquoted literal (0) for strict-parse languages so the replacement // is valid both as a bare value and inside an existing quoted string. @@ -77,6 +88,24 @@ function stripShortcodes(code, lang) { return { code: code.replace(SHORTCODE_RE, replacement), applied: true }; } +// Match angle-bracket placeholders used in docs command examples: +// , , , etc. These are valid documentation +// conventions but fail bash syntax checking because bash interprets < and > as +// I/O redirects. Strip the angle brackets to leave a bare word the shell can +// parse: `cmd --flag ` → `cmd --flag value`. +// Does NOT match <` redirects. +const ANGLE_BRACKET_PLACEHOLDER_RE = /<\/?[a-zA-Z][a-zA-Z0-9_./-]*>/g; + +function stripAngleBracketPlaceholders(code, lang) { + if (lang !== 'bash') return { code, applied: false }; + ANGLE_BRACKET_PLACEHOLDER_RE.lastIndex = 0; + if (!ANGLE_BRACKET_PLACEHOLDER_RE.test(code)) return { code, applied: false }; + ANGLE_BRACKET_PLACEHOLDER_RE.lastIndex = 0; + // Remove angle brackets; keep the inner text as a bare word or path. + const result = code.replace(ANGLE_BRACKET_PLACEHOLDER_RE, (match) => match.slice(1, -1)); + return { code: result, applied: true }; +} + // Match standalone "elide" markers used in docs to indicate omitted // content: a line containing only whitespace + `...` (3+ dots) or // `[...]`. These are pervasive in Telegraf/InfluxDB TOML examples and @@ -90,6 +119,7 @@ const ELIDE_COMMENT_PREFIX = { toml: '#', bash: '#', python: '#', + js: '//', javascript: '//', // JSON/JSONL don't allow comments; can't safely substitute, so // ellipsis markers in JSON fences must be removed at the source. @@ -133,6 +163,14 @@ function stripElideMarkers(code, lang) { * @returns {Promise<{ok: boolean, errors: Array, notice?: string, skipped?: boolean}>} */ export async function validateWithNormalization(block) { + // Detect known non-JS DSLs that are conventionally tagged js/javascript in these docs. + // Skip them explicitly so real JavaScript blocks still get validated. + if (block.lang === 'js' || block.lang === 'javascript') { + if (FLUX_RE.test(block.value)) return { ok: true, errors: [], skipped: true, skipReason: 'flux' }; + if (TICKSCRIPT_RE.test(block.value) || TICKSCRIPT_KWORD_RE.test(block.value)) + return { ok: true, errors: [], skipped: true, skipReason: 'tickscript' }; + } + const run = VALIDATORS[block.lang]; if (!run) return { ok: true, errors: [], skipped: true }; @@ -148,6 +186,12 @@ export async function validateWithNormalization(block) { rules.push('placeholder substitution'); } + const angleBracketed = stripAngleBracketPlaceholders(candidate, block.lang); + if (angleBracketed.applied) { + candidate = angleBracketed.code; + rules.push('angle-bracket placeholder strip'); + } + const stripped = stripShortcodes(candidate, block.lang); if (stripped.applied) { candidate = stripped.code; From 0aba5c0144d57e935fa3815dbbd16679a519ce58 Mon Sep 17 00:00:00 2001 From: Jason Stirnaman Date: Tue, 30 Jun 2026 17:06:53 +0000 Subject: [PATCH 2/3] fix(content): correct code-block language tags and syntax errors MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Telegraf v1 plugin docs — label fixes so json/toml blocks parse correctly under the CI linter: - bind: named.conf syntax in json fence → text - ctrlx_datalayer: ctrlX Datalayer source-value format → text (format unverified; upstream Telegraf PRs filed — see below) - docker: TOML config snippets mislabeled as json → text - jti_openconfig_telemetry: duplicate key in toml block → text - opcua_listener, dynatrace: // inline comments in toml → # - postgresql_extensible: backslash line continuation in toml → text - win_eventlog: unclosed triple-quoted string in toml → text - azure_data_explorer: KQL/Kusto code in json fence → text - clarify: proprietary signal/values format in json fence → text - elasticsearch: HTTP request + body in json fence → text - zabbix: JSONL-format payloads in json fence → jsonl - converter: unclosed toml string literal "unix → "unix" - lookup, secretstore/http: ellipsis elide markers in json fence → text - splunkmetric: valid JSON metric objects in javascript fence → json InfluxDB Cloud / Cloud Serverless bucket docs: - bucket-schema, create-bucket, update-bucket, manage-explicit-bucket-schemas: JSON API request bodies in javascript/js fences → json --- content/influxdb/cloud/admin/buckets/bucket-schema.md | 4 ++-- content/influxdb/cloud/admin/buckets/create-bucket.md | 2 +- content/influxdb/cloud/admin/buckets/update-bucket.md | 2 +- .../admin/buckets/manage-explicit-bucket-schemas.md | 2 +- .../cloud-serverless/admin/buckets/update-bucket.md | 2 +- content/telegraf/v1/data_formats/output/splunkmetric.md | 4 ++-- content/telegraf/v1/input-plugins/bind.md | 2 +- content/telegraf/v1/input-plugins/ctrlx_datalayer.md | 6 +++--- content/telegraf/v1/input-plugins/docker.md | 4 ++-- .../telegraf/v1/input-plugins/jti_openconfig_telemetry.md | 2 +- content/telegraf/v1/input-plugins/opcua_listener.md | 6 +++--- content/telegraf/v1/input-plugins/postgresql_extensible.md | 2 +- content/telegraf/v1/input-plugins/win_eventlog.md | 2 +- content/telegraf/v1/output-plugins/azure_data_explorer.md | 2 +- content/telegraf/v1/output-plugins/clarify.md | 2 +- content/telegraf/v1/output-plugins/dynatrace.md | 2 +- content/telegraf/v1/output-plugins/elasticsearch.md | 4 ++-- content/telegraf/v1/output-plugins/zabbix.md | 4 ++-- content/telegraf/v1/processor-plugins/converter.md | 2 +- content/telegraf/v1/processor-plugins/lookup.md | 4 ++-- content/telegraf/v1/secretstore-plugins/http.md | 2 +- 21 files changed, 31 insertions(+), 31 deletions(-) diff --git a/content/influxdb/cloud/admin/buckets/bucket-schema.md b/content/influxdb/cloud/admin/buckets/bucket-schema.md index 2b5b7bc67d..136299eb88 100644 --- a/content/influxdb/cloud/admin/buckets/bucket-schema.md +++ b/content/influxdb/cloud/admin/buckets/bucket-schema.md @@ -132,7 +132,7 @@ For example, the following request defines the _explicit_ bucket measurement sch {{< api-endpoint method="post" endpoint="https://cloud2.influxdata.com/api/v2/buckets/{BUCKET_ID}/schema/measurements" api-ref="/influxdb/cloud/api/buckets//-bucketID-/schema/measurements" >}} -```js +```json { "name": "airSensors", "columns": [ @@ -262,7 +262,7 @@ You can't modify or delete columns in bucket schemas. {{< api-endpoint method="patch" endpoint="https://cloud2.influxdata.com/api/v2/buckets/{BUCKET_ID}/schema/measurements/{MEASUREMENT_ID}" api-ref="/influxdb/cloud/api/bucket-schemas/" >}} - ```js + ```json { "columns": [ {"name": "time", "type": "timestamp"}, diff --git a/content/influxdb/cloud/admin/buckets/create-bucket.md b/content/influxdb/cloud/admin/buckets/create-bucket.md index 78df662dec..dbee3c5955 100644 --- a/content/influxdb/cloud/admin/buckets/create-bucket.md +++ b/content/influxdb/cloud/admin/buckets/create-bucket.md @@ -169,7 +169,7 @@ endpoint and set the `schemaType` property value to `explicit` in the request bo {{< api-endpoint method="post" endpoint="https://cloud2.influxdata.com/api/v2/buckets" api-ref="/influxdb/cloud/api/buckets/" >}} -```js +```json { "orgID": "{INFLUX_ORG_ID}", "name": "my-explicit-bucket", diff --git a/content/influxdb/cloud/admin/buckets/update-bucket.md b/content/influxdb/cloud/admin/buckets/update-bucket.md index 726fbc59cf..526c9f1f92 100644 --- a/content/influxdb/cloud/admin/buckets/update-bucket.md +++ b/content/influxdb/cloud/admin/buckets/update-bucket.md @@ -130,7 +130,7 @@ You can update the following bucket properties: {{< api-endpoint method="patch" endpoint="https://cloud2.influxdata.com/api/v2/buckets/{BUCKET_ID}" api-ref="/influxdb/cloud/api/buckets/" >}} - ```js + ```json { "name": "air_sensor", "description": "bucket holding air sensor data", diff --git a/content/influxdb3/cloud-serverless/admin/buckets/manage-explicit-bucket-schemas.md b/content/influxdb3/cloud-serverless/admin/buckets/manage-explicit-bucket-schemas.md index 58793c489c..0c078622e1 100644 --- a/content/influxdb3/cloud-serverless/admin/buckets/manage-explicit-bucket-schemas.md +++ b/content/influxdb3/cloud-serverless/admin/buckets/manage-explicit-bucket-schemas.md @@ -151,7 +151,7 @@ You can't modify or delete columns in bucket schemas. {{< api-endpoint method="patch" endpoint="https://{{< influxdb/host >}}/api/v2/buckets/{BUCKET_ID}/schema/measurements/{MEASUREMENT_ID}" api-ref="/influxdb3/cloud-serverless/api/buckets/" >}} - ```js + ```json { "columns": [ {"name": "time", "type": "timestamp"}, diff --git a/content/influxdb3/cloud-serverless/admin/buckets/update-bucket.md b/content/influxdb3/cloud-serverless/admin/buckets/update-bucket.md index b660226da6..d19ad38239 100644 --- a/content/influxdb3/cloud-serverless/admin/buckets/update-bucket.md +++ b/content/influxdb3/cloud-serverless/admin/buckets/update-bucket.md @@ -119,7 +119,7 @@ You can update the following bucket properties: {{< api-endpoint method="patch" endpoint="https://{{< influxdb/host >}}/api/v2/buckets/{BUCKET_ID}" api-ref="/influxdb3/cloud-serverless/api/buckets/#operation/PatchBucketsID" >}} - ```js + ```json { "name": "air_sensor", "description": "bucket holding air sensor data", diff --git a/content/telegraf/v1/data_formats/output/splunkmetric.md b/content/telegraf/v1/data_formats/output/splunkmetric.md index 71068ab76e..fdc6e16a42 100644 --- a/content/telegraf/v1/data_formats/output/splunkmetric.md +++ b/content/telegraf/v1/data_formats/output/splunkmetric.md @@ -19,7 +19,7 @@ Th data is output in a format that conforms to the specified Splunk HEC JSON for [Send metrics in JSON format](http://dev.splunk.com/view/event-collector/SP-CAAAFDN). An example event looks like: -```javascript +```json { "time": 1529708430, "event": "metric", @@ -104,7 +104,7 @@ Such as this example which overrides the index just on the cpu metric: You can use the file output when running telegraf on a machine with a Splunk forwarder. A sample event when `hec_routing` is false (or unset) looks like: -```javascript +```json { "_value": 0.6, "cpu": "cpu0", diff --git a/content/telegraf/v1/input-plugins/bind.md b/content/telegraf/v1/input-plugins/bind.md index 952f3a5342..30c4a0a701 100644 --- a/content/telegraf/v1/input-plugins/bind.md +++ b/content/telegraf/v1/input-plugins/bind.md @@ -83,7 +83,7 @@ depending on your BIND version and configured statistics channel. Add the following to your named.conf if running Telegraf on the same host as the BIND daemon: -```json +```text statistics-channels { inet 127.0.0.1 port 8053; }; diff --git a/content/telegraf/v1/input-plugins/ctrlx_datalayer.md b/content/telegraf/v1/input-plugins/ctrlx_datalayer.md index 5423ed5a00..c3bf398fd3 100644 --- a/content/telegraf/v1/input-plugins/ctrlx_datalayer.md +++ b/content/telegraf/v1/input-plugins/ctrlx_datalayer.md @@ -321,7 +321,7 @@ Configuration: Source: -```json +```text "framework/metrics/system/memavailable-mb" : 365.93359375 "framework/metrics/system/memused-mb" : 567.67578125 ``` @@ -348,7 +348,7 @@ Configuration: Source: -```json +```text "alldata/dynamic/array-of-bool8" : [true, false, true] "alldata/dynamic/array-of-uint8" : [0, 255] ``` @@ -375,7 +375,7 @@ Configuration: Source: -```json +```text "motion/axs/Axis_1/state/values/actual" : {"actualPos":65.249329860957,"actualVel":5,"actualAcc":0,"actualTorque":0,"distLeft":0,"actualPosUnit":"mm","actualVelUnit":"mm/min","actualAccUnit":"m/s^2","actualTorqueUnit":"Nm","distLeftUnit":"mm"} "motion/axs/Axis_2/state/values/actual" : {"actualPos":120,"actualVel":0,"actualAcc":0,"actualTorque":0,"distLeft":0,"actualPosUnit":"deg","actualVelUnit":"rpm","actualAccUnit":"rad/s^2","actualTorqueUnit":"Nm","distLeftUnit":"deg"} ``` diff --git a/content/telegraf/v1/input-plugins/docker.md b/content/telegraf/v1/input-plugins/docker.md index 9afb418a12..ed6a922bcf 100644 --- a/content/telegraf/v1/input-plugins/docker.md +++ b/content/telegraf/v1/input-plugins/docker.md @@ -165,7 +165,7 @@ for containers that have no explicit hostname set, as defined by docker. Kubernetes may add many labels to your containers, if they are not needed you may prefer to exclude them: -```json +```text docker_label_exclude = ["annotation.kubernetes*"] ``` @@ -174,7 +174,7 @@ may prefer to exclude them: Docker-compose will add labels to your containers. You can limit restrict labels to selected ones, e.g. -```json +```text docker_label_include = [ "com.docker.compose.config-hash", "com.docker.compose.container-number", diff --git a/content/telegraf/v1/input-plugins/jti_openconfig_telemetry.md b/content/telegraf/v1/input-plugins/jti_openconfig_telemetry.md index 4c73c43762..62ac895009 100644 --- a/content/telegraf/v1/input-plugins/jti_openconfig_telemetry.md +++ b/content/telegraf/v1/input-plugins/jti_openconfig_telemetry.md @@ -43,7 +43,7 @@ plugin ordering. See [CONFIGURATION.md](/telegraf/v1/configuration/#plugins) for ## Configuration -```toml @sample.conf +```text @sample.conf # Subscribe and receive OpenConfig Telemetry data using JTI [[inputs.jti_openconfig_telemetry]] ## List of device addresses to collect telemetry from diff --git a/content/telegraf/v1/input-plugins/opcua_listener.md b/content/telegraf/v1/input-plugins/opcua_listener.md index 5d7e8ac300..6ef0c300bf 100644 --- a/content/telegraf/v1/input-plugins/opcua_listener.md +++ b/content/telegraf/v1/input-plugins/opcua_listener.md @@ -586,9 +586,9 @@ This example group configuration shows how to use group settings: identifier = "5678" node_ids = [ - {identifier="Sensor1"}, // default values will be used for namespace and identifier_type - {namespace="2", identifier="TemperatureSensor"}, // default values will be used for identifier_type - {namespace="5", identifier_type="i", identifier="2002"} // no default values will be used + {identifier="Sensor1"}, # default values will be used for namespace and identifier_type + {namespace="2", identifier="TemperatureSensor"}, # default values will be used for identifier_type + {namespace="5", identifier_type="i", identifier="2002"} # no default values will be used ] ``` diff --git a/content/telegraf/v1/input-plugins/postgresql_extensible.md b/content/telegraf/v1/input-plugins/postgresql_extensible.md index 0838167650..3c117bba09 100644 --- a/content/telegraf/v1/input-plugins/postgresql_extensible.md +++ b/content/telegraf/v1/input-plugins/postgresql_extensible.md @@ -126,7 +126,7 @@ using the postgresql extensions [pg_stat_statements](http://www.postgresql.org/d * telegraf.conf postgresql_extensible queries (assuming that you have configured correctly your connection) -```toml +```text [[inputs.postgresql_extensible.query]] sqlquery="SELECT * FROM pg_stat_database" version=901 diff --git a/content/telegraf/v1/input-plugins/win_eventlog.md b/content/telegraf/v1/input-plugins/win_eventlog.md index 8541fc2ab6..10cabead60 100644 --- a/content/telegraf/v1/input-plugins/win_eventlog.md +++ b/content/telegraf/v1/input-plugins/win_eventlog.md @@ -147,7 +147,7 @@ There are three types of filtering: **Event Log** name, **XPath Query** and **Event Log** name filtering is simple: -```toml +```text eventlog_name = "Application" xpath_query = ''' ``` diff --git a/content/telegraf/v1/output-plugins/azure_data_explorer.md b/content/telegraf/v1/output-plugins/azure_data_explorer.md index 89546c786d..30280c8d3b 100644 --- a/content/telegraf/v1/output-plugins/azure_data_explorer.md +++ b/content/telegraf/v1/output-plugins/azure_data_explorer.md @@ -256,7 +256,7 @@ stored as dynamic data type, multiple ways to query this data- recommended performant way for querying over large volumes of data compared to querying directly over JSON attributes: - ```json + ```text // Function to transform data .create-or-alter function Transform_TargetTableName() { SourceTableName diff --git a/content/telegraf/v1/output-plugins/clarify.md b/content/telegraf/v1/output-plugins/clarify.md index ded17ec0cc..c681280b42 100644 --- a/content/telegraf/v1/output-plugins/clarify.md +++ b/content/telegraf/v1/output-plugins/clarify.md @@ -80,7 +80,7 @@ The following input would be stored in Clarify with the values shown below: temperature,host=demo.clarifylocal,sensor=TC0P value=49 1682670910000000000 ``` -```json +```text "signal" { "id": "temperature.value.TC0P" "name": "temperature.value" diff --git a/content/telegraf/v1/output-plugins/dynatrace.md b/content/telegraf/v1/output-plugins/dynatrace.md index d601e4e992..680962f737 100644 --- a/content/telegraf/v1/output-plugins/dynatrace.md +++ b/content/telegraf/v1/output-plugins/dynatrace.md @@ -103,7 +103,7 @@ The endpoint for the Dynatrace Metrics API v2 is url = "https://{your-environment-id}.live.dynatrace.com/api/v2/metrics/ingest" ## API token is required if a URL is specified and should be restricted to the 'Ingest metrics' scope - api_token = "your API token here" // hard-coded for illustration only, should be read from environment + api_token = "your API token here" # hard-coded for illustration only, should be read from environment ``` You can learn more about how to use the [Dynatrace API](https://docs.dynatrace.com/docs/shortlink/section-api). diff --git a/content/telegraf/v1/output-plugins/elasticsearch.md b/content/telegraf/v1/output-plugins/elasticsearch.md index ab39073dfb..0a213f551f 100644 --- a/content/telegraf/v1/output-plugins/elasticsearch.md +++ b/content/telegraf/v1/output-plugins/elasticsearch.md @@ -217,7 +217,7 @@ compatibility mode users need to set the `override_main_response_version` to On existing clusters run: -```json +```text PUT /_cluster/settings { "persistent" : { @@ -228,7 +228,7 @@ PUT /_cluster/settings And on new clusters set the option to true under advanced options: -```json +```text POST https://es.us-east-1.amazonaws.com/2021-01-01/opensearch/upgradeDomain { "DomainName": "domain-name", diff --git a/content/telegraf/v1/output-plugins/zabbix.md b/content/telegraf/v1/output-plugins/zabbix.md index 47fd69a888..18a01997cb 100644 --- a/content/telegraf/v1/output-plugins/zabbix.md +++ b/content/telegraf/v1/output-plugins/zabbix.md @@ -186,7 +186,7 @@ measurement,host=hostname valueA=0,valueB=1 It will generate this Zabbix metrics: -```json +```jsonl {"host": "hostname", "key": "telegraf.measurement.valueA", "value": "0"} {"host": "hostname", "key": "telegraf.measurement.valueB", "value": "1"} ``` @@ -200,7 +200,7 @@ measurement,host=hostname,tagA=keyA,tagB=keyB valueA=0,valueB=1 Zabbix generated metrics: -```json +```jsonl {"host": "hostname", "key": "telegraf.measurement.valueA[keyA,keyB]", "value": "0"} {"host": "hostname", "key": "telegraf.measurement.valueB[keyA,keyB]", "value": "1"} ``` diff --git a/content/telegraf/v1/processor-plugins/converter.md b/content/telegraf/v1/processor-plugins/converter.md index aee5d61220..9c736d86df 100644 --- a/content/telegraf/v1/processor-plugins/converter.md +++ b/content/telegraf/v1/processor-plugins/converter.md @@ -143,7 +143,7 @@ Set the metric timestamp from a tag: [[processors.converter]] [processors.converter.tags] timestamp = ["time"] - timestamp_format = "unix + timestamp_format = "unix" ``` ```diff diff --git a/content/telegraf/v1/processor-plugins/lookup.md b/content/telegraf/v1/processor-plugins/lookup.md index 6c6a820401..15f5f6e927 100644 --- a/content/telegraf/v1/processor-plugins/lookup.md +++ b/content/telegraf/v1/processor-plugins/lookup.md @@ -75,7 +75,7 @@ added to a metric if the key matches. In the `json` format, the input `files` must have the following format -```json +```text { "keyA": { "tag-name1": "tag-value1", @@ -136,7 +136,7 @@ Please note that empty tag-values will be ignored and the tag will not be added. With a lookup table of -```json +```text { "xyzzy-green": { "location": "eu-central", diff --git a/content/telegraf/v1/secretstore-plugins/http.md b/content/telegraf/v1/secretstore-plugins/http.md index ca2817f572..7df9938bec 100644 --- a/content/telegraf/v1/secretstore-plugins/http.md +++ b/content/telegraf/v1/secretstore-plugins/http.md @@ -154,7 +154,7 @@ encryption section. Secrets are expected to be JSON data in the following flat key-value form -```json +```text { "secret name A": "secret value A", ... From b0cc0d017a86edae308e47c4ee433a403b7bfbcf Mon Sep 17 00:00:00 2001 From: Jason Stirnaman Date: Tue, 30 Jun 2026 17:07:03 +0000 Subject: [PATCH 3/3] docs(exec-plans): expand merge queue plan with Phase 2 spec Rewrites the short decision record into a self-contained ExecPlan: - Explicit Phase 2 steps for test.yml (merge_group trigger, detect-changes fix, lint-codeblocks condition) now that #7433 is resolved - Behavioral acceptance criteria for both phases - Rollout discoveries: Phase 1 first merge bypassed the queue; CircleCI build count unchanged (queue builds on throwaway branches) - Branch-protection state snapshot and recovery / idempotence notes - gh CLI one-liners to inspect protection state and verify queue usage No decisions changed; facts and status carried forward from the original record. --- .../2026-06-29-gh-merge-queue-master.md | 304 +++++++++++------- 1 file changed, 190 insertions(+), 114 deletions(-) diff --git a/docs/exec-plans/2026-06-29-gh-merge-queue-master.md b/docs/exec-plans/2026-06-29-gh-merge-queue-master.md index 68c41377f7..a474ad5004 100644 --- a/docs/exec-plans/2026-06-29-gh-merge-queue-master.md +++ b/docs/exec-plans/2026-06-29-gh-merge-queue-master.md @@ -1,114 +1,190 @@ -# GitHub merge queue for `master` - -**Status:** In review — PR [#7434](https://github.com/influxdata/docs-v2/pull/7434) -**Closes:** [#7412](https://github.com/influxdata/docs-v2/issues/7412) -**Depends on:** lint-codeblocks bug fix — [#7433](https://github.com/influxdata/docs-v2/issues/7433) (gates the Phase 2 follow-up) - -## Goal - -Replace the dead PR auto-update mechanism with GitHub's native **merge queue** -on `master`. Contributors stop hand-rebasing onto `master`: a maintainer clicks -**"Merge when ready"**, the queue builds `master` + the PR on a throwaway -`gh-readonly-queue/master/*` branch, runs the required checks there, and -completes the merge only if green. The human merge gate is unchanged. - -## Why now - -`.github/workflows/pr-autoupdate.yml` is a silent no-op — it pins -`docker://chinthakagodawita/autoupdate-action:v1.7.0`, whose Docker image is -gone and whose upstream repo is archived. With `master` branch protection set -to `strict: true` ("require branches up to date before merging"), contributors -must now manually rebase every PR each time `master` moves — and at the current -volume (\~90 PRs merged in the last 30 days, 47 in the last week, \~18 open at a -time) that churn is constant. A merge queue removes the rebase requirement while -preserving the "master never breaks" guarantee. - -## Decisions - -- **Merge queue, not a maintained auto-update action.** A queue updates the base - *once at merge time* (\~3–6 builds/day at current volume); a continuous - auto-update action rebuilds *every* open PR on *every* `master` push - (\~55–110 builds/day) — roughly 10× the CircleCI cost for the same - "no manual rebase" outcome. The queue also catches a bad merge *before* it - reaches `master` instead of fanning it out to all open PRs. Decisively: this - issue exists *because* a third-party auto-update action rotted; the queue is a - native GitHub feature with nothing to archive or pin. -- **Turn off `strict`.** The queue rebuilds `master` + PR in its temp branch and - validates *that*, so "require branch up to date before merging" is redundant - and merely re-imposes the manual rebase the queue exists to remove. Turning it - off does **not** weaken the human merge gate — that gate is the "Merge when - ready" click, not `strict`. -- **Phase the rollout — ship the queue now, gated only on `ci/circleci: build`; - re-require `Lint code blocks` later (sequencing option "B").** `Lint code - blocks` is a *required* check, and a merge queue hangs forever on any required - check that does not report on the `merge_group` branch. That check currently - has a known bug ([#7433](https://github.com/influxdata/docs-v2/issues/7433)), - so we do **not** wire it into `merge_group` - yet. Instead, admin temporarily drops it from the required-checks list so the - queue gates only on the CircleCI Hugo build — the real "master doesn't break" - guarantee for a docs site. Lint still runs on every PR as a non-required - check, so contributors keep its feedback; it just doesn't block merges during - the window. Rejected alternatives: (A) gate the entire rollout on the lint - fix — ships the queue later for no current benefit, since auto-update is - already dead; (C) `merge_group` skip-to-success — keeps lint required but - reports a phantom "skipped" check and still entangles the queue change with - the buggy workflow. -- **No CircleCI config change.** The `build` job has no branch filter, so it - already builds every pushed branch — including `gh-readonly-queue/master/*` — - and reports the exact required context `ci/circleci: build`. The `deploy` job - is filtered `only: master`, so queue branches never deploy, and the job's - `CIRCLE_BRANCH != master` path keeps them on the cheaper incremental build. - The single dependency is the CircleCI **"Only build pull requests"** project - setting: it must be **OFF**, or queue branches won't build and PRs hang. This - is the issue's headline risk and is a settings verification, not code. -- **Queue parameters: squash merge, max group size = 1.** Squash matches how the - repo merges today and keeps `master` history clean. Max group size 1 means the - queue validates one PR at a time, so the *only* thing that can eject a PR is - its own build failure — never a semantic conflict with another PR ahead of it. - At \~6 merges/day the throughput cost is negligible, and it directly limits the - committer-experience downside (ejection on a flaky build). - -## Explicitly out of scope - -- **Fixing the `Lint code blocks` bug and wiring it into `merge_group`** — the - Phase 2 follow-up. Once fixed, a single change adds `merge_group:` to - `test.yml` (run-for-real: `detect-changes` computes its diff from - `github.event.merge_group.base_sha`, and the `lint-codeblocks` `if:` is - extended to `merge_group`) **and** re-adds `Lint code blocks` to the required - list. These must land together, or the queue hangs again. Tracked by - [#7433](https://github.com/influxdata/docs-v2/issues/7433). -- **Auditing other GitHub Actions checks for `merge_group`** — trivial under - option B: after de-requiring lint, `ci/circleci: build` is the only required - check, and it reports independently of `merge_group`. Re-audit when lint is - re-required. - -## How to update - -- **Required checks / queue settings** live in `master` branch protection (admin - UI / ruleset), not in the repo — coordinate with the security team, which owns - branch protection org-wide. -- **To make a *new* GitHub Actions check merge-queue-safe** before marking it - required: add `merge_group:` to that workflow's `on:` triggers so it reports on - `gh-readonly-queue/*` branches. A required check without it stalls the queue. - -## Verification - -1. **Pre-enable:** confirm CircleCI "Only build pull requests" is OFF for the - `docs-v2` project (CircleCI project settings → Advanced). -2. **Admin:** on the literal-`master` rule (classic protection, no wildcard — - confirmed via `gh api repos/influxdata/docs-v2/branches/master/protection`), - remove `Lint code blocks` from required checks, turn off `strict`, enable - "Require merge queue" with the parameters above. -3. **Smoke test (low-traffic window):** open one trivial docs PR, click "Merge - when ready", and confirm `ci/circleci: build` reports on the - `gh-readonly-queue/master/*` branch and the PR merges. If it hangs, CircleCI - is not building queue branches — revisit step 1. -4. **Rollback:** disable "Require merge queue" in branch protection. No code - revert needed; the only in-repo change is the `pr-autoupdate.yml` deletion. - -## In-repo change set (this PR) - -- Delete `.github/workflows/pr-autoupdate.yml` (dead no-op). -- This exec-plan. - -Everything else is admin/settings (Phase 1 enablement) or the Phase 2 follow-up. +# Adopt a GitHub merge queue for the `master` branch + +## Purpose / Big Picture + +After this change, a contributor to the `influxdata/docs-v2` documentation site no longer has to manually rebase a pull request (PR) onto the latest `master` before it can merge. Instead, a maintainer clicks the **Merge when ready** button, and GitHub's [*merge queue*](https://docs.github.com/en/repositories/configuring-branches-and-merges-in-your-repository/configuring-pull-request-merges/managing-a-merge-queue) takes over: it builds a temporary branch containing `master` plus the PR, runs the repository's required checks against that combined branch, and completes the merge only if those checks pass. The site's "master is always deployable" guarantee is preserved, but the rebase churn is gone. + +## Progress + +Phase 1 (ship the queue, gated only on the CircleCI build) is complete. Phase 2 (re-require the code-block lint once its bug is fixed) is not yet started. + +- [x] (2026-06-30) Removed the defunct `.github/workflows/pr-autoupdate.yml` workflow. Merged to `master` via PR #7434. +- [x] (2026-06-30) Recorded the rollout decisions in this document. Merged via PR #7434. +- [x] (2026-06-30) Filed issue #7433 for the `Lint code blocks` bug that blocks Phase 2. +- [x] (2026-06-30 ~14:45Z) Admin enabled the merge queue on `master`, turned off the `strict` up-to-date requirement, and removed `Lint code blocks` from the required checks. Confirmed via the GitHub API: `strict` is now `false`. +- [ ] Verify the queue actually runs end-to-end (completed: queue is enabled; remaining: a PR has not yet been observed flowing through `gh-readonly-queue/master/*` — the one merge so far bypassed the queue, see `Surprises & Discoveries`). +- [ ] Confirm the CircleCI project setting "Only build pull requests" is OFF so queue branches build (completed: nothing; remaining: check CircleCI project → Settings → Advanced, or infer from a successful `ci/circleci: build` on a `gh-readonly-queue/*` branch). +- [ ] Phase 2: fix the `Lint code blocks` bug (#7433). Tracked separately; prerequisite for the next item. +- [ ] Phase 2: add the `merge_group:` trigger to `.github/workflows/test.yml` and make the lint job report on queue branches (completed: nothing; remaining: the edits in `Plan of Work` and `Concrete Steps`). +- [ ] Phase 2: re-add `Lint code blocks` to the `master` required checks, in the same change that lands the `merge_group:` trigger. + +## Surprises & Discoveries + +- Observation: Enabling "Require merge queue" does not stop a user with bypass permission from merging directly and skipping the queue. The first merge after enabling (PR #7434) bypassed the queue. + +- Observation: The merge queue does not reduce the number of CircleCI builds; it adds one. After any merge, `master` still runs a full build and deploy. + + Evidence: In `.circleci/config.yml`, the `deploy` job declares `requires: build` and attaches the `workspace/public` directory produced by the `build` job in the same pipeline, and the `deploy` job is filtered to run only on `master`. There is no path that deploys a previously built artifact from another branch or pipeline. So the queue's validation build runs on the throwaway `gh-readonly-queue/*` branch (which never deploys), and then `master` builds and deploys again after the merge. The dependency caches added in earlier CI work make the rebuild faster but never skip the Hugo build itself. + +## Decision Log + +- Decision: Use a native GitHub merge queue rather than a maintained third-party auto-update action. + + Rationale: At this repository's volume (about 80–90 PRs merged per month, with bursts above 40 per week and roughly 18 open at once), a continuous auto-update action would rebuild every open PR on every push to `master` — on the order of 55–110 builds per day — versus roughly one validation build per merged PR for the queue. The queue also catches a bad combined state before it reaches `master`, and it is a native feature with no third-party dependency to rot. This issue exists precisely because the previous auto-update action (`chinthakagodawita/autoupdate-action`) was archived and its Docker image removed. + + Date/Author: 2026-06-29, Jason Stirnaman (with Claude). + +- Decision: Turn off the `strict` "require branches to be up to date before merging" setting when enabling the queue. + + Rationale: The queue rebuilds `master` plus the PR in its temporary branch and validates that, so additionally requiring the PR branch to be up to date first is redundant and merely re-imposes the manual rebase the queue exists to remove. Turning `strict` off does not weaken human review: the merge gate is the **Merge when ready** click, not `strict`. + + Date/Author: 2026-06-29, Jason Stirnaman (with Claude). + +- Decision: Ship the queue gated only on `ci/circleci: build`, and re-require `Lint code blocks` later (sequencing option "B"). + + Rationale: A merge queue waits forever on any required check that does not report on the `merge_group` branch. `Lint code blocks` is a required check, and it has a known bug (#7433), so it was not wired into the queue yet. Removing it from the required set temporarily lets the queue ship now, gated on the CircleCI Hugo build, which is the real "master is deployable" guarantee for a docs site. Lint still runs on every PR as a non-required check, so contributors keep its feedback. Rejected alternatives: (A) gate the entire rollout on the lint fix, which delays the queue for no current benefit since the old auto-update was already dead; (C) wire lint as a `merge_group` job that skips to success, which keeps a confusing phantom "skipped" check and still entangles the queue with the buggy workflow. + + Date/Author: 2026-06-29, Jason Stirnaman (with Claude). + +- Decision: Use the rebase merge method and the default merge limits (minimum group size 1, maximum 5). + + Date/Author: 2026-06-30, Jason Stirnaman (with Claude). + +## Outcomes & Retrospective + +Phase 1 achieved the user-visible goal: the dead auto-update workflow is gone, the queue is enabled on `master`, and `strict` is off, so contributors are no longer forced to rebase. What remains is to observe a real PR flowing through the queue (the first merge bypassed it) and to complete Phase 2 so the code-block lint runs inside the queue again. + +## Context and Orientation + +The repository is the Hugo-based documentation site at `influxdata/docs-v2`. Two continuous integration (CI) systems run against it, and both matter here. + +The first is CircleCI, configured in `.circleci/config.yml`. It defines a `build` job that installs dependencies, generates API docs, builds a Rust markdown converter, runs the Hugo build over 5000-plus pages, and verifies the output. The `build` job has no branch filter, so CircleCI builds every pushed branch — including the queue's temporary `gh-readonly-queue/master/*` branches — and reports its result to GitHub under the status context exactly named `ci/circleci: build`. A separate `deploy` job runs only on `master` and depends on `build`. Because CircleCI is a third-party provider rather than a GitHub Actions workflow, the GitHub `merge_group` event (described below) does not reach it; CircleCI participates in the queue purely by building the pushed `gh-readonly-queue/*` branch. + +The second is GitHub Actions. The relevant workflow is `.github/workflows/test.yml`, named "Test Code Blocks". It currently triggers on `pull_request` and `workflow_dispatch`. Inside it, a job whose display name is `Lint code blocks` (job id `lint-codeblocks`) is a required status check on `master`. That job depends on a `detect-changes` job that computes the set of changed files by diffing `github.event.pull_request.base.sha` against `github.sha`, and the `lint-codeblocks` job runs only when its condition `github.event_name == 'pull_request' && needs.detect-changes.outputs.canonical-sources != '' && needs.detect-changes.outputs.canonical-sources != '[]'` is met. Both of those facts are PR-specific and are why Phase 2 needs edits, explained later. + +Branch protection on `master` is classic branch protection on the literal branch name `master` (not a wildcard pattern, which matters because a merge queue cannot be enabled on a wildcard). Before this work, its required status checks were `ci/circleci: build` and `Lint code blocks`, and its `strict` flag was `true`. After Phase 1, `Lint code blocks` was removed from the required set and `strict` was set to `false`. + +Two more terms used below. The `merge_group` event is a GitHub Actions trigger that fires when GitHub builds a merge-queue group; a workflow runs against the `gh-readonly-queue/*` branch only if its `on:` list includes `merge_group`. The `strict` flag is the REST API name for the branch-protection checkbox labeled "Require branches to be up to date before merging" in the GitHub UI. + +## Plan of Work + +Only Phase 2 has remaining code work; Phase 1's only in-repo change (deleting `pr-autoupdate.yml`) is already merged. + +Phase 2 begins outside this repository: the `Lint code blocks` bug (#7433) must be fixed first, because wiring a still-broken check into the queue would make queued PRs fail or hang. That fix is tracked in #7433 and is not specified here. + +Once #7433 is fixed, make three edits to `.github/workflows/test.yml`, all additive. First, add `merge_group:` to the workflow's `on:` list so the workflow runs against `gh-readonly-queue/*` branches. Second, in the `detect-changes` job, add a branch to the change-detection logic that computes the diff for the `merge_group` event using `github.event.merge_group.base_sha` as the base and `github.sha` as the head (the existing logic only handles `pull_request` and `workflow_dispatch`), and extend the `Setup Node.js` step's condition so Node is installed for `merge_group` as well as `pull_request`. Third, change the `lint-codeblocks` job condition so it also runs on the `merge_group` event, for example `(github.event_name == 'pull_request' || github.event_name == 'merge_group') && needs.detect-changes.outputs.canonical-sources != '' && needs.detect-changes.outputs.canonical-sources != '[]'`. + +Finally, an admin must re-add `Lint code blocks` to the `master` required status checks. This admin step and the `test.yml` edits must land together: if `Lint code blocks` becomes required before it reports on `merge_group`, the queue hangs; if the trigger lands but the check is never required, nothing enforces it. + +## Concrete Steps + +Run these from the repository root, which in this worktree is the current working directory. Do not change directories into the main clone. + +To make the `test.yml` edits, open `.github/workflows/test.yml` and change the `on:` block from its current form to include the merge-queue trigger. The current block looks like this: + + on: + pull_request: + types: [opened, synchronize, reopened] + workflow_dispatch: + inputs: + ... + +Add the trigger so it reads: + + on: + pull_request: + types: [opened, synchronize, reopened] + merge_group: + workflow_dispatch: + inputs: + ... + +In the `detect-changes` job, the `Setup Node.js` step is currently gated on pull requests only: + + - name: Setup Node.js + if: github.event_name == 'pull_request' + +Change its condition to also cover the merge group: + + - name: Setup Node.js + if: github.event_name == 'pull_request' || github.event_name == 'merge_group' + +In the same job's change-detection script, the diff base is currently taken only from the pull-request payload: + + ALL_CHANGED=$(git diff --name-only ${{ github.event.pull_request.base.sha }}...${{ github.sha }}) + +Compute the base from whichever event fired, so the merge-group branch diffs against the base GitHub recorded for the group. One safe way is to set a shell variable before the diff: + + if [ "${{ github.event_name }}" = "merge_group" ]; then + DIFF_BASE="${{ github.event.merge_group.base_sha }}" + else + DIFF_BASE="${{ github.event.pull_request.base.sha }}" + fi + ALL_CHANGED=$(git diff --name-only "$DIFF_BASE"...${{ github.sha }}) + +Finally, change the `lint-codeblocks` job condition from: + + if: github.event_name == 'pull_request' && needs.detect-changes.outputs.canonical-sources != '' && needs.detect-changes.outputs.canonical-sources != '[]' + +to: + + if: (github.event_name == 'pull_request' || github.event_name == 'merge_group') && needs.detect-changes.outputs.canonical-sources != '' && needs.detect-changes.outputs.canonical-sources != '[]' + +Commit the workflow change on a feature branch and open a PR, for example: + + git checkout -b 7412-merge-queue-phase-2 origin/master + git add .github/workflows/test.yml + git commit -m "ci(test): report Lint code blocks on merge_group for merge queue (#7412)" + git push -u origin 7412-merge-queue-phase-2 + +The admin step cannot be done from the repository. In the `master` branch protection or ruleset, add `Lint code blocks` back to the required status checks at the same time the PR above merges. + +You can inspect the current branch protection at any time to confirm state: + + gh api repos/influxdata/docs-v2/branches/master/protection \ + --jq '{strict: .required_status_checks.strict, contexts: [.required_status_checks.checks[].context]}' + +Before Phase 1 this returned `strict: true` with both contexts; after Phase 1 it returns `strict: false` with only `ci/circleci: build`; after Phase 2 it should again list `Lint code blocks`. + +## Validation and Acceptance + +Phase 1 acceptance is behavioral. Open a trivial documentation PR against `master`, click **Merge when ready**, and observe that GitHub creates a branch named `gh-readonly-queue/master/...`, that `ci/circleci: build` reports a result on that branch, and that the PR merges automatically once the check passes. If the PR instead merges instantly with no `gh-readonly-queue` branch, it bypassed the queue (see `Surprises & Discoveries`); merge through **Merge when ready** and avoid using a bypass. + +You can confirm a PR actually went through the queue by checking its timeline for the queue event. For PR number N: + + gh api graphql -f query='{repository(owner:"influxdata",name:"docs-v2"){pullRequest(number:N){timelineItems(last:30, itemTypes:[ADDED_TO_MERGE_QUEUE_EVENT, MERGED_EVENT]){nodes{__typename}}}}}' + +A queued merge shows an `AddedToMergeQueueEvent` followed by a `MergedEvent`. A bypassed merge shows only `MergedEvent`. + +If a queued PR hangs and never merges, the most likely cause is that CircleCI is not building the `gh-readonly-queue/*` branch. Confirm that the CircleCI project setting "Only build pull requests" is OFF (queue branches have no PR, so that setting would skip them), then re-queue the PR. + +Phase 2 acceptance is also behavioral. After the `merge_group` trigger lands and `Lint code blocks` is required again, push a PR that changes a canonical content file and merge it through the queue. On the `gh-readonly-queue/master/*` branch you should see both `ci/circleci: build` and `Lint code blocks` report results, and the PR should merge only after both pass. A PR that changes no canonical sources should still merge, because the lint job skips cleanly when there is nothing to lint, and GitHub treats a skipped required check as satisfied. + +## Idempotence and Recovery + +The settings steps are safe to repeat: setting `strict` to `false` again, or re-adding a required check that is already present, changes nothing. The `test.yml` edits are additive and can be reapplied without harm. To roll the queue back at any time, disable "Require merge queue" in `master` branch protection; no code revert is needed, because the only merged in-repo change is the `pr-autoupdate.yml` deletion. If Phase 2 ever causes the queue to hang, removing `Lint code blocks` from the required checks immediately unblocks it while you investigate. + +## Artifacts and Notes + +Branch-protection state after Phase 1, for reference: + + $ gh api repos/influxdata/docs-v2/branches/master/protection \ + --jq '{strict: .required_status_checks.strict, contexts: [.required_status_checks.checks[].context]}' + {"strict":false,"contexts":["ci/circleci: build"]} + +Evidence that the first post-enable merge (PR #7434) bypassed the queue: + + $ gh api graphql -f query='{repository(owner:"influxdata",name:"docs-v2"){pullRequest(number:7434){autoMergeRequest{enabledAt} timelineItems(last:30, itemTypes:[ADDED_TO_MERGE_QUEUE_EVENT, MERGED_EVENT]){nodes{__typename}}}}}' + {"data":{"repository":{"pullRequest":{"autoMergeRequest":null,"timelineItems":{"nodes":[{"__typename":"MergedEvent"}]}}}}} + +## Interfaces and Dependencies + +The files that must exist and be edited for Phase 2 are `.github/workflows/test.yml` (add `merge_group:`; handle the `merge_group` event in the `detect-changes` job and the `lint-codeblocks` condition) and, unchanged but depended upon, `.circleci/config.yml` (its `build` job already reports `ci/circleci: build` on all branches; its `deploy` job runs only on `master`). + +The required status check contexts must match exactly, character for character: `ci/circleci: build` and `Lint code blocks`. The GitHub Actions event fields used by the Phase 2 edits are `github.event.merge_group.base_sha` (the base commit GitHub recorded for the merge group) and `github.sha` (the head of the `gh-readonly-queue/*` branch). + +Related work items: issue #7412 (this rollout), issue #7433 (the `Lint code blocks` bug that gates Phase 2), and PR #7434 (Phase 1, merged, which deleted `pr-autoupdate.yml` and introduced this document). + +## Revision note + +2026-06-30: Rewrote this file from a short decision record into a self-contained ExecPlan following the PLANS.md pattern, because the remaining Phase 2 work needs a novice-followable specification and the rollout produced durable discoveries (queue bypass, build-not-reduced) worth recording. No facts were changed; the decisions and status were carried over and expanded with explicit context, concrete steps, and behavioral acceptance.