verae-mcp-timestamping-server/docs/html/architecture.html
George Lambert 840755c84a docs: HTML and PDF set plus optional CORS
WhatToChange: recommended-changes/2026-09-21-docs-and-cors/
  What-to-Change.md
  What-to-Change-To.md
  How-to-implement-the-changes.md

What was actually done:
- Markdown, HTML, and PDF for standards, architecture, API, and the operator guide.
- README points at scripts/build-docs.sh.
- VERAE_MCP_CORS=1 enables CORS and JSON responses on the Streamable HTTP app.

What was not done:
- (none)
2026-09-21 14:13:07 -04:00

95 lines
3.2 KiB
HTML

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta charset="utf-8" />
<meta name="generator" content="pandoc" />
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes" />
<title>architecture</title>
<style>
/* Default styles provided by pandoc.
** See https://pandoc.org/MANUAL.html#variables-for-html for config info.
*/
code{white-space: pre-wrap;}
span.smallcaps{font-variant: small-caps;}
div.columns{display: flex; gap: min(4vw, 1.5em);}
div.column{flex: auto; overflow-x: auto;}
div.hanging-indent{margin-left: 1.5em; text-indent: -1.5em;}
/* The extra [class] is a hack that increases specificity enough to
override a similar rule in reveal.js */
ul.task-list[class]{list-style: none;}
ul.task-list li input[type="checkbox"] {
font-size: inherit;
width: 0.8em;
margin: 0 0.8em 0.2em -1.6em;
vertical-align: middle;
}
.display.math{display: block; text-align: center; margin: 0.5rem auto;}
</style>
<link rel="stylesheet" href="style.css" />
</head>
<body>
<header id="title-block-header">
<h1 class="title">architecture</h1>
</header>
<h1 id="architecture">Architecture</h1>
<h2 id="flow">Flow</h2>
<ol type="1">
<li>An MCP client calls <code>stamp</code>, <code>verify</code>, or
<code>hash_report</code>.</li>
<li><code>RoutingLedger</code> sends <code>scope=global</code> to
<code>GlobalLedger</code> and every other scope to
<code>FileLedger</code>.</li>
<li><code>FileLedger</code> keeps an idempotent JSON list. The same
digest, org, and scope returns the existing receipt.</li>
<li><code>GlobalClient</code> posts the digest to VeraeTime and, when
the body has no certificate yet, polls
<code>/api/status/{jobId}</code>.</li>
<li><code>verify</code> with <code>want_scope=global</code> posts
<code>{ "certificate": "&lt;id&gt;" }</code> to
<code>/api/verify</code>. Otherwise it checks the local file first, then
VeraeTime.</li>
</ol>
<h2 id="modules">Modules</h2>
<table>
<colgroup>
<col style="width: 50%" />
<col style="width: 50%" />
</colgroup>
<thead>
<tr>
<th>Module</th>
<th>Role</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>server.py</code></td>
<td>MCP tools and process entry</td>
</tr>
<tr>
<td><code>ledger.py</code></td>
<td>Receipt model, memory ledger, file ledger, router</td>
</tr>
<tr>
<td><code>global_client.py</code></td>
<td>VeraeTime HTTPS client; blocking I/O runs in a worker thread</td>
</tr>
<tr>
<td><code>nats_ledger.py</code></td>
<td>Optional leaf <code>locald</code> client</td>
</tr>
</tbody>
</table>
<h2 id="idempotency">Idempotency</h2>
<p>Local stamps are idempotent per digest + org + scope. Global stamps
send <code>restamp: false</code> and <code>wait: true</code>. VeraeTime
may return the same certificate for the same digest. This server does
not cache global receipts in the local file.</p>
<h2 id="what-this-process-is-not">What this process is not</h2>
<p>It does not replace <code>verae-timestamp</code> /
<code>locald</code>. It does not write JetStream. It does not store
document bytes. Memory ledger exists for tests and for
<code>mcp dev</code> when a caller injects it. <code>main()</code>
always builds <code>RoutingLedger</code>.</p>
</body>
</html>