<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en-GB">
  <title>Inside the Workshop | PageTech Solutions</title>
  <subtitle>Real systems, with the reasoning left in: what the problem was, what I chose and why.</subtitle>
  <id>https://www.pagetech.solutions/workshop/</id>
  <link rel="self" type="application/atom+xml" href="https://www.pagetech.solutions/workshop/feed.xml"/>
  <link rel="alternate" type="text/html" href="https://www.pagetech.solutions/workshop/"/>
  <updated>2026-10-16T00:00:00Z</updated>
  <author><name>Jamie Page</name><uri>https://www.pagetech.solutions/about/</uri></author>
  <icon>https://www.pagetech.solutions/assets/favicon-32.png</icon>
  <rights>© PageTech Solutions Limited</rights>
  <entry>
    <title>One vulnerable package, four fixes</title>
    <link rel="alternate" type="text/html" href="https://www.pagetech.solutions/workshop/one-package-four-fixes/"/>
    <id>https://www.pagetech.solutions/workshop/one-package-four-fixes/</id>
    <published>2026-10-16T00:00:00Z</published>
    <updated>2026-10-16T00:00:00Z</updated>
    <summary>A .NET security advisory broke my builds overnight with no code change. Why the right fix differed in each of four repositories, and why audit stayed on.</summary>
  </entry>
  <entry>
    <title>Seventy-nine redundant routing rules</title>
    <link rel="alternate" type="text/html" href="https://www.pagetech.solutions/workshop/seventy-nine-routing-rules/"/>
    <id>https://www.pagetech.solutions/workshop/seventy-nine-routing-rules/</id>
    <published>2026-10-16T00:00:00Z</published>
    <updated>2026-10-16T00:00:00Z</updated>
    <summary>My hosting config was 98 bytes from its cap. 79 of its rules restated the platform, and the redirects among them were dropping ad click IDs.</summary>
  </entry>
  <entry>
    <title>A dashboard is as honest as its labels</title>
    <link rel="alternate" type="text/html" href="https://www.pagetech.solutions/workshop/dashboard-honest-labels/"/>
    <id>https://www.pagetech.solutions/workshop/dashboard-honest-labels/</id>
    <published>2026-10-09T00:00:00Z</published>
    <updated>2026-10-16T00:00:00Z</updated>
    <summary>Five ways my own dashboard misled me, and a contact form that took 146 enquiries and accepted 3. Why every figure needs a label saying what it counts.</summary>
  </entry>
  <entry>
    <title>A green health check isn’t a deployment</title>
    <link rel="alternate" type="text/html" href="https://www.pagetech.solutions/workshop/green-health-check/"/>
    <id>https://www.pagetech.solutions/workshop/green-health-check/</id>
    <published>2026-10-09T00:00:00Z</published>
    <updated>2026-10-16T00:00:00Z</updated>
    <summary>Three releases where the pipeline was wrong about production, and why deployment success, service health and build identity are separate claims.</summary>
  </entry>
  <entry>
    <title>Why only 5 of 62 invoices matched</title>
    <link rel="alternate" type="text/html" href="https://www.pagetech.solutions/workshop/invoice-matching/"/>
    <id>https://www.pagetech.solutions/workshop/invoice-matching/</id>
    <published>2026-10-09T00:00:00Z</published>
    <updated>2026-10-16T00:00:00Z</updated>
    <summary>An invoice matcher that matched 5 of 62. A regex that read a heading as a reference, a repair that swapped one false value for another, and silent failures.</summary>
  </entry>
  <entry>
    <title>The morning email that went quiet</title>
    <link rel="alternate" type="text/html" href="https://www.pagetech.solutions/workshop/quiet-morning-email/"/>
    <id>https://www.pagetech.solutions/workshop/quiet-morning-email/</id>
    <published>2026-10-09T00:00:00Z</published>
    <updated>2026-10-16T00:00:00Z</updated>
    <summary>For a scheduled email, silence is the failure, and nothing alerts on silence. Five quiet failures of a twice-daily digest, and what notices them now.</summary>
  </entry>
  <entry>
    <title>Shipping an internal app to my phone</title>
    <link rel="alternate" type="text/html" href="https://www.pagetech.solutions/workshop/shipping-the-app/"/>
    <id>https://www.pagetech.solutions/workshop/shipping-the-app/</id>
    <published>2026-10-09T00:00:00Z</published>
    <updated>2026-10-16T00:00:00Z</updated>
    <summary>Roughly half the commits behind a small internal app went on packaging, signing, distribution and sign-in. Five failures that came after a green build.</summary>
  </entry>
  <entry>
    <title>Six weeks of ‘done’ that did nothing</title>
    <link rel="alternate" type="text/html" href="https://www.pagetech.solutions/workshop/six-weeks-of-done/"/>
    <id>https://www.pagetech.solutions/workshop/six-weeks-of-done/</id>
    <published>2026-10-09T00:00:00Z</published>
    <updated>2026-10-16T00:00:00Z</updated>
    <summary>A daily contact sync logged ‘done’ for six weeks while a missing permission refused every read. Why a refusal must fail the run, not pass as an empty mailbox.</summary>
  </entry>
  <entry>
    <title>Proving you honoured an unsubscribe</title>
    <link rel="alternate" type="text/html" href="https://www.pagetech.solutions/workshop/unsubscribe-ledger/"/>
    <id>https://www.pagetech.solutions/workshop/unsubscribe-ledger/</id>
    <published>2026-09-11T00:00:00Z</published>
    <updated>2026-10-16T00:00:00Z</updated>
    <summary>Every sending platform keeps its own list, and the obligation stays with you when you move. A suppression ledger you own, and the permissions behind it.</summary>
  </entry>
  <entry>
    <title>Deleting the last connection string</title>
    <link rel="alternate" type="text/html" href="https://www.pagetech.solutions/workshop/deleting-the-last-connection-string/"/>
    <id>https://www.pagetech.solutions/workshop/deleting-the-last-connection-string/</id>
    <published>2026-09-07T00:00:00Z</published>
    <updated>2026-10-16T00:00:00Z</updated>
    <summary>Removing long-lived keys from four services in favour of managed identity. The code change is trivial; everything around it is where the time goes.</summary>
  </entry>
  <entry>
    <title>A Windows service for one firewall rule</title>
    <link rel="alternate" type="text/html" href="https://www.pagetech.solutions/workshop/firewall-sync-service/"/>
    <id>https://www.pagetech.solutions/workshop/firewall-sync-service/</id>
    <published>2026-09-06T00:00:00Z</published>
    <updated>2026-10-16T00:00:00Z</updated>
    <summary>A dynamic IP against a locked-down key vault and database. Why a script was the wrong shape, and the debounce race that made the service report itself healthy.</summary>
  </entry>
  <entry>
    <title>Three identity providers, one flow</title>
    <link rel="alternate" type="text/html" href="https://www.pagetech.solutions/workshop/oauth-integration/"/>
    <id>https://www.pagetech.solutions/workshop/oauth-integration/</id>
    <published>2026-09-04T00:00:00Z</published>
    <updated>2026-10-16T00:00:00Z</updated>
    <summary>Adding a second sign-in provider is where verification systems go wrong silently. Why the fix was structural, and why the host refuses to start.</summary>
  </entry>
  <entry>
    <title>Bulk-editing a live mailbox safely</title>
    <link rel="alternate" type="text/html" href="https://www.pagetech.solutions/workshop/bulk-editing-a-live-mailbox/"/>
    <id>https://www.pagetech.solutions/workshop/bulk-editing-a-live-mailbox/</id>
    <published>2026-09-02T00:00:00Z</published>
    <updated>2026-10-16T00:00:00Z</updated>
    <summary>Preview mode before apply mode, a safety cap, and going live only on an explicit go-ahead. Plus what the low-code platform charged for the privilege.</summary>
  </entry>
  <entry>
    <title>The build agent I killed, then rebuilt</title>
    <link rel="alternate" type="text/html" href="https://www.pagetech.solutions/workshop/self-hosted-build-agent/"/>
    <id>https://www.pagetech.solutions/workshop/self-hosted-build-agent/</id>
    <published>2026-09-02T00:00:00Z</published>
    <updated>2026-10-16T00:00:00Z</updated>
    <summary>Eight of twenty-six jobs failed and the VM was deleted after 32 hours. What the failures actually said, and what changed when it was rebuilt four months later.</summary>
  </entry>
  <entry>
    <title>Fifteen API routes that never existed</title>
    <link rel="alternate" type="text/html" href="https://www.pagetech.solutions/workshop/api-routes-that-never-existed/"/>
    <id>https://www.pagetech.solutions/workshop/api-routes-that-never-existed/</id>
    <published>2026-08-31T00:00:00Z</published>
    <updated>2026-10-16T00:00:00Z</updated>
    <summary>A proxy with 170 routes, fifteen of which pointed at endpoints that do not exist. Why nothing caught them, and the two related failures alongside.</summary>
  </entry>
  <entry>
    <title>Azure costs: more asleep than awake</title>
    <link rel="alternate" type="text/html" href="https://www.pagetech.solutions/workshop/azure-cost-reductions/"/>
    <id>https://www.pagetech.solutions/workshop/azure-cost-reductions/</id>
    <published>2026-08-30T00:00:00Z</published>
    <updated>2026-10-16T00:00:00Z</updated>
    <summary>Bursty compliance work on an always-on host. Why scale-to-zero was the last step and not the first, and what the move actually cost and saved.</summary>
  </entry>
  <entry>
    <title>A cleanup job that came for production</title>
    <link rel="alternate" type="text/html" href="https://www.pagetech.solutions/workshop/acr-purge-fail-closed/"/>
    <id>https://www.pagetech.solutions/workshop/acr-purge-fail-closed/</id>
    <published>2026-08-28T00:00:00Z</published>
    <updated>2026-10-16T00:00:00Z</updated>
    <summary>A scheduled registry purge deleted the image production was running on. Why the obvious fix was not enough, and why deletion jobs have to fail closed.</summary>
  </entry>
  <entry>
    <title>Verifying referees without trusting me</title>
    <link rel="alternate" type="text/html" href="https://www.pagetech.solutions/workshop/testimonial-verification/"/>
    <id>https://www.pagetech.solutions/workshop/testimonial-verification/</id>
    <published>2026-08-25T00:00:00Z</published>
    <updated>2026-10-16T00:00:00Z</updated>
    <summary>Verifying a referee's identity without letting that imply approval. Two records kept separate, two levels, and only one of them public.</summary>
  </entry>
  <entry>
    <title>Tools an AI agent can call</title>
    <link rel="alternate" type="text/html" href="https://www.pagetech.solutions/workshop/webmcp/"/>
    <id>https://www.pagetech.solutions/workshop/webmcp/</id>
    <published>2026-08-18T00:00:00Z</published>
    <updated>2026-10-16T00:00:00Z</updated>
    <summary>The tools an AI agent can call on this site instead of scraping it: availability, rates, services, the FAQ and a staged contact enquiry. 100% remote.</summary>
  </entry>
  <entry>
    <title>How this site actually works</title>
    <link rel="alternate" type="text/html" href="https://www.pagetech.solutions/workshop/how-this-site-works/"/>
    <id>https://www.pagetech.solutions/workshop/how-this-site-works/</id>
    <published>2026-08-09T00:00:00Z</published>
    <updated>2026-10-16T00:00:00Z</updated>
    <summary>Two walk-throughs of this site's own machinery: what happens when you press send on the contact form, failure paths included, and what an AI agent sees.</summary>
  </entry>
  <entry>
    <title>Reading your DMARC and TLS-RPT reports</title>
    <link rel="alternate" type="text/html" href="https://www.pagetech.solutions/workshop/email-authentication-reports/"/>
    <id>https://www.pagetech.solutions/workshop/email-authentication-reports/</id>
    <published>2026-06-23T00:00:00Z</published>
    <updated>2026-10-16T00:00:00Z</updated>
    <summary>DMARC and TLS-RPT reports arrive daily and almost nobody reads them. Ingesting them from the mailbox they already land in, and why the DNS half mattered more.</summary>
  </entry>
</feed>
