From bc779e3f862b1f34baa8135b23982fcdc0bb88d8 Mon Sep 17 00:00:00 2001 From: Callum Reid Date: Wed, 2 Sep 2026 18:56:23 -0700 Subject: [PATCH 1/2] [COVAL-5822] Model the dropped review-project and report request fields Review projects lost project_rules, blind_labeling_shown_metric_ids, and enforced_collaboration on create, and additionally add_linked_simulation_ids, remove_linked_simulation_ids, and metric_addition_completion_action on update. The two membership deltas are the ones that cost something: without them the CLI could only replace linked_simulation_ids wholesale, so there was no way to add or remove one simulation without re-sending the whole set. The API rejects a delta combined with the replacement, so the flags conflict with --simulation-ids. Reports lost simulation_output_ids and source_human_review_project_id on create, and additionally view_config on update. The report PATCH applies simulation_output_ids and source_human_review_project_id through model_fields_set, so an explicit null unpins the report; both take explicit_option to keep that distinct from an omission. view_config is a nested partial-update object the API validates and never accepts as null, so it stays a plain optional JSON value behind --view-config. Every review-project field is applied under an `is not None` guard, so none of them need the null-versus-omitted treatment. explicit_option moves from test_case.rs to common.rs. COVAL-5821 makes the same move; the content is identical, so whichever lands second drops the hunk. --- README.md | 15 ++ src/client/models/report.rs | 24 +++ src/client/models/review_project.rs | 27 +++ src/commands/reports.rs | 43 +++++ src/commands/review_projects.rs | 64 +++++++ tests/cli_tests.rs | 286 ++++++++++++++++++++++++++++ 6 files changed, 459 insertions(+) diff --git a/README.md b/README.md index c40088b..19c9b20 100644 --- a/README.md +++ b/README.md @@ -200,6 +200,21 @@ coval reports create \ --run-ids run1,run2 \ --compare-by test_case +# Pin a report to specific simulations from a human-review project +coval reports create \ + --name "Reviewed Subset" \ + --run-ids run1,run2 \ + --simulation-output-ids sim1,sim2 \ + --source-human-review-project-id 01ARZ3NDEKTSV4RRFFQ69G5FAV + +# Unpin it again (a flag can only set a value, so clearing needs an explicit null) +coval reports update --input-json '{"simulation_output_ids":null}' + +# Add and remove review-project simulations without re-sending the whole set +coval review-projects update \ + --add-simulation-ids sim3,sim4 \ + --remove-simulation-ids sim1 + # Merge existing reports into one report with a group per source report coval reports merge \ --name "Q3 Scorecard" \ diff --git a/src/client/models/report.rs b/src/client/models/report.rs index 90fe614..56fe4ea 100644 --- a/src/client/models/report.rs +++ b/src/client/models/report.rs @@ -89,6 +89,12 @@ pub enum ReportPermission { pub struct CreateReportRequest { pub name: String, pub run_ids: Vec, + /// Pins the report to a subset of the runs' simulations. + #[serde(skip_serializing_if = "Option::is_none")] + pub simulation_output_ids: Option>, + /// Human-review project the pinned simulations came from. + #[serde(skip_serializing_if = "Option::is_none")] + pub source_human_review_project_id: Option, #[serde(skip_serializing_if = "Option::is_none")] pub compare_by: Option, #[serde(skip_serializing_if = "Option::is_none")] @@ -109,10 +115,28 @@ pub struct UpdateReportRequest { pub name: Option, #[serde(skip_serializing_if = "Option::is_none")] pub run_ids: Option>, + // The API applies these through `model_fields_set`, so an explicit null unpins + // the report rather than leaving it as it was. + #[serde( + default, + deserialize_with = "super::explicit_option", + skip_serializing_if = "Option::is_none" + )] + pub simulation_output_ids: Option>>, + #[serde( + default, + deserialize_with = "super::explicit_option", + skip_serializing_if = "Option::is_none" + )] + pub source_human_review_project_id: Option>, #[serde(skip_serializing_if = "Option::is_none")] pub compare_by: Option, #[serde(skip_serializing_if = "Option::is_none")] pub metadata_key: Option, + /// Partial update to the saved view configuration. Its members are validated by + /// the API, and it must never be sent as null. + #[serde(skip_serializing_if = "Option::is_none")] + pub view_config: Option, #[serde(skip_serializing_if = "Option::is_none")] pub permissions: Option, } diff --git a/src/client/models/review_project.rs b/src/client/models/review_project.rs index e54e37a..5fcb701 100644 --- a/src/client/models/review_project.rs +++ b/src/client/models/review_project.rs @@ -57,6 +57,14 @@ pub struct CreateReviewProjectRequest { pub project_type: Option, #[serde(skip_serializing_if = "Option::is_none")] pub notifications: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub project_rules: Option>, + /// Must be a subset of `linked_metric_ids`. + #[serde(skip_serializing_if = "Option::is_none")] + pub blind_labeling_shown_metric_ids: Option>, + /// Only takes effect on a collaborative project. + #[serde(skip_serializing_if = "Option::is_none")] + pub enforced_collaboration: Option, } #[derive(Debug, Default, Serialize, Deserialize)] @@ -75,6 +83,25 @@ pub struct UpdateReviewProjectRequest { pub notifications: Option, #[serde(skip_serializing_if = "Option::is_none")] pub opted_out_assignees: Option>, + /// Adds to the linked simulations instead of replacing them; cannot be combined + /// with `linked_simulation_ids`. + #[serde(skip_serializing_if = "Option::is_none")] + pub add_linked_simulation_ids: Option>, + /// Removes from the linked simulations instead of replacing them; cannot be + /// combined with `linked_simulation_ids`. + #[serde(skip_serializing_if = "Option::is_none")] + pub remove_linked_simulation_ids: Option>, + #[serde(skip_serializing_if = "Option::is_none")] + pub project_rules: Option>, + /// Must be a subset of `linked_metric_ids`. + #[serde(skip_serializing_if = "Option::is_none")] + pub blind_labeling_shown_metric_ids: Option>, + /// What to do with already-completed assignments when linking a new metric. + #[serde(skip_serializing_if = "Option::is_none")] + pub metric_addition_completion_action: Option, + /// Only takes effect on a collaborative project. + #[serde(skip_serializing_if = "Option::is_none")] + pub enforced_collaboration: Option, } #[derive(Debug, Deserialize)] diff --git a/src/commands/reports.rs b/src/commands/reports.rs index 3a159e4..2c0ef34 100644 --- a/src/commands/reports.rs +++ b/src/commands/reports.rs @@ -106,6 +106,12 @@ pub struct CreateArgs { /// Report layout (default rows) #[arg(long, value_enum)] view_mode: Option, + /// Comma-separated simulation IDs pinning the report to a subset of the runs + #[arg(long, value_delimiter = ',')] + simulation_output_ids: Option>, + /// Human-review project the pinned simulations came from (26-character ULID) + #[arg(long)] + source_human_review_project_id: Option, /// Report visibility (default PRIVATE) #[arg(long, value_enum)] permissions: Option, @@ -145,6 +151,15 @@ pub struct UpdateArgs { /// Updated metadata key (only valid when compare-by is metadata) #[arg(long)] metadata_key: Option, + /// Updated comma-separated simulation IDs (replaces existing) + #[arg(long, value_delimiter = ',')] + simulation_output_ids: Option>, + /// Updated human-review project the pinned simulations came from + #[arg(long)] + source_human_review_project_id: Option, + /// JSON partial update to the saved view configuration + #[arg(long)] + view_config: Option, /// Updated visibility #[arg(long, value_enum)] permissions: Option, @@ -214,6 +229,16 @@ pub async fn execute(cmd: ReportCommands, client: &CovalClient, ctx: &OutputCont input_json::insert(&mut input, "compare_by", args.compare_by)?; input_json::insert(&mut input, "metadata_key", args.metadata_key)?; input_json::insert(&mut input, "view_mode", args.view_mode)?; + input_json::insert( + &mut input, + "simulation_output_ids", + args.simulation_output_ids, + )?; + input_json::insert( + &mut input, + "source_human_review_project_id", + args.source_human_review_project_id, + )?; input_json::insert(&mut input, "permissions", args.permissions)?; validate_metadata_key(&input)?; validate_custom_dimensions(&input)?; @@ -246,6 +271,22 @@ pub async fn execute(cmd: ReportCommands, client: &CovalClient, ctx: &OutputCont input_json::insert(&mut input, "run_ids", args.run_ids)?; input_json::insert(&mut input, "compare_by", args.compare_by)?; input_json::insert(&mut input, "metadata_key", args.metadata_key)?; + input_json::insert( + &mut input, + "simulation_output_ids", + args.simulation_output_ids, + )?; + input_json::insert( + &mut input, + "source_human_review_project_id", + args.source_human_review_project_id, + )?; + let view_config: Option = args + .view_config + .map(|raw| serde_json::from_str(&raw)) + .transpose() + .map_err(|e| anyhow::anyhow!("Invalid JSON for --view-config: {e}"))?; + input_json::insert(&mut input, "view_config", view_config)?; input_json::insert(&mut input, "permissions", args.permissions)?; validate_metadata_key(&input)?; let req: UpdateReportRequest = input_json::finish(input)?; @@ -378,6 +419,8 @@ async fn merge_reports( let request = CreateReportRequest { name: args.name, run_ids, + simulation_output_ids: None, + source_human_review_project_id: None, compare_by: Some(CompareBy::Custom), metadata_key: None, custom_dimensions: Some(vec![ReportCustomDimension { diff --git a/src/commands/review_projects.rs b/src/commands/review_projects.rs index 49c70c2..d43644a 100644 --- a/src/commands/review_projects.rs +++ b/src/commands/review_projects.rs @@ -74,6 +74,15 @@ pub struct CreateArgs { /// Enable notifications for assignees #[arg(long)] notifications: Option, + /// Comma-separated project rules + #[arg(long, value_delimiter = ',')] + project_rules: Option>, + /// Comma-separated metric IDs whose machine score stays visible during blind labeling + #[arg(long, value_delimiter = ',')] + blind_labeling_shown_metric_ids: Option>, + /// Require claims and explicit single-author completion (collaborative projects only) + #[arg(long, num_args = 0..=1, default_missing_value = "true")] + enforced_collaboration: Option, } #[derive(Args)] @@ -102,6 +111,24 @@ pub struct UpdateArgs { /// Comma-separated emails of assignees to opt out #[arg(long, value_delimiter = ',')] opted_out_assignees: Option>, + /// Comma-separated simulation output IDs to add, instead of replacing the linked set + #[arg(long, value_delimiter = ',', conflicts_with = "simulation_ids")] + add_simulation_ids: Option>, + /// Comma-separated simulation output IDs to remove, instead of replacing the linked set + #[arg(long, value_delimiter = ',', conflicts_with = "simulation_ids")] + remove_simulation_ids: Option>, + /// What to do with completed assignments when linking a new metric (e.g. REOPEN_COMPLETED) + #[arg(long)] + metric_addition_completion_action: Option, + /// Comma-separated project rules + #[arg(long, value_delimiter = ',')] + project_rules: Option>, + /// Comma-separated metric IDs whose machine score stays visible during blind labeling + #[arg(long, value_delimiter = ',')] + blind_labeling_shown_metric_ids: Option>, + /// Require claims and explicit single-author completion (collaborative projects only) + #[arg(long, num_args = 0..=1, default_missing_value = "true")] + enforced_collaboration: Option, } #[derive(Args)] @@ -160,6 +187,17 @@ pub async fn execute( input_json::insert(&mut input, "description", args.description)?; input_json::insert(&mut input, "project_type", args.project_type)?; input_json::insert(&mut input, "notifications", args.notifications)?; + input_json::insert(&mut input, "project_rules", args.project_rules)?; + input_json::insert( + &mut input, + "blind_labeling_shown_metric_ids", + args.blind_labeling_shown_metric_ids, + )?; + input_json::insert( + &mut input, + "enforced_collaboration", + args.enforced_collaboration, + )?; let req: CreateReviewProjectRequest = input_json::finish(input)?; let project = client.review_projects().create(req).await?; emit_one_with_actions( @@ -179,6 +217,32 @@ pub async fn execute( input_json::insert(&mut input, "linked_metric_ids", args.metric_ids)?; input_json::insert(&mut input, "notifications", args.notifications)?; input_json::insert(&mut input, "opted_out_assignees", args.opted_out_assignees)?; + input_json::insert( + &mut input, + "add_linked_simulation_ids", + args.add_simulation_ids, + )?; + input_json::insert( + &mut input, + "remove_linked_simulation_ids", + args.remove_simulation_ids, + )?; + input_json::insert( + &mut input, + "metric_addition_completion_action", + args.metric_addition_completion_action, + )?; + input_json::insert(&mut input, "project_rules", args.project_rules)?; + input_json::insert( + &mut input, + "blind_labeling_shown_metric_ids", + args.blind_labeling_shown_metric_ids, + )?; + input_json::insert( + &mut input, + "enforced_collaboration", + args.enforced_collaboration, + )?; let req: UpdateReviewProjectRequest = input_json::finish(input)?; let project = client .review_projects() diff --git a/tests/cli_tests.rs b/tests/cli_tests.rs index d78133c..7b756df 100644 --- a/tests/cli_tests.rs +++ b/tests/cli_tests.rs @@ -4002,6 +4002,292 @@ async fn test_review_projects_get() { .stdout(predicate::str::contains("proj123")); } +fn review_project_response() -> Value { + json!({ + "review_project": { + "id": "proj456", + "display_name": "New Project", + "assignees": ["alice@example.com"], + "linked_simulation_ids": ["sim1"], + "linked_metric_ids": ["met1"], + "project_type": "PROJECT_COLLABORATIVE", + "notifications": true, + "create_time": "2026-09-02T10:30:00Z", + "update_time": "2026-09-02T10:30:00Z" + } + }) +} + +fn report_response() -> Value { + json!({ + "report": { + "id": "01HXXXXXXXXXXXXXXXXXXXXXXX", + "name": "Scorecard", + "run_ids": ["run1"], + "compare_by": "none", + "permissions": "PRIVATE" + } + }) +} + +#[tokio::test] +async fn test_review_projects_create_forwards_every_modeled_field() { + let mock_server = MockServer::start().await; + let capture = BodyCapture::default(); + + Mock::given(method("POST")) + .and(path("/v1/review-projects")) + .and(header("X-API-Key", "test_key")) + .and(capture.clone()) + .respond_with(ResponseTemplate::new(200).set_body_json(review_project_response())) + .mount(&mock_server) + .await; + + coval() + .arg("--api-key") + .arg("test_key") + .arg("--api-url") + .arg(mock_server.uri()) + .arg("review-projects") + .arg("create") + .arg("--name") + .arg("New Project") + .arg("--assignees") + .arg("alice@example.com") + .arg("--simulation-ids") + .arg("sim1") + .arg("--metric-ids") + .arg("met1") + .arg("--project-rules") + .arg("rule-a,rule-b") + .arg("--blind-labeling-shown-metric-ids") + .arg("met1") + .arg("--enforced-collaboration") + .assert() + .success(); + + let body = capture.take(); + assert_eq!(body["project_rules"], json!(["rule-a", "rule-b"])); + assert_eq!(body["blind_labeling_shown_metric_ids"], json!(["met1"])); + assert_eq!(body["enforced_collaboration"], true); +} + +#[tokio::test] +async fn test_review_projects_update_sends_membership_deltas() { + let mock_server = MockServer::start().await; + let capture = BodyCapture::default(); + + Mock::given(method("PATCH")) + .and(path("/v1/review-projects/proj456")) + .and(header("X-API-Key", "test_key")) + .and(capture.clone()) + .respond_with(ResponseTemplate::new(200).set_body_json(review_project_response())) + .mount(&mock_server) + .await; + + coval() + .arg("--api-key") + .arg("test_key") + .arg("--api-url") + .arg(mock_server.uri()) + .arg("review-projects") + .arg("update") + .arg("proj456") + .arg("--add-simulation-ids") + .arg("sim2,sim3") + .arg("--remove-simulation-ids") + .arg("sim1") + .arg("--metric-addition-completion-action") + .arg("REOPEN_COMPLETED") + .assert() + .success(); + + let body = capture.take(); + assert_eq!(body["add_linked_simulation_ids"], json!(["sim2", "sim3"])); + assert_eq!(body["remove_linked_simulation_ids"], json!(["sim1"])); + assert_eq!( + body["metric_addition_completion_action"], + "REOPEN_COMPLETED" + ); + // Replacing the linked set is a different operation from a delta, so the + // wholesale field must not ride along. + assert!(body.get("linked_simulation_ids").is_none()); +} + +#[test] +fn test_review_projects_update_rejects_a_delta_with_a_replacement() { + coval() + .arg("--api-key") + .arg("test_key") + .arg("review-projects") + .arg("update") + .arg("proj456") + .arg("--simulation-ids") + .arg("sim1") + .arg("--add-simulation-ids") + .arg("sim2") + .assert() + .failure(); +} + +#[tokio::test] +async fn test_reports_create_forwards_pinned_simulations() { + let mock_server = MockServer::start().await; + let capture = BodyCapture::default(); + + Mock::given(method("POST")) + .and(path("/v1/reports")) + .and(header("X-API-Key", "test_key")) + .and(capture.clone()) + .respond_with(ResponseTemplate::new(200).set_body_json(report_response())) + .mount(&mock_server) + .await; + + coval() + .arg("--api-key") + .arg("test_key") + .arg("--api-url") + .arg(mock_server.uri()) + .arg("reports") + .arg("create") + .arg("--name") + .arg("Scorecard") + .arg("--run-ids") + .arg("run1") + .arg("--simulation-output-ids") + .arg("sim1,sim2") + .arg("--source-human-review-project-id") + .arg("01ARZ3NDEKTSV4RRFFQ69G5FAV") + .assert() + .success(); + + let body = capture.take(); + assert_eq!(body["simulation_output_ids"], json!(["sim1", "sim2"])); + assert_eq!( + body["source_human_review_project_id"], + "01ARZ3NDEKTSV4RRFFQ69G5FAV" + ); +} + +#[tokio::test] +async fn test_reports_update_forwards_view_config() { + let mock_server = MockServer::start().await; + let capture = BodyCapture::default(); + + Mock::given(method("PATCH")) + .and(path("/v1/reports/01HXXXXXXXXXXXXXXXXXXXXXXX")) + .and(header("X-API-Key", "test_key")) + .and(capture.clone()) + .respond_with(ResponseTemplate::new(200).set_body_json(report_response())) + .mount(&mock_server) + .await; + + coval() + .arg("--api-key") + .arg("test_key") + .arg("--api-url") + .arg(mock_server.uri()) + .arg("reports") + .arg("update") + .arg("01HXXXXXXXXXXXXXXXXXXXXXXX") + .arg("--view-config") + .arg(r#"{"view_mode":"grouped","secondary_compare_by":"agent"}"#) + .assert() + .success(); + + assert_eq!( + capture.take()["view_config"], + json!({"view_mode": "grouped", "secondary_compare_by": "agent"}) + ); +} + +#[test] +fn test_reports_update_rejects_invalid_view_config_json() { + coval() + .arg("--api-key") + .arg("test_key") + .arg("reports") + .arg("update") + .arg("01HXXXXXXXXXXXXXXXXXXXXXXX") + .arg("--view-config") + .arg("{not json") + .assert() + .failure() + .stderr(predicate::str::contains("Invalid JSON for --view-config")); +} + +#[tokio::test] +async fn test_reports_update_forwards_an_explicit_null_to_unpin() { + let mock_server = MockServer::start().await; + let capture = BodyCapture::default(); + + Mock::given(method("PATCH")) + .and(path("/v1/reports/01HXXXXXXXXXXXXXXXXXXXXXXX")) + .and(header("X-API-Key", "test_key")) + .and(capture.clone()) + .respond_with(ResponseTemplate::new(200).set_body_json(report_response())) + .mount(&mock_server) + .await; + + coval() + .arg("--api-key") + .arg("test_key") + .arg("--api-url") + .arg(mock_server.uri()) + .arg("reports") + .arg("update") + .arg("01HXXXXXXXXXXXXXXXXXXXXXXX") + .arg("--input-json") + .arg(r#"{"simulation_output_ids":null,"source_human_review_project_id":null}"#) + .assert() + .success(); + + // The API unpins through `model_fields_set`, so dropping the key would turn a + // deliberate unpin into a no-op. + let body = capture.take(); + for key in ["simulation_output_ids", "source_human_review_project_id"] { + assert!(body.get(key).is_some(), "{key} must be sent"); + assert!(body[key].is_null(), "{key} must be sent as null"); + } +} + +#[tokio::test] +async fn test_reports_update_omits_unset_fields() { + let mock_server = MockServer::start().await; + let capture = BodyCapture::default(); + + Mock::given(method("PATCH")) + .and(path("/v1/reports/01HXXXXXXXXXXXXXXXXXXXXXXX")) + .and(header("X-API-Key", "test_key")) + .and(capture.clone()) + .respond_with(ResponseTemplate::new(200).set_body_json(report_response())) + .mount(&mock_server) + .await; + + coval() + .arg("--api-key") + .arg("test_key") + .arg("--api-url") + .arg(mock_server.uri()) + .arg("reports") + .arg("update") + .arg("01HXXXXXXXXXXXXXXXXXXXXXXX") + .arg("--name") + .arg("Renamed") + .assert() + .success(); + + let body = capture.take(); + assert_eq!(body["name"], "Renamed"); + for key in [ + "simulation_output_ids", + "source_human_review_project_id", + "view_config", + ] { + assert!(body.get(key).is_none(), "unset {key} must be omitted"); + } +} + #[tokio::test] async fn test_review_projects_create() { let mock_server = MockServer::start().await; From ac3e4a19f5de1d22d9718feec4b51a5b6b2b8cbd Mon Sep 17 00:00:00 2001 From: Callum Reid Date: Thu, 3 Sep 2026 15:37:32 -0700 Subject: [PATCH 2/2] [COVAL-5822] Drop 14 stale review-project and report field gaps and refresh report --- api-coverage-report.md | 20 ++---------- api-coverage.toml | 70 ------------------------------------------ 2 files changed, 3 insertions(+), 87 deletions(-) diff --git a/api-coverage-report.md b/api-coverage-report.md index 659f9e9..c173e10 100644 --- a/api-coverage-report.md +++ b/api-coverage-report.md @@ -18,8 +18,8 @@ only when coverage actually changes. | Reviewed gaps | 62 | | Client operations | 143 | | Published request fields on covered operations | 363 | -| Request fields modeled by the CLI | 329 | -| Reviewed request-field gaps | 31 | +| Request fields modeled by the CLI | 343 | +| Reviewed request-field gaps | 17 | Catalog: https://api.coval.dev/v1/openapi @@ -50,7 +50,7 @@ Catalog: https://api.coval.dev/v1/openapi ## Coverage snapshot mismatches - `published_request_fields: recorded 360, current 363` -- `cli_modeled_request_fields: recorded 313, current 329` +- `cli_modeled_request_fields: recorded 313, current 343` ## Client-only operations @@ -148,15 +148,6 @@ Catalog: https://api.coval.dev/v1/openapi - `PATCH /agents/{id} workflows` - `PATCH /conversations/uploaded/{id} metadata` - `PATCH /metrics/{id} ivr_flow` -- `PATCH /reports/{id} simulation_output_ids` -- `PATCH /reports/{id} source_human_review_project_id` -- `PATCH /reports/{id} view_config` -- `PATCH /review-projects/{id} add_linked_simulation_ids` -- `PATCH /review-projects/{id} blind_labeling_shown_metric_ids` -- `PATCH /review-projects/{id} enforced_collaboration` -- `PATCH /review-projects/{id} metric_addition_completion_action` -- `PATCH /review-projects/{id} project_rules` -- `PATCH /review-projects/{id} remove_linked_simulation_ids` - `PATCH /run-templates/{id} agent_id` - `PATCH /run-templates/{id} persona_id` - `PATCH /run-templates/{id} tags` @@ -164,11 +155,6 @@ Catalog: https://api.coval.dev/v1/openapi - `PATCH /test-sets/{id} tags` - `POST /conversations/uploaded:submit tags` - `POST /metrics ivr_flow` -- `POST /reports simulation_output_ids` -- `POST /reports source_human_review_project_id` -- `POST /review-projects blind_labeling_shown_metric_ids` -- `POST /review-projects enforced_collaboration` -- `POST /review-projects project_rules` - `POST /run-templates agent_id` - `POST /run-templates persona_id` - `POST /run-templates tags` diff --git a/api-coverage.toml b/api-coverage.toml index 700e69a..b11ccf6 100644 --- a/api-coverage.toml +++ b/api-coverage.toml @@ -421,51 +421,6 @@ operation = "PATCH /conversations/uploaded/{conversation_id}" field = "metadata" reason = "The additive customer-metadata patch path is served but unmodeled; tracked under COVAL-5823." -[[known_field_gap]] -operation = "PATCH /reports/{report_id}" -field = "simulation_output_ids" -reason = "Report fields are served but unmodeled; tracked under COVAL-5822." - -[[known_field_gap]] -operation = "PATCH /reports/{report_id}" -field = "source_human_review_project_id" -reason = "Report fields are served but unmodeled; tracked under COVAL-5822." - -[[known_field_gap]] -operation = "PATCH /reports/{report_id}" -field = "view_config" -reason = "Report fields are served but unmodeled; tracked under COVAL-5822." - -[[known_field_gap]] -operation = "PATCH /review-projects/{project_id}" -field = "add_linked_simulation_ids" -reason = "Review-project fields are served but unmodeled; tracked under COVAL-5822." - -[[known_field_gap]] -operation = "PATCH /review-projects/{project_id}" -field = "blind_labeling_shown_metric_ids" -reason = "Review-project fields are served but unmodeled; tracked under COVAL-5822." - -[[known_field_gap]] -operation = "PATCH /review-projects/{project_id}" -field = "enforced_collaboration" -reason = "Review-project fields are served but unmodeled; tracked under COVAL-5822." - -[[known_field_gap]] -operation = "PATCH /review-projects/{project_id}" -field = "metric_addition_completion_action" -reason = "Review-project fields are served but unmodeled; tracked under COVAL-5822." - -[[known_field_gap]] -operation = "PATCH /review-projects/{project_id}" -field = "project_rules" -reason = "Review-project fields are served but unmodeled; tracked under COVAL-5822." - -[[known_field_gap]] -operation = "PATCH /review-projects/{project_id}" -field = "remove_linked_simulation_ids" -reason = "Review-project fields are served but unmodeled; tracked under COVAL-5822." - [[known_field_gap]] operation = "PATCH /run-templates/{run_template_id}" field = "agent_id" @@ -496,31 +451,6 @@ operation = "POST /conversations/uploaded:submit" field = "tags" reason = "Resource tagging on write is served but unmodeled; tracked under COVAL-5823." -[[known_field_gap]] -operation = "POST /reports" -field = "simulation_output_ids" -reason = "Report fields are served but unmodeled; tracked under COVAL-5822." - -[[known_field_gap]] -operation = "POST /reports" -field = "source_human_review_project_id" -reason = "Report fields are served but unmodeled; tracked under COVAL-5822." - -[[known_field_gap]] -operation = "POST /review-projects" -field = "blind_labeling_shown_metric_ids" -reason = "Review-project fields are served but unmodeled; tracked under COVAL-5822." - -[[known_field_gap]] -operation = "POST /review-projects" -field = "enforced_collaboration" -reason = "Review-project fields are served but unmodeled; tracked under COVAL-5822." - -[[known_field_gap]] -operation = "POST /review-projects" -field = "project_rules" -reason = "Review-project fields are served but unmodeled; tracked under COVAL-5822." - [[known_field_gap]] operation = "POST /run-templates" field = "agent_id"