Fact Graph Documentation

repository·main·Indexed 19 days ago

https://github.com/irs-public/fact-graph

A production-ready knowledge graph and tax logic engine used for modeling the United States Internal Revenue Code and associated tax laws. Designed for JavaScript and JVM-based environments, it utilizes Fact XML (FXML) to define Fact Dictionaries containing Writable and Derived facts. Version 3.1 provides a standalone library for calculating taxes based on user-provided information, supporting custom types, reusable calculations, and collection facts with wildcards.

Tokens
12.2K
Snippets
44
Records
54
Agent score
64%

What's inside Fact Graph

  1. What is the Fact Graph?

    main

    The Fact Graph is a standalone tax logic engine designed to calculate taxes based on user-provided information. It is intended to be used as a consumable library for both JVM and JavaScript-based applications, allowing developers to implement tax law changes without hard-coding logic into their specific applications.

    It consists of two primary components:

    1. Fact Dictionary: A set of tax facts (e.g., eligibility requirements for a credit) represented as XML documents using Fact XML (FXML).
    2. The Graph: An instantiation of a specific user's tax scenario, created by applying the Fact Dictionary logic to the taxpayer's personal information.
  2. Handle Collection facts and wildcards

    main

    The Fact Graph supports collections where each item shares the same possible facts. In the dictionary, collection facts are identified by a wildcard * in their path (e.g., /jobs/*/income).

    During evaluation, the * is replaced with a # followed by the unique UUID of the specific item. For example, a job with UUID a3006af1-a040-4235-9d31-68c5830c55fd will have its path resolved to /jobs/#a3006af1-a040-4235-9d31-68c5830c55fd/income.

    <Fact path="/jobs/*/yearToDateIncome">
      <Writable>
        <Dollar/>
      </Writable>
    </Fact>
  3. Key terms in Fact Graph

    main

    Understanding the following terminology is essential for working with the Fact Graph:

    • Fact Graph (lowercase): A specific instantiation of a user's tax scenario.
    • Fact Dictionary: A set of facts about tax logic (e.g., 'to be eligible for X credit you must be Y years of age').
    • Fact XML (FXML): The markup language used to define Fact Dictionaries.
    • TS25: Refers to Tax Season 2025.
  4. Add metadata to Fact XML (FXML)

    main

    You can include arbitrary, user-defined metadata in your Fact Dictionary using the <Meta> tag. This metadata is intended to be serialized along with the fact graph JSON.

    Example XML:

    <Meta>
      <name>My Facts</name>
      <version>1.3.0</version>
    </Meta>

    Resulting JSON structure:

    {
      "facts": [],
      "meta": {
        "name": "My Facts",
        "version": "1.3.0"
      }
    }
  5. Manage Fact Graph persistence and validation

    main

    The Fact Graph is designed to exist in-memory during a session. To persist the state, use the serialization method provided by the graph instance, which returns a JSON representation. The consumer is responsible for deciding when and how to save this JSON (e.g., to a database or file).

    Validation Logic: Validation is decoupled from the save() process. Because users may enter data incrementally, the graph may exist in an invalid state during the process. The library is moving toward exposing validation through its own dedicated interface so that users can check for errors without being forced to trigger a save operation.

  6. Define facts in a Fact Dictionary

    main

    A Fact Dictionary is defined using an XML structure. The root container is a <FactDictionaryModule>, which must contain a single <Facts> element. The <Facts> element acts as a container for multiple <Fact> definitions.

    To define a fact, use the <Fact> element with a path attribute. Every <Fact> must have exactly one of either <Writable> or <Derived> as a child to determine how its value is obtained.

    <FactDictionaryModule>
      <Facts>
        <Fact path="/totalTax">
          <Derived>
            <Add>
              <Dependency path="/tentativeTaxNetNonRefundableCredits"/>
              <Dependency path="/totalOtherTaxes"/>
            </Add>
          </Derived>
        </Fact>
      </Facts>
    </FactDictionaryModule>
  7. Define custom types in Fact XML (FXML)

    main

    To avoid using only basic primitives, you can define custom types within a <Types> module in your FactDictionary. This allows you to create domain-specific types (like IpPin or Address) based on the core Fact Graph primitives.

    Supported Primitives:

    • Boolean
    • Integer
    • Double (used for precision instead of float)
    • String
    • Object (key-value pairs of other types)

    Example Type Declaration:

    <Type>
      <Name>IpPin</Name>
      <BaseType>String</BaseType>
      <Limit type="Match">
         <![CDATA[^([0-9]{6})$]]>
      </Limit>
    </Type>
  8. Understand the Fact Graph 3.1 architectural direction

    main
    Fact Graph 3.1 is being developed as a standalone, isolated library to improve re-usability across different IRS projects. Unlike previous versions that were tightly coupled with df-client, FG3.1 aims to remove DF-specific logic from its API. This allows the library to be used in various environments, including directly in the browser without complex scaffolding. The project continues to use Scala to maintain the ability to target both JavaScript (JS) and the Java Virtual Machine (JVM).
  9. Configure Vim or Neovim for Scala and Scalafmt

    main

    To use Vim/Nvim with Fact Graph, first install the necessary tools via Coursier:

    # Install scalafmt and Metals language server
    # (Assumes coursier is already installed)
    coursier install scalafmt
    coursier install metals

    Vim Configuration

    Add this to your ~/.vimrc to enable auto-formatting on save:

    autocmd BufWritePre *.scala call s:scalafmt()
    
    function! s:scalafmt()
      let l:cmd = 'scalafmt ' . shellescape(expand('%:p'))
      let l:output = system(l:cmd)
      if v:shell_error
        echohl ErrorMsg | echo "Scalafmt failed:" l:output | echohl None
      else
        silent! edit!
      endif
    endfunction

    Neovim Configuration

    Add this to your init.lua to enable auto-formatting on save:

    vim.api.nvim_create_autocmd("BufWritePre", {
      pattern = "*.scala",
      callback = function()
        local file = vim.fn.expand("%:p")
        local result = vim.system({ "scalafmt", file }):wait()
    
        if result.code ~= 0 then
          vim.notify("Scalafmt failed:\n" .. result.stderr, vim.log.levels.ERROR)
        else
          vim.cmd("silent! edit!")
        end
      end,
    })
    -- Neovim init.lua snippet
    vim.api.nvim_create_autocmd("BufWritePre", {
      pattern = "*.scala",
      callback = function()
        local file = vim.fn.expand("%:p")
        local result = vim.system({ "scalafmt", file }):wait()
    
        if result.code ~= 0 then
          vim.notify("Scalafmt failed:\n" .. result.stderr, vim.log.levels.ERROR)
        else
          vim.cmd("silent! edit!")
        end
      end,
    })
  10. Install Java, Scala, and sbt using Coursier

    main

    Fact Graph requires Scala, a JDK, and sbt (Scala Build Tool). The recommended way to install these is via coursier.

    1. Install Coursier based on your OS:

      • Linux x86-64: curl -fL "https://github.com/coursier/launchers/raw/master/cs-x86_64-pc-linux.gz" | gzip -d > cs
      • Linux ARM64: curl -fL "https://github.com/VirtusLab/coursier-m1/releases/latest/download/cs-aarch64-pc-linux.gz" | gzip -d > cs
      • macOS Apple Silicon: curl -fL https://github.com/coursier/coursier/releases/latest/download/cs-aarch64-apple-darwin.gz | gzip -d > cs
      • macOS Intel: curl -fL https://github.com/coursier/launchers/raw/master/cs-x86_64-apple-darwin.gz | gzip -d > cs
      • macOS (Homebrew): brew install coursier/formulas/coursier
    2. Run Setup: chmod +x cs && ./cs setup (or cs setup if using Homebrew).

    3. Install Dependencies:

      • Java 21.0.5: cs java install openjdk:21.0.5
      • sbt: cs install sbt
      • scalafmt: cs install scalafmt

    Note: A NodeJS installation is also required to run the test suite against the JS build.

    # Example for macOS Apple Silicon
    curl -fL https://github.com/coursier/coursier/releases/latest/download/cs-aarch64-apple-darwin.gz | gzip -d > cs
    chmod +x cs
    ./cs setup
    cs java install openjdk:21.0.5
    cs install sbt
    cs install scalafmt
  11. Configure your GitHub no-reply email for commits

    main

    To comply with project requirements, all commits must use your GitHub-provided noreply email address (e.g., {ID}+{USERNAME}@users.noreply.github.com).

    1. Enable private email: In GitHub email settings, enable Keep my email address private.
    2. Set local git config:
      • To use this email for all projects: git config --global user.email "YOUR_NO_REPLY_EMAIL".
      • To use this email only for Fact Graph: Navigate to the project directory and run git config user.email "YOUR_NO_REPLY_EMAIL".
    3. Verify: Run git config user.email to confirm.
    # Set for all projects
    git config --global user.email "YOUR_ID+YOUR_USERNAME@users.noreply.github.com"
    
    # Set for this repository only
    cd ./path/to/fact-graph/
    git config user.email "YOUR_ID+YOUR_USERNAME@users.noreply.github.com"
    
    # Verify
    git config user.email