<?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: Adrian M. Peticila</title>
    <description>The latest articles on DEV Community by Adrian M. Peticila (@adrian_m_peticila).</description>
    <link>https://dev.to/adrian_m_peticila</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%2F4023987%2Fd612ce0e-229b-43bb-9592-1b922c36ff01.png</url>
      <title>DEV Community: Adrian M. Peticila</title>
      <link>https://dev.to/adrian_m_peticila</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/adrian_m_peticila"/>
    <language>en</language>
    <item>
      <title>The Cadence Gate: make the model prove it wrote like a human</title>
      <dc:creator>Adrian M. Peticila</dc:creator>
      <pubDate>Thu, 05 Nov 2026 12:47:52 +0000</pubDate>
      <link>https://dev.to/adrian_m_peticila/the-cadence-gate-make-the-model-prove-it-wrote-like-a-human-268p</link>
      <guid>https://dev.to/adrian_m_peticila/the-cadence-gate-make-the-model-prove-it-wrote-like-a-human-268p</guid>
      <description>&lt;p&gt;Every style prompt ends the same way. "Write naturally. Vary sentence length. Avoid corporate language." The model agrees, writes 600 words, and ships the same flat rhythm as the last run.&lt;/p&gt;

&lt;p&gt;The prompt is a request. Nobody checks the answer.&lt;/p&gt;

&lt;p&gt;A gate is different. It reads the file after the model writes it, computes a number, and fails the check when the number misses the floor. The model can still write badly. It cannot do it silently.&lt;/p&gt;

&lt;h2&gt;
  
  
  One file, no network
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;grai-gate&lt;/code&gt; is a single Python file with no dependencies outside the standard library. It imports &lt;code&gt;re&lt;/code&gt;, &lt;code&gt;sys&lt;/code&gt;, &lt;code&gt;json&lt;/code&gt; and &lt;code&gt;math&lt;/code&gt;. It never opens a socket, never reads an API key, never writes a cache file.&lt;/p&gt;

&lt;p&gt;It runs in three places:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A command line: &lt;code&gt;pipx run grai-gate README.md&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;A pre-commit hook, before the commit lands.&lt;/li&gt;
&lt;li&gt;A GitHub Action, on the pull request.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The analyzer is the same in all three. Only the wrapper changes.&lt;/p&gt;

&lt;h2&gt;
  
  
  What it measures
&lt;/h2&gt;

&lt;p&gt;The core metric is sentence-length burstiness:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;CV = standard deviation of words per sentence / mean words per sentence
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A draft that alternates a 6-word line with a 30-word explanation gets a high CV. A draft where every sentence runs 14 to 18 words gets a low one.&lt;/p&gt;

&lt;p&gt;The thresholds come from a 134,522-post study:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Band&lt;/th&gt;
&lt;th&gt;CV&lt;/th&gt;
&lt;th&gt;Meaning&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Flat&lt;/td&gt;
&lt;td&gt;under 0.32&lt;/td&gt;
&lt;td&gt;Hard flag, the draft fails&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Warning&lt;/td&gt;
&lt;td&gt;0.32 to 0.35&lt;/td&gt;
&lt;td&gt;Hard flag&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Borderline&lt;/td&gt;
&lt;td&gt;0.35 to 0.40&lt;/td&gt;
&lt;td&gt;Soft flag, three points&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Human&lt;/td&gt;
&lt;td&gt;0.40 and above&lt;/td&gt;
&lt;td&gt;No cadence flag&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The gate needs at least four sentences and a mean length of four words before it computes a CV. A three-line stub has no measurable rhythm, so the gate stays quiet instead of inventing one.&lt;/p&gt;

&lt;h2&gt;
  
  
  The structural checks
&lt;/h2&gt;

&lt;p&gt;Vocabulary lists age fast. Structure changes slowly, so the gate checks structure.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Check&lt;/th&gt;
&lt;th&gt;What it catches&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Flat cadence&lt;/td&gt;
&lt;td&gt;CV under 0.32&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Dash punctuation&lt;/td&gt;
&lt;td&gt;Em dashes, en dashes, double hyphens used as punctuation&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Opening formula&lt;/td&gt;
&lt;td&gt;"Here is why" at the start of a sentence&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Contrastive negation&lt;/td&gt;
&lt;td&gt;"Not X, but Y" used as a fake distinction&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Arrow cascade&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;-&amp;gt;&lt;/code&gt;, &lt;code&gt;=&amp;gt;&lt;/code&gt;, arrows used as bullets&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Triadic padding&lt;/td&gt;
&lt;td&gt;Three bullets with near-identical sentence lengths&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Weak closer&lt;/td&gt;
&lt;td&gt;"Thoughts?" and similar&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Dead lexicon&lt;/td&gt;
&lt;td&gt;A short list of words that signal template prose&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The dead lexicon is deliberately small. A long list produces false positives on technical writing, and a false positive teaches the team to skip the gate.&lt;/p&gt;

&lt;h2&gt;
  
  
  How the score works
&lt;/h2&gt;

&lt;p&gt;The score starts at 100. Each flag subtracts a fixed penalty. A hard flag caps the result below the pass mark even when the arithmetic would pass.&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="n"&gt;score&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;max&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nf"&gt;sum&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;penalties&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="k"&gt;pass&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;score&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="mi"&gt;85&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="n"&gt;hard_flags&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The pass condition has two parts for a reason. A draft can collect several soft flags, score 86, and still fail because one hard flag fired. The team sees one number in CI and one honest verdict underneath.&lt;/p&gt;

&lt;h2&gt;
  
  
  What the analyzer ignores
&lt;/h2&gt;

&lt;p&gt;False positives kill adoption, so the parser strips the parts that are not prose:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Fenced code blocks and inline code.&lt;/li&gt;
&lt;li&gt;YAML frontmatter at the top of the file.&lt;/li&gt;
&lt;li&gt;Link URLs. Link text survives.&lt;/li&gt;
&lt;li&gt;Images.&lt;/li&gt;
&lt;li&gt;Table separator rows.&lt;/li&gt;
&lt;li&gt;Headings for the cadence math. Headings still get scanned for tells.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A README full of commands should not fail because the commands look like short sentences.&lt;/p&gt;

&lt;h2&gt;
  
  
  The report card
&lt;/h2&gt;

&lt;p&gt;A failing file prints one compact card:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[grai-gate] Slop Score: 64/100 (CV: 0.27 | Flags: 2)
- Worst offender: flat cadence ("CV 0.27 across 12 sentences")
- Tells detected: flat cadence, zombie words (x2)
- Fix prompt: "Rewrite to increase sentence burstiness (target CV &amp;gt; 0.45) and eliminate flat cadence, zombie words."
- Pro Cockpit: Full Voice DNA &amp;amp; repair workbench at https://grai.page?utm_source=devto&amp;amp;utm_medium=article&amp;amp;utm_campaign=gate_v0.1#developer
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A clean file prints nothing by default. That matters. A gate that prints on every run becomes noise, and noise gets muted.&lt;/p&gt;

&lt;h2&gt;
  
  
  Install it in a repo
&lt;/h2&gt;

&lt;p&gt;One command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pipx run grai-gate README.md
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Pre-commit:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;repos&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;repo&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;https://github.com/adrianpeticila/grai-gate-action&lt;/span&gt;
    &lt;span class="na"&gt;rev&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;v0.1.5&lt;/span&gt;
    &lt;span class="na"&gt;hooks&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;grai-gate&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;GitHub Actions:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;adrianpeticila/grai-gate-action@v0.1.5&lt;/span&gt;
  &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;fail-on-slop&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;false"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The Action is advisory by default. It scores only files changed in the pull request, and it writes the card to the workflow summary, so the reviewer sees it on the checks page without opening the job log. Set &lt;code&gt;fail-on-slop: "true"&lt;/code&gt; when the team wants a hard gate.&lt;/p&gt;

&lt;p&gt;The command line exits 0 on clean, 1 on slop, and 2 on an input error. That contract lets any CI system consume it without parsing text.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why CI and not a writing app
&lt;/h2&gt;

&lt;p&gt;A writing app catches the draft the writer remembers to paste. CI catches every markdown file the team ships, and it catches the ones an agent wrote at 2am when nobody was watching.&lt;/p&gt;

&lt;p&gt;The gate also runs before the commit, which is the last moment the writer still has context. A failure there costs one edit. A failure in review costs a round trip.&lt;/p&gt;

&lt;h2&gt;
  
  
  Limits
&lt;/h2&gt;

&lt;p&gt;The gate judges cadence, not truth. It cannot tell whether a claim is correct, a quote is real, or a number is sourced.&lt;/p&gt;

&lt;p&gt;It also cannot hear intent. A manifesto written in short declaratives may score low and still be right for the piece. The gate reports, and a person decides.&lt;/p&gt;

&lt;p&gt;And it only sees files. A pull request description typed in a browser never reaches disk, so the gate never scores it.&lt;/p&gt;

&lt;p&gt;It is a style gate, not an authorship detector. On the v2 corpus, it flagged 7 of 63 model docs and 3 of 58 human docs.&lt;/p&gt;

&lt;h2&gt;
  
  
  The point
&lt;/h2&gt;

&lt;p&gt;A prompt asks a model to behave. A gate measures whether it did. The second one survives a model upgrade, a new teammate, and a deadline.&lt;/p&gt;

&lt;p&gt;The engine is MIT and one file. Run it on your worst README and see whether the number matches your read.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pipx run grai-gate README.md
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Repo: &lt;a href="https://github.com/adrianpeticila/grai-gate-action" rel="noopener noreferrer"&gt;https://github.com/adrianpeticila/grai-gate-action&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you want the full calibration workbench behind the gate, it lives at &lt;a href="https://grai.page?utm_source=devto&amp;amp;utm_medium=article&amp;amp;utm_campaign=gate_v0.1#developer" rel="noopener noreferrer"&gt;https://grai.page?utm_source=devto&amp;amp;utm_medium=article&amp;amp;utm_campaign=gate_v0.1#developer&lt;/a&gt;&lt;/p&gt;

</description>
      <category>python</category>
      <category>githubactions</category>
      <category>ai</category>
      <category>writing</category>
    </item>
    <item>
      <title>We audited 134,522 posts to see why AI writing still sounds fake (and open-sourced a deterministic syntactic gate)</title>
      <dc:creator>Adrian M. Peticila</dc:creator>
      <pubDate>Fri, 23 Oct 2026 09:30:30 +0000</pubDate>
      <link>https://dev.to/adrian_m_peticila/we-audited-134522-posts-to-see-why-ai-writing-still-sounds-fake-and-open-sourced-a-deterministic-3k8h</link>
      <guid>https://dev.to/adrian_m_peticila/we-audited-134522-posts-to-see-why-ai-writing-still-sounds-fake-and-open-sourced-a-deterministic-3k8h</guid>
      <description>&lt;p&gt;in 2025/2026, everyone removed the obviously AI keywords from their prompts. but even non-dev/tech-minded readers can detect an LLM post in the first 3 sentences.&lt;/p&gt;

&lt;p&gt;why? because they removed the words that people made fun of, but not the &lt;em&gt;syntactic patterns&lt;/em&gt; that betray RLHF models.&lt;/p&gt;

&lt;p&gt;to quantify the change, we &lt;em&gt;audited 134,522 random organic linkedin posts&lt;/em&gt; on 1,499 founder profiles, over jan'23 to sep'26 timeframe (LigoSocial dataset).&lt;/p&gt;




&lt;ol&gt;
&lt;li&gt;empirical change: words got nuked, structure went wild&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;SYNTACTIC PATTERN&lt;/th&gt;
&lt;th&gt;JAN'23&lt;/th&gt;
&lt;th&gt;SEP'26&lt;/th&gt;
&lt;th&gt;RELATIVE CHANGE&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;mocked ai verbs&lt;/td&gt;
&lt;td&gt;4.2%&lt;/td&gt;
&lt;td&gt;0.5%&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;-88.1%&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;"here's why" epiphany onset&lt;/td&gt;
&lt;td&gt;1.3%&lt;/td&gt;
&lt;td&gt;9.6%&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;+7.4x&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;"it's not X, it's Y" negate&lt;/td&gt;
&lt;td&gt;1.2%&lt;/td&gt;
&lt;td&gt;5.9%&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;+4.9x&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;arrow &amp;amp; emoji bullets waterfall&lt;/td&gt;
&lt;td&gt;0.6%&lt;/td&gt;
&lt;td&gt;12.3%&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;+20.5x&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;avg. sent burstiness (CV=$\sigma$/$\mu$)&lt;/td&gt;
&lt;td&gt;0.48&lt;/td&gt;
&lt;td&gt;0.23&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;-52.1%&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;most indicative is &lt;strong&gt;burstiness&lt;/strong&gt; (CV=$\sigma$/$\mu$ - std.dev. of sentence word count over avg. sentence word count)&lt;/p&gt;

&lt;p&gt;normal human, non-assisted text: CV=0.48. you may see sharp jumps of 4-word observation. and then next to it, 32-word breakdown of architecture. default GPT4o/claude 3.5 sonnet. tightly cluster around 14-18 words/sentence. (CV=0.21-0.23).&lt;/p&gt;




&lt;ol&gt;
&lt;li&gt;why negative prompts are not effective&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;if you ask llm &lt;em&gt;"vary sentence length. don't use contrastive negatives"&lt;/em&gt;. the model takes it as a soft weighting in attention. but then, in 3rd paragraph it tries to converge back to a safe, well-mannered 15-word mean (rlhf).&lt;/p&gt;

&lt;p&gt;you can't use a prob. generator as deterministic linter.&lt;/p&gt;




&lt;ol&gt;
&lt;li&gt;generation vs. validation (grai)&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;we designed &lt;strong&gt;grai&lt;/strong&gt; to be two layers:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;OpenCore MIT Instruction Harness + Agent Skill:&lt;/strong&gt; &lt;a href="https://github.com/adrianpeticila/grai" rel="noopener noreferrer"&gt;github.com/adrianpeticila/grai&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;622kb air-gapped html5 workbench:&lt;/strong&gt; &lt;a href="https://grai.page" rel="noopener noreferrer"&gt;grai.page&lt;/a&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The model will not self-censor: deterministic external (non-LLM) vanilla JS preflight engine is applied to each draft:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;CONTRASTIVE_NEGATION. Flags "It's not X. It's Y" / "Less X, more Y".&lt;/li&gt;
&lt;li&gt;LESS_MORE_SYMMETRY. Corporate paralleslisms "Stop X. Start Y".&lt;/li&gt;
&lt;li&gt;EPIPHANY_OPENER. Flags "Here is why" "The harsh truth is", "Let that sink in".&lt;/li&gt;
&lt;li&gt;ARROW_BULLET_SLOP. Flags cascading Unicode/emoji arrows/bullets (→ ↳ 🚀💡).&lt;/li&gt;
&lt;li&gt;TRIADIC_PADDING. Flags catchy triadic slogans. "No X, No Y, Just Z".&lt;/li&gt;
&lt;li&gt;LEXICAL_SLOP. Flags remaining synth vocab red flags.&lt;/li&gt;
&lt;li&gt;&lt;p&gt;HARD_BURSTINESS_FLOOR ($CV &amp;gt; 0.32). Computes sentence wordcount variance. (Preserves decimal "3.14", abbreviations "U.S.", "Dr." etc.) Any draft that does not have $CV &amp;gt; 0.32, is rejected.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Engineering quirk. FIPS 180-4 SHA256 on "file://"&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;We made the workbench (grai.html) to be 100% offline from disk. Use the file:// protocol and strict Content-Security-Policy (connect-src 'none' by default).&lt;/p&gt;

&lt;p&gt;Here's where we ran into some problems testing on WebKit/Chromium. They block window.crypto.subtle.digest("SHA-256") on file:// (local files are not Secure Context). We need SHA256 fingerprint of author's voice profile to be deterministic for our printable A4 Voice DNA Dossier. So we created a pure JS FIPS 180-4 SHA256 workaround. To have the same hash whether we load it from disk or over HTTPS.&lt;/p&gt;

&lt;p&gt;Try the Scorer, or the MIT Harness&lt;/p&gt;

&lt;p&gt;• Live Cadence Gate Scorer (free - no signup required) &lt;a href="https://grai.page/#test" rel="noopener noreferrer"&gt;https://grai.page/#test&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;• Full 134522-post Methodology Report &lt;a href="https://grai.page/methodology" rel="noopener noreferrer"&gt;https://grai.page/methodology&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;• Github repo (MIT skill &amp;amp; instructions) &lt;a href="https://github.com/adrianpeticila/grai" rel="noopener noreferrer"&gt;https://github.com/adrianpeticila/grai&lt;/a&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>llm</category>
      <category>opensource</category>
      <category>writing</category>
    </item>
    <item>
      <title>Ninety-Two Blog Posts, Five Percent of the Answer</title>
      <dc:creator>Adrian M. Peticila</dc:creator>
      <pubDate>Tue, 29 Sep 2026 21:17:59 +0000</pubDate>
      <link>https://dev.to/adrian_m_peticila/ninety-two-blog-posts-five-percent-of-the-answer-3opl</link>
      <guid>https://dev.to/adrian_m_peticila/ninety-two-blog-posts-five-percent-of-the-answer-3opl</guid>
      <description>&lt;p&gt;Every quarter I get asked the same question by a marketing director: why is our blog traffic up and our AI visibility flat? The answer is arithmetic, and it is not flattering.&lt;/p&gt;

&lt;p&gt;Last quarter I reviewed the content budget of a company that had shipped ninety-two blog posts in a year. Ninety-two. Every one researched, written, edited, SEO-checked, and promoted. The company was delighted with the traffic. It was also invisible in every AI answer about its own category.&lt;/p&gt;

&lt;p&gt;That gap is the entire argument of this piece, and it is not a fringe position. In June 2026, llemmy pulled 37,547 citations out of 5,200 AI answers generated by ChatGPT, Claude, Gemini, Perplexity and Google AI Overviews. About 5% of those citations pointed at the brand's own website. Nineteen out of twenty went somewhere else.&lt;/p&gt;

&lt;p&gt;Ninety-two posts competed for that 5%.&lt;/p&gt;

&lt;p&gt;Worse, most of those posts never got even that. Semrush, working with Kevin Indig, analysed thousands of domain appearances across AI search engines and found 62% of AI citations are what they call ghost citations. The model links your site as a source and never says your name. You collect the authority, the traffic does not arrive, and the brand does not register in the answer. The engines also behave in opposite ways. Gemini names a brand in 83.7% of answers but cites it as a source only 21.4% of the time. ChatGPT reverses it: 87% citation rate, 20.7% mention rate.&lt;/p&gt;

&lt;p&gt;Being right is not the objective. Being named is.&lt;/p&gt;

&lt;p&gt;So what is happening inside these systems? Search ranked pages. AI retrieval ranks sources, and it rewards something pages were never built to carry: agreement between independent nodes. When several unrelated sources describe you the same way, the odds a model repeats that description rise sharply. When your own blog makes a claim and nothing else in the world corroborates it, you have a weak signal in a large amount of noise. The model is not weighing the quality of your argument. It is counting how many places that have nothing to do with you say the same thing.&lt;/p&gt;

&lt;p&gt;The 5W Citation Source Audit makes the consequence concrete. Only about 12% of AI citations overlap Google's top 10 results. Wikipedia at 13.15% and Reddit at 11.97% together account for more than a quarter of US ChatGPT citations. YouTube appears in 23% of Google AI Overview answers.&lt;/p&gt;

&lt;p&gt;Reddit, Wikipedia, YouTube. None of them are trade publications, and none of them will accept a media kit. The expensive, relationship-driven work this industry has relied on for twenty years was built to earn links in the marketing press. That work still matters. It is simply no longer the mechanism doing the heavy lifting.&lt;/p&gt;

&lt;p&gt;The budgeting consequence is uncomfortable for anyone whose career runs on owned content. The blog is not your message to the market. It is your record for the machines. Structured data, entity markup, canonical facts, crawler policy: that is what the owned domain is for. It is the evidence locker, not the pulpit. Being believed happens on somebody else's domain.&lt;/p&gt;

&lt;p&gt;Three moves follow, in the order I would fund them.&lt;/p&gt;

&lt;p&gt;Cut first, measure second. Audit what the models currently say about you, not what you say about you. Run the prompts your buyers actually type, read the footnotes, and find out whether you are named, cited, or ignored. Most teams have never done this, and most discover the answer is "ignored".&lt;/p&gt;

&lt;p&gt;Then redirect the savings. The citations cluster in review sites, directories, communities and structured records, not in owned properties. Move the ninety-two posts of budget into places a machine is willing to read about you by people who do not work for you.&lt;/p&gt;

&lt;p&gt;And fix the plumbing underneath. Get the company and leadership names into structured, machine-readable, third-party records, because entity resolution decides whether a model merges your CEO with somebody who has the same surname and a louder footprint.&lt;/p&gt;

&lt;p&gt;None of this is a content strategy. The brands that win the AI answer will be the ones that appear, accurately and often, everywhere the engines look. Your own website was never going to be that place. It is roughly 5% of it, and 5% is not a budget line.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;By Adrian M. Peticila, CMO &amp;amp; AI Practitioner&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
&lt;em&gt;Website: &lt;a href="https://peticila.ro" rel="noopener noreferrer"&gt;peticila.ro&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

</description>
      <category>marketing</category>
      <category>seo</category>
      <category>ai</category>
      <category>machinelearning</category>
    </item>
    <item>
      <title>Why I Built Gorgona: Turning Runaway AI Agents to Stone</title>
      <dc:creator>Adrian M. Peticila</dc:creator>
      <pubDate>Wed, 02 Sep 2026 20:37:03 +0000</pubDate>
      <link>https://dev.to/adrian_m_peticila/why-i-built-gorgona-turning-runaway-ai-agents-to-stone-28ho</link>
      <guid>https://dev.to/adrian_m_peticila/why-i-built-gorgona-turning-runaway-ai-agents-to-stone-28ho</guid>
      <description>&lt;p&gt;Running multiple digital brands simultaneously with autonomous AI agents sounds like a dream until you wake up to a $500 token bill, an agent stuck in an infinite tool call loop, or sensitive credentials leaked into public commits.&lt;/p&gt;

&lt;p&gt;When you manage several brands alone, you cannot afford probabilistic safety. You need cold, deterministic discipline.&lt;/p&gt;

&lt;p&gt;That is why I created &lt;strong&gt;Gorgona&lt;/strong&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Problem With Modern Autonomous Agents
&lt;/h2&gt;

&lt;p&gt;Most agent frameworks operate on optimistic recursion. The agent plans, calls tools, observes outputs, and continues thinking. When an unexpected error occurs, the typical failure mode is disastrous:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;The Infinite Hallucination Loop&lt;/strong&gt;: The agent attempts to fix a missing dependency, fails, repeats the same terminal command 15 times, and exhausts rate limits.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Context Bleed&lt;/strong&gt;: An agent working on Brand A accesses notes or credentials meant for Brand B, embedding them into commits or deploy scripts.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The AI Slop Creep&lt;/strong&gt;: Text generated by runaway prompts becomes saturated with buzzwords ("delve into", "tapestry of", "fostering innovation") and unneeded punctuation.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;You do not solve deterministic engineering problems with probabilistic prompts like "Please be careful not to leak secrets".&lt;/p&gt;

&lt;p&gt;You solve them with guardrails that &lt;strong&gt;turn runaway agents to stone&lt;/strong&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  What Is Gorgona?
&lt;/h2&gt;

&lt;p&gt;Gorgona is a lightweight, zero-dependency Python engine designed to enforce uncompromising boundaries on AI agents.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;       Autonomous Agent Step
                 │
                 ▼
         [ Gorgona Engine ]
                 │
  ┌──────────────┼──────────────┐
  ▼              ▼              ▼
Exposure     Isolation      Text Clean
 Guard         Guard          Guard
  │              │              │
  └──────────────┼──────────────┘
                 │
         [ Memory Graph ]
                 │
                 ▼
       Verified or Frozen
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If an agent violates a rule, Gorgona halts execution immediately. No polite warnings. No retries. The agent is frozen before disk writes or git commits can occur.&lt;/p&gt;




&lt;h2&gt;
  
  
  Four Pillars of Stone
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Exposure Guard
&lt;/h3&gt;

&lt;p&gt;Detects leaked credentials, Bearer tokens, private SSH keys, and sensitive environment files before any push or deploy action.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Isolation Guard
&lt;/h3&gt;

&lt;p&gt;Enforces strict brand borders. If code or documentation for one client references identifiers from another client, execution stops immediately.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Text Cleaner Guard
&lt;/h3&gt;

&lt;p&gt;Enforces strict prose discipline. It flags AI markers and eliminates characters that scream synthetic generation, including a strict zero em-dash policy.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Memory Graph Guard
&lt;/h3&gt;

&lt;p&gt;Monitors agent recursion using depth-first search cycle detection. If an agent loops over the same action sequence, it triggers an immediate breaker.&lt;/p&gt;




&lt;h2&gt;
  
  
  Zero Dependencies Philosophy
&lt;/h2&gt;

&lt;p&gt;Gorgona was built with standard Python libraries. No heavy dependencies. No network calls. No telemetry. It runs in milliseconds inside lightweight CI/CD containers, local CLI environments, or edge workers.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;gorgona doctor
gorgona scan ./output-directory
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  The Future of Solo Engineering
&lt;/h2&gt;

&lt;p&gt;Operating as a solo builder at scale requires ruthless automation paired with ruthless constraints. Autonomous agents are incredible force multipliers, but only if they are held accountable to deterministic standards.&lt;/p&gt;

&lt;p&gt;Gorgona is available open source on GitHub:&lt;br&gt;
👉 &lt;a href="https://github.com/adrianpeticila/gorgona" rel="noopener noreferrer"&gt;https://github.com/adrianpeticila/gorgona&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Turn runaway agents to stone. Build with discipline.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>python</category>
      <category>opensource</category>
      <category>architecture</category>
    </item>
  </channel>
</rss>
