#[tokio::test]
async fn test_help_true_returns_schema_for_kg_create() {
let invocations = Arc::new(AtomicUsize::new(0));
let reg = build_help_registry(invocations.clone());
let result = reg
.dispatch("create", serde_json::json!({ "help": true }))
.await
.expect("help=true must succeed for a known verb");
assert_eq!(result["verb"], "create", "envelope must name the verb");
assert_eq!(
result["pack"], "helptest",
"envelope must name the owning pack"
);
assert!(
result["description"].as_str().is_some(),
"description must be a string"
);
let params = result["params"]
.as_array()
.expect("params must be a JSON array");
assert!(!params.is_empty(), "params array must not be empty");
let kind_param = params.iter().find(|p| p["name"] == "kind");
assert!(
kind_param.is_some(),
"params array must include the 'kind' parameter"
);
let kind_param = kind_param.unwrap();
assert_eq!(
kind_param["required"],
serde_json::json!(true),
"'kind' must be required"
);
assert_eq!(kind_param["type"], "string", "'kind' type must be 'string'");
let identifier_help = result["identifier_resolution"]
.as_object()
.expect("help=true must include the shared identifier contract");
assert!(identifier_help["full_uuid"]
.as_str()
.is_some_and(|text| text.contains("globally unique")));
assert!(identifier_help["short_prefix"]
.as_str()
.is_some_and(|text| text.contains("lookup scope belongs to the consuming parameter")));
assert!(identifier_help["parameter_rule"]
.as_str()
.is_some_and(|text| text.contains("submitted again")));
}
#[test]
fn event_target_resolution_metadata_has_a_conditional_contract() {
let mode = IdResolutionMode::EdgeOrEventTarget;
let text = resolution_mode_contract(mode).unwrap();
assert!(text.contains("kind=event accepts only a full subject UUID"));
assert!(text.contains("prefixes and names are rejected without graph resolution"));
assert!(text.contains("For kind=edge"));
assert!(text.contains("prefix or entity name resolves in the primary namespace"));
assert_eq!(resolution_mode_key(mode), "edge_or_event_target");
assert_eq!(
identifier_resolution_help()["resolution_modes"]["edge_or_event_target"],
text
);
}
#[tokio::test]
async fn test_help_true_uuid_param_carries_shared_id_contract() {
let invocations = Arc::new(AtomicUsize::new(0));
let reg = build_help_registry(invocations.clone());
let result = reg
.dispatch("get", serde_json::json!({ "help": true }))
.await
.expect("help=true must succeed for a known verb");
let params = result["params"]
.as_array()
.expect("params must be a JSON array");
let id_param = params
.iter()
.find(|p| p["name"] == "id")
.expect("params array must include the 'id' parameter");
let description = id_param["description"]
.as_str()
.expect("description must be a string");
assert!(
description.contains("UUID of the record to fetch"),
"shared contract must be appended, not replace, the verb-specific text; got: {description}"
);
assert!(
description.contains("no namespace filter"),
"id contract must state that by-ID prefix resolution applies NO namespace filter \
(ADR-007 Rev 6, `resolve_prefix_unfiltered`); got: {description}"
);
assert!(
!description.contains("namespace-scoped resolution"),
"id contract must not claim prefix resolution is namespace-scoped — get/update/\
delete/merge resolve prefixes unfiltered; got: {description}"
);
assert!(
description.to_ascii_lowercase().contains("prefix"),
"id contract must describe short-prefix semantics; got: {description}"
);
let link_result = reg
.dispatch("link", serde_json::json!({ "help": true }))
.await
.expect("help=true must succeed for link");
let link_params = link_result["params"]
.as_array()
.expect("link params must be a JSON array");
let source_id_param = link_params
.iter()
.find(|p| p["name"] == "source_id")
.expect("link params must include 'source_id'");
let source_id_description = source_id_param["description"]
.as_str()
.expect("description must be a string");
assert!(
source_id_description.contains("get/update/delete/merge/link"),
"id contract's by-ID verb enumeration must include 'link' alongside get/update/\
delete/merge, since link's source_id/target_id resolve through the same \
unfiltered path; got: {source_id_description}"
);
}