{"record":{"id":"6b091ace97371404","repo":"Hmbown/CodeWhale","slug":"web-action-enum","errorCode":null,"errorMessage":"Web action enum","messagePattern":"Web action enum","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/tui/src/tools/subagent/tests.rs","lineNumber":7901,"sourceCode":"            .iter()\n            .find(|tool| tool.name == \"read\")\n            .and_then(|tool| tool.strict),\n        Some(true)\n    );\n}\n\n#[tokio::test]\nasync fn small_surface_read_only_child_discovers_web_deferred() {\n    let registry = small_surface_registry(FleetRole::Scout);\n    let catalog = registry.deferred_catalog_for_model(&FleetRole::Scout);\n    let web = catalog\n        .iter()\n        .find(|tool| tool.name == \"Web\")\n        .expect(\"configured Web evidence tool\");\n    assert_eq!(web.defer_loading, Some(true));\n    let actions = web.input_schema[\"properties\"][\"action\"][\"enum\"]\n        .as_array()\n        .expect(\"Web action enum\");\n    assert_eq!(actions, &[json!(\"search\"), json!(\"fetch\")]);\n\n    let mut surface = SubAgentToolSurface::new(catalog, &[]);\n    assert!(!model_tool_names(model_request_tools(&mut surface)).contains(\"Web\"));\n    let request_active = surface.active_names.clone();\n    let result = registry\n        .execute_from_surface(\n            \"agent_scout\",\n            \"\",\n            &mut surface,\n            &request_active,\n            TOOL_SEARCH_NAME,\n            json!({\"query\": \"web\", \"match\": \"regex\"}),\n        )\n        .await\n        .expect(\"child-local search\");\n    assert!(result.result.content.contains(\"\\\"tool_name\\\":\\\"Web\\\"\"));\n    let same_batch = registry","sourceCodeStart":7883,"sourceCodeEnd":7919,"githubUrl":"https://github.com/Hmbown/CodeWhale/blob/73e0f67d83c59909b571efdfc88c4bc28c309cb1/crates/tui/src/tools/subagent/tests.rs#L7883-L7919","documentation":"A panic from `.expect(\"Web action enum\")` in `small_surface_read_only_child_discovers_web_deferred`. The test walks the Web tool's JSON `input_schema` at `properties.action.enum` and asserts it is an array containing exactly `search` and `fetch`. If the schema omits an `action` property, the enum, or stores a non-array value, `as_array()` returns `None` and the expect panics. It encodes the contract that the child-visible Web tool exposes exactly the search/fetch actions.","triggerScenarios":"The Web tool's input schema changes: `action` renamed, enum moved to another schema location, schema built without the enum array, or `input_schema` is not a JSON object at the queried path (e.g. `Value::Null` via `/` indexing on a missing key).","commonSituations":"A developer edits the Web tool's parameter definition (adds modes, renames action values, switches schema representation) without updating this assertion; schema generation code regresses and drops the enum.","solutions":["Dump the Web tool's `input_schema` (e.g. `dbg!(&web.input_schema)`) to see its actual shape","Update the JSON path in the test if `action`/`enum` moved to a different schema location","If the schema intentionally changed, adjust the expected `actions` slice to the new allowed values; if accidental, restore the enum in the tool's schema definition"],"exampleFix":"// before\nweb.input_schema[\"properties\"][\"action\"][\"enum\"]\n    .as_array()\n    .expect(\"Web action enum\");\n// after (enum moved under anyOf)\nweb.input_schema[\"properties\"][\"action\"][\"anyOf\"][0][\"enum\"]\n    .as_array()\n    .expect(\"Web action enum\");","handlingStrategy":"validation","validationCode":"let action = web.input_schema.get(\"properties\")\n    .and_then(|p| p.get(\"action\"))\n    .and_then(|a| a.get(\"enum\"))\n    .and_then(|e| e.as_array());\nassert!(action.is_some(), \"Web schema lacks properties.action.enum: {:?}\", web.input_schema);","typeGuard":"fn schema_action_enum(schema: &serde_json::Value) -> Option<&Vec<serde_json::Value>> {\n    schema.get(\"properties\")?\n        .get(\"action\")?\n        .get(\"enum\")?\n        .as_array()\n}","tryCatchPattern":"let actions = schema_action_enum(&web.input_schema)\n    .unwrap_or_else(|| panic!(\"Web action enum missing; schema: {}\", web.input_schema));","preventionTips":["Build tool input schemas from typed definitions so enum paths cannot drift silently","When changing a tool's parameter schema, grep tests for the schema path","Keep a snapshot test of each tool's input_schema","Avoid hand-written JSON paths in assertions — centralize them"],"tags":["rust","json-schema","test-assertion","tool-catalog"],"backgroundTag":"schema-validation-failed","analyzedSha":"73e0f67d83c59909b571efdfc88c4bc28c309cb1","analyzedAt":"2026-09-22T01:30:00.501Z","contentChangedAt":"2026-09-22T01:30:00.501Z","schemaVersion":2},"datasetVersion":"2026-09-22T06:17:15.046Z"}