Skip to content

traffic_ctl: emit JSON null instead of YAML tilde - #13609

Open
brbzull0 wants to merge 12 commits into
apache:masterfrom
brbzull0:fix/traffic-ctl-json-null
Open

traffic_ctl: emit JSON null instead of YAML tilde#13609
brbzull0 wants to merge 12 commits into
apache:masterfrom
brbzull0:fix/traffic-ctl-json-null

Conversation

@brbzull0

@brbzull0 brbzull0 commented Sep 1, 2026

Copy link
Copy Markdown
Contributor

What

traffic_ctl advertises JSON output but emits YAML. The JSON encoders are
yaml-cpp emitters configured with YAML::DoubleQuoted << YAML::Flow, which
produces something that usually looks like JSON — until a value is null,
which yaml-cpp spells ~.

traffic_ctl hostdb status hits this on every freshly started server, in both
default and -f json mode, and exits 0 while doing it. A monitoring script
or dashboard sees success, then dies on the parse.

$ traffic_ctl hostdb status
{"metadata": {"timestamp": "...", "version": "..."}, "partitions": ~}
$ echo $?
0

$ traffic_ctl hostdb status | python3 -c 'import json,sys; json.load(sys.stdin)'
json.decoder.JSONDecodeError: Expecting value: line 1 column 160 (char 159)

The -f rpc wire trace shows the ~ arrives already formed from the server, so
this is not a client-side rendering problem:

$ traffic_ctl hostdb status -f rpc
--> {"id": "...", "jsonrpc": "2.0", "method": "get_hostdb_status", "params": {"hostname": ""}}
<-- {"jsonrpc": "2.0", "result": {"data": {"metadata": {...}, "partitions": ~}}, "id": "..."}

traffic_ctl plugin list has the same defect when plugin.config is empty.

It also violates its own schema

src/mgmt/rpc/schema/hostdb_status_schema.json declares partitions as
"type": "array". Validating the live payload against that schema:

json.loads      : FAIL -> Expecting value: line 1 column 198 (char 197)
yaml.safe_load  : OK -> partitions=None timestamp='1788196772'
jsonschema      : 2 violation(s)
   /metadata/timestamp : '1788196772' is not of type 'integer'
   /partitions : None is not of type 'array'

yaml.safe_load succeeding where json.loads fails is the whole bug in one
line: this is YAML labelled as JSON.

Why it happens

Two independent layers.

Layer 1 — the accumulator node is never initialised as a sequence. A
default-constructed YAML::Node is Null, not an empty Sequence. In
HostDB.cc, if every partition is empty the push_back loop never runs, so
partitions is emitted as null. Plugins.cc has the identical shape.

Layer 2 — there is no JSON serializer. Six sites each re-implemented "JSON"
as a yaml-cpp emitter with two manipulators, and none of them mapped null to
null.

This is a known limitation finally coming due. Standing comment in
YAMLCodec.h:

yamlcpp does not give us all the behavior we need, such as the way it handles
the null values. Json needs to use literal null and yamlcpp uses ~. If this
becomes a problem, then we may need to change the codec implementation

A second comment in the same file omits the response id rather than emit it
as null, specifically to dodge this. Every other null in every other payload
was still exposed.

The fix

Three commits.

1. Emit null instead of ~, and [] for empty accumulators.

  • Initialise the two accumulator nodes as sequences, so an empty result is [].
    This is what makes the payload schema-conformant — null would still not be
    an array.
  • Set LowerNull on the JSON emitters, so any remaining null anywhere in any
    payload is spelled null. This fixes the class of bug, not just the two
    observed instances.

2. Route every JSON emitter through one helper.

The first commit set LowerNull at the four emitters on the RPC path, but
SSLMultiCertMarshaller::to_json and StorageMarshaller::to_json build their
own emitters off that path and were missed. Neither can emit a null today, so
nothing was broken, but both were one null away from the same bug.

ts::Yaml::configure_json_emitter() in include/tsutil/YamlCfg.h is now the
single place that puts an emitter into JSON mode. The invariant is greppable:

$ git grep -n 'SetNullFormat\|YAML::DoubleQuoted' -- src/ include/
include/tsutil/YamlCfg.h:54:    emitter.SetNullFormat(YAML::LowerNull);
include/tsutil/YamlCfg.h:55:    emitter << YAML::DoubleQuoted << YAML::Flow;

3. Review fixes. Direct include of tsutil/YamlCfg.h in CtrlPrinters.cc
rather than relying on a transitive one, and corrected comment wording — the
helper comment had overstated the output as valid JSON for every node type but
null, which holds only for the node shapes these callers build. Tags, anchors
and aliases still emit YAML that JSON does not accept.

LowerNull and Emitter::SetNullFormat exist both in the in-tree yaml-cpp
0.9.0 and in 0.8.0, the minimum EXTERNAL_YAML_CPP accepts, so both build
configurations are covered. SetNullFormat(...) is used rather than the
<< YAML::LowerNull manipulator because the method is FmtScope::Global while
the stream form routes through SetLocalValue at FmtScope::Local.

Compatibility

This does not trade YAML support for JSON support. In YAML, ~ and null
are the same value — YAML 1.2 resolves ~, null, Null, NULL and empty all
to null, and yaml-cpp implements exactly that:

bool IsNullString(const char* str, std::size_t size) {
  return size == 0 || same(str, size, "~") || same(str, size, "null") ||
         same(str, size, "Null") || same(str, size, "NULL");
}

The two spellings differ only in portability:

Spelling Valid YAML Valid JSON
~ yes no
null yes yes

null is the strict superset, so this moves the output into the intersection of
both formats rather than favouring one. Verified by round-trip: emitting with
LowerNull produces {"a": null}, which re-parses through yaml-cpp as
IsNull() == true — a genuine null, not the string "null".

LowerNull changes nothing else. Same node set emitted both ways:

Field Before After
null node ~ null
empty sequence [] []
empty map {} {}
string "~" "~" "~"
string "null" "null" "null"
number, bool, empty string unchanged unchanged

Specifically unaffected:

  • YAML input. The architecture doc's yamlcpp rationale is about the server
    accepting JSON or YAML. This changes encoders only; the decoder and
    YAML::Load path are untouched.
  • jsonrpc_response_schema.json. It places no type constraint on result.
    The id field keeps its documented deviation — still omitted, not nulled.
  • Existing tests. No gold file in tests/ contains a tilde.

The only conceivable breakage is a consumer string-matching ~, which would be
a consumer hand-parsing invalid JSON. No metric names, config keys, or API
signatures change.

Testing

Check Before After
hostdb status human "partitions": ~, exit 0 "partitions": []
hostdb statusjson.load JSONDecodeError col 160 parses
hostdb status -f jsonjson.load JSONDecodeError col 198 parses
wire trace -f rpc "partitions": ~ "partitions": []
jsonschema violations 2 1 (see below)
plugin list, empty plugin.config "plugins": ~ "plugins": []
plugin list, plugins loaded ok ok, unregressed
config ssl-multicert show --json ok ok, now via the helper
unit test suite 167/167
autests (14, incl. jsonrpc_api_schema) 13 pass
format target clean

Both layers were verified independently. To prove the emitter change on its
own, the sequence-init hunk was reverted and the build rerun, exercising the
untouched uninitialised-node path:

<-- {"jsonrpc": "2.0", "result": {"data": {"source": "plugin.config", "plugins": null}}, "id": "..."}
PARSED OK -> plugins = None

null rather than ~, and it parses.

The one autest failure is basic_plugin_handler, which fails identically on
unmodified master — three plugin init strings never reach traffic.out on
macOS. Confirmed by building pristine d01f3caf6a and running it there.

Still to do

No autest asserts that -f json output parses. That gap is why the tilde
shipped green: the suite's only JSON parse assertions are
validate_json_contains (used twice, both on server status) and the JSONRPC
response validator, and none of them exercises a payload containing a null.
hostdb status and plugin list have no autest coverage at all. A gold file
would not help — it would have matched ~ indefinitely, so the assertion has to
be a real parse on the empty-HostDB and no-plugins cases.

Candidate for Backport to 10.2.x, where hostdb status first shipped.

Out of scope

hostdb status still emits "timestamp": "1788196772" — a string where the
schema declares integer. This is the remaining schema violation above.
YAML::DoubleQuoted quotes every scalar, so every numeric field in every
-f json payload is a JSON string. Dropping DoubleQuoted is not a fix —
yaml-cpp would then emit unquoted strings and break JSON differently. Needs its
own design decision and a separate issue.

traffic_ctl plugin list -f json ignores the format flag and prints the
human-readable table. Unrelated to this change; present before and after.

The JSON encoders are yaml-cpp emitters, and yaml-cpp spells null as
`~`, so any RPC payload holding a null value was rejected by every
JSON parser. `hostdb status` hit this on every freshly started server
and still exited 0, so callers saw success and then failed to parse.

Initialise the two accumulator nodes as sequences so an empty result
is `[]` rather than null, which also satisfies the published schema,
and set LowerNull on the four JSON emitters so any remaining null is
spelled `null`. Both spellings parse back as null in YAML, so the
server's ability to accept YAML input is unaffected.
@brbzull0 brbzull0 added this to the 11.0.0 milestone Sep 1, 2026
@brbzull0 brbzull0 self-assigned this Sep 1, 2026
Copilot AI lite review requested due to automatic review settings September 1, 2026 09:56
@brbzull0 brbzull0 added the JSONRPC JSONRPC 2.0 related work. label Sep 1, 2026

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Warning

Copilot couldn't run its full agentic review because it didn't start before the timeout. Make sure your repository has a runner available, or add a copilot-code-review.yml file specifying one with the runs-on attribute. See the docs for more details.

Pull request overview

Fixes invalid JSON output caused by yaml-cpp emitting null as ~, ensuring RPC/traffic_ctl JSON outputs use literal null and empty accumulators emit [] per schema.

Changes:

  • Configure multiple yaml-cpp emitters to output null via YAML::LowerNull.
  • Initialize accumulator YAML::Nodes as sequences so empty results serialize as [] instead of null.
  • Update JSON-RPC architecture/docs to reflect the null-emission behavior.

Reviewed changes

Copilot reviewed 6 out of 6 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
src/traffic_ctl/CtrlPrinters.cc Ensures traffic_ctl JSON output uses literal null rather than ~.
src/mgmt/rpc/handlers/plugins/Plugins.cc Makes plugin list accumulator a sequence so empty results emit [].
src/mgmt/rpc/handlers/hostdb/HostDB.cc Makes partitions accumulator a sequence so empty results emit [].
include/shared/rpc/yaml_codecs.h Configures JSONRPC request encoder emitter to output literal null.
include/mgmt/rpc/jsonrpc/json/YAMLCodec.h Configures response encoders to output literal null and updates inline docs.
doc/developer-guide/jsonrpc/jsonrpc-architecture.en.rst Documents the null vs ~ behavior for JSON output.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread include/mgmt/rpc/jsonrpc/json/YAMLCodec.h
Comment thread include/mgmt/rpc/jsonrpc/json/YAMLCodec.h Outdated
Comment thread doc/developer-guide/jsonrpc/jsonrpc-architecture.en.rst Outdated
The tilde fix set LowerNull at the four emitters on the RPC path, but
SSLMultiCertMarshaller::to_json and StorageMarshaller::to_json build
their own emitters and were missed. Neither can emit a null today, so
nothing is broken, but both are one null away from the same bug.

Collapse the DoubleQuoted/Flow/LowerNull idiom into
ts::Yaml::configure_json_emitter() so a new emitter cannot silently
omit part of it. There is now exactly one place in the tree that puts
an emitter into JSON mode.
Copilot AI review requested due to automatic review settings September 1, 2026 15:21

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Warning

Copilot couldn't run its full agentic review because it didn't start before the timeout. Make sure your repository has a runner available, or add a copilot-code-review.yml file specifying one with the runs-on attribute. See the docs for more details.

Pull request overview

Copilot reviewed 9 out of 9 changed files in this pull request and generated 3 comments.

Comment thread include/tsutil/YamlCfg.h
Comment thread src/traffic_ctl/CtrlPrinters.cc
Comment thread include/mgmt/rpc/jsonrpc/json/YAMLCodec.h Outdated
Include tsutil/YamlCfg.h directly in CtrlPrinters.cc rather than
relying on it arriving through the codec headers.

Correct the helper comment, which claimed the output was valid JSON
for every node type but null. That holds only for the node shapes
these callers build; a tag, anchor or alias still emits YAML that
JSON does not accept. Say so, and use the canonical yaml-cpp, YAML
and JSON spellings in the comments and the architecture doc.
Copilot AI review requested due to automatic review settings September 1, 2026 15:54

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Warning

Copilot couldn't run its full agentic review because it didn't start before the timeout. Make sure your repository has a runner available, or add a copilot-code-review.yml file specifying one with the runs-on attribute. See the docs for more details.

Pull request overview

Copilot reviewed 9 out of 9 changed files in this pull request and generated 1 comment.

Comment thread include/tsutil/YamlCfg.h

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Warning

Copilot couldn't run its full agentic review because it didn't start before the timeout. Make sure your repository has a runner available, or add a copilot-code-review.yml file specifying one with the runs-on attribute. See the docs for more details.

Pull request overview

Copilot reviewed 9 out of 9 changed files in this pull request and generated 3 comments.

Comment thread include/tsutil/YamlCfg.h
Comment thread src/mgmt/rpc/handlers/hostdb/HostDB.cc
Comment thread src/mgmt/rpc/handlers/plugins/Plugins.cc
Nothing asserted that -f json output parses, which is how the yaml-cpp
`~` went unnoticed with every CI job green. A gold file cannot catch it
either, since it matches `~` forever, so this parses the output for real
and covers the empty HostDB and no-plugins cases that trigger it.

Also scope the emitter comment: flow style with every scalar quoted
parses as JSON but is not type-faithful, so numbers and booleans arrive
as strings.
Copilot AI review requested due to automatic review settings September 7, 2026 10:36

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Warning

Copilot couldn't run its full agentic review because it didn't start before the timeout. Make sure your repository has a runner available, or add a copilot-code-review.yml file specifying one with the runs-on attribute. See the docs for more details.

Pull request overview

Copilot reviewed 11 out of 11 changed files in this pull request and generated 3 comments.

Comment thread tests/gold_tests/traffic_ctl/traffic_ctl_test_utils.py Outdated
Comment thread tests/gold_tests/traffic_ctl/traffic_ctl_test_utils.py
Comment thread doc/developer-guide/jsonrpc/jsonrpc-architecture.en.rst
validate_is_valid_json and validate_json_contains appended `| python3 -c
...` to the command, putting a second process at the end of the pipeline.
The shell reports only the last command's exit status, so traffic_ctl's own
exit code never reached the ReturnCode check that TrafficCtl.add_test sets
on every test run. A run whose traffic_ctl exited non-zero passed as long as
the output happened to parse.

Both checks now run in the autest process as a Testers.Lambda over the
captured stdout file. traffic_ctl stays the only process in the run, so its
exit status is the one the harness compares, and the JSON result is reported
separately with the raw output attached rather than collapsing into the
return code.

set -o pipefail is not an option here: CI runs /bin/sh as dash, which
rejects the flag outright, and it would still merge the two distinct
failures into one number.

Also quote the hostname interpolated into `hostdb status`, omitting it
entirely when empty since an empty argument is not the same as no argument,
and factor the duplicated lookup of autest's injected Testers/All into one
helper that searches out the frame carrying those names.
Copilot AI review requested due to automatic review settings September 7, 2026 16:13

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Warning

Copilot couldn't run its full agentic review because it didn't start before the timeout. Make sure your repository has a runner available, or add a copilot-code-review.yml file specifying one with the runs-on attribute. See the docs for more details.

Pull request overview

Copilot reviewed 11 out of 11 changed files in this pull request and generated 3 comments.

Comment thread tests/gold_tests/traffic_ctl/traffic_ctl_json_null.test.py
Comment thread tests/gold_tests/traffic_ctl/traffic_ctl_test_utils.py Outdated
Comment thread tests/gold_tests/traffic_ctl/traffic_ctl_test_utils.py Outdated
…ministic

_test_file_globals searched for autest's injected `Testers` alone, so a
frame carrying that name but not `All` satisfied the search and then failed
inside validate_contains_all with a bare KeyError. Require every injected
name the module uses, and name them in the error.

_read_stdout opened the captured stream in text mode with no encoding, which
means the decode follows the runner's locale. Under LC_ALL=C the preferred
encoding is US-ASCII, so a non-ASCII byte in otherwise identical output
decoded to U+FFFD there and nowhere else; a validate_json_contains
comparison against such a field would then fail for no real reason. Decode
as UTF-8, which JSON requires anyway.

Undecodable bytes stay replaced rather than strict on purpose. autest treats
an exception raised by a tester callback as fatal, setting KillOnFailure and
abandoning the remainder of the test run, whereas a replaced byte simply
fails the JSON parse and is reported with the output attached.
Copilot AI review requested due to automatic review settings September 8, 2026 07:39

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔵 Needs a closer look

The new JSON field-check helper compares parsed values to un-stringified expected values, which can produce false negatives when callers pass non-string expectations.

Review details

Suppressed comments (1)

Previously missed (1) — in code that hasn't changed since the last review.

tests/gold_tests/traffic_ctl/traffic_ctl_test_utils.py:128

  • _check_json_fields() compares str(doc.get(key)) to the raw expected value. If a caller passes a non-string expected value (e.g. True, 0, []), this will report a mismatch even when the JSON value matches semantically. Coerce the expected side to str(...) as well so the helper behaves consistently regardless of the expected value type (and matches the previous behavior where everything was stringified into the generated python snippet).
  • Files reviewed: 11/11 changed files
  • Comments generated: 0 new
  • Review effort level: Lite

_check_json_fields stringified only the value read from the output and left
the expected side as whatever the caller passed. The shell pipeline it
replaced had stringified both sides, because it formatted expectations into
python source as quoted string literals, so `validate_json_contains(
partitions=[])` matched there and reported a false mismatch here. Coerce
both sides.

Document the rule that follows from comparing against str() of the parsed
value: the expectation is written the way Python renders that value, not the
way JSON spells it. Those agree for `[]` and for numbers, but a JSON boolean
reads as 'true' rather than True, which matters because get_server_status
emits its flags as the strings "true" and "false". Note also that a missing
key and a JSON null both render as 'None', so `field=None` passes for a
misspelled field.

No current caller is affected: all three pass their expectations as strings
already.
Copilot AI review requested due to automatic review settings September 8, 2026 09:42

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Warning

Copilot couldn't run its full agentic review because it didn't start before the timeout. Make sure your repository has a runner available, or add a copilot-code-review.yml file specifying one with the runs-on attribute. See the docs for more details.

Pull request overview

Copilot reviewed 11 out of 11 changed files in this pull request and generated 4 comments.

Comment thread tests/gold_tests/traffic_ctl/traffic_ctl_json_null.test.py
Comment thread tests/gold_tests/traffic_ctl/traffic_ctl_test_utils.py Outdated
Comment thread include/mgmt/rpc/jsonrpc/json/YAMLCodec.h Outdated
Comment thread tests/gold_tests/traffic_ctl/traffic_ctl_test_utils.py Outdated
The note added with the string comparison had it backwards. It claimed a
JSON boolean reads as 'true' rather than True, but json.loads turns a real
JSON boolean into Python True, which str() renders as 'True'. The 'false'
spelling these tests use comes from somewhere else: the emitters they cover
set YAML::DoubleQuoted, so every scalar leaves as a JSON string, and
get_server_status sends "is_draining": "false". Say that instead, and keep
the contrast with a genuine JSON boolean.

While here, read each field once per key instead of calling doc.get twice,
and capitalize json in the id comment in YAMLCodec.h.
Copilot AI review requested due to automatic review settings September 8, 2026 10:16

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Warning

Copilot couldn't run its full agentic review because it didn't start before the timeout. Make sure your repository has a runner available, or add a copilot-code-review.yml file specifying one with the runs-on attribute. See the docs for more details.

Pull request overview

Copilot reviewed 11 out of 11 changed files in this pull request and generated 3 comments.

Comment thread tests/gold_tests/traffic_ctl/traffic_ctl_test_utils.py Outdated
Comment thread tests/gold_tests/traffic_ctl/traffic_ctl_test_utils.py Outdated
Comment thread tests/gold_tests/traffic_ctl/traffic_ctl_test_utils.py Outdated
_test_file_globals reached up the call stack for `Testers` and `All` on the
premise that autest injects them into each test file's globals rather than
exposing them for import. The premise is wrong: core/test.py imports the
testers module itself and injects that module under the name, so both are
ordinary importables. Import them and delete the helper, which retires the
frame walk together with the question of which call site needs which name.

Decode captured output as strict UTF-8 and return the failure as a value.
Replacing undecodable bytes let output that is not UTF-8, and so not JSON,
parse cleanly and pass a check meant to reject exactly that. No wrapped
command reaches this today, because yaml-cpp substitutes U+FFFD in its own
double quoted scalar writer, so the strict decode states the requirement
rather than resting on that staying true. It is a value and not an exception
because autest treats an exception from a tester callback as fatal.

Guard the field check against a JSON document that is not an object. doc.get
assumed a dict, so valid non-object JSON raised AttributeError out of the
callback, which sets KillOnFailure and abandons the remainder of the run.
Every input now returns a result triple.

Drop a docstring claim that an unnamed encoding would follow the runner's
locale and mangle non-ASCII output. PEP 540 enables UTF-8 mode for the C and
POSIX locales, so it would not.
Copilot AI review requested due to automatic review settings September 8, 2026 13:01

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Warning

Copilot couldn't run its full agentic review because it didn't start before the timeout. Make sure your repository has a runner available, or add a copilot-code-review.yml file specifying one with the runs-on attribute. See the docs for more details.

Pull request overview

Copilot reviewed 11 out of 11 changed files in this pull request and generated 3 comments.

Comment thread tests/gold_tests/traffic_ctl/traffic_ctl_json_null.test.py Outdated
Comment thread tests/gold_tests/traffic_ctl/traffic_ctl_test_utils.py Outdated
Comment thread doc/developer-guide/jsonrpc/jsonrpc-architecture.en.rst
Damian Meden added 2 commits September 9, 2026 09:53
_check_json_fields read every field with doc.get, so a key that was absent
and a key present with a JSON null both arrived as None. An expectation of
None therefore matched a misspelled field name, and the check silently
accepted output that did not carry the field at all.

Test presence before comparing, and report a missing key as missing. That
also makes `field=None` mean what it looks like: the field is there and it
is null. The docstring said this gap existed; enforce it instead.
The hostdb case asserted `partitions` is `[]`, but the plugin case only
checked that the response parsed, so it would have passed on any shape the
emitter produced. Compare the whole result instead, the way the connection
tracker cases in traffic_ctl_server_output.test.py already do, which pins
`plugins` to `[]`. The field sits at result.data.plugins, out of reach of
validate_json_contains.

Verified in both directions: the assertion passes as written and fails when
the expectation is changed to the `~` the emitter produced before the fix.
Copilot AI review requested due to automatic review settings September 9, 2026 08:12

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Warning

Copilot couldn't run its full agentic review because it didn't start before the timeout. Make sure your repository has a runner available, or add a copilot-code-review.yml file specifying one with the runs-on attribute. See the docs for more details.

Pull request overview

Copilot reviewed 11 out of 11 changed files in this pull request and generated 4 comments.

Comment thread tests/gold_tests/traffic_ctl/traffic_ctl_json_null.test.py
Comment thread tests/gold_tests/traffic_ctl/traffic_ctl_test_utils.py
Comment thread tests/gold_tests/traffic_ctl/traffic_ctl_test_utils.py
Comment thread tests/gold_tests/traffic_ctl/traffic_ctl_test_utils.py
@brbzull0

brbzull0 commented Sep 9, 2026

Copy link
Copy Markdown
Contributor Author

[approve ci autest 3]

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Warning

Copilot couldn't run its full agentic review because it didn't start before the timeout. Make sure your repository has a runner available, or add a copilot-code-review.yml file specifying one with the runs-on attribute. See the docs for more details.

Pull request overview

Copilot reviewed 11 out of 11 changed files in this pull request and generated 5 comments.

Comment thread tests/gold_tests/traffic_ctl/traffic_ctl_test_utils.py
Comment thread tests/gold_tests/traffic_ctl/traffic_ctl_test_utils.py
Comment thread tests/gold_tests/traffic_ctl/traffic_ctl_test_utils.py
Comment thread tests/gold_tests/traffic_ctl/traffic_ctl_test_utils.py
Comment thread tests/gold_tests/traffic_ctl/traffic_ctl_test_utils.py Outdated
_check_json_fields compared str(actual) to str(want), which flattens the
JSON type out of both sides. An array and a string spelling of it become
the same text, so a field regressing from "partitions": [] to
"partitions": "[]" passed the check -- the class of bug these tests were
added to catch. A number regressing to a quoted number was masked the
same way.

Compare with == against the value the JSON parses to, so expectations are
written as Python values: partitions=[] for the array, is_draining='false'
for the JSON string the DoubleQuoted emitters produce. Both existing call
sites hold under that rule; only the partitions one changes spelling.

Null, the case this branch fixes, failed the check before and still does.

Render both sides with !r in the failure text. Without it a type mismatch
reported "partitions = [] (expected [])".
Copilot AI review requested due to automatic review settings September 10, 2026 09:25

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Warning

Copilot couldn't run its full agentic review because it didn't start before the timeout. Make sure your repository has a runner available, or add a copilot-code-review.yml file specifying one with the runs-on attribute. See the docs for more details.

Pull request overview

Copilot reviewed 11 out of 11 changed files in this pull request and generated 1 comment.

Comment thread tests/gold_tests/traffic_ctl/traffic_ctl_json_null.test.py
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

JSONRPC JSONRPC 2.0 related work.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants