<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
    <id>https://straymark.dev/blog</id>
    <title>StrayMark Blog</title>
    <updated>2026-05-23T00:00:00.000Z</updated>
    <generator>https://github.com/jpmonette/feed</generator>
    <link rel="alternate" href="https://straymark.dev/blog"/>
    <subtitle>The StrayMark chronicle.</subtitle>
    <icon>https://straymark.dev/favicon.ico</icon>
    <rights>Copyright © 2026 Strange Days Tech.</rights>
    <entry>
        <title type="html"><![CDATA[What the binary couldn't hide]]></title>
        <id>https://straymark.dev/blog/what-the-binary-couldnt-hide</id>
        <link href="https://straymark.dev/blog/what-the-binary-couldnt-hide"/>
        <updated>2026-05-23T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[Ten latent gaps surfaced in a single polish Charter, and the anti-pattern that earned a name]]></summary>
        <content type="html"><![CDATA[<p><em>A polish Charter that was supposed to be cosmetic cleanup surfaced ten production gaps in six hours — including two features that had shipped to <code>main</code> and never functionally worked for ten days. The anti-pattern got named, the pattern got documented as <code>fw-4.18.0</code>, and the CLI helper got deferred on purpose.</em></p>
<!-- -->
<blockquote>
<p><em>"The first thing the polish Charter tried — booting <code>./sentinel</code> from <code>main</code> to run the §5 smoke — failed with two distinct panics."</em></p>
</blockquote>
<p>That sentence opened Issue <a href="https://github.com/StrangeDaysTech/straymark/issues/199" target="_blank" rel="noopener noreferrer" class="">#199</a> on May 22, filed by the Sentinel adopter as an RFC. By the time the thread closed five comment-updates later, the count had grown from two to ten. The polish Charter — the closing Charter of Etapa 2, planned as a docket of WCAG audits and quickstart verification — had spent six hours doing something else: catching a class of latent regression that none of the per-Charter test suites of the eight previous Charters had caught, and that none of them <em>could</em> have caught given how they were written.</p>
<p>This post is the reconstruction of why that happened, what the recurring shape underneath it turned out to be, and the deliberate decision in PR <a href="https://github.com/StrangeDaysTech/straymark/pull/200" target="_blank" rel="noopener noreferrer" class="">#200</a> to <strong>name the anti-pattern but not yet tool for it</strong>. The cycle is familiar to readers who followed the previous posts on <a class="" href="https://straymark.dev/blog/emergent-observation-design">emergent observation</a> and <a class="" href="https://straymark.dev/blog/pattern-1-and-pattern-2-chain-evolution">chain evolution</a> — this is the third pattern in two weeks to crystallize via the same arc: surface in N=1, name the meta, defer the cross-project tooling until N=2 validates.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="the-two-cases-that-mattered">The two cases that mattered<a href="https://straymark.dev/blog/what-the-binary-couldnt-hide#the-two-cases-that-mattered" class="hash-link" aria-label="Direct link to The two cases that mattered" title="Direct link to The two cases that mattered" translate="no">​</a></h2>
<p>Of the ten gaps the polish session surfaced, eight were either dependency rot (a <code>huma</code> upgrade introduced a panic on <code>*string</code> parameters; Go 1.22 tightened <code>http.ServeMux</code> wildcard semantics) or runbook drift (env vars missing from §boot, smoke recipes that mixed mutually-exclusive modes, claims about a fake provider's stdout that the fake never wrote to). Each one merits a fix. None of them rewrites the playbook.</p>
<p>The two that did rewrite the playbook are different. They share a shape.</p>
<p><strong>US3 Preference Center, shipped May 12.</strong> When recipients of a Sentinel-sent email click the unsubscribe-style footer link, they land on a JWT-in-path URL like <code>/preferences/&lt;token&gt;</code>. The handler is intentionally public-by-contract: the JWT <em>is</em> the auth; no <code>Authorization</code> header is expected. The handler's doc-comment said so. The integration test, written in <code>humatest</code>, mounted the handler directly through the testing adapter and confirmed: given a valid JWT in the path, the handler returns the right HTML. CI passed. The feature shipped to <code>main</code>.</p>
<p>What never happened: anything that exercised the production middleware chain in front of that handler. <code>internal/core/middleware/auth.go</code> has a <code>publicPrefixes</code> list of route prefixes that bypass the <code>Authorization</code> check. <code>/preferences/</code> was not in it. For ten days, every recipient who clicked an unsubscribe link got a <code>401 missing authorization header</code> from the middleware before the request ever reached the handler that knew not to expect one. The Preference Center was reachable in tests, unreachable in production.</p>
<p><strong>OTel observability instruments for the send pipeline, shipped the same week.</strong> Eight metric instruments — counters, histograms, gauges — declared in <code>internal/core/metrics/commshub.go</code>, registered with the OpenTelemetry meter at boot. The Charter's <code>Constitution Check §IV</code> formally declared the FR-039..042 observability gate satisfied: the API layer was correct, the registrations went through, dashboards were planned. Seven of those eight instruments had <strong>zero <code>.Add()</code> / <code>.Record()</code> call sites in the entire commshub module</strong>. Declared, registered, never invoked. The dashboards that ops built on top of those series had been receiving zero data for ten days. The polish Charter's manual smoke — boot an OTel Collector, generate a few sends, grep collector output for the FR-039..042 names — surfaced this instantly.</p>
<p>Neither case is exotic. Neither case is a hard bug. They are both instances of the same mechanical mistake: an artifact got declared in one place, and the implementation that was supposed to wire it lived in another place, and nothing in the codebase or in CI correlated the two.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="the-name-the-anti-pattern-wanted">The name the anti-pattern wanted<a href="https://straymark.dev/blog/what-the-binary-couldnt-hide#the-name-the-anti-pattern-wanted" class="hash-link" aria-label="Direct link to The name the anti-pattern wanted" title="Direct link to The name the anti-pattern wanted" translate="no">​</a></h2>
<p>A name matters when the same shape shows up enough times to deserve one. By the third comment update on #199, the Sentinel author had counted four sub-classes of the same underlying mistake:</p>






























<table><thead><tr><th>Declaration site</th><th>Wiring site</th><th>Mechanical check</th></tr></thead><tbody><tr><td>env var documented in the operator runbook</td><td><code>os.Getenv(...)</code> (or stack equivalent) in code</td><td>each documented env var has at least one consumer</td></tr><tr><td>metric instrument declared in a metrics package</td><td><code>.Record()</code> / <code>.Add()</code> call site in handler or worker code</td><td>each declared instrument is recorded at least once</td></tr><tr><td>URL referenced from rendered/embedded HTML (<code>&lt;script src=...&gt;</code>, <code>&lt;link href=...&gt;</code>)</td><td>route registered on the same API surface</td><td>each <code>src=</code>/<code>href=</code> in served HTML resolves to a registered route</td></tr><tr><td>route marked public-by-contract (doc-comment, dedicated marker)</td><td>entry in the auth middleware's public-prefix list</td><td>each public-by-contract handler has a matching prefix entry</td></tr></tbody></table>
<p>The unifier — the one-liner that the new governance doc opens with — is:</p>
<blockquote>
<p><em>Every declared surface artifact has at least one wiring site reachable from a real request.</em></p>
</blockquote>
<p>The anti-pattern's name, which lands canonically in <code>dist/.straymark/00-governance/POLISH-CHARTER-PATTERN.md</code>, is <strong>Surface declaration without wiring.</strong> That is the deliverable. The polish Charter is the discovery vehicle, not the thesis.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="why-integration-tests-systematically-miss-this">Why integration tests systematically miss this<a href="https://straymark.dev/blog/what-the-binary-couldnt-hide#why-integration-tests-systematically-miss-this" class="hash-link" aria-label="Direct link to Why integration tests systematically miss this" title="Direct link to Why integration tests systematically miss this" translate="no">​</a></h2>
<p>This part is worth dwelling on because it shapes the rest of the post. The common failure mode across all four sub-classes is that the standard integration-test harness — <code>humatest.NewTestAdapter</code> in Go, the equivalent in TypeScript, Python, Rust — mounts handlers <em>directly</em> via the testing API. The handler under test is wired correctly by the fixture. The production composition step — where the route registration meets the middleware chain meets the env-var inventory meets the embedded asset table — is what's broken. CI's green light is genuine for what it claims: the handler returns the right response given the right request. It says nothing about whether the request can reach the handler in production, or whether the artifact the handler depends on was ever wired to the runtime.</p>
<p>There's a temptation to read this as a critique of <code>humatest</code>. It isn't. <code>humatest</code> (and its equivalents) is doing exactly what it was designed to do: let you test handler logic in isolation, fast, without standing up the whole composition tree. That isolation is a feature. The cost of the isolation is what we just named — and the cost only becomes visible when something outside the isolation surfaces a divergence. The polish Charter is the cheapest method to surface that divergence, because it does what no test fixture does: it boots the actual binary and runs the actual documented operator recipe against it.</p>
<p>This is the load-bearing claim of the new pattern doc. Not that polish Charters are valuable for cosmetic reasons. That they are <strong>the only place</strong> where the production composition gets exercised end-to-end against an externally-readable specification (the operator runbook). If you treat the polish Charter as cosmetic cleanup, you also treat that surfacing capacity as cosmetic. Sentinel's data argues the opposite.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="the-decision-b-not-b">The decision: B′, not B<a href="https://straymark.dev/blog/what-the-binary-couldnt-hide#the-decision-b-not-b" class="hash-link" aria-label="Direct link to The decision: B′, not B" title="Direct link to The decision: B′, not B" translate="no">​</a></h2>
<p>The RFC proposed three options. The decision in PR #200 was none of them as stated — call it B′. Worth saying why, because the structural choice matters more than it looks.</p>
<p><strong>The RFC's Option B</strong> asked for a pattern doc under <code>docs/patterns/</code>. That directory does not exist in StrayMark today, and creating it would have split the project's documentation convention. The empirical patterns that already live in the canon — <code>FOLLOW-UPS-BACKLOG-PATTERN.md</code>, <code>CHARTER-CHAIN-EVOLUTION.md</code>, <code>EMERGENT-OBSERVATION-DESIGN.md</code>, <code>SPECKIT-CHARTER-BRIDGE.md</code> — all live in <code>dist/.straymark/00-governance/</code>. They share an i18n mirror infrastructure (every governance doc has English, Spanish, and Simplified Chinese siblings). Adding a third documentation surface would have multiplied the i18n overhead and pulled the project's patterns across two homes. Keeping the new doc inside <code>00-governance/</code> reused the existing infrastructure with zero marginal cost.</p>
<p><strong>The RFC's Option C</strong> asked for a <code>straymark charter polish-checklist</code> or <code>straymark analyze declared-vs-wired</code> CLI helper. The Sentinel author had already prototyped one (CHARTERs 25/26/27, the three preparatory CI guards) and offered to seed it upstream. The decision here was conservative: defer. Not because the prototype isn't valuable — it is — but because Sentinel is N=1. The four sub-classes were the ones <em>one adopter, one stack</em> surfaced. The fifth, sixth, and seventh sub-classes that the framework would have to anticipate to ship a useful cross-project CLI don't exist yet, because no second adopter has pushed them. We've been down this road before. <a href="https://github.com/StrangeDaysTech/straymark/blob/main/dist/.straymark/00-governance/FOLLOW-UPS-BACKLOG-PATTERN.md" target="_blank" rel="noopener noreferrer" class=""><code>FOLLOW-UPS-BACKLOG-PATTERN.md</code></a> shipped as v0 in <code>fw-4.10.0</code> and has lived there for a month and a half, waiting for a second adopter to validate before graduating to a <code>straymark followups</code> subcommand. The same gate applies here. The new doc's <code>## Open questions</code> says so explicitly: "Crystallization as <code>straymark analyze declared-vs-wired</code> CLI subcommand … Gate: N=2 adopters."</p>
<p><strong>B′ is what landed.</strong> A new governance pattern doc in the canonical location, in three languages. A seventh <code>Format conventions</code> bullet in the Charter template pointing authors at it when closing an Etapa or SpecKit <code>Polish</code> Phase. A row in the QUICK-REFERENCE <code>## Patterns</code> table. A <code>fw-4.18.0</code> bump with the footer cascade across thirty-some docs. No CLI subcommand. No new frontmatter field. No schema change. The anti-pattern has a name; the discovery ritual has a doc; the tooling waits.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="the-arc-that-keeps-repeating">The arc that keeps repeating<a href="https://straymark.dev/blog/what-the-binary-couldnt-hide#the-arc-that-keeps-repeating" class="hash-link" aria-label="Direct link to The arc that keeps repeating" title="Direct link to The arc that keeps repeating" translate="no">​</a></h2>
<p>Three weeks ago, the follow-ups backlog pattern crystallized via the same arc: an adopter surfaced a need, the pattern got named at v0, the CLI helper was deferred. Two weeks ago, the chain-evolution patterns crystallized: Pattern 1 (pre-declare SpecKit refresh) and Pattern 2 (post-close audit-driven Batch N.4), surfaced from the same Sentinel adopter, named in <code>fw-4.16.0</code>, with <code>straymark charter refresh-suggest</code> as a soft helper rather than a hard gate. One week ago, the meta — <code>EMERGENT-OBSERVATION-DESIGN.md</code> — codified what made any of those observations possible in the first place: formal cross-referencing plus cultural permission. This week, this pattern.</p>
<p>That's four crystallizations in a month, all from the same adopter, all following the same shape: <strong>surface in N=1 → name the meta → tool only after N=2</strong>. The temptation when a pattern surfaces vividly — and ten production gaps in six hours is vivid — is to skip the name and go straight to the tool. The discipline is the opposite. The name does most of the work. The tool, when it comes, is parameterized by what at least two adopters have surfaced; built on N=1, it's an extrapolation from one stack and one team's failure modes, and it tends to ossify those choices into framework defaults that don't generalize.</p>
<p>There is one piece of this iteration that is genuinely new and worth flagging. The new pattern doc names a falsifiable prediction the Sentinel author already committed to publishing: the next Etapa's polish Charter, executed against the three preparatory CI guards that just landed in Sentinel CHARTERs 25/26/27, should surface roughly 80% fewer gaps. If that prediction holds, the case for graduating Option C from "open question" to "CLI subcommand" gets quantitative backing. If it fails — if the next polish Charter still surfaces ten gaps but in a fifth, unanticipated sub-class — the failure itself is the next data point, and reshapes the spec before tooling is built. Either result is useful. Neither result has been observed yet. We wait.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="a-note-on-what-was-deliberately-not-done">A note on what was deliberately not done<a href="https://straymark.dev/blog/what-the-binary-couldnt-hide#a-note-on-what-was-deliberately-not-done" class="hash-link" aria-label="Direct link to A note on what was deliberately not done" title="Direct link to A note on what was deliberately not done" translate="no">​</a></h2>
<p>There is no <code>phase: polish</code> field in the Charter frontmatter. There is no <code>straymark charter polish-checklist &lt;ID&gt;</code>. There is no automated analyzer scanning Go (or any other language) code for declared-but-unwired symbols. The pattern doc lists each of those as a candidate evolution, gated explicitly on N=2 or on the post-Etapa-3 retrospective. None of them are present in <code>fw-4.18.0</code>.</p>
<p>This is intentional and worth saying out loud, because the natural reaction to a vivid finding is to over-build the response. Each one of those deferrals trades short-term thoroughness for long-term portability. A frontmatter field commits the framework to a vocabulary the next adopter may not share. A CLI helper commits the framework to a runtime that mirrors one specific stack's failure modes. An analyzer commits the framework to scanning a language whose conventions may diverge from the next adopter's. None of those commitments should be made on a single domain's signal, however clean the signal is. The pattern doc itself can be revised; a CLI subcommand cannot be unshipped without breaking adopters.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="what-id-suggest-you-look-at-if-youve-read-this-far">What I'd suggest you look at, if you've read this far<a href="https://straymark.dev/blog/what-the-binary-couldnt-hide#what-id-suggest-you-look-at-if-youve-read-this-far" class="hash-link" aria-label="Direct link to What I'd suggest you look at, if you've read this far" title="Direct link to What I'd suggest you look at, if you've read this far" translate="no">​</a></h2>
<p>If you operate a codebase with mock-adapter integration tests — which is most codebases — you can run a useful internal exercise without adopting anything from StrayMark at all. Pick the most recent feature your team shipped that has both (a) a docs-side declaration (env vars, OpenAPI specs, embedded HTML, metric instruments) and (b) a wiring site that lives in a different file. Boot the binary from a clean shell. Run the operator-facing recipe from the runbook end-to-end. If it works on the first try, your codebase doesn't yet have the latent debt this pattern catches — or it does and you got lucky on this one. If it doesn't, count the gaps. The number is the calibration you need for whether the polish-Charter-as-debt-detection ritual would be worth its overhead in your project.</p>
<p>If you've adopted StrayMark and you're closing an Etapa with handlers tested through <code>humatest</code>-style adapters, the new pattern doc has the four sub-class checks scoped for you. Budget the polish Charter as L, not XS or S. Expect emergent follow-on Charters, not residual cleanup scope creep. Read <a href="https://github.com/StrangeDaysTech/straymark/blob/main/dist/.straymark/00-governance/POLISH-CHARTER-PATTERN.md" target="_blank" rel="noopener noreferrer" class=""><code>POLISH-CHARTER-PATTERN.md</code></a> before scoping the work, not after.</p>
<p>And if you're an adopter on a stack other than Go — TypeScript, Python, Rust, Elixir — the four sub-classes are language-agnostic, but the concrete check shape is not. Surfacing a fifth or sixth sub-class in your stack is exactly the second-adopter signal the pattern needs to graduate from v0. The path from "interesting observation in your project" to "named in the StrayMark canon" runs through the same channel #199 went through: open an issue. The cost of opening it is low; the cost of leaving the pattern under-validated is real.</p>
<hr>
<p><em>StrayMark <code>fw-4.18.0</code> — Issue <a href="https://github.com/StrangeDaysTech/straymark/issues/199" target="_blank" rel="noopener noreferrer" class="">#199</a> · PR <a href="https://github.com/StrangeDaysTech/straymark/pull/200" target="_blank" rel="noopener noreferrer" class="">#200</a> · tag <a href="https://github.com/StrangeDaysTech/straymark/releases/tag/fw-4.18.0" target="_blank" rel="noopener noreferrer" class=""><code>fw-4.18.0</code></a>. Sentinel anchors: <a href="https://github.com/StrangeDaysTech/sentinel/pull/93" target="_blank" rel="noopener noreferrer" class=""><code>AIDEC-2026-05-22-001</code></a> · <a href="https://github.com/StrangeDaysTech/sentinel/pull/94" target="_blank" rel="noopener noreferrer" class="">CHARTERs 25/26/27 PR</a>.</em></p>
<p><em>This document was produced with assistance from generative AI tools (Claude 4.7); all responsibility for the content rests with the human author.</em></p>]]></content>
        <author>
            <name>José Villaseñor Montfort</name>
            <uri>https://github.com/montfort</uri>
        </author>
        <category label="straymark" term="straymark"/>
        <category label="charters" term="charters"/>
        <category label="governance" term="governance"/>
        <category label="polish-charter" term="polish-charter"/>
        <category label="sentinel" term="sentinel"/>
        <category label="anti-pattern" term="anti-pattern"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[The day the agent saw something nobody asked it to see]]></title>
        <id>https://straymark.dev/blog/emergent-observation-design</id>
        <link href="https://straymark.dev/blog/emergent-observation-design"/>
        <updated>2026-05-16T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[Naming a design property that was already silently doing its job]]></summary>
        <content type="html"><![CDATA[<p><em>An agent flagged a stale spec before being asked to. The reconstruction of that morning, and the design property that surfaces it — codified after the fact as Principle #8 of StrayMark.</em></p>
<!-- -->
<blockquote>
<p><em>"Hi, did we already deal with Issue #153?"</em></p>
</blockquote>
<p>That's how the conversation started, today, May 16th, in the morning. A short, almost-housekeeping question, before getting into something else. The answer was no — Issue #153 was open on purpose, waiting for a second domain to exercise the mechanic before crystallizing it (StrayMark's Principle #12: validation against a second domain before canonization). But the question opened another door, and by the end of that conversation I had codified a design property of the framework that had been doing its job in silence for months, surfaced by an episode from just two days ago.</p>
<p>This post is the reconstruction of that arc, because it's worth keeping. Not for the outcome — a new canonical doc, a Principle #8, a PR already merged — but for the mechanism it revealed. StrayMark has a human project behind it: making sure that agent-assisted development doesn't slip through the fingers of the engineers who are responsible for the software being produced. And this episode exposed a concrete design property pushing in that direction.</p>
<p>A note on craft: StrayMark gets tested first on my own projects. Sentinel is one of them — private, but its interaction with StrayMark is documented in the public Issues of the StrayMark repo, so the context is linkable. I'm the author and first adopter of the framework. Principle #12 obliges me to wait for a second domain before declaring any new mechanic canonical; but the first domain is me, and this post acknowledges that without disguise.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="the-incident-an-agent-that-flagged-what-nobody-asked-it-to-flag">The incident: an agent that flagged what nobody asked it to flag<a href="https://straymark.dev/blog/emergent-observation-design#the-incident-an-agent-that-flagged-what-nobody-asked-it-to-flag" class="hash-link" aria-label="Direct link to The incident: an agent that flagged what nobody asked it to flag" title="Direct link to The incident: an agent that flagged what nobody asked it to flag" translate="no">​</a></h2>
<p>On <strong>May 14, two days ago</strong>, in Sentinel, an agent brought to my attention an observation I hadn't requested. It was about to help me fill out CHARTER-18 — a concrete piece of work inside an already-long chain — and before writing a single line of code it said, in essence:</p>
<blockquote>
<p><em>(translated from the original in Spanish)</em> There's a problem. The <code>specs/002-commshub/plan.md</code> was frozen on April 21. Since then seven consecutive Charters have passed, and across the AILOGs of that chain there are twelve empirical learnings unreflected in the plan that materially affect the scope of US5. If we fill out CHARTER-18 reading the stale plan, the next audit cycle is going to remediate divergences atomically pre-close — with approximately 50% probability of at least one critical or high finding from stale-premise inheritance.</p>
</blockquote>
<p>And it cited the specific AILOGs by ID. And the concrete code references.</p>
<p>Nobody asked for that analysis. There was no trigger configured. There was no CLI command whose purpose was to produce that output. The agent was there to help me with the next task, not to audit the project's state. But while positioning itself for that next task, it saw a divergence between two sources that StrayMark's documentation explicitly connects, and it chose to flag it before proceeding.</p>
<p>I filed Issue <a href="https://github.com/StrangeDaysTech/straymark/issues/150" target="_blank" rel="noopener noreferrer" class="">#150</a> that same afternoon as an RFC, and between 5pm and the night the manual spec-refresh discipline got discussed and landed in <code>fw-4.14.3</code>. The next day, <strong>May 15</strong>, I raised Issue <a href="https://github.com/StrangeDaysTech/straymark/issues/156" target="_blank" rel="noopener noreferrer" class="">#156</a> to upstream the two patterns the exercise had revealed: a <em>pre-declare SpecKit refresh</em> and a <em>post-close Batch N.4 amendment</em>. By the early hours of <strong>May 16</strong> they were canonized in <code>fw-4.16.0</code> as <code>CHARTER-CHAIN-EVOLUTION.md</code>, with dedicated telemetry and a CLI helper (<code>straymark charter refresh-suggest</code>). The behavior reproduced, the patterns crystallized, cycle closed.</p>
<p>But when I sat down that same morning of the 16th to open the conversation with Issue #153 — <em>"did we deal with this?"</em> — and then bounced back the inverse question — <em>"hold on, what made that observation possible in the first place?"</em> — I realized the cycle had only half closed. What got codified in <code>fw-4.16.0</code> was the <strong>application</strong> of the pattern. What remained to be codified was the <strong>mechanism</strong> that produced it.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="the-human-question-said-with-technical-words">The human question, said with technical words<a href="https://straymark.dev/blog/emergent-observation-design#the-human-question-said-with-technical-words" class="hash-link" aria-label="Direct link to The human question, said with technical words" title="Direct link to The human question, said with technical words" translate="no">​</a></h2>
<p>I phrased it like this, in the conversation with the agent that generated this post:</p>
<blockquote>
<p><em>(translated from the original in Spanish)</em> I was somewhat surprised by the agent's behavior — that it noticed the accumulated knowledge that, if not applied, would cause problems with the implementation of Charter 18. That is, it wasn't a task I asked it to analyze, nor was it the result of a prompt trigger being activated, and it seems to me that it was thanks to the StrayMark documentation. I'd like to dig deeper into how this happened, which I think is positive, so that we can take advantage of the experience and hook it into StrayMark's habitual behavior — this emergent pattern that came from the agent and its relationship to the generated documentation was very interesting.</p>
</blockquote>
<p>What I'm asking there isn't to implement a feature. It's to understand a mechanism in order to reproduce it. The difference matters. When you ask to implement something, the path is clear: spec → tasks → code. When you ask to understand why something worked, the path is rarer: you have to diagnose a working system, identify which pieces made it work, and separate the accidental from the structural.</p>
<p>There's a particular urgency to this kind of question when you're building tools to collaborate with AI agents. Because if what worked was an accident, the next agent — or the next version of the same agent — may not reproduce it. If what worked was structure, then it can be preserved deliberately. The difference between those two things, for a project that intends to give engineers control over AI-assisted development, is the difference between luck and design.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="the-audit-which-pieces-of-straymark-made-the-observation-possible">The audit: which pieces of StrayMark made the observation possible?<a href="https://straymark.dev/blog/emergent-observation-design#the-audit-which-pieces-of-straymark-made-the-observation-possible" class="hash-link" aria-label="Direct link to The audit: which pieces of StrayMark made the observation possible?" title="Direct link to The audit: which pieces of StrayMark made the observation possible?" translate="no">​</a></h2>
<p>I asked an agent to systematically map StrayMark's documentation with three concrete questions:</p>
<ol>
<li class="">Which documentary mechanisms connect sources explicitly to each other? (Frontmatter, canonical sections, stable IDs, CLI commands that cross sources.)</li>
<li class="">Where does the documentation give the agent <em>explicit permission</em> to flag things beyond the task asked?</li>
<li class="">What pairs of sources exist, beyond the one that originated this case, that could produce similar emergent observations if the infrastructure is present?</li>
</ol>
<p>The report came back structured, with file:line for each finding. What mattered wasn't the individual details (frontmatter with <code>originating_charter:</code>, sections <code>§Risk: R&lt;N&gt;</code>, conventions of stable IDs, commands like <code>charter drift</code>) but the pattern that emerged when seeing them together. Two properties consistently coexisted:</p>
<p><strong>Property 1: mandatory structural cross-referencing.</strong> Each document type has <em>required fields</em> and <em>canonical sections</em> that declare, in the document's own structure, which other documents it points to. When an agent reads an AILOG, it doesn't have to guess which Charter it belongs to — the <code>originating_charter:</code> tells it. When it sees a risk, it isn't an observation in free prose — it's an <code>R&lt;N&gt;</code> entry in a canonical, countable section. When the spec points to Charters, it does so formally; when Charters point to AILOGs, the same. It's an explicit linkage graph the agent can triangulate without creative work.</p>
<p><strong>Property 2: cultural permission without blocking gatekeeping.</strong> AGENT-RULES §6 tells the agent: <em>"Be Proactive — Identify potential risks, Suggest improvements when evident, Alert about technical debt"</em>. PRINCIPLES §2 tells it: <em>"Not hide relevant information"</em>. And critically, AGENT-RULES §3 gives it autonomy to <em>create</em> documents (AILOG, AIDEC, TDE) without operator pre-approval. The operator retains prioritization, not creation. The agent doesn't have to ask permission to flag something: flagging it is rule execution, not a value judgment.</p>
<p>What's interesting is that neither property alone produces the behavior. If you only had formal linkage (Property 1) without cultural permission, you'd have a queryable corpus no agent dares to query proactively. If you only had cultural permission (Property 2) without structure, you'd have vague flags — <em>"I think something might be wrong somewhere"</em> — that operators can't act on.</p>
<p>Combined, they produce something that deserves its own name: the agent externalized <em>"should I say something?"</em> as <em>"is there a canonical section where this fits?"</em>. If the answer is yes, flagging stops being an emotional decision and becomes mechanical execution. The cost of flagging drops because the destination — the canonical section — already exists.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="why-this-matters-beyond-straymark">Why this matters beyond StrayMark<a href="https://straymark.dev/blog/emergent-observation-design#why-this-matters-beyond-straymark" class="hash-link" aria-label="Direct link to Why this matters beyond StrayMark" title="Direct link to Why this matters beyond StrayMark" translate="no">​</a></h2>
<p>We're in a moment where AI agents can write code as fast as we think, and the question of how <em>not to lose control</em> of the process is genuinely urgent. It's not an apocalyptic question — it's an operational, craft-level question, asked by people who are building software right now and have to ship. The very pace of this episode is evidence: from the agent's diagnosis to the canonized meta-pattern less than <strong>72 hours</strong> passed. That speed is a gain, but it's also why visibility mechanisms matter so much.</p>
<p>The dominant response in the industry today is some variant of <em>stricter prompts, more rules in context, more gates in CI</em>. Those approaches are valid but have one characteristic worth naming: they turn the agent into something closer to a worker executing orders in verifiable pipelines. That solves reliability but at the cost of emergent observation. An agent that only does what it's ordered to do isn't going to flag something nobody asked it to flag, no matter how good its reasoning.</p>
<p>What the Sentinel episode showed is a different, complementary response: <strong>build the documentary apparatus such that important divergences are structurally visible, and give the agent cultural permission to flag them without asking approval.</strong> That preserves emergent observation as a property of the system, not as luck depending on how good the agent is or how long the prompt is.</p>
<p>There's something almost Taoist about this stance: we don't tell the agent what to look for; we build an environment where what needs to be seen is visible. The pair "visible structure + permission to name" does the work. The agent becomes, paraphrasing some colleagues, an <em>honest broker</em> between living documentation and the state of the code.</p>
<p>And this is what the human project behind StrayMark pursues, even if it's rarely said in those words: that the dizzying change of AI-assisted development doesn't throw us into a world where engineers lose visibility over what's being built. Visibility isn't preserved with more bureaucratic controls; it's preserved by designing the environment the agent works in so that what matters is naturally visible. The engineer doesn't become a reviewer of endless Pull Requests — they become a prioritizer of observations the agent brings structured and named.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="what-we-did-about-it">What we did about it<a href="https://straymark.dev/blog/emergent-observation-design#what-we-did-about-it" class="hash-link" aria-label="Direct link to What we did about it" title="Direct link to What we did about it" translate="no">​</a></h2>
<p>With the diagnosis clear, the question was how to hook it into StrayMark's habitual behavior without killing the emergent quality. This tension is real: every time you turn a spontaneous behavior into an obligation, you turn it into something else. A hard rule can be robust, but it can also generate agent resistance or false signal when triggered out of context.</p>
<p>The decision was conservative: <strong>name the meta-pattern, don't mandate its use.</strong></p>
<p>Concretely, in PR <a href="https://github.com/StrangeDaysTech/straymark/pull/160" target="_blank" rel="noopener noreferrer" class="">#160</a> released as <code>fw-4.17.0</code>:</p>
<ul>
<li class="">
<p>A new canonical doc — <code>EMERGENT-OBSERVATION-DESIGN.md</code> — articulates the design property with its two components, presents the Sentinel empirical case as anchor, and builds a <em>pyramid of instances</em>: the meta-pattern at the top, and underneath all the applications already canonized (Pattern 1 and Pattern 2 of chain evolution; charter drift; follow-ups backlog drift; TDE-vs-<code>R&lt;N&gt;</code> escalation; external audit checkpoint). What previously seemed like ad hoc patterns reveal themselves as applications of the same underlying principle. This visualization alone is worth it: when you see seven things that seemed different and suddenly recognize they share a shape, the framework gains internal coherence without having added anything.</p>
</li>
<li class="">
<p>A new Principle #8 — <em>Cross-Source Dissonance Surfacing</em> — in <code>PRINCIPLES.md</code>. It's the cultural rule condensed in five lines. The agent reads it when onboarding into the project and applies it recursively.</p>
</li>
<li class="">
<p>An expansion of <code>AGENT-RULES.md §6 "Be Proactive"</code> with concrete examples of divergence to watch for: stale spec, accumulated <code>R&lt;N&gt;</code> not escalated to TDE, ADR contradicted by implementation, follow-ups crossing the backlog-pattern threshold, audit findings emerging post-close. They're not obligations; they're <em>examples of what a proactive agent would notice</em>. The difference matters for preserving the emergent quality.</p>
</li>
<li class="">
<p>Four open axes identified as gaps — places where the cross-referencing infrastructure exists partially but the pattern isn't named: MCARD ↔ deployed model code, SBOM ↔ lockfiles, ADR vigente ↔ contradicting implementation, Constitution Check ↔ framework version bump. Each one needs N=1 empirical validation before crystallizing — Principle #12 applies. They got recorded in Issue <a href="https://github.com/StrangeDaysTech/straymark/issues/161" target="_blank" rel="noopener noreferrer" class="">#161</a> as a tracking RFC, waiting for a second domain to push one of them.</p>
</li>
<li class="">
<p>Explicit anti-patterns: how the meta breaks. If a new document type ships with optional frontmatter linkage, cross-referencing develops blind spots. If a canonical section is replaced by free prose, queryability evaporates. If blocking gatekeeping is introduced into AILOG/AIDEC/TDE creation, the cultural permission breaks. If telemetry evolves without preserving signals like <code>r_n_plus_one_emergent_count</code>, the feedback loop breaks. These anti-patterns are cheap but effective protection against accidental erosion: any future change proposal can be checked against the list to detect whether it's regressing the meta-pattern.</p>
</li>
</ul>
<p>All of this, from diagnosis to merge and the published <code>fw-4.17.0</code> release, took place between 9am and 4am the same day. Fifteen hours. Which is exactly the kind of pace the blog admits: you have to learn to operate under this clock, or control slips away.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="what-i-learned-from-the-process">What I learned from the process<a href="https://straymark.dev/blog/emergent-observation-design#what-i-learned-from-the-process" class="hash-link" aria-label="Direct link to What I learned from the process" title="Direct link to What I learned from the process" translate="no">​</a></h2>
<p>Three things I didn't expect to learn when I started by answering <em>"no, Issue #153 is still open"</em>:</p>
<p><strong>First, that codifying a meta-pattern is different from codifying a pattern.</strong> The meta-pattern doesn't add obligations; it adds <em>vocabulary</em> and <em>visibility of the underlying property</em>. That property was already doing its job; what was missing was giving it a name to protect it under future framework evolution. Whoever reads <code>EMERGENT-OBSERVATION-DESIGN.md</code> doesn't learn to do something new — they learn to <em>recognize</em> something that was already there. That's what allows preserving it deliberately.</p>
<p><strong>Second, that the emergent property disappears if over-regulated.</strong> There was a moment in the conversation where I chose not to turn Pattern 1 into a hard obligation (<em>"the agent MUST run <code>refresh-suggest</code> before declaring Charter-(N+1)"</em>) and instead keep it as recommendation plus the naming of the meta. That decision is counterintuitive if you come from the world of <em>"more controls = more reliability"</em>, but it's the right call for this kind of property. Agent proactivity is fragile: the moment it becomes a mandate, it stops being proactivity. What scales is the cultural engine ("Be Proactive") plus the structural linkage, not the list of specific obligations.</p>
<p><strong>Third, that the documentary apparatus we build for agents is also educating us humans.</strong> When I saw the seven patterns scattered across various governance docs and recognized them as instances of the same meta, I understood something about StrayMark I hadn't understood before — and StrayMark is me building it over months. The framework is revealing things to its own author. That property — that structured documentation produces <em>insights about itself</em> when audited — is a domestic variant of what the agent does when it flags a divergence. It's the same mechanism, applied at a different scale.</p>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="the-human-project-behind-it">The human project behind it<a href="https://straymark.dev/blog/emergent-observation-design#the-human-project-behind-it" class="hash-link" aria-label="Direct link to The human project behind it" title="Direct link to The human project behind it" translate="no">​</a></h2>
<p>I mean it when I say StrayMark has a human project. I'm not building a documentation governance framework because frontmatter fields obsess me. I'm building it because I have the suspicion — increasingly less speculative — that the next five years of software engineering are going to be a constant negotiation between the speed agents offer and the visibility engineers need to keep being responsible for the product. If that negotiation tilts to the agents' side, we end up in a world where code gets written and nobody knows why. If it tilts to bureaucratic control, we end up without the productivity gains that justified the experiment.</p>
<p>The balance isn't theoretical. It's built with concrete decisions: where to put a frontmatter field, which section should be canonical versus free, when to give the agent autonomy and when to retain prioritization. Each of those decisions tilts the balance one way or the other. And the only way to know if the balance is right is to test it — and to name what works when it works, so it survives the next change in the framework.</p>
<p>The CHARTER-18 episode, two days ago, was a test. It worked. What I wrote today was giving it a name. The next test already has candidates: MCARD, SBOM, ADR vigente vs implementation, Constitution Check ↔ framework bump. Four axes where the meta-pattern could reproduce if we close the infrastructure gaps. I'll wait for a second domain to push one empirically before codifying it. Principle #12 — validation against a second domain before crystallizing — remains the guardrail.</p>
<p>If you're reading this and you work with agents to develop software, I invite you to look at your own documentary apparatus with these two questions: <em>which sources are formally connected, with explicit linkage an agent can triangulate without creative work?</em> and <em>how cheap is it for the agent to flag something not asked when it detects a divergence?</em> If the answer to the first question is "few" and to the second is "expensive", you're probably leaving emergent observations on the table. Which isn't the end of the world — but it's exactly what separates an AI-assisted development process <em>under human control</em> from one that slips away.</p>
<hr>
<p><em>StrayMark fw-4.17.0 — Issue <a href="https://github.com/StrangeDaysTech/straymark/issues/150" target="_blank" rel="noopener noreferrer" class="">#150</a> · <a href="https://github.com/StrangeDaysTech/straymark/issues/156" target="_blank" rel="noopener noreferrer" class="">#156</a> · <a href="https://github.com/StrangeDaysTech/straymark/issues/161" target="_blank" rel="noopener noreferrer" class="">#161</a> · PR <a href="https://github.com/StrangeDaysTech/straymark/pull/160" target="_blank" rel="noopener noreferrer" class="">#160</a> · tag <a href="https://github.com/StrangeDaysTech/straymark/releases/tag/fw-4.17.0" target="_blank" rel="noopener noreferrer" class=""><code>fw-4.17.0</code></a></em></p>
<p><em>This document was produced with assistance from generative AI tools (Claude 4.7); all responsibility for the content rests with the human author.</em></p>]]></content>
        <author>
            <name>José Villaseñor Montfort</name>
            <uri>https://github.com/montfort</uri>
        </author>
        <category label="straymark" term="straymark"/>
        <category label="ai-agents" term="ai-agents"/>
        <category label="governance" term="governance"/>
        <category label="emergent-design" term="emergent-design"/>
        <category label="charter" term="charter"/>
        <category label="sentinel" term="sentinel"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[Pattern 1 and Pattern 2 — chain evolution]]></title>
        <id>https://straymark.dev/blog/pattern-1-and-pattern-2-chain-evolution</id>
        <link href="https://straymark.dev/blog/pattern-1-and-pattern-2-chain-evolution"/>
        <updated>2026-05-16T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[When discipline stops being habit and becomes name]]></summary>
        <content type="html"><![CDATA[<p><em>Twenty-seven hours later, the manual discipline got two names: Pattern 1 — pre-declare SpecKit refresh, and Pattern 2 — post-close audit-driven Batch N.4. The canonical document, the telemetry schema, the CLI helpers — and one hour after that, a meta-pattern that reabsorbs both upward.</em></p>
<!-- -->
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="1-twenty-seven-hours-to-name-them">1. Twenty-seven hours to name them<a href="https://straymark.dev/blog/pattern-1-and-pattern-2-chain-evolution#1-twenty-seven-hours-to-name-them" class="hash-link" aria-label="Direct link to 1. Twenty-seven hours to name them" title="Direct link to 1. Twenty-seven hours to name them" translate="no">​</a></h2>
<p>PR <a href="https://github.com/StrangeDaysTech/straymark/pull/152" target="_blank" rel="noopener noreferrer" class="">#152</a>, which closed the Post 9 episode, merged on 14 May at 21:39 UTC. It brought <code>fw-4.14.3</code> and the three canonized gates of the manual refresh.</p>
<p>PR <a href="https://github.com/StrangeDaysTech/straymark/pull/157" target="_blank" rel="noopener noreferrer" class="">#157</a> — the one this post comes to tell — merged on 16 May at 00:31 UTC. Twenty-seven hours later. It brought <code>fw-4.16.0 / cli-3.14.0</code> and, with that, two named meta-patterns:</p>
<ul>
<li class=""><strong>Pattern 1 — <em>pre-declare SpecKit refresh</em></strong>. Refresh the spec before declaring the next Charter in a chain.</li>
<li class=""><strong>Pattern 2 — <em>post-close audit-driven Batch N.4</em></strong>. Amend an already-closed Charter when external audit surfaces findings post-close, without opening a new Charter.</li>
</ul>
<p>Post 9 covered the manually applied discipline on CHARTER-18. This post covers what came after: the two named patterns, the canonical document that names them (<code>CHARTER-CHAIN-EVOLUTION.md</code>), the telemetry schema that measures them, the two <em>CLI helpers</em> that scaffold them — and, as the closing of the entire editorial arc, one hour and seventeen minutes later, a philosophical meta-pattern that reabsorbs both upward.</p>
<p>It's the last post of the arc. The blog Post 1 opened from ahead closes here from behind.</p>
<hr>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="2-pattern-1--pre-declare-refresh">2. Pattern 1 — Pre-declare refresh<a href="https://straymark.dev/blog/pattern-1-and-pattern-2-chain-evolution#2-pattern-1--pre-declare-refresh" class="hash-link" aria-label="Direct link to 2. Pattern 1 — Pre-declare refresh" title="Direct link to 2. Pattern 1 — Pre-declare refresh" translate="no">​</a></h2>
<p>The literal definition, copied from the canonical document:</p>
<blockquote>
<p><em>"A dedicated refresh PR lands between Charter-N close and Charter-(N+1) declare. It touches only the non-locked sections of the SpecKit artifacts (plan.md, data-model.md, contracts, quickstart.md, research.md)."</em></p>
</blockquote>
<p>This is exactly what Sentinel did manually for CHARTER-18 in Post 9. The difference between Post 9 and Post 10 is one of kind: Post 9 documents the procedure; Post 10 documents its <em>conditional activation</em> — when the framework recommends to the adopter that Pattern 1 should be applied.</p>
<p>The activation criteria are quantifiable, and the document names them without softening:</p>
<ul>
<li class="">The module has <strong>≥ 3 closed Charters</strong> on the same spec.</li>
<li class="">The rolling mean (last 3 Charters) of the <code>agent_quality.r_n_plus_one_emergent_count</code> field in telemetry is <strong>greater than 6</strong>.</li>
<li class="">No <em>refresh PR</em> has landed since the last <em>branch point</em>.</li>
</ul>
<p>The <code>&gt; 6</code> threshold isn't arbitrary. It's Sentinel CHARTER-18 turned into a rule: the average of emergent findings (risks discovered during the Charter that weren't declared in the original plan) during CHARTER-15, 16, 17 was exactly what triggered the feeling that the spec was accumulating too much debt. The framework, instead of asking the adopter to trust intuition, gives them a number their telemetry can compare against.</p>
<p>What Pattern 1 produces, when applied:</p>
<ul>
<li class="">A categorized table in <code>research.md</code> that enumerates what was discovered in prior Charters into four types: <em>reusable patterns</em>, <em>code gaps</em>, <em>discipline patterns</em>, <em>empirical corrections</em>.</li>
<li class="">Explicit operational decisions (<code>D1</code>, <code>D2</code>, etc.) if categorization shows trade-offs.</li>
<li class="">Citations in the next Charter's <code>§Context</code>, by <code>id</code>, pointing to the integrated items.</li>
<li class="">An opt-in <code>pre_declare_refresh:</code> telemetry block in the <code>charter-telemetry.yaml</code> of the Charter receiving the refresh.</li>
</ul>
<p>The metric that holds the pattern up comes from Sentinel CHARTER-18 itself, cited literally in <code>CHARTER-CHAIN-EVOLUTION.md</code>:</p>
<blockquote>
<p><em>"Sentinel CHARTER-18 was the first Charter in a 7-Charter chain to close cleanly without a mid-flight remediation Charter. <code>estimation_drift_factor: 1.0</code>, <code>pre_work.items_discovered_during_planning: 0</code>, <code>overall_satisfaction: 5/5</code>."</em></p>
</blockquote>
<p>One single domain. <code>N=1</code>. The document says so without shortcuts: the pattern is empirically validated <em>in Sentinel</em>. Wait for the second domain before crystallizing it higher.</p>
<hr>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="3-pattern-2--amend-on-emergence">3. Pattern 2 — Amend-on-emergence<a href="https://straymark.dev/blog/pattern-1-and-pattern-2-chain-evolution#3-pattern-2--amend-on-emergence" class="hash-link" aria-label="Direct link to 3. Pattern 2 — Amend-on-emergence" title="Direct link to 3. Pattern 2 — Amend-on-emergence" translate="no">​</a></h2>
<p>The literal definition:</p>
<blockquote>
<p><em>"The amendment rides the same execute branch as the original Charter (the branch is still mergeable to main; the amendment commit lands on top)."</em></p>
</blockquote>
<p>The idea: when a closed Charter receives post-close external audit findings — <em>critical</em> or <em>high</em> — the framework doesn't force opening a new Charter. The operator can <em>amend</em> the closed Charter while the <code>execute</code> branch is still mergeable to <code>main</code>.</p>
<p>The justification, also literal from the document:</p>
<blockquote>
<p><em>"A new Charter would have created multi-week governance overhead for ~6h of focused engineering."</em></p>
</blockquote>
<p>That asymmetry — weeks of governance vs. six hours of engineering — is what the pattern resolves. Opening a new Charter to fix five post-close findings means: declare new context, repeat external audit, generate new AILOG, register telemetry from scratch. For a correction that in code takes an afternoon. Pattern 2 says: no.</p>
<p>The activation criteria, also quantifiable:</p>
<ul>
<li class="">Critical/High <em>findings</em> appear post-close, after external audit.</li>
<li class="">The Charter's closure criterion was materially unmet by those findings.</li>
<li class="">The fix surface is under 25 files.</li>
<li class="">It doesn't require architectural reopening (design decisions the original Charter assumed closed).</li>
</ul>
<p>If all four criteria hold, Pattern 2 applies. If any fails, you have to open a new Charter.</p>
<p>What it produces, when applied:</p>
<ul>
<li class="">An <em>amendment</em> commit on the same <code>execute</code> branch as the original Charter.</li>
<li class="">A new AILOG (don't edit the original) with <code>risk_level: high</code>, <code>review_required: true</code>, and an <code>amends:</code> field pointing to the original AILOG.</li>
<li class="">A <code>## Historical correction (YYYY-MM-DD)</code> section in the original AILOG pointing <em>forward</em> to the new one. It's archival: the original AILOG isn't rewritten; it's linked.</li>
<li class="">A <code>post_close_amendment:</code> telemetry block in the <code>charter-telemetry.yaml</code>.</li>
</ul>
<p>The empirical metric backing Pattern 2, cited literally:</p>
<blockquote>
<p><em>"Sentinel CHARTER-18 closed 2026-05-15 with audit reports landing 2026-05-15..05-17. Five findings (4 from gpt-5.3-codex, 1 from gemini-2.5-pro) were code-level fixes — DI wiring, retry header parsing, multi-tenant filter, timeout default. The Batch 7.4 amendment closed all five in one cohesive commit (19 files, +2257/-106 lines)."</em></p>
</blockquote>
<p>One commit, 19 files, two auditor models converging on similar findings, five fixes. If it had been a new Charter: minimum two weeks between declare, external audit, and close. Instead: an <em>amendment</em> on the same branch, six hours.</p>
<hr>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="4-composition-not-exclusion">4. Composition, not exclusion<a href="https://straymark.dev/blog/pattern-1-and-pattern-2-chain-evolution#4-composition-not-exclusion" class="hash-link" aria-label="Direct link to 4. Composition, not exclusion" title="Direct link to 4. Composition, not exclusion" translate="no">​</a></h2>
<p>The most interesting piece of the document — and, I think, the one that best closes the arc — is the section on how the two patterns relate. Cited literally:</p>
<blockquote>
<p><em>"A Charter that received Pattern 1 is more likely to avoid Pattern 2, because the refresh absorbs pre-execution risk that would otherwise surface as post-close findings. But CHARTER-18 needed both — the refresh handled spec-level drift; the amendment handled runtime-level drift the refresh did not reach into."</em></p>
</blockquote>
<p>They aren't rival patterns. They're applications of the same principle at different moments of the cycle. Pattern 1 absorbs <em>spec-level</em> drift — what the original plan no longer describes correctly. Pattern 2 absorbs <em>runtime-level</em> drift — what only shows up once the code runs, external auditors look at it fresh, and it emerges from the code itself.</p>
<p>Sentinel CHARTER-18 needed both. The refreshed spec eliminated emergent findings a later audit cycle would have had to remediate atomically; the later <em>amendment</em> absorbed what the refresh couldn't have predicted — DI wiring, retry header parsing, a multi-tenant filter, a timeout default. Things the plan couldn't know and that only emerged when the code existed.</p>
<p>The framework, by naming the two patterns and explicitly declaring their composition, does something I want to underline: it puts on record that discipline isn't linear. There isn't a single inspection point before each Charter; there's one before (Pattern 1) and one after (Pattern 2), and both may be necessary in the same Charter. The chain evolves; the patterns evolve too.</p>
<hr>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="5-the-schema-and-the-helpers">5. The schema and the helpers<a href="https://straymark.dev/blog/pattern-1-and-pattern-2-chain-evolution#5-the-schema-and-the-helpers" class="hash-link" aria-label="Direct link to 5. The schema and the helpers" title="Direct link to 5. The schema and the helpers" translate="no">​</a></h2>
<p>What <code>fw-4.16.0</code> added to the telemetry schema are two optional sub-objects in <code>charter-telemetry.schema.v0.json</code> v0.2:</p>
<div class="language-yaml codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-yaml codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token key atrule" style="color:#00a4db">pre_declare_refresh</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token key atrule" style="color:#00a4db">enabled</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> boolean</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token key atrule" style="color:#00a4db">refresh_pr</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> string </span><span class="token punctuation" style="color:#393A34">|</span><span class="token plain"> null</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token key atrule" style="color:#00a4db">refresh_aidec</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> string </span><span class="token punctuation" style="color:#393A34">|</span><span class="token plain"> null</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token key atrule" style="color:#00a4db">reusable_patterns_integrated</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> integer  </span><span class="token comment" style="color:#999988;font-style:italic"># ≥ 0</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token key atrule" style="color:#00a4db">code_gaps_integrated</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> integer</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token key atrule" style="color:#00a4db">discipline_patterns_integrated</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> integer</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token key atrule" style="color:#00a4db">empirical_corrections_integrated</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> integer</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token key atrule" style="color:#00a4db">operator_decisions_ratified</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> integer</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token key atrule" style="color:#00a4db">post_close_amendment</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token key atrule" style="color:#00a4db">applied</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> boolean</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token key atrule" style="color:#00a4db">trigger</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> external_audit </span><span class="token punctuation" style="color:#393A34">|</span><span class="token plain"> production_incident </span><span class="token punctuation" style="color:#393A34">|</span><span class="token plain"> deferred_implementation</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token key atrule" style="color:#00a4db">ailog_id</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> string</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token key atrule" style="color:#00a4db">findings_closed</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> integer</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token key atrule" style="color:#00a4db">files_modified</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> integer</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token key atrule" style="color:#00a4db">effort_hours</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> number</span><br></div></code></pre></div></div>
<p>Integer counters, not narratives. The decision is deliberate: what the telemetry schema captures is what the agent or operator can count mechanically. What can't be counted — <em>how deep the problem was, how clever the fix was</em> — lives in the AILOG, not in telemetry. The schema measures the <em>shape</em> of work; the documents carry the <em>content</em>.</p>
<p>And <code>cli-3.14.0</code> added two helpers, neither mutator:</p>
<ul>
<li class="">
<p><strong><code>straymark charter refresh-suggest &lt;module&gt; [--threshold N]</code></strong> — <em>read-only</em>. It reads the telemetry of the last three closed Charters of the module, computes the rolling mean of <code>r_n_plus_one_emergent_count</code>, and emits a recommendation: <em>refresh-now</em>, <em>not-needed</em>, or <em>insufficient-data</em>. <em>Exit 0</em> always. It's informational, never a CI gate.</p>
</li>
<li class="">
<p><strong><code>straymark charter amend &lt;CHARTER-ID&gt; --trigger &lt;kind&gt; --ailog-title &lt;title&gt; [--findings-closed N] [--merge-into &lt;PATH&gt;]</code></strong> — scaffolding. It creates an AILOG stub with the correct fields (<code>risk_level: high</code>, <code>review_required: true</code>, <code>amends:</code> pointing to the original), adds the <code>## Historical correction</code> section to the original AILOG, and renders the <code>post_close_amendment:</code> YAML block. <strong>Doesn't touch git.</strong></p>
</li>
</ul>
<p>Keeping the two helpers humble — one only recommends, the other only prepares — is consistent with the A1 decision of Post 4: <em>"the CLI orchestrates but doesn't invoke APIs"</em>. Here: the CLI suggests but doesn't decide; scaffolds but doesn't mutate. The human remains the point where discipline happens. The framework only puts the tools within reach.</p>
<hr>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="6-seventy-seven-minutes-later">6. Seventy-seven minutes later<a href="https://straymark.dev/blog/pattern-1-and-pattern-2-chain-evolution#6-seventy-seven-minutes-later" class="hash-link" aria-label="Direct link to 6. Seventy-seven minutes later" title="Direct link to 6. Seventy-seven minutes later" translate="no">​</a></h2>
<p>There's one more piece worth recording before the arc's closing. PR #157 merged at 00:31 UTC on 16 May. PR #160 — the one from Post 1, <code>EMERGENT-OBSERVATION-DESIGN.md</code>, fw-4.17.0 — merged at 01:48 UTC the same day. Seventy-seven minutes later.</p>
<p>What happened in those seventy-seven minutes is the inverted closing of the arc. The philosophical meta-pattern Post 1 named — <em>emergent observation composed of formal links plus cultural permission to flag</em> — crystallized <strong>one hour and seventeen minutes</strong> after the two operational meta-patterns of this post. The philosophical meta-pattern doesn't precede the discipline; it succeeds it. It's the ascending reading of the same evidence.</p>
<p><code>CHARTER-CHAIN-EVOLUTION.md</code> records it explicitly in its <code>§Related</code> section:</p>
<blockquote>
<p><em>"EMERGENT-OBSERVATION-DESIGN.md — the meta-pattern of which Pattern 1 and Pattern 2 are applications (formal cross-referencing + cultural permission to surface)."</em></p>
</blockquote>
<p>Pattern 1 is composition of formal links (the <code>r_n_plus_one_emergent_count</code> telemetry, the citations by <code>id</code> in <code>§Context</code>, the categorized AILOGs) with cultural permission (the rule that an agent should flag drift between spec and code when it finds it). Pattern 2 is similar composition (the AILOGs with <code>amends:</code>, the <code>Historical correction</code> section linking <em>forward</em>) with permission to flag post-close findings instead of absorbing them in silence. The two patterns are applications of the same cultural+structural principle that Post 1 named from above.</p>
<p>It's an ending I keep liking: the blog that opened saying <em>"the agent saw something nobody asked it to see"</em> closes saying, in the chronologically preceding episode, <em>"here are the two things the agent can see well because the framework names them"</em>.</p>
<hr>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="7-closing-the-arc">7. Closing the arc<a href="https://straymark.dev/blog/pattern-1-and-pattern-2-chain-evolution#7-closing-the-arc" class="hash-link" aria-label="Direct link to 7. Closing the arc" title="Direct link to 7. Closing the arc" translate="no">​</a></h2>
<p>Ten posts. Eleven episodes covered (<code>H-01</code> through <code>H-13</code>, with several bundled). One editorial decision — retroactive publication — that Post 2 introduced and the nine following posts honored without violating it. A bilingual commitment that held at every close.</p>
<p>Some things I learned writing the blog and that are worth recording before closing it:</p>
<ol>
<li class="">
<p><strong>The pattern is born of the discipline.</strong> The phrase already appeared in Post 9, but the entire arc holds it. The meta-patterns of this post weren't designed; they were extracted. Each documented milestone had its operational episode first and its name after.</p>
</li>
<li class="">
<p><strong>The cadence isn't uniform.</strong> Nineteen days between the first commit (Post 2, 27 January) and the first bounded unit with external audit (Post 3, 25 April). Five hours between applied discipline and canonized discipline (Post 9, 14 May). Seventy-seven minutes between two meta-patterns and their philosophical reading (Posts 10 and 1, 16 May). The project went through every speed, and the blog records them all.</p>
</li>
<li class="">
<p><strong>The framework isn't neutral with respect to its adopter.</strong> Sentinel made it possible for each pattern to be empirically validated before being crystallized. The blog doesn't hide that provenance; it underlines it as a methodological precondition.</p>
</li>
<li class="">
<p><strong>What isn't named, isn't seen.</strong> Post 5 formulated it as <em>structural visibility</em>; Post 7 applied it to transversal debt; Post 8 pointed it out about the language outlier. It's the most persistent regularity of the arc. Existing as a technical artifact isn't enough. The name activates the artifact.</p>
</li>
</ol>
<p>The arc the blog came to tell — milestones <code>H-01</code> to <code>H-13</code>, the four names of the project, the six Plans, the first-class Charters, the external audit cycle, Issue #113, the rebrand to StrayMark, the TDE, the audit-prompt outlier, the manual discipline, and the two meta-patterns — closes here. What's left as explicit debt: <code>H-14</code>, the <code>straymark explore</code> TUI (which appeared laterally in Post 8 as a visibility tool), and the candidate milestones <code>H-?-A</code> to <code>H-?-E</code> that <code>PLAN-INVESTIGACION.md §1.43-55</code> listed as pending. Possible future second batch. No promise.</p>
<p>One last observation, symmetric to Post 1. That post opened saying: <em>"the agent saw something nobody asked it to see"</em>. What the blog closes by recording, after ten episodes, is the other half of the sentence: the agent saw because the framework had put it in conditions to see. The emergent observation of Post 1 is the proof; the named patterns of this post are the preconditions. Every thing the agent surfaced during the four months the arc covers was possible because some prior episode had put an artifact, a trigger, a formal link, a visible surface where there was nothing before.</p>
<p>The blog finishes telling the story. The framework goes on.</p>
<hr>
<p><em>Anchors: <a href="https://github.com/StrangeDaysTech/straymark/issues/156" target="_blank" rel="noopener noreferrer" class="">Issue #156</a>. PR <a href="https://github.com/StrangeDaysTech/straymark/pull/157" target="_blank" rel="noopener noreferrer" class="">#157</a> — <code>fw-4.16.0 / cli-3.14.0</code> (merged 2026-05-16 00:31 UTC). Canonical document: <a href="https://github.com/StrangeDaysTech/straymark/blob/main/dist/.straymark/00-governance/CHARTER-CHAIN-EVOLUTION.md" target="_blank" rel="noopener noreferrer" class=""><code>CHARTER-CHAIN-EVOLUTION.md</code></a>. Schema: <code>dist/.straymark/schemas/charter-telemetry.schema.v0.json</code> v0.2. Successor meta-pattern: <a href="https://github.com/StrangeDaysTech/straymark/blob/main/dist/.straymark/00-governance/EMERGENT-OBSERVATION-DESIGN.md" target="_blank" rel="noopener noreferrer" class=""><code>EMERGENT-OBSERVATION-DESIGN.md</code></a>, <code>fw-4.17.0</code> (merged 2026-05-16 01:48 UTC, 77 minutes later).</em></p>
<p><em>This document was produced with assistance from generative AI tools (Claude 4.7); all responsibility for the content rests with the human author.</em></p>
<p><em>— End of the H-01 → H-13 arc of the StrayMark blog.</em></p>]]></content>
        <author>
            <name>José Villaseñor Montfort</name>
            <uri>https://github.com/montfort</uri>
        </author>
        <category label="straymark" term="straymark"/>
        <category label="charters" term="charters"/>
        <category label="chain-evolution" term="chain-evolution"/>
        <category label="governance" term="governance"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[AGENTS.md as a universal standard]]></title>
        <id>https://straymark.dev/blog/agents-md-as-a-universal-standard</id>
        <link href="https://straymark.dev/blog/agents-md-as-a-universal-standard"/>
        <updated>2026-05-15T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[Four months between the intuition and the open standard]]></summary>
        <content type="html"><![CDATA[<p><em>Four months between the project's first AIDEC — "AI agents are a single technical audience" — and the open standard that operationalized it. <code>AGENTS.md</code> at the repo root, read by fifteen vendor CLIs, replacing the proliferation of CLAUDE.md / GEMINI.md / .cursorrules and a dozen more.</em></p>
<!-- -->
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="1-four-months-between-intuition-and-standard">1. Four months between intuition and standard<a href="https://straymark.dev/blog/agents-md-as-a-universal-standard#1-four-months-between-intuition-and-standard" class="hash-link" aria-label="Direct link to 1. Four months between intuition and standard" title="Direct link to 1. Four months between intuition and standard" translate="no">​</a></h2>
<p>On 15 May 2026, at 19:05 UTC, PR <a href="https://github.com/StrangeDaysTech/straymark/pull/155" target="_blank" rel="noopener noreferrer" class="">#155</a> closed the framework as <code>fw-4.15.0 / cli-3.13.2</code>. What it brought is a single new file in the list of directives the CLI injects: <code>AGENTS.md</code>, at the adopter's repo root, parallel to the ones already there (<code>CLAUDE.md</code>, <code>GEMINI.md</code>, <code>.github/copilot-instructions.md</code>, <code>.cursorrules</code>, <code>.cursor/rules/straymark.md</code>).</p>
<p>This would be trivial if it weren't for the fact that exactly four months earlier, on 27 January 2026, the project's first AIDEC — the one Post 2 covered with the typo'd-year anecdote — had declared:</p>
<blockquote>
<p><em>"AI agents (Claude, Gemini, Copilot, Cursor) process instructions equally well in any language, so translating their config files provides no functional benefit."</em></p>
</blockquote>
<p>That sentence, written six hours after the project's <em>initial commit</em>, contained an intuition the framework had been operationalizing ever since: agents are a single technical audience. Config files (<code>CLAUDE.md</code>, etc.) stayed in English (while human documentation got translated into three languages) because the "AI agents" audience didn't benefit from translation. What was missing to close that intuition was giving it a single place to point at, without having to clone the file four or five times for each different vendor.</p>
<p>This post covers exactly that: how <code>AGENTS.md</code> — an open standard donated to the Agentic AI Foundation in December 2025 — completed four months later the decision the first AIDEC had opened in January.</p>
<hr>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="2-the-fragmentation-agentsmd-resolves">2. The fragmentation <code>AGENTS.md</code> resolves<a href="https://straymark.dev/blog/agents-md-as-a-universal-standard#2-the-fragmentation-agentsmd-resolves" class="hash-link" aria-label="Direct link to 2-the-fragmentation-agentsmd-resolves" title="Direct link to 2-the-fragmentation-agentsmd-resolves" translate="no">​</a></h2>
<p>Between 2024 and 2026, while AI agent CLIs proliferated, each one invented its own instruction-file format:</p>
<ul>
<li class="">Anthropic published <code>CLAUDE.md</code> with the first version of Claude Code.</li>
<li class="">Google adopted <code>GEMINI.md</code> for Gemini CLI.</li>
<li class="">GitHub established <code>.github/copilot-instructions.md</code> for Copilot CLI.</li>
<li class="">Cursor started with <code>.cursorrules</code> and later migrated to <code>.cursor/rules/*.md</code>.</li>
<li class="">OpenAI used another path for Codex CLI; Aider, Devin, Continue, Roo Code, Factory Droids, Sourcegraph Amp, Zed AI, Windsurf, Amazon Q each had their own.</li>
</ul>
<p>A StrayMark adopter using two or three of those CLIs had to maintain two or three copies of the same content, hand-synced, hoping none diverged. Up to <code>fw-4.14.x</code>, the framework acknowledged that fragmentation in its <code>straymark init</code> command: it injected into the five most common vendor-specific files. But the other ten or fifteen CLIs were left out. The adopter handled them by copying content by hand.</p>
<p>In late 2025, the community of open-source projects producing agent CLIs did what gets done when a fragmentation becomes costly: they agreed on a standard. <code>AGENTS.md</code> at the repo root, read by everyone. The donation to the Agentic AI Foundation (Linux Foundation, December 2025) gave it institutional governance. The specification is deliberately minimal: a Markdown file, no imposed schema, in a predictable location. What each CLI does with that file is its own business; the canonical question — <em>"where is the agent configuration for this repo?"</em> — now has a single answer.</p>
<p>By May 2026, the list of CLIs that read <code>AGENTS.md</code> includes (cited literally from the PR #155 body):</p>
<blockquote>
<p><em>"Claude Code, OpenAI Codex CLI, Cursor, Aider, Devin, Sourcegraph Amp, Google Jules, Zed AI, Continue, Roo Code, Factory Droids, GitHub Copilot, Gemini CLI, Windsurf, Amazon Q and others."</em></p>
</blockquote>
<p>Fifteen CLIs. Some still read <em>also</em> their vendor-specific files for historical compatibility. But all fifteen know to look for <code>AGENTS.md</code> first.</p>
<hr>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="3-adopt-without-killing-your-own">3. Adopt without killing your own<a href="https://straymark.dev/blog/agents-md-as-a-universal-standard#3-adopt-without-killing-your-own" class="hash-link" aria-label="Direct link to 3. Adopt without killing your own" title="Direct link to 3. Adopt without killing your own" translate="no">​</a></h2>
<p>The most interesting decision of <code>fw-4.15.0</code> isn't adopting <code>AGENTS.md</code>; that was inevitable once the standard had critical mass. What's interesting is <em>how</em>. The PR body articulates it without softening:</p>
<blockquote>
<p><em>"Parallel to CLAUDE.md / GEMINI.md: marker block points to STRAYMARK.md, with a minimum-viable body below for readers that cannot follow relative links."</em></p>
</blockquote>
<p>Three key words: <strong>parallel</strong>, <strong>marker block</strong>, <strong>minimum-viable body</strong>.</p>
<p><em>Parallel</em> means <code>AGENTS.md</code> doesn't replace vendor-specific files. It coexists. The framework still injects <code>CLAUDE.md</code>, <code>GEMINI.md</code>, <code>.cursorrules</code> and the others. The reason is pragmatic: some CLIs (notably Cursor in its legacy version) require the full content to be embedded, not behind a relative link. Keeping the sibling files preserves that compatibility without each adopter having to wrestle with their specific CLI.</p>
<p><em>Marker block</em> is the convention the framework already used in the other vendor-specific files: an HTML-commented block between <code>&lt;!-- straymark:begin --&gt;</code> and <code>&lt;!-- straymark:end --&gt;</code> pointing to <code>STRAYMARK.md</code> as source-of-truth. Any <code>straymark update-framework</code> replaces only what's between those markers. Whatever the adopter wrote <em>outside</em> them — for instance, project-specific instructions — stays intact. The framework respects the adopter's file; it only governs its own section.</p>
<p><em>Minimum-viable body</em> is the concession to CLIs that don't follow relative links. Below the marker block, <code>AGENTS.md</code> carries a short body with the essentials: agent identity, review requirements, pre-commit checklist, regulatory frontmatter snippet, NIST AI 600-1 risk categories, observability rules, naming convention. It's enough for an agent that can't read <code>STRAYMARK.md</code> to operate correctly; it's insufficient to replace the canonical document. The asymmetry is deliberate: we want the agent to <em>want</em> to open <code>STRAYMARK.md</code>.</p>
<p>The defensive CLI detail (<code>cli/src/commands/remove.rs:13</code>) closes the operational flank: <code>AGENTS.md</code> was added to <code>LEGACY_DIRECTIVE_TARGETS</code>. If an adopter loses their <code>.straymark/dist-manifest.yml</code> and runs <code>straymark remove</code>, the legacy fallback cleans <code>AGENTS.md</code> too instead of leaving it orphaned. It's boring housekeeping, but it's the difference between a framework that uninstalls completely and one that leaves debris.</p>
<hr>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="4-no-adr">4. No ADR<a href="https://straymark.dev/blog/agents-md-as-a-universal-standard#4-no-adr" class="hash-link" aria-label="Direct link to 4. No ADR" title="Direct link to 4. No ADR" translate="no">​</a></h2>
<p>It's worth naming an absence. The decision to adopt <code>AGENTS.md</code> did not get its own ADR.</p>
<p>It's a deliberate contrast with Post 6's StrayMark rebrand, which did have a public <code>ADR-2026-05-08-001</code> with three evaluated alternatives and enumerated consequences. It's also a contrast with Post 12's Phase 2, which had a dense CHANGELOG entry with architectural justification. <code>fw-4.15.0</code> had only the PR body as documentary justification — a good body, with a clear argument, but not an ADR.</p>
<p>Why? The operational answer: the decision was perceived as <strong>additive</strong>, not structural. Adopting an open standard that coexists with existing formats doesn't change the framework's model; it only extends it. There's no alternative whose dismissal would require formal justification: not adopting <code>AGENTS.md</code> would mean leaving fifteen CLIs out for aesthetic preference, and nobody had that argument to make.</p>
<p>But there's a recordable lesson here. The blog has seen the pattern before — Phase 2 closes an empirical loop, the rebrand changes identity, Post 10's meta-patterns name what was already there — and in each case the question <em>"does this deserve an ADR?"</em> has a different answer. The operational rule the framework seems to have adopted, without naming it, is this: <strong>an ADR is justified when the decision closes costly alternatives and leaves a record of those not chosen</strong>. <code>fw-4.15.0</code> didn't close costly alternatives — it only added a layer. So the PR was enough.</p>
<p>I leave it on the record here because it's worth acknowledging that not every change deserves an ADR, nor is every PR a historical document. Archival discipline has its own criteria.</p>
<hr>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="5-visibility-for-agents-two-layers">5. Visibility for agents, two layers<a href="https://straymark.dev/blog/agents-md-as-a-universal-standard#5-visibility-for-agents-two-layers" class="hash-link" aria-label="Direct link to 5. Visibility for agents, two layers" title="Direct link to 5. Visibility for agents, two layers" translate="no">​</a></h2>
<p>Ten days before <code>fw-4.15.0</code>, on 9 May, Issue <a href="https://github.com/StrangeDaysTech/straymark/issues/113" target="_blank" rel="noopener noreferrer" class="">#113</a> was closed — the episode Post 5 documented as <em>"Charters invisible to the agents"</em>. The operator had worked six hours with a capable, attentive agent, with the canonical onboarding apparatus loaded, and the agent had never proposed using a Charter. The conclusion that post canonized: <em>structural visibility</em> is the framework's responsibility, not the agent's property.</p>
<p><code>fw-4.15.0</code> covers the other face of the same problem.</p>
<p>Post 5 was about <strong>internal structural visibility</strong>: how we ensure an agent already reading our repo discovers the framework's core concepts. PR #122's answer (Post 5) was to multiply the internal surfaces where Charter appears as a concept: <code>STRAYMARK.md §15</code>, <code>CLAUDE.md</code>/<code>GEMINI.md</code> directives, <code>/straymark-*</code> skills, <code>status</code> output, templates, the bridge to SpecKit. Nine internal surfaces.</p>
<p>This post is about <strong>external structural visibility</strong>: how we ensure any agent entering the repo, whatever its vendor, finds the framework's apparatus. <code>fw-4.15.0</code>'s answer is to adopt the canonical meeting point the community chose. One external surface, read by fifteen vendors.</p>
<p>Both layers share the same conceptual axis — <em>a technical artifact only exists for the agent if the surface names it</em> — but a different scope. Internal visibility guarantees the agent sees the Charters while reading <code>STRAYMARK.md</code>. External visibility guarantees the agent sees <code>STRAYMARK.md</code> when entering the repo. One layer without the other is incomplete.</p>
<hr>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="6-what-the-adopter-does-when-running-update-framework">6. What the adopter does when running <code>update-framework</code><a href="https://straymark.dev/blog/agents-md-as-a-universal-standard#6-what-the-adopter-does-when-running-update-framework" class="hash-link" aria-label="Direct link to 6-what-the-adopter-does-when-running-update-framework" title="Direct link to 6-what-the-adopter-does-when-running-update-framework" translate="no">​</a></h2>
<p>The operational part of the release, cited literally from the CHANGELOG:</p>
<blockquote>
<p><em>"straymark update-framework brings the new template and injects AGENTS.md at the project root. The injection follows the same rules as every other directive target: it creates the file if absent, replaces the marker block on subsequent runs, and appends safely when the file pre-exists without StrayMark markers (very common in 2026 — many adopters already hand-maintain an AGENTS.md)."</em></p>
</blockquote>
<p>Three important behaviors:</p>
<ol>
<li class=""><strong>If it doesn't exist</strong>, the CLI creates it with the canonical template.</li>
<li class=""><strong>If it already exists with StrayMark markers</strong>, the CLI replaces only the content between markers.</li>
<li class=""><strong>If it already exists without markers</strong> — very common in 2026, because many adopters were already writing their own <code>AGENTS.md</code> by hand — the CLI <strong>appends its markers at the end of the file</strong>, without touching what the adopter had written.</li>
</ol>
<p>It's the same archival respect the blog already documented in Posts 3 and 6: the framework governs <em>its section</em>, not the whole file. If the adopter wants to write project-specific instructions in their <code>AGENTS.md</code> — internal policies, naming conventions, instructions specific to a particular codebase — those instructions stay intact at every <code>update</code>. The StrayMark block lives within its small marked boundary, and updates within that boundary.</p>
<p>The CHANGELOG note closes with a small operational warning worth recording: <em>"If your .gitignore excludes AGENTS.md, adjust it before update-framework so the injection lands in version control."</em> It's honest about edge cases the framework can't resolve on its own — the adopter's choice to ignore the file is sovereignty, not error.</p>
<hr>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="7-closing">7. Closing<a href="https://straymark.dev/blog/agents-md-as-a-universal-standard#7-closing" class="hash-link" aria-label="Direct link to 7. Closing" title="Direct link to 7. Closing" translate="no">​</a></h2>
<p>What I took from the process, in four claims:</p>
<ol>
<li class="">
<p><strong>Four months between intuition and materialization is what it takes to close a loop well.</strong> January's AIDEC carried the intuition — <em>"agents are a single audience"</em>. <code>fw-4.15.0</code> closed it with an open standard. Between the two, the framework iterated on vendor-specific archetypes until the universal substitute appeared. The early intuition was right; the timeline was what the ecosystem's maturation required.</p>
</li>
<li class="">
<p><strong>Adopting an open standard doesn't require renouncing your own format.</strong> <code>AGENTS.md</code> coexists with <code>CLAUDE.md</code>, <code>GEMINI.md</code>, <code>.cursorrules</code>. The decision isn't "one replaces the others" but "one joins the others when it contributes". The framework gains external visibility without losing compatibility with CLIs that require specific formats.</p>
</li>
<li class="">
<p><strong>Not every change deserves an ADR.</strong> The StrayMark rebrand closed costly alternatives and left a formal record of the discarded ones. <code>fw-4.15.0</code> only added a universal layer: no ADR would have enriched the decision. Archival discipline has operational criteria, not doctrines.</p>
</li>
<li class="">
<p><strong>Visibility for agents operates in two layers.</strong> The internal layer (Post 5, <code>fw-4.12.0</code>) ensures the agent sees the framework's concepts while reading the repo. The external layer (<code>fw-4.15.0</code>) ensures the agent enters the repo through the right door regardless of which CLI orchestrates it. One without the other leaves either capable agents reading in silence or disoriented agents with no entry point.</p>
</li>
</ol>
<hr>
<p><em>Anchors: PR <a href="https://github.com/StrangeDaysTech/straymark/pull/155" target="_blank" rel="noopener noreferrer" class="">#155</a> — <code>fw-4.15.0 / cli-3.13.2</code> (merged 2026-05-15 19:05 UTC). Original AIDEC (Post 2): <code>.chronicle/07-ai-audit/decisions/AIDEC-2025-01-27-001-i18n-strategy.md</code> (commit <code>7b7193e</code>, ID with typo'd year). Injected template: <code>dist/dist-templates/directives/AGENTS.md</code>. Standard specification: <a href="https://agents.md/" target="_blank" rel="noopener noreferrer" class="">agents.md</a> — donated to the Agentic AI Foundation (Linux Foundation), December 2025.</em></p>
<p><em>This document was produced with assistance from generative AI tools (Claude 4.7); all responsibility for the content rests with the human author.</em></p>]]></content>
        <author>
            <name>José Villaseñor Montfort</name>
            <uri>https://github.com/montfort</uri>
        </author>
        <category label="straymark" term="straymark"/>
        <category label="agents-md" term="agents-md"/>
        <category label="governance" term="governance"/>
        <category label="open-standards" term="open-standards"/>
        <category label="i18n" term="i18n"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[Opening the framework]]></title>
        <id>https://straymark.dev/blog/opening-the-framework</id>
        <link href="https://straymark.dev/blog/opening-the-framework"/>
        <updated>2026-05-15T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[Seventy-two hours of gestures that only make sense together]]></summary>
        <content type="html"><![CDATA[<p><em>Two gestures in seventy-two hours: closing the last 5% of i18n parity (20/20/20 governance docs across EN + ES + zh-CN) and publishing the CLA badge in the README. Small separately; together, the moment the framework stops talking to itself and starts talking to whoever wants to read it.</em></p>
<!-- -->
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="1-two-gestures-in-seventy-two-hours">1. Two gestures in seventy-two hours<a href="https://straymark.dev/blog/opening-the-framework#1-two-gestures-in-seventy-two-hours" class="hash-link" aria-label="Direct link to 1. Two gestures in seventy-two hours" title="Direct link to 1. Two gestures in seventy-two hours" translate="no">​</a></h2>
<p>On 13 May 2026, at 06:20 UTC, <code>fw-4.13.4</code> merged. It closed two small i18n coverage gaps — the ISO-25010 reference document that was only in English, and the Charter template that was missing in Simplified Chinese. Twenty-two canonical framework files reached structural EN/ES/zh-CN parity.</p>
<p>On 15 May, at 00:14 UTC, sixty-five hours later, PR <a href="https://github.com/StrangeDaysTech/straymark/pull/154" target="_blank" rel="noopener noreferrer" class="">#154</a> merged. It added a badge to the README — the CLA Assistant one, that small visible square that tells the visitor the repo accepts contributions under a Contributor License Agreement. The CLA policy had existed for months already in <code>CONTRIBUTING.md</code>; the only thing that changed was that it now appears in the README at first glance.</p>
<p>This post covers the two gestures. Seen separately, they're small — one completes the last 5% of a technical job, the other publishes something that was already there. Seen together, they're the moment the framework decides to present itself to the outside. The piece an open-source project does when it stops talking to itself and starts talking to whoever wants to read it.</p>
<hr>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="2-the-last-5-of-i18n-coverage">2. The last 5% of i18n coverage<a href="https://straymark.dev/blog/opening-the-framework#2-the-last-5-of-i18n-coverage" class="hash-link" aria-label="Direct link to 2. The last 5% of i18n coverage" title="Direct link to 2. The last 5% of i18n coverage" translate="no">​</a></h2>
<p><code>fw-4.13.4</code> isn't a big release. PR <a href="https://github.com/StrangeDaysTech/straymark/pull/144" target="_blank" rel="noopener noreferrer" class="">#144</a> has 511 addition lines and almost all are translations. But the PR summary says something worth recording:</p>
<blockquote>
<p><em>"Brings governance docs to full 20/20/20 parity across EN + ES + zh-CN."</em></p>
</blockquote>
<p>Twenty over twenty over twenty. Twenty-two canonical files in <code>dist/.straymark/00-governance/</code> (the count grew later; in May it was twenty), all with their counterpart in <code>i18n/es/</code> and <code>i18n/zh-CN/</code>. Full parity, not approximate.</p>
<p>The two files that closed parity are specific:</p>
<ul>
<li class=""><code>ISO-25010-2023-REFERENCE.md</code> — the normative reference to the international software quality standard, cited from framework principles. Up to <code>fw-4.13.4</code> it existed only in English. The release added <code>i18n/es/ISO-25010-2023-REFERENCE.md</code> and <code>i18n/zh-CN/ISO-25010-2023-REFERENCE.md</code>, 150 lines each.</li>
<li class=""><code>charter-template.md</code> in zh-CN. The Charter template was already translated into Spanish; Simplified Chinese was missing, 211 lines.</li>
</ul>
<p>It's not glamorous work. It's the piece that closes a frame. But it matters for two things. First: until that release, a Chinese adopter cloning the framework was going to find essential templates in English only, which contradicts the promise that the framework is available in three languages. Second: the blog already documented in Post 8 that the framework's i18n coverage was nearly complete, with two minor gaps remaining as recorded debt. <code>fw-4.13.4</code> closed that debt. What looked like a side note in a post about the audit-prompt outlier turned out to be a release of its own, with its own CHANGELOG entry.</p>
<hr>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="3-what-gets-translated-and-what-doesnt">3. What gets translated and what doesn't<a href="https://straymark.dev/blog/opening-the-framework#3-what-gets-translated-and-what-doesnt" class="hash-link" aria-label="Direct link to 3. What gets translated and what doesn't" title="Direct link to 3. What gets translated and what doesn't" translate="no">​</a></h2>
<p>There's an operational rule that PR #144 codifies explicitly and that's worth recording, because it's the framework's clearest rule on i18n:</p>
<blockquote>
<p><em>"LLM-processed assets (skills, workflows, schemas) stay EN-only; human-primary artifacts get translated."</em></p>
</blockquote>
<p>That is: what AI agents read — skills, workflows in <code>.claude/</code>, <code>.gemini/</code>, <code>.agent/</code>, schemas in <code>dist/.straymark/schemas/</code>, prompts in <code>dist/.straymark/audit-prompts/</code> — lives in English only. What humans read — documentation, principles, contribution guides, templates with human-facing copy — gets translated into the three languages.</p>
<p>It's the same principle Post 13 documented as the intellectual ancestor of the universal <code>AGENTS.md</code>: agents are a single technical audience that doesn't benefit from translation. What's recordable here is that the rule, in May, is written into a PR as an operational criterion, not as an intuition. Technical proposals cite it; reviewers use it to decide whether a new file goes into <code>i18n/</code> or not.</p>
<p>One additional detail from PR #144 is worth recording literally:</p>
<blockquote>
<p><em>"docs/contributors/TRANSLATION-GUIDE.md gap was left intentional — its target audience already reads English to read the guide."</em></p>
</blockquote>
<p>The translation guide stayed intentionally in English because its audience — contributors translating the framework into other languages — necessarily already reads English. It's operational honesty: 20/20/20 parity isn't 22/22/22 for every repo file. It's 20/20/20 for files whose translation adds user value. The difference between total coverage and applicable coverage.</p>
<hr>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="4-the-badge-that-introduced-nothing-new">4. The badge that introduced nothing new<a href="https://straymark.dev/blog/opening-the-framework#4-the-badge-that-introduced-nothing-new" class="hash-link" aria-label="Direct link to 4. The badge that introduced nothing new" title="Direct link to 4. The badge that introduced nothing new" translate="no">​</a></h2>
<p>PR #154 is the pedagogical opposite of <code>fw-4.13.4</code>. Where <code>fw-4.13.4</code> closes technical work, PR #154 publishes something that was already there. Its 12 lines of change add exactly this to the README (in English, Spanish, and Chinese):</p>
<div class="language-markdown codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-markdown codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token url" style="color:#36acaa">[</span><span class="token url content" style="color:#36acaa">![CLA assistant</span><span class="token url" style="color:#36acaa">](</span><span class="token url" style="color:#36acaa">https://cla-assistant.io/readme/badge/StrangeDaysTech/straymark</span><span class="token url" style="color:#36acaa">)</span><span class="token plain">](https://cla-assistant.io/StrangeDaysTech/straymark)</span><br></div></code></pre></div></div>
<p>A badge. A small image that appears above the README, next to the other project badges (license, version, downloads). Visually unremarkable.</p>
<p>But the badge isn't decoration. It's a signal. And the signal says something concrete: <em>"this repo accepts external contributions, and here are the rules"</em>. Any visitor who opens the README can click the badge and land at CLA Assistant — the service that automatically comments on any contributor's first pull request, asking them to sign the Contributor License Agreement. One signature covers all future contributions to the project.</p>
<p>What matters is that the CLA, the <code>CONTRIBUTING.md</code>, the full review policy, all of that existed before PR #154. It was coded, alive, operational. The framework already accepted external contributions — it's just that the casual repo visitor had to open <code>CONTRIBUTING.md</code> to find out how it worked.</p>
<p>PR #154 makes a distinction worth naming: <strong>having the policy</strong> and <strong>publishing the policy</strong> are two different things. The first is internal discipline; the second is a public invitation. Until 15 May, the framework had the policy. From 15 May, it publishes it.</p>
<p>It's an editorial change, not an architectural one. But the day an open-source project decides to put the CLA Assistant badge above the README is the day it decides to formally present itself as adoptable by third parties. It's the moment the framework stops being a one-developer-and-its-adopter (Sentinel) project and becomes a project that <em>accepts</em> having more adopters, more contributors, more hands.</p>
<hr>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="5-when-a-framework-feels-ready-to-be-seen">5. When a framework feels ready to be seen<a href="https://straymark.dev/blog/opening-the-framework#5-when-a-framework-feels-ready-to-be-seen" class="hash-link" aria-label="Direct link to 5. When a framework feels ready to be seen" title="Direct link to 5. When a framework feels ready to be seen" translate="no">​</a></h2>
<p>These two milestones, read together, record a specific moment in a young framework's life: the moment it feels ready to be seen by people who didn't write it.</p>
<p><code>fw-4.13.4</code> closes the technical promise. If the framework says it's bilingual Spanish-English with experimental Simplified Chinese support, the twenty-two canonical files must be in all three languages. Not nineteen out of twenty. Not twenty out of twenty-one with two pending. Twenty over twenty over twenty. Full parity is what makes the promise credible when the visitor checks.</p>
<p>PR #154 closes the social promise. If the framework says it accepts external contributions, the CLA badge in the README is the industry-standard way of saying so. Without the badge, the openness exists but you have to discover it; with the badge, it's signposted. The visitor's first click finds the path.</p>
<p>It's worth naming the asymmetry of the two gestures. Closing the last 5% of technical work costs exactly that — a dedicated release, two translated files, a CHANGELOG entry. Publishing a preexisting policy costs twelve lines of Markdown. The cheap one is sometimes the operationally most significant gesture, because it changes how the outside world perceives the project without changing anything about the project itself.</p>
<p>It's the "opening the framework" version of the pattern Post 5 documented as <em>structural visibility</em>: what exists but isn't named, doesn't exist for the agent. Here: what exists but isn't published, doesn't exist for the external adopter. Seventy-two hours in May, two small milestones — one technical, one editorial — and the framework crosses the line between <em>"it works but whoever wrote it knows it"</em> and <em>"it works and anyone can see it"</em>.</p>
<hr>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="6-symbolic-closing-of-the-arc">6. Symbolic closing of the arc<a href="https://straymark.dev/blog/opening-the-framework#6-symbolic-closing-of-the-arc" class="hash-link" aria-label="Direct link to 6. Symbolic closing of the arc" title="Direct link to 6. Symbolic closing of the arc" translate="no">​</a></h2>
<p>With this post, the blog covers the last pending milestones from the second batch that <code>RETOMAR-AQUI.md §5</code> listed after the closing of the main H-01 → H-13 arc. The four identified candidates — <code>H-?-C</code> (validate + schemas), <code>H-?-A</code> (universal AGENTS.md), <code>H-?-B</code> (full i18n coverage), <code>H-?-E</code> (CLA badge) — are all covered: three in their own posts (Posts 12, 13, this one) and one combined.</p>
<p>What I learned writing the second batch, looking at the four milestones together:</p>
<ul>
<li class=""><strong>Phase 2 / validate</strong> (Post 12) is structural: the framework starts to verify what it had been promising.</li>
<li class=""><strong>TUI explore</strong> (Post 11) is about visibility: the framework becomes navigable.</li>
<li class=""><strong>Universal AGENTS.md</strong> (Post 13) is about reach: the framework becomes discoverable by any CLI.</li>
<li class=""><strong>Full i18n coverage + CLA badge</strong> (this post) is about opening: the framework becomes visible to the external visitor.</li>
</ul>
<p>Each one covers a distinct dimension of the same idea, which the blog already encoded in earlier posts: what a framework says it is isn't enough for it to be; it has to be present on every surface where someone — agent, external adopter, visitor — can build a model of the project. The second batch's milestones are the mature version of the <em>structural visibility</em> Post 5 named with a governance Issue.</p>
<p>Now, after Post 14, there are no more candidates in the queue. If new framework milestones emerge between today and when the blog's next session activates, RETOMAR-AQUI will be used again as the resumption point. If none emerge, this post is the real closing — the closing that completes the inventory the blog set out to cover.</p>
<hr>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="7-closing">7. Closing<a href="https://straymark.dev/blog/opening-the-framework#7-closing" class="hash-link" aria-label="Direct link to 7. Closing" title="Direct link to 7. Closing" translate="no">​</a></h2>
<p>What I took from the process, in four claims:</p>
<ol>
<li class="">
<p><strong>Total coverage costs little at the end of the work and a lot at the beginning.</strong> The last 5% — those two files in Chinese — is a dedicated release. But it's only trivially closable because the other 95% was already done. 20/20/20 parity isn't born at the start; it's pursued for months and closed at the end with a small PR.</p>
</li>
<li class="">
<p><strong>Having a policy and publishing it are two different things.</strong> The framework's CLA existed months before the badge. Twelve lines of Markdown turned an internal policy into a public invitation. The day you put the badge you invent nothing; you declare you're ready to be found.</p>
</li>
<li class="">
<p><strong>The operational rule of what gets translated is archival.</strong> What humans read gets translated; what agents read lives in English. That distinction, intuited from January's first AIDEC, became an explicit review criterion in May. Every new framework file passes through that question before choosing its destination.</p>
</li>
<li class="">
<p><strong>When a framework becomes adoptable by third parties is a decision, not a state.</strong> There's a day when the operator decides the framework can be seen without embarrassment by people who didn't write it. That day materializes in small gestures — completing translations, publishing the badge — that don't change functionality but change posture. The framework stops talking to itself.</p>
</li>
</ol>
<p>With this the blog closes the second batch. The arc that started retroactively with the project's prehistory (Post 2, January) and completed with the meta-patterns (Post 10, May) now also has its corollary: the milestones that made the framework adoptable. Fourteen posts, twenty-eight files (fourteen ES + fourteen EN), between twenty-five and twenty-six thousand words per language. As the closing of Post 10 said: <em>the blog finishes telling the story. The framework goes on</em>.</p>
<hr>
<p><em>Anchors: PR <a href="https://github.com/StrangeDaysTech/straymark/pull/144" target="_blank" rel="noopener noreferrer" class="">#144</a> — <code>fw-4.13.4</code> (merged 2026-05-13 06:20 UTC, full i18n coverage). PR <a href="https://github.com/StrangeDaysTech/straymark/pull/154" target="_blank" rel="noopener noreferrer" class="">#154</a> — CLA Assistant badge in READMEs (merged 2026-05-15 00:14 UTC). Full policy: <code>CONTRIBUTING.md</code> (repo root + translations in <code>docs/i18n/{es,zh-CN}/CONTRIBUTING.md</code>).</em></p>
<p><em>This document was produced with assistance from generative AI tools (Claude 4.7); all responsibility for the content rests with the human author.</em></p>
<p><em>— End of the second batch of the StrayMark blog.</em></p>]]></content>
        <author>
            <name>José Villaseñor Montfort</name>
            <uri>https://github.com/montfort</uri>
        </author>
        <category label="straymark" term="straymark"/>
        <category label="i18n" term="i18n"/>
        <category label="cla" term="cla"/>
        <category label="governance" term="governance"/>
        <category label="opening" term="opening"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[Manual discipline before the pattern]]></title>
        <id>https://straymark.dev/blog/manual-discipline-before-the-pattern</id>
        <link href="https://straymark.dev/blog/manual-discipline-before-the-pattern"/>
        <updated>2026-05-14T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[Twelve learnings in an Issue, three gates in a PR, and a Charter that closed cleanly before the name existed]]></summary>
        <content type="html"><![CDATA[<p><em>Seven consecutive Charters on a one-month-old plan in Sentinel, executing CHARTER-18 by hand with the feeling that any false step would bury six Charters of work. Five hours to canonize the manual discipline as upstream governance — without naming the pattern yet.</em></p>
<!-- -->
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="1-the-right-question">1. The right question<a href="https://straymark.dev/blog/manual-discipline-before-the-pattern#1-the-right-question" class="hash-link" aria-label="Direct link to 1. The right question" title="Direct link to 1. The right question" translate="no">​</a></h2>
<p><a href="https://github.com/StrangeDaysTech/straymark/issues/150" target="_blank" rel="noopener noreferrer" class="">Issue #150</a>, opened on 14 May at 16:59 UTC, wasn't looking for a <em>yes/no</em>. What the operator was asking was for the question to be reframed:</p>
<blockquote>
<p><em>"The real question the bridge doc should address is how, not whether: what discipline ensures spec stays in sync with code during multi-Charter execution without the regeneration step lying about the parts that already shipped."</em></p>
</blockquote>
<p>The discipline already existed. It was being applied in Sentinel at that very moment, on <code>CHARTER-18</code>, by hand, with the feeling that any false step would bury the work of six previous Charters. What was missing — what the Issue documented with uncomfortable precision — was the name. The <em>when</em>. The rules a future adopter could follow without going through the pain of inventing them.</p>
<p>This post covers the five hours between that Issue and the PR that canonized the discipline as upstream governance, the 12 empirical learnings that justified the canonization, and the concrete operational episode — Sentinel's <code>CHARTER-18</code> — that exercised the pattern before the pattern existed. The next post will cover what came 27 hours later: the name.</p>
<hr>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="2-seven-charters-on-the-same-plan">2. Seven Charters on the same plan<a href="https://straymark.dev/blog/manual-discipline-before-the-pattern#2-seven-charters-on-the-same-plan" class="hash-link" aria-label="Direct link to 2. Seven Charters on the same plan" title="Direct link to 2. Seven Charters on the same plan" translate="no">​</a></h2>
<p>Context, in one line: Sentinel executed <code>specs/002-commshub/plan.md</code> — written in commit <code>be29421</code> on 21 April 2026 — through <strong>seven consecutive Charters</strong> (<code>CHARTER-07</code> through <code>CHARTER-17</code>), one calendar month, without refreshing the plan once.</p>
<p>The original plan was good. It was carefully written, with four user stories (US1-US4) detailed, the data-model declared, the contracts sketched. But the plan was a snapshot of how the operator imagined, back in April, the code would behave. Execution discovered things the plan couldn't have anticipated:</p>
<ul>
<li class="">Infrastructure patterns that appeared <em>during</em> execution and turned out to be reusable (a namespace in <code>core.processed_events</code>, a <code>withRLS</code> helper, PL/pgSQL triggers for invariants).</li>
<li class="">Code gaps the plan assumed resolved (<code>AnomalyDetector</code> <em>half-built</em>, missing idempotency dedup, <code>Recipient.TenantID</code> schema gap).</li>
<li class="">Charter/audit patterns that crystallized over the month (cross-family audit cycle, HTTP layer test coverage gap, cursor pagination with strict-greater-than).</li>
</ul>
<p>When the time came to plan <code>CHARTER-18</code> for US5, the plan was a month old and the code had a month of empirical learning on top. The two weren't in sync. And <code>SPECKIT-CHARTER-BRIDGE.md</code> — the framework document that would normally answer <em>"what do I do here?"</em> — was silent on the case. The rule <em>"how spec stays in sync with code during multi-Charter execution"</em> didn't exist yet.</p>
<hr>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="3-the-twelve-empirical-learnings">3. The twelve empirical learnings<a href="https://straymark.dev/blog/manual-discipline-before-the-pattern#3-the-twelve-empirical-learnings" class="hash-link" aria-label="Direct link to 3. The twelve empirical learnings" title="Direct link to 3. The twelve empirical learnings" translate="no">​</a></h2>
<p>Issue #150 enumerates the twelve learnings that had accumulated without reflection in the plan. The literal table, grouped by type, is worth keeping in view:</p>






































































<table><thead><tr><th>#</th><th>Type</th><th>Learning</th></tr></thead><tbody><tr><td>1</td><td>Infra pattern</td><td><code>core.processed_events</code> with namespace <code>module='commshub'</code> is reusable — plan describes its own table.</td></tr><tr><td>2</td><td>Infra pattern</td><td><code>EnvSecretLoader</code> + Secret Manager projection (PRs #70/71) — plan describes direct access.</td></tr><tr><td>3</td><td>Infra pattern</td><td><code>withRLS</code> helper as single-source-of-truth for tenant isolation — plan doesn't anchor it.</td></tr><tr><td>4</td><td>Infra pattern</td><td>FR-005 PL/pgSQL triggers as invariant enforcement — plan describes app-level checks.</td></tr><tr><td>5</td><td>Code gap</td><td><code>AnomalyDetector</code> <em>half-built</em> — plan implies functional.</td></tr><tr><td>6</td><td>Code gap</td><td>Idempotency dedup at <code>delivery_log</code> layer missing — plan implies coordinated.</td></tr><tr><td>7</td><td>Code gap</td><td><code>Recipient.TenantID</code> schema gap — plan references <code>tenant_id</code> as if it existed.</td></tr><tr><td>8</td><td>Code gap</td><td>Per-tier rate limit overrides absent — plan says <em>"3-tier hierarchy"</em> without mentioning US1 implemented a uniform tier.</td></tr><tr><td>9</td><td>Charter pattern</td><td>Cross-family external audit cycle mandatory (6 consecutive) — plan silent.</td></tr><tr><td>10</td><td>Charter pattern</td><td>HTTP layer test coverage gap — plan silent on test layering.</td></tr><tr><td>11</td><td>Charter pattern</td><td>Cursor pagination tuple with strict-greater-than — plan silent.</td></tr><tr><td>12</td><td>Charter pattern</td><td>Dispatcher interface-stable swap pattern — plan silent.</td></tr></tbody></table>
<p>Four infrastructure patterns discovered or refined during execution. Four code gaps the plan didn't anticipate. Four Charter/audit patterns crystallized on the fly. Twelve pieces, in a single month, all real. The plan didn't have them. And the next Charter — <code>CHARTER-18</code> — was going to read the plan as if they didn't exist.</p>
<p>The estimate the operator documented in the Issue is honest:</p>
<blockquote>
<p><em>"Estimated probability of ≥1 critical/high finding from stale-premise inheritance: ~50%."</em></p>
</blockquote>
<p>Coin flip, in one word. Half of Charters started on a stale plan end with a critical finding a later audit cycle has to remediate atomically pre-close. And the other half escape only by luck.</p>
<hr>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="4-alternative-4-the-discipline-applied-by-hand">4. Alternative 4: the discipline applied by hand<a href="https://straymark.dev/blog/manual-discipline-before-the-pattern#4-alternative-4-the-discipline-applied-by-hand" class="hash-link" aria-label="Direct link to 4. Alternative 4: the discipline applied by hand" title="Direct link to 4. Alternative 4: the discipline applied by hand" translate="no">​</a></h2>
<p>What happened inside Sentinel, that same day, before the discipline had a name: the operator evaluated five concrete alternatives and chose the fourth. Sentinel's private AIDEC — <code>AIDEC-2026-05-14-001-speckit-plan-scope-limited-us5-refresh.md</code> — records the analysis without softening. I paraphrase it here because the detailed content lives in the private repo, but the structure of the reasoning is what matters:</p>
<ul>
<li class=""><strong>Alternative 1 — <em>"Read it as before"</em>.</strong> Keep the plan stale and read it as the previous six times. Cost: pay the debt in a later audit cycle, ~50% probability of critical finding.</li>
<li class=""><strong>Alternative 2 — Regenerate everything with <code>/speckit-plan</code>.</strong> Risk: overwriting assertions about US1-US4 that the real code <em>doesn't</em> satisfy; the regenerator doesn't know the current state.</li>
<li class=""><strong>Alternative 3 — Refresh in another PR without restrictions.</strong> Same risk as Alt 2 plus review friction.</li>
<li class=""><strong>Alternative 4 — Scope-limited refresh + 3 gates.</strong> The chosen one.</li>
<li class=""><strong>Alternative 5 — Defer CHARTER-18, do a refactor Charter first.</strong> High calendar cost, marginal benefit over Alt 4.</li>
</ul>
<p>The fourth consisted of three concrete mechanisms:</p>
<p><strong>First mechanism — <em>scope-limited prompt</em>.</strong> Run <code>/speckit-plan</code> with an explicitly restrictive <em>prompt</em>: regenerate only Phase 7+8 corresponding to US5; leave US1-US4 byte for byte as they are, marked with <code>&lt;!-- LOCKED: prior US shipped --&gt;</code> comments the agent must respect. Without that explicit restriction, SpecKit's regeneration is destructive: it rewrites the whole plan, overwriting descriptions the real code already contradicts.</p>
<p><strong>Second mechanism — <em>Gate (a): validation against code reality</em>.</strong> An ad-hoc script, ~30 lines of bash + grep, that diffs each non-US5 entity in <code>data-model.md</code> against the real schema in <code>db/migrations/*.sql</code>, and each non-US5 endpoint in <code>contracts/*.md</code> against the actual handler signatures in <code>internal/modules/commshub/handler_*.go</code>. Any divergence blocks merge. The script exists in Sentinel's repo; it isn't elegant, it's operational. What the framework would canonize later as gate (a) was already there, as artisanal bash.</p>
<p><strong>Third mechanism — <em>Gate (b): granular hunk-by-hunk review</em>.</strong> Review <code>git diff</code> file by file, hunk by hunk, accepting no changes to <em>locked</em> sections without justification. The operator explicitly notes the expected friction in R1 of the AIDEC: if the agent regenerates more hunks than necessary, the human reviewer tires and the discipline collapses. Mitigation: hunks over 50 lines trigger P1 review.</p>
<p><strong>Fourth mechanism — <em>Gate (c): two-PR split</em>.</strong> The refresh is an independent PR, reviewed against <strong>current code</strong>. The Charter-fill that follows is another PR, reviewed against the already-refreshed plan. Don't mix the two reviews — because if they're mixed, the refresh's debt hides behind the new work.</p>
<p>Four mechanisms. Applied manually, with no upstream documentation backing them. A single adopter (me), a single session, and the feeling the whole time of solving a case no one had solved before.</p>
<hr>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="5-the-result">5. The result<a href="https://straymark.dev/blog/manual-discipline-before-the-pattern#5-the-result" class="hash-link" aria-label="Direct link to 5. The result" title="Direct link to 5. The result" translate="no">​</a></h2>
<p><code>CHARTER-18</code> closed the same day. The Charter Telemetry metrics, recorded literally in the closure YAML:</p>
<ul>
<li class=""><code>estimation_drift_factor: 1.0</code> — the Charter finished exactly in the estimated hour range.</li>
<li class=""><code>pre_work.items_discovered_during_planning: 0</code> — no unexpected items appeared during planning.</li>
<li class=""><code>overall_satisfaction: 5/5</code> — the operator's best subjective calibration in the entire chain.</li>
</ul>
<p>More important than the metrics: <code>CHARTER-18</code> was the <strong>first Charter in the chain of seven to close without a mid-flight remediation Charter</strong>. The previous six had each needed, at least one, an atomic pre-close remediation to cover divergences between what was declared and what was delivered. CHARTER-18 didn't. The operator's closing statement, cited literally from the later <code>CHARTER-CHAIN-EVOLUTION.md</code>:</p>
<blockquote>
<p><em>"The SpecKit refresh from PR #76 eliminated most ambiguity that drove drift in prior Charters. No mid-flight remediation Charter required — the EC1..EC15 empirical-corrections inventory in research.md absorbed what would have been pre-execution risk into in-execution awareness."</em></p>
</blockquote>
<p>The manual discipline worked. It didn't just close the Charter cleanly; it changed the nature of the risk. What used to be pre-execution risk (discovering divergences during Charter execution, remediating atomically) became pre-planning awareness (the <code>EC1..EC15</code> inventory enumerates the empirical corrections before declaring the Charter). The risk isn't eliminated; it's moved to a moment where it's manageable.</p>
<hr>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="6-four-hours-and-forty-minutes">6. Four hours and forty minutes<a href="https://straymark.dev/blog/manual-discipline-before-the-pattern#6-four-hours-and-forty-minutes" class="hash-link" aria-label="Direct link to 6. Four hours and forty minutes" title="Direct link to 6. Four hours and forty minutes" translate="no">​</a></h2>
<p>The chronology is worth keeping precise, because it's what the blog comes to record:</p>
<ul>
<li class=""><strong>14 May, 16:59 UTC</strong> — Issue #150 opened. Twelve learnings enumerated, three gates proposed, probability analysis published.</li>
<li class=""><strong>14 May, 21:39 UTC</strong> — PR <a href="https://github.com/StrangeDaysTech/straymark/pull/152" target="_blank" rel="noopener noreferrer" class="">#152</a> merged. <code>fw-4.14.3</code> shipped. <em>"Spec maintenance during multi-Charter execution"</em> added as a new section of <code>SPECKIT-CHARTER-BRIDGE.md</code> with the three gates canonized literally as framework governance. <strong>Four hours and forty minutes</strong> between the question and the upstream answer.</li>
</ul>
<p>What PR #152 documented as governance is exactly what the private AIDEC had applied by hand hours earlier. The three gates with the same names: validation against code reality (gate a), granular hunk-by-hunk review (gate b), two-PR split (gate c). Plus four heuristics of <em>when to refresh</em>: ≥3 closed Charters on the same plan, ≥4 weeks + ≥2 Charters, <code>R&lt;N&gt;(new)</code> count &gt; 6, target US touches refined infra. Plus an explicit note on why NOT to re-run <code>/speckit-tasks</code> (because it destroys the <code>[X]</code> markers and the <code>*CHARTER-NN:* &lt;sha&gt;</code> annotations that form the historical trace). Plus a roadmap note mentioning a future <code>straymark spec-drift</code> CLI that would mechanize gate (a).</p>
<p>Four hours. It's no exaggeration to say the framework wrote the guidance while the operator still had <code>git diff</code> open in another window. The discipline and its canonization were practically simultaneous. And that's worth recording because it's the reverse of the order the academic governance apparatus usually assumes: theory first, then practice. Here it went the other way. Practice first, while it hurt. Theory after, while the pain was still fresh.</p>
<hr>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="7-closing">7. Closing<a href="https://straymark.dev/blog/manual-discipline-before-the-pattern#7-closing" class="hash-link" aria-label="Direct link to 7. Closing" title="Direct link to 7. Closing" translate="no">​</a></h2>
<p>What I took from the process, in four claims:</p>
<ol>
<li class="">
<p><strong>The pattern is born of the discipline, not the other way around.</strong> The three gates of <code>fw-4.14.3</code> weren't designed in the abstract; they were <em>extracted</em> from a concrete operational episode, hours after being applied by hand. Governance is post-empirical when the framework respects the order.</p>
</li>
<li class="">
<p><strong>Explicit probability is discipline.</strong> <em>"~50% probability of critical finding from stale-premise inheritance"</em> isn't Bayesian precision; it's a public claim that forces the decision to be justified. Without that number, the question <em>"should we refresh?"</em> gets decided by intuition. With it, it gets decided by risk arithmetic.</p>
</li>
<li class="">
<p><strong>Twelve learnings in thirty days is the actual cadence.</strong> It's not noise capturable with <em>"let me read it later"</em>. It's empirical density the original plan couldn't have anticipated, and that destroys any long-range planning assumption. The cadence of agent-assisted development is this.</p>
</li>
<li class="">
<p><strong>Four hours is not a record; it's a property of the process.</strong> When the discipline is already being applied in one domain, canonizing it upstream is execution, not design. Same as we saw in Post 4 about the external audit cycle (<em>"five PRs in a day"</em>), same in Post 6 about the rebrand (<em>"forty-three minutes"</em>). The framework didn't invent the discipline; it extracted it and gave it a name.</p>
</li>
</ol>
<p>Next, in the following post, the last episode of the arc this blog came to tell: <em>"Pattern 1 + Pattern 2 — chain evolution"</em> (<code>H-12</code>). Twenty-seven hours after PR #152, the three governance gates crystallized as two named meta-patterns — <em>pre-declare refresh</em> and <em>amend-on-emergence</em> — with a telemetry schema and CLI helpers. It's the closing of the arc Post 1 opened from ahead.</p>
<hr>
<p><em>Anchors: <a href="https://github.com/StrangeDaysTech/straymark/issues/150" target="_blank" rel="noopener noreferrer" class="">Issue #150</a> (14 May 16:59 UTC). PR <a href="https://github.com/StrangeDaysTech/straymark/pull/152" target="_blank" rel="noopener noreferrer" class="">#152</a> — <code>fw-4.14.3</code> (14 May 21:39 UTC). Canonized section: <code>SPECKIT-CHARTER-BRIDGE.md §"Spec maintenance during multi-Charter execution"</code>. CHARTER-18 metrics reported in <code>CHARTER-CHAIN-EVOLUTION.md</code> (fw-4.16.0). Private source paraphrased per <code>GUIA-EDITORIAL.md §7</code>: <code>AIDEC-2026-05-14-001-speckit-plan-scope-limited-us5-refresh.md</code> in Sentinel's repo.</em></p>
<p><em>This document was produced with assistance from generative AI tools (Claude 4.7); all responsibility for the content rests with the human author.</em></p>]]></content>
        <author>
            <name>José Villaseñor Montfort</name>
            <uri>https://github.com/montfort</uri>
        </author>
        <category label="straymark" term="straymark"/>
        <category label="charters" term="charters"/>
        <category label="speckit" term="speckit"/>
        <category label="discipline" term="discipline"/>
        <category label="governance" term="governance"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[The audit-prompt was the outlier]]></title>
        <id>https://straymark.dev/blog/the-audit-prompt-was-the-outlier</id>
        <link href="https://straymark.dev/blog/the-audit-prompt-was-the-outlier"/>
        <updated>2026-05-13T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[The only file in the framework that lived in another language]]></summary>
        <content type="html"><![CDATA[<p><em>One file among dozens lived backwards — Spanish-canonical in an EN-canonical framework, for six weeks, without anyone noticing. A maintenance fix that records something the blog keeps running into: outliers teach you the convention by contrast.</em></p>
<!-- -->
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="1-one-line-from-the-commit">1. One line from the commit<a href="https://straymark.dev/blog/the-audit-prompt-was-the-outlier#1-one-line-from-the-commit" class="hash-link" aria-label="Direct link to 1. One line from the commit" title="Direct link to 1. One line from the commit" translate="no">​</a></h2>
<p>This is the post's operational opening. Commit <code>a8a1ac5</code> from 12 May 2026 carries a body that begins with this sentence:</p>
<blockquote>
<p><em>"The unified audit-prompt template at <code>dist/.straymark/audit-prompts/</code> was the only framework artifact whose canonical content lived in Spanish — every other template, skill, workflow, and governance doc follows the EN-canonical + <code>i18n/&lt;lang&gt;/</code> overlay pattern resolved by <code>cli/src/utils.rs:146</code>."</em></p>
</blockquote>
<p>One single file. Among dozens. It lived backwards. And it had been living that way since May of the previous year, without anyone noticing.</p>
<p>This post is deliberately short. The fix it covers — PR <a href="https://github.com/StrangeDaysTech/straymark/pull/142" target="_blank" rel="noopener noreferrer" class="">#142</a>, <code>fw-4.13.3</code> and <code>cli-3.12.3</code>, merged on 13 May — is not a major narrative milestone. It's a maintenance piece. But it records one of the regularities I keep running into in this craft: outliers are useful. They teach you the convention by contrast.</p>
<hr>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="2-where-the-outlier-came-from">2. Where the outlier came from<a href="https://straymark.dev/blog/the-audit-prompt-was-the-outlier#2-where-the-outlier-came-from" class="hash-link" aria-label="Direct link to 2. Where the outlier came from" title="Direct link to 2. Where the outlier came from" translate="no">​</a></h2>
<p>The audit-prompt wasn't born in the framework. It was born as a local <em>skill</em> of Sentinel's — <code>sentinel/.claude/skills/plan-audit/</code> — during the six-Plan experiment Post 3 covered, in April. It was a <em>context-specific</em> skill, written by the operator (me) in Spanish for reasons that can now be enumerated honestly: it was a private experiment, the operator speaks Spanish, and nobody was going to read the skill ever again. I improvised it in my language because it was for me.</p>
<p>When the experiment crystallized into the framework — the fw-4.4.0 to fw-4.9.0 arc Post 4 covered — the skill was ported to the canonical path <code>dist/.straymark/audit-prompts/audit-prompt.md</code>. The port was mechanical: copy the file, generalize it enough that it didn't mention Sentinel-specific components, adjust the <em>Plan</em> → <em>Charter</em> nomenclature. What wasn't done: translate it to English. The file entered the framework <em>in the language it had been written in</em>. Without anyone deciding it, Spanish became the canonical version of that one artifact.</p>
<p>The rest of the framework — every other template, every skill, the canonical governance docs — had been written in English since January, with Spanish and zh-CN as overlays under <code>i18n/&lt;lang&gt;/</code>. The audit-prompt was the silent exception, for six weeks, until 12 May.</p>
<hr>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="3-how-it-was-found-by-visual-inspection">3. How it was found: by visual inspection<a href="https://straymark.dev/blog/the-audit-prompt-was-the-outlier#3-how-it-was-found-by-visual-inspection" class="hash-link" aria-label="Direct link to 3. How it was found: by visual inspection" title="Direct link to 3. How it was found: by visual inspection" translate="no">​</a></h2>
<p>It wasn't emergent observation from the agent. The operator noticed it, visually. The CHANGELOG entry records it without metaphor:</p>
<blockquote>
<p><em>"Surfaced empirically when Sentinel audited the <code>straymark explore</code> rendering and the user noted that audit-cycle templates were ES while all other templates and skills were EN."</em></p>
</blockquote>
<p><code>straymark explore</code> is the framework's TUI — the interactive documentation browser Post 14 will cover. Its value is rendering all templates side by side, in the same view. And when all templates are side by side, one in another language is obvious. That's the observation.</p>
<p>It's worth leaving the data because it matters for the blog's honesty. Post 1 articulated the pattern of <em>emergent observation</em> — an agent flagging something nobody asked it to flag — and Post 5 documented what happens when that pattern is missing because of <em>structural visibility</em>. This episode is neither. It's a more pedestrian observation: a new surface of the framework (the TUI) put all the files in simultaneous view, and the inconsistency became as obvious as when you tidy the bookshelf and notice one book is shelved with the spine backwards. Tools also produce visibility.</p>
<hr>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="4-the-fix-three-moves-in-one-commit">4. The fix: three moves in one commit<a href="https://straymark.dev/blog/the-audit-prompt-was-the-outlier#4-the-fix-three-moves-in-one-commit" class="hash-link" aria-label="Direct link to 4. The fix: three moves in one commit" title="Direct link to 4. The fix: three moves in one commit" translate="no">​</a></h2>
<p>PR #142 did three things in the same commit:</p>
<ul>
<li class=""><strong><code>dist/.straymark/audit-prompts/audit-prompt.md</code></strong> rewritten in English as the canonical version. 312 lines. The translation took care to preserve the severity structure and calibration examples of the original.</li>
<li class=""><strong><code>dist/.straymark/audit-prompts/i18n/es/audit-prompt.md</code></strong> created as an overlay. 318 lines. It's the Spanish content that used to live in root, now in its correct place.</li>
<li class=""><strong><code>cli/src/commands/charter/audit.rs</code></strong> wired to the i18n resolver. Until then, the subcommand hardcoded the <code>dist/.straymark/audit-prompts/audit-prompt.md</code> path without consulting the adopter's <code>language</code> field in <code>.straymark/config.yml</code>. After the PR, it reads the project config and resolves the localized path — if the adopter has <code>language: es</code>, they get the Spanish overlay; if they have <code>language: zh-CN</code>, it falls back to EN canonical (there's no zh-CN translation of the audit-prompt yet); if they have <code>language: en</code> or don't specify, they get the canonical.</li>
</ul>
<p>Three new tests cover the three paths. Zero functional change for English users (who are the majority). For Spanish users, an improvement: before, they received the prompt in Spanish by accident (because the canonical path pointed to ES); now they receive it in Spanish by convention (because the resolver decides it).</p>
<hr>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="5-the-lateral-move">5. The lateral move<a href="https://straymark.dev/blog/the-audit-prompt-was-the-outlier#5-the-lateral-move" class="hash-link" aria-label="Direct link to 5. The lateral move" title="Direct link to 5. The lateral move" translate="no">​</a></h2>
<p>While doing the language switch, the operator took the chance to extract a specificity that had carried over from the Sentinel origin. The §Step 5 section of the prompt — about severity calibration of findings — cited a literal case from the April experiment: <em>"Etapa 12 Pub/Sub stub vs gochannel"</em>. A perfectly didactic example, but specific to a Sentinel component no other adopter would recognize.</p>
<p>The English translation replaced that example with a vendor-neutral formulation: <em>"declared deferral, not a defect — a charter that introduces a thin adapter slated for replacement in a future Charter"</em>. The idea — a <em>stub</em> that is declared debt, not a defect — is preserved. What goes is the component's name.</p>
<p>The move is small but coherent with the blog's principle. When there's an opportunity to detach the framework from a specific adopter without losing pedagogy, take it. It's the same generalization operation Post 3 documented for the six Plans and Post 4 for the first Charter: empirical content stays <em>in</em> Sentinel; what enters the framework is the vendor-neutral abstraction. The audit-prompt, almost a year later, finally finished honoring that rule.</p>
<hr>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="6-closing">6. Closing<a href="https://straymark.dev/blog/the-audit-prompt-was-the-outlier#6-closing" class="hash-link" aria-label="Direct link to 6. Closing" title="Direct link to 6. Closing" translate="no">​</a></h2>
<p>Three short claims:</p>
<ol>
<li class="">
<p><strong>In a framework with a convention, a single file violating it is a sign of legacy, not of design.</strong> The audit-prompt was the outlier because it was born earlier, and nobody migrated it when the other artifacts aligned. Outliers accumulate provenance.</p>
</li>
<li class="">
<p><strong>New tools produce visibility.</strong> The ES → EN switch wasn't decided by systematic repo review. It was decided because a new TUI put all the templates on the same screen and the inconsistency became obvious. The same applies to <code>grep</code>, to aggregate views, to <code>status</code> outputs: every new surface exposes what was misaligned.</p>
</li>
<li class="">
<p><strong>Small rebrands are opportunities to de-identify.</strong> When you touch a file to change the language, the marginal cost of also extracting the adopter specificity left from origin is zero. The blog has recorded this pattern before (Plan → Charter, DevTrail → StrayMark); this is the miniature version. The framework becomes more vendor-neutral one file at a time.</p>
</li>
</ol>
<p>Next, in the following post, an episode that already brushed Post 1 but deserves its own treatment: <em>"Manual discipline before the pattern"</em> (<code>H-11</code>). How Sentinel handled <code>CHARTER-18</code> before the <code>Pattern 1</code> of chain evolution existed — the empirical learning that Post 1 later named as meta-pattern.</p>
<hr>
<p><em>Anchors: PR <a href="https://github.com/StrangeDaysTech/straymark/pull/142" target="_blank" rel="noopener noreferrer" class="">#142</a>. Releases: <code>fw-4.13.3</code> / <code>cli-3.12.3</code>. Key commit: <code>a8a1ac5</code>. Files: <code>dist/.straymark/audit-prompts/audit-prompt.md</code> (EN canonical) + <code>dist/.straymark/audit-prompts/i18n/es/audit-prompt.md</code> (overlay). CLI: <code>cli/src/commands/charter/audit.rs</code> wired to the i18n resolver.</em></p>
<p><em>This document was produced with assistance from generative AI tools (Claude 4.7); all responsibility for the content rests with the human author.</em></p>]]></content>
        <author>
            <name>José Villaseñor Montfort</name>
            <uri>https://github.com/montfort</uri>
        </author>
        <category label="straymark" term="straymark"/>
        <category label="i18n" term="i18n"/>
        <category label="audit" term="audit"/>
        <category label="governance" term="governance"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[TDE and transversal debt]]></title>
        <id>https://straymark.dev/blog/tde-and-transversal-debt</id>
        <link href="https://straymark.dev/blog/tde-and-transversal-debt"/>
        <updated>2026-05-12T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[The type existed. The trigger didn't. And the stacked-PR lesson that came along for the ride.]]></summary>
        <content type="html"><![CDATA[<p><em>Zero TDEs across thirteen closed Charters in Sentinel, despite at least seven recognizable pieces of transversal debt. The document type existed; the operational trigger didn't. How fw-4.13.0 closed the gap — and how its PR chain accidentally codified a lesson about stacked PRs.</em></p>
<!-- -->
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="1-zero-tdes-across-thirteen-charters">1. Zero TDEs across thirteen Charters<a href="https://straymark.dev/blog/tde-and-transversal-debt#1-zero-tdes-across-thirteen-charters" class="hash-link" aria-label="Direct link to 1. Zero TDEs across thirteen Charters" title="Direct link to 1. Zero TDEs across thirteen Charters" translate="no">​</a></h2>
<p>Issue <a href="https://github.com/StrangeDaysTech/straymark/issues/128" target="_blank" rel="noopener noreferrer" class="">#128</a> opens with a disquieting asymmetry:</p>
<blockquote>
<p><em>"Sentinel adopter (primary, fw-4.12.0) created zero TDEs across 13 closed Charters despite ≥7 instances of transversal debt routed through parallel mechanisms."</em></p>
</blockquote>
<p>Thirteen closed Charters. At least seven recognizable pieces of transversal debt — inherited from prior Charters, crossing modules, persisting between sessions. Zero TDEs. If the operator had been discussing quotas, the data wouldn't mean anything. But the operator was me and the adopter was the same project that empirically validates the framework. If Sentinel — the repo where the full framework was being used most aggressively — wasn't producing TDEs even once in thirteen tries, something was broken.</p>
<p>What was broken wasn't the debt, which was being captured by other channels (<code>R&lt;N&gt; (new, not in Charter)</code> inside the AILOGs, entries in <code>follow-ups-backlog.md</code>). What was broken was that no criterion in the framework said <em>"this specific piece deserves TDE, not R<n>"</n></em>. The document type existed. The operational trigger didn't.</p>
<p>This post covers the 11-12 May 2026 episode: how the missing trigger was diagnosed, how it was closed with four canonical criteria (<code>fw-4.13.0</code>), and how the PR chain that fixed the problem left behind, in passing, an operational lesson about stacked-PRs that ended up codified in the project's <code>CLAUDE.md</code>. It's the first blog episode where the framework fixes <em>two different things</em> in the same arc, and where the second is accidental.</p>
<hr>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="2-the-type-existed-the-trigger-didnt">2. The type existed. The trigger didn't.<a href="https://straymark.dev/blog/tde-and-transversal-debt#2-the-type-existed-the-trigger-didnt" class="hash-link" aria-label="Direct link to 2. The type existed. The trigger didn't." title="Direct link to 2. The type existed. The trigger didn't." translate="no">​</a></h2>
<p><code>TDE</code> — <em>Technical Debt Entry</em> — has existed in the framework since the January initial commit (Post 2 recorded it: it was on the list of eight original types in the v1.0.0 README). The template was there. The taxonomy field was there. The <code>06-evolution/technical-debt/</code> folder was there.</p>
<p>What wasn't there was a sentence, somewhere in the canonical apparatus, that said <em>"create a TDE now"</em>. Issue #128 put it without softening:</p>
<blockquote>
<p><em>"Reading the adopter-facing docs (<code>AGENT-RULES.md</code>, <code>DOCUMENTATION-POLICY.md</code>, <code>QUICK-REFERENCE.md</code>, <code>CLAUDE.md</code> autonomous rules), there is no clear trigger that says 'create a TDE now'. The trigger language exists for AILOG (creation freely), AIDEC (when alternatives considered), ETH (high risk PII), ADR (architectural decisions), but TDE is just listed as 'agent can Identify'."</em></p>
</blockquote>
<p><em>"Agent can identify."</em> Identify if you feel like it. An agent entering the repo reads that line, shrugs, and moves on to AILOG and AIDEC, which do tell it <em>when</em>. The defect is the same one from Issue #113 (Post 5): the artifact technically exists, but the canonical <em>surface</em> doesn't give the agent the verb needed to activate it. What makes this case different from #113 is the consequence. For Charters, not seeing them meant not using the new flow. For TDE, not seeing them meant something worse: transversal debt <em>was</em> being captured — but fragmented, with no consolidated view, no prioritization across artifacts, no <code>assigned_to</code> or <code>priority</code> field for a human reviewer to order it.</p>
<p>The Issue cites that consequence with embarrassing detail, because it enumerates everything that wasn't happening:</p>
<blockquote>
<p><em>"No queryable 'all open technical debts' view at the document level. No <code>impact × effort</code> prioritization matrix per item. No <code>assigned_to</code> / <code>priority</code> fields surfaced to the human reviewer. Architectural debt that legitimately spans multiple charters (e.g., scope authorization gap heritage across modules) gets fragmented into per-charter R-numbers instead of consolidated into a single TDE."</em></p>
</blockquote>
<p>Thirteen Charters' worth of debt fragmented into per-Charter <code>R&lt;N&gt;</code>. From the repo operator's point of view: no consolidated list, none explicitly named as inherited, no piece of debt prioritizable at project level. Everything was in the repo. None of it was in the place the repo builds for the humans coming in from outside to read it.</p>
<hr>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="3-four-criteria-for-a-piece-of-debt">3. Four criteria for a piece of debt<a href="https://straymark.dev/blog/tde-and-transversal-debt#3-four-criteria-for-a-piece-of-debt" class="hash-link" aria-label="Direct link to 3. Four criteria for a piece of debt" title="Direct link to 3. Four criteria for a piece of debt" translate="no">​</a></h2>
<p>PR <a href="https://github.com/StrangeDaysTech/straymark/pull/129" target="_blank" rel="noopener noreferrer" class="">#129</a> (<code>fw-4.13.0</code>, merged 11 May at 19:38 UTC, exactly thirteen hours after the Issue was opened) closed the gap with a new section in <code>AGENT-RULES.md §3</code> titled <em>"TDE vs `R<n> (new, not in Charter)"</n></em>. The four criteria, literal:</p>

























<table><thead><tr><th>Criterion</th><th>When it applies</th></tr></thead><tbody><tr><td><strong>1. Heritage from a prior Charter</strong></td><td>The debt is literally inherited from the previous Charter (<em>strict heritage</em>) or reappears when following the previous Charter's pattern (<em>pattern propagation</em>).</td></tr><tr><td><strong>2. Applies to multiple modules or Charter execution boundaries</strong></td><td>The debt crosses code modules <em>or</em> crosses execution boundaries between Charters (governance-trail debt).</td></tr><tr><td><strong>3. Requires a dedicated Charter outside current scope</strong></td><td>Resolving it requires opening its own Charter, outside the current Charter's envelope.</td></tr><tr><td><strong>4. Requires human prioritization/assignment</strong></td><td>Deciding priority or assignment is beyond the agent's range.</td></tr></tbody></table>
<p>The operational rule: if a piece of debt satisfies <em>at least one</em> of the four criteria, it's a TDE. If it satisfies none, it stays as <code>R&lt;N&gt;</code> inside the Charter where it appeared.</p>
<p>The four each have their logic. Heritage (1) captures debt that persists across time, which a reviewer would want grouped by origin, not by Charter. Multi-module or multi-Charter (2) captures debt that lives <em>between</em> artifacts, not <em>inside</em> one. Dedicated Charter (3) acknowledges that some pieces of debt are large enough to deserve their own cycle and therefore don't fit as risk declared <em>ex-ante</em>. Human prioritization (4) acknowledges the autonomy limit: there are decisions the agent can flag but can't resolve, and those decisions deserve a document where a human can queue up.</p>
<p>The same PR added a new field to the TDE template's frontmatter — <code>promoted_from_followup: FU-NNN | null</code> — and a section in <code>FOLLOW-UPS-BACKLOG-PATTERN.md</code> documenting how to promote a follow-ups entry to a TDE. The promotion has two shapes, both recorded literally: promotion of an existing entry (a follow-up that had been on the list for weeks matures into a TDE) and <em>retropromotion at creation</em> (when the TDE is created, it's acknowledged it originated in a prior follow-up and noted). The frontmatter field closes the trail: any TDE can now point back to the follow-up that originated it, if one existed.</p>
<hr>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="4-three-tdes-in-sentinel--the-empirical-loop-closed">4. Three TDEs in Sentinel — the empirical loop closed<a href="https://straymark.dev/blog/tde-and-transversal-debt#4-three-tdes-in-sentinel--the-empirical-loop-closed" class="hash-link" aria-label="Direct link to 4. Three TDEs in Sentinel — the empirical loop closed" title="Direct link to 4. Three TDEs in Sentinel — the empirical loop closed" translate="no">​</a></h2>
<p>Issue #128 didn't close by argument; it closed by evidence. The same day, Sentinel — the same adopter that had been through thirteen Charters without a single TDE — created three:</p>
<ul>
<li class="">A TDE for a <strong>RequireScope architectural gap</strong>, heritage crossing modules. Criteria 1 + 2 + 3.</li>
<li class="">A TDE about <strong>missing test coverage in the HTTP layer</strong>, debt persisting across feature Charters. Criteria 1 + 4.</li>
<li class="">A TDE for <strong>review of legacy AILOGs</strong> predating Charter format v3, a piece needing its own cycle. Criteria 1 + 3.</li>
</ul>
<p>Three documents in hours. The speed matters less than the fact that each one applied <em>at least one</em> of the criteria and none landed in gray territory. The criteria worked as an unambiguous heuristic — the operator didn't have to negotiate with himself about whether a piece was TDE or <code>R&lt;N&gt;</code>. The empirical loop the Issue had opened in the morning closed with three documents that same afternoon.</p>
<p>PR <a href="https://github.com/StrangeDaysTech/straymark/pull/136" target="_blank" rel="noopener noreferrer" class="">#136</a> (<code>fw-4.13.1</code>, merged the next day) refined two criteria based on that same experience. <em>Heritage</em> (1) was explicitly split into <em>strict heritage</em> vs <em>pattern propagation</em> because one of Sentinel's three TDEs showed the second case clearly: the debt wasn't literally inherited; it was the same pattern reappearing when the same procedure was followed. <em>Multi-module</em> (2) was reformulated as <em>"multiple modules <strong>or Charter execution boundaries</strong>"</em> because another of the three TDEs was governance-trail (crossing session boundaries without crossing code modules). The criteria grew one single refinement-pass after being exercised on three real cases. The framework validated principle #12 again: no schema crystallizes without a second domain.</p>
<hr>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="5-the-stacked-pr-lesson">5. The stacked-PR lesson<a href="https://straymark.dev/blog/tde-and-transversal-debt#5-the-stacked-pr-lesson" class="hash-link" aria-label="Direct link to 5. The stacked-PR lesson" title="Direct link to 5. The stacked-PR lesson" translate="no">​</a></h2>
<p>This is where the post deliberately veers off. The PR chain #129 → #131 → #133 that closed Issue #128 left behind an adjacent operational lesson — not about TDE but about how <em>not</em> to stack branches. The lesson is documented literally in <code>CLAUDE.md</code> (lines 181-220) of the public repo under the section <strong>"Stacked PRs — avoid, or use merge commits"</strong>.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="how-it-broke">How it broke<a href="https://straymark.dev/blog/tde-and-transversal-debt#how-it-broke" class="hash-link" aria-label="Direct link to How it broke" title="Direct link to How it broke" translate="no">​</a></h3>
<p>PR #131 (<code>cli-3.12.1</code>, validator fix that was rejecting <code>status: identified</code> on TDEs) was opened with <code>base = #129</code> because <code>#131</code> needed <code>#129</code>'s code to compile its tests. Then <code>#129</code> was merged to <code>main</code> with <em>squash</em>. The current <code>CLAUDE.md</code> describes it with a precision worth quoting in full:</p>
<blockquote>
<p><em>"When you stack PR B on top of PR A's branch (base of B is A's head, not <code>main</code>), and A is squash-merged to <code>main</code>, B's content gets stranded:</em></p>
<p><em>— The squash merge of A creates a new commit on <code>main</code> with content equivalent to A but a different SHA than A's original commits.</em></p>
<p><em>— B's branch still points at A's original commits, which now have no descendant on <code>main</code>.</em></p>
<p><em>— When B is merged, GitHub merges it into A's branch (its declared base), not <code>main</code>. The 'merge to main' never happens — even though GitHub UI shows B as MERGED."</em></p>
</blockquote>
<p>The practical result in the #129/#131 cycle: GitHub's UI showed <code>#131</code> as <em>MERGED</em>, the validator tests were ostensibly on main, but the content never arrived. PR #133 was the procedural sync that had to be opened later to carry the content to its destination. Time lost in diagnosis: about three hours. Time of the recovery operation once understood: five minutes.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="how-to-prevent-it">How to prevent it<a href="https://straymark.dev/blog/tde-and-transversal-debt#how-to-prevent-it" class="hash-link" aria-label="Direct link to How to prevent it" title="Direct link to How to prevent it" translate="no">​</a></h3>
<p>The <code>CLAUDE.md</code> documents two strategies, one conservative and one pragmatic:</p>
<blockquote>
<p><em>"1. Sequential, not stacked. Wait for PR A to merge to <code>main</code>, then rebase B onto <code>main</code> and open B as a standalone PR with <code>base = main</code>. Slower but bulletproof.</em></p>
<p><em>2. If you must stack, use merge commits (not squash) for the parent. A merge commit preserves shared history, so subsequent merges of stacked PRs into <code>main</code> resolve cleanly. Pay the cost of a noisier <code>git log</code> for the stacked-PR safety."</em></p>
</blockquote>
<p>Sentinel and StrayMark default to squash. That choice is good for keeping <code>git log</code> clean, one decision per feature, one commit per PR. But it costs exactly this: incompatibility with stacked-PRs. The rule <code>CLAUDE.md</code> now codifies is honest: either don't stack, or pay in commit history to be able to stack. There's no third option that doesn't break something.</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="how-to-recover-if-it-already-happened">How to recover (if it already happened)<a href="https://straymark.dev/blog/tde-and-transversal-debt#how-to-recover-if-it-already-happened" class="hash-link" aria-label="Direct link to How to recover (if it already happened)" title="Direct link to How to recover (if it already happened)" translate="no">​</a></h3>
<p>The recovery section of the <code>CLAUDE.md</code> is the most operational piece of the document. Four steps:</p>
<blockquote>
<p><em>"1. <code>git checkout -b chore/sync-&lt;B-content&gt;-to-main main</code></em></p>
<p><em>2. <code>git cherry-pick &lt;B's merge commit SHA&gt;</code> — should be clean because B touches files outside A's conflict zone (which is why it could be stacked in the first place).</em></p>
<p><em>3. Push, open PR with <code>base = main, head = chore/sync-...</code>. Cherry-pick produces a fresh commit on top of <code>main</code>, so no conflicts.</em></p>
<p><em>4. The branch protection may require <code>--admin</code> merge if the content was already reviewed in B (the original PR) — sync PRs are purely procedural."</em></p>
</blockquote>
<p>The last step is editorially important: explicit note that an <code>--admin</code> merge is authorized <em>only</em> for procedural PRs like this — where the content was already reviewed in the original PR. It's the only exception to the <em>"content goes through human review"</em> rule of the project.</p>
<p>The reason it's worth registering the lesson as a sub-section of the TDE post — and not as a separate post — is that they share a trait: both are pieces of <strong>transversal process debt</strong> the framework now explicitly names. One is code debt (TDE as a new type); the other is workflow debt (stacked-PR as a documented anti-pattern). They share an origin: real operational friction was what triggered the document.</p>
<hr>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="6-what-the-episode-left-in-the-repo">6. What the episode left in the repo<a href="https://straymark.dev/blog/tde-and-transversal-debt#6-what-the-episode-left-in-the-repo" class="hash-link" aria-label="Direct link to 6. What the episode left in the repo" title="Direct link to 6. What the episode left in the repo" translate="no">​</a></h2>
<p>Four PRs in under twenty-four hours, three recorded lessons:</p>
<ul>
<li class=""><strong>PR <a href="https://github.com/StrangeDaysTech/straymark/pull/129" target="_blank" rel="noopener noreferrer" class="">#129</a></strong> (<code>fw-4.13.0</code>, 11 May 19:38 UTC) — TDE activation trigger. Four criteria + new section in <code>AGENT-RULES.md §3</code> + FU → TDE path.</li>
<li class=""><strong>PR <a href="https://github.com/StrangeDaysTech/straymark/pull/131" target="_blank" rel="noopener noreferrer" class="">#131</a></strong> (<code>cli-3.12.1</code>, 11 May 19:39 UTC) — validator accepts <code>status: identified</code> on TDEs. Without the fix, the first TDE created under the new trigger failed validation.</li>
<li class=""><strong>PR <a href="https://github.com/StrangeDaysTech/straymark/pull/134" target="_blank" rel="noopener noreferrer" class="">#134</a></strong> (12 May 04:54 UTC) — the stacked-PR lesson documented in <code>CLAUDE.md</code>. It didn't change framework code; it changed the repo's operational rules.</li>
<li class=""><strong>PR <a href="https://github.com/StrangeDaysTech/straymark/pull/136" target="_blank" rel="noopener noreferrer" class="">#136</a></strong> (<code>fw-4.13.1</code>, 12 May 04:54 UTC) — TDE trigger refinements based on Sentinel's three real cases.</li>
</ul>
<p>What I most want to flag about the chronology: <code>CLAUDE.md</code> (PR #134) was updated in the same arc that closed Issue #128. The stacked-PR lesson didn't wait to be forgotten. If the framework's discipline is <em>"every significant change leaves a documented trace"</em>, that applies to operational friction too, not only to design. The framework exists, in part, so expensive learnings don't evaporate.</p>
<hr>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="7-closing">7. Closing<a href="https://straymark.dev/blog/tde-and-transversal-debt#7-closing" class="hash-link" aria-label="Direct link to 7. Closing" title="Direct link to 7. Closing" translate="no">​</a></h2>
<p>What I took from the process, in four claims:</p>
<ol>
<li class="">
<p><strong>A document type without a trigger is an invisible type.</strong> Same as in Issue #113, what the agent doesn't see on entering the repo doesn't exist for it. TDE existed technically from January, but only started being used when the four criteria appeared in <code>AGENT-RULES.md §3</code>. Structure without an activating verb is decoration.</p>
</li>
<li class="">
<p><strong>Transversal debt deserves its own type.</strong> Fragmenting debt into per-Charter <code>R&lt;N&gt;</code> destroys the most important property of a governance system: the consolidated view. Four criteria, any one is enough, holds the line between <em>this is risk of the Charter</em> and <em>this is debt of the project</em>.</p>
</li>
<li class="">
<p><strong>Operational learnings get documented too.</strong> PR #134 updated the project's <code>CLAUDE.md</code> the same day the lesson surfaced. It isn't archival paranoia; it's the same rule applied to process: if the friction cost you three hours today, write the lesson today.</p>
</li>
<li class="">
<p><strong>The framework grows from features as well as from anti-patterns.</strong> This episode left behind a new type (TDE as operational entity) <em>and</em> a documented anti-pattern (stacked-PRs incompatible with squash). Both are framework material, even if only one shows up as a version bump.</p>
</li>
</ol>
<p>Next, in the following post, a brief but structural episode: <em>"The Spanish audit-prompt was the outlier"</em> (<code>H-10</code>). An i18n convention detail that revealed which language had been the canonical one — and why fixing it changed, without meaning to, how the framework thinks about translation.</p>
<hr>
<p><em>Anchors: <a href="https://github.com/StrangeDaysTech/straymark/issues/128" target="_blank" rel="noopener noreferrer" class="">Issue #128</a>. PRs <a href="https://github.com/StrangeDaysTech/straymark/pull/129" target="_blank" rel="noopener noreferrer" class="">#129</a> · <a href="https://github.com/StrangeDaysTech/straymark/pull/131" target="_blank" rel="noopener noreferrer" class="">#131</a> · <a href="https://github.com/StrangeDaysTech/straymark/pull/134" target="_blank" rel="noopener noreferrer" class="">#134</a> · <a href="https://github.com/StrangeDaysTech/straymark/pull/136" target="_blank" rel="noopener noreferrer" class="">#136</a>. Releases: <code>fw-4.13.0</code> / <code>cli-3.12.1</code> / <code>fw-4.13.1</code>. Stacked-PR lesson codified in <a href="https://github.com/StrangeDaysTech/straymark/blob/main/CLAUDE.md" target="_blank" rel="noopener noreferrer" class=""><code>CLAUDE.md</code> lines 181-220</a> of the repo.</em></p>
<p><em>This document was produced with assistance from generative AI tools (Claude 4.7); all responsibility for the content rests with the human author.</em></p>]]></content>
        <author>
            <name>José Villaseñor Montfort</name>
            <uri>https://github.com/montfort</uri>
        </author>
        <category label="straymark" term="straymark"/>
        <category label="tde" term="tde"/>
        <category label="technical-debt" term="technical-debt"/>
        <category label="governance" term="governance"/>
        <category label="git-workflow" term="git-workflow"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[Validate and the schemas as a formal layer]]></title>
        <id>https://straymark.dev/blog/validate-and-schemas-as-a-formal-layer</id>
        <link href="https://straymark.dev/blog/validate-and-schemas-as-a-formal-layer"/>
        <updated>2026-05-11T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[Phase 2: when the framework starts to verify what it had been promising]]></summary>
        <content type="html"><![CDATA[<p><em>464 lines of bash got replaced with a flag. From "I check this looks like a document" to "I check this satisfies the canonical schema, in the mode you ask for, with concrete operational consequences." Phase 2 of the CLI roadmap and the formalization of validate.</em></p>
<!-- -->
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="1-having-schemas-is-not-the-same-as-validating-against-schemas">1. Having schemas is not the same as validating against schemas<a href="https://straymark.dev/blog/validate-and-schemas-as-a-formal-layer#1-having-schemas-is-not-the-same-as-validating-against-schemas" class="hash-link" aria-label="Direct link to 1. Having schemas is not the same as validating against schemas" title="Direct link to 1. Having schemas is not the same as validating against schemas" translate="no">​</a></h2>
<p><code>straymark validate</code> had existed since 25 March 2026 — PR #27, part of the first arc of CLI Phase 1. What it did back then was small: verify that documents in <code>.straymark/</code> had valid Markdown syntax, parseable frontmatter, and the minimum fields of the correct type. It was useful. It was not <em>enforcement</em>.</p>
<p>What changed on 11 May 2026, with the <code>fw-4.6.0 / cli-3.7.0</code> release, was something else: Phase 2 of the CLI roadmap closed a full arc of seven PRs (#73 to #79) and consolidated them into one (#80). The CHANGELOG says it without metaphor:</p>
<blockquote>
<p><em>"The first feature-bearing release since the repositioning... Phase 2 of <code>Propuesta/devtrail-cli-roadmap.md</code> lands as 7 bisect-safe PRs (#73–#79), grouped here for reviewers. The release closes the empirical loop the Sentinel experiment opened: telemetry at Charter close, drift detection at Charter close, and a canonical approval signal for <code>review_required: true</code> documents."</em></p>
</blockquote>
<p>What matters for this post isn't the seven PRs as individual milestones; it's the three that touched the <code>validate</code> command and the schemas. What in March was <em>"I check that this looks like a document"</em> in May became <em>"I check that this satisfies the canonical schema of the type, in the mode you ask for, with concrete operational consequences"</em>.</p>
<hr>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="2-from-artisanal-bash-to-a-command-flag">2. From artisanal bash to a command flag<a href="https://straymark.dev/blog/validate-and-schemas-as-a-formal-layer#2-from-artisanal-bash-to-a-command-flag" class="hash-link" aria-label="Direct link to 2. From artisanal bash to a command flag" title="Direct link to 2. From artisanal bash to a command flag" translate="no">​</a></h2>
<p>One of the most visible pieces of the change is small: the <code>--staged</code> flag.</p>
<p>Until Phase 2, the recommended pattern for adopters to validate their documents before a commit was a bash script called <code>pre-commit-docs.sh</code>. It lived in <code>dist/.straymark/scripts/</code> and had 464 lines. It did the reasonable thing: read <code>git diff --cached --name-only</code>, filter files in <code>.straymark/</code>, parse their frontmatter with <code>awk</code>, check fields. It worked. And it was 464 lines of bash each adopter had to trust executed the right thing, in the right version, with the right YAML parser.</p>
<p>A PR on 28 March (commit <code>d9ea874</code>) replaced the 464 lines with a flag:</p>
<div class="language-bash codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-bash codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">straymark validate </span><span class="token parameter variable" style="color:#36acaa">--staged</span><br></div></code></pre></div></div>
<p>Reads staged files the same, filters by <code>.straymark/</code> the same, validates the same. The difference: today all of that lives in Rust inside the binary, not in bash on disk. The adopter doesn't have to maintain the script; the script can't diverge between versions; the behavior is the same on Linux, macOS and Windows. The framework stopped asking the adopter to trust a loose script and started giving them a command with the implicit promise of a versioned binary.</p>
<p>It's the same pattern Post 6 documented for archival discipline (preserve git history instead of rewriting) or Post 4 documented with decision A1 (orchestrate without invoking APIs): move from <em>"the operator does X manually with risk of divergence"</em> to <em>"the framework canonizes X in a declarative command"</em>. <code>--staged</code> isn't an exotic feature; it's manual debt swept away.</p>
<hr>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="3-the-three-v0-schemas">3. The three v0 schemas<a href="https://straymark.dev/blog/validate-and-schemas-as-a-formal-layer#3-the-three-v0-schemas" class="hash-link" aria-label="Direct link to 3. The three v0 schemas" title="Direct link to 3. The three v0 schemas" translate="no">​</a></h2>
<p>Phase 2 also consolidated the three schemas that live in <code>dist/.straymark/schemas/</code>:</p>

























<table><thead><tr><th>Schema</th><th>What it describes</th><th>Origin</th></tr></thead><tbody><tr><td><code>charter.schema.v0.json</code></td><td>Structure of the Charter as a first-class entity (Post 4)</td><td>Sentinel <code>/plan-audit</code> (6 cycles, format v1 → v2 → v3)</td></tr><tr><td><code>charter-telemetry.schema.v0.json</code></td><td>Charter telemetry (Post 3, extended in Post 10)</td><td>5 <code>PLAN-NN.telemetry.yaml</code> files from Sentinel</td></tr><tr><td><code>audit-output.schema.v0.json</code></td><td>Canonical output of external audit (Post 4 + Post 10)</td><td>Sentinel dual-audit (Copilot + Gemini + critical Claude)</td></tr></tbody></table>
<p>Each schema carries a <code>$comment</code> field in its root. The one in <code>charter.schema.v0.json</code> says literally:</p>
<blockquote>
<p><em>"EXPERIMENTAL v0. Crystallized from Sentinel /plan-audit (6 cycles, format v1 → v2 → v3). Will not stabilize to v1.0 until validated in a second domain (frontend, ML pipeline, or infra-as-code)."</em></p>
</blockquote>
<p>The one in <code>charter-telemetry.schema.v0.json</code>, similar:</p>
<blockquote>
<p><em>"EXPERIMENTAL v0. Derived from 5 PLAN-NN.telemetry.yaml files in Sentinel (one project, Go backend) — same N=1-domain caveat as charter.schema.v0.json. Will not stabilize to v1.0 until validated in a second domain."</em></p>
</blockquote>
<p>The one in <code>audit-output.schema.v0.json</code>, idem:</p>
<blockquote>
<p><em>"EXPERIMENTAL v0.x. Phase 3 of the CLI roadmap. Crystallized from the dual-audit pattern validated empirically in Sentinel."</em></p>
</blockquote>
<p>All three share an explicit declaration: <em>no crystallizes without a second domain</em>. It's framework principle #12, not as a separate paragraph in governance documentation, but <strong>inside the JSON Schema itself, in a field any standard validator reads and any schema-explorer tool renders to the user</strong>. The framework doesn't hide the provisional nature of its schemas; it puts it where nobody can miss it.</p>
<p>This matters more than it seems. The usual practice in schema ecosystems (JSON Schema, OpenAPI, Avro) is to publish <code>v1</code> and then bump as things change. Marking <code>v0</code> with a <code>$comment</code> saying <em>"this is experimental until a second domain validates it"</em> is admitting, from the start, that the first crystallization isn't definitive. The schema itself is honest.</p>
<hr>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="4-three-modes-of-the-command">4. Three modes of the command<a href="https://straymark.dev/blog/validate-and-schemas-as-a-formal-layer#4-three-modes-of-the-command" class="hash-link" aria-label="Direct link to 4. Three modes of the command" title="Direct link to 4. Three modes of the command" translate="no">​</a></h2>
<p><code>straymark validate</code> is no longer a command with one flow. After Phase 2 it has three operational modes, each coupled to a moment in the life cycle:</p>
<ul>
<li class="">
<p><strong><code>all</code> mode (default)</strong> — <code>straymark validate</code> with no flags. Walks <code>.straymark/</code> recursively, parses each <code>.md</code> file, tries to resolve its type (AILOG, AIDEC, ADR, ETH, REQ, TES, INC, TDE, MCARD, SBOM, SEC, DPIA, Charter), applies the corresponding schema, and reports per-file violations. This is the <em>full audit</em> mode. Useful for CI, useful for reviewing a fresh repo, useful when an adopter wants to measure how much formal debt accumulated.</p>
</li>
<li class="">
<p><strong><code>--staged</code> mode</strong> — <code>straymark validate --staged</code>. The one that replaced bash. Only validates files <code>git diff --cached --name-only</code> reports as staged within <code>.straymark/</code>. Its natural home is <code>.git/hooks/pre-commit</code>, and since fw-4.6.0 there's a <code>straymark init --hooks</code> that installs it automatically. This is the <em>operational gate</em> mode — the one that prevents broken documents from reaching <code>main</code>.</p>
</li>
<li class="">
<p><strong><code>--check-pending-reviews</code> mode</strong> — <code>straymark validate --check-pending-reviews</code>. The subtlest of the three, and the one that justifies more paragraphs.</p>
</li>
</ul>
<p>Until Phase 2, a document the agent marked <code>review_required: true</code> in the frontmatter (an AIDEC with low confidence, an AILOG with high risk, etc.) sat waiting for <em>human approval</em>. But there was no canonical way to <em>signal</em> that approval. The operator read the document, mentally approved it, moved on. No structural trace of the approval. This was exactly Issue <a href="https://github.com/StrangeDaysTech/straymark/issues/67" target="_blank" rel="noopener noreferrer" class="">#67</a>.</p>
<p><code>--check-pending-reviews</code> closes that hole. The command walks all documents with <code>review_required: true</code> and lists them with their <code>confidence</code>, their <code>risk_level</code>, their author (human or agent), and their date. Approval is a commit that changes <code>review_required: true</code> → <code>review_required: false</code> with human co-authorship in the commit message — and <code>validate --check-pending-reviews</code> stops listing the document. Approval is a <em>canonical signal</em>, not a verbal agreement with oneself.</p>
<p>This is the piece that closes the agent's loop. The framework lets the agent create documents without prior human approval (Post 1, property #2: <em>"cultural permission without blocking control"</em>); but marks them for review when appropriate; and now has a command to list what's pending, with no escape hatch. No audit document gets lost silently.</p>
<hr>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="5-phase-2-closes-the-empirical-loop">5. Phase 2 closes the empirical loop<a href="https://straymark.dev/blog/validate-and-schemas-as-a-formal-layer#5-phase-2-closes-the-empirical-loop" class="hash-link" aria-label="Direct link to 5. Phase 2 closes the empirical loop" title="Direct link to 5. Phase 2 closes the empirical loop" translate="no">​</a></h2>
<p>The full CHANGELOG sentence is worth keeping because it condenses what the release means:</p>
<blockquote>
<p><em>"The release closes the empirical loop the Sentinel experiment opened: telemetry at Charter close, drift detection at Charter close, and a canonical approval signal for <code>review_required: true</code> documents (resolving issue #67)."</em></p>
</blockquote>
<p>Three pieces that close an arc that started with the six-Plan experiment (Post 3):</p>
<ol>
<li class=""><strong>Telemetry at Charter close</strong> — the YAML block Sentinel filled by hand during the experiment became the validatable <code>charter-telemetry.schema.v0.json</code>.</li>
<li class=""><strong>Drift detection at Charter close</strong> — the 145-line bash script (<code>check-plan-drift.sh</code>) became the <code>straymark charter drift</code> subcommand, integrated into the validate flow.</li>
<li class=""><strong>Canonical approval signal</strong> — what the operator did mentally became a command with structural consequences: <code>--check-pending-reviews</code>.</li>
</ol>
<p>It's the pattern the blog has seen recur: every time the framework crystallizes a practice Sentinel was doing manually, it does it after empirically validating that the practice works. The difference this time is that <strong>the command that verifies the crystallization is part of the package</strong>. Before Phase 2, Sentinel had templates, declared schemas, and the implicit promise that documents followed the schemas. After Phase 2, there is a command that <strong>checks</strong>. It isn't a capability change; it's a guarantee change.</p>
<hr>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="6-principle-12-turned-into-a-schema">6. Principle #12, turned into a schema<a href="https://straymark.dev/blog/validate-and-schemas-as-a-formal-layer#6-principle-12-turned-into-a-schema" class="hash-link" aria-label="Direct link to 6. Principle #12, turned into a schema" title="Direct link to 6. Principle #12, turned into a schema" translate="no">​</a></h2>
<p>The philosophical piece of the post — and the one I most want on record — is this:</p>
<p>The <code>$comment</code> of the three v0 schemas encodes a principle the framework had been declaring in prose since April. Post 4 named it like this: <em>"schema marked <code>v0</code> on purpose, not <code>v1</code>, because the framework's principle #12 says no schema crystallizes without a second domain validating it"</em>. Post 7 applied it to the TDE design: <em>"the framework validated principle #12 again: no schema crystallizes without a second domain"</em>. Post 10 applied it to Pattern 1 and Pattern 2: <em>"the document says so without shortcuts: the pattern is empirically validated in Sentinel. Wait for the second domain before crystallizing it higher"</em>.</p>
<p>Phase 2 does something different. <strong>It doesn't declare the principle; it writes it inside the schema itself, in a place any schema consumer is going to read.</strong> The <code>$comment</code> isn't marketing; it's protocol. Any JSON Schema 2020-12 validator exposes it; any IDE that parses the schema shows it. It's the first time the framework formalizes the provisional nature of its formalizations.</p>
<p>If I had to sum it up in one sentence: the framework validates what it has, knowing that what it has is provisional, and puts that in writing <em>in the place where validation happens</em>. Validating the provisional is discipline. Crystallizing prematurely and validating the crystallized is theology.</p>
<hr>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="7-closing">7. Closing<a href="https://straymark.dev/blog/validate-and-schemas-as-a-formal-layer#7-closing" class="hash-link" aria-label="Direct link to 7. Closing" title="Direct link to 7. Closing" translate="no">​</a></h2>
<p>What I took from the process, in four claims:</p>
<ol>
<li class="">
<p><strong>Having schemas is not the same as validating against schemas.</strong> The first step is declarative; the second is operational. Phase 2 did the second, not the first. The difference between the two framework modes — <em>"I have the promise"</em> vs. <em>"I have the command that checks it"</em> — determines whether the adopter can trust what's declared.</p>
</li>
<li class="">
<p><strong>The "artisanal bash → command flag" pattern is structural.</strong> <code>--staged</code> isn't an isolated feature. It's Phase 2's version of the same pattern Post 4 documented for the external audit cycle, that Post 10 documented for the chain-evolution CLI helpers: verbose imperative → readable declarative → versioned. Every time the framework sweeps a bash script for a flag, it raises a layer of guarantees.</p>
</li>
<li class="">
<p><strong><code>--check-pending-reviews</code> closes the agent's loop.</strong> What Post 1 named as cultural permission without pre-approval completes here: the agent can create, but documents marked for review don't get lost — the command lists them until a human approves them with an explicit commit. Without that signal, the cultural permission of Post 1 would be negligence.</p>
</li>
<li class="">
<p><strong>Declared provisionality &gt; premature formalization.</strong> The <code>$comment</code> of v0 schemas makes principle #12 protocol, not doctrine. Any tool that consumes the schema knows the formalization is provisional. It's the strongest structural honesty a young framework can have: validate what you have, without pretending what you have is definitive.</p>
</li>
</ol>
<hr>
<p><em>Anchors: PR <a href="https://github.com/StrangeDaysTech/straymark/pull/27" target="_blank" rel="noopener noreferrer" class="">#27</a> — original <code>validate</code> version (March 2026). Phase 2: PRs #73 to #79 + PR <a href="https://github.com/StrangeDaysTech/straymark/pull/80" target="_blank" rel="noopener noreferrer" class="">#80</a> — <code>fw-4.6.0 / cli-3.7.0</code> (merged 2026-05-11). Schemas: <code>dist/.straymark/schemas/{charter,charter-telemetry,audit-output}.schema.v0.json</code>. <a href="https://github.com/StrangeDaysTech/straymark/issues/67" target="_blank" rel="noopener noreferrer" class="">Issue #67</a> — origin of <code>--check-pending-reviews</code>.</em></p>
<p><em>This document was produced with assistance from generative AI tools (Claude 4.7); all responsibility for the content rests with the human author.</em></p>]]></content>
        <author>
            <name>José Villaseñor Montfort</name>
            <uri>https://github.com/montfort</uri>
        </author>
        <category label="straymark" term="straymark"/>
        <category label="validate" term="validate"/>
        <category label="schemas" term="schemas"/>
        <category label="governance" term="governance"/>
        <category label="phase-2" term="phase-2"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[Charters invisible to the agents]]></title>
        <id>https://straymark.dev/blog/charters-invisible-to-agents</id>
        <link href="https://straymark.dev/blog/charters-invisible-to-agents"/>
        <updated>2026-05-09T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[Issue #113 — the gap between having an artifact and the agent seeing it]]></summary>
        <content type="html"><![CDATA[<p><em>Six hours of session work with a capable agent and the framework's full onboarding loaded — and not once did Charters get suggested. Five minutes to apply them when asked directly. The asymmetry isn't about capability; it's about visibility.</em></p>
<!-- -->
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="1-six-hours-not-to-see-it-five-minutes-to-see-it">1. Six hours not to see it, five minutes to see it<a href="https://straymark.dev/blog/charters-invisible-to-agents#1-six-hours-not-to-see-it-five-minutes-to-see-it" class="hash-link" aria-label="Direct link to 1. Six hours not to see it, five minutes to see it" title="Direct link to 1. Six hours not to see it, five minutes to see it" translate="no">​</a></h2>
<p>Issue <a href="https://github.com/StrangeDaysTech/straymark/issues/113" target="_blank" rel="noopener noreferrer" class="">#113</a> opens with one of those sentences that, read back months later, sounds obvious and at the same time cost a lot to reach:</p>
<blockquote>
<p><em>"Time to detect: ~6 hours of session work; never autonomously surfaced. Time to resolve once user prompted: ~5 minutes."</em></p>
</blockquote>
<p>Six hours working with a capable, attentive agent, with the framework's whole canonical onboarding apparatus loaded — <code>STRAYMARK.md</code>, the project constitution, the <code>CLAUDE.md</code> checklist, the <code>/straymark-*</code> skills available, <code>/straymark-status</code> run at the start — and not once, over six hours, did the agent suggest using a Charter. When I asked for it directly, the flow was incorporated in five minutes. The asymmetry isn't about capability. It's about visibility.</p>
<p>This post covers a short, specific episode: Issue #113, opened on 7 May 2026, three days after Charters crystallized as a first-class entity in the framework (fw-4.4.0, 2 May). It's the natural counterweight to this blog's first post. That post named a property that appeared when everything was in place. This post documents what happens when a structural piece exists but <em>isn't on the surface the agent reads first</em>.</p>
<hr>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="2-the-accidental-experiment">2. The accidental experiment<a href="https://straymark.dev/blog/charters-invisible-to-agents#2-the-accidental-experiment" class="hash-link" aria-label="Direct link to 2. The accidental experiment" title="Direct link to 2. The accidental experiment" translate="no">​</a></h2>
<p>The setup wasn't designed as an experiment. It was a real project: a <em>greenfield</em> in Rust, CLI+TUI suite, on its first <code>v0.1</code> version. The agent was Claude Opus 4.7 with a 1M-token window, enough to keep the whole repo in context without paging. The flow was the canonical SpecKit one: <code>/speckit-specify</code>, <code>/speckit-plan</code>, <code>/speckit-tasks</code>, and between tasks and implement the idea of splitting into Charters should have surfaced — <em>in theory</em>.</p>
<p>The Issue formulates it with almost cold precision:</p>
<blockquote>
<p><em>"A capable, attentive agent following the canonical project onboarding (<code>DEVTRAIL.md</code>, the project constitution, <code>CLAUDE.md</code> checklist, available <code>/devtrail-*</code> skills, <code>/devtrail-status</code>) did not autonomously identify Charters as a workflow concept during plan/tasks generation, even though the project clearly fit their use case (multi-session implementation, multi-phase tasks, audit value)."</em></p>
</blockquote>
<p><em>(The Issue still uses <code>DEVTRAIL.md</code> because, given the chronology, the rebrand to StrayMark was being merged almost in parallel. The mixed nomenclature is calendar residue, not oversight.)</em></p>
<p>The project met each condition where a Charter is the right unit: multi-session implementation, multiple phases, audit value. The agent did everything right — read the constitution, ran status, identified available skills, generated a reasonable SpecKit plan — and never connected to Charters. As if the concept didn't exist. To the agent, in its model of the repo, it didn't.</p>
<p>The most uncomfortable thing about the Issue, in hindsight, is that the agent didn't fail from incapacity. It failed because the framework, without meaning to, had built a map where Charters weren't marked.</p>
<hr>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="3-nine-gaps-converging-on-one">3. Nine gaps converging on one<a href="https://straymark.dev/blog/charters-invisible-to-agents#3-nine-gaps-converging-on-one" class="hash-link" aria-label="Direct link to 3. Nine gaps converging on one" title="Direct link to 3. Nine gaps converging on one" translate="no">​</a></h2>
<p>When the operator (me) opened the Issue and sat down to audit why it had happened, the problem wasn't one thing. It was nine. And all of them were versions of the same defect:</p>























































<table><thead><tr><th>#</th><th>Gap</th><th>Where</th></tr></thead><tbody><tr><td>1</td><td>The framework's canonical document didn't list Charter as a concept</td><td><code>STRAYMARK.md</code> (then <code>DEVTRAIL.md</code>) §6/9/10/11/13/15</td></tr><tr><td>2</td><td>The <code>CLAUDE.md</code> checklist had no trigger to suggest Charter</td><td><code>dist/dist-templates/directives/CLAUDE.md</code> (also <code>GEMINI.md</code>, <code>copilot-instructions.md</code>)</td></tr><tr><td>3</td><td>Project constitutions inherited the framework's gap</td><td>Any <code>*-constitution.md</code> installed via <code>straymark init</code></td></tr><tr><td>4</td><td>No <code>/straymark-charter-new</code> skill existed</td><td>Skills directory</td></tr><tr><td>5</td><td><code>/straymark-status</code> didn't list Charters in its output</td><td>Skill + CLI subcommand <code>straymark status</code></td></tr><tr><td>6</td><td>The audit skills framed the Charter as an <em>external</em> artifact, not as a surface to generate</td><td><code>/straymark-audit-*</code> skills</td></tr><tr><td>7</td><td>Charter templates lived indistinguishable from other templates</td><td><code>dist/.straymark/templates/</code> (root)</td></tr><tr><td>8</td><td>No conceptual bridge between SpecKit (<code>plan.md</code>) and Charter</td><td>No explicit document</td></tr><tr><td>9</td><td>The mental model the agent ended up building was binary: either SpecKit, or nothing</td><td>Compounded effect</td></tr></tbody></table>
<p>Nine failures and one single defect: the Charter existed as a technical artifact (valid schema, working command, template ported from Sentinel), but wasn't named in any of the places where the agent builds its mental model of the project on entry.</p>
<p>The agent reads <code>STRAYMARK.md</code> and the constitution to understand what the project is about. If Charter doesn't appear, it isn't there. The agent reviews which skills are available to use. If there's no <code>/straymark-charter-new</code>, it isn't there. The agent runs <code>/straymark-status</code> to understand what kinds of files live in the repo. If the output doesn't mention Charters, they aren't there. Each surface the agent passes through on onboarding repeats the same silence. And the sum of silences convinces the agent the concept isn't part of this project.</p>
<hr>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="4-why-this-episode-matters-beyond-the-issue">4. Why this episode matters beyond the Issue<a href="https://straymark.dev/blog/charters-invisible-to-agents#4-why-this-episode-matters-beyond-the-issue" class="hash-link" aria-label="Direct link to 4. Why this episode matters beyond the Issue" title="Direct link to 4. Why this episode matters beyond the Issue" translate="no">​</a></h2>
<p>It's worth pausing here, because this is exactly the episode the fw-4.17.0 meta-pattern — the pattern of <em>emergent observation</em> — needed to have happened <em>first</em> in order to be formulated at all.</p>
<p>A week after #113, in <code>EMERGENT-OBSERVATION-DESIGN.md</code>, the framework named two properties whose composition produces an agent surfacing things nobody asked it to surface: formal links between artifacts (<code>originating_charter</code>, <code>originating_ailog</code>, <code>originating_spec</code> in frontmatter), and cultural permission to flag dissonances between sources. Those two properties, <em>composed</em>, produce the agent reading the AILOG, counting the <code>R&lt;N&gt;(new, not in Charter)</code> entries, and flagging the delta without being asked.</p>
<p>But there's a precondition that formulation takes for granted: that the agent <em>sees</em> the Charters on entering the repo. If the Charters aren't on the visible surface, no formal link between artifacts can compose into emergent observation — because one of the composition's terms doesn't exist for the agent.</p>
<p>Issue #113 is the episode that documented that precondition from the reverse. Fw-4.17.0 named the pattern when it was present; fw-4.12.0 (five days earlier) closed the gap that prevented it from being present at all. Without Issue #113 and its correction, the meta-pattern wouldn't have anywhere to stand. The framework doesn't surface what it can't see, and it can't see what the surface doesn't name.</p>
<hr>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="5-the-response-multiplying-surfaces">5. The response: multiplying surfaces<a href="https://straymark.dev/blog/charters-invisible-to-agents#5-the-response-multiplying-surfaces" class="hash-link" aria-label="Direct link to 5. The response: multiplying surfaces" title="Direct link to 5. The response: multiplying surfaces" translate="no">​</a></h2>
<p>PR <a href="https://github.com/StrangeDaysTech/straymark/pull/122" target="_blank" rel="noopener noreferrer" class="">#122</a> (<code>fw-4.12.0</code>, 9 May) closed the nine gaps with a single operational strategy: <em>name Charter in every place where the agent builds its model of the project</em>. The PR's numbers are honest: +1211 lines, −92 lines, 36 files modified, almost entirely documentation and templates. There was no code refactor. There was a redistribution of visibility.</p>
<p>Main changes, grouped:</p>
<ul>
<li class=""><strong>In the canonical document</strong> (<code>STRAYMARK.md</code>): a new section dedicated to Charter as a concept (§15), plus rows in the §6/9/10/11/13 tables that listed document types without Charter.</li>
<li class=""><strong>In agent directives</strong> (<code>CLAUDE.md</code>, <code>GEMINI.md</code>, <code>copilot-instructions.md</code>): an explicit trigger teaching the agent when to <em>suggest</em> a Charter, not only when to create one if asked.</li>
<li class=""><strong>In skills</strong>: new <code>/straymark-charter-new</code> (Claude, Gemini, agnostic versions). <code>/straymark-status</code> updated to list active Charters.</li>
<li class=""><strong>In the CLI</strong>: a <code>Charters</code> block added to <code>straymark status</code> output, so the agent running the command sees it among the initial signals.</li>
<li class=""><strong>In templates</strong>: moved to a dedicated subdirectory <code>dist/.straymark/templates/charter/</code>, no longer mixed with other templates.</li>
<li class=""><strong>New document</strong>: <code>SPECKIT-CHARTER-BRIDGE.md</code> (171 lines, EN/ES/zh-CN). Makes the bridge between SpecKit's <code>plan.md</code> and StrayMark's Charter explicit — the four criteria for a SpecKit feature to produce one or more Charters, the three cases where it doesn't apply, the four granularity heuristics, the <code>originating_spec ↔ originating_charter ↔ originating_ailog</code> frontmatter linkage.</li>
</ul>
<p>The epilogue of <code>SPECKIT-CHARTER-BRIDGE.md</code> records the case that originated the entire change without metaphor:</p>
<blockquote>
<p><em>"Cited the empirical context (issue #113): Greenfield Rust CLI/TUI suite, Claude Opus 4.7 onboarding via canonical entry points. Charters were eventually adopted (2 Charters: foundation + MVP) only after explicit user prompt — confirming the gap was systemic, not session-specific. This document removes the gap."</em></p>
</blockquote>
<p><em>The gap was systemic, not session-specific.</em> That sentence is the Issue's operational lesson. It wasn't a distracted agent one day; it was the framework that didn't speak to the agent about Charters in any of the places the agent was looking.</p>
<hr>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="6-what-i-learned-about-structural-visibility">6. What I learned about structural visibility<a href="https://straymark.dev/blog/charters-invisible-to-agents#6-what-i-learned-about-structural-visibility" class="hash-link" aria-label="Direct link to 6. What I learned about structural visibility" title="Direct link to 6. What I learned about structural visibility" translate="no">​</a></h2>
<p>The lesson, written in prose and not in a table:</p>
<p>Creating an artifact in a framework is not the same as making it visible to the agents that work in repos of that framework. They're two steps. The first — schema, command, template, examples — is the visible step: it shows up in the CHANGELOG, ships in the release, appears in <code>git log</code>. The second — anchoring the artifact on every surface where the agent enters the repo — is invisible: nothing about the second step appears as a <em>feature</em> in itself; it's cross-references, lines in checklists, items in outputs, sections in docs. But the second step is what decides whether the first one exists for the agent.</p>
<p>The framework governs agents that read the repo from outside the session where the artifact was created. Each agent entering the repo builds its mental model from scratch, reading the canonical documents, the available skills, the status outputs. If the artifact isn't named there, it doesn't exist in the model. And a model without the artifact doesn't propose using it, doesn't audit its absence, doesn't flag related dissonances. The agent's technical capability is irrelevant if the repo's surface doesn't give it the right noun on entry.</p>
<p>That's what I now call, internally, <em>structural visibility</em>. It isn't a property of the agent. It's a property of the repo, and by extension, a responsibility of the framework: every time it crystallizes a new concept, it has to multiply the surfaces where that concept is named. One single surface — the schema, the command, the template — isn't enough. There are nine, minimum, and they're the nine in Issue #113.</p>
<hr>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="7-closing">7. Closing<a href="https://straymark.dev/blog/charters-invisible-to-agents#7-closing" class="hash-link" aria-label="Direct link to 7. Closing" title="Direct link to 7. Closing" translate="no">​</a></h2>
<p>What I took from the process, in four claims:</p>
<ol>
<li class="">
<p><strong>Existing as an artifact isn't the same as being visible to the agent.</strong> Charters had schema, command, template, examples — and were still invisible. The difference between the two states is the nine surfaces of Issue #113.</p>
</li>
<li class="">
<p><strong>Six hours vs. five minutes.</strong> A capable agent can spend hours not detecting what, once named, takes minutes to integrate. The asymmetry doesn't diagnose the agent; it diagnoses the repo.</p>
</li>
<li class="">
<p><strong>Structural visibility is the framework's responsibility.</strong> When it crystallizes a concept, it doesn't end with the command that creates it. It ends when the concept is named on every surface where the agent builds its model of the repo: canonical document, directive, skill, status, template, bridge to other frameworks.</p>
</li>
<li class="">
<p><strong>Without structural visibility there is no emergent observation.</strong> The properties that later made it possible for an agent to surface dissonances between sources — formal links + cultural permission — need, as a precondition, the artifacts to be visible from the first moment of onboarding. Issue #113 documents what happens when that precondition is missing.</p>
</li>
</ol>
<p>Next, in the following post: an episode adjacent to this one — <em>the rebranding to StrayMark</em> (<code>H-08</code>). Issue #113 was resolved in the same temporal arc as the rename from DevTrail to StrayMark, and they share something worth naming — the responsibility of a framework to declare its identity with clarity, both to its agents and to its adopters.</p>
<hr>
<p><em>Anchors: <a href="https://github.com/StrangeDaysTech/straymark/issues/113" target="_blank" rel="noopener noreferrer" class="">Issue #113</a> (opened 2026-05-07). <a href="https://github.com/StrangeDaysTech/straymark/pull/122" target="_blank" rel="noopener noreferrer" class="">PR #122</a> — <code>fw-4.12.0</code> (merged 2026-05-09). Document generated by the PR: <a href="https://github.com/StrangeDaysTech/straymark/blob/main/dist/.straymark/00-governance/SPECKIT-CHARTER-BRIDGE.md" target="_blank" rel="noopener noreferrer" class=""><code>SPECKIT-CHARTER-BRIDGE.md</code></a>.</em></p>
<p><em>This document was produced with assistance from generative AI tools (Claude 4.7); all responsibility for the content rests with the human author.</em></p>]]></content>
        <author>
            <name>José Villaseñor Montfort</name>
            <uri>https://github.com/montfort</uri>
        </author>
        <category label="straymark" term="straymark"/>
        <category label="charters" term="charters"/>
        <category label="agents" term="agents"/>
        <category label="observability" term="observability"/>
        <category label="governance" term="governance"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[The rebrand to StrayMark]]></title>
        <id>https://straymark.dev/blog/the-rebrand-to-straymark</id>
        <link href="https://straymark.dev/blog/the-rebrand-to-straymark"/>
        <updated>2026-05-09T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[The fourth rename — this time with a public ADR and a disciplined arc]]></summary>
        <content type="html"><![CDATA[<p><em>The fourth rename, unlike the first three, wasn't searching for the concept — it came from a trademark conflict investigation. Eight days, an ADR, five PRs in forty-three minutes. The first disciplined rebrand of the project, and what "in scope / out of scope" meant when applied to its own past.</em></p>
<!-- -->
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="1-the-rename-that-wasnt-looking-for-the-concept">1. The rename that wasn't looking for the concept<a href="https://straymark.dev/blog/the-rebrand-to-straymark#1-the-rename-that-wasnt-looking-for-the-concept" class="hash-link" aria-label="Direct link to 1. The rename that wasn't looking for the concept" title="Direct link to 1. The rename that wasn't looking for the concept" translate="no">​</a></h2>
<p>ADR <code>2026-05-08-001</code> opens with a sentence that, for anyone who read Post 2 of this blog, sounds out of place:</p>
<blockquote>
<p><em>"The decision is motivated by legal certainty over the trademark rather than by product strategy or user feedback."</em></p>
</blockquote>
<p>The three renames of January (Chronicle → Monimen → DevTrail) were rushed searches for the concept. Each one ratified a distinct intuition about what the product was. None had an ADR; commit messages were all the documentary justification that existed.</p>
<p>The fourth rename, the May one, is of a different nature. It doesn't come from looking for the concept. It comes from a trademark conflict investigation — commissioned via a Claude.ai web session in early May — which surfaced <em>"legal uncertainty about trademark ownership as the project gained adopters."</em> In January the project had zero adopters and renames could be improvised. In May the project had one adopter (Sentinel), 286 <em>crate</em> downloads, two open issues, and a public manifesto promising structured governance. The threshold for improvising another rebrand had already been crossed.</p>
<p>This post covers three things: the disciplined decision made on 8 May, the operational arc of five PRs in forty-three minutes the following day, and the residuals that surfaced two days later. And, underneath all that, a subtler distinction: when a rebrand is purely surface, and when — without quite meaning to — it also changes identity.</p>
<hr>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="2-the-first-disciplined-rename">2. The first disciplined rename<a href="https://straymark.dev/blog/the-rebrand-to-straymark#2-the-first-disciplined-rename" class="hash-link" aria-label="Direct link to 2. The first disciplined rename" title="Direct link to 2. The first disciplined rename" translate="no">​</a></h2>
<p>What's new on 8 May is the form. This time there was:</p>
<ul>
<li class=""><strong>A prior investigation.</strong> It wasn't decide-rebrand-then-justify; first a conflict was detected, then the decision followed from it.</li>
<li class=""><strong>A public ADR.</strong> Three alternatives explicitly considered (keep "DevTrail" and accept the trademark risk; hybrid branding with legacy + new in parallel; reset to v0.1.0 under StrayMark as "new project"). All three dismissed with literal argument.</li>
<li class=""><strong>A temporal calculation.</strong> The ADR itself frames the cost this way: <em>"The rename window narrows over time — every new adopter increases the cost of changing later... The legal risk dominates. Acting now, with one self-owned adopter, is materially cheaper than acting later under pressure."</em></li>
</ul>
<p>The reason the calculation matters is structural. If the rebrand had waited two more months — until the second adopter showed up, or the third — the migration cost would have multiplied. Each adopter repo would have had to run <code>mv .devtrail .straymark</code>, update its <code>CLAUDE.md</code>/<code>AGENT.md</code>, regenerate its pipelines. With a single adopter (the operator himself), the cost was contained and reversible. What the ADR calls <em>"acting now is materially cheaper"</em> is exactly that: the rebrand was an exercise in minimizing future debt, not a marketing decision.</p>
<p>There's an unintended echo with Post 2. That one closed with the line <em>"there probably won't be another rebranding."</em> This post, written from May, knows there was. The difference between promising and ratifying is that the fourth rename, unlike the first three, was forced by external circumstances no operator can foresee — a trademark conflict — and was faced with the discipline January didn't have.</p>
<hr>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="3-in-scope-out-of-scope--the-adrs-masterpiece">3. <em>In scope</em>, <em>out of scope</em> — the ADR's masterpiece<a href="https://straymark.dev/blog/the-rebrand-to-straymark#3-in-scope-out-of-scope--the-adrs-masterpiece" class="hash-link" aria-label="Direct link to 3-in-scope-out-of-scope--the-adrs-masterpiece" title="Direct link to 3-in-scope-out-of-scope--the-adrs-masterpiece" translate="no">​</a></h2>
<p>The ADR section that shapes the rest of this post is the one that distinguishes what gets renamed from what gets preserved. Cited literally:</p>
<blockquote>
<p><em>"In scope (the 'live state' of the project): all identifiers in source code, Cargo metadata, source-of-truth path, 30 skill/workflow files, public documentation, CI workflows, GitHub repository name."</em></p>
</blockquote>
<blockquote>
<p><em>"Out of scope (immutable history, preserved verbatim): all commits, commit messages, and git history; all tags published before this ADR; all release titles and bodies of releases published before; all prior CHANGELOG.md sections."</em></p>
</blockquote>
<p>That distinction is the rebrand's armature. The <em>live</em> — paths, commands, URLs, release assets, README — is renamed in one stroke. The <em>historic</em> — git log, <code>devtrail-cli@3.10.0</code> tags, prior CHANGELOG sections, closed issues — is preserved literally. The project doesn't rewrite itself backwards.</p>
<p>It's the same archival discipline that Post 3 documented for the Plan → Charter rename, now applied to the framework-wide operational rebrand. I lay it out as a table because it helps to see it:</p>




























































<table><thead><tr><th>Layer</th><th>Gets renamed</th><th>Gets preserved</th></tr></thead><tbody><tr><td>Filesystem paths</td><td><code>.devtrail/</code> → <code>.straymark/</code></td><td>—</td></tr><tr><td>Rust source</td><td><code>devtrail-cli</code> → <code>straymark-cli</code></td><td>—</td></tr><tr><td>Skills/workflows</td><td>30 files <code>devtrail-*</code> → <code>straymark-*</code></td><td>—</td></tr><tr><td>Public docs</td><td>README, CLAUDE.md, ADOPTION-GUIDE</td><td>—</td></tr><tr><td>CI/CD</td><td>asset names, binary paths</td><td>Tag prefixes (<code>fw-</code>, <code>cli-</code>) untouched</td></tr><tr><td>GitHub repo</td><td><code>StrangeDaysTech/devtrail</code> → <code>StrangeDaysTech/straymark</code></td><td>—</td></tr><tr><td>CHANGELOG</td><td>New <code>fw-4.11.0</code> entry on top</td><td>Prior sections literal</td></tr><tr><td>Published tags</td><td>—</td><td><code>fw-4.10.0</code>, <code>cli-3.10.0</code>, etc. preserved</td></tr><tr><td>Whole git log</td><td>—</td><td>Messages with "DevTrail" intact</td></tr><tr><td>Legacy <em>crate</em></td><td>—</td><td><code>devtrail-cli@3.10.0</code> on crates.io, not <em>yanked</em></td></tr></tbody></table>
<p>Version continuity is the most visible proof. The next release wasn't <code>0.1.0</code> or <code>1.0.0</code>; it was <code>fw-4.11.0</code> and <code>cli-3.11.0</code>. The numbering declares, without metaphor, that the project is the same project.</p>
<hr>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="4-five-prs-forty-three-minutes">4. Five PRs, forty-three minutes<a href="https://straymark.dev/blog/the-rebrand-to-straymark#4-five-prs-forty-three-minutes" class="hash-link" aria-label="Direct link to 4. Five PRs, forty-three minutes" title="Direct link to 4. Five PRs, forty-three minutes" translate="no">​</a></h2>
<p>On 9 May, between 06:05 and 06:48 UTC, five PRs merged in a chain:</p>



































<table><thead><tr><th>PR</th><th>UTC time</th><th>What it did</th></tr></thead><tbody><tr><td><a href="https://github.com/StrangeDaysTech/straymark/pull/114" target="_blank" rel="noopener noreferrer" class="">#114</a></td><td>06:05</td><td>Merge of the ADR itself. Zero code changes — first you fix the decision.</td></tr><tr><td><a href="https://github.com/StrangeDaysTech/straymark/pull/115" target="_blank" rel="noopener noreferrer" class="">#115</a></td><td>06:42</td><td>174 <em>renames</em> + 74 modifications. Rust source (38 files), tests (18), <code>dist/.devtrail/</code> → <code>dist/.straymark/</code> (122 files via <code>git mv</code>), 30 skills × 3 platforms.</td></tr><tr><td><a href="https://github.com/StrangeDaysTech/straymark/pull/116" target="_blank" rel="noopener noreferrer" class="">#116</a></td><td>06:44</td><td>Public docs in three languages (EN/ES/zh-CN). CHANGELOG preamble updated: <em>"StrayMark (formerly DevTrail; rebranded 2026-05-08)"</em>.</td></tr><tr><td><a href="https://github.com/StrangeDaysTech/straymark/pull/117" target="_blank" rel="noopener noreferrer" class="">#117</a></td><td>06:45</td><td>Release workflows. Asset names (<code>straymark-cli-*</code>), release titles. Tag prefixes untouched.</td></tr><tr><td><a href="https://github.com/StrangeDaysTech/straymark/pull/118" target="_blank" rel="noopener noreferrer" class="">#118</a></td><td>06:48</td><td>Bump <code>fw-4.11.0</code> / <code>cli-3.11.0</code>. New CHANGELOG section.</td></tr></tbody></table>
<p>The order is deliberate and goes from outside in: first the law (ADR), then internal code, then what adopters see (docs), then distribution (CI), finally the consummated fact (release). This sequence has an archival reading: when someone six months out reviews <code>git log</code> chronologically, they'll first see the decision, then the implementation. Causality lives in the repo.</p>
<p>It's worth naming a piece of the arc that broke the original plan. The ADR had contemplated nine distinct PRs (one per logical layer). In practice, the CLI tests depended on <em>hardcoded</em> paths — <code>include_str!("../../dist/.devtrail/...")</code> — and breaking the path without updating the tests at the same time left CI red. The plan compacted to five because the layers were technically coupled, not because the conceptual discipline failed. The PR #115 note records it without softening: <em>"The consolidation was forced by tight coupling: tests use <code>include_str!</code> on <code>dist/.devtrail/</code> paths."</em></p>
<p>Forty-three minutes for a rebrand that touched around two hundred sixty files. The pace is only possible because the ADR had closed every decision before code was touched. Framework principle #6 — <em>"when the proposal is well-written, implementation is execution, not design"</em> — found another validation case, similar to the external audit cycle one in Post 4.</p>
<hr>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="5-why-straymark-does-change-more-than-the-name">5. Why StrayMark does change more than the name<a href="https://straymark.dev/blog/the-rebrand-to-straymark#5-why-straymark-does-change-more-than-the-name" class="hash-link" aria-label="Direct link to 5. Why StrayMark does change more than the name" title="Direct link to 5. Why StrayMark does change more than the name" translate="no">​</a></h2>
<p>Up to here the ADR is clear: the rebrand is on the surface, the conceptual identity is preserved. But there's a nuance worth naming.</p>
<p>PR <a href="https://github.com/StrangeDaysTech/straymark/pull/120" target="_blank" rel="noopener noreferrer" class="">#120</a> — merged hours after the main arc, the same 9 May — added the <em>"Why StrayMark?"</em> section to the README. It isn't code; it's a manifesto. And it says things no prior document of the project had articulated:</p>
<blockquote>
<p><em>"Code is just the fossil trace of a mental battle. Real engineering happens in the chaos of decisions, calculated risks, and the paths you chose not to take. Traditionally, all that human trail is discarded as stray marks (accidental smudges) in a project's history. At Strange Days Tech, we believe those marks are the signal, not the noise."</em></p>
</blockquote>
<p>The name choice, viewed from the manifesto, isn't arbitrary. The <em>stray marks</em> — the erratic traces, the accidental tracks most projects discard — are exactly what the framework drags to the foreground: AIDECs, AILOGs, TDEs, Charters. What in any conventional project would be discardable noise is, in this project, the raw material of audit. The name embodies the product's thesis in a way <em>DevTrail</em> never did. <em>DevTrail</em> was a neutral path; <em>StrayMark</em> is a claim.</p>
<p>The manifesto closes with three lines that later became what an editor would call an operational <em>tagline</em>:</p>
<blockquote>
<p><em>"Capture the noise. Weave the signal. Humanize the machine."</em></p>
</blockquote>
<p>Here's the small interesting tension of the rebrand. The ADR says only the surface changed; the manifesto from the same day suggests the identity was also articulated — perhaps for the first time with clarity. It's not a contradiction: the moment of the operational rebrand was used to write down what was already in the project but hadn't been named yet. The identity didn't change. It became legible.</p>
<hr>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="6-what-was-left-undone">6. What was left undone<a href="https://straymark.dev/blog/the-rebrand-to-straymark#6-what-was-left-undone" class="hash-link" aria-label="Direct link to 6. What was left undone" title="Direct link to 6. What was left undone" translate="no">​</a></h2>
<p>Even with a public ADR and a disciplined arc, <em>"complete"</em> remains an approximation.</p>
<p>Two days after the rebrand, while Sentinel was preparing its next external audit cycle, the agent surfaced three classes of residuals. The chronology — captured honestly in <code>CHANGELOG.md</code> as inline errata — is worth keeping visible:</p>
<ul>
<li class=""><strong>PR <a href="https://github.com/StrangeDaysTech/straymark/pull/137" target="_blank" rel="noopener noreferrer" class="">#137</a></strong> (11 May, 22:55) — <em>Orphaned skill directories</em>. The rebrand rewrote the <code>name:</code> field inside each <code>SKILL.md</code>, but didn't rename the directories of the three platforms (<code>.gemini/skills/devtrail-*</code>, <code>.claude/skills/devtrail-*</code>, <code>.agent/workflows/devtrail-*.md</code>). Thirty orphaned artifacts: new name, old path. Gemini CLI reported it as ten conflict warnings at startup.</li>
<li class=""><strong>PR <a href="https://github.com/StrangeDaysTech/straymark/pull/138" target="_blank" rel="noopener noreferrer" class="">#138</a></strong> (11 May, 23:32) — <em>Legacy Charter paths</em>. Three framework artifacts still referenced <code>docs/charters/</code> after <code>fw-4.12.0</code> had migrated the canonical path to <code>.straymark/charters/</code>. Worst of all: the <code>pre-pr.sh</code> hook was gated on <code>[ ! -d docs/charters ]</code>, which made for a silent <em>exit 0</em> for any post-4.12.0 adopter. The drift check had been installed for seven months but was no-op.</li>
<li class=""><strong>PR <a href="https://github.com/StrangeDaysTech/straymark/pull/139" target="_blank" rel="noopener noreferrer" class="">#139</a></strong> (12 May, 12:02) — <em>Broken installers</em>. <code>install.sh</code> and <code>install.ps1</code> still pointed to <code>REPO=StrangeDaysTech/devtrail</code>, <code>BINARY=devtrail</code>, asset name <code>devtrail-cli-v*</code>. The README — already rebranded — pointed to the new URL. Result: any user copying the README command from 9 May onward got a GitHub 404 running the installer. <em>The product was broken in production for seventy-two hours.</em></li>
<li class=""><strong>PR <a href="https://github.com/StrangeDaysTech/straymark/pull/140" target="_blank" rel="noopener noreferrer" class="">#140</a></strong> (12 May, 16:49) — <em>Micro-residual</em>. Line one of <code>.gitignore</code> still read <code># DevTrail - .gitignore</code>. Plus a new entry for <code>Aparador/</code> in internal-dev patterns.</li>
</ul>
<p>The lesson isn't that the discipline was insufficient. It's that discipline <em>does not prevent</em> residuals — it makes them findable, documentable, and repairable in a public inline errata. The first three renames (January) probably had equivalent residuals; we never cataloged them because there was no documentary habit. The fourth rebrand cataloged them. It's the first project rebrand that admits, in the public repo and in the CHANGELOG itself, that the operator didn't catch everything on the first pass.</p>
<p>The most uncomfortable detail — broken installers for seventy-two hours — is the one I most care to record. If instead of one solo adopter (the operator) there had been a team, that window would have hit real users. <em>Acting now, with one self-owned adopter, was materially cheaper</em>, says the ADR. That's exactly what the sentence was buying: the right to be wrong for seventy-two hours without hurting anyone.</p>
<hr>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="7-closing">7. Closing<a href="https://straymark.dev/blog/the-rebrand-to-straymark#7-closing" class="hash-link" aria-label="Direct link to 7. Closing" title="Direct link to 7. Closing" translate="no">​</a></h2>
<p>What I took from the process, in four claims:</p>
<ol>
<li class="">
<p><strong>Not all renames are the same type.</strong> The three of January were looking for the concept; the May one was defending the project against future legal debt. Only the May one could be done with a public ADR, because only the May one was born of external evidence and not internal intuition.</p>
</li>
<li class="">
<p><strong>The surface vs. identity distinction belongs to the document, not to rhetoric.</strong> The ADR itself declares what gets renamed and what gets preserved. That list — paths yes, git log no; release titles yes, prior tags no — is the rebrand's armature. Without that explicit list, <em>"rebrand"</em> means anything you want.</p>
</li>
<li class="">
<p><strong>Identity can be made legible without changing.</strong> The <em>"Why StrayMark?"</em> manifesto didn't invent what the project was; it articulated it clearly for the first time. The operational rebrand was used to write down what was already in the code but hadn't made it to the README. Identity wasn't rewritten — it was published.</p>
</li>
<li class="">
<p><strong>Discipline does not prevent residuals; it makes them findable.</strong> Four <em>errata</em> PRs two days later aren't a failure of the rebrand; they're evidence that the rebrand was honest enough to admit what slipped through. The three January renames probably had equivalents; they were never documented.</p>
</li>
</ol>
<p>Next, in the following post, an episode that connects directly with the last point: <em>TDE as a mechanism for naming transversal debt</em> (<code>H-09</code>). The first real case the framework used to articulate how to surface debt — and which left a hard lesson about stacked-PRs that deserves its own paragraph when we get there.</p>
<hr>
<p><em>Anchors: ADR <a href="https://github.com/StrangeDaysTech/straymark/blob/main/docs/decisions/ADR-2026-05-08-rebranding-straymark.md" target="_blank" rel="noopener noreferrer" class=""><code>2026-05-08-001</code></a>. Core arc: PRs <a href="https://github.com/StrangeDaysTech/straymark/pull/114" target="_blank" rel="noopener noreferrer" class="">#114</a> · <a href="https://github.com/StrangeDaysTech/straymark/pull/115" target="_blank" rel="noopener noreferrer" class="">#115</a> · <a href="https://github.com/StrangeDaysTech/straymark/pull/116" target="_blank" rel="noopener noreferrer" class="">#116</a> · <a href="https://github.com/StrangeDaysTech/straymark/pull/117" target="_blank" rel="noopener noreferrer" class="">#117</a> · <a href="https://github.com/StrangeDaysTech/straymark/pull/118" target="_blank" rel="noopener noreferrer" class="">#118</a>. Manifesto: PR <a href="https://github.com/StrangeDaysTech/straymark/pull/120" target="_blank" rel="noopener noreferrer" class="">#120</a>. Residuals: PRs <a href="https://github.com/StrangeDaysTech/straymark/pull/137" target="_blank" rel="noopener noreferrer" class="">#137</a> · <a href="https://github.com/StrangeDaysTech/straymark/pull/138" target="_blank" rel="noopener noreferrer" class="">#138</a> · <a href="https://github.com/StrangeDaysTech/straymark/pull/139" target="_blank" rel="noopener noreferrer" class="">#139</a> · <a href="https://github.com/StrangeDaysTech/straymark/pull/140" target="_blank" rel="noopener noreferrer" class="">#140</a>. Release: <code>fw-4.11.0</code> / <code>cli-3.11.0</code>.</em></p>
<p><em>This document was produced with assistance from generative AI tools (Claude 4.7); all responsibility for the content rests with the human author.</em></p>]]></content>
        <author>
            <name>José Villaseñor Montfort</name>
            <uri>https://github.com/montfort</uri>
        </author>
        <category label="straymark" term="straymark"/>
        <category label="rebranding" term="rebranding"/>
        <category label="governance" term="governance"/>
        <category label="identity" term="identity"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[Charters as a first-class entity, and the external audit cycle]]></title>
        <id>https://straymark.dev/blog/charters-and-the-external-audit-cycle</id>
        <link href="https://straymark.dev/blog/charters-and-the-external-audit-cycle"/>
        <updated>2026-05-06T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[From manual ritual in Sentinel to canonized CLI command]]></summary>
        <content type="html"><![CDATA[<p><em>Forty minutes of copy-paste per Charter on top of two hours of work. Discipline was working; the ritual was becoming the problem. How the Charter became a first-class CLI entity, and the architectural decision that left audit orchestration to the framework and the prompt-eval to anyone else.</em></p>
<!-- -->
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="1-when-discipline-starts-to-feel-like-ceremony">1. When discipline starts to feel like ceremony<a href="https://straymark.dev/blog/charters-and-the-external-audit-cycle#1-when-discipline-starts-to-feel-like-ceremony" class="hash-link" aria-label="Direct link to 1. When discipline starts to feel like ceremony" title="Direct link to 1. When discipline starts to feel like ceremony" translate="no">​</a></h2>
<p>By late April, Sentinel closed its fourth Charter of the month with a feeling that, in writing, sounds slightly pathetic: external audit was working — Copilot 9.25, Gemini 9.5, the drift script with zero false positives — but every close had me opening three files by hand, copying three prompts into three different windows, waiting for replies, pasting three calibration YAMLs back into the telemetry file, and eyeballing the hashes to make sure they matched. Forty minutes of copy-paste per Charter on top of work that took two hours. Discipline was working; the ritual was becoming a problem.</p>
<p>The <code>audit-skills-design.md</code> proposal, written on 3 May, named it without softening:</p>
<blockquote>
<p><em>"If at every close the operator had to manually move data between files, throughput would collapse and discipline would stop being virtuous friction and turn into ceremony. Whatever can be automated reversibly should be automated; the documents are kept for ex-post human audit."</em></p>
</blockquote>
<p>This post covers three days — from 2 to 6 May 2026 — during which two parallel arcs finished at the same time. One: the Charter stopped being artisanal practice and became a first-class entity of the CLI. Two: the external audit cycle stopped being a manual ritual with ad-hoc prompts and became a canonical command (with a counterintuitive architectural decision behind it that deserves its own section).</p>
<hr>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="2-what-sentinel-was-already-doing-and-what-straymark-didnt-have">2. What Sentinel was already doing, and what StrayMark didn't have<a href="https://straymark.dev/blog/charters-and-the-external-audit-cycle#2-what-sentinel-was-already-doing-and-what-straymark-didnt-have" class="hash-link" aria-label="Direct link to 2. What Sentinel was already doing, and what StrayMark didn't have" title="Direct link to 2. What Sentinel was already doing, and what StrayMark didn't have" translate="no">​</a></h2>
<p>The 3 May proposal puts it in a sentence that's barely elegant but precisely accurate about what was happening:</p>
<blockquote>
<p><em>"Sentinel has the skills, StrayMark doesn't."</em></p>
</blockquote>
<p>What Sentinel had: <code>sentinel/.claude/skills/plan-audit/</code> and <code>plan-audit-review/</code> — local skills that generated a prompt, calibrated the response on return, and merged it into telemetry. They worked. They had been validated across six cycles. But they were coupled to Sentinel-specific paths (<code>docs/plans/</code>, <code>internal/modules/</code>, <code>go vet</code>) and to the <em>"Plan"</em> vocabulary, which had already been renamed to Charter a week earlier.</p>
<p>What StrayMark didn't have: nothing equivalent. The framework, up to April, was documentation + skills + a CLI with <code>init</code>, <code>update</code>, <code>remove</code>. The unit that in Sentinel was called <em>Plan</em> — the bounded unit, declared <em>ex-ante</em>, audited <em>ex-post</em> — didn't exist as a CLI artifact. It existed as practice.</p>
<p>The arc of fw-4.4.0 (2 May) and of fw-4.7 → 4.9 (3-5 May) consists, almost verbatim, of porting what Sentinel did by hand into generic commands that any framework adopter can invoke. The migration table, copied from <code>cli-roadmap.md</code>, is honest about the origin:</p>





























<table><thead><tr><th>Sentinel artifact <em>(April 2026)</em></th><th>StrayMark equivalent <em>(May 2026)</em></th></tr></thead><tbody><tr><td><code>TEMPLATE.md</code> (v3) in <code>docs/plans/</code></td><td><code>dist/.straymark/templates/charter-template.md</code></td></tr><tr><td><code>scripts/check-plan-drift.sh</code> (145 bash lines)</td><td><code>straymark charter drift</code> (Rust subcommand)</td></tr><tr><td>Local skill <code>plan-audit</code></td><td>Generic skill <code>straymark-audit-prepare</code></td></tr><tr><td>Dual reports in <code>audit/plans/05,06/{copilot,gemini,claude}.md</code></td><td>Canonical output of <code>straymark charter audit</code></td></tr><tr><td>Hand-edited telemetry YAML</td><td><code>dist/.straymark/schemas/charter-telemetry.schema.v0.json</code></td></tr></tbody></table>
<p>The fw-4.4.0 CHANGELOG frames it without metaphor: <em>"Crystallizes the Charter pattern — bounded, auditable units of work declared ex-ante and validated ex-post — that emerged from the 6-cycle Sentinel /plan-audit experiment."</em> The crystallization is the point. What in April was custom-with-a-bash-script, in May is a command with a validatable schema.</p>
<hr>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="3-what-happens-when-something-becomes-first-class">3. What happens when something becomes "first-class"<a href="https://straymark.dev/blog/charters-and-the-external-audit-cycle#3-what-happens-when-something-becomes-first-class" class="hash-link" aria-label="Direct link to 3. What happens when something becomes &quot;first-class&quot;" title="Direct link to 3. What happens when something becomes &quot;first-class&quot;" translate="no">​</a></h2>
<p>PR #65 (fw-4.4.0 / cli-3.6.0, 2 May) does three concrete things:</p>
<ul>
<li class="">It creates the <code>straymark charter new</code> command. Auto-increments the number (<code>NN-slug.md</code>), pre-populates the origin (<code>originating_ailogs</code> if it's born from a prior AILOG; <code>originating_spec</code> if it's born from a SpecKit <code>plan.md</code>), and supports the <code>--type X|S|M|L</code> flag to fix the size from the first moment.</li>
<li class="">It introduces <code>charter-template.md</code>, ported from Sentinel's <code>TEMPLATE.md</code> v3. It carries embedded the six conventions that the April experiment was crystallizing cycle by cycle: Local/Production checks separation, effort in time (not story points), structured sub-sections, <code>R&lt;N&gt;</code> risk documentation, closure with post-merge reconciliation via AILOG, and auto-checklist drift.</li>
<li class="">It ships <code>dist/.straymark/schemas/charter.schema.v0.json</code> — the schema marked <code>v0</code> on purpose, not <code>v1</code>, because the framework's principle #12 says no schema crystallizes without a second domain validating it. Sentinel is one domain. The second is missing.</li>
</ul>
<p>PR #68 (3 May) does something that looks small but matters: the <em>atomic Charter closure pattern</em>, format v4. In Sentinel, the step <em>"update the Plan-doc post-merge if the AILOG documents divergences"</em> existed as a note in the TEMPLATE but had no systematic trigger. In practice, that meant when there was divergence between what was declared and what was delivered, the operator (me) relied on memory to reconcile the document — and memory failed. The drift stayed in the repo for days, sometimes weeks, until the next cycle caught it. Format v4 makes the reconciliation a mandatory step of closure, not a marginal note.</p>
<p>PR #69 (same day) closes one friction detail: manual numbering. Before, you had to decide whether the next Charter was 11 or 12; now <code>straymark charter new</code> reads the directory and proposes the next number. Pure UX. But it's the class of friction that, summed across twenty Charters, decides whether the framework gets used or abandoned.</p>
<p>The three PRs shipped in the same commit storm of a Sunday and a Monday. That cadence is deliberate: once the pattern crystallizes, UX details have to close <em>together</em>, not in separate bumps that leave the adopter with half the flow.</p>
<hr>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="4-three-releases-in-a-day">4. Three releases in a day<a href="https://straymark.dev/blog/charters-and-the-external-audit-cycle#4-three-releases-in-a-day" class="hash-link" aria-label="Direct link to 4. Three releases in a day" title="Direct link to 4. Three releases in a day" translate="no">​</a></h2>
<p>What came next — fw-4.7.0, fw-4.8.0, fw-4.9.0 — are consecutive releases of the external audit cycle. The <code>audit-skills-rollout.md</code> proposal records the pace without disguise:</p>
<blockquote>
<p><em>"Phase 1 executed in 1 calendar day (5 sequential PRs on 3 May 2026), substantially faster than the 1.5-2 weeks focused estimate. The throughput is due to the design in <code>audit-skills-design.md</code> already having the decisions crystallized (D1/D2/D3) and the arborist heuristic with explicit graceful-degradation — there were no pending decisions during implementation. It serves as additional operational evidence for principle #6 (when the proposal is well-written, implementation is execution, not design)."</em></p>
</blockquote>
<p>The concrete external audit cycle consists of three chained commands:</p>
<ol>
<li class=""><code>straymark charter audit prepare &lt;CHARTER-NN&gt;</code> — generates canonical prompts for external auditors from the closed Charter, its associated AILOG, and the diff of touched files. Output: three <code>.prompt.md</code> files in <code>audit/&lt;CHARTER-NN&gt;/{copilot,gemini,claude}.prompt.md</code>.</li>
<li class=""><em>(The human carries those prompts to their auditor of choice, receives replies, pastes them back.)</em></li>
<li class=""><code>straymark charter audit collect &lt;CHARTER-NN&gt;</code> — takes the responses, validates each one against the audit schema, merges calibrations into the Charter's telemetry, and produces a summary with the convergence (or divergence) between auditors.</li>
</ol>
<p>Decision D1 in the proposal is what holds everything else up:</p>
<blockquote>
<p><em>"Skills delegate via <code>Bash(straymark charter audit *)</code> to the canonical implementation. Templates live only in <code>dist/.straymark/audit-prompts/</code>. Zero drift possible between skill and CLI."</em></p>
</blockquote>
<p>There's only one place where the prompts live, one single implementation of the flow, and skills (Claude, Cursor) invoke it via Bash. It's a humble pattern — the CLI is the single source — but it avoids what in any framework with two surfaces (skill + CLI) ends up being the chronic problem: that the skill and the CLI say different things depending on who updated which last.</p>
<hr>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="5-why-the-cli-orchestrates-but-doesnt-invoke-apis">5. Why the CLI orchestrates but doesn't invoke APIs<a href="https://straymark.dev/blog/charters-and-the-external-audit-cycle#5-why-the-cli-orchestrates-but-doesnt-invoke-apis" class="hash-link" aria-label="Direct link to 5. Why the CLI orchestrates but doesn't invoke APIs" title="Direct link to 5. Why the CLI orchestrates but doesn't invoke APIs" translate="no">​</a></h2>
<p>This is the strangest decision of May, and the one that took me the most work to make. It's documented literally in <code>cli-roadmap.md</code> §0 as <em>"architectural decision A1"</em>:</p>
<blockquote>
<p><em>"A1 (Phase 3): orchestration-only, no HTTP API clients in v0. Roadmap §5.4 originally suggested 'support OpenAI/Google/Anthropic in v0' with API key handling. The implemented reality is that the CLI prepares prompts, validates outputs against schema, and integrates with telemetry — but does NOT invoke APIs. The operator pastes the prompts into their auditor of choice manually."</em></p>
</blockquote>
<p>The reasoning, also literal:</p>
<blockquote>
<p><em>"Implementing 3 HTTP clients is 1-2 weeks + perpetual maintenance when the APIs change (premature for an experimental v0); the human-in-the-loop pattern matches Sentinel's <code>/plan-audit</code>; complies with principle #10 ('it is not an LLM gateway'); closes RFC #82 by design. HTTP clients reopen in v1 when a real adopter justifies it with data."</em></p>
</blockquote>
<p>Three arguments, each with its own weight.</p>
<p><strong>The first is pragmatic.</strong> Three HTTP clients — OpenAI, Anthropic, Google — are between one and two weeks of implementation, plus permanent maintenance every time any of the three changes something. For a command whose manual form was already working empirically in Sentinel, that's an absurd cost. It's engineering to solve a problem no adopter had asked to solve.</p>
<p><strong>The second is about continuity.</strong> What Sentinel validated in April was precisely the human-in-the-loop pattern: the operator pastes the prompt into Copilot/Gemini/Claude <em>by hand</em>, reads the response, pastes it back. The six-Plan experiment that gave rise to this whole arc <em>never</em> invoked APIs. If the CLI now invoked APIs on its own, it would be replacing a validated pattern with an unvalidated one, with no empirical reason.</p>
<p><strong>The third is about identity.</strong> StrayMark is not an <em>LLM gateway</em>. Framework principle #10 says it explicitly. There are dozens of products that <em>are</em> — LangChain, LiteLLM, LiteLLM Proxy, OpenRouter, every wrapper — and they're useful for what they do. StrayMark does something else: it structures discipline around the work done <em>with</em> those models, whichever model that is. Whether the CLI invokes or doesn't invoke APIs changes what the framework <em>is</em>; keeping it <em>orchestration-only</em> keeps the identity clean.</p>
<p>The part of the paragraph I care about most: <em>"HTTP clients reopen in v1 when a real adopter justifies it with data."</em> The decision wasn't closed by dogma; it was deferred behind an evidence threshold. If in six months an adopter shows that the human-in-the-loop flow breaks their throughput, the HTTP clients land. Until then, the forty seconds of manual friction it takes to paste the prompt into another window is trivial compared to the cost of maintaining three live SDKs.</p>
<hr>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="6-what-the-framework-decided-not-to-automate">6. What the framework decided <em>not</em> to automate<a href="https://straymark.dev/blog/charters-and-the-external-audit-cycle#6-what-the-framework-decided-not-to-automate" class="hash-link" aria-label="Direct link to 6-what-the-framework-decided-not-to-automate" title="Direct link to 6-what-the-framework-decided-not-to-automate" translate="no">​</a></h2>
<p>It's worth closing with the other face of the same decision. The <code>audit-skills-design.md</code> proposal says:</p>
<blockquote>
<p><em>"Whatever can be automated reversibly should be automated; the documents are kept for ex-post human audit."</em></p>
</blockquote>
<p>The first half explains May's three releases: prompts generated automatically, calibrations merged automatically, drift detected automatically. The second half — <em>"the documents are kept for ex-post human audit"</em> — explains what was chosen to stay manual on purpose.</p>
<p>What the framework does <em>not</em> automate:</p>
<ul>
<li class=""><strong>The operator's reading of the AILOG before closing the Charter.</strong> The <code>straymark charter audit prepare</code> command generates the prompts, but the operator <em>has</em> to open the AILOG and read it. If we automated that — an agent that reads, summarizes, decides — we'd lose the moment of human judgment that justifies the Charter existing at all.</li>
<li class=""><strong>The decision to accept or reject the external audit.</strong> The CLI merges calibrations into the telemetry, but doesn't act on them. If an auditor scores the Charter a 4, the Charter doesn't auto-reopen: the operator decides whether to reopen, to argue, or to declare it <em>acceptable-with-known-debt</em>. That decision is the discipline; automating it would destroy it.</li>
<li class=""><strong>The invocation of the models.</strong> As argued above: the pause where the operator copies the prompt is exactly where they decide which model to use, which prompt to tweak, whether the question as phrased seems fair. That pause is feature, not bug.</li>
</ul>
<p>The criterion running through all three is one: <em>automate what's reversible and mechanical; preserve as manual what's judgment</em>. Forty seconds of copy-paste aren't too many if they buy keeping the judgment human.</p>
<hr>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="7-closing">7. Closing<a href="https://straymark.dev/blog/charters-and-the-external-audit-cycle#7-closing" class="hash-link" aria-label="Direct link to 7. Closing" title="Direct link to 7. Closing" translate="no">​</a></h2>
<p>What I took from the process, in four claims:</p>
<ol>
<li class="">
<p><strong>A practice that works empirically doesn't need to be reinvented to be canonized.</strong> Sentinel did the validation work in April; May only ported it into the framework. The crystallization is transfer, not design-from-scratch.</p>
</li>
<li class="">
<p><strong>When the proposal is well-written, implementation is execution.</strong> Three releases in a day are only possible when all the decisions were closed before code was touched. Principle #6 says it more prosaically, but this is what it means.</p>
</li>
<li class="">
<p><strong>Not everything automatable should be automated.</strong> Decision A1 — the CLI orchestrates but doesn't invoke APIs — is the technical version of a philosophical decision: human-in-the-loop isn't legacy to get rid of, it's a feature that holds the discipline up.</p>
</li>
<li class="">
<p><strong>A framework's identity is defined as much by what it does as by what it doesn't.</strong> <em>"It is not an LLM gateway"</em> is one of the few principle #10 sentences worth remembering verbatim. What StrayMark does, it does well because there are many things it refuses to do.</p>
</li>
</ol>
<p>Next, in the following post: the methodological episode that connects with the very start of this blog — <em>Issue #113: Charters invisible to the agents</em> — where the framework discovers that creating commands and schemas isn't enough if the repo's <em>surface</em> doesn't speak to the agent. It's the natural counterweight to this post: here we talk about what got canonized; there we talk about what didn't get seen.</p>
<hr>
<p><em>Anchors: PRs <a href="https://github.com/StrangeDaysTech/straymark/pull/65" target="_blank" rel="noopener noreferrer" class="">#65</a> · <a href="https://github.com/StrangeDaysTech/straymark/pull/68" target="_blank" rel="noopener noreferrer" class="">#68</a> · <a href="https://github.com/StrangeDaysTech/straymark/pull/69" target="_blank" rel="noopener noreferrer" class="">#69</a> (Charters first-class). Proposals <a href="https://github.com/StrangeDaysTech/straymark/blob/main/docs/decisions/proposals/2026-05-03-audit-skills-design.md" target="_blank" rel="noopener noreferrer" class=""><code>audit-skills-design.md</code></a> · <a href="https://github.com/StrangeDaysTech/straymark/blob/main/docs/decisions/proposals/2026-05-03-audit-skills-rollout.md" target="_blank" rel="noopener noreferrer" class=""><code>audit-skills-rollout.md</code></a> · <a href="https://github.com/StrangeDaysTech/straymark/blob/main/docs/decisions/proposals/2026-05-04-audit-cli-flow.md" target="_blank" rel="noopener noreferrer" class=""><code>audit-cli-flow.md</code></a> · <a href="https://github.com/StrangeDaysTech/straymark/blob/main/docs/decisions/proposals/2026-05-03-cli-roadmap.md" target="_blank" rel="noopener noreferrer" class=""><code>cli-roadmap.md</code></a> (decision A1 §0). Releases fw-4.4.0 → fw-4.9.0.</em></p>
<p><em>This document was produced with assistance from generative AI tools (Claude 4.7); all responsibility for the content rests with the human author.</em></p>]]></content>
        <author>
            <name>José Villaseñor Montfort</name>
            <uri>https://github.com/montfort</uri>
        </author>
        <category label="straymark" term="straymark"/>
        <category label="charters" term="charters"/>
        <category label="audit" term="audit"/>
        <category label="cli" term="cli"/>
        <category label="governance" term="governance"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[Six Plans for one thesis (and the rename to Charter)]]></title>
        <id>https://straymark.dev/blog/six-plans-and-the-rename-to-charter</id>
        <link href="https://straymark.dev/blog/six-plans-and-the-rename-to-charter"/>
        <updated>2026-04-30T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[The first systematic experiment, and the day Plan became Charter]]></summary>
        <content type="html"><![CDATA[<p><em>Six Plans on paper, five in practice — Sentinel's first systematic experiment between April 25 and 28. The cycle that turned an artisanal pattern into Charters, the framework's bounded unit of work.</em></p>
<!-- -->
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="1-a-footnote-that-says-a-lot">1. A footnote that says a lot<a href="https://straymark.dev/blog/six-plans-and-the-rename-to-charter#1-a-footnote-that-says-a-lot" class="hash-link" aria-label="Direct link to 1. A footnote that says a lot" title="Direct link to 1. A footnote that says a lot" translate="no">​</a></h2>
<p>In the <code>charter-telemetry.md</code> proposal, written on 30 April 2026, there's a terminological note at the top:</p>
<blockquote>
<p><em>"What this document calls 'Charter' was called 'Plan' in the Sentinel experiment (PLAN-01..06). The empirical data cited below refers to those historical Plans by their original name; the schema shape and prospective examples use the going-forward name 'Charter'."</em></p>
</blockquote>
<p>It's a footnote, technical, drama-free. But it records the exact moment the artifact changed names — and, more interestingly, it records an archival decision the blog also respects: what was called <em>Plan</em> at the time keeps being called <em>Plan</em> in the original records. Rewriting the name backwards would falsify the trace.</p>
<p>This post covers two things that happened in five days: the framework's first systematic experiment — Sentinel's six Plans, run between 25 and 28 April — and the rename that came right after, on the 30th. They aren't two separate events. One led to the other.</p>
<hr>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="2-six-plans-on-paper-five-in-practice">2. Six Plans on paper, five in practice<a href="https://straymark.dev/blog/six-plans-and-the-rename-to-charter#2-six-plans-on-paper-five-in-practice" class="hash-link" aria-label="Direct link to 2. Six Plans on paper, five in practice" title="Direct link to 2. Six Plans on paper, five in practice" translate="no">​</a></h2>
<p>The experiment was designed with six Plans (<code>PLAN-01</code> through <code>PLAN-06</code>) and executed with five. PLAN-04 never ran: it stayed as a catalog of seven <em>deferred features</em>, a list of things we wanted to do but the test cycle couldn't cover. It's only honest to say so, because the very document that validates the thesis (<code>thesis-validation.md</code>) records it openly in its summary table:</p>















































<table><thead><tr><th>Plan</th><th>Size</th><th>What it did</th><th>Format</th></tr></thead><tbody><tr><td>PLAN-01</td><td>XS</td><td>Governance docs deploy</td><td>v1</td></tr><tr><td>PLAN-02</td><td>S</td><td>Admin endpoint (<code>gcp-resource</code>)</td><td>v1</td></tr><tr><td>PLAN-03</td><td>XS</td><td>Contract bumps</td><td>v1</td></tr><tr><td>PLAN-05</td><td>M</td><td>Per-service anomaly thresholds</td><td><strong>v2</strong></td></tr><tr><td>PLAN-06</td><td>XS</td><td>Manual baseline recompute</td><td><strong>v3</strong></td></tr><tr><td><em>(PLAN-04 catalog)</em></td><td>—</td><td>Roadmap of 7 deferred features, not executed</td><td>—</td></tr></tbody></table>
<p>Five Plans, four distinct sizes: three XS, one S, one M. Deliberately heterogeneous domains — an operations deploy, two admin endpoints, a contract bump, a backend feature with configuration logic. It wasn't a synthetic benchmark. It was Sentinel's real code between 25 and 28 April, partitioned into bounded units and audited piece by piece with three models (Copilot, Gemini, Claude) acting as external auditors.</p>
<p>That the sixth Plan didn't run matters for two reasons. The obvious one: the experiment ran out of time. The more interesting one: PLAN-04 was the only large Plan in the batch — seven accumulated features, no natural boundary. That precisely <em>that</em> Plan was the one that didn't make it through was already saying something about the size the format could tolerate. Small Plans, yes; roadmap-Plans, no. That lesson was canonized later without anyone having to write it: StrayMark's Charters today are <em>"bounded units, hours to days, one branch"</em>, not quarterly roadmaps.</p>
<hr>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="3-the-experiment-iterated-on-itself">3. The experiment iterated on itself<a href="https://straymark.dev/blog/six-plans-and-the-rename-to-charter#3-the-experiment-iterated-on-itself" class="hash-link" aria-label="Direct link to 3. The experiment iterated on itself" title="Direct link to 3. The experiment iterated on itself" translate="no">​</a></h2>
<p>Five executed Plans produced three different formats. It wasn't on a whim; it was because each cycle exposed something the previous format didn't capture.</p>
<ul>
<li class="">
<p><strong>v1</strong> — the first three Plans (<code>01</code>, <code>02</code>, <code>03</code>) ran on an original format. Five recurring patterns were identified in the audit AILOGs, but none was formalized into a template. They existed as habit, not as contract.</p>
</li>
<li class="">
<p><strong>v2</strong> — for PLAN-05, those five patterns were materialized into <code>TEMPLATE.md</code>, plus a <em>"Format conventions"</em> section in the README. Doc-only: nothing executable yet. The hypothesis: if the format is explicit, external auditors converge better. AILOG-020 says it plainly: <em>"Internal patterns that have been applied for a while but have no name remain invisible to external auditors. Naming them formally turns practice into a public signal."</em></p>
</li>
<li class="">
<p><strong>v3</strong> — for PLAN-06, a new pattern was added (auto-checklist drift) and, this time, <em>executable tooling</em>: <code>scripts/check-plan-drift.sh</code>, ~145 lines of bash that validate whether the actual delivery matches what the Plan declared. For the first time, the format stopped being prose only and started having a verifier.</p>
</li>
</ul>
<p>What I want to point out here is the shape of the curve. v1 captured latent practice. v2 named it. v3 wrote a program that checks it. That's the full arc of any useful standardization — only compressed into five Plans, not five years.</p>
<p>It's also the first concrete evidence of something that, two months later, would be named explicitly as Pattern 1 (<em>pre-declare refresh</em>) and Pattern 2 (<em>amend-on-emergence</em>) in <code>CHARTER-CHAIN-EVOLUTION.md</code>. What got canonized there as a meta-pattern started here, in April, as habit-without-a-name.</p>
<hr>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="4-the-hardest-evidence-external-auditors-converging">4. The hardest evidence: external auditors converging<a href="https://straymark.dev/blog/six-plans-and-the-rename-to-charter#4-the-hardest-evidence-external-auditors-converging" class="hash-link" aria-label="Direct link to 4. The hardest evidence: external auditors converging" title="Direct link to 4. The hardest evidence: external auditors converging" translate="no">​</a></h2>
<p>The most loaded assumption of the thesis was: <em>"structured notes reduce failure modes, and the reduction is visible when external auditors look"</em>. The way to prove it: send the output of each Plan — the modified files, the AILOG, the Plan-doc under TEMPLATE — to three auditors who hadn't participated in development (Copilot, Gemini, and a critical analysis from Claude) and compare the aggregate scores.</p>
<p>The number <code>thesis-validation.md</code> reports for PLAN-05 (the first Plan under v2, and the only M-size one) is clear:</p>
<blockquote>
<p><em>"Best combined auditor calibration across 5 cycles (Copilot 9.25, Gemini 9.5). Accumulated hypothesis confirmed: TEMPLATE v2 + rich AILOGs reduce the ambiguity surface for external audit."</em></p>
</blockquote>
<p>Two heterogeneous models, different instructions, converging around 9.3 out of 10 — on the largest Plan in the batch, no less, not the smallest. That's signal, not noise. And it replicated when v3's <code>check-plan-drift.sh</code> was exercised:</p>
<blockquote>
<p><em>"PLAN-05 (with known drifts): script reports 3 omitted files: <code>evaluator_test.go</code> (F4), <code>repository.go</code> (F1/R6), <code>statuscenter/service.go</code> (F5) — exactly the 3 drifts that Copilot+Gemini captured in their audits. Zero false positives."</em></p>
</blockquote>
<p>The automated script and the two external auditors agreed exactly on which Plan files had been left undone. This isn't an argument that the script is smart — it's bash and <em>grep</em>; it couldn't be dumber. It's an argument that the Plan format, once formalized, makes <em>any inspector</em> (human, agent, script) see the same things. Structured discipline doesn't require intelligence to be audited: it requires clarity.</p>
<hr>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="5-what-the-experiment-didnt-prove">5. What the experiment <em>didn't</em> prove<a href="https://straymark.dev/blog/six-plans-and-the-rename-to-charter#5-what-the-experiment-didnt-prove" class="hash-link" aria-label="Direct link to 5-what-the-experiment-didnt-prove" title="Direct link to 5-what-the-experiment-didnt-prove" translate="no">​</a></h2>
<p>This is the section I most want on the record, because it's where it gets tested whether the blog is willing to be honest.</p>
<p><code>thesis-validation.md</code> was explicitly designed to break the thesis, not to defend it. The first line of the document reads:</p>
<blockquote>
<p><em>"This document confronts that thesis with data. It does not defend it; it tries to break it. The goal is that a reader who didn't buy the thesis can, reading only this text, decide whether the available evidence supports it, qualifies it, or refutes it."</em></p>
</blockquote>
<p>The final verdict, with the thesis's six assumptions faced against the evidence, is this:</p>








































<table><thead><tr><th>#</th><th>Assumption</th><th>Verdict</th></tr></thead><tbody><tr><td>1</td><td>Vibe coding doesn't scale</td><td>Partially validated <em>(no control arm)</em></td></tr><tr><td>2</td><td>Structured notes reduce failure modes</td><td>Validated</td></tr><tr><td>3</td><td>Regulatory byproduct with no extra work</td><td>Validated <em>(pending real human auditor test)</em></td></tr><tr><td>4</td><td>Approvals are rarely binary</td><td>No evidence — pending multi-actor project</td></tr><tr><td>5</td><td>Stage &gt; commit as traceability unit</td><td>Validated</td></tr><tr><td>6</td><td>In-situ signing &gt; later reconstruction</td><td>Partially validated <em>(no cryptographic signing tested)</em></td></tr></tbody></table>
<p>Three assumptions fully validated, two partial, one <em>without evidence</em>, zero refuted. The assumption about non-binary approvals went untested because Sentinel is a single-owner project; ruling on it would require a real team with multiple signers. And cryptographic signing — Sigstore, hash-chaining, the technical guarantees of an append-only log — wasn't exercised because no Plan touched that part of the flow. That stays in the document as an explicit <em>gap</em>, not as a hand-waved claim.</p>
<p>What the experiment didn't prove matters more than what it did. If we'd published six greens instead of five honest verdicts, the blog would be marketing. The way to avoid it is to say, without softening: here are assumptions we don't have evidence for, and a one-operator project can't generate it. Others will; the framework will mature with that data.</p>
<hr>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="6-why-plan-became-charter">6. Why Plan became Charter<a href="https://straymark.dev/blog/six-plans-and-the-rename-to-charter#6-why-plan-became-charter" class="hash-link" aria-label="Direct link to 6. Why Plan became Charter" title="Direct link to 6. Why Plan became Charter" translate="no">​</a></h2>
<p>The 30 April rename wasn't marketing. The reason is written literally in <code>WHAT-IS-A-CHARTER.md</code>:</p>
<blockquote>
<p><em>"GitHub SpecKit already uses the word 'plan' (<code>/speckit.plan</code>, <code>plan.md</code>) for a different artifact, and the nominal collision generated friction in adopter docs that combine both flows."</em></p>
</blockquote>
<p>SpecKit already had a <code>plan.md</code>. StrayMark had one too. In the documentation of an adopter using both, <em>plan</em> meant different things in adjacent paragraphs. The rename existed to fix that collision.</p>
<p>But behind the pragmatism there's a nuance worth naming. The two artifacts <em>are</em> distinct, and the distinction is structural:</p>






























<table><thead><tr><th></th><th><strong>SpecKit <code>plan.md</code></strong></th><th><strong>StrayMark Charter</strong></th></tr></thead><tbody><tr><td>Granularity</td><td>Complete feature (weeks, several stories)</td><td>Bounded unit (hours to days, one branch)</td></tr><tr><td>Dominant content</td><td>Stack, dependencies, project structure, constitution gates</td><td>Concrete files to touch, verification commands, <code>R&lt;N&gt;</code> risks</td></tr><tr><td>Validation</td><td>Constitution Check (<em>ex-ante</em> gate)</td><td>Drift-check + external audit (<em>ex-post</em> gates)</td></tr><tr><td>Optimization</td><td><em>Upfront clarity</em></td><td><em>Ex-post traceability</em></td></tr></tbody></table>
<p>What SpecKit calls <em>plan</em> looks more like an ADR with an architectural skeleton. What StrayMark calls <em>Charter</em> looks more like a task-card with contractual verification and an audit anchor. They're complementary artifacts, not competitors; <code>SPECKIT-CHARTER-BRIDGE.md</code> makes that explicit later, in May. But the nomenclature had to stop colliding before complementarity could even be discussed.</p>
<p>The part I find important to highlight is the adjacent decision: Sentinel's historical records — the AILOGs, the telemetry, the <code>check-plan-drift.sh</code>, the <code>sentinel/docs/plans/</code> folders — preserve the name <em>Plan</em>. <code>WHAT-IS-A-CHARTER.md</code> itself argues it this way:</p>
<blockquote>
<p><em>"Sentinel's historical records (Plans 01–06, <code>sentinel/docs/plans/</code>, <code>sentinel/scripts/check-plan-drift.sh</code>, AILOGs and YAML telemetries <code>PLAN-NN.telemetry.yaml</code>) preserve the original name — they are empirical evidence of a specific moment in time, and rewriting history would falsify the record."</em></p>
</blockquote>
<p><em>Rewriting history would falsify the record.</em> For me, that sentence is the true heart of the rename. The framework exists to preserve a trace, not to rewrite one. When the artifact changed names, the change was prospective: from 30 April onward, new ones are Charters. The old ones, the experiment ones, are still Plans. The inconsistency is deliberate, and the inconsistency <em>is</em> the evidence.</p>
<p>The 30 April rename's other companion — the telemetry proposal — came the same day for reasons that look obvious in hindsight: if the emergent pattern deserved a new name, it also deserved structured measurement. The <code>charter-telemetry.schema.v0.json</code> schema, with its fields for invested time, detected drifts, size, domain, is the machinery that runs today what Sentinel was still measuring by hand in YAML. Plan got renamed to Charter on the same day we decided to start counting Charters.</p>
<hr>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="7-closing">7. Closing<a href="https://straymark.dev/blog/six-plans-and-the-rename-to-charter#7-closing" class="hash-link" aria-label="Direct link to 7. Closing" title="Direct link to 7. Closing" translate="no">​</a></h2>
<p>What I took from the process, in four claims:</p>
<ol>
<li class="">
<p><strong>The experiment was designed to break, not to confirm.</strong> <em>"It does not defend it; it tries to break it"</em> — that was, literally, the brief of the document that validated the thesis. Any technical blog worth respecting has to tolerate that framing.</p>
</li>
<li class="">
<p><strong>Five Plans executed, of six designed, in four days.</strong> The one that didn't run (the largest, a seven-feature roadmap) was, accidentally, the first evidence of what size the unit can tolerate. Today Charters are bounded by contract. In April, they were bounded by accident.</p>
</li>
<li class="">
<p><strong>The format evolved inside the experiment itself: from habit, to template, to script.</strong> Five Plans produced three versions of the format. The v1 → v2 → v3 curve is the curve of any useful standardization — just compressed.</p>
</li>
<li class="">
<p><strong>The rename came from pragmatism, not marketing. And historical preservation came from principle.</strong> <em>Plan</em> keeps being called <em>Plan</em> in Sentinel, where that's what it was called. <em>Charter</em> started being used from April onward. The framework doesn't rewrite its own archive: that's why it's worth tracing.</p>
</li>
</ol>
<p>Next, in the following post: two close-by milestones that codify qualitatively new capabilities — <em>Charters as a first-class entity</em> (PR #65, fw-4.4.0) and <em>the external multi-model audit cycle</em> (<code>audit-skills-design</code>, <code>audit-cli-flow</code>, releases fw-4.7 → fw-4.9). That's where the Sentinel experiment became CLI functionality.</p>
<hr>
<p><em>Anchors: proposals <a href="https://github.com/StrangeDaysTech/straymark/blob/main/docs/decisions/proposals/2026-04-30-thesis-validation.md" target="_blank" rel="noopener noreferrer" class=""><code>thesis-validation.md</code></a> and <a href="https://github.com/StrangeDaysTech/straymark/blob/main/docs/decisions/proposals/2026-04-30-charter-telemetry.md" target="_blank" rel="noopener noreferrer" class=""><code>charter-telemetry.md</code></a> (both 2026-04-30). Canonical Charter definition: <a href="https://github.com/StrangeDaysTech/straymark/blob/main/docs/contributors/WHAT-IS-A-CHARTER.md" target="_blank" rel="noopener noreferrer" class=""><code>WHAT-IS-A-CHARTER.md</code></a>. Operational schema: <code>dist/.straymark/schemas/charter-telemetry.schema.v0.json</code>.</em></p>
<p><em>This document was produced with assistance from generative AI tools (Claude 4.7); all responsibility for the content rests with the human author.</em></p>]]></content>
        <author>
            <name>José Villaseñor Montfort</name>
            <uri>https://github.com/montfort</uri>
        </author>
        <category label="straymark" term="straymark"/>
        <category label="sentinel" term="sentinel"/>
        <category label="charters" term="charters"/>
        <category label="methodology" term="methodology"/>
        <category label="governance" term="governance"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[Exploring the framework]]></title>
        <id>https://straymark.dev/blog/exploring-the-framework</id>
        <link href="https://straymark.dev/blog/exploring-the-framework"/>
        <updated>2026-04-27T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[The TUI that produced visibility without meaning to]]></summary>
        <content type="html"><![CDATA[<p><em>By April 2026 the framework had ~50 governed Markdown files and they had become opaque. <code>straymark explore</code> — a TUI that renders the whole repo as a navigable surface — was born three weeks before it accidentally revealed the outlier from Post 8. New tools produce visibility without meaning to.</em></p>
<!-- -->
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="1-the-tool-that-two-weeks-later-revealed-the-outlier">1. The tool that two weeks later revealed the outlier<a href="https://straymark.dev/blog/exploring-the-framework#1-the-tool-that-two-weeks-later-revealed-the-outlier" class="hash-link" aria-label="Direct link to 1. The tool that two weeks later revealed the outlier" title="Direct link to 1. The tool that two weeks later revealed the outlier" translate="no">​</a></h2>
<p>Post 8 of this blog covered a very specific episode: the discovery of the only framework file whose canonical language was Spanish. The operator didn't find it through systematic inspection; they found it by running <code>straymark explore --lang es</code> during an audit preparation and noticing, visually, that one template was written backwards relative to the rest. The line from that post:</p>
<blockquote>
<p><em>"A new surface of the framework (the TUI) put all the files into simultaneous view, and the inconsistency became obvious — like tidying the bookshelf and noticing one book is shelved spine-backwards."</em></p>
</blockquote>
<p>This post covers the tool. The TUI <code>straymark explore</code> was born almost three weeks before the discovery it enabled — on 25 April 2026 in <code>cli-3.4.0</code> — and matured across four more releases, all closed in under 48 hours. This isn't a post about code. It's a post about a specific piece of tooling that ratifies a thesis the blog already named: new tools produce visibility without meaning to.</p>
<hr>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="2-why-a-tui-in-a-markdown-framework">2. Why a TUI in a Markdown framework<a href="https://straymark.dev/blog/exploring-the-framework#2-why-a-tui-in-a-markdown-framework" class="hash-link" aria-label="Direct link to 2. Why a TUI in a Markdown framework" title="Direct link to 2. Why a TUI in a Markdown framework" translate="no">​</a></h2>
<p>By late April 2026, the framework had something like fifty governed Markdown files — <code>PRINCIPLES.md</code>, <code>AGENT-RULES.md</code>, <code>DOCUMENTATION-POLICY.md</code>, <code>QUICK-REFERENCE.md</code>, <code>SPECKIT-CHARTER-BRIDGE.md</code>, plus templates in <code>dist/.straymark/templates/</code>, plus audit prompts, plus the versions in three languages of each one (<code>i18n/es/</code>, <code>i18n/zh-CN/</code>). All on disk, all browsable with <code>find</code> and <code>cat</code>, all perfectly accessible.</p>
<p>And, at the same time, all invisible. For an adopter cloning the framework for the first time, the first question wasn't <em>"where is rule N?"</em>. It was <em>"what's here?"</em>. And a recursive <code>ls</code> doesn't answer that question — it overwhelms it. A <code>grep</code> requires knowing what to search for. An editor opens one file at a time. The framework had reached the size where its own surface had become opaque.</p>
<p><code>straymark explore</code> was born precisely to fix that: a navigable surface that answered <em>"what's here?"</em> in three seconds. Not an IDE; not a Read-the-Docs-style system; not a static site. A TUI — terminal user interface — that runs on the adopter's repo, indexes the framework's canonical files, shows them grouped by category, and lets you read them with a colored Markdown viewer inside the terminal.</p>
<p>The decision to build a TUI and not a web app is aligned with two things the blog already argued. First, Post 4's principle #10 — <em>"StrayMark is not an LLM gateway"</em> — generalizes to <em>"StrayMark is not whatever already does something else"</em>. We don't compete with MkDocs or Material for MkDocs. Second, the A1 decision of the same Post 4: orchestration-only. The TUI doesn't require a server, doesn't require a build step, doesn't require a connection: it runs on the adopter's repo, where the framework already lives. It's the humblest piece that could solve the problem.</p>
<hr>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="3-what-landed-in-cli-340">3. What landed in <code>cli-3.4.0</code><a href="https://straymark.dev/blog/exploring-the-framework#3-what-landed-in-cli-340" class="hash-link" aria-label="Direct link to 3-what-landed-in-cli-340" title="Direct link to 3-what-landed-in-cli-340" translate="no">​</a></h2>
<p><a href="https://github.com/StrangeDaysTech/straymark/pull/57" target="_blank" rel="noopener noreferrer" class="">PR #57</a> from 25 April, merged as <code>cli-3.4.0</code>, did three concrete things:</p>
<ul>
<li class="">Introduced the <code>straymark explore</code> command. Two-panel layout when the terminal has 100 columns or more: navigation on the left (30%), document on the right (70%). Narrower terminals collapse to a single panel. Status bar at the foot with relevant shortcuts.</li>
<li class="">Indexed the framework's canonical files into a navigable hierarchy: governance docs (<code>AGENT-RULES.md</code>, <code>DOCUMENTATION-POLICY.md</code>, ...), templates (<code>dist/.straymark/templates/</code>), audit prompts, and the adopter's directories (<code>docs/charters/</code>, <code>.straymark/07-ai-audit/</code>, ...). Each node expandable with <code>Enter</code>.</li>
<li class="">Wired in the i18n resolver. The <code>--lang &lt;code&gt;</code> option lets you run <code>straymark explore --lang es</code> and get all governance docs in Spanish <em>if</em> a translation is available. If not, silent fallback to canonical EN. The commit's literal description:</li>
</ul>
<blockquote>
<p><em>"Wire <code>language</code> config and a new <code>--lang</code> flag through the explore TUI so framework governance docs are served from <code>i18n/&lt;lang&gt;/</code> when a translation exists, falling back silently to English otherwise."</em></p>
</blockquote>
<p>The i18n resolver part matters more than the TUI itself. Until <code>cli-3.4.0</code>, the helper <code>resolve_localized_path</code> was used only by <code>straymark new</code> (to resolve which template to inject into the adopter in the right language). PR #57 extracted it into <code>cli/src/utils.rs:146</code> as a shared helper, so that <strong>a single definition of how <code>i18n/&lt;lang&gt;/</code> overlays resolve</strong> backs both the <code>new</code> command and the <code>explore</code> command. The behavior stays predictable for the adopter: if you translate a template into <code>i18n/es/</code>, the TUI will show it the same way generation will use it. No surprises.</p>
<p>Markdown rendering uses <code>pulldown-cmark</code> for the parser and <code>ratatui</code> widgets to paint. Color-coded syntax, code blocks with borders, tables with rounded borders, headings indented by level. It isn't flashy; it's readable.</p>
<hr>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="4-four-refinements-in-thirty-six-hours">4. Four refinements in thirty-six hours<a href="https://straymark.dev/blog/exploring-the-framework#4-four-refinements-in-thirty-six-hours" class="hash-link" aria-label="Direct link to 4. Four refinements in thirty-six hours" title="Direct link to 4. Four refinements in thirty-six hours" translate="no">​</a></h2>
<p>What happened between 25 and 27 April is what Post 9 named months later as a property of the process: when the proposal is well-written, implementation is execution. Four more PRs, closed in under 36 hours, took the TUI from "works" to "done":</p>



































<table><thead><tr><th>PR</th><th>Tag</th><th>Time</th><th>What it added</th></tr></thead><tbody><tr><td><a href="https://github.com/StrangeDaysTech/straymark/pull/60" target="_blank" rel="noopener noreferrer" class="">#60</a></td><td>cli-3.5.0</td><td>25 Apr 22:36</td><td><strong>Live language switcher.</strong> <code>L</code> key cycles the display language without leaving the TUI: <code>en → es → zh-CN → en</code>. The index rebuilds in-place.</td></tr><tr><td><a href="https://github.com/StrangeDaysTech/straymark/pull/61" target="_blank" rel="noopener noreferrer" class="">#61</a></td><td>cli-3.5.0 (same release)</td><td>25 Apr 23:41</td><td><strong>OS locale auto-detect.</strong> If the adopter has no <code>config.yml</code>, the TUI reads <code>$LC_ALL</code> / <code>$LANG</code> and maps the POSIX locale (e.g. <code>es_MX.UTF-8</code> → <code>es</code>) onto the closest supported language.</td></tr><tr><td><a href="https://github.com/StrangeDaysTech/straymark/pull/62" target="_blank" rel="noopener noreferrer" class="">#62</a></td><td>cli-3.5.1</td><td>26 Apr 00:07</td><td><strong>Metadata panel translated.</strong> 25 new i18n entries for labels and titles, with visual padding to keep cross-language alignment.</td></tr><tr><td><a href="https://github.com/StrangeDaysTech/straymark/pull/63" target="_blank" rel="noopener noreferrer" class="">#63</a></td><td>cli-3.5.2</td><td>26 Apr 00:13</td><td><strong>Keybinding cleanup.</strong> Removed undocumented vim aliases <code>l</code> and <code>h</code> (the lowercase <code>l</code> clashed with the <code>L</code> language switcher). Kept documented <code>j/k/g/G/n/N</code>.</td></tr></tbody></table>
<p>The arc's speed repeats the pattern. The five PRs of fw-4.11.0 covered in Post 6 (rebrand to StrayMark) closed in forty-three minutes. The three audit-cycle releases covered in Post 4 closed in one day. The TUI curve is similar: the design was clear in PR #57, and refinements came as the operator started using the command frequently and noticed the frictions.</p>
<p>The anecdote worth recording is <code>cli-3.5.2</code>: the <code>l</code> and <code>h</code> keys it removed were vim aliases — the operator uses them out of muscle memory in their editor. But when the uppercase-<code>L</code> language switcher landed hours earlier, the lowercase <code>l</code> and the uppercase <code>L</code> shared the same physical key, and the visual transition was confusing. The fix was to remove the undocumented aliases: the full-letter spelling (<code>j/k/g/G</code>) stays; the abbreviations that duplicated functions go away. It's a small UX detail that illustrates how TUI decisions tune against real use, not UX theory.</p>
<hr>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="5-what-the-tui-revealed-two-weeks-later">5. What the TUI revealed two weeks later<a href="https://straymark.dev/blog/exploring-the-framework#5-what-the-tui-revealed-two-weeks-later" class="hash-link" aria-label="Direct link to 5. What the TUI revealed two weeks later" title="Direct link to 5. What the TUI revealed two weeks later" translate="no">​</a></h2>
<p>Here the post picks up Post 8's thread from the other end. What <code>cli-3.4.0</code> added to the framework wasn't just a navigation command; it was a <strong>surface of simultaneous visualization</strong>. That is: before the TUI, the framework's files existed but were read one by one. After the TUI, they could be seen all at once, grouped, tagged, in the same presentation mode.</p>
<p>That changes what the operator can notice.</p>
<p>On 12 May, two and a half weeks after the <code>cli-3.4.0</code> merge, the operator ran <code>straymark explore --lang es</code> before an external audit cycle. They got to the "audit prompts" group. Opened it. And noticed something that had been there for a year: the root <code>audit-prompt.md</code> was written <em>in Spanish</em>, while every other canonical framework file had English in root and <code>i18n/es/</code> overlays. One file, backwards relative to the convention.</p>
<p>The detail wasn't found by systematic review. It was found by visual contrast. It's exactly what Post 8 §3 codified as thesis:</p>
<blockquote>
<p><em>"New tools produce visibility."</em></p>
</blockquote>
<p>The TUI didn't cause the outlier — the outlier had existed since the first commit that ported the Sentinel skill <code>plan-audit</code> into the canonical framework (Post 3 records this). The TUI didn't look for the outlier either; it isn't an inconsistency-detection tool. All it did was put every file on the same screen, in the same presentation mode, and let the human eye notice what had been there from the start. The conclusion worth recording is structural: any framework that crosses fifty canonical files needs a surface of simultaneous visualization, not because the surface is pedagogically important in itself, but because without it certain regularities of the repo become unobservable.</p>
<hr>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="6-small-technical-decisions-that-matter">6. Small technical decisions that matter<a href="https://straymark.dev/blog/exploring-the-framework#6-small-technical-decisions-that-matter" class="hash-link" aria-label="Direct link to 6. Small technical decisions that matter" title="Direct link to 6. Small technical decisions that matter" translate="no">​</a></h2>
<p>Three TUI design details worth recording, all coherent with framework principles the blog has already named:</p>
<p><strong>Feature flag <code>tui</code>.</strong> The CLI's <code>Cargo.toml</code> declares the TUI as an optional dependency (<code>ratatui</code> + <code>crossterm</code> + <code>pulldown-cmark</code> live behind the <code>tui</code> flag, enabled by default). An adopter who only wants <code>init</code>, <code>update</code>, <code>validate</code> can build a binary without the TUI via <code>cargo build --no-default-features</code>. It closes a sub-architectural decision that recurs in the framework: give the adopter value by default, but let them choose a lighter binary when the TUI adds nothing to the flow.</p>
<p><strong>Lazy document loading.</strong> The <code>DocIndex</code> keeps a <code>HashMap&lt;PathBuf, Document&gt;</code> that fills up as each node is opened, not at startup. For a repo with a hundred governance files, this means <code>straymark explore</code> boots in under 200ms and only reads disk when the operator hits <code>Enter</code>. The decision is technically trivial; what isn't trivial is that it was made consciously. The TUI doesn't compete with an IDE; it competes with <code>cat</code>. It has to feel just as immediate.</p>
<p><strong>History stack for hyperlinks.</strong> When one framework document mentions another (e.g., <code>AGENT-RULES.md §3</code> refers to <code>DOCUMENTATION-POLICY.md §6</code>), the TUI lets you jump to the referenced one with a click — and back with <code>Esc</code>. Internally there's a navigation stack that restores the previous document's scroll position. It's the piece that turns reading the framework from <em>"I open a file, close it, open another"</em> into <em>"I follow a conversation between documents without losing the thread"</em>. The number of cross-references the framework has today — between principles, agent rules, schemas, templates — makes this navigation structurally important, not cosmetic.</p>
<hr>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="7-closing">7. Closing<a href="https://straymark.dev/blog/exploring-the-framework#7-closing" class="hash-link" aria-label="Direct link to 7. Closing" title="Direct link to 7. Closing" translate="no">​</a></h2>
<p>What I took from the process, in four claims:</p>
<ol>
<li class="">
<p><strong>A framework that crosses a certain size needs a surface of simultaneous visualization.</strong> It isn't ergonomics; it's the condition for certain regularities of the repo to be observable. Post 8 documented the consequence; this post documents the tool.</p>
</li>
<li class="">
<p><strong>The TUI doesn't cause the discoveries; it enables them.</strong> The audit-prompt outlier had existed since May of the previous year. All that changed in April was that a screen appeared where it could be seen next to its peers. The tool doesn't have opinions about content; it changes the conditions under which the human eye can notice regularities.</p>
</li>
<li class="">
<p><strong>When the design is clear, implementation is hours, not sprints.</strong> Five PRs in thirty-six hours — language-aware, live switcher, OS detection, panel i18n, keybinding cleanup — are only possible because the design was closed in PR #57. It's the same pattern as Posts 4, 6 and 9.</p>
</li>
<li class="">
<p><strong>The most interesting technical decision can be a compile-time flag.</strong> The <code>tui</code> feature flag explicitly declares that the TUI is optional, that the framework still works without it, that the adopter decides. That architectural humility is the difference between a CLI that assumes how the adopter works and a CLI that offers itself where it can be useful.</p>
</li>
</ol>
<p>With this post the blog covers the <code>H-14</code> milestone the first batch left as explicit debt. The remaining candidate milestones that <code>PLAN-INVESTIGACION.md §1.43-55</code> recorded — <code>AGENTS.md</code> universal inject, full EN/ES/zh-CN i18n coverage, <code>straymark validate</code> as a formal layer, CLA assistant — stay available for future batches. No promised cadence, but recorded.</p>
<hr>
<p><em>Anchors: PR <a href="https://github.com/StrangeDaysTech/straymark/pull/57" target="_blank" rel="noopener noreferrer" class="">#57</a> — <code>cli-3.4.0</code> (language-aware explore, 25 Apr 2026). PRs <a href="https://github.com/StrangeDaysTech/straymark/pull/60" target="_blank" rel="noopener noreferrer" class="">#60</a> · <a href="https://github.com/StrangeDaysTech/straymark/pull/61" target="_blank" rel="noopener noreferrer" class="">#61</a> · <a href="https://github.com/StrangeDaysTech/straymark/pull/62" target="_blank" rel="noopener noreferrer" class="">#62</a> · <a href="https://github.com/StrangeDaysTech/straymark/pull/63" target="_blank" rel="noopener noreferrer" class="">#63</a> — refinements <code>cli-3.5.0</code> to <code>cli-3.5.2</code> (25-26 Apr 2026). Code: <code>cli/src/tui/</code> (15 files). Adopter doc: <code>docs/adopters/CLI-REFERENCE.md</code> §<code>straymark explore</code>.</em></p>
<p><em>This document was produced with assistance from generative AI tools (Claude 4.7); all responsibility for the content rests with the human author.</em></p>]]></content>
        <author>
            <name>José Villaseñor Montfort</name>
            <uri>https://github.com/montfort</uri>
        </author>
        <category label="straymark" term="straymark"/>
        <category label="tui" term="tui"/>
        <category label="cli" term="cli"/>
        <category label="i18n" term="i18n"/>
        <category label="structural-visibility" term="structural-visibility"/>
    </entry>
    <entry>
        <title type="html"><![CDATA[Four names in four months]]></title>
        <id>https://straymark.dev/blog/four-names-in-four-months</id>
        <link href="https://straymark.dev/blog/four-names-in-four-months"/>
        <updated>2026-04-05T00:00:00.000Z</updated>
        <summary type="html"><![CDATA[Looking for the concept by trying out names]]></summary>
        <content type="html"><![CDATA[<p><em>Chronicle → Monimen → DevTrail → Strange Days Tech → StrayMark. The project's prehistoric arc of four renames in four months — three rushed ones in January and a disciplined one in May. The idea didn't move; the name did.</em></p>
<!-- -->
<blockquote>
<p><strong>Editorial note</strong>: this is the first post published retroactively on the blog. The <code>date</code> in the frontmatter corresponds to a point inside the arc the post narrates, not the day it was written. The entire blog is being built this way, backwards, starting from the episode that triggered me to write it at all (<code>emergent-observation-design</code>, 2026-05-16). Pretending otherwise wouldn't help anyone.</p>
</blockquote>
<hr>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="1-the-day-after">1. The day after<a href="https://straymark.dev/blog/four-names-in-four-months#1-the-day-after" class="hash-link" aria-label="Direct link to 1. The day after" title="Direct link to 1. The day after" translate="no">​</a></h2>
<p>On 28 January 2026, at 17:29 Central Time, this commit landed in the repo:</p>
<blockquote>
<p><code>chore: rebrand Chronicle to Monimen</code></p>
</blockquote>
<p>One day. Twenty-nine hours, to be exact, after the project's <em>initial commit</em>. The framework barely existed, and it was already changing its name.</p>
<p>I'm telling this in the past tense, but it happened three months ago. And three months ago, two more renames later, it still wasn't called StrayMark. The project that today bills itself as <em>Documentation Governance for AI-Assisted Software Development</em> carries a short, disorderly prehistory that's worth naming before moving on.</p>
<hr>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="2-five-events-four-months">2. Five events, four months<a href="https://straymark.dev/blog/four-names-in-four-months#2-five-events-four-months" class="hash-link" aria-label="Direct link to 2. Five events, four months" title="Direct link to 2. Five events, four months" translate="no">​</a></h2>









































<table><thead><tr><th>Date (UTC-6)</th><th>Time</th><th>Event</th><th>Anchor</th></tr></thead><tbody><tr><td>2026-01-27</td><td>12:14</td><td><em>Initial commit</em>: <strong>Enigmora Chronicle Framework v1.0.0</strong></td><td><a href="https://github.com/StrangeDaysTech/straymark/commit/7c58b6d" target="_blank" rel="noopener noreferrer" class=""><code>7c58b6d</code></a></td></tr><tr><td>2026-01-28</td><td>17:29</td><td>Rebrand: Chronicle → <strong>Monimen</strong></td><td><a href="https://github.com/StrangeDaysTech/straymark/commit/0b772bc" target="_blank" rel="noopener noreferrer" class=""><code>0b772bc</code></a></td></tr><tr><td>2026-01-29</td><td>19:30</td><td>Rebrand: Monimen → <strong>DevTrail</strong> (<code>BREAKING CHANGE</code>)</td><td><a href="https://github.com/StrangeDaysTech/straymark/commit/25ab7a4" target="_blank" rel="noopener noreferrer" class=""><code>25ab7a4</code></a></td></tr><tr><td>2026-03-01</td><td>19:05</td><td>Org rebrand: Enigmora → <strong>Strange Days Tech</strong> + the Rust CLI is born</td><td><a href="https://github.com/StrangeDaysTech/straymark/commit/c7e9026" target="_blank" rel="noopener noreferrer" class=""><code>c7e9026</code></a></td></tr><tr><td>2026-05-08/09</td><td>—</td><td>DevTrail → <strong>StrayMark</strong> (ADR + arc of 5 PRs)</td><td>ADR <code>2026-05-08-001</code>, PRs #114-#118</td></tr></tbody></table>
<p>Three renames in three days. Then a month-long pause. Then the org rebrand with the Rust CLI bundled in. Then another two-month pause. Then StrayMark, this time with a public ADR anchoring the decision.</p>
<p>A small detail worth flagging: the 28 January commit (Chronicle → Monimen) was not marked <code>BREAKING CHANGE</code>. The 29 January one (Monimen → DevTrail) was. <em>"BREAKING CHANGE: Complete rebrand from Monimen to DevTrail"</em>, the commit body reads. The difference is small but telling: the second rename felt more definitive. It was, for two months.</p>
<hr>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="3-what-doesnt-move">3. What doesn't move<a href="https://straymark.dev/blog/four-names-in-four-months#3-what-doesnt-move" class="hash-link" aria-label="Direct link to 3. What doesn't move" title="Direct link to 3. What doesn't move" translate="no">​</a></h2>
<p>This is the section that interests me most. The project changes names four times in four months. The idea doesn't.</p>
<p>The README of the <em>initial commit</em> — the one that lived in the repo when it was called <em>Enigmora Chronicle Framework</em> — opens with this line:</p>
<blockquote>
<p><strong>Documentation Governance for AI-Assisted Software Development</strong></p>
</blockquote>
<p>It's the same line that opens the StrayMark README today. Four names, one tagline.</p>
<p>A bit further down, that same v1.0.0 README states the project's thesis in an explicit block quote:</p>
<blockquote>
<p><em>"No significant change without a documented trace."</em></p>
</blockquote>
<p>That sentence is, today, Principle #1 of the framework. It lives in <code>PRINCIPLES.md §1 — Total Traceability</code>. The wording shifted slightly when translated into Spanish, but the weight of the claim stayed intact: no significant change without a documented trace.</p>
<p>The eight document types listed in the v1.0.0 README — REQ, ADR, TES, INC, TDE, AILOG, AIDEC, ETH — are all still alive. Others were added later (MCARD, SBOM, SEC, DPIA), but none displaced the originals. The January taxonomy held.</p>
<p><strong>The name moves four times; the idea doesn't.</strong> What changed across those four months wasn't the <em>what</em> — it was the label that fit on it.</p>
<hr>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="4-the-aidec-with-a-typod-year">4. The AIDEC with a typo'd year<a href="https://straymark.dev/blog/four-names-in-four-months#4-the-aidec-with-a-typod-year" class="hash-link" aria-label="Direct link to 4. The AIDEC with a typo'd year" title="Direct link to 4. The AIDEC with a typo'd year" translate="no">​</a></h2>
<p>There's a small anecdote I keep coming back to.</p>
<p>The project's first structured document — the first AIDEC, the document that, in the framework's own taxonomy, records a decision made with an agent's assistance — is <code>AIDEC-2025-01-27-001-i18n-strategy.md</code>. It lives in commit <a href="https://github.com/StrangeDaysTech/straymark/commit/7b7193e" target="_blank" rel="noopener noreferrer" class=""><code>7b7193e</code></a>, added at 18:01 on 27 January 2026, six hours after the <em>initial commit</em>.</p>
<p>The ID says <strong>2025</strong>. The commit is from <strong>2026</strong>.</p>
<p>The very document that established the <code>[TYPE]-[YYYY-MM-DD]-[NNN]</code> identifier convention has a typo in its own year. The framework started imperfect, and nobody fixed it in time. Anyone who clones the repo and looks at the ID closely will notice it — and will also see that the commit which introduced it is dated correctly. That's the best evidence I have that audit discipline is something that arrives later; it doesn't ship with the repo.</p>
<p>But more interesting than the typo is what that AIDEC decides. The question José posed in January, with help from Claude Opus 4.5, was: how do you internationalize a framework that exists for humans but whose configuration is read by agents? The answer, from the justification section of the AIDEC itself:</p>
<blockquote>
<p><em>"AI agents (Claude, Gemini, Copilot, Cursor) process instructions equally well in any language, so translating their config files provides no functional benefit."</em></p>
</blockquote>
<p>The decision that document made — translate what humans read (documentation, templates); keep what agents read (CLAUDE.md, GEMINI.md, .cursorrules) in English — was an early intuition that the framework has two distinct audiences. The blog itself ratifies that intuition today: bilingual Spanish/English for the humans who'll read it, while the skills and prompts that orchestrate agents stay in English only. Three months later, it's still the right call.</p>
<hr>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="5-the-birth-of-the-cli--and-the-missing-number">5. The birth of the CLI — and the missing number<a href="https://straymark.dev/blog/four-names-in-four-months#5-the-birth-of-the-cli--and-the-missing-number" class="hash-link" aria-label="Direct link to 5. The birth of the CLI — and the missing number" title="Direct link to 5. The birth of the CLI — and the missing number" translate="no">​</a></h2>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="5a-the-day-the-project-became-software">5a. The day the project became software<a href="https://straymark.dev/blog/four-names-in-four-months#5a-the-day-the-project-became-software" class="hash-link" aria-label="Direct link to 5a. The day the project became software" title="Direct link to 5a. The day the project became software" translate="no">​</a></h3>
<p>On 1 March 2026, at 19:05, commit <a href="https://github.com/StrangeDaysTech/straymark/commit/c7e9026" target="_blank" rel="noopener noreferrer" class=""><code>c7e9026</code></a> landed:</p>
<blockquote>
<p><em>"feat: rebrand to Strange Days Tech, add CLI scaffolder, restructure repo"</em></p>
</blockquote>
<p>Until that day, the project was prose. It was templates, skills, governance rules, and a pile of Markdown that depended on the operator (me) copying it by hand into the repos where I wanted to use it. There was a bash script called <code>copy-devtrail.sh</code>. It was a toy.</p>
<p>That 1 March commit introduced <code>cli/Cargo.toml</code> and <code>cli/src/main.rs</code>. The first CLI was called <code>devtrail-cli</code>, version <code>2.0.0</code>, and had three commands:</p>
<div class="language-rust codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-rust codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token keyword" style="color:#00009f">enum</span><span class="token plain"> </span><span class="token type-definition class-name">Commands</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token class-name">Init</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"> path</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token class-name">String</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token class-name">Update</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token class-name">Remove</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"> full</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token keyword" style="color:#00009f">bool</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"></span><br></div><div class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></div></code></pre></div></div>
<p><code>init</code>, <code>update</code>, <code>remove</code>. Three operations. Everything else came later: <code>status</code>, <code>repair</code>, <code>validate</code>, <code>new</code>, <code>compliance</code>, <code>metrics</code>, <code>analyze</code>, <code>audit</code>, <code>explore</code>. But the original three are still there, almost untouched.</p>
<p>The important thing about that commit isn't the three commands: it's that, on that day, the project stopped being a body of documentation living in its own repo and started being an executable tool that gets installed into other repos. The boundary between <em>"documentation governance project"</em> and <em>"framework with tooling"</em> was crossed that Sunday in March. It matters more than any of the renames that came before.</p>
<p>It was also, incidentally, the day the project moved GitHub accounts: from <code>enigmora/devtrail</code> to <code>StrangeDaysTech/devtrail</code>. The organization renamed itself from Enigmora to Strange Days Tech, S.A.S., in the same commit that shipped the CLI. Simultaneous renames: the product's (Monimen to DevTrail) had happened in January; the company's, in March. Two distinct layers of identity moving on different clocks.</p>
<p>(A side note, important for archival accuracy: agent co-authorship — the <code>Co-Authored-By: Claude Opus X.Y</code> line that appears in commits — does not start in March. The <em>initial commit</em> of 27 January is already signed by Claude Opus 4.5. Transparency about AI co-authorship was a rule from the first line of code. What changes on 1 March isn't the practice, it's the scale: the CLI is the first artifact where co-authorship produces <em>executable code</em>, not documentation.)</p>
<h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="5b-the-missing-number">5b. The missing number<a href="https://straymark.dev/blog/four-names-in-four-months#5b-the-missing-number" class="hash-link" aria-label="Direct link to 5b. The missing number" title="Direct link to 5b. The missing number" translate="no">​</a></h3>
<p>There's a detail about framework versioning that makes more sense if you just look at <code>git tag</code>:</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><div class="token-line" style="color:#393A34"><span class="token plain">fw-2.0.0</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">fw-2.1.0</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">fw-4.0.0</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">fw-4.1.0</span><br></div><div class="token-line" style="color:#393A34"><span class="token plain">...</span><br></div></code></pre></div></div>
<p>There is no <code>fw-3.x.x</code>. The project deliberately jumped from 2 to 4.</p>
<p>The jump syncs with commit <a href="https://github.com/StrangeDaysTech/straymark/commit/21e03b2" target="_blank" rel="noopener noreferrer" class=""><code>21e03b2</code></a>, dated 27 March 2026, whose body describes the change like this:</p>
<blockquote>
<p><em>"Reposition DevTrail from 'documentation helper' to 'ISO 42001-aligned AI governance platform' across all user-facing docs. Lead with regulatory urgency (EU AI Act Aug 2026) and compliance value proposition."</em></p>
</blockquote>
<p>Until March, DevTrail presented itself as a <em>documentation helper</em>. From that commit onward, it presented itself as an <em>ISO 42001-aligned AI governance platform</em>. The version-number jump (2 → 4, skipping 3) marked the magnitude of the thesis shift. It was a conscious call: one major bump wasn't enough to signal the difference.</p>
<p>And this is where the prehistory starts to make retrospective sense. The intuition that had been in the repo since January — the idea of a robust, normative, standards-alignable record-keeping system — was only named explicitly in March. We'll see this more clearly in the next section, when we talk about the second name.</p>
<hr>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="6-about-the-names">6. About the names<a href="https://straymark.dev/blog/four-names-in-four-months#6-about-the-names" class="hash-link" aria-label="Direct link to 6. About the names" title="Direct link to 6. About the names" translate="no">​</a></h2>
<p>Three of the four renames have no ADR. The justification lives only in commit messages, and sometimes not even there: the commit <code>chore: rebrand Chronicle to Monimen</code> doesn't say why Monimen. The next one, <code>chore: rebrand Monimen to DevTrail</code>, doesn't say why DevTrail either. The practice of the ADR as a disciplined artifact came later; in January the name would change with a commit and the justification would evaporate into the conversation that produced it.</p>
<p>But some etymology is rescuable.</p>
<ul>
<li class="">
<p><strong>Chronicle</strong> <em>(27 Jan)</em>. Historical record. Logbook. The name speaks for itself: what you do with a <em>chronicle</em> is write down what happened, in order, so it can be reviewed later. No ADR, but the word carries its own meaning.</p>
</li>
<li class="">
<p><strong>Monimen</strong> <em>(28 Jan)</em>. This is the only name whose intuition I do remember and that's worth telling. <em>Monimen</em> came from a wordplay on <em>Monumento</em> (Monument in English). The analogy that motivated the suggestion: the norms already being intuited at that point — AIDEC, AILOG, alignable with the emerging ISO 42001 governance regime — represented something solid and durable. A <em>monument</em> is something erected to last; an immovable reference point for a community. That's what the framework wanted to be. The clipped suffix — <em>Monimen</em> instead of <em>Monument</em> — was an attempt to give the term a more agile, software-like feel, less marble. It lasted twenty-five hours. But the intuition didn't die: what would, in March, get named explicitly as <em>ISO 42001-aligned AI governance platform</em> is the mature version of that same impulse. Monimen was a name with the right thesis and the wrong tongue.</p>
</li>
<li class="">
<p><strong>DevTrail</strong> <em>(29 Jan)</em>. The developer's trail. Less solemn than Monimen, more concrete. The commit marked it <code>BREAKING CHANGE</code> — which, viewed from May, carries some irony: the most definitive of the first three rebrands was precisely the one that lasted three and a half months before being replaced.</p>
</li>
<li class="">
<p><strong>StrayMark</strong> <em>(8-9 May)</em>. The mark, the trace that's left behind. But this rebrand deserves its own post: there's already a public ADR (<code>2026-05-08-001</code>), an arc of five core PRs (#114-#118), and a <em>"Why StrayMark?"</em> manifesto in the README that earns separate treatment. Here, I just close it as the rebrand that finally came with documentary discipline behind it.</p>
</li>
</ul>
<p>The point isn't the etymology itself. It's that each name ratified a distinct intuition about what the product was: <strong>logbook</strong> (Chronicle), <strong>normative pillar</strong> (Monimen), <strong>developer's trail</strong> (DevTrail), <strong>residual mark</strong> (StrayMark). Four names are four hypotheses about the concept. The search ends when the concept stabilizes — and only then can the name sit still.</p>
<hr>
<h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="7-closing">7. Closing<a href="https://straymark.dev/blog/four-names-in-four-months#7-closing" class="hash-link" aria-label="Direct link to 7. Closing" title="Direct link to 7. Closing" translate="no">​</a></h2>
<p>What I took from the process, in four claims:</p>
<ol>
<li class="">
<p><strong>We weren't looking for a name. We were looking for the concept.</strong> The four renames are evidence of searching, not of indecision. The concept got sharper as it cycled through names.</p>
</li>
<li class="">
<p><strong>Three of four renames without an ADR.</strong> The practice of the ADR as a disciplined artifact came later. In January there was no habit yet. That isn't debt — it's honesty about pace. Governance habits are the result of wanting to record what was already happening, not the precondition for starting.</p>
</li>
<li class="">
<p><strong>The project became software on 1 March 2026. Before that, it was prose.</strong> The Rust CLI is the boundary. Any conversation about StrayMark <em>as a framework</em> has to acknowledge there's a before and an after that commit.</p>
</li>
<li class="">
<p><strong>There probably won't be another rebranding.</strong> But the blog isn't promising it. The project is honest about its own mutability, and promising otherwise would betray the first claim of the first post.</p>
</li>
</ol>
<p>When I started writing this blog, two weeks ago, I didn't intend to cover the prehistory. The idea was to talk about Charters, about emergent observation, about the things the framework actually does today. But the blog itself is a retroactive act — it exists because something surprised me enough to make me start writing. And once I decided to write backwards, getting to January was inevitable. To the three renames in three days. To the AIDEC with the typo'd year. To <em>Monimen</em>.</p>
<p>Next, in the following post: the framework's first real methodological experiment — Sentinel's six Plans, and the day <em>Plan</em> got renamed to <em>Charter</em>. That's where the story the blog came to tell actually begins.</p>
<hr>
<p><em>Anchors: commits <a href="https://github.com/StrangeDaysTech/straymark/commit/7c58b6d" target="_blank" rel="noopener noreferrer" class=""><code>7c58b6d</code></a> · <a href="https://github.com/StrangeDaysTech/straymark/commit/0b772bc" target="_blank" rel="noopener noreferrer" class=""><code>0b772bc</code></a> · <a href="https://github.com/StrangeDaysTech/straymark/commit/25ab7a4" target="_blank" rel="noopener noreferrer" class=""><code>25ab7a4</code></a> · <a href="https://github.com/StrangeDaysTech/straymark/commit/7b7193e" target="_blank" rel="noopener noreferrer" class=""><code>7b7193e</code></a> · <a href="https://github.com/StrangeDaysTech/straymark/commit/c7e9026" target="_blank" rel="noopener noreferrer" class=""><code>c7e9026</code></a> · <a href="https://github.com/StrangeDaysTech/straymark/commit/21e03b2" target="_blank" rel="noopener noreferrer" class=""><code>21e03b2</code></a>. Original README: <code>git show v1.0.0:README.md</code>.</em></p>
<p><em>This document was produced with assistance from generative AI tools (Claude 4.7); all responsibility for the content rests with the human author.</em></p>]]></content>
        <author>
            <name>José Villaseñor Montfort</name>
            <uri>https://github.com/montfort</uri>
        </author>
        <category label="straymark" term="straymark"/>
        <category label="prehistory" term="prehistory"/>
        <category label="identity" term="identity"/>
        <category label="governance" term="governance"/>
    </entry>
</feed>