Skip to content

Commit 773bb03

Browse files
committed
fix(test): the stdin gate's DeusData#1359 guards survive a registry with no zero-argument tool
DeusData#1181 gave list_projects pagination parameters, retiring the last empty-properties schema — and the two DeusData#1359 regression tests leaned on list_projects as their live zero-argument example, so main went red the moment the merge train composed (the PR was green on its July base, which predated these tests). The gate's schema→decision core is split behind a CBM_CLI_ENABLE_TEST_API seam, so the zero-argument branch stays pinned directly (empty properties, absent properties, populated properties) regardless of what the registry ships; list_projects now asserts its NEW truth (piped args accepted, TTY still refused); and the schema↔gate parity sweep keeps running over every tool without the impossible >=1 zero-argument floor. Production behavior is unchanged — this is the tests catching up with an intended schema change, plus a seam so they never again depend on a shipped example. Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
1 parent 4d7d9f1 commit 773bb03

2 files changed

Lines changed: 41 additions & 17 deletions

File tree

‎src/cli/cli.c‎

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12561,6 +12561,8 @@ static void cli_add_typed(yyjson_mut_doc *out, yyjson_mut_val *obj, const char *
1256112561
yyjson_mut_obj_add(obj, yyjson_mut_strcpy(out, key), vv);
1256212562
}
1256312563

12564+
static bool cli_stdin_allowed_for_schema(const char *schema_str);
12565+
1256412566
bool cbm_cli_args_from_stdin_allowed(const char *tool_name, bool stdin_is_tty) {
1256512567
/* An interactive run has nothing piped to read: consulting the terminal
1256612568
* would just sit waiting for the user to type JSON. Unchanged by #1359 —
@@ -12589,6 +12591,17 @@ bool cbm_cli_args_from_stdin_allowed(const char *tool_name, bool stdin_is_tty) {
1258912591
return false;
1259012592
}
1259112593

12594+
return cli_stdin_allowed_for_schema(schema_str);
12595+
}
12596+
12597+
/* Schema→decision core of the stdin gate, split out so the zero-argument
12598+
* branch stays TESTED even when no shipped tool is zero-argument anymore:
12599+
* #1181 gave list_projects pagination parameters, retiring the last
12600+
* empty-properties schema, and the #1359 regression tests had leaned on it
12601+
* as their live example. The product contract is unchanged — a schema that
12602+
* declares no properties means stdin has nothing to carry and the read is
12603+
* pure deadlock; the tests now exercise this path directly. */
12604+
static bool cli_stdin_allowed_for_schema(const char *schema_str) {
1259212605
yyjson_doc *schema_doc = yyjson_read(schema_str, strlen(schema_str), 0);
1259312606
if (!schema_doc) {
1259412607
/* The schemas are compile-time constants, so a parse failure means a
@@ -12604,6 +12617,12 @@ bool cbm_cli_args_from_stdin_allowed(const char *tool_name, bool stdin_is_tty) {
1260412617
return accepts_arguments;
1260512618
}
1260612619

12620+
#ifdef CBM_CLI_ENABLE_TEST_API
12621+
bool cbm_cli_stdin_allowed_for_schema_for_test(const char *schema_str) {
12622+
return cli_stdin_allowed_for_schema(schema_str);
12623+
}
12624+
#endif
12625+
1260712626
char *cbm_cli_build_args_json(const char *tool_name, int argc, char **argv, char **err_out) {
1260812627
if (err_out) {
1260912628
*err_out = NULL;

‎tests/test_cli.c‎

Lines changed: 22 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ int cbm_cli_activation_abort_cleanup_probe_for_test(void);
5454
bool cbm_cli_activation_test_ops_installed(void);
5555
int cbm_cli_build_yaml_stdio_mcp_block_for_test(const char *binary_path, bool goose_schema,
5656
char *block, size_t block_size);
57+
bool cbm_cli_stdin_allowed_for_schema_for_test(const char *schema_str);
5758

5859
TEST(cli_progress_visibility_policy) {
5960
ASSERT_TRUE(cbm_cli_progress_enabled(true, false));
@@ -12453,22 +12454,22 @@ TEST(cli_print_tool_help_issue680) {
1245312454
* properties, so stdin could never have carried anything it accepts: the read
1245412455
* was pure deadlock. Gate the read on the tool actually declaring arguments. */
1245512456
TEST(cli_zero_argument_tool_never_reads_stdin_issue1359) {
12456-
/* The reported hang: zero-argument tool + non-terminal stdin. */
12457-
ASSERT_FALSE(cbm_cli_args_from_stdin_allowed("list_projects", false));
12458-
12459-
/* The documented `echo '<json>' | cli <tool>` channel must survive. */
12460-
ASSERT_TRUE(cbm_cli_args_from_stdin_allowed("index_status", false));
12461-
ASSERT_TRUE(cbm_cli_args_from_stdin_allowed("search_graph", false));
12462-
ASSERT_TRUE(cbm_cli_args_from_stdin_allowed("index_repository", false));
12463-
12464-
/* Interactive runs never read the terminal for arguments — unchanged. */
12465-
ASSERT_FALSE(cbm_cli_args_from_stdin_allowed("index_status", true));
12457+
/* #1359's deadlock class: a tool whose schema declares no properties must
12458+
* never read stdin (nothing it could carry; the read is pure deadlock).
12459+
* Since #1181 no SHIPPED tool is zero-argument anymore — list_projects,
12460+
* the original example, now declares pagination properties — so the
12461+
* zero-argument branch is exercised directly through the schema seam,
12462+
* and list_projects asserts its NEW truth. */
12463+
ASSERT_FALSE(
12464+
cbm_cli_stdin_allowed_for_schema_for_test("{\"type\":\"object\",\"properties\":{}}"));
12465+
ASSERT_FALSE(cbm_cli_stdin_allowed_for_schema_for_test("{\"type\":\"object\"}"));
12466+
ASSERT_TRUE(cbm_cli_stdin_allowed_for_schema_for_test(
12467+
"{\"type\":\"object\",\"properties\":{\"p\":{\"type\":\"string\"}}}"));
12468+
12469+
/* list_projects now takes piped arguments (offset/limit/include_details);
12470+
* the TTY guard still refuses regardless of schema. */
12471+
ASSERT_TRUE(cbm_cli_args_from_stdin_allowed("list_projects", false));
1246612472
ASSERT_FALSE(cbm_cli_args_from_stdin_allowed("list_projects", true));
12467-
12468-
/* An unknown tool is rejected by name; blocking for input first can only
12469-
* delay that verdict, never change it. */
12470-
ASSERT_FALSE(cbm_cli_args_from_stdin_allowed("nope_not_a_tool", false));
12471-
ASSERT_FALSE(cbm_cli_args_from_stdin_allowed(NULL, false));
1247212473
PASS();
1247312474
}
1247412475

@@ -12496,8 +12497,12 @@ TEST(cli_stdin_args_gate_tracks_tool_schema_issue1359) {
1249612497
ASSERT_EQ(cbm_cli_args_from_stdin_allowed(name, false), declares_properties);
1249712498
ASSERT_FALSE(cbm_cli_args_from_stdin_allowed(name, true));
1249812499
}
12499-
/* list_projects at minimum; without one the sweep above proves nothing. */
12500-
ASSERT_GTE(zero_argument_tools, 1);
12500+
/* Since #1181 every shipped tool declares properties, so the sweep's
12501+
* zero-argument branch can be empty here — that branch is pinned directly
12502+
* against the schema seam in the test above, which survives the registry
12503+
* having no zero-argument example. The sweep still proves schema↔gate
12504+
* parity for every tool that exists. */
12505+
(void)zero_argument_tools;
1250112506
PASS();
1250212507
}
1250312508

0 commit comments

Comments
 (0)