Educational only; not legal advice. SPP explains diligence issue-spotting, evidence collection, risk triage, and the accountant and certified-fraud-examiner workflow. It does not give filing advice, sanctions opinions, export classifications, CFIUS legal opinions, privacy opinions, forfeiture-defense advice, whistleblower advice, or voluntary self-disclosure advice. Regulatory and source status is current as of drafting (2026-06-16); see the status note at the end.
The first mistake in public-data diligence is treating a list hit as an answer. The second mistake is treating a no-hit as comfort.
Both mistakes are common because list screening looks deceptively simple. Put a company name into a search box. Get a possible match. Put another name into the box. Get nothing. The software interface makes the result feel binary. It is not. A sanctions list, export screening list, exclusion list, procurement database, beneficial-ownership chart, or public case timeline is a source of leads. It is not a legal conclusion, a sanctions opinion, an export classification, a beneficial-ownership determination, or a clearance letter.
That is why D2 exists. The earlier articles teach the regimes. D1 teaches the stage-gated workflow. This article teaches the public-data layer inside that workflow: how to use free and authoritative sources, how to build a small reproducible screen, how to preserve the access date and source path, how to write the output so it does not overclaim, and how to know when the result belongs in counsel’s queue.
D2 is the Applied DD Lab capstone for the series. It is not a pure coding article. The code is here because a practitioner learns the method faster by running it. The point is not to replace a sanctions-screening vendor, export-control counsel, a CFIUS filing analysis, a bank’s anti-money-laundering program, or a lawyer’s ownership memo. The point is to build the reader’s evidence discipline. The reader should walk away knowing how to ask better questions of a target, counsel, and the buyer’s own deal team.
The companion repository lives in the series folder as lab/national-security-diligence-lab/. It uses only the Python standard library. It ships synthetic inputs, teaching fixtures, redacted outputs, unit tests, optional live-source smoke tests, and source documentation. It does not use client data, target names, private records, paywalled data, or FinCEN beneficial ownership information.
The output posture is deliberate:
| Output phrase | Meaning | What it does not mean |
|---|---|---|
lead_only |
The supplied name looked similar enough to a supplied list entry to require review. | It does not prove a true sanctions match, export restriction, ownership conclusion, or violation. |
no_current_signal_from_supplied_list |
The supplied list snapshot did not produce a match under the configured method. | It does not clear the party, owner, transaction, country, product, or deal. |
synthetic_lead_only |
The output came from invented teaching data. | It cannot be cited as evidence about a real person or company. |
This vocabulary sounds cautious because it has to. Public-source diligence is strongest when it is modest. It should say exactly what the source shows, exactly what was checked, exactly when it was checked, exactly what remains unresolved, and exactly who must decide the legal consequence.
What problem the toolkit was built to solve
The practical problem is repeatability. A buyer can hire counsel to answer a legal question, but the diligence team still needs a repeatable way to collect the names, pull the public lists, preserve the source date, write the output, and route the results. If that process lives only in screenshots and ad hoc browser searches, the diligence file is weak.
A weak file usually has the same defects. It does not say which list was used. It does not record the access date. It does not preserve the exact spelling searched. It does not distinguish an exact match from a fuzzy match. It does not capture the source information URL. It does not explain whether aliases, addresses, vessel identifiers, tax IDs, or registration numbers were checked. It does not separate public records from seller assertions. It does not say whether a no-hit came from a complete official list, an aggregator, a stale export, or a search-engine result. It does not identify the counsel owner for a true match.
That is a problem for sanctions diligence. It is also a problem for export controls, anti-money-laundering evidence, data-security diligence, forfeiture-risk tracing, and whistleblower triage. A buyer needs a workpaper that shows the method, not just the answer.
The D2 toolkit solves a narrow version of that problem:
- It uses public or synthetic data only.
- It fetches or parses official public list data from sources the reader can inspect.
- It screens synthetic counterparties against a teaching fixture or downloaded list.
- It marks possible matches as leads.
- It generates publishable redacted outputs.
- It includes tests so the reader can reproduce the method.
- It documents source URLs, access dates, limitations, and update method.
The toolkit does not solve the larger legal problem. It does not decide whether a person is blocked. It does not apply every OFAC program rule. It does not aggregate indirect ownership through every legal-entity chain. It does not classify an item under an Export Control Classification Number, known as an ECCN. It does not decide whether a license is required. It does not access beneficial ownership information, known as BOI, from FinCEN. It does not determine whether a transaction triggers the Committee on Foreign Investment in the United States, known as CFIUS. It does not decide whether a voluntary self-disclosure should be made.
The distinction matters because a data exercise can create false confidence. A spreadsheet cell saying “no hit” can travel through a deal room like a clean bill of health. That is not what the cell means. It means only that the supplied list snapshot, supplied names, and supplied matching method did not surface a current signal. If the input name is wrong, the list is stale, the alias is missing, the entity is owned by a blocked person, the relevant restriction is not a name list, or the legal issue is product classification rather than party screening, the no-hit tells the buyer very little.
The proper goal is therefore not “automate national-security diligence.” The proper goal is “make the public-data portion disciplined enough to support a risk memo.”
Who owns the sources, and why that matters
The toolkit pulls from public sources, but the sources come from different institutions and have different legal meanings.
Trade.gov, through the International Trade Administration, publishes the Consolidated Screening List, usually abbreviated CSL. The CSL is useful because it consolidates multiple export screening lists from the Departments of Commerce, State, and Treasury into a downloadable and API-accessible source. Trade.gov also tells users how to treat it. The CSL is an aid for electronic screening. If a party appears to match, additional due diligence should be conducted before proceeding. Trade.gov also instructs users to check official publications and official lists maintained by the source agencies to confirm restrictions. That language is the operating rule for this article: a CSL hit is a lead.
The Office of Foreign Assets Control, known as OFAC, publishes the Specially Designated Nationals and Blocked Persons List, usually called the SDN List, and other sanctions lists. OFAC provides machine-readable formats, including comma-separated-value files. OFAC also publishes technical guidance explaining that a single SDN flat file can miss related alias, address, and comments data if the user does not download the full file series. That matters for D2 because the teaching code uses a simple CSV parser. It is good enough to teach source handling. It is not a complete sanctions-screening system.
The Bureau of Industry and Security, known as BIS, administers the Export Administration Regulations, known as the EAR. The Entity List is codified in Supplement No. 4 to Part 744 of Title 15 of the Code of Federal Regulations. Entity List entries can create license requirements and other restrictions for exports, reexports, and transfers in-country. But a list hit still is not an ECCN. It does not tell the buyer what the item is. It does not determine whether the item is subject to the EAR. It does not decide whether a foreign direct product rule applies. It does not decide whether a license exception is available. It is one party-screening fact inside a broader export-control analysis.
FinCEN owns a different kind of source problem. BOI is a real federal system, but it is confidential and access-limited. The March 2025 interim final rule narrowed the reporting-company definition and exempted domestic reporting companies. Whatever lawful diligence use may exist in a specific transaction, BOI is not a public bulk dataset and does not belong in this automated screen. That exclusion is not a weakness. It is source discipline.
CFIUS public actions, Treasury annual reports, USAspending, SAM.gov, court dockets, Federal Register notices, and agency enforcement releases are also useful public sources. They are not all implemented in the current D2 code sample. They remain part of the larger Applied DD Lab roadmap and the case-data matter. The current capstone focuses on public list screening and synthetic ownership because those are the safest skills to teach reproducibly without leaking client data or creating a misleading pseudo-clearance tool.
The source-owner map is the first practitioner lesson:
| Source | Owner | What it can surface | What it cannot prove |
|---|---|---|---|
| Trade.gov CSL | International Trade Administration, aggregating Commerce, State, and Treasury list sources | Possible restricted-party leads across several public screening lists | Final legal restriction, product classification, or transaction clearance |
| OFAC SDN CSV | OFAC, Treasury | Names on the SDN list in a machine-readable flat file | Complete sanctions analysis, aliases and identifiers if related files are omitted, 50 Percent Rule conclusion |
| eCFR Entity List | BIS / Federal Register / eCFR | Legal source for Entity List entries and restrictions | ECCN, license exception, end-use analysis, deemed-export analysis |
| FinCEN BOI page | FinCEN, Treasury | Current public status of BOI reporting and access limits | Public bulk ownership verification |
| Synthetic ownership graph | SPP lab teaching data | How aggregated flagged ownership can cross a teaching threshold | Any real blocked-property conclusion |
The buyer’s risk memo should preserve that map. It should not say “screened against government databases” as if all databases were the same. It should say which source, which date, which field, which limitation, and which counsel owner.
What changed from 2024 to 2026
The need for a public-data lab became stronger because the diligence surface expanded faster than ordinary deal files did.
First, sanctions and export controls moved deeper into corporate enforcement. DOJ’s national-security posture, OFAC enforcement expectations, BIS export-control enforcement, and corporate voluntary-self-disclosure policy all pushed sanctions and export issues into the same practical universe as anti-bribery and anti-money-laundering diligence. A buyer that acquires a target with unresolved sanctions or export history can inherit remediation, disclosure, and successor-liability problems.
Second, the outbound investment program turned investor diligence into a regulatory fact pattern. A fund or corporate investor now has to ask whether capital is moving into covered technologies and covered foreign persons. That question does not begin with a filing form. It begins with names, ownership, technology descriptions, countries, and documentary support.
Third, the DOJ Data Security Program made data access a national-security diligence item. The buyer has to know who can access what data, where, under what contract, and at what volume. That is not a list-screening question, but it uses the same discipline: source the field, preserve the count, mark the gap, escalate the legal conclusion.
Fourth, FinCEN’s rules showed why status dashboards matter. The Residential Real Estate rule is vacated and on appeal. The Investment Adviser AML rule is delayed to 2028-01-01. BOI reporting was narrowed, and BOI access remains limited. Stale compliance assumptions can turn into wrong public guidance. D2’s answer is to place source date and source status inside the workpaper.
Fifth, whistleblower and bounty programs made internal information more valuable. A screen hit, ownership gap, source-of-funds question, or export-control issue may interact with internal reporting, voluntary self-disclosure, and award eligibility. The D2 code does not decide any of that. It does, however, create a cleaner evidence trail for the lawyers who must.
The 2024 to 2026 story, then, is not that every buyer needs to become a software engineer. It is that every serious diligence practice needs reproducible evidence handling. The practitioner should be able to show, months later, what public data was checked, when it was checked, what the output said, what it did not say, and what was escalated.
What triggers use of the toolkit
Use the D2 screen when the deal file has names that need public-list triage. Those names can be legal entities, owners, officers, directors, customers, suppliers, vendors, distributors, resellers, agents, lenders, banks, brokers, vessels, aircraft owners, data processors, offshore support providers, or portfolio companies.
The trigger is not suspicion. The trigger is the existence of a party list that belongs in the diligence file. Even a low-risk deal should have a controlled method for recording no-current-signal results, because the method matters if a later question arises. A higher-risk deal needs the method even more because the screen may route a possible match to sanctions counsel, export-control counsel, AML counsel, CFIUS counsel, privacy counsel, or deal counsel.
Use the D2 screen especially when one of these facts appears:
- foreign ownership, foreign control, or unusual information rights;
- customers, suppliers, distributors, or banks in higher-risk jurisdictions;
- products, software, technology, source code, research, or services with export-control sensitivity;
- data vendors, offshore support, managed-service providers, or access paths in countries of concern;
- unexplained source-of-funds, complex ownership, nominee structures, or politically exposed capital;
- seller disclosures that mention sanctions, export controls, AML, subpoenas, government inquiries, denied-party screens, voluntary disclosures, internal reports, or blocked property;
- a prior diligence team provided only screenshots without source dates or source files.
Do not use the screen as a substitute for source documents. A name screen cannot tell you who owns a company unless the ownership data is supplied and verified. It cannot tell you whether a product is controlled unless the technical facts and classification support are supplied and reviewed. It cannot tell you whether a country-of-concern data path exists unless the system access map is supplied. It cannot tell you whether a whistleblower program applies unless the information, source, timing, and program rules are reviewed.
The toolkit is useful because it sits in the middle of the process. It comes after intake has produced names and before the risk memo tries to draw conclusions.
What the screen can do
The screen can standardize six practical tasks.
First, it can record the exact input names. That sounds simple, but legal names, trade names, abbreviations, translated names, former names, and aliases often differ. A disciplined screen preserves the name that was supplied and the source of that name. If the target later says the name was wrong, the file can show where it came from.
Second, it can normalize list rows. Public list files arrive with fields the analyst does not control. The CSL has a source field, a name field, a type field, a programs field, an address field, and a source_information_url field. OFAC’s SDN CSV uses its own flat-file structure. D2 normalizes enough fields to teach the method and preserve source visibility.
Third, it can compare names using a conservative score. The D2 code uses standard-library normalization and SequenceMatcher. Exact matches score high. Near matches can score high enough to require review. Bad matches should not disappear without leaving a row. The output should show both the query name and the candidate name.
Fourth, it can mark posture. A lead is not a finding. A no-current-signal result is not clearance. A synthetic output is not evidence. The posture field is a control. It keeps the screen from being misused downstream.
Fifth, it can generate a reproducible CSV. A diligence memo should not depend on a screenshot. The workpaper should have an input file, an output file, a command, a source date, and a limitation note.
Sixth, it can support an evidence gap log. If the screen produces a possible match, the next step is not panic. The next step is identifiers, aliases, addresses, ownership, source documents, and counsel escalation. If the screen produces no current signal but the target’s ownership data is missing, the gap remains.
The code is intentionally simple. That is a feature for teaching. It lets the reader see the method without hiding it inside a commercial black box.
What the screen cannot do
The screen cannot make a sanctions finding. OFAC screening requires program-specific legal analysis, identifiers, aliases, addresses, ownership aggregation, property-interest analysis, licensing questions, blocked-property handling, and counsel review. The D2 example uses a teaching fixture and a simple SDN CSV parser. OFAC’s own documentation warns that related flat files can contain important alias, address, and comments data. A complete sanctions-screening process needs a fuller data model.
The screen cannot automate the OFAC 50 Percent Rule. The B1 article explains the rule. D2’s ownership graph shows the arithmetic shape on synthetic rows: flagged owner percentages can aggregate above 50 percent. That demonstration is useful because it teaches why direct named-list screening is not enough. It is also limited because real ownership tracing must evaluate indirect ownership, aggregation among blocked persons, legal entities, trusts, side agreements, control rights, and source documents.
The screen cannot classify exports. An Entity List or Denied Persons List hit may be a major issue, but export-control diligence also asks what the item is, whether it is subject to the EAR, what its ECCN is, where it is going, who will use it, whether a license is required, whether a license exception is available, whether the foreign direct product rule applies, and whether a deemed export exists. D2 flags party-list issues. It does not classify products.
The screen cannot access BOI. FinCEN BOI is confidential and access-limited. It is also currently narrowed in reporting scope after the March 2025 interim final rule. D2 does not scrape, bulk-download, infer, or simulate real BOI. When the article uses synthetic ownership records, those records are invented teaching data.
The screen cannot decide CFIUS. A CFIUS question depends on transaction structure, foreign-person status, control, covered investment rights, TID U.S. business status, critical technologies, critical infrastructure, sensitive personal data, real estate, foreign-government ownership, and counsel analysis. A public-list screen may identify a party fact relevant to the CFIUS memo. It does not answer the CFIUS question.
The screen cannot make a buyer’s risk memo by itself. It produces a workpaper input. The memo must still distinguish allegation from finding, source from assertion, status from stale commentary, lead from legal conclusion, and unresolved gap from verified fact.
Those limits should be printed into the workflow because they are part of the professional standard. A practitioner who writes down the limits is less likely to overstate the result.
The three-surface rule
D2 uses a three-surface rule because the series has three different jobs.
The first surface is the public article. The article teaches the concept, shows safe output, links to authoritative sources, and explains the diligence procedure. It is written for a professional reader who needs to understand the method and the boundaries. The public article should not contain live-party accusations, client names, target names, private records, or screenshots that would be misunderstood as findings.
The second surface is the companion GitHub lab. The lab contains reproducible code, synthetic inputs, teaching fixtures, redacted outputs, tests, and source documentation. It is where the reader learns the method by running a screen. The lab should remain clean enough that a reader can clone it, inspect it, run it, and understand every field without needing access to a private matter file. That is why D2 uses synthetic counterparties and teaching fixtures for article outputs even though the code can parse official public endpoints.
The third surface is the case-data matter. That is where actual public case materials belong when the series wants to study a real enforcement matter, docket, public release, forfeiture complaint, consent order, settlement, divestiture timeline, or agency report. A case-data matter can be public-source and non-client, but it is still a separate evidence workspace because it carries allegation-versus-finding risk. It needs source URLs, docket status, release dates, amounts, parties, procedural posture, and update notes. The public article may summarize the lessons after review, but the raw case-data work should not be mixed into the synthetic lab in a way that makes the lab look like a list of targets.
This separation keeps the series credible. The article teaches. The lab lets the reader replicate. The case-data matter preserves real-world evidence. If those surfaces are mixed, the work becomes weaker. A public lab with real company names can look like SPP is accusing parties. A public article with raw code output can look like a legal finding. A case-data workspace without allegation posture can turn a complaint into a conclusion. The three-surface rule prevents those errors.
For D2, the rule means:
| Surface | What it contains | What it excludes |
|---|---|---|
| Public article | Explanation, tables, commands, synthetic output, source links, limitations | Client names, target names, raw live-list matches, private records |
| GitHub lab | Code, tests, synthetic data, teaching fixtures, source docs, redacted outputs | BOI, client files, private matter data, legal conclusions |
| Case-data matter | Curated public enforcement and docket evidence with allegation posture | Synthetic teaching rows, unsourced claims, stale status assertions |
The distinction is not just a publishing preference. It is a diligence skill. A practitioner should know when a fact belongs in the memo, when it belongs in the code repo, and when it belongs in a case file. The same discipline applies in real buy-side work. A buyer should not paste private target data into a public tool. It should not circulate raw unverified list hits as findings. It should not let a public complaint become a final fact. It should keep the surfaces separate.
Data quality controls before any screen
The best screen is useless if the input is bad. Before a practitioner runs D2-style screening on a real diligence file, the input names need quality controls.
Start with provenance. Every name should have a source. “Customer list from seller data room, file name, upload date” is useful. “Copied from website” is weaker. “Management said” is a source, but it is an assertion, not a document. If the source is an assertion, say so.
Then normalize roles. The screen should not mix owners, customers, suppliers, officers, banks, vessels, and vendors without a role field. A possible match on a minor customer has a different deal consequence from a possible match on a majority owner, payment bank, or core supplier. The same name can require different escalation depending on role.
Then preserve legal names and aliases separately. Do not overwrite the seller’s supplied name with the analyst’s corrected guess. Keep the original query name, any cleaned name, and any alias fields. If the target later says the analyst searched the wrong name, the workpaper should show both the source input and the reason for any normalization.
Then collect identifiers. Legal names are not enough. Registration numbers, addresses, countries, tax IDs where appropriate, vessel identifiers, aircraft tail numbers, and bank identifiers can separate false positives from true matches. A fuzzy match without identifiers is a lead with weak resolution power.
Then date the list. A list screen has a time dimension. The output should say whether the list was pulled today, last week, or from an old spreadsheet. Sanctions and restricted-party lists can change quickly. A stale no-hit is especially dangerous because it looks clean while silently resting on old data.
Then record coverage. The practitioner should know whether the screen covered only direct names, aliases, ownership, addresses, vessels, banks, products, or counterparties. If the screen covered only direct names, write that. If it did not check aliases, write that. If it did not check ownership, write that. Limits are not embarrassing. Hidden limits are.
A practical intake table looks like this:
| Field | Why it matters |
|---|---|
name |
The query value used for screening. |
role |
Owner, officer, customer, supplier, vendor, bank, agent, or other deal role. |
source_document |
Where the name came from. |
source_date |
Date of the data-room file, seller response, contract, or public source. |
country |
Screening context and possible sanctions, export, or data relevance. |
identifier |
Registration number, address, tax ID, or other disambiguator where lawfully available. |
notes |
Known alias, unresolved spelling, seller caveat, or reason for escalation. |
D2’s synthetic input is intentionally simpler than a real deal input. A real file should be richer. The simple sample teaches the mechanics; the richer file protects the deal.
Repository structure
The companion repo is intentionally small:
national-security-diligence-lab/
README.md
LICENSE
requirements.txt
pyproject.toml
ns_screen.py
src/ns_diligence/
fetch_csl.py
fetch_ofac.py
screen_names.py
export_list_screen.py
ownership_graph.py
outbound_triage.py
data_threshold_checker.py
timeline_builder.py
award_matrix.py
risk_workflow.py
data/sample/
data/synthetic/
data/redacted_outputs/
tests/
docs/
data_sources.md
limitations.md
update_log.md
The D2 capstone modules are:
| File | Job | Data posture |
|---|---|---|
fetch_csl.py |
Pull and normalize Trade.gov CSL CSV rows | Live public endpoint, optional |
fetch_ofac.py |
Pull and normalize OFAC SDN CSV rows | Live public endpoint, optional |
screen_names.py |
Compare input names against supplied list rows | Works with fixture or downloaded list |
export_list_screen.py |
Filter BIS-related CSL rows and screen query names | Public CSL source labels |
ownership_graph.py |
Aggregate synthetic flagged-owner percentages | Synthetic teaching data only |
ns_screen.py |
Wrapper for the D2 name-screen artifact | Synthetic or authorized public input |
tests/test_live_sources.py |
Optional endpoint smoke tests | Skipped unless NS_DILIGENCE_LIVE=1 |
The repo does not need external packages. That is important. A lightweight standard-library tool is easier for a reader to audit, easier to run in a locked-down environment, and easier to explain in an article. If later versions add graph, data, or visualization libraries, those dependencies should go through the same open-source and non-PRC review that governs the rest of the lab.
The source register
Every dataset used by the lab belongs in docs/data_sources.md. That file is not window dressing. It is the workpaper discipline.
For each real source, the register should identify:
- the source name;
- the official source URL;
- the access date;
- the terms or license note;
- the update method;
- the fields used;
- the lab use;
- the no-hit interpretation.
D2 records the following public sources as of 2026-06-16:
| Dataset or page | Source URL | D2 use |
|---|---|---|
| Trade.gov CSL page | https://www.trade.gov/consolidated-screening-list |
Source authority and limitation language |
| Trade.gov CSL CSV | https://data.trade.gov/downloadable_consolidated_screening_list/v1/consolidated.csv |
Optional public list data for live smoke tests and normalized rows |
| OFAC SDN CSV | https://www.treasury.gov/ofac/downloads/sdn.csv |
Optional public list data for live smoke tests and normalized rows |
| OFAC FAQ 80 | https://ofac.treasury.gov/faqs/80 |
Authority that OFAC publishes SDN CSV data |
| OFAC flat-file tutorial | OFAC SDN data formats and schemas page | Limitation that one SDN flat file can miss related data |
| BIS Part 744 / eCFR Entity List | BIS and eCFR official pages | Legal source for Entity List explanation |
| FinCEN BOI page | https://www.fincen.gov/boi |
BOI exclusion and status caution |
For synthetic sources, the register says they are invented. That matters because the article can safely show outputs without putting real people or companies into a public post. It also protects the reader from mistaking the sample for a case file.
The D2 synthetic sources are:
| Synthetic file | Purpose |
|---|---|
data/synthetic/d2_counterparties.csv |
Counterparty names for the teaching name screen |
data/sample/d2_fixture_screening_list.csv |
Teaching fixture shaped like normalized list data |
data/synthetic/d2_ownership_edges.csv |
Synthetic ownership graph for 50 Percent Rule arithmetic |
data/redacted_outputs/d2_ns_screen_sample.csv |
Publishable screen output |
data/redacted_outputs/d2_ownership_graph_sample.csv |
Publishable ownership teaching output |
The source register is what lets the article update every quarter. If Trade.gov changes the endpoint, OFAC changes the list service, BIS changes page structure, or FinCEN changes BOI status, the update should happen in the source register first and the article second.
Running the local screen
From the lab folder:
cd /Users/noah.r.green/NGO/SPP/articles/2026-06-14_national_security_diligence_stack/lab/national-security-diligence-lab
Run the synthetic name screen:
PYTHONPATH=src python3 ns_screen.py \
data/synthetic/d2_counterparties.csv \
data/sample/d2_fixture_screening_list.csv \
data/redacted_outputs/d2_ns_screen_sample.csv \
--threshold 0.80
The command writes a CSV and prints a reminder that outputs are leads only, not findings.
The publishable output looks like this:
query_name,candidate_name,source,score,posture
Synthetic Aero Components LLC,,,0.0000,no_current_signal_from_supplied_list
Redacted Quantum Trading Ltd,Redacted Quantum Trading Limited,Fixture BIS Entity List,0.9333,lead_only
Example Health Data Services Inc,,,0.0000,no_current_signal_from_supplied_list
Blocked Example Holdings,Blocked Example Holdings,Fixture OFAC SDN,1.0000,lead_only
Every row is synthetic. The output shows four different diligence ideas.
The first and third rows show no current signal from the supplied fixture list. They do not clear those names. They say only that this fixture and this method did not produce a match.
The second row shows a near match. “Ltd” and “Limited” are not identical strings, but they are close enough that the practitioner should review the source. In a real file, the next step would be identifiers, addresses, ownership, source list, and counsel routing if the source list were live and relevant.
The fourth row shows an exact match to a teaching fixture. In a real sanctions file, that would not be the end of the work. The analyst would need identifiers, program tags, addresses, aliases, ownership, blocked-property handling, and counsel.
The posture field is as important as the score. A score without a posture can be misunderstood. A posture without a score cannot be audited. D2 uses both.
Running the ownership teaching graph
Run the synthetic ownership graph:
PYTHONPATH=src python3 -m ns_diligence.ownership_graph \
data/synthetic/d2_ownership_edges.csv \
data/redacted_outputs/d2_ownership_graph_sample.csv
The publishable output is:
target,flagged_owner_percent,ofac_50_percent_teaching_signal,owners_seen,posture
Synthetic Target A,55.00,review,Blocked Example Holdings; Redacted Listed LP; Ordinary Investor LP,synthetic_lead_only
Synthetic Target B,15.00,below_synthetic_threshold,Ordinary Founder; Blocked Example Holdings,synthetic_lead_only
This is not a sanctions finding. It teaches why ownership matters. Direct list screening asks whether a named party appears on a list. Ownership tracing asks whether the entity is owned, directly or indirectly, by one or more blocked persons at a level that creates a restriction even if the entity itself is not named.
In the synthetic example, Target A has two flagged owners whose percentages sum to 55 percent. The output says “review.” It does not say blocked. In a real file, the next step would be the ownership documents, legal-entity chart, blocked-person status, indirect ownership, aggregation, control rights, dates, and counsel review. Target B has only 15 percent flagged ownership in the synthetic file, but that still does not mean clean. It means the supplied synthetic data does not cross the teaching threshold.
The reason to include this lablet in D2 is not to teach a lawyer how to apply OFAC. It is to teach a buyer-side diligence practitioner that a direct name screen is incomplete if ownership is unresolved.
Optional live-source smoke tests
D2 includes optional live tests. They are disabled by default because routine tests should not depend on network availability. To run them:
NS_DILIGENCE_LIVE=1 PYTHONPATH=src python3 -m unittest tests/test_live_sources.py
As of the D2 verification pass on 2026-06-16, the live tests passed:
| Test | Result | Meaning |
|---|---|---|
| Trade.gov CSL CSV parses into rows | OK | The endpoint was reachable and the parser saw expected public fields. |
| CSL includes BIS-related source rows | OK | The source field could be filtered for BIS-related list categories. |
| OFAC SDN CSV parses into rows | OK | The endpoint was reachable and the parser saw SDN rows. |
Those tests are engineering checks. They do not certify legal currency. They do not prove that the endpoint will be available tomorrow. They do not prove that every relevant alias is present in the parsed file. They do not prove that a no-hit clears a deal. They prove only that the public endpoints were reachable and parseable when tested.
That is still useful. A serious diligence file should be able to say: “This source was checked on this date, with this method, and this result.” If the source breaks later, the quarterly update log can show what changed.
How the code works
The code is intentionally readable.
fetch_csl.py defines the CSL CSV endpoint, fetches text with a simple user agent, parses the CSV with csv.DictReader, and normalizes a small set of fields:
source;name;type;programs;addresses;source_information_url;federal_register_notice.
The source_information_url matters because Trade.gov’s own CSL page tells users to go back to official source pages to confirm restrictions. A screen output that drops the source URL is weaker than one that preserves it.
fetch_ofac.py parses the SDN CSV into normalized rows with source, name, type, programs, and remarks. It is enough for teaching a list screen. It is not enough for a complete sanctions-screening database. OFAC’s own data materials explain why related files matter.
screen_names.py normalizes names by lowercasing and stripping punctuation, then compares the normalized query name to the normalized candidate name. It returns the best candidate above the configured threshold or a no-current-signal row. The default threshold is conservative for teaching. In a real system, matching thresholds, transliteration, alias logic, identifiers, and quality review need more work.
export_list_screen.py filters CSL rows for BIS-related source labels such as Entity List, Denied Persons, Unverified List, and Military End User. That is a party-screening exercise. It is not export classification.
ownership_graph.py reads synthetic owner-to-target rows, aggregates flagged-owner percentages by target, and writes a teaching signal. It does not handle indirect ownership, circular ownership, trusts, control rights, date changes, or conflicting source documents. Those are real-world issues for counsel and source-document diligence.
ns_screen.py ties the name screen together for the article. It reads a query CSV and a screening-list CSV, writes a CSV output, and prints the reminder: outputs are leads only, not findings.
The tests are equally plain. tests/test_screening_toolkit.py covers the parsers, BIS filtering, near-match output, exact-match output, and synthetic ownership signal. tests/test_live_sources.py checks live endpoint shape only when the environment variable is set.
The result is a lab that a reader can run in minutes. That matters because the code is not a black box. The reader can inspect every field and every limitation.
How to use the output in a risk memo
The output belongs in the risk memo as a lead table, not a conclusion table.
A useful risk-memo entry has five parts:
- The source and access date.
- The exact input name and source of that input name.
- The possible match, score, and source list.
- The next evidence request.
- The counsel escalation or unresolved gap.
For the synthetic near match, a real memo pattern would look like this:
| Field | Memo language |
|---|---|
| Input | Seller supplied “Redacted Quantum Trading Ltd” as a customer name in the customer list dated [date]. |
| Screen | D2 screen produced a possible match to “Redacted Quantum Trading Limited” from [source list] using [list access date]. |
| Posture | Lead only. Not a finding. Identifiers not yet verified. |
| Next request | Request legal name, registration number, address, country, customer contract, invoices, payment route, beneficial-owner support, and any prior sanctions/export review. |
| Escalation | Route to sanctions/export-control counsel before treating the relationship as ordinary-course revenue. |
For a no-current-signal result, the memo should still be disciplined:
| Field | Memo language |
|---|---|
| Input | Seller supplied “Synthetic Aero Components LLC” as a supplier name in the supplier list dated [date]. |
| Screen | No current signal from supplied list snapshot and configured threshold. |
| Posture | No-hit is not clearance. Alias, ownership, identifiers, and product/end-use facts remain outside this row. |
| Next request | Request registration number, ownership, address, country, products supplied, and export classification support if goods or technology are sensitive. |
| Escalation | Escalate if ownership, country, product, or payment facts create a separate trigger. |
That writing style prevents two bad outcomes. It prevents the deal team from panicking over a lead, and it prevents the deal team from relying on a no-hit as a clearance.
From public-list lead to counsel packet
A D2 screen is most useful when it turns a loose concern into a counsel-ready packet. Counsel should not receive a message that says “possible bad party?” Counsel should receive a compact packet with source, identifiers, role, and the exact unresolved question.
For a sanctions lead, the packet should include:
- the query name and source document;
- the candidate name and source list;
- the access date;
- the score and match posture;
- any addresses, countries, aliases, or identifiers available in the source list;
- ownership documents or a note that ownership is unresolved;
- transaction role, such as owner, customer, supplier, bank, or agent;
- payment history or proposed payment route if relevant;
- whether any property, contract, funds, receivable, or payable is currently exposed;
- the analyst’s limitation note.
The counsel question should be specific: “Does this possible OFAC match, if verified, require blocking, rejection, contract pause, reporting, license review, or further ownership tracing?” That is much better than “Is this okay?”
For an export-list lead, the packet should include:
- the query name and source document;
- the candidate name and list source;
- the source-information URL if available;
- the target’s product or technology involved in the transaction;
- any ECCN support the seller provided;
- country, end user, end use, and distributor facts;
- whether foreign-national employees or offshore teams can access controlled technology;
- a note that D2 did not classify the item.
The counsel question should be specific: “Does this restricted-party lead affect any export, reexport, transfer in-country, deemed export, license requirement, license exception, or technology-control-plan issue?” Again, the point is to route the fact pattern, not to answer it.
For an ownership lead, the packet should include:
- the direct owners and percentages;
- the source document for each percentage;
- any missing indirect ownership;
- blocked or restricted-party signals tied to owners;
- side letters or control rights;
- date of ownership chart;
- unresolved gaps.
The counsel question should be specific: “Do these ownership facts require OFAC 50 Percent Rule analysis, CFIUS foreign-person analysis, source-of-funds review, or deal-term protection?”
This packet discipline is where a certified fraud examiner’s habits matter. A CFE is trained to separate allegation, evidence, and conclusion. D2 uses that same posture for public-data diligence. The output is a lead. The packet is the evidence. The legal conclusion is counsel’s.
Common failure modes
D2 is also useful because it teaches what goes wrong.
Failure mode one is the screenshot screen. The analyst searches a web tool, takes a screenshot, and drops it into a folder. Six months later nobody knows the exact input, the source list date, whether fuzzy matching was enabled, whether the list was official, or whether the screenshot captured all results. A screenshot can be supporting evidence, but it is not a reproducible method.
Failure mode two is the stale export. A diligence team downloads a list once, saves it to a shared drive, and keeps reusing it. The output looks systematic because it comes from a CSV, but the source is old. The fix is simple: record the access date and re-pull before relying on the result.
Failure mode three is the clean no-hit. The memo says “no sanctions hits identified” when the screen checked only direct names, did not check aliases, did not check ownership, did not check addresses, and used a stale list. The better memo says “No current direct-name signal from the supplied list snapshot; alias, ownership, and identifier review remain open.”
Failure mode four is the overbroad hit. The memo says “sanctioned customer” when the output shows only a fuzzy lead with no identifier match. That can damage deal negotiations and credibility. The better memo says “Possible list lead, identifiers unresolved.”
Failure mode five is export classification drift. A party screen returns no signal, and someone treats that as export clearance. Export controls are not only about parties. They are also about items, technology, software, destination, end use, end user, and access. D2 intentionally repeats this point because it is one of the easiest ways to misuse list data.
Failure mode six is BOI confusion. A buyer assumes there is a public federal ownership database it can bulk-query. There is not. BOI is confidential and access-limited, and current reporting scope has changed. D2 uses synthetic ownership to teach the concept without misrepresenting FinCEN access.
Failure mode seven is public-case overclaim. A public forfeiture complaint or enforcement release may contain allegations, charges, admissions, orders, settlements, or final judgments. Those are different postures. Actual case data belongs in the case-data matter with a posture field. The D2 lab should not turn public case names into a screening list unless the source and legal meaning are carefully controlled.
These failure modes are avoidable. The fix is disciplined language, source dates, field preservation, and escalation.
What a buyer should ask for
The screen is only as good as the evidence around it. The buyer should request source documents that improve match quality and legal routing.
For parties and counterparties:
- legal name;
- prior names;
- trade names;
- aliases;
- registration numbers;
- tax IDs where appropriate;
- addresses;
- countries of formation, headquarters, operation, and payment;
- websites and email domains;
- bank names and payment routes where relevant;
- role in the transaction.
For ownership:
- capitalization table;
- beneficial-owner chart;
- shareholder register;
- limited partnership agreement;
- side letters;
- voting agreements;
- board and observer rights;
- control rights;
- information rights;
- trust or nominee documentation;
- source-of-funds support.
For sanctions and AML:
- existing sanctions-screening policy;
- latest screening logs;
- alert disposition history;
- blocked-property records;
- voluntary self-disclosure history;
- bank inquiries;
- AML risk assessment;
- customer due diligence files where lawfully accessible;
- regulator correspondence;
- internal audit reports.
For export controls:
- product list;
- technology descriptions;
- ECCN support;
- EAR99 support where asserted;
- Commodity Classification Automated Tracking System numbers if any;
- license applications and licenses;
- deemed-export review;
- foreign-national access;
- customer and end-user list;
- distributor and reseller list;
- technology-control plan.
For data-security diligence:
- data inventory;
- bulk counts;
- data categories;
- government-related data status;
- data-flow map;
- vendor and processor list;
- offshore support access;
- country-of-concern access paths;
- administrative roles;
- investor information rights.
D2 does not analyze all of those documents. It tells the buyer which documents to ask for when a public-data lead appears or when a no-hit leaves a gap.
Escalation rules
The screen should escalate on facts, not on fear.
Escalate to sanctions counsel when:
- a party, owner, bank, vessel, or counterparty appears to match an OFAC list entry;
- ownership by a blocked person is possible;
- a payment route, service, country, or property interest may be blocked or prohibited;
- a seller has prior OFAC correspondence, blocked-property reports, or voluntary disclosures;
- the buyer cannot resolve identifiers or ownership.
Escalate to export-control counsel when:
- the screen shows an Entity List, Denied Persons, Unverified List, Military End User, or related restricted-party lead;
- the target sells goods, software, source code, or technology with possible control sensitivity;
- foreign-national employees or offshore teams can access controlled technology;
- a customer, end user, distributor, or reseller creates end-use or end-user concern;
- the seller lacks ECCN support or gives only marketing descriptions.
Escalate to AML or financial-crime counsel when:
- ownership is complex, unexplained, nominee-based, or inconsistent across documents;
- source of funds is unclear;
- banking relationships raise questions;
- internal reports mention money-laundering, suspicious transactions, sanctions evasion, or fraud;
- a regulated target cannot produce program files, audit results, or regulator correspondence.
Escalate to CFIUS or national-security counsel when:
- foreign ownership or control intersects with sensitive technology, infrastructure, data, real estate, or government customers;
- a foreign limited partner has unusual rights;
- a data-rich target grants foreign access or information rights;
- a public-list lead changes the foreign-person or control analysis.
Escalate to privacy or DOJ Data Security Program counsel when:
- sensitive personal data or government-related data may be accessible by countries of concern or covered persons;
- vendor, employment, investment, or data-brokerage relationships create foreign access paths;
- data counts approach or exceed bulk thresholds;
- the target cannot produce a data map.
The accountant or certified fraud examiner owns the evidence file. Counsel owns the legal determination.
Practitioner Skill Built By This Article
This article builds the practitioner’s public-data screening discipline.
The practitioner can now recognize a public-list diligence lead, a no-current-signal result, a source-date problem, an unresolved ownership gap, and an export-list result that is being mistaken for export classification.
The practitioner verifies the source against the Authority Ladder:
- primary public list or official agency page first, including Trade.gov CSL, OFAC SDN materials, BIS/eCFR Part 744, and FinCEN BOI status;
- official guidance and data specifications second;
- source-status table and source log for article status and claims;
- law-firm or commercial commentary only as issue discovery.
The practitioner can produce:
- a reproducible screen command;
- a source register entry;
- a redacted or synthetic output;
- an evidence gap log;
- a risk-memo table that separates lead, no-hit, next request, and counsel escalation.
The practitioner escalates to counsel when a possible match, ownership gap, export-list signal, BOI/access issue, data-access path, funds-flow problem, or internal report creates a legal question. The practitioner does not decide whether the match is true, whether property is blocked, whether a license is required, whether BOI is lawfully available, whether CFIUS applies, or whether disclosure is required.
Practitioner artifact: runnable screen and redacted output
The shipped artifact is the D2 capstone screen:
PYTHONPATH=src python3 ns_screen.py \
data/synthetic/d2_counterparties.csv \
data/sample/d2_fixture_screening_list.csv \
data/redacted_outputs/d2_ns_screen_sample.csv \
--threshold 0.80
The artifact also includes:
docs/data_sources.md, the source register;docs/limitations.md, the interpretation limits;tests/test_screening_toolkit.py, the deterministic offline test suite;tests/test_live_sources.py, the optional live-source smoke tests;data/redacted_outputs/d2_ns_screen_sample.csv, the name-screen output;data/redacted_outputs/d2_ownership_graph_sample.csv, the synthetic ownership output.
The artifact is intentionally small enough for a reader to inspect. That is the point. A diligence practitioner does not need to trust the code blindly. The practitioner can see the fields, run the tests, inspect the output, and understand the limits.
Applied DD Lab: Replicate the Screen
This D2 Applied DD Lab has four steps.
Step 1: run the offline test suite.
PYTHONPATH=src python3 -m unittest tests/test_screening_toolkit.py
Expected result as of the D2 verification pass:
Ran 5 tests in 0.001s
OK
Step 2: generate the redacted name-screen output.
PYTHONPATH=src python3 ns_screen.py \
data/synthetic/d2_counterparties.csv \
data/sample/d2_fixture_screening_list.csv \
data/redacted_outputs/d2_ns_screen_sample.csv \
--threshold 0.80
Expected result:
NS screen complete: {'rows': 4, 'output': 'data/redacted_outputs/d2_ns_screen_sample.csv'}
Reminder: outputs are leads only, not findings.
Step 3: generate the synthetic ownership output.
PYTHONPATH=src python3 -m ns_diligence.ownership_graph \
data/synthetic/d2_ownership_edges.csv \
data/redacted_outputs/d2_ownership_graph_sample.csv
Expected result:
Ownership graph complete: {'rows': 2, 'output': 'data/redacted_outputs/d2_ownership_graph_sample.csv'}
Step 4: optionally run the live-source smoke tests.
NS_DILIGENCE_LIVE=1 PYTHONPATH=src python3 -m unittest tests/test_live_sources.py
Expected result as of 2026-06-16:
Ran 3 tests in 7.126s
OK
The live tests may fail later if a public endpoint changes, rate-limits, blocks automated access, or changes schema. That is not a failure of the article. It is the reason the repo has docs/update_log.md and the series has a quarterly update queue.
The D2 checklist
Before a D2-style screen goes into a diligence file, the practitioner should be able to answer these questions:
| Question | Required answer |
|---|---|
| What names were screened? | Exact query names, source document, and date received. |
| What list was used? | Official source, endpoint or file, access date, and source owner. |
| What fields were preserved? | At least query name, candidate name, source, score, and posture. |
| What does a hit mean? | Lead only, pending identifiers and counsel review. |
| What does no-hit mean? | No current signal from supplied list snapshot only. |
| Were aliases checked? | Say yes only if alias files or source documents were actually checked. |
| Was ownership checked? | Say yes only if source documents support the ownership graph. |
| Was export classification checked? | Say yes only if ECCN or classification support was reviewed by the proper specialist. |
| Was BOI used? | No, not in this public bulk screen. |
| What gets escalated? | Possible matches, unresolved ownership, export-list signals, data access, funds-flow gaps, and legal interpretation. |
This checklist is the real habit. The code teaches the habit, but the habit is what protects the file.
What belongs in the risk memo
The risk memo should not attach the CSV and stop. It should explain the method.
Use this structure:
- Scope. State which parties were screened and which parties were not screened.
- Sources. Identify the public list, endpoint, source date, and official source owner.
- Method. State the matching method, threshold, and fields retained.
- Results. Separate leads from no-current-signal rows.
- Limitations. State that outputs are leads only, no-hit is not clearance, and source lists can be incomplete for the legal question.
- Evidence gaps. List missing identifiers, aliases, ownership, addresses, product facts, data facts, and source documents.
- Escalation. Name the counsel lane and decision owner.
- Next refresh. Record when the source will be re-pulled.
The memo should avoid three phrases:
- “Cleared by screening.”
- “No sanctions issue.”
- “Export compliant.”
Those phrases are legal conclusions or too broad for a public-data screen. Better phrases are:
- “No current signal from the supplied list snapshot under the configured method.”
- “Possible restricted-party lead, identifiers unresolved.”
- “Export-list party signal identified; ECCN and license analysis remain counsel-controlled.”
Precise language is not a defensive exercise. It makes the buyer more effective. It lets deal counsel focus on the right unresolved fact instead of unwinding an analyst’s overstatement.
Where this fits in the full workflow
D2 sits after D1 intake and before final risk-memo conclusions.
The order is:
- Intake collects names, countries, ownership, products, data, funds flow, and source documents.
- D2 screens names against public or supplied lists.
- The team reviews leads, no-current-signal rows, and evidence gaps.
- Counsel receives the possible legal questions.
- The risk memo records the posture.
- Deal terms respond if the issue is material.
- The file is refreshed before signing, closing, and quarterly maintenance if the deal remains open.
That order matters because a screen without intake is underfed, and a risk memo without screening is under-sourced.
The D2 output can support several deal responses:
- request missing identifiers;
- require seller remediation before signing;
- add a condition precedent for regulatory review;
- require a sanctions or export-control representation;
- add a special indemnity or escrow for an identified issue;
- carve out a customer, supplier, or contract;
- pause closing until counsel resolves a possible match;
- plan post-close look-back and voluntary self-disclosure review.
The output cannot decide which response is correct. It can make the decision record better.
Quarterly maintenance
The toolkit needs quarterly maintenance for the same reason the articles do. Public-list endpoints, legal status, agency guidance, and rule posture change.
Every quarter, update:
docs/data_sources.md, with current endpoint checks and access dates;docs/limitations.md, if a source changes what the data can or cannot support;docs/update_log.md, with what changed;source_status_table.md, if a related legal status changes;source_log.md, if the article keeps a claim about source status or endpoint shape;- the article status note;
- live-source smoke tests, if endpoints changed.
Always recheck:
- Trade.gov CSL page and CSV endpoint;
- OFAC SDN download and Sanctions List Service posture;
- BIS Part 744 and eCFR Entity List source;
- FinCEN BOI page;
- any added USAspending, SAM.gov, CFIUS public-action, or case-data modules;
- the source URLs embedded in any public-release timeline.
The reader-return mechanism should be visible. A status note near the top or bottom of the article tells the reader when the screen was last reviewed and what the watch items are. That is how the article becomes a living reference rather than a static post.
Terms used in this article
- BOI (beneficial ownership information): FinCEN beneficial-ownership information under the Corporate Transparency Act; confidential and access-limited, not a public bulk dataset.
- CSL (Consolidated Screening List): Trade.gov’s public consolidated screening aid for multiple federal export and sanctions-related lists.
- ECCN (Export Control Classification Number): the EAR classification code for controlled items on the Commerce Control List; D2 does not assign ECCNs.
- Entity List: BIS list in Supplement No. 4 to Part 744 identifying parties subject to license requirements and other restrictions.
- False negative: a missed risk signal caused by source, spelling, alias, identifier, data, or method limits.
- False positive: a possible match that turns out not to be the same person or entity after verification.
- Fuzzy match: a near-name match based on similarity rather than exact spelling.
- OFAC 50 Percent Rule: OFAC guidance treating entities owned 50 percent or more, directly or indirectly, by one or more blocked persons as blocked even if not separately listed.
- SDN (Specially Designated National): a person, entity, vessel, or aircraft listed by OFAC as blocked under one or more sanctions programs.
- Source-information URL: a CSL field pointing users back to the official source for restrictions or list details.
- Synthetic data: invented teaching data used to demonstrate a method without exposing client, target, private, or live-party records.
Selected sources
- Trade.gov, Consolidated Screening List, https://www.trade.gov/consolidated-screening-list
- Trade.gov, downloadable CSL CSV endpoint, https://data.trade.gov/downloadable_consolidated_screening_list/v1/consolidated.csv
- OFAC FAQ 80, SDN CSV format, https://ofac.treasury.gov/faqs/80
- OFAC SDN legacy CSV endpoint, https://www.treasury.gov/ofac/downloads/sdn.csv
- OFAC, Tutorial on the Use of List-related Legacy Flat Files, https://ofac.treasury.gov/sdn-list-data-formats-data-schemas/tutorial-on-the-use-of-list-related-legacy-flat-files
- OFAC SDN data specification, https://ofac.treasury.gov/media/29976/download?inline=
- BIS, EAR Part 744, https://www.bis.gov/regulations/ear/744
- eCFR, 15 CFR Part 744, Supplement No. 4, Entity List, https://www.ecfr.gov/current/title-15/subtitle-B/chapter-VII/subchapter-C/part-744/appendix-Supplement%20No.%204%20to%20Part%20744
- FinCEN, Beneficial Ownership Information Reporting, https://www.fincen.gov/boi
- D2 Applied DD Lab:
lab/national-security-diligence-lab/ns_screen.py - D2 source register and limitations:
lab/national-security-diligence-lab/docs/data_sources.mdandlab/national-security-diligence-lab/docs/limitations.md
Status note
Last reviewed: 2026-06-16.
Next scheduled review: 2026-09-16.
Current watch items: Trade.gov CSL endpoint shape and update policy; OFAC Sanctions List Service and legacy SDN CSV availability; BIS Entity List and Part 744 amendments; FinCEN BOI status and access rules; any added USAspending, SAM.gov, CFIUS public-action, or case-data modules; quarterly test results for tests/test_live_sources.py.
By Noah Green CPA CFE, for Sheepdog Prosperity Partners. Educational only; not legal advice. SPP explains diligence issue-spotting, evidence collection, risk triage, and the accountant/CFE workflow. It does not provide sanctions opinions, export classifications, CFIUS legal opinions, BOI access advice, privacy opinions, forfeiture-defense advice, whistleblower advice, or voluntary self-disclosure advice.
