<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Anslem Owhofasa</title>
    <description>The latest articles on DEV Community by Anslem Owhofasa (@ace2016).</description>
    <link>https://dev.to/ace2016</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3861514%2F8c66a62e-3afd-473e-a40c-664ce51d6b68.png</url>
      <title>DEV Community: Anslem Owhofasa</title>
      <link>https://dev.to/ace2016</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/ace2016"/>
    <language>en</language>
    <item>
      <title>No server in the middle: how Tracepack moves evidence between two browser tabs</title>
      <dc:creator>Anslem Owhofasa</dc:creator>
      <pubDate>Wed, 19 Aug 2026 10:42:53 +0000</pubDate>
      <link>https://dev.to/ace2016/no-server-in-the-middle-how-tracepack-moves-evidence-between-two-browser-tabs-hpg</link>
      <guid>https://dev.to/ace2016/no-server-in-the-middle-how-tracepack-moves-evidence-between-two-browser-tabs-hpg</guid>
      <description>&lt;p&gt;&lt;em&gt;Part 2 of the Local-First Evidence series. Part 1 covered why routing sensitive exports through a third-party server is risky. This post is the mechanics: how the handoff and the hashing actually work.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Saying "it's local-first" is easy. Doing it without sacrificing reliability or integrity means solving two separate problems: how to pass structured data across browser tabs safely, and how to hash JSON so two different tools arrive at the exact same fingerprint for the exact same record.&lt;/p&gt;

&lt;p&gt;Here's how it actually works.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why not the obvious options
&lt;/h2&gt;

&lt;p&gt;A few standard patterns get ruled out before landing on a window handshake:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;A server API.&lt;/strong&gt; Routing data through an intermediate backend defeats the entire point. It recreates the exact server-side attack surface and data-retention risk the previous post was about eliminating.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;A browser extension.&lt;/strong&gt; Tracepack's original design used &lt;code&gt;externally_connectable&lt;/code&gt; inside a browser extension. That's gone now, replaced with a plain hosted page. An extension adds install friction and one more background process users have to trust before they've gotten any value from it.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;URL state (query parameters or hash fragments).&lt;/strong&gt; Fragments break once a payload grows past a few kilobytes, and worse, URL state leaks into browser history, referrer headers, and any proxy sitting in between. That's a non-starter for records containing customer PII.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;A server-mediated iframe embed.&lt;/strong&gt; Still routes customer bytes through infrastructure you have to run, secure, and pay for.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The actual mechanism: &lt;code&gt;window.open&lt;/code&gt; plus &lt;code&gt;postMessage&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;Tracepack uses a direct handshake between the source app (a help desk, an internal tool, whatever you're building) and the evidence viewer tab it opens. No server sees the payload at any point, not even Tracepack's own: the hosted app only ever serves static JavaScript.&lt;/p&gt;

&lt;p&gt;There are two versions of this handshake live at once, and which one you get depends on whether you hand-roll the &lt;code&gt;postMessage&lt;/code&gt; calls yourself or use the &lt;code&gt;@tracepack/integration&lt;/code&gt; package. Both are real, both are wired into the live receiver, they just make different tradeoffs.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The plain handshake&lt;/strong&gt; , the one you'd write by hand from the embed guide:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;+-------------------+ +-------------------+
| Source App | | Tracepack Viewer |
| (e.g. Helpdesk) | | (Hosted app) |
+---------+---------+ +---------+---------+
          | |
          | 1. window.open(tracepackUrl) |
          |---------------------------------------------&amp;gt;|
          | |
          | 2. { source: "tracepack", type: "ready" } |
          |&amp;lt;---------------------------------------------|
          | |
          | 3. { source: "tracepack-producer", |
          | type: "evidence", |
          | payload: { ... } } |
          |---------------------------------------------&amp;gt;|
          | |
          | 4. { source: "tracepack", type: "imported", |
          | projectId, evidenceCount } |
          | (best effort, may never arrive if the |
          | tab is closed before a pack is picked) |
          |&amp;lt;---------------------------------------------|

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If the payload fails validation here, there's no reply telling the source tab why. Tracepack shows the error inline on its own page, and that's the only place it shows up. Fine for a producer that just wants to fire evidence at Tracepack and doesn't need to react to failure programmatically.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Protocol v1, via&lt;/strong&gt; &lt;code&gt;@tracepack/integration&lt;/code&gt;, is a real state machine, not a looser version of the same thing:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  ready ──▶ send(handoff_id) ──┬──▶ accepted(handoff_id) ──┬──▶ imported(handoff_id, project_id, evidence_count)
                                │ └──▶ cancelled(handoff_id)
                                └──▶ rejected(handoff_id, issues[])

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Every message after &lt;code&gt;send&lt;/code&gt; carries the same &lt;code&gt;handoff_id&lt;/code&gt;, so a producer can correlate a specific submission to its outcome, not just infer success from silence. &lt;code&gt;rejected&lt;/code&gt; carries a real &lt;code&gt;issues[]&lt;/code&gt; array with a machine-readable code per problem (&lt;code&gt;UNSUPPORTED_PROTOCOL&lt;/code&gt;, &lt;code&gt;INVALID_HANDOFF&lt;/code&gt;, &lt;code&gt;PAYLOAD_TOO_LARGE&lt;/code&gt;, &lt;code&gt;DUPLICATE_HANDOFF&lt;/code&gt;, and others), so a producer can show the user something more useful than "something went wrong." Re-sending the exact same accepted handoff is idempotent, it just gets acknowledged again rather than double-imported, and trying to send a second, different handoff while one is already awaiting review gets an explicit &lt;code&gt;DUPLICATE_HANDOFF&lt;/code&gt; rejection instead of silently clobbering the first.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;On origin checking:&lt;/strong&gt; both versions already check that the reply actually came from the window that was opened (&lt;code&gt;event.source === window.opener&lt;/code&gt; on the receiving side), so a message from some other tab is ignored regardless of which protocol you're using. What differs is origin &lt;em&gt;pinning&lt;/em&gt;. &lt;code&gt;@tracepack/integration&lt;/code&gt;'s producer side records the exact origin it opened (&lt;code&gt;targetOrigin&lt;/code&gt;) and refuses to trust a reply from anywhere else, from the very first message. The receiver's very first &lt;code&gt;ready&lt;/code&gt; broadcast has to go out to &lt;code&gt;"*"&lt;/code&gt;, because it genuinely cannot know the opener's origin before the opener's own first message arrives, that's a hard limit of cross-origin &lt;code&gt;window.opener&lt;/code&gt;, not a shortcut. Every reply after that targets the real origin exactly. None of this is an allowlist of approved producer sites, there isn't one, and there's no practical way to pre-register every app that might embed this button. That's a deliberate trust boundary, not a gap.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why hashing raw JSON isn't enough
&lt;/h2&gt;

&lt;p&gt;Set the problem up before the fix: two semantically identical JSON documents can serialize to completely different bytes. Key order, whitespace, and number formatting (&lt;code&gt;1&lt;/code&gt; versus &lt;code&gt;1.0&lt;/code&gt;) all vary by library. Hash the raw bytes and the same evidence can produce two different hashes depending on which tool wrote the JSON, which breaks the entire point of hashing in the first place. Proving nothing changed only works if "nothing changed" can actually be checked.&lt;/p&gt;

&lt;h2&gt;
  
  
  RFC 8785 in one paragraph
&lt;/h2&gt;

&lt;p&gt;RFC 8785, the JSON Canonicalization Scheme, fixes this by defining one deterministic serialization: fixed key ordering, fixed number formatting, fixed string escaping. The same logical document always serializes to the same bytes, no matter which tool produced it. That's what makes &lt;code&gt;integrity.payload_hash&lt;/code&gt; meaningful. It's a hash of the canonical form, not whatever bytes happened to come off the wire.&lt;/p&gt;

&lt;h2&gt;
  
  
  The two-hash model
&lt;/h2&gt;

&lt;p&gt;A single record actually carries two separate hashes, each proving a different thing:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;content_hash&lt;/code&gt; on each attachment: a SHA-256 of the raw file bytes. Proves a specific screenshot or document wasn't altered, independent of everything else in the record.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;integrity.payload_hash&lt;/code&gt;: a SHA-256 of the whole envelope after RFC 8785 canonicalization. Proves the record as a whole (metadata, observations, attachment references) wasn't altered.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F23r9drml19ictr5qnyym.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F23r9drml19ictr5qnyym.png" alt="envelopediagram" width="799" height="465"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Together you can check a single file, the entire record, or both, and know exactly which one failed if a check ever comes back wrong.&lt;/p&gt;

&lt;h2&gt;
  
  
  What's actually proven versus what's asserted
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;source.producer_id&lt;/code&gt; and &lt;code&gt;source.producer_name&lt;/code&gt; are self-reported by whatever tool packaged the evidence. There's no signature tying them to anything. The hash proves the bytes weren't changed after export. It doesn't prove who exported them. Those are two different guarantees, and conflating them is the easiest mistake to make when writing about evidence handling.&lt;/p&gt;

&lt;p&gt;If you've seen Sigstore mentioned around this project, here's the accurate scope of it today: Sigstore protects Tracepack's own published npm and CLI release artifacts. You can verify a downloaded package came from the real repository's release workflow with &lt;code&gt;cosign verify-blob&lt;/code&gt;. It isn't used for evidence payloads or producer identity, and evidence data never goes anywhere near a public transparency log. A &lt;code&gt;tracepack-authentication&lt;/code&gt; layer for real producer identity is a documented research direction, not a shipped feature.&lt;/p&gt;

&lt;h2&gt;
  
  
  What this design doesn't solve
&lt;/h2&gt;

&lt;p&gt;Worth being honest about the edges:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;It doesn't stop someone from editing a record before hashing it. Garbage in, verifiably-consistent garbage out.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;It doesn't prove producer identity, as above.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;It depends on both tabs being genuine. A compromised or spoofed viewer tab could still claim &lt;code&gt;imported&lt;/code&gt; when nothing actually happened.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Next
&lt;/h2&gt;

&lt;p&gt;Part 3 walks through building your own "Send to Tracepack" button end to end, using &lt;code&gt;@tracepack/integration&lt;/code&gt; and protocol v1, the version worth building against.&lt;/p&gt;

&lt;p&gt;Repo: &lt;a href="https://github.com/ace2016/tracepack" rel="noopener noreferrer"&gt;https://github.com/ace2016/tracepack&lt;/a&gt; Format spec: &lt;a href="https://github.com/ace2016/tracepack/blob/main/packages/evidence-interchange/SPEC.md" rel="noopener noreferrer"&gt;https://github.com/ace2016/tracepack/blob/main/packages/evidence-interchange/SPEC.md&lt;/a&gt;&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Why exporting support tickets is a security risk and how to fix it local first</title>
      <dc:creator>Anslem Owhofasa</dc:creator>
      <pubDate>Tue, 18 Aug 2026 10:32:21 +0000</pubDate>
      <link>https://dev.to/ace2016/why-exporting-support-tickets-is-a-security-risk-and-how-to-fix-it-local-first-mai</link>
      <guid>https://dev.to/ace2016/why-exporting-support-tickets-is-a-security-risk-and-how-to-fix-it-local-first-mai</guid>
      <description>&lt;p&gt;When a critical bug, billing dispute, or compliance issue happens, someone on the team inevitably needs to export a support conversation. A security engineer might need the raw thread to investigate a report, or a customer might request an official copy of their history.&lt;/p&gt;

&lt;p&gt;In most help desks, exporting a conversation means clicking a button that generates a plain text file, a PDF, or a raw JSON dump sent through email or a third party server.&lt;/p&gt;

&lt;p&gt;That approach creates three quiet problems that most engineering teams ignore until a compliance audit forces them to deal with it.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Unchecked PII Exposure
&lt;/h2&gt;

&lt;p&gt;Support threads are full of sensitive customer data: email addresses, phone numbers, IP logs, internal staff notes, and occasionally accidental API keys or passwords pasted by users. When you export a raw thread to a third party server or email attachment, you duplicate that sensitive data across unmonitored systems.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Zero Proof of Integrity
&lt;/h2&gt;

&lt;p&gt;Standard text or PDF exports can be modified by anyone with a text editor. If a customer or an auditor asks for proof of what was said at a specific timestamp, a standard text file holds zero cryptographic proof. There is no easy way to verify if an attachment or message was altered after the fact.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. Heavy Server to Server Overhead
&lt;/h2&gt;

&lt;p&gt;Building server integrations between your help desk and external audit platforms usually requires storing API keys, maintaining webhook infrastructure, and paying for third party storage just to hold static logs.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Local First Solution: Client Side Handoffs and Canonical Hashes
&lt;/h2&gt;

&lt;p&gt;To solve this without adding heavy server infrastructure, we can shift the export workflow to be local first.&lt;/p&gt;

&lt;p&gt;Instead of sending conversation data to an external server, the help desk hands the structured payload directly to a hosted web app via a &lt;code&gt;postMessage&lt;/code&gt; handshake, the same-origin-safe way two browser tabs exchange data without either one hitting a server.&lt;/p&gt;

&lt;p&gt;Here is how that workflow operates step by step:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Structure the payload in the help desk.&lt;/strong&gt; The help desk application extracts the conversation, attachments, and basic metadata, then formats it into a standardized schema.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Generate cryptographic fingerprints.&lt;/strong&gt; Instead of relying on file names, each attachment gets hashed with SHA-256 the moment it's packaged. The whole payload is then canonicalized (RFC 8785) and hashed again as a single envelope fingerprint, so both individual files and the record as a whole can be checked for tampering later.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Perform a zero-server handoff.&lt;/strong&gt; The help desk opens the evidence viewer in a new tab and the two tabs negotiate a handshake (&lt;code&gt;ready&lt;/code&gt; → &lt;code&gt;evidence&lt;/code&gt; → &lt;code&gt;imported&lt;/code&gt;). The payload moves directly between the two tabs; Tracepack's own server only ever serves static JavaScript and never sees the evidence itself.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Review before saving.&lt;/strong&gt; Because the data lives in the browser the whole time, the person handling the export can review the record and apply redactions locally before producing a hashed, portable evidence file.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  What a Portable Evidence Schema Looks Like
&lt;/h2&gt;

&lt;p&gt;To keep evidence files consistent across different help desks and tools, the underlying export should follow a simple, deterministic schema.&lt;/p&gt;

&lt;p&gt;Here is an example of how a conversation thread converts into a portable record (the real &lt;code&gt;tracepack-evidence&lt;/code&gt; v1 format):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"schema_version"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"source"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"producer_id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"freescout-tracepack-module"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"producer_name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"FreeScout"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"producer_version"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"1.0.0"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"capture_timestamp"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2026-08-18T10:00:00Z"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"source_url"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://support.example.com/conversation/1042"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"evidence_type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"support_conversation"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"attachments"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"att_01"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"filename"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"screenshot.png"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"mime_type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"image/png"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"size"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;48213&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"content_hash"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"encoding"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"base64"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"data"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"..."&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"observations"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"obs_01"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"kind"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"message"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"label"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Customer message"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"detail"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Transaction timed out on checkout page."&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"attachment_ref"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"att_01"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"integrity"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"algorithm"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"sha256"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"canonicalization"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"RFC8785"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"payload_hash"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"..."&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A few things worth calling out about the real shape:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;attachments[]&lt;/code&gt; and &lt;code&gt;observations[]&lt;/code&gt; are kept separate rather than merged into one generic "records" list. Attachments are the files; observations are the structured claims about the conversation (a message, a note, a flagged detail).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;There are two hashes, not one: a &lt;code&gt;content_hash&lt;/code&gt; per attachment (raw file bytes), and a single &lt;code&gt;integrity.payload_hash&lt;/code&gt; for the canonicalized envelope as a whole.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;source.producer_name&lt;/code&gt; and &lt;code&gt;source.producer_id&lt;/code&gt; are self-reported by whatever tool packaged the evidence. They are not cryptographically verified, so the export UI and any copy describing it should say "reported by," not "verified."&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;By standardizing this payload, any local tool can read the thread, verify the hashes, and allow safe redactions without breaking the historical record.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why This Matters for Open Source Maintainers
&lt;/h2&gt;

&lt;p&gt;Building local first workflows keeps systems lean. Help desk maintainers do not have to worry about storing customer data on third party servers or managing complex webhook queues. The entire operation happens right in the browser, tab to tab.&lt;/p&gt;

&lt;p&gt;If you are interested in exploring how portable evidence packages work in practice, check out the open source &lt;code&gt;tracepack-evidence&lt;/code&gt; v1 specification and CLI on GitHub. I built it to help developers and support teams handle local evidence files safely, and feedback or contributions are always welcome.&lt;/p&gt;

</description>
      <category>security</category>
      <category>php</category>
      <category>opensource</category>
      <category>javascript</category>
    </item>
    <item>
      <title>Truth Technology and the Architecture of Digital Trust</title>
      <dc:creator>Anslem Owhofasa</dc:creator>
      <pubDate>Sat, 04 Apr 2026 21:48:32 +0000</pubDate>
      <link>https://dev.to/ace2016/truth-technology-and-the-architecture-of-digital-trust-3ij2</link>
      <guid>https://dev.to/ace2016/truth-technology-and-the-architecture-of-digital-trust-3ij2</guid>
      <description>&lt;p&gt;The digital economy has entered a credibility crisis.&lt;/p&gt;

&lt;p&gt;Across industries, borders, and institutions, systems now move information at extraordinary speed, yet too often fail at the more fundamental task of proving what that information actually means. Credentials can be duplicated. Professional claims can be inflated. Identity can be fragmented across platforms. In this environment, the central challenge is no longer access to data, but confidence in its validity.&lt;/p&gt;

&lt;p&gt;This is not a peripheral issue. It is one of the defining infrastructure problems of the modern technological era.&lt;/p&gt;

&lt;p&gt;My work sits precisely at this intersection. As a Data Scientist and Full-Stack Developer, I have come to view trust not as a social abstraction, but as a systems problem that must be solved through rigorous engineering. The future of digital platforms will depend on whether they can distinguish verified truth from unverified assertion, and whether they can do so at scale, across contexts, and in ways that remain usable to people.&lt;/p&gt;

&lt;p&gt;That is the premise behind Truth Technology.&lt;/p&gt;

&lt;h3&gt;
  
  
  Truth Technology as a New Category of Engineering
&lt;/h3&gt;

&lt;p&gt;Truth Technology is the design of digital systems that make verification a core function rather than an afterthought.&lt;/p&gt;

&lt;p&gt;It is a category of engineering focused on reducing uncertainty where trust matters most. In practice, this means building infrastructure that can verify human skills, validate professional credentials, and support portable forms of digital credibility. It is an approach that recognizes that modern economies do not merely require information. They require evidence that information can be trusted.&lt;/p&gt;

&lt;p&gt;This is a technical challenge with profound economic and social consequences. In a global market shaped by mobility, remote work, and digital identity, the ability to verify competence is now essential. Without reliable verification, institutions face inefficiency, individuals face exclusion, and systems become vulnerable to manipulation.&lt;/p&gt;

&lt;p&gt;My approach to this problem is grounded in applied technical depth. Data Science provides the methods for identifying patterns of integrity, inconsistency, and risk. Python supports the automation and logic needed for scalable verification workflows. SQL provides the precision and structure required for auditable data systems. Angular enables the creation of interfaces that make these systems transparent, accessible, and operational for real users. Together, these tools form the basis of an architecture that is not only technically sound, but ethically deliberate.&lt;/p&gt;

&lt;p&gt;The significance of Truth Technology is that it shifts the goal of engineering from mere digitization to trustworthy digitization.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Silicon Delta as an Emerging Centre of Global Technical Leadership
&lt;/h3&gt;

&lt;p&gt;The Silicon Delta is increasingly important in this conversation.&lt;/p&gt;

&lt;p&gt;It should not be understood merely as a regional innovation cluster, but as a rising technology hub in Nigeria with global relevance. It is a place where technical ambition, local problem-solving, and entrepreneurial discipline are converging to produce work that speaks to international standards. In a global technology landscape that increasingly values resilience, adaptability, and practical innovation, the Silicon Delta represents a meaningful source of both talent and perspective.&lt;/p&gt;

&lt;p&gt;What distinguishes this region is not only the presence of capable engineers. It is the nature of the problems being addressed. The most valuable innovations are often born in environments where trust, access, and systems integrity must be engineered carefully and intentionally. That reality creates a generation of technologists who are not simply building products, but designing responses to structural gaps in the digital economy.&lt;/p&gt;

&lt;p&gt;To contribute from the Silicon Delta is to participate in a broader redefinition of where serious technological leadership emerges. It is to demonstrate that world-class innovation is not confined to established global centres. It can also emerge from regions that understand the urgency of solving real-world infrastructure problems with precision and discipline.&lt;/p&gt;

&lt;h3&gt;
  
  
  TiiQu and the Global Verification Challenge
&lt;/h3&gt;

&lt;p&gt;My work with TiiQu is a direct expression of this philosophy.&lt;/p&gt;

&lt;p&gt;TiiQu is a global entity focused on verifying human skills and credentials, and its mission aligns closely with the future of digital trust. As labour markets become more distributed and opportunity becomes increasingly borderless, the ability to establish credible proof of human capability has become critical. Institutions need reliable verification. Professionals need portable credibility. Technology platforms need systems that can support both.&lt;/p&gt;

&lt;p&gt;This is where collaboration becomes strategically important. Verification is not a local problem with a local answer. It is a global requirement that demands interoperable systems, robust data practices, and engineering frameworks that can adapt across markets. TiiQu’s work reflects that reality, and my contribution to it has been shaped by the conviction that trust infrastructure must be built with both technical rigor and global relevance.&lt;/p&gt;

&lt;p&gt;The broader implication is clear. If we want digital systems to support real opportunity, they must be able to authenticate human value in a way that is reliable, scalable, and transparent.&lt;/p&gt;

&lt;h3&gt;
  
  
  Conclusion: Innovation Must Now Be Measured by Trustworthiness
&lt;/h3&gt;

&lt;p&gt;The next era of technological leadership will not be defined only by speed, scale, or automation. It will be defined by trustworthiness.&lt;/p&gt;

&lt;p&gt;That is why Truth Technology matters. It recognizes that the most consequential systems of the future will be those that can justify belief. They will not merely process claims. They will verify them. They will not simply store records. They will make records credible. They will not just enable participation. They will make participation meaningful.&lt;/p&gt;

&lt;p&gt;The Silicon Delta has a growing role in shaping that future. So do the engineers, scientists, and builders who understand that trust is not a secondary feature of technology. It is the foundation on which durable digital progress depends.&lt;/p&gt;

&lt;p&gt;My work is committed to that principle. Build systems that can be verified. Build platforms that deserve confidence. Build technology that restores trust in the digital economy.&lt;/p&gt;

&lt;p&gt;That is not only a technical goal. It is a standard for the future.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>webdev</category>
      <category>programming</category>
      <category>productivity</category>
    </item>
  </channel>
</rss>
