<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:itunes="http://www.itunes.com/dtds/podcast-1.0.dtd" xmlns:googleplay="http://www.google.com/schemas/play-podcasts/1.0"><channel><title><![CDATA[Fritz Jung]]></title><description><![CDATA[#temutalent | #alwaysonvacation]]></description><link>https://fritzjung.substack.com</link><image><url>https://substackcdn.com/image/fetch/$s_!kd_5!,w_256,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F56306608-e78c-40be-8f91-8b75550f7ea3_508x508.png</url><title>Fritz Jung</title><link>https://fritzjung.substack.com</link></image><generator>Substack</generator><lastBuildDate>Mon, 13 Jul 2026 10:10:11 GMT</lastBuildDate><atom:link href="https://fritzjung.substack.com/feed" rel="self" type="application/rss+xml"/><copyright><![CDATA[Fritz Jung]]></copyright><language><![CDATA[en]]></language><webMaster><![CDATA[fritzjung@substack.com]]></webMaster><itunes:owner><itunes:email><![CDATA[fritzjung@substack.com]]></itunes:email><itunes:name><![CDATA[Fritz Jung]]></itunes:name></itunes:owner><itunes:author><![CDATA[Fritz Jung]]></itunes:author><googleplay:owner><![CDATA[fritzjung@substack.com]]></googleplay:owner><googleplay:email><![CDATA[fritzjung@substack.com]]></googleplay:email><googleplay:author><![CDATA[Fritz Jung]]></googleplay:author><itunes:block><![CDATA[Yes]]></itunes:block><item><title><![CDATA[Building A Data Intelligence System]]></title><description><![CDATA[Over the past months I&#8217;ve been working on a data intelligence platform.]]></description><link>https://fritzjung.substack.com/p/building-a-data-intelligence-system</link><guid isPermaLink="false">https://fritzjung.substack.com/p/building-a-data-intelligence-system</guid><dc:creator><![CDATA[Fritz Jung]]></dc:creator><pubDate>Mon, 06 Jul 2026 16:52:22 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!kd_5!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F56306608-e78c-40be-8f91-8b75550f7ea3_508x508.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Over the past months I&#8217;ve been working on a data intelligence platform. A system to bring disparate data into a coherent picture.</p><p>Building the system, I am focusing on 10 questions I have about the world around me. A mechanical interest in understand a holistic picture as to why things happen. </p><p>FEC, SEC, Legislation, BLM (the government org, not the advocacy org), GSA, and various OIG orgs are among the data sources I&#8217;m ingesting. There are state level agencies sprinkled in there, such things as business data. </p><p>I can currently ingest a lot of it. A day or two ago I was ingesting quarterly SEC bulk data.  On my desktop it is more limited but between Having 3 very different data pieces, joining them with my DSL gumlang language and compiling an 11 million line csv to then put it in Clickhouse I clocked it at ~14 minutes. So the breakdown total was processing around 742K pieces of data a minute. </p><p>There is room for improvement, but it was a good real world reminder of the importance of Big O. Algorithms matter a lot for time and energy costs.</p><h2>What is Gumpla conceptually?</h2><p>Above I said I &#8220;compiled facts&#8221;. That means little, what are facts here?</p><h4>Facts are:</h4><ul><li><p>a subject</p></li><li><p>a predicate (donates to, does business with, legislated on)</p></li><li><p>a value ($100, 100 documents, 100 connections etc)</p></li><li><p>time</p></li><li><p>confidence</p></li><li><p>provenance</p></li><li><p>properties </p></li></ul><h4>Example</h4><blockquote><p>Apple Inc. reported assets 364,980,000,000 USD on 2025-03-31</p></blockquote><p>The point being conceptually gumpla revolves around facts. </p><h3>Conceptual shift to facts and interpretability</h3><p>While I outlined facts above, I am aware &#8220;fact&#8221; can be a loaded term. It is the most relevant concept to what I&#8217;m doing.</p><p>The facts pertain to the data alone. Facts are gathered to bring about &#8220;interpretability&#8221;.</p><p>During test ingestion of FEC and SEC data sources I&#8217;ve come across wild data. You can read about how official data sucks here: <a href="https://fritzjung.substack.com/p/official-data-sucks">"why official data sucks"</a></p><p>I decided that dropping the wild data points I found was a fools errand. Defining what is actually dirty in data is a tough problem. Sure, outliers are easy to find. You only need to establish standard deviations and find which points are outside it.</p><p>The problem though is deeper, not every piece of dirty data would necessarily be an outlier. Outliers themselves may not be bad data points. More important though, these outliers still tell me things.</p><p>Take the 14 person bio company claiming to have earned 4x apple during a &lt;$20M IPO. </p><p>Is it an intentional misleading? </p><p>Is it a mistake? </p><p>The data colors the dataset in which it exists. I&#8217;ve found what is better is to see how many colors I can elicit from this portrait. Facts surrounding the company in which I can interpret it better.</p><p>Bad data still tells me a story. And it&#8217;s only a problem if I don&#8217;t have context in which it exists.</p><div><hr></div><h2>The Architecture</h2><p>Initially I called this project Oliver, then Gumshoe, then into settling on Gumpla, a play on gumshoe + gunpla. </p><p>Over the iterations I came on the shape below, its a sketch, I diagramed it on Linux and I didn&#8217;t have that adobe niceness. </p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!DcnW!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F549f4f18-3bf5-405d-86c5-45ddfcd42a60_931x1211.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!DcnW!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F549f4f18-3bf5-405d-86c5-45ddfcd42a60_931x1211.png 424w, https://substackcdn.com/image/fetch/$s_!DcnW!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F549f4f18-3bf5-405d-86c5-45ddfcd42a60_931x1211.png 848w, https://substackcdn.com/image/fetch/$s_!DcnW!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F549f4f18-3bf5-405d-86c5-45ddfcd42a60_931x1211.png 1272w, https://substackcdn.com/image/fetch/$s_!DcnW!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F549f4f18-3bf5-405d-86c5-45ddfcd42a60_931x1211.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!DcnW!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F549f4f18-3bf5-405d-86c5-45ddfcd42a60_931x1211.png" width="931" height="1211" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/549f4f18-3bf5-405d-86c5-45ddfcd42a60_931x1211.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1211,&quot;width&quot;:931,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:143038,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://fritzjung.substack.com/i/205576873?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F549f4f18-3bf5-405d-86c5-45ddfcd42a60_931x1211.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!DcnW!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F549f4f18-3bf5-405d-86c5-45ddfcd42a60_931x1211.png 424w, https://substackcdn.com/image/fetch/$s_!DcnW!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F549f4f18-3bf5-405d-86c5-45ddfcd42a60_931x1211.png 848w, https://substackcdn.com/image/fetch/$s_!DcnW!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F549f4f18-3bf5-405d-86c5-45ddfcd42a60_931x1211.png 1272w, https://substackcdn.com/image/fetch/$s_!DcnW!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F549f4f18-3bf5-405d-86c5-45ddfcd42a60_931x1211.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p></p><p>Not the prettiest, however I feel it conveys the general meaning and shape. In this document I want to go over the rational and pieces of it.</p><div><hr></div><h2>Gumption and Gumlang</h2><h3>Gumption</h3><p>Gumption is the data query dsl I wrote to query both Clickhouse and Tantivy. Below is a robust example:</p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;rust&quot;,&quot;nodeId&quot;:&quot;3f12debf-2429-4a26-886a-4066dd2f7656&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-rust">//
// Montana PCA Provider Investigation
//

family pca_providers {
    subject.entity_type = organization
    subject.topic = pca_provider
    subject.jurisdiction = MT

    observed_at between 2019-01-01 and 2024-12-31
}

family audited_providers {
    use pca_providers

    mention.source in [
        mt_legislative_auditor,
        cms_audit,
        oig_hhs,
    ]
}

family high_billers {
    use pca_providers

    predicate = billed_medicaid
    value_number &gt;= 500000
}

family sanctioned {
    use pca_providers

    predicate in [
        sanctioned_by,
        investigated_by,
        cited_in_audit,
    ]
}

//
// Profile
//

pca_providers -&gt; profile {
    include = [
        facts,
        mentions,
        relationships,
    ]

    depth = 2
    limit = 100
}

//
// Billing statistics
//

pca_providers -&gt; facts {
    predicate in [
        billed_medicaid,
        registered_as,
    ]

    value_number &gt;= 100000

    group_by = subject_id
    metric = sum(value_number)

    sort = metric desc
    limit = 50
}

//
// Mentions
//

audited_providers -&gt; mentions {

    interval = year

    sort = observed_at desc

    limit = 200
}

//
// Relationship graph
//

pca_providers -&gt; flows {

    predicate in [
        owned_by,
        registered_agent_of,
        shares_address_with,
    ]

    depth = 2

    group_by = object_id

    metric = count()

    sort = metric desc

    threshold = 2
}

//
// Timeline
//

sanctioned -&gt; timeline {

    interval = quarter

    group_by = predicate
}

//
// Compare populations
//

compare high_billers against audited_providers {

    by = subject_id

    emit = [
        shared,
        only_left,
        only_right,
    ]

    limit = 100
}

//
// Statistical outliers
//

high_billers -&gt; outliers {

    metric = value_number

    method = zscore

    threshold = 2.5

    limit = 25
}

//
// Rendering hints
//

render {

    default_view = timeline

    color_by = topic

    allow_drilldown = true

    show_confidence = true
}</code></pre></div><p></p><p>This investigation defines a reusable population of Montana Personal Care Assistance (PCA) provider organizations and performs several analytical views over that population.</p><p>The investigation:</p><ul><li><p>Defines reusable families representing provider populations and derived subsets.</p></li><li><p>Summarizes Medicaid billing activity and organizational registrations.</p></li><li><p>Collects audit and oversight mentions from multiple public sources.</p></li><li><p>Explores ownership and organizational relationship networks.</p></li><li><p>Builds chronological timelines of audits, investigations, and sanctions.</p></li><li><p>Compares high-billing providers against those appearing in oversight reports.</p></li><li><p>Identifies statistical outliers in Medicaid billing activity.</p></li><li><p>Specifies default rendering behavior for interactive exploration.</p></li></ul><p>The result is a complete investigative workspace describing both the operational characteristics and oversight history of Montana PCA providers.</p><p>Big, I know.</p><h3>Gumlang</h3><p>Gumlang is the DSL to define facts from documents. Below is an example I use to ingest bulk SEC data.</p><p>Bulk SEC data comes with multiple files, the one I omit is pre.txt.</p><div class="highlighted_code_block" data-attrs="{&quot;language&quot;:&quot;plaintext&quot;,&quot;nodeId&quot;:&quot;58e9db5f-3a82-4d9e-b506-ea5a5479592d&quot;}" data-component-name="HighlightedCodeBlockToDOM"><pre class="shiki"><code class="language-plaintext">//Name the data sources and alias them
#{num}[num.txt]
#{sub}[sub.txt]
#{tag}[tag.txt]

// it is a fact of the measurement type name "sec_reported"
fact measurement.sec_reported {
    //$sub{name} -&gt; sub is the file, name is the field and it gets put in the subject field
    subject: company "sec_company:{$sub{cik}}" $sub{name}
    predicate: reported
    object: financial_concept "sec_concept:{$num{tag}}:{$num{version}}" $tag{tlabel}
    value_number: $num{value}
    value_unit: $num{uom}
    value_date: $num{ddate}
    props: [$num{qtrs}, $num{segments}, $num{coreg}]
    //establish where the fact came from
    provenance: [$num, $sub, $tag]

    //fields in which these documents are joined
    $num{adsh} == $sub{adsh}
    $num{tag} == $tag{tag}
    $num{version} == $tag{version}
}
</code></pre></div><p>This was a complex part and a real world example showcasing the importance of Big O.</p><p>Early versions of gumlang execution  we based on repeatedly scanning documents for joins. In essence I was doing loops in loops to scan documents. This resulted in around 35K facts within 20 minutes.</p><p>Awful timing. Nowhere near what i needed to ingest files with millions of lines. </p><p>I instead opted to perform joins by building hash indexes over lookup sources before compilation begins.  Rather than repeatedly scanning reference datasets for every input row, each lookup source is loaded once into an in-memory hash map keyed by its join fields. </p><p>During compilation, joins became constant-time hash lookups instead of repeated linear searches through source files.  This shifts the execution model from repeating work to pre-computed indexing, reducing the overall computational cost. </p><p>In the wild, this change had a ~600&#8211;700&#215; improvement in throughput without changing the overall compiler architecture.</p><p>I went from creating ~35K facts in 20 minutes to producing ~1M facts a minute. Overall throughput including all steps rose dramatically.</p><p>This isn&#8217;t the optimization ceiling, but it proves the architecture is good.</p><p>Gumlang will need to be extended to define more facts or forms in the future. Ideally I don&#8217;t want 3 DSLs. I also don&#8217;t want to introduce yaml configuration as the error surface on yaml is greater than my compiler for this use case.</p><div><hr></div><h2>Gumware</h2><p>Gumware is the gui front end, the driver seat to the system in a sense. I initially wrote one in Next.js. It worked well enough.</p><p>I ultimately didn&#8217;t want to maintain it because I found js/ts to be spaghetti in many ways. Looking at it made me irrationally frustrated. </p><p>Plus the dependency hell I found in npm and its contemporaries to be brutal. </p><p>I found my dependency graph to be a tangled web which in some cases included what I felt were intrusive telemetry. Especially with deck.gl. I fumbled around testing Godot because I wondered if a game engine would provide a better user experience.</p><p>I decided against that.</p><p>I went to slint. I then realized the target market for it may be slimmer because I&#8217;m asking for an install to desktop which has it&#8217;s own downsides.</p><p>Dioxus is where I landed. It isn&#8217;t the most mature, but serious organizations use it so I don&#8217;t have too many concerns of it just evaporating.</p><p>Gumware flows to the api which in essence is just an axum webserver which can control gumd.</p><p>I don&#8217;t have any recent pictures of it because the UI is still in flux.</p><div><hr></div><h2>Gumd </h2><p>Gumd ingests data targets. Targets can be bulk downloads. Targets can be trails of unstructured data like web pages. Right now the trails exist as a yaml file which defines a chron like job to retrieve documents. You can do one off&#8217;s too. Gumd is rust. It uses sqlite as not only a store but a FIFO like queue to send jobs.</p><p>It sends jobs to a deno playwright worker (of which there are a few). I decided I needed to integrate deno because  of playwright. </p><p>Unfortunately a lot of webpages use js. There is fantoccini in Rust, there is a chromium crate. None have the maturity of playwright. </p><p>I decided against using python because of the data chunking abilities and if I had to choose to either do Typescript or Python I choose Typescript. I also chose Deno because of the security implications around a pure nodejs implementation. Deno is more security aware. </p><p>Though I&#8217;m very aware dependencies can still hose my system. It to me seems more prudent to have deno.</p><h4>Deno Workers + Gomitm</h4><p>Deno workers are the data grabbers. They exist to grab structured and unstructured data from jobs via gumd.</p><p>Deno workers can do steps. </p><p>These steps, or &#8220;job specifications&#8221; have deno do things like click buttons, log in, go to pages to get data. </p><p>Jobs aren&#8217;t limited to single captures. This is a manual process because trying to grab webpages is a pain. Users would be encouraged to do recon through something like Caido and see what valid workflows are before drafting job specifications.</p><p>Deno workers then send data to the gomitm proxy. The proxy does a lot under the hood that I don&#8217;t need to configure.</p><p>I like the idea that the deno workers running through the proxy can block trackers among other things. </p><p>Chunking out through the gomitm proxy also allows me to stop ddosing attempts. Having gomitm also gives me a single endpoint for multiple deno workers.</p><p>You likely realized I&#8217;m using golang instead of the python mitm crate. I was using the python mitm proxy at first. Outside of again just not wanting to work with python, I felt more at home with the design and capabilities of a golang proxy over a python one.  </p><p>Eventually I will be working on an in house proxy called gumitm in Rust, but that is a ways out.</p><div><hr></div><h2>Capture Core</h2><p>When the gomitm proxy receives flows and sessions through the deno workers, it relays that data to the system&#8217;s capture core. </p><p>Capture core assembles data coming from the gomitm proxy, structured and unstructured data. </p><h3>Data here has two paths.</h3><h4>Path 1: large files</h4><p>I don&#8217;t want to spool big files to pieces on the disk. It&#8217;d be too long and ultimately dumb. So instead I stream large files into minio through .part pieces. </p><p>While I have to keep a certain amount of pieces in memory, I&#8217;m not sitting and creating a 20 million line file through pure spooling. Parting it out into minio only really works with large files as there are data size requirements. Once minio has the data, the pad then gets a letter basically giving the minio key and</p><p>&#8220;you gotta enrich this data buddy&#8221;.</p><h4>Path 2: not large files</h4><p>Files that aren&#8217;t large do get spooled in a sense in memory by getting written to a rolling warc writer. </p><p>I have written the warc implementation myself. This is an unfortunate evil as streaming single pieces of webpages into minio directly sucks and I need warcs.</p><p>I haven&#8217;t seen a good way to stream warc writing into minio. There would be coordination complexity. Ideally I keep warc sizes ~80mb, keeping full sessions together. </p><p>Capture core also tees off sessions into extraction core via an envelope message. I can have this as a parallelized process.</p><div><hr></div><h2>Extraction Core + NER/OCR</h2><p>Extraction core extracts data from unstructured data. Web pages, metadata, OCR, pdf ingestion, form ingestion. Right now form ingestion like SEC 10-K forms are yaml. The plethora of form types do present and interesting problem which gumlang somewhat fixes. In the future the form ingestion logic will likely exist as an extension of gumlang as stated above. </p><p>Forms or the push to be able to ingest arbitrary data is an interesting problem and hell. I see myself drifting into a configuration landscape I&#8217;m not thrilled about. However, hearkening back to my intro the questions I want answered unfortunately are disparate data sources. I also have a lot more I want to point the system at (threat feeds, historical campaign, etc..). Right now gumlang works on unstructured data mainly through gazetteers. On top of gazetteers I have implemented NER.</p><h3>Onnx NER and sentimental analysis</h3><p>I landed on using onnx inference model. Namely the bert base model. I needed NER initially for SEC def14a forms. Those forms are unstructured, however they are important as they are an incredible source of officer information. The need for entity extraction ended up extending far past the initial SEC forms. Entities in documents give me contextual understanding when paired with provenance and sentiment. </p><p>Sentimental analysis right now is gazetteer based, mainly. An array of words attached to document tone and confidence. I chose this route mostly because i needed some more deterministic functionality.</p><p>Last, I chose ONNX over spaCy because I didn&#8217;t want to spin up a python service where I&#8217;d need grpc and tonic. Keeping it better in the Rust ecosystem was a no brainer.</p><div><hr></div><h2>Pad</h2><p>The pad is the space where the execution of gumlang actually happens. Pad executes compiled gumlang on documents. Currently pad pieces things out to a csv, in the future it will stream batches into clickhouse directly.</p><p>Pad is central because all data runs through it for fact aggregation. Pad&#8217;s rules are basically &#8220;always produce facts even if all data sources aren&#8217;t new&#8221;. </p><p>Basically, if you get one new document in your fact set, produce new facts. Pad executes on unstructured data too, mostly based on gazetteers.</p><p>Pad performs no operations outside of the scope of fact production.</p><p>No OCR.</p><p>No NER.</p><p>It takes in data, matches provenance and writes facts based on compiled gumlang.</p><div><hr></div><h2>Clickhouse</h2><p>Clickhouse is where the analytical processes actually happen. Initially I thought maybe to put them in Rust, but it came down to having Clickhouse do what it does best.</p><h3>Base analytical points in Clickhouse</h3><h5>1. Depth</h5><p>    - Graph traversal depth. What is connected to Acme Inc.&#8221;</p><h5>2. Entropy</h5><p>    - Measurement of uncertainty or concentration. Basically to measure diversity in data. What is random?</p><h5>3. Frequency</h5><p>    - Simple counts of facts</p><h5>4. Cardinality</h5><h5>5. Temporal Density</h5><p>    - How activity changes over time</p><h5>6. Velocity</h5><p>    - Velocity, not the same of frequency in a density sense</p><h5>7. Centrality</h5><p>    - Analytical approximations like most referenced organization or most shared address, or most common officer</p><h5>8. Outliers</h5><h5>9 Correlation</h5><p>    - correlating officers to organizations to other places in sets of data I have.</p><h5>10 Confidence</h5><p>    - Weighted aggregation to denote how confident I am in certain aspects</p><h5>11. Completeness</h5><p>    - how complete an entity is in terms of its holistic interpretability</p><h5>12. Coverage</h5><p>    - The amount of evidence that supports something</p><h5>13. Information Gain</h5><p>    - does this fact/observation reduce uncertainty?</p><p>The schema in Clickhouse is on flat facts table. Ideally in the future there would be two Clickhouse instances: one analytical and one on the hot path that sync data. I landed on a single table as Clickhouse is columnar and huge join sets on it aren&#8217;t as performant. If I place everything in one place I&#8217;m better able to derive data from it quickly. Will this shoot me in the foot? Maybe. Its an unorthodox approach to the problem space, but I&#8217;m willing to experiment.</p><div><hr></div><h2>Clerk and Tweak</h2><p>Clerk and tweak both have to deal with Tantivy. Tantivy will be a multi index search engine for the data. The clerk is basically the interface to use tantivy.</p><p>Tweak basically drives the analytical pieces of Clickhouse and updates Tantivy indexes based on new information gained from the analytical processes in Clickhouse.</p><div><hr></div><h2>Snoop</h2><p>Snoop is the auditing surface for the system. Just logs and other useful information. </p><div><hr></div><h2>Conclusion</h2><p>The whole system ideally runs in a single binary composed of tasks which pass around tokio channels. So far I don&#8217;t have a reason to distribute it. I don&#8217;t want to distribute it. Parallel tasks just passing data through channels is ideal. That said there are unfortunately a few places I needed to externally containerize. It is the cost of doing business instead of a need to look sophisticated.</p><p>I have made great progress with the system so far. While I yearn to just look at data, I unfortunately built something robust. </p>]]></content:encoded></item><item><title><![CDATA[Official Data Sucks ]]></title><description><![CDATA[experience thus far with big data sets]]></description><link>https://fritzjung.substack.com/p/official-data-sucks</link><guid isPermaLink="false">https://fritzjung.substack.com/p/official-data-sucks</guid><dc:creator><![CDATA[Fritz Jung]]></dc:creator><pubDate>Wed, 01 Jul 2026 00:11:26 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!kd_5!,w_256,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F56306608-e78c-40be-8f91-8b75550f7ea3_508x508.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>This article is an update on Gumshoe. Gumshoe is an investigation platform I started building because I wasn&#8217;t pleased with answers I got writing my congressmen. The question first posed was: &#8220;if they don&#8217;t listen to me, who do they listen to?&#8221;. </p><p>I got it to the point where I was mapping geographical positions of campaign donations over temporality. It was originally built with Neo4J because it felt like the right fit, but it wasn&#8217;t a good experience for 100&#8217;s of millions of enteries. Bolt doesn&#8217;t handle that volume well. So I eventually ditched it. I needed a lot of data, and I needed the analytical database to handle it which was clickhouse. The focus on columnar data in clickhouse helps me more than the row based focus of other databases. But I grew and realized I needed to query/search all the disparate data I had. </p><p>pywb was way too tedious and arcane. It didn&#8217;t work for what I needed, and to add to that it is python to which I&#8217;m not a fan.</p><p>I started on gumpla (play on gunpla but with gumshoe). It started as a config driven system to build entities, aliases, topics, topic groups, and facts.  I build out a &#8220;pad&#8221; to join different data sets, then I built out functionality to create an insertable csv artifact that had all the components needed to have graph like functionality within clickhouse. I established an onnx ner pipeline to derive entities from unstructured data and feed them into the same pipeline.</p><p>Before my realization I was able to work with about 56M rows on my desktop. Not enterprise, but its a lot to me.</p><p>I was happy to start playing with the data until I realized how much straight up bullshit exists in official data. Not even plausible bullshit. Straight up absurd bullshit.</p><p>My first encounter was finding a $100M political donation from a committee that was null/bunk/didn&#8217;t really exist.  This committee and subsequent donation reports were from an eccentric man in a Carolina. To give context, Elon Musk donated $30M.  This man reported he donated $70M more than Elon musk from his residential address in a middle class neighborhood. So it turns out you can just file whatever number you want. With that I was intrigued by the guy and his story. He evidently not only had a penchant for making bogus committee filings and subsequent absurd donations, but he was also really interested in geothermal properties. And yes, he filed bogus bids to the bureau of land management. Its harmless, and I&#8217;m happy he has a hobby. But it really screws my numbers and faith. </p><p>So, my thoughts then were &#8220;surely the SEC has way more intergrity!&#8221;</p><p>Nope. </p><p>After ingesting the bulk num, pre, tag, sub files for the 4 quarters in 2025 I ran across another anomaly: MDB Capital Holdings apparently earning three times Apple's quarterly income.  In fact, in the SEC data MDB earn 4X what Apple did. Wow, this is interesting! Kinda..</p><p>I traced it a $419 billion dimensional XBRL fact attached to a 14-person biotech startup that raised $17 million in its IPO. The problem started to really form. I needed to stop fighting bad data and derive context that explains its meaning. MDB Capital Holdings, the numbers needed a lot of context to figure out if they are meaningless or actively misleading. This ran me down a huge rabbit hole of XBRL. I guess its an active problem. But XBRL is too niche and I&#8217;m not an economist or whatever.</p><p>Every data set I touch turned out to have absurd anomalies. Anomalies you would think would be caught and corrected. Bad assumption on my part. For all my faith that the SEC makes the suits tremble, they&#8217;re completely fine being like &#8220;Your 14 person company earned $300B more than apple? Sounds legit.&#8221;</p><p>Why fight to clean it? Cleaning it is a losing battle in not only the sense that its a fools errand to catch it all, but also that I&#8217;m losing data in the cleaning process.</p><p>All of these absurdities tell me different things about the data I&#8217;m ingesting. In the case of the FEC data it tells me I should give committee context. The SEC data, I realized I needed a lot of XBRL context that can be enriched with the additions of quarters and 10-K filings.</p><p>I spent a LOT of time writing my pipelines to ingest datasets. </p><p>That is the wrong goal. </p><p>Datasets exist in a vacuum. Numbers have meaning. Topology has meaning outside of where it is seen.</p><p>I started writing my ingestion pipelines around facts, better yet, questions. The data needed to answer those questions. </p><p>Take MDB Capital Holdings, instead of building the database around the data set it exists in, I built out what makes MDB Capital Holdings make sense. What filings make any of this make sense. What contextualizes their absurd reporting to a commission who evidently cares so little that they just lean into the bogus data.</p><p>The FEC data surrounding the $100M hotshot: what is this committee, what filings does it appear in? Easier question in this context, but it illustrates a point.</p><p>These are multi-domain questions and facts. I could tell you that Winklevoss Captial Management donated $21M over 3 days for a crypto initiative, dwarfing anyone in Delaware. But it is meaningless without the context of motivation and topology. What was the initiative? What was a temporal cousin? Who did they donate to? The best question behind it comes to what payoff that may have come from it. I&#8217;m not a rich man but I have a hard time believing anyone just burns that. </p><p>With these absurdities, provenance became first class. If I see these numbers, and I report on these numbers, people will point out the absurdity. I cannot afford to not establish provenance. Provenance establishes integrity, design, and reason. It also establishes baselines of where good data actually comes from. </p><p>Most important I started with methodology. Build around how I intend to work. I wrote down 10 questions, somewhat open ended and at face value ambitious. Building out schema and configurations around the data to derive facts to answer these questions was far easier than it was to think abstractly. A tangible path forward was birthed from understanding that my system needs to focus on making things interpretable. Giving context over whatever idea of truth I was trying to cultivate.  </p><p>Once I establish the platform around interpretability, I stopped the vigorous pruning and just took stock of the bush I was looking at.</p><p>Bullshit tells a story too, sometimes bullshit makes the smell of truth more noticeable. </p>]]></content:encoded></item><item><title><![CDATA[Gumshoe: an investigation platform and descent into madness]]></title><description><![CDATA[how something started and how its going]]></description><link>https://fritzjung.substack.com/p/gumshoe-an-investigation-platform</link><guid isPermaLink="false">https://fritzjung.substack.com/p/gumshoe-an-investigation-platform</guid><dc:creator><![CDATA[Fritz Jung]]></dc:creator><pubDate>Sun, 31 May 2026 13:43:13 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!c_13!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fafaab38c-b68f-4f47-ae80-ed37f380b879_1254x1254.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>I started writing Gumshoe a few weeks ago. Gumshoe is an investigative platform. Data agnostic, config driven, unruly, and a passion.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!c_13!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fafaab38c-b68f-4f47-ae80-ed37f380b879_1254x1254.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!c_13!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fafaab38c-b68f-4f47-ae80-ed37f380b879_1254x1254.png 424w, https://substackcdn.com/image/fetch/$s_!c_13!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fafaab38c-b68f-4f47-ae80-ed37f380b879_1254x1254.png 848w, https://substackcdn.com/image/fetch/$s_!c_13!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fafaab38c-b68f-4f47-ae80-ed37f380b879_1254x1254.png 1272w, https://substackcdn.com/image/fetch/$s_!c_13!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fafaab38c-b68f-4f47-ae80-ed37f380b879_1254x1254.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!c_13!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fafaab38c-b68f-4f47-ae80-ed37f380b879_1254x1254.png" width="1254" height="1254" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/afaab38c-b68f-4f47-ae80-ed37f380b879_1254x1254.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1254,&quot;width&quot;:1254,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:1047870,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:&quot;https://fritzjung.substack.com/i/199974227?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fafaab38c-b68f-4f47-ae80-ed37f380b879_1254x1254.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!c_13!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fafaab38c-b68f-4f47-ae80-ed37f380b879_1254x1254.png 424w, https://substackcdn.com/image/fetch/$s_!c_13!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fafaab38c-b68f-4f47-ae80-ed37f380b879_1254x1254.png 848w, https://substackcdn.com/image/fetch/$s_!c_13!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fafaab38c-b68f-4f47-ae80-ed37f380b879_1254x1254.png 1272w, https://substackcdn.com/image/fetch/$s_!c_13!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fafaab38c-b68f-4f47-ae80-ed37f380b879_1254x1254.png 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p></p><p></p><p>How it started out is that  I emailed my congress men and women about an important issue. Much to my chagrin, the response was basically &#8220;I do what I want, sorry bro&#8221;. And I thought &#8220;well they don&#8217;t listen to me, I wonder who they would listen to?&#8221;</p><p>That one thought was the catalyst to what started as a platform to map campaign finance.</p><p>Then I mapped campaign contributions (I only chose Pelosi because I needed to test a Cali dataset and I&#8217;m not clued into politics in general. Pelosi was only who I knew from California).</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!4CL0!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F608e265b-b75f-41e9-9d64-0b7acb098a62_1422x931.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!4CL0!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F608e265b-b75f-41e9-9d64-0b7acb098a62_1422x931.png 424w, https://substackcdn.com/image/fetch/$s_!4CL0!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F608e265b-b75f-41e9-9d64-0b7acb098a62_1422x931.png 848w, https://substackcdn.com/image/fetch/$s_!4CL0!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F608e265b-b75f-41e9-9d64-0b7acb098a62_1422x931.png 1272w, https://substackcdn.com/image/fetch/$s_!4CL0!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F608e265b-b75f-41e9-9d64-0b7acb098a62_1422x931.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!4CL0!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F608e265b-b75f-41e9-9d64-0b7acb098a62_1422x931.png" width="1422" height="931" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/608e265b-b75f-41e9-9d64-0b7acb098a62_1422x931.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:931,&quot;width&quot;:1422,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:255272,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://fritzjung.substack.com/i/199974227?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F608e265b-b75f-41e9-9d64-0b7acb098a62_1422x931.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!4CL0!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F608e265b-b75f-41e9-9d64-0b7acb098a62_1422x931.png 424w, https://substackcdn.com/image/fetch/$s_!4CL0!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F608e265b-b75f-41e9-9d64-0b7acb098a62_1422x931.png 848w, https://substackcdn.com/image/fetch/$s_!4CL0!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F608e265b-b75f-41e9-9d64-0b7acb098a62_1422x931.png 1272w, https://substackcdn.com/image/fetch/$s_!4CL0!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F608e265b-b75f-41e9-9d64-0b7acb098a62_1422x931.png 1456w" sizes="100vw"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p></p><p></p><p>Above is basically mapping donations to Nancy Pelosi&#8217;s campaign.</p><p>And I found odd things, like odd committee names (again, just needed Cali to test)</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!O2dt!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff36ae2f1-546e-4e0d-b44e-509f0b698aff_1602x1130.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!O2dt!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff36ae2f1-546e-4e0d-b44e-509f0b698aff_1602x1130.png 424w, https://substackcdn.com/image/fetch/$s_!O2dt!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff36ae2f1-546e-4e0d-b44e-509f0b698aff_1602x1130.png 848w, https://substackcdn.com/image/fetch/$s_!O2dt!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff36ae2f1-546e-4e0d-b44e-509f0b698aff_1602x1130.png 1272w, https://substackcdn.com/image/fetch/$s_!O2dt!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff36ae2f1-546e-4e0d-b44e-509f0b698aff_1602x1130.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!O2dt!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff36ae2f1-546e-4e0d-b44e-509f0b698aff_1602x1130.png" width="1456" height="1027" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/f36ae2f1-546e-4e0d-b44e-509f0b698aff_1602x1130.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1027,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:217999,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://fritzjung.substack.com/i/199974227?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff36ae2f1-546e-4e0d-b44e-509f0b698aff_1602x1130.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!O2dt!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff36ae2f1-546e-4e0d-b44e-509f0b698aff_1602x1130.png 424w, https://substackcdn.com/image/fetch/$s_!O2dt!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff36ae2f1-546e-4e0d-b44e-509f0b698aff_1602x1130.png 848w, https://substackcdn.com/image/fetch/$s_!O2dt!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff36ae2f1-546e-4e0d-b44e-509f0b698aff_1602x1130.png 1272w, https://substackcdn.com/image/fetch/$s_!O2dt!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff36ae2f1-546e-4e0d-b44e-509f0b698aff_1602x1130.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p></p><p>I found it exciting to work with the data. From campaign finance I learned a lot of things like:</p><ol><li><p>About 80% of the donors from states I looked at are retired/unemployed</p></li><li><p>Women who donated to Republican causes were more likely to list themselves as homemakers if out of work. Their counterparts donating to Democrat causes listed themselves as unemployed</p></li><li><p>Generally the highest donors listed themselves as unemployed</p></li><li><p>FEC data is cumbersome. They use a format from the 90s, they don&#8217;t give you headers, they give a committee master you have to link. If I didn&#8217;t know government better I&#8217;d assume they are intentionally opaque</p></li><li><p>I learned that I needed to gate keep it since I made it trivial to find and correlate PII that requires an undertaking to really searchable</p></li></ol><p>What was really cool? The outliers. The retired woman who donated almost 9K times in the last year, sometimes 30 times a day, all small amounts. I&#8217;ve found donors blowing so much money but who had a profile that made no sense. I&#8217;m a gossip girl and I love theory crafting.</p><p>I ended up getting hooked. </p><p>Little did I know, the local first work bench would bloom into something like this:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!W9iM!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Faa518738-a101-4b1e-be83-8a6156c2dde8_1536x1024.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!W9iM!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Faa518738-a101-4b1e-be83-8a6156c2dde8_1536x1024.png 424w, https://substackcdn.com/image/fetch/$s_!W9iM!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Faa518738-a101-4b1e-be83-8a6156c2dde8_1536x1024.png 848w, https://substackcdn.com/image/fetch/$s_!W9iM!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Faa518738-a101-4b1e-be83-8a6156c2dde8_1536x1024.png 1272w, https://substackcdn.com/image/fetch/$s_!W9iM!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Faa518738-a101-4b1e-be83-8a6156c2dde8_1536x1024.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!W9iM!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Faa518738-a101-4b1e-be83-8a6156c2dde8_1536x1024.png" width="1456" height="971" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/aa518738-a101-4b1e-be83-8a6156c2dde8_1536x1024.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:971,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:1549208,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://fritzjung.substack.com/i/199974227?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Faa518738-a101-4b1e-be83-8a6156c2dde8_1536x1024.png&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!W9iM!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Faa518738-a101-4b1e-be83-8a6156c2dde8_1536x1024.png 424w, https://substackcdn.com/image/fetch/$s_!W9iM!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Faa518738-a101-4b1e-be83-8a6156c2dde8_1536x1024.png 848w, https://substackcdn.com/image/fetch/$s_!W9iM!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Faa518738-a101-4b1e-be83-8a6156c2dde8_1536x1024.png 1272w, https://substackcdn.com/image/fetch/$s_!W9iM!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Faa518738-a101-4b1e-be83-8a6156c2dde8_1536x1024.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p><br>It turned into scope creep as far wiser people than me would say. </p><p>I&#8217;m 250 files and 12k lines code, 4-5 language span into a solo project. </p><p>I feel the weight of it. Every decision, every refactor, I feel it. Having castles made of sand is the tough part. Adding new functionality in a modular system? Simple. Rust for me is easy. Golang is simple because I had to learn it. Python though, is always a test of grit.</p><p>Always one more thing all the time.</p><p>The pictures above was an old version. I realized I needed to go to slint to do what I need. So yea, all that work got trashed, and yea, that front end work is hard. I stomped my feet and threw my tantrum. But I got a roadmap.</p><p>So where did I land?</p><p>Cartridge system -  a north star. </p><p>Cartridges that are pre-built for portability and visibility are central to gumshoe. Loading up 5 million line tables in neo4j and traversing connections that have complex connections is tedious. Like folding laundry. So I decided I would move data into different cartridges (or views). Typically for my use case by state, and flows in and out of the state of data points.</p><p>Provenance - the big dipper</p><p>And investigative platform needs provenance. In the old days you could just be like &#8220;trust me bro&#8221; but we&#8217;ve all gotten hoodwinked one too many times. So data sets have provenance. Web investigations are all warc driven. I&#8217;ve set up a system to collect full webpages in warcs for pywb and outbackcdx. I need to cross my t&#8217;s and dot my i&#8217;s. If I&#8217;m not squared away I look bad.</p><p>Data Agnostic - Orion&#8217;s belt</p><p>In general when I build systems I have idiosyncrasies where I have to make it as general and as extensible as possible. It&#8217;s who I am. I look at something and wonder &#8220;how can I use this one thing for as many things as I can?&#8221; The sentiment stems from laziness more than frugality or planning. I don&#8217;t want to write a lot to add to something. I don&#8217;t want to restructure everything. So my work reflects a level of effort invested into making sure I can do all those things. Sometimes an inordinate amount of effort.</p><p>Aesthetics - Venus</p><p>I like aesthetics in my GUIs. I don&#8217;t enjoy something that is painful to look at (like Python). So I&#8217;ve invested a lot of time into color. Nice colors. Colors that would make you think I had taste. Aesthetics don&#8217;t generally stop there, aesthetics to me encompass the whole experience. So I use what I make. If it&#8217;s tiring, I failed.</p><p></p><p>Last I want to talk about the ethos I kinda adopted in this process. I started reading &#8220;Scouts Mindset&#8221; and it went over a lot of what my natural neuroticism does for me: being objective about myself and the world around me. Above I wrote about outliers, things, people and places that don&#8217;t make sense in the data. That confusion is essentially my ignorance and bias in action (likely). Public data is public, sure. But not a lot of people go through the effort to correlate and map it in the ways I did. I keep the mindset that the data is just interesting. I can theory craft, sure. But it stops  at me understanding I have no conclusion to come to. As a human when I do I realized I needed to exhaust ever charitable explanation and steel man something. My world is shaped by my experience. So I need to realize people are very different from me.</p><p>Also, I realized things need guardrails sometimes. As a developer and builder of many things I often forget that I sometimes make things that are dual use. This turned out to be something I have to put some gates up on. The 99% of people would be fine, but that 1% is where we pick a whole bouquet of oopsie-daisies. </p><p> I&#8217;ve invested a lot of work into Gumshoe, this article is just my thoughts on it so far. My plan is to come on here and just walk through interesting things I&#8217;ve found. No conclusions, just data and what I&#8217;ve learned from it. Shell companies, trust sprawl, linkages to campaign finance. I&#8217;m able to explore all sorts of things with Gumshoe.</p><p>That said, once gumshoe is finished, it&#8217;ll be open the the more seasoned investigators or researchers. Hopefully what I use would be useful to small teams or a lone wolf with good gear. This started as a project of accountability. To take data that is disorganized, opaque and scattered and make it into a cohesive picture for us to really know what is happening in the world.</p>]]></content:encoded></item></channel></rss>