Shared memory and context tools for agentic work.
Code Rooms
use crate::rfc_adapter::append_general_ref;
use crate::{IngestAdapter, IngestStats};
use m1nd_core::error::M1ndResult;
use m1nd_core::graph::{Graph, NodeProvenanceInput};
use m1nd_core::types::{EdgeDirection, FiniteF32, NodeType};
use quick_xml::events::Event;
use quick_xml::Reader;
use std::collections::{HashMap, HashSet};
use std::path::{Path, PathBuf};
use std::time::{Instant, SystemTime, UNIX_EPOCH};
use walkdir::WalkDir;
/// Maps a patent kind code to a L1GHT state.
fn kind_to_state(kind: &str) -> &'static str {
match kind {
"A1" | "A2" | "A9" => "draft", // Published application
"B1" | "B2" => "active", // Granted patent
"C1" | "C2" | "C3" => "active", // Reexamination certificate
"P1" | "P2" | "P3" | "P4" => "active", // Plant patent
"S1" => "active", // Design patent
"E1" => "active", // Reissue
"H1" => "deprecated", // Statutory invention registration
_ => "active",
}
/// Extracted fields from a patent XML document.
#[derive(Default, Debug)]
struct PatentRecord {
doc_number: String,
kind: String,
country: String,
title: String,
pub_date: String,
app_date: String,
assignees: Vec<String>,
inventors: Vec<String>,
abstract_text: String,
classifications: Vec<String>,
citations: Vec<String>,
/// Source format detected
format: PatentFormat,
#[derive(Default, Debug, Clone, Copy)]
enum PatentFormat {
#[default]
Unknown,
UsRedBook, // <us-patent-grant>
UsYellowBook, // <us-patent-application>
EpoDocDb, // <ep-patent-document>
impl PatentRecord {
fn external_id(&self) -> String {
let num = if self.doc_number.is_empty() {
"UNKNOWN"
} else {
&self.doc_number
};
let country = if self.country.is_empty() {
"XX"
&self.country
let kind = if self.kind.is_empty() { "" } else { &self.kind };
format!("patent::{}::{}{}", country, num, kind)
fn label(&self) -> String {
if self.title.is_empty() {
self.external_id()
format!(
"{}{}{} — {}",
self.country, self.doc_number, self.kind, self.title
)
fn state(&self) -> &'static str {
kind_to_state(&self.kind)
fn excerpt(&self) -> Option<String> {
if self.abstract_text.is_empty() {
None
Some(self.abstract_text.chars().take(220).collect())
pub struct PatentIngestAdapter {
namespace: String,
impl PatentIngestAdapter {
pub fn new(namespace: Option<String>) -> Self {
let namespace = namespace
.unwrap_or_else(|| "patent".to_string())
.trim()
.to_lowercase();
let namespace = if namespace.is_empty() {
"patent".to_string()
namespace
Self { namespace }
fn accepted_extension(path: &Path) -> bool {
matches!(
path.extension()
.and_then(|ext| ext.to_str())
.map(|ext| ext.to_ascii_lowercase()),
Some(ext) if matches!(ext.as_str(), "xml")
fn collect_files(&self, root: &Path) -> Vec<PathBuf> {
if root.is_file() {
return if Self::accepted_extension(root) {
vec![root.to_path_buf()]
vec![]
WalkDir::new(root)
.into_iter()
.filter_map(Result::ok)
.filter(|entry| entry.file_type().is_file() && Self::accepted_extension(entry.path()))
.map(|entry| entry.into_path())
.collect()
fn file_timestamp(path: &Path) -> f64 {
std::fs::metadata(path)
.ok()
.and_then(|meta| meta.modified().ok())
.and_then(|time| time.duration_since(UNIX_EPOCH).ok())
.map(|d| d.as_secs_f64())
.unwrap_or_else(|| {
SystemTime::now()
.duration_since(UNIX_EPOCH)
.unwrap_or(0.0)
})
/// Split concatenated XML documents (USPTO bulk files).
/// USPTO ships files with multiple `<?xml` declarations concatenated.
fn split_concatenated_xml(content: &str) -> Vec<&str> {
let mut docs = Vec::new();
let mut start = 0;
for (i, _) in content.match_indices("<?xml") {
if i > start && i > 0 {
let chunk = content[start..i].trim();
if !chunk.is_empty() {
docs.push(chunk);
start = i;
// Last document
if start < content.len() {
let chunk = content[start..].trim();
// If no <?xml found, treat whole content as one doc
if docs.is_empty() && !content.trim().is_empty() {
docs.push(content);
docs
/// Parse a single patent XML document into a PatentRecord.
fn parse_patent_xml(xml: &str) -> Option<PatentRecord> {
let mut reader = Reader::from_str(xml);
let mut record = PatentRecord::default();
let mut path: Vec<String> = Vec::new();
let mut buf = Vec::new();
let mut text_buf = String::new();
let mut in_abstract = false;
let mut in_title = false;
let mut in_citation = false;
let mut current_citation_doc = String::new();
let mut in_classification = false;
let mut in_orgname = false;
let mut in_inventor_name = false;
let mut inventor_parts: Vec<String> = Vec::new();
// EPO B-series SDOBI flags
let mut in_b541 = false; // EPO title
let mut in_b721 = false; // EPO inventor block
let mut in_b731 = false; // EPO assignee block
let mut in_b561 = false; // EPO citation block
let mut in_pdat = false; // EPO inline data
let mut in_snm = false; // EPO surname
let mut in_fnm = false; // EPO first name
loop {
match reader.read_event_into(&mut buf) {
Ok(Event::Start(e)) => {
let name = String::from_utf8_lossy(e.name().as_ref()).to_string();
// Detect format from root element
if path.is_empty() {
match name.as_str() {
"us-patent-grant" => record.format = PatentFormat::UsRedBook,
"us-patent-application" => {
record.format = PatentFormat::UsYellowBook;
"ep-patent-document" => {
record.format = PatentFormat::EpoDocDb;
// EPO stores country/doc-number/kind as attributes
for attr in e.attributes().filter_map(|a| a.ok()) {
let key = String::from_utf8_lossy(attr.key.as_ref());
let val = String::from_utf8_lossy(&attr.value);
match key.as_ref() {
"country" if record.country.is_empty() => {
record.country = val.to_string();
"doc-number" if record.doc_number.is_empty() => {
record.doc_number = val.to_string();
"kind" if record.kind.is_empty() => {
record.kind = val.to_string();
_ => {}
path.push(name.clone());
"abstract" => in_abstract = true,
"invention-title" => in_title = true,
"orgname" => in_orgname = true,
"patcit" | "us-citation" => in_citation = true,
"classification-ipcr" | "classification-cpc-text" => {
in_classification = true;
"given-name" | "family-name" | "last-name" | "first-name"
if path.iter().any(|p| {
p == "inventors" || p == "inventor" || p == "applicants"
}) =>
{
in_inventor_name = true;
// EPO B-series SDOBI tags
"B541" => in_b541 = true,
"B721" => in_b721 = true,
"B731" => in_b731 = true,
"B561" => in_b561 = true,
"pdat" => in_pdat = true,
"snm" => in_snm = true,
"fnm" => in_fnm = true,
"pcit" if in_b561 => {
in_citation = true;
Ok(Event::End(e)) => {
"abstract" => {
in_abstract = false;
if !text_buf.is_empty() {
record.abstract_text = text_buf.trim().to_string();
text_buf.clear();
"invention-title" => {
in_title = false;
record.title = text_buf.trim().to_string();
"orgname" => {
in_orgname = false;
let parent_is_assignee =
path.iter().any(|p| p == "assignee" || p == "assignees");
if parent_is_assignee {
record.assignees.push(text_buf.trim().to_string());
"given-name" | "family-name" | "last-name" | "first-name" => {
if in_inventor_name && !text_buf.is_empty() {
inventor_parts.push(text_buf.trim().to_string());
in_inventor_name = false;
"inventor" if !inventor_parts.is_empty() => {
record.inventors.push(inventor_parts.join(" "));
inventor_parts.clear();
// EPO B-series end tags
"B541" => {
in_b541 = false;
if !text_buf.is_empty() && record.title.is_empty() {
"B721" => {
in_b721 = false;
if !inventor_parts.is_empty() {
"B731" => {
in_b731 = false;
"B561" => {
in_b561 = false;
"pdat" => {
in_pdat = false;
"snm" => {
if in_snm && !text_buf.is_empty() && in_b721 {
// For B731 (assignee), don't clear — let B731 close handle it
in_snm = false;
"fnm" => {
if in_fnm && !text_buf.is_empty() {
if in_b721 {
in_fnm = false;
"pcit" if in_citation => {
if !current_citation_doc.is_empty() {
record.citations.push(current_citation_doc.clone());
current_citation_doc.clear();
in_citation = false;
"patcit" | "us-citation" => {
in_classification = false;
record.classifications.push(text_buf.trim().to_string());
"country" if !text_buf.is_empty() => {
// Country in publication-reference context
if path
.iter()
.any(|p| p == "publication-reference" || p == "document-id")
if record.country.is_empty() {
record.country = text_buf.trim().to_string();
if in_citation {
current_citation_doc.push_str(text_buf.trim());
"doc-number" if !text_buf.is_empty() => {
} else if record.doc_number.is_empty() {
record.doc_number = text_buf.trim().to_string();
"kind" if !text_buf.is_empty() => {
} else if record.kind.is_empty() {
record.kind = text_buf.trim().to_string();
"date" if !text_buf.is_empty() => {
if path.iter().any(|p| p == "publication-reference")
&& record.pub_date.is_empty()
record.pub_date = text_buf.trim().to_string();
} else if path.iter().any(|p| p == "application-reference")
&& record.app_date.is_empty()
record.app_date = text_buf.trim().to_string();
path.pop();
Ok(Event::Text(e)) => {
if in_abstract
|| in_title
|| in_orgname
|| in_inventor_name
|| in_classification
|| in_citation
|| in_pdat
|| in_snm
|| in_fnm
if let Ok(t) = e.decode() {
text_buf.push_str(&t);
// Capture text for country/doc-number/kind/date
let current = path.last().map(|s| s.as_str()).unwrap_or("");
if matches!(current, "country" | "doc-number" | "kind" | "date") {
Ok(Event::GeneralRef(e)) => {
append_general_ref(&mut text_buf, &e);
Ok(Event::Eof) => break,
Err(_) => break,
buf.clear();
if record.doc_number.is_empty() {
return None;
Some(record)
impl IngestAdapter for PatentIngestAdapter {
fn domain(&self) -> &str {
"patent"
fn ingest(&self, root: &Path) -> M1ndResult<(Graph, IngestStats)> {
let start = Instant::now();
let files = self.collect_files(root);
let mut stats = IngestStats {
files_scanned: files.len() as u64,
..Default::default()
let mut node_ids: HashSet<String> = HashSet::new();
let mut edge_keys: HashSet<(String, String, String)> = HashSet::new();
struct NodeRecord {
id: String,
label: String,
node_type: NodeType,
tags: Vec<String>,
timestamp: f64,
source_path: String,
excerpt: Option<String>,
struct EdgeRecord {
source: String,
target: String,
relation: String,
weight: f32,
let mut nodes: Vec<NodeRecord> = Vec::new();
let mut edges: Vec<EdgeRecord> = Vec::new();
for path in &files {
let content = match std::fs::read_to_string(path) {
Ok(c) => c,
Err(_) => continue,
let rel_path = path
.strip_prefix(root)
.unwrap_or(path)
.to_string_lossy()
.replace('\\', "/");
let timestamp = Self::file_timestamp(path);
let xml_docs = Self::split_concatenated_xml(&content);
for xml_doc in xml_docs {
let record = match Self::parse_patent_xml(xml_doc) {
Some(r) => r,
None => continue,
let ext_id = record.external_id();
if !node_ids.insert(ext_id.clone()) {
continue; // duplicate
let state = record.state();
let mut tags = vec![
"patent".to_string(),
format!("patent:country:{}", record.country),
format!("patent:state:{}", state),
format!("namespace:{}", self.namespace),
];
if !record.kind.is_empty() {
tags.push(format!("patent:kind:{}", record.kind));
for cls in &record.classifications {
tags.push(format!("patent:class:{}", cls));
// Patent node
nodes.push(NodeRecord {
id: ext_id.clone(),
label: record.label(),
node_type: NodeType::File,
tags: tags.clone(),
timestamp,
source_path: rel_path.clone(),
excerpt: record.excerpt(),
namespace: self.namespace.clone(),
});
// Citation edges (depends_on)
for citation in &record.citations {
let target_id = format!("patent::{}", citation.replace(' ', ""));
let key = (ext_id.clone(), target_id.clone(), "cites".to_string());
if edge_keys.insert(key) {
// Create a reference node for the cited patent
// (may be resolved later if the cited patent is also ingested)
if node_ids.insert(target_id.clone()) {
id: target_id.clone(),
label: citation.clone(),
node_type: NodeType::Reference,
tags: vec!["patent".to_string(), "patent:cited".to_string()],
excerpt: None,
edges.push(EdgeRecord {
source: ext_id.clone(),
target: target_id,
relation: "cites".to_string(),
weight: 0.8,
// Assignee nodes
for assignee in &record.assignees {
let assignee_id = format!(
"patent::assignee::{}",
assignee.to_lowercase().replace(' ', "_")
);
if node_ids.insert(assignee_id.clone()) {
id: assignee_id.clone(),
label: assignee.clone(),
node_type: NodeType::Concept,
tags: vec!["patent".to_string(), "patent:assignee".to_string()],
let key = (
ext_id.clone(),
assignee_id.clone(),
"assigned_to".to_string(),
target: assignee_id,
relation: "assigned_to".to_string(),
weight: 1.0,
// Classification nodes (IPC/CPC)
let cls_id = format!(
"patent::class::{}",
cls.to_lowercase().replace(' ', "").replace('/', "_")
if node_ids.insert(cls_id.clone()) {
id: cls_id.clone(),
label: cls.clone(),
tags: vec!["patent".to_string(), "patent:classification".to_string()],
let key = (ext_id.clone(), cls_id.clone(), "classified_as".to_string());
target: cls_id,
relation: "classified_as".to_string(),
weight: 0.9,
stats.files_parsed += 1;
// Build graph
let mut graph = Graph::with_capacity(nodes.len(), edges.len());
for node in &nodes {
let tags: Vec<&str> = node.tags.iter().map(String::as_str).collect();
if let Ok(node_id) = graph.add_node(
&node.id,
&node.label,
node.node_type,
&tags,
node.timestamp,
0.5, // change_frequency
) {
graph.set_node_provenance(
node_id,
NodeProvenanceInput {
source_path: Some(&node.source_path),
line_start: None,
line_end: None,
excerpt: node.excerpt.as_deref(),
namespace: Some(&node.namespace),
canonical: true,
},
stats.nodes_created += 1;
for edge in &edges {
if let (Some(source), Some(target)) = (
graph.resolve_id(&edge.source),
graph.resolve_id(&edge.target),
if graph
.add_edge(
source,
target,
&edge.relation,
FiniteF32::new(edge.weight),
EdgeDirection::Forward,
false,
FiniteF32::new(0.7),
.is_ok()
stats.edges_created += 1;
if graph.num_nodes() > 0 {
graph.finalize()?;
stats.elapsed_ms = start.elapsed().as_secs_f64() * 1000.0;
Ok((graph, stats))
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn resolves_general_entity_refs_in_captured_text() {
let xml = r#"<?xml version="1.0" encoding="UTF-8"?>
<us-patent-grant>
<us-bibliographic-data-grant>
<publication-reference>
<document-id>
<country>US</country>
<doc-number>1</doc-number>
<kind>B2</kind>
<date>20230101</date>
</document-id>
</publication-reference>
<invention-title>AT&T <fiber> ≤ loss</invention-title>
</us-bibliographic-data-grant>
</us-patent-grant>"#;
let record = PatentIngestAdapter::parse_patent_xml(xml).unwrap();
assert_eq!(record.title, "AT&T <fiber> \u{2264} loss");
const SAMPLE_USPTO_XML: &str = r#"<?xml version="1.0" encoding="UTF-8"?>
<doc-number>11636241</doc-number>
<date>20230425</date>
<application-reference>
<doc-number>17387082</doc-number>
<date>20210728</date>
</application-reference>
<invention-title>Physical device optimization with reduced memory footprint</invention-title>
<assignees>
<assignee>
<orgname>Luminous Computing Inc</orgname>
</assignee>
</assignees>
<inventors>
<inventor>
<given-name>John</given-name>
<family-name>Doe</family-name>
</inventor>
</inventors>
<us-references-cited>
<us-citation>
<patcit>
<doc-number>9977644</doc-number>
</patcit>
</us-citation>
<doc-number>5774693</doc-number>
<kind>A</kind>
</us-references-cited>
<classification-ipcr>G06F 30/23</classification-ipcr>
<abstract>
<p>A method for physical device optimization using time reversal at absorbing boundaries to reduce memory usage during adjoint simulations.</p>
</abstract>
fn parses_single_patent() {
let record = PatentIngestAdapter::parse_patent_xml(SAMPLE_USPTO_XML).unwrap();
assert_eq!(record.doc_number, "11636241");
assert_eq!(record.kind, "B2");
assert_eq!(record.country, "US");
assert_eq!(record.state(), "active");
assert_eq!(
record.title,
"Physical device optimization with reduced memory footprint"
assert_eq!(record.assignees, vec!["Luminous Computing Inc"]);
assert_eq!(record.inventors, vec!["John Doe"]);
assert_eq!(record.citations.len(), 2);
assert!(!record.abstract_text.is_empty());
fn splits_concatenated_xml() {
let bulk = format!(
"{}\n{}\n{}",
SAMPLE_USPTO_XML,
SAMPLE_USPTO_XML.replace("11636241", "99999999"),
SAMPLE_USPTO_XML.replace("11636241", "88888888"),
let docs = PatentIngestAdapter::split_concatenated_xml(&bulk);
assert_eq!(docs.len(), 3);
fn kind_codes_map_correctly() {
assert_eq!(kind_to_state("A1"), "draft");
assert_eq!(kind_to_state("B2"), "active");
assert_eq!(kind_to_state("H1"), "deprecated");
fn ingest_sample_creates_graph() {
let dir = std::env::temp_dir().join(format!(
"m1nd-patent-test-{}",
.unwrap()
.as_nanos()
));
std::fs::create_dir_all(&dir).unwrap();
std::fs::write(dir.join("sample.xml"), SAMPLE_USPTO_XML).unwrap();
let adapter = PatentIngestAdapter::new(None);
let (graph, stats) = adapter.ingest(&dir).unwrap();
// 1 patent + 2 citations + 1 assignee + 1 classification = 5 nodes
assert!(stats.nodes_created >= 5);
// cites(2) + assigned_to(1) + classified_as(1) = 4 edges
assert!(stats.edges_created >= 4);
assert!(graph.resolve_id("patent::US::11636241B2").is_some());
let _ = std::fs::remove_dir_all(dir);