<?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: PrestonCole1111</title>
    <description>The latest articles on DEV Community by PrestonCole1111 (@prestoncole1111).</description>
    <link>https://dev.to/prestoncole1111</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%2F4065035%2F9b6134c3-e9e2-4114-b9f4-c38f7a3104e3.png</url>
      <title>DEV Community: PrestonCole1111</title>
      <link>https://dev.to/prestoncole1111</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/prestoncole1111"/>
    <language>en</language>
    <item>
      <title>One API Key, Many Safety Surfaces: A Structured Model Architecture</title>
      <dc:creator>PrestonCole1111</dc:creator>
      <pubDate>Fri, 07 Aug 2026 00:47:27 +0000</pubDate>
      <link>https://dev.to/prestoncole1111/one-api-key-many-safety-surfaces-a-structured-model-architecture-7o0</link>
      <guid>https://dev.to/prestoncole1111/one-api-key-many-safety-surfaces-a-structured-model-architecture-7o0</guid>
      <description>&lt;p&gt;The operational constraint is publication, not inference: every surface needs a defensible answer about whether content may become visible. &lt;strong&gt;Short answer: put text and image moderation behind one server-side policy gateway, keep the API key there, and make a versioned decision record — rather than a model response — the contract used by chat, comments, avatars, and marketplace uploads.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;That distinction matters. A single credential can simplify access, but it can't make four product surfaces share the same latency budget, release rule, or consequence for uncertainty. The smallest architecture worth shipping has one input envelope, one structured evidence shape, surface-specific policy, and explicit pending states.&lt;/p&gt;

&lt;p&gt;Start there.&lt;/p&gt;

&lt;h2&gt;
  
  
  How should text and image moderation cover chat, comments, avatars, and uploads?
&lt;/h2&gt;

&lt;p&gt;Treat the moderation gateway as a narrow internal boundary. Product handlers send it an immutable content reference, a content hash, the surface, the media kind, and the current policy version. The gateway owns authentication and converts an external or self-hosted check into a stable evidence record. A policy function then maps that evidence to an application action such as &lt;code&gt;allow&lt;/code&gt;, &lt;code&gt;hold&lt;/code&gt;, or &lt;code&gt;reject&lt;/code&gt;. Credentials never reach a browser or mobile client.&lt;/p&gt;

&lt;p&gt;The important split is between evidence and action. A model can return category signals in structured output, but those signals don't know whether the item is a private message, a public comment, an avatar, or a seller's listing photo. The application does. A borderline signal might place a public upload in review while a different surface follows a different, evaluated rule. That isn't inconsistency; it is policy expressed where the business context exists.&lt;/p&gt;

&lt;p&gt;Calling the checker directly from every request handler looks shorter in a notebook. It also copies schema parsing, credential access, timeout behavior, and policy mapping into unrelated code paths. Once those copies drift, a policy replay no longer answers the question you care about: “What would the current rules do to the same accepted bytes?” A gateway avoids that drift without pretending every request must be synchronous.&lt;/p&gt;

&lt;p&gt;One API key is therefore an implementation detail, not the architecture. Keep it in a secret store available only to the adapter, rotate it without changing product clients, and attribute each request to an internal surface and resource. If different modalities or residency requirements later demand separate checkers, the stable envelope and decision record can remain in place while the adapter changes underneath.&lt;/p&gt;

&lt;h2&gt;
  
  
  Make the decision record replayable
&lt;/h2&gt;

&lt;p&gt;I want the first notebook experiment to produce the same kind of artifact that the production replay harness will inspect. A Boolean &lt;code&gt;flagged&lt;/code&gt; field is too weak. It loses the policy version, reason codes, input identity, and the distinction between “the checker found no signal” and “no valid decision exists.” Those omissions show up later as irreproducible appeals and misleading evals.&lt;/p&gt;

&lt;p&gt;A compact contract is enough. Store the resource ID and content hash, not an arbitrary mutable URL. Record the surface and media kind. Keep the checker evidence separate from the final action, attach a policy version, and give each attempt its own identifier. Downstream publication code should read the action and decision state, never raw vendor categories.&lt;/p&gt;

&lt;p&gt;Here is a focused Python shape. The protocol deliberately says nothing about a particular model or service, so a notebook stub, a hosted adapter, and an internally served checker can all feed the same policy function.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;dataclasses&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;dataclass&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;enum&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;StrEnum&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;typing&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Protocol&lt;/span&gt;


&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Action&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;StrEnum&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;ALLOW&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;allow&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="n"&gt;HOLD&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;hold&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="n"&gt;REJECT&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;reject&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;


&lt;span class="nd"&gt;@dataclass&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;frozen&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ContentEnvelope&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;resource_id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;
    &lt;span class="n"&gt;content_hash&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;
    &lt;span class="n"&gt;surface&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;
    &lt;span class="n"&gt;media_kind&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;
    &lt;span class="n"&gt;policy_version&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;


&lt;span class="nd"&gt;@dataclass&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;frozen&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Evidence&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;reason_codes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;tuple&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;...]&lt;/span&gt;
    &lt;span class="n"&gt;scores&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;dict&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;float&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;


&lt;span class="nd"&gt;@dataclass&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;frozen&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Decision&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;envelope&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;ContentEnvelope&lt;/span&gt;
    &lt;span class="n"&gt;action&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Action&lt;/span&gt;
    &lt;span class="n"&gt;reason_codes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;tuple&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;...]&lt;/span&gt;


&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Checker&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Protocol&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;inspect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;envelope&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;ContentEnvelope&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;Evidence&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="bp"&gt;...&lt;/span&gt;


&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;decide&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;checker&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Checker&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;envelope&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;ContentEnvelope&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;Decision&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;evidence&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;checker&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;inspect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;envelope&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;action&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Action&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;HOLD&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;evidence&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;reason_codes&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="n"&gt;Action&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ALLOW&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nc"&gt;Decision&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;envelope&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;envelope&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;action&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;action&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;reason_codes&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;evidence&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;reason_codes&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The mapping is intentionally conservative sample code, not a universal safety policy. Real mappings belong in a versioned rule table backed by labeled fixtures for each surface. The adapter should reject malformed structured output instead of filling missing fields with guesses. A missing decision is an operational state, not permission to publish.&lt;/p&gt;

&lt;p&gt;Idempotency belongs in this contract too. Use the resource identity, accepted-content hash, and policy version as the logical moderation key. A worker may retry an attempt, but it should converge on one current decision for that exact content and policy. If an avatar is replaced, its hash changes and it earns a new decision; if the same job is delivered twice, it doesn't create two review cases.&lt;/p&gt;

&lt;p&gt;This is the notebook-to-prod move I care about most: preserve the question being evaluated. A quick experiment that returns attractive JSON but can't be replayed against immutable inputs has proved syntax, not an operating model.&lt;/p&gt;

&lt;h2&gt;
  
  
  How can delivery paths differ without splitting the policy boundary?
&lt;/h2&gt;

&lt;p&gt;Comments and chat messages often arrive as small text requests. Image uploads have a different ingestion problem: the server must accept bytes, validate the allowed format and size, decode them under resource limits, and create the normalized representation that will actually be inspected. The public Sharp documentation is a useful catalogue of image-processing operations for Node pipelines. In a Python service I would choose an appropriate Python image stack, but the architectural rule stays the same — moderation receives a server-accepted artifact, not a client-declared type or an untrusted remote location.&lt;/p&gt;

&lt;p&gt;Uploads naturally fit a state machine. Create the resource as &lt;code&gt;pending&lt;/code&gt;, persist its immutable identity, enqueue moderation, and move it to a visible or review state only after policy consumes a valid decision. Keep the original away from public delivery while it is pending. The UI can show progress, but it can't promote the asset by declaring success locally.&lt;/p&gt;

&lt;p&gt;Fast text feels different. Some chat designs moderate before fan-out; others let the sender see a private pending representation while public delivery waits. Server-Sent Events can carry status changes from the server to a browser over a one-way connection using &lt;code&gt;EventSource&lt;/code&gt;, as MDN documents. SSE changes notification delivery, not authority: the server still owns the publication transition, and clients should be able to reconnect and fetch the current state rather than infer it from a missed event.&lt;/p&gt;

&lt;p&gt;Don't hide the state.&lt;/p&gt;

&lt;p&gt;The simple synchronous path is attractive when its measured latency fits the product budget and the content can remain unpublished until the response arrives. A queue is a better fit when decoding, inspection, or human review can exceed that budget. Both paths can call the same adapter and policy code. Forcing them into one transport merely to preserve a one-box diagram creates coupling where none is useful.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Concern&lt;/th&gt;
&lt;th&gt;Synchronous request&lt;/th&gt;
&lt;th&gt;Queued job&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Best fit&lt;/td&gt;
&lt;td&gt;Small inputs within the measured request budget&lt;/td&gt;
&lt;td&gt;Decode-heavy media or review workflows&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Publication&lt;/td&gt;
&lt;td&gt;Wait for a valid decision&lt;/td&gt;
&lt;td&gt;Remain pending until a valid decision&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Retry identity&lt;/td&gt;
&lt;td&gt;Resource, hash, and policy version&lt;/td&gt;
&lt;td&gt;Resource, hash, and policy version&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Client update&lt;/td&gt;
&lt;td&gt;Normal response&lt;/td&gt;
&lt;td&gt;State fetch or server event&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Failure handling also needs an explicit rule. Invalid media should stop at ingestion. Invalid structured output should stop at the adapter. A timed-out or interrupted attempt should leave the resource pending and schedule an idempotent retry or review according to policy; it must not silently become &lt;code&gt;allow&lt;/code&gt;. Log enough metadata to distinguish those paths without placing sensitive user content in general application logs.&lt;/p&gt;

&lt;h2&gt;
  
  
  Let evals choose thresholds and topology
&lt;/h2&gt;

&lt;p&gt;The evaluation set should be organized around product decisions, not generic model categories. Build it from content you are permitted to use, label the expected application action, and retain the rationale. Include ordinary content that resembles prohibited material, quoted or reclaimed language, multilingual examples relevant to the audience, screenshots containing text, difficult crops, duplicate images, and media that fails ingestion. Split results by chat, comments, avatars, and listings because an aggregate score can hide a costly false-reject pattern on one surface.&lt;/p&gt;

&lt;p&gt;Then measure the whole policy path. I track false allows, false rejects, hold rate, reviewer disagreement, schema-valid response rate, end-to-end latency, pending age, duplicate-job rate, and cost per decided item. For a chat model used as a classifier, I also track input and output tokens by policy version; prompt growth is an architecture change when it affects latency and spend. Request counts alone won't expose repeated context or retries.&lt;/p&gt;

&lt;p&gt;The experiment sequence is straightforward, but this is where I spend the most care. Freeze an evaluation snapshot, run candidate checkers through the adapter, and apply the exact policy mapping intended for production. Compare final actions, not just model scores. For every disagreement, inspect the accepted input representation, parsed evidence, policy version, and expected action together; otherwise a decoding difference can masquerade as a model difference, or a rule-table change can look like a classifier regression. Next, shadow the candidate on live-shaped traffic that may legally be evaluated without letting it control publication. Replay the frozen fixtures after any prompt, model, preprocessing, schema, or rule change, and report results by surface as well as in aggregate. A notebook can make two candidates look equivalent on a handful of clean examples, while this harness exposes whether one creates an impractical review queue for avatars or misses a class of public comments. There is genuine uncertainty here: I'm not sure a useful universal latency target exists across private chat and public marketplace media because reviewer coverage, audience exposure, and product expectations determine it. Your mileage may vary. The evidence that resolves the choice is a per-surface latency distribution paired with abandonment, pending age, and safety outcomes — not a single average copied from another system.&lt;/p&gt;

&lt;p&gt;Cost belongs in the eval harness, but it shouldn't lead the design. Count attempts, bytes processed, and model tokens where applicable. A shared account may make usage reporting easier, yet it can also hide which surface is driving load unless every request carries internal attribution. Budget alarms should use that attribution and policy version so a prompt edit or upload surge is visible before the monthly total becomes the first signal.&lt;/p&gt;

&lt;h2&gt;
  
  
  Know when the simplest gateway is the wrong choice
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;The catch is that one checker behind one API key is not suitable when your measured requirements demand independent data residency, materially different modality performance, separate failure domains, or tighter control over model serving.&lt;/strong&gt; Keep the common application contract, but use specialized adapters when the eval set shows that the added operational path buys a necessary safety or compliance outcome.&lt;/p&gt;

&lt;p&gt;A self-hosted checker can offer control over deployment and data handling, while making the team responsible for capacity, updates, monitoring, and repeated evaluation. An externally operated checker moves some serving work outside the team, while adding a dependency whose retention, access, and regional behavior need review. A general chat model with structured output can speed an experiment, but its schema conformance, prompt sensitivity, token use, and decision quality still have to earn production traffic. None of these options removes policy ownership.&lt;/p&gt;

&lt;p&gt;Human review is another topology decision. A &lt;code&gt;hold&lt;/code&gt; action without reviewer staffing is only a growing queue. Measure queue age and appeal reversals, define who may view sensitive material, and make policy changes replayable before rollout. Sample allowed content as well as held or rejected content under an authorized review process; looking only at positive signals cannot estimate false allows.&lt;/p&gt;

&lt;p&gt;Before copying this design, measure three things in your own system: the action-quality trade-off per surface, the time content can safely remain pending, and the operational burden of each additional checker. The right endpoint is the smallest architecture that meets those measured constraints. It may use one credential or several. The durable part is the evidence boundary, versioned policy, and publication state machine.&lt;/p&gt;

&lt;h2&gt;
  
  
  References
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events/Using_server-sent_events" rel="noopener noreferrer"&gt;https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events/Using_server-sent_events&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://sharp.pixelplumbing.com" rel="noopener noreferrer"&gt;https://sharp.pixelplumbing.com&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Further reading
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events/Using_server-sent_events" rel="noopener noreferrer"&gt;https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events/Using_server-sent_events&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://sharp.pixelplumbing.com" rel="noopener noreferrer"&gt;https://sharp.pixelplumbing.com&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>moderation</category>
      <category>python</category>
      <category>architecture</category>
    </item>
  </channel>
</rss>
