///|
/// Interpret the explicit engine adapter without changing any authored Ion.
/// This is not a native IR 4.1/Ion codec or a general JSON-LD processor.
/// A caller that has the node identities of `file` and `unit_id` already, as
/// `@identities.nodes` gives them, passes them as `owned`, so that they are not
/// collected again.
pub fn interpret(
  file : @ir.IRFile,
  unit_id : String,
  entries : Array[MetadataEntry],
  capabilities~ : Capabilities = Capabilities::unavailable(),
  owned? : Map[String, Bool],
) -> Interpretation raise {
  let owners : Map[String, String] = Map([])
  if file.distribution is Library(package_name, _, definition) {
    for module_name, module_def in definition.modules {
      for name, _ in module_def.value.values {
        let fqname : @ir.FQName = {
          package_name,
          module_name,
          local_name: name,
        }
        owners[value_uri(file, fqname)] = "value:" + fqname.to_canonical()
      }
    }
  }
  let owned = match owned {
    Some(owned) => owned
    None => @identities.node_set(unit_id, file)
  }
  let facts : Map[String, NamingFact] = Map([])
  let unvalidated : Map[String, Bool] = Map([])
  let restored : Map[String, String] = Map([])
  for entry in entries {
    if !entry.data.annotations().any(a => a.text() == Some(ADAPTER_PROFILE)) {
      continue
    }
    if !owned.contains(entry.node_id) {
      raise Invalid(
        "metadata.invalid_holder",
        entry.node_id,
        "Attach the adapter to an owned engine node; graph subjects remain separate",
      )
    }
    let payload = fields(entry.data, entry.node_id)
    let document = text(
      required(payload, "document", entry.node_id),
      entry.node_id,
    )
    let document_address = address(document)
    if document_address.fragment != "/distribution" {
      raise Invalid(
        "metadata.invalid_document_owner", document, "Supply the containing document's distribution URI, separate from its subjects",
      )
    }
    let base = match payload.get("contextBase") {
      Some(value) => text(value, "contextBase")
      None => ""
    }
    let parent = match payload.get("@context") {
      Some(value) =>
        resolve_context(
          value,
          Context::new(),
          capabilities,
          base,
          Map([]),
          Map([]),
        )
      None => Context::new()
    }
    let metadata = required(payload, "$meta", entry.node_id)
    let context = scoped_context(metadata, parent, capabilities, base)
    for fact in graph(metadata, context, entry.node_id, document) {
      let predicate = fact.assertion.predicate
      if !is_target_names_predicate(predicate) {
        unvalidated[predicate] = true
        continue
      }
      let (subject, parsed) = declaration(fact.assertion.subject)
      let expected = value_uri(file, subject)
      if parsed.revision is Some(_) ||
        parsed.format != file.format_version.to_release_string() ||
        !owners.contains(expected) ||
        expected != fact.assertion.subject {
        raise Invalid(
          "metadata.unresolved_subject",
          fact.assertion.subject,
          "Name an existing, current ValueDefinition in this exact input; do not reuse body or storage paths",
        )
      }
      if !fact.is_json || fact.data is None {
        raise Invalid(
          "metadata.invalid_target_names", predicate, "Wrap one frontend/backend record in @json or declare @json coercion",
        )
      }
      let names = TargetNames::from_ion(
        fact.data.unwrap(),
        owner=fact.assertion.subject,
        language_ids=false,
      )
      let revision = match restored.get(predicate) {
        Some(revision) => revision
        None => {
          guard capabilities.restore_library is Some(restore) else {
            raise Invalid(
              "metadata.provider_unavailable", predicate, "Configure a host capability that freshly authenticates and restores the signed provider Library; metadata and matching digests cannot grant trust",
            )
          }
          let revision = observed_provider(
            predicate,
            restore(predicate),
            capabilities,
          )
          restored[predicate] = revision
          revision
        }
      }
      if !capabilities.target_names_interpreter {
        raise Invalid(
          "metadata.required_interpreter_unavailable", predicate, "Register target-name-language-ids before generation; the authored fact remains preserved",
        )
      }
      ignore(
        TargetNames::from_ion(fact.data.unwrap(), owner=fact.assertion.subject),
      )
      let owner = owners[expected]
      if facts.get(owner) is Some(old) {
        if old.names != names || old.provider_revision != revision {
          raise Invalid(
            "metadata.conflicting_target_names",
            owner,
            "Conflicting assertions from '" +
            old.assertions[0].document +
            "' and '" +
            document +
            "'; retain one consistent frontend/backend record",
          )
        }
        old.assertions.push(fact.assertion)
      } else {
        facts[owner] = {
          owner,
          names,
          assertions: [fact.assertion],
          provider_revision: revision,
        }
      }
    }
  }
  let keys = facts.keys().collect()
  keys.sort()
  let unknown = unvalidated.keys().collect()
  unknown.sort()
  { facts: keys.map(k => facts[k]), unvalidated_predicates: unknown, }
}