1pub mod macros;
18
19mod agent_sessions;
20pub mod agent_state;
21pub(crate) mod agents;
22mod agents_daemon;
23mod artifact_emit;
24pub(crate) mod assemble;
25pub mod asset_paths;
26mod bytes;
27mod calendar;
28mod channel_guardrails;
29mod channels;
30pub(crate) mod clock;
31pub(crate) mod collections;
32mod command_policy;
33pub(crate) mod compaction;
34mod compression;
35mod concurrency;
36pub(crate) use concurrency::cancelled_vm_error;
37mod connectors;
38mod cookies;
39mod cron;
40mod crypto;
41mod csv;
42mod datetime;
43pub(crate) use datetime::date_dict_from_millis;
44mod document;
45mod durable_step;
46mod event_log;
47mod external_agent;
48pub(crate) mod files;
49mod flow;
50pub(crate) mod fs;
51mod git;
52pub(crate) mod git_topology;
53mod grounding;
54pub(crate) mod harn_entry;
55pub(crate) mod hitl;
56mod hitl_read;
57pub mod host;
58pub mod http_response;
59pub(crate) mod io;
60mod iter;
61pub(crate) mod json;
62mod json_query;
63pub(crate) mod json_stream;
64mod jsonrpc;
65mod junit;
66mod lifecycle_receipts;
67mod logging;
68pub mod long_running;
69mod math;
70pub(crate) use math::call_seeded_random_method;
71pub(crate) mod memory;
72mod monitors;
73mod multipart;
74mod net;
75mod net_policy;
76mod oauth_dynreg;
77mod oauth_storage;
78pub(crate) mod observability;
79pub(crate) mod options;
80mod package_snapshot;
81pub(crate) use package_snapshot::PackageSnapshotRegistry;
82mod path;
83pub(crate) mod path_scope_guard;
84pub(crate) mod pool;
85#[cfg(feature = "postgres")]
86mod postgres;
87#[cfg(feature = "postgres")]
88pub use postgres::install_shared_pool_registry;
89pub mod process;
90pub(crate) mod process_spawn;
91mod project;
92mod project_catalog;
93mod project_enrich;
94mod regex;
95mod review;
96mod runtime_scope;
97pub(crate) mod sandbox;
98pub mod secret_scan;
99pub(crate) mod session_store;
100mod sets;
101pub(crate) mod shapes;
102mod skills;
103#[cfg(feature = "sqlite")]
104mod sqlite;
105pub(crate) mod strings;
106pub(crate) mod supervisor;
107pub mod template;
108mod testbench;
109mod testing;
110mod timing;
111pub mod token_redaction;
112pub(crate) mod tool_hooks;
113pub(crate) mod tools;
114pub mod tracing;
115mod transcript_compact;
116pub(crate) mod transcript_project;
117mod triggers_stdlib;
118mod tui;
119mod types;
120mod url_parse;
121mod vision;
122pub(crate) mod waitpoint;
123mod web;
124pub mod workflow_messages;
125pub(crate) mod xml;
126
127use crate::http::register_http_builtins;
128use crate::llm::register_llm_builtins;
129use crate::mcp::register_mcp_builtins;
130use crate::mcp_server::register_mcp_server_builtins;
131use crate::vm::Vm;
132
133pub(crate) use crate::schema::{json_to_vm_value, schema_result_value};
134pub(crate) fn set_thread_source_dir(dir: &std::path::Path) {
135 process::set_thread_source_dir(dir);
136}
137
138pub fn register_core_stdlib(vm: &mut Vm) {
140 types::register_type_builtins(vm);
141 math::register_math_builtins(vm);
142 strings::register_string_builtins(vm);
143 json::register_json_builtins(vm);
144 json_stream::register_json_stream_builtins(vm);
145 xml::register_xml_builtins(vm);
146 datetime::register_datetime_builtins(vm);
147 document::register_document_builtins(vm);
148 calendar::register_calendar_builtins(vm);
149 cron::register_cron_builtins(vm);
150 regex::register_regex_builtins(vm);
151 bytes::register_bytes_builtins(vm);
152 compression::register_compression_builtins(vm);
153 command_policy::register_command_policy_builtins(vm);
154 runtime_scope::register_runtime_scope_builtins(vm);
155 crypto::register_crypto_builtins(vm);
156 csv::register_csv_builtins(vm);
157 junit::register_junit_builtins(vm);
158 multipart::register_multipart_builtins(vm);
159 url_parse::register_url_builtins(vm);
160 web::register_web_builtins(vm);
161 cookies::register_cookie_builtins(vm);
162 path::register_path_helper_builtins(vm);
163 sets::register_set_builtins(vm);
164 collections::register_collection_builtins(vm);
165 iter::register_iter_builtins(vm);
166 event_log::register_event_log_builtins(vm);
167 durable_step::register_durable_step_builtins(vm);
168 channels::register_channel_builtins(vm);
169 channel_guardrails::register_channel_guardrail_builtins(vm);
170 shapes::register_shape_builtins(vm);
171 testing::register_testing_builtins(vm);
172 flow::register_flow_builtins(vm);
173 lifecycle_receipts::register_lifecycle_receipt_builtins(vm);
174 net_policy::register_net_policy_builtins(vm);
175 http_response::register_http_response_builtins(vm);
176}
177
178pub fn register_io_stdlib(vm: &mut Vm) {
180 io::register_io_builtins(vm);
181 host::register_host_builtins(vm);
182 fs::register_fs_builtins(vm);
183 package_snapshot::register_package_snapshot_builtins(vm);
184 files::register_file_builtins(vm);
185 git::register_git_builtins(vm);
186 vision::register_vision_builtins(vm);
187 agent_state::register_agent_state_builtins(vm);
188 memory::register_memory_builtins(vm);
189 session_store::register_session_store_builtins(vm);
190 net::register_net_builtins(vm);
191 process::register_process_builtins(vm);
192 process::register_path_builtins(vm);
193 sandbox::register_sandbox_builtins(vm);
194 clock::register_clock_builtins(vm);
197 crate::durable_rate_limit::register_durable_rate_limit_builtins(vm);
198 testbench::register_testbench_builtins(vm);
199 project::register_project_builtins(vm);
200 grounding::register_grounding_builtins(vm);
201 tracing::register_tracing_builtins(vm);
202 observability::register_observability_builtins(vm);
203 timing::register_timing_builtins(vm);
204 tui::register_tui_builtins(vm);
205}
206
207fn register_agent_stdlib_before_llm(vm: &mut Vm) {
208 concurrency::register_concurrency_builtins(vm);
209 connectors::register_connector_builtins(vm);
210 review::register_review_builtins(vm);
211 secret_scan::register_secret_scan_builtins(vm);
212 tools::register_tool_builtins(vm);
213 tool_hooks::register_tool_hooks_builtins(vm);
214 crate::composition::register_composition_builtins(vm);
215 skills::register_skill_builtins(vm);
216 agents_daemon::register_daemon_builtins(vm);
217 triggers_stdlib::register_trigger_builtins(vm);
218 #[cfg(feature = "postgres")]
219 postgres::register_postgres_builtins(vm);
220 #[cfg(feature = "sqlite")]
221 sqlite::register_sqlite_builtins(vm);
222 monitors::register_monitor_builtins(vm);
223 hitl::register_hitl_builtins(vm);
224 hitl_read::register_hitl_read_builtins(vm);
225 waitpoint::register_waitpoint_builtins(vm);
226 supervisor::register_supervisor_builtins(vm);
227 agents::register_agent_builtins(vm);
228 pool::register_pool_builtins(vm);
229 oauth_storage::register_oauth_storage_builtins(vm);
230 oauth_dynreg::register_oauth_dynreg_builtins(vm);
231 token_redaction::register_token_redaction_builtins(vm);
232 agent_sessions::register_agent_session_builtins(vm);
233 artifact_emit::register_artifact_emit_builtins(vm);
234 external_agent::register_external_agent_builtins(vm);
235 path_scope_guard::register_path_scope_guard_builtins(vm);
236 workflow_messages::register_workflow_message_builtins(vm);
237 transcript_compact::register_transcript_compaction_builtins(vm);
238 compaction::register_compaction_builtins(vm);
239 transcript_project::register_transcript_projection_builtins(vm);
240 assemble::register_assemble_context_builtin(vm);
241 crate::egress::register_egress_builtins(vm);
242 crate::security::register_security_builtins(vm);
243 register_http_builtins(vm);
244 jsonrpc::register_jsonrpc_builtins(vm);
245}
246
247fn register_agent_stdlib_after_llm(vm: &mut Vm) {
248 register_mcp_builtins(vm);
249 register_mcp_server_builtins(vm);
250 crate::step_runtime::register_step_builtins(vm);
251}
252
253pub fn register_agent_stdlib(vm: &mut Vm) {
255 register_agent_stdlib_before_llm(vm);
256 register_llm_builtins(vm);
257 register_agent_stdlib_after_llm(vm);
258}
259
260pub fn register_vm_stdlib(vm: &mut Vm) {
264 register_core_stdlib(vm);
265 register_io_stdlib(vm);
266 register_agent_stdlib(vm);
267 vm.project_declared_capability_methods();
268 if vm.harness().is_none() {
269 vm.set_harness(crate::harness::Harness::real());
270 }
271 if harn_parser::legacy_ambient_capabilities_enabled() && vm.global("harness").is_none() {
272 let harness = vm
273 .root_harness_value()
274 .expect("register_vm_stdlib installs a root Harness");
275 vm.set_global("harness", harness);
276 }
277 vm.project_legacy_capability_globals();
278 harn_builtin_registry::install_builtin_manifest(all_builtin_manifest());
279}
280
281pub(crate) fn rebind_execution_state_builtins(vm: &mut Vm) {
282 concurrency::register_concurrency_builtins(vm);
283}
284
285fn stdlib_probe_vm() -> Vm {
286 let mut vm = Vm::new();
287 register_vm_stdlib(&mut vm);
288 let tmp = std::env::temp_dir();
292 crate::store::register_store_builtins(&mut vm, &tmp);
293 crate::checkpoint::register_checkpoint_builtins(&mut vm, &tmp, "default");
294 crate::metadata::register_metadata_builtins(&mut vm, &tmp);
295 harn_builtin_registry::install_builtin_manifest(all_builtin_manifest());
300 vm
301}
302
303pub fn all_builtin_defs() -> &'static [&'static macros::VmBuiltinDef] {
319 let defs = ¯os::ALL_BUILTIN_DEFS;
320 validate_builtin_contracts(defs);
321 defs
322}
323
324fn validate_builtin_contracts(defs: &[¯os::VmBuiltinDef]) {
325 use harn_builtin_meta::BuiltinExposure;
326 let mut source_names = std::collections::BTreeSet::new();
327 let mut capability_methods = std::collections::BTreeSet::new();
328 for def in defs {
329 assert!(
330 def.contract.is_declared(),
331 "builtin `{}` has no typed exposure/effect contract",
332 def.sig.name
333 );
334 assert!(
335 !matches!(def.contract.exposure, BuiltinExposure::PureGlobal)
336 || def.contract.effects.is_empty(),
337 "ambient global builtin `{}` declares effects; effects must flow through Harness",
338 def.sig.name
339 );
340 if let BuiltinExposure::CapabilityFunction { authority_argument } = def.contract.exposure {
341 assert!(
342 !def.contract.effects.is_empty(),
343 "capability function `{}` must declare effects",
344 def.sig.name
345 );
346 assert!(
347 usize::from(authority_argument) < def.sig.params.len(),
348 "capability function `{}` authority argument is out of range",
349 def.sig.name
350 );
351 }
352 if def.runtime_only {
353 assert!(
354 matches!(def.contract.exposure, BuiltinExposure::RuntimeInternal),
355 "runtime_only builtin `{}` must use runtime_internal exposure",
356 def.sig.name
357 );
358 }
359 if let BuiltinExposure::HarnessMethod { method, .. } = def.contract.exposure {
360 assert!(
361 !method.is_empty(),
362 "harness method for `{}` cannot be empty",
363 def.sig.name
364 );
365 let BuiltinExposure::HarnessMethod { capability, method } = def.contract.exposure
366 else {
367 unreachable!()
368 };
369 assert!(
370 capability_methods.insert((capability, method)),
371 "duplicate contract for harness.{}.{}",
372 capability.field_name(),
373 method
374 );
375 }
376 if matches!(
377 def.contract.exposure,
378 BuiltinExposure::PureGlobal
379 | BuiltinExposure::CapabilityFunction { .. }
380 | BuiltinExposure::PrivilegedWire
381 | BuiltinExposure::HarnessMethod { .. }
382 ) {
383 assert!(
384 source_names.insert(def.sig.name),
385 "duplicate source contract name `{}`",
386 def.sig.name
387 );
388 }
389 }
390}
391
392pub fn force_link() {
400 let len = std::hint::black_box(macros::ALL_BUILTIN_DEFS.len());
406 assert!(
407 len >= 1,
408 "linkme distributed_slice ALL_BUILTIN_DEFS is empty — \
409 the binary is missing `harn_vm::stdlib::force_link()` at startup, \
410 or the linker stripped the harn-vm rlib statics (see linkme issue #36)"
411 );
412}
413
414pub fn all_builtin_manifest() -> &'static [&'static harn_builtin_registry::BuiltinManifestEntry] {
416 use std::sync::OnceLock;
417 static AGG: OnceLock<Vec<&'static harn_builtin_registry::BuiltinManifestEntry>> =
418 OnceLock::new();
419 AGG.get_or_init(|| {
420 let mut out = Vec::new();
421 let mut capability_methods = std::collections::BTreeSet::new();
422 for def in all_builtin_defs() {
423 if def.runtime_only {
424 continue;
425 }
426 out.push(
427 Box::leak(Box::new(harn_builtin_registry::BuiltinManifestEntry {
428 name: def.sig.name,
429 canonical_name: def.sig.name,
430 signature: &def.sig,
431 contract: def.contract,
432 })) as &'static harn_builtin_registry::BuiltinManifestEntry,
433 );
434 if let harn_builtin_meta::BuiltinExposure::HarnessMethod { capability, method } =
435 def.contract.exposure
436 {
437 capability_methods.insert((capability, method));
438 }
439 for alias in def.aliases {
440 let signature = Box::leak(Box::new(harn_builtin_meta::BuiltinSignature {
441 name: alias,
442 ..def.sig
443 }));
444 out.push(
445 Box::leak(Box::new(harn_builtin_registry::BuiltinManifestEntry {
446 name: alias,
447 canonical_name: def.sig.name,
448 signature,
449 contract: def.contract,
450 })) as &'static harn_builtin_registry::BuiltinManifestEntry,
451 );
452 }
453 }
454 for entry in harn_capability_contracts::manifest() {
455 let harn_builtin_meta::BuiltinExposure::HarnessMethod { capability, method } =
456 entry.contract.exposure
457 else {
458 unreachable!("leaf capability manifest contains a non-method contract")
459 };
460 if !capability_methods.insert((capability, method)) {
461 let runtime_entry = out
462 .iter()
463 .find(|candidate| candidate.contract.exposure == entry.contract.exposure)
464 .expect("duplicate capability key must have a runtime manifest entry");
465 assert_eq!(
466 runtime_entry.contract,
467 entry.contract,
468 "runtime effect contract drift for harness.{}.{}",
469 capability.field_name(),
470 method
471 );
472 assert_eq!(
473 runtime_entry.signature,
474 entry.signature,
475 "runtime signature drift for harness.{}.{}",
476 capability.field_name(),
477 method
478 );
479 continue;
480 }
481 out.push(*entry);
482 }
483 for group in harn_builtin_meta::host_capabilities::all_host_capability_groups() {
484 for method in group.methods {
485 if !capability_methods.insert((group.capability, *method)) {
486 continue;
487 }
488 let internal_name: &'static str = Box::leak(
489 format!("__cap_{}_{}", group.capability.field_name(), method).into_boxed_str(),
490 );
491 let params: &'static [harn_builtin_meta::Param] =
492 Box::leak(Box::new([harn_builtin_meta::Param::new(
493 "request",
494 harn_builtin_meta::Ty::Named("dict"),
495 )]));
496 let signature = Box::leak(Box::new(harn_builtin_meta::BuiltinSignature::simple(
497 internal_name,
498 params,
499 harn_builtin_meta::Ty::Named("dict"),
500 )));
501 out.push(Box::leak(Box::new(
502 harn_builtin_registry::BuiltinManifestEntry {
503 name: internal_name,
504 canonical_name: internal_name,
505 signature,
506 contract: harn_builtin_meta::BuiltinContract::harness(
507 group.capability,
508 method,
509 group.effects,
510 ),
511 },
512 )));
513 }
514 }
515 out
516 })
517 .as_slice()
518}
519
520struct BuiltinManifestIndex {
527 by_name: std::collections::HashMap<
528 &'static str,
529 &'static harn_builtin_registry::BuiltinManifestEntry,
530 >,
531 by_capability: std::collections::HashMap<
532 harn_builtin_meta::CapabilityId,
533 std::collections::HashMap<
534 &'static str,
535 &'static harn_builtin_registry::BuiltinManifestEntry,
536 >,
537 >,
538 recorded_effects_by_name: std::collections::HashMap<
539 &'static str,
540 &'static harn_builtin_registry::BuiltinManifestEntry,
541 >,
542}
543
544fn builtin_manifest_index() -> &'static BuiltinManifestIndex {
545 use harn_builtin_meta::BuiltinExposure;
546 use std::sync::OnceLock;
547
548 static INDEX: OnceLock<BuiltinManifestIndex> = OnceLock::new();
549 INDEX.get_or_init(|| {
550 let mut by_name = std::collections::HashMap::new();
551 let mut by_capability: std::collections::HashMap<
552 harn_builtin_meta::CapabilityId,
553 std::collections::HashMap<
554 &'static str,
555 &'static harn_builtin_registry::BuiltinManifestEntry,
556 >,
557 > = std::collections::HashMap::new();
558 let mut recorded_effects_by_name = std::collections::HashMap::new();
559 for entry in all_builtin_manifest() {
560 assert!(
561 by_name.insert(entry.name, *entry).is_none(),
562 "duplicate builtin manifest name `{}`",
563 entry.name
564 );
565 if let BuiltinExposure::HarnessMethod { capability, method } = entry.contract.exposure {
568 if entry.is_canonical() {
569 assert!(
570 by_capability
571 .entry(capability)
572 .or_default()
573 .insert(method, *entry)
574 .is_none(),
575 "duplicate Harness method manifest entry `harness.{}.{method}`",
576 capability.field_name()
577 );
578 }
579 }
580 if matches!(
581 entry.contract.exposure,
582 BuiltinExposure::CapabilityFunction { .. } | BuiltinExposure::PrivilegedWire
583 ) && !entry.contract.effects.is_empty()
584 {
585 recorded_effects_by_name.insert(entry.name, *entry);
586 }
587 }
588 BuiltinManifestIndex {
589 by_name,
590 by_capability,
591 recorded_effects_by_name,
592 }
593 })
594}
595
596pub fn builtin_for_harness_path(path: &str) -> Option<&'static str> {
603 let (field, method) = path.strip_prefix("harness.")?.split_once('.')?;
604 let capability = harn_builtin_meta::CapabilityId::from_field_name(field)?;
605 capability_method_manifest_entry(capability, method).map(|entry| entry.name)
606}
607
608pub fn harness_method_for_builtin(
610 name: &str,
611) -> Option<(harn_builtin_meta::CapabilityId, &'static str)> {
612 match builtin_manifest_entry(name)?.contract.exposure {
613 harn_builtin_meta::BuiltinExposure::HarnessMethod { capability, method } => {
614 Some((capability, method))
615 }
616 _ => None,
617 }
618}
619
620pub fn builtin_manifest_entry(
622 name: &str,
623) -> Option<&'static harn_builtin_registry::BuiltinManifestEntry> {
624 builtin_manifest_index().by_name.get(name).copied()
625}
626
627pub fn capability_method_manifest_entry(
629 capability: harn_builtin_meta::CapabilityId,
630 method: &str,
631) -> Option<&'static harn_builtin_registry::BuiltinManifestEntry> {
632 builtin_manifest_index()
633 .by_capability
634 .get(&capability)
635 .and_then(|methods| methods.get(method))
636 .copied()
637}
638
639pub fn recorded_effect_builtin_manifest_entry(
645 name: &str,
646) -> Option<&'static harn_builtin_registry::BuiltinManifestEntry> {
647 builtin_manifest_index()
648 .recorded_effects_by_name
649 .get(name)
650 .copied()
651}
652
653mod harness_migration;
654
655pub use harness_migration::{
656 harness_migration_for_builtin, HarnessBuiltinArgumentMigration, HarnessBuiltinMigration,
657};
658
659pub fn register_all_macro_builtins(vm: &mut Vm) {
664 for def in all_builtin_defs() {
665 vm.register_builtin_def(def);
666 }
667}
668
669pub fn stdlib_builtin_names() -> Vec<String> {
672 let vm = stdlib_probe_vm();
673 let mut names = vm.builtin_names();
674 for extra in harn_parser::builtin_signatures::LANGUAGE_INTRINSICS {
677 names.push(extra.to_string());
678 }
679 names
680}
681
682pub fn stdlib_builtin_metadata() -> Vec<crate::vm::VmBuiltinMetadata> {
684 stdlib_probe_vm().builtin_metadata()
685}
686
687pub fn reset_stdlib_state() {
700 logging::reset_logging_state();
701 process::reset_process_state();
702 clock::reset_clock_state();
703 io::reset_io_state();
704 sandbox::reset_sandbox_state();
705 git::reset_git_state();
706 fs::reset_fs_state();
707 json::reset_json_state();
708 json_stream::reset_json_stream_state();
709 host::reset_host_state();
710 host::reset_scoped_host_state();
711 observability::reset_observability_state();
712 timing::reset_timing_state();
713 durable_step::reset_durable_step_state();
714 crate::egress::reset_egress_policy_for_host();
715 hitl::reset_hitl_state();
716 crate::http::reset_http_state();
717 crate::external_agent::reset_external_agent_state();
718 monitors::reset_monitor_state();
719 waitpoint::reset_waitpoint_state();
720 triggers_stdlib::reset_auto_resume_timeouts();
721 compaction::reset_compaction_state();
722 agents::reset_agent_worker_state();
723 agents::workflow::reset_workflow_run_states();
724 pool::reset_pool_state();
725 #[cfg(feature = "postgres")]
726 postgres::reset_postgres_state();
727 #[cfg(feature = "sqlite")]
728 sqlite::reset_sqlite_state();
729 supervisor::reset_supervisor_state();
730 agents::records::reset_eval_metrics();
731 agents::records::reset_friction_events();
732 tools::clear_current_tool_registry();
733 tools::clear_tool_synthesis_cache();
734 vision::reset_vision_state();
735 crate::skills::clear_current_skill_registry();
736 template::reset_prompt_registry();
737 crate::triggers::clear_webhook_intake_state();
738 crate::llm::cache::reset_in_process_cache_state();
739}
740
741#[cfg(test)]
742mod tests {
743 use super::*;
744
745 #[tokio::test(flavor = "current_thread")]
746 async fn register_vm_stdlib_passes_default_harness_only_to_main() {
747 let chunk = crate::compile_source(
748 r"
749fn __probe_harness_clock(clock: HarnessClock) {
750 const now = clock.now_ms()
751 return now >= 0
752}
753
754fn main(harness: Harness) {
755 return __probe_harness_clock(harness.clock)
756}
757",
758 )
759 .expect("compile harness clock probe");
760 let mut vm = Vm::new();
761 register_vm_stdlib(&mut vm);
762
763 assert!(vm.root_harness_value().is_some());
764 assert!(vm.global("harness").is_none());
765 let result = vm
766 .execute(&chunk)
767 .await
768 .expect("execute harness clock probe");
769 assert!(matches!(result, crate::value::VmValue::Bool(true)));
770 }
771
772 #[test]
778 fn every_stdlib_builtin_reexport_names_a_registered_builtin() {
779 let registered: std::collections::HashSet<&str> = all_builtin_defs()
780 .iter()
781 .flat_map(|def| std::iter::once(def.sig.name).chain(def.aliases.iter().copied()))
782 .collect();
783
784 let mut checked = 0;
785 for entry in harn_stdlib::STDLIB_SOURCES {
786 for name in harn_stdlib::builtin_reexports(entry.module) {
787 assert!(
788 registered.contains(name),
789 "std/{} re-exports '{name}', which is not a registered builtin",
790 entry.module
791 );
792 checked += 1;
793 }
794 }
795 assert!(
796 checked > 0,
797 "no re-exports were checked — the table or the module list is not being read"
798 );
799 }
800
801 #[test]
802 fn ambient_effect_builtin_allowlist_is_empty() {
803 let offenders = all_builtin_defs()
804 .iter()
805 .filter(|def| {
806 matches!(
807 def.contract.exposure,
808 harn_builtin_meta::BuiltinExposure::PureGlobal
809 ) && !def.contract.effects.is_empty()
810 })
811 .map(|def| def.sig.name)
812 .collect::<Vec<_>>();
813
814 assert!(
815 offenders.is_empty(),
816 "ambient effect builtins are forbidden; route these through Harness: {offenders:?}"
817 );
818 }
819
820 #[test]
821 fn harness_builtin_migrations_preserve_canonical_call_shapes() {
822 use harn_builtin_meta::CapabilityId;
823
824 assert_eq!(
825 harness_migration_for_builtin("provider_capabilities"),
826 Some(HarnessBuiltinMigration {
827 capability: CapabilityId::Llm,
828 method: "provider_capabilities",
829 arguments: HarnessBuiltinArgumentMigration::Forward,
830 })
831 );
832 assert_eq!(
833 harness_migration_for_builtin("log_info"),
834 Some(HarnessBuiltinMigration {
835 capability: CapabilityId::Observability,
836 method: "log_info",
837 arguments: HarnessBuiltinArgumentMigration::Forward,
838 })
839 );
840 assert_eq!(
841 harness_migration_for_builtin("runtime_introspection"),
842 Some(HarnessBuiltinMigration {
843 capability: CapabilityId::Runtime,
844 method: "introspection",
845 arguments: HarnessBuiltinArgumentMigration::Forward,
846 })
847 );
848 assert_eq!(
849 harness_migration_for_builtin("project_fingerprint"),
850 Some(HarnessBuiltinMigration {
851 capability: CapabilityId::Project,
852 method: "fingerprint",
853 arguments: HarnessBuiltinArgumentMigration::Forward,
854 })
855 );
856 assert_eq!(
857 harness_migration_for_builtin("project_scan_tree_native"),
858 Some(HarnessBuiltinMigration {
859 capability: CapabilityId::Project,
860 method: "scan_tree",
861 arguments: HarnessBuiltinArgumentMigration::Forward,
862 })
863 );
864 assert_eq!(
865 harness_migration_for_builtin("llm_call"),
866 Some(HarnessBuiltinMigration {
867 capability: CapabilityId::Llm,
868 method: "call",
869 arguments: HarnessBuiltinArgumentMigration::Forward,
870 })
871 );
872 assert_eq!(
873 harness_migration_for_builtin("llm_call_structured"),
874 Some(HarnessBuiltinMigration {
875 capability: CapabilityId::Llm,
876 method: "call_structured",
877 arguments: HarnessBuiltinArgumentMigration::Forward,
878 })
879 );
880 assert_eq!(
881 harness_migration_for_builtin("security_policy"),
882 Some(HarnessBuiltinMigration {
883 capability: CapabilityId::System,
884 method: "security_policy",
885 arguments: HarnessBuiltinArgumentMigration::Forward,
886 })
887 );
888 assert_eq!(
889 harness_migration_for_builtin("llm_provider_status"),
890 Some(HarnessBuiltinMigration {
891 capability: CapabilityId::Llm,
892 method: "providers",
893 arguments: HarnessBuiltinArgumentMigration::Forward,
894 })
895 );
896 assert_eq!(
897 harness_migration_for_builtin("agent_session_current_id"),
898 Some(HarnessBuiltinMigration {
899 capability: CapabilityId::Agent,
900 method: "current_id",
901 arguments: HarnessBuiltinArgumentMigration::Forward,
902 })
903 );
904 assert_eq!(
905 harness_migration_for_builtin("metadata_set"),
906 Some(HarnessBuiltinMigration {
907 capability: CapabilityId::Project,
908 method: "metadata_set",
909 arguments: HarnessBuiltinArgumentMigration::RequestRecord(&[
910 "dir",
911 "namespace",
912 "data",
913 ]),
914 })
915 );
916 assert_eq!(
917 harness_migration_for_builtin("metadata_save"),
918 Some(HarnessBuiltinMigration {
919 capability: CapabilityId::Project,
920 method: "metadata_save",
921 arguments: HarnessBuiltinArgumentMigration::RequestRecord(&[]),
922 })
923 );
924 assert_eq!(
925 harness_migration_for_builtin("platform"),
926 Some(HarnessBuiltinMigration {
927 capability: CapabilityId::System,
928 method: "platform",
929 arguments: HarnessBuiltinArgumentMigration::CallThenProperty("os"),
930 })
931 );
932 assert_eq!(
933 harness_migration_for_builtin("arch"),
934 Some(HarnessBuiltinMigration {
935 capability: CapabilityId::System,
936 method: "platform",
937 arguments: HarnessBuiltinArgumentMigration::CallThenProperty("arch"),
938 })
939 );
940 assert_eq!(
941 harness_migration_for_builtin("home_dir"),
942 Some(HarnessBuiltinMigration {
943 capability: CapabilityId::Fs,
944 method: "home_dir",
945 arguments: HarnessBuiltinArgumentMigration::Forward,
946 })
947 );
948 assert_eq!(harness_migration_for_builtin("json_parse"), None);
949 }
950
951 #[test]
952 fn every_source_named_runtime_callable_has_a_typed_contract() {
953 let manifest_names = all_builtin_manifest()
954 .iter()
955 .map(|entry| entry.name)
956 .collect::<std::collections::HashSet<_>>();
957 let offenders = stdlib_probe_vm()
958 .builtin_names()
959 .into_iter()
960 .filter(|name| {
961 !name.starts_with("__")
962 && !manifest_names.contains(name.as_str())
963 && !harn_parser::builtin_signatures::is_language_intrinsic(name)
964 })
965 .collect::<Vec<_>>();
966
967 assert!(
968 offenders.is_empty(),
969 "runtime callables without typed source contracts bypass the Harness gate: {offenders:?}"
970 );
971 }
972
973 #[test]
974 fn builtin_manifest_indexes_preserve_the_authoritative_contracts() {
975 use harn_builtin_meta::BuiltinExposure;
976
977 let mut capability_entries = 0;
978 for entry in all_builtin_manifest() {
979 assert!(
980 std::ptr::eq(
981 builtin_manifest_entry(entry.name).expect("indexed builtin entry"),
982 *entry,
983 ),
984 "name index projected a different contract for `{}`",
985 entry.name
986 );
987 let should_record = matches!(
988 entry.contract.exposure,
989 BuiltinExposure::CapabilityFunction { .. } | BuiltinExposure::PrivilegedWire
990 ) && !entry.contract.effects.is_empty();
991 assert_eq!(
992 recorded_effect_builtin_manifest_entry(entry.name).is_some(),
993 should_record,
994 "recorded-effect index drifted for `{}`",
995 entry.name
996 );
997 if let BuiltinExposure::HarnessMethod { capability, method } = entry.contract.exposure {
998 capability_entries += 1;
999 let indexed = capability_method_manifest_entry(capability, method)
1000 .expect("indexed Harness method entry");
1001 assert_eq!(
1004 indexed.name,
1005 entry.canonical_name,
1006 "capability index projected a different builtin for `harness.{}.{method}`",
1007 capability.field_name()
1008 );
1009 assert_eq!(
1010 indexed.contract,
1011 entry.contract,
1012 "capability index projected a different contract for `harness.{}.{method}`",
1013 capability.field_name()
1014 );
1015 }
1016 }
1017 assert!(capability_entries > 0, "no Harness contracts were indexed");
1018 assert!(builtin_manifest_entry("__definitely_missing_builtin").is_none());
1019 assert!(capability_method_manifest_entry(
1020 harn_builtin_meta::CapabilityId::Fs,
1021 "__definitely_missing_method",
1022 )
1023 .is_none());
1024 }
1025}
1026
1027#[cfg(test)]
1028mod ambient_host_internal_projection_tests {
1029 use super::*;
1030
1031 #[test]
1032 fn ambient_bridge_projects_host_internal_emit_event_alias() {
1033 let previous = std::env::var_os(harn_parser::HARN_LEGACY_AMBIENT_CAPABILITIES_ENV);
1034 unsafe {
1035 std::env::set_var(harn_parser::HARN_LEGACY_AMBIENT_CAPABILITIES_ENV, "1");
1036 }
1037 let mut vm = Vm::new();
1038 register_vm_stdlib(&mut vm);
1039 assert!(
1040 vm.builtin_metadata_for("agent_emit_event").is_some(),
1041 "ambient bridge must project __host_agent_emit_event as agent_emit_event"
1042 );
1043 assert!(
1044 vm.builtin_metadata_for("__host_agent_emit_event").is_some(),
1045 "canonical host internal must remain registered"
1046 );
1047 unsafe {
1048 match previous {
1049 Some(value) => {
1050 std::env::set_var(harn_parser::HARN_LEGACY_AMBIENT_CAPABILITIES_ENV, value);
1051 }
1052 None => std::env::remove_var(harn_parser::HARN_LEGACY_AMBIENT_CAPABILITIES_ENV),
1053 }
1054 }
1055 }
1056}