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