Building a Better Way to Navigate the Cuban Assets Control Regulations

avatar
(Edited)

Built with GPT technology

Most discussions about the U.S. sanctions imposed on Cuba eventually become ideological. Very few people—regardless of their political position—are actually familiar with the regulatory framework governing those sanctions. Some minimize their impact without ever reading the regulations. Others denounce them without understanding how they are legally structured. Thus, in both cases, the debate often relies more on rhetoric than on evidence.

That observation became the starting point of a project I've been building over the past few days. My goal is not simply to make the regulations available—they already are—but to make them understandable, navigable, and traceable. I want someone with no prior knowledge of U.S. federal regulations to be more able to explore those relevant to Cuba, understand where each provision comes from, follow its regulatory history, and eventually ask complex questions about its content.

The regulatory core of the U.S. sanctions program against Cuba is administered by the U.S. Department of the Treasury's Office of Foreign Assets Control (OFAC). It is codified as 31 CFR Part 515, better known as the Cuban Assets Control Regulations (CACR). The regulations were originally introduced on July 9, 1963, and have grown through more than 150 regulatory sections and many amendments over the decades.

My application is the foundation of a much larger project whose long-term objective is to translate the CACR's legal and regulatory language into something ordinary Cubans can understand. Ultimately, I want to build a system capable of answering complex questions in natural language while preserving complete documentary traceability back to the original federal sources.

Building an Integration Layer

At first I considered implementing everything as a standalone HTML application. That approach quickly reached its limits. The project depends on combining information coming from several federal repositories that were never designed to interoperate with one another. Some expose REST APIs, others provide XML documents, others only expose HTML pages intended for human consumption, and some critical resources don't even return the CORS headers required for direct browser access.

Rather than maintaining separate Python and JavaScript stacks, I decided to build the backend entirely in Node.js. Express became the HTTP layer of the application, while axios handles outbound requests to external services and Cheerio parses XML/HTML whenever no structured API is available. The backend therefore does much more than simply proxy requests. It acts as an integration layer that

  • normalizes responses coming from multiple federal sources;

  • parses XML and HTML documents;

  • resolves hidden document links;

  • exposes clean REST endpoints to the frontend;

  • caches expensive lookups;

  • and gracefully falls back to an alternative source whenever the eCFR API becomes unavailable.

That architectural decision immediately solved one of the most frustrating problems I encountered.

Recovering the Original Federal Register "Issue Slice"

Every amendment to the CACR references its original publication in the Federal Register.

A citation such as

28 FR 6974

corresponds to the Federal Register entry that originally established the Cuban Assets Control Regulations in 1963.

The Federal Register provides a citation page such as https://www.federalregister.gov/citation/28-FR-6974, which conveniently links both to

  • the complete Federal Register issue;

  • and the much smaller Issue Slice PDF, containing only the relevant pages.

Serving the citation page itself would have been easy. Likewise, I could simply redirect users to GovInfo's Link Service using a URL pattern like

https://www.govinfo.gov/link/fr/28/6974

However, that would often send readers of older Federal Register volumes to an entire scanned issue containing hundreds of irrelevant pages. I wanted something much more useful, so my application automatically retrieves the Federal Register citation page, parses its HTML, extracts the URL pointing to the Issue Slice PDF, and injects it directly into the application's source references.

The overall workflow looks like this:

Browser
    │
    ▼
Express endpoint
    │
    ▼
Federal Register citation page
    │
    ▼
Cheerio parses HTML
    │
    ▼
Issue Slice URL extracted
    │
    ▼
JSON response
    │
    ▼
Frontend

Since the citation page does not expose CORS headers, this operation cannot be performed directly from browser-side JavaScript. Moving the logic to the backend not only bypasses the browser's CORS restrictions, but also encapsulates the entire resolution process behind a clean API that the frontend can consume without worrying about HTML parsing or document discovery. From the user's perspective, this reduces what normally requires several manual clicks on the official eCFR website into a single click directly to the exact PDF containing the regulatory amendment.

Automatically Building the Historical Editions Timeline

Another limitation of a purely client-side application appeared when I tried to generate the historical timeline of the Cuban Assets Control Regulations. I want users to be able to browse every annual edition of 31 CFR Part 515, regardless of whether it was published last year or sixty years ago. At first glance, that sounds trivial. It isn't. GovInfo provides a convenient entry point for the latest available edition through a stable URL:

https://www.govinfo.gov/link/cfr/31/515

Today, that link redirects to https://www.govinfo.gov/content/pkg/CFR-2025-title31-vol3/pdf/CFR-2025-title31-vol3-part515.pdf. The challenge is that the browser never gets access to the redirection target because the request is subject to CORS restrictions, and I need to know the year of the last edition. Once again, the backend became the natural place to solve the problem.

Instead of hardcoding years, the server follows the redirection, discovers the latest available annual edition, extracts the publication year, and generates the complete historical sequence. As a result, whenever GovInfo publishes a new annual revision, the application automatically updates itself without requiring any changes to the frontend.

Going Beyond GovInfo

GovInfo, however, only tells part of the story. The annual CFR volumes available there do not cover the entire history of the Cuban Assets Control Regulations. Earlier editions are preserved elsewhere. To bridge that historical gap, I integrated another federal repository: the Library of Congress. It exposes a JSON endpoint that allows searching its CFR collection programmatically. I retrieved and organized those records automatically, and the result is a continuous timeline that spans from the earliest CFR editions through the most recent publications available on GovInfo. From the user's perspective, there is no visible distinction between repositories. Everything appears as a single, coherent historical collection. That is precisely the role of the backend: hiding the complexity of multiple federal archives behind a unified interface.

When Production Breaks

Ironically, while I was writing this post and testing the application, one of the most important services suddenly stopped working. The endpoint I rely on to retrieve historical versions of individual sections from the eCFR Versioner endpoint began returning errors. For example:

https://www.ecfr.gov/api/versioner/v1/full/2026-07-23/title-31.xml?subtitle=B&chapter=V&part=515&section=515.201

Until that moment, this endpoint had been the primary source for retrieving the regulatory text from any section on any specific date. This is one of those situations where architectural decisions prove their value. I spent the better part of Saturday designing a graceful degradation strategy. Whenever the Versioner endpoint cannot provide the text, the backend automatically switches to GovInfo and retrieves the corresponding XML from the latest consolidated annual edition instead.

For example:

https://www.govinfo.gov/link/cfr/31/515?sectionnum=209&link-type=xml

This guarantees that users can continue reading the regulatory text instead of facing an error page. I consider that an important characteristic of any software intended to support research.

What This Project Is Really About

Although this application revolves around the Cuban Assets Control Regulations, I don't see it as a "31 CFR Part 515 viewer." That is merely its first use case. The real objective is much broader. What I'm building is an integration layer capable of transforming heterogeneous federal regulatory sources into a single searchable, traceable, and machine-readable knowledge base.

So far, I am connecting:

  • the eCFR Versioner API;

  • the Federal Register;

  • Federal Register citation pages;

  • GovInfo;

  • the Library of Congress;

  • and historical CFR collections.

Tomorrow, the same architecture can incorporate other regulatory regimes with very little structural change. The next obvious candidate is the Export Administration Regulations (EAR), particularly the provisions governing exports and reexports involving Cuba. Ultimately, I want this platform to evolve beyond document retrieval to become a regulatory intelligence system capable of answering complex questions in natural language while preserving complete traceability to the original legal sources.

Large language models make that vision dramatically more achievable than it was only a few years ago. They simplify implementation. They accelerate development. But remember that they do not replace the most important ingredient of the project: a deep understanding of the regulatory domain and the business logic that must be faithfully represented. Modern software can only become truly useful when those two elements work together.

A Look Under the Hood

The previous sections describe the architecture from a conceptual perspective. But software is ultimately built through concrete decisions. The following examples show some of the mechanisms behind the platform.

Resolving Federal Register Issue Slices

The Federal Register citation page contains the link to the Issue Slice PDF, but that information is embedded in HTML rather than exposed through a simple API. The backend resolves it automatically:

app.get("/api/fr/slice/:citation", async (req, res) => {
    try {
        const url = `https://www.federalregister.gov/citation/${req.params.citation}`;

        const response = await axios.get(url);

        const $ = cheerio.load(response.data);

        const sliceUrl = $('a[href*="issue_slice"]')
            .first()
            .attr("href");

        res.json({
            citation: req.params.citation,
            issueSlice: sliceUrl
        });

    } catch (error) {
        res.status(500).json({
            error: "Unable to resolve Federal Register slice"
        });
    }
});

Building a Dynamic Regulatory Timeline

The annual CFR editions are not hardcoded. The server follows the GovInfo Link Service, identifies the latest available edition, and generates the historical timeline dynamically. A simplified version of that logic:

async function getLatestCFRVersion() {
    const response = await axios.get(
        "https://www.govinfo.gov/link/cfr/31/515",
        {
            maxRedirects: 0,
            validateStatus: status => status === 302
        }
    );

    const location = response.headers.location;

    const match = location.match(
        /CFR-(\d{4})-title31-vol3/
    );

    return match ? match[1] : null;
}

Degradation Through Fallback Sources

External APIs are powerful, but they are also external dependencies. When the eCFR Versioner endpoint becomes unavailable, the system switches to govinfo.gov.

async function getSection(section) {
    try {
        return await getFromECFR(section);

    } catch (error) {
        console.log(
            "eCFR unavailable. Using GovInfo fallback."
        );

        return await getFromGovInfo(section);
    }
}

Screenshot from the frontend

Source for the cover image, built with GPT technology.



0
0
0.000
0 comments