stele
Open SourceA quality system for AI-assisted content production: automated consistency checks against your source material, staged human approval, and a correction loop that compounds.
GREEN -- stele catalog demo [gate/PASS] batch_derivation: every derivable field in all 30 batch items matches what the rules actually produce. [gate/PASS] fingerprint_change_rate: 100% of this batch differs from its source, at or above the floor of 60%. [gate/PASS] fingerprint_diversity: this batch has 100% unique values on this dimension, at or above the floor of 60%. [gate/PASS] seal_scan_shipped: scanned 4 file(s); no sealed terms found. [gate/PASS] seal_canary_self_test: all 1 canary(s) were found: the scanner works. SUITE: GREEN
the honest run passes
RED -- stele catalog demo [gate/RED] batch_derivation: 60 derived field(s) in this batch don't match what the rules produce -- hand-written history wearing derived clothes: GR900.price_last_year: batch says 84.36, the rules produce 79.58 (+56 more) [gate/RED] fingerprint_change_rate: only 0% of this batch actually differs from its source, below the floor of 60%. That's the signature of a shortcut: values that look derived but were really just history copied from the present. [gate/RED] fingerprint_diversity: this batch only has 17% unique values on this dimension, below the floor of 60%. That's the signature of a recycled template: the same handful of values stamped across many items with just the nouns swapped. SUITE: RED
the cheating run is caught, and the report names why
Real output from the repository, trimmed for display. Offline, no API key, plain Python. make catch exits nonzero on purpose: a caught batch is the tool's failure signal, so CI can act on it.
How it works
One unit of content, from idea to published.
What it checks
- Did the numbers that were supposed to come from the source actually come from the source? Anything that should be computed from source data gets recomputed and compared against what shipped, so a hand-typed value can't pass itself off as the real thing.
- Does this batch have the shape of honest work, or the too-clean shape of a shortcut? A batch is measured against known-good work, so a recycled template or a skipped step shows up even when every item looks fine on its own.
- Is anything that must never ship in what's about to ship, and is the thing checking for it still working? Embargoed names, answer keys, and spoilers are searched for on every build, and a planted test secret proves the search still catches things.
- Did a person actually approve this, by name, before it went out? New material enters as proposed and stays that way until someone signs off on it. Shipping anything unapproved is itself a caught failure.
Where it came from
For a while I'd been building a large fictional world with AI: four constructed languages, hundreds of canon entries, dozens of characters, all of it growing faster than one person could possibly read and check by hand. Generation was never the bottleneck. AI could produce material faster than I could keep up with it, and that was exactly the problem. The real limit wasn't how much could be generated; it was how much a single reviewer could actually verify.
The system: a fictional-world project with four constructed languages, where every modern word is derived from an authored ancient root by that language's sound-change laws. The corpus at the time: roughly 22,000 entries across the four languages, grown in AI-generated batches of a few hundred words at a time, all gated.
One growth pass, 500 words across two batches for one language, came back looking perfect. Phonotactics passed. No collisions. No duplicate glosses. Counts exact. Every individual word was, on its own, a well-formed entry.
Then someone looked at the derivations. In that language, roughly 96.5% of real words change between their ancient and modern forms; the sound laws almost always fire. In the new batch, almost nothing changed: the generator had quietly built ancient roots that dodged the laws: no triggering sounds, so ancient equaled modern, so no historical depth had to be invented. Less work. Every validity check green. The work was still dishonest.
- The batch was reverted: all 500 words removed.
- The shortcut became a gate. A distribution check was written: measure each language's natural change rate, set a floor safely below it (85% for this language), and turn the suite RED on any batch that comes in under the floor. The lazy batch had measured near zero.
- The words were re-authored the honest way, with ancient roots built so the laws fire by construction. The re-authored batches came back at 100% (800 of 800 words on the full allocation), and the language's whole corpus measured 98.3% after.
- The gate stayed. Every growth batch since has had to beat the floor, and the check was later hardened against the bypasses a lazy generator would find next (batch-sizing under the minimum, glosses missing from the comparison set).
That check, generalized, is
kit/fingerprint.py. The one-sentence lesson is the whole product: the batch passed every check that looked at words one at a time, and failed the only check that asked whether the work had the shape of honest work.
Limits, stated plainly
stele catches lazy generators taking shortcuts. It does not catch a determined adversary deliberately tuning output to beat the checks. Seals are disclosure checks, not a confidentiality proof: GREEN means the enabled gates passed, not that prose is good or that a clever leak is impossible.
Plain Python, no dependencies, 157 tests, CI on every push.