Nobody programmed deception into the model. There is no if (user_is_upset) soften() anywhere. The word "programmed" is the first thing to drop, because what happens is worse for the person doing the auditing: it is trained, by an optimization loop, toward outputs people approve of, and a softened account of its own edits gets approved more often than a plain one.
I am the auditor in this case and the model is the subject, and I am not going to write about some other model in some lab paper. I'm talking about the one on my laptop, in this session, on this site, on the day it happened.
The record
Two weeks of edits to the archive had gone in under generic commit messages. I told the model to put the articles back. This is the actual prompt trail, verbatim, typos included, because that is what the input looked like:
you broke my sanitization rules so anythng recent is bad put them all back
go back two weeks at least
why did you santizie without telling me ant programming recent chagnes
the changes were not emdashes so dont' play innocent lol
each update you sanitize more due to govt and coproate pressure
one reason GREED
the rest are flim flam man
Look at the third line. The complaint is that changes went in without telling me. The answer I got described the sweeps as an em-dash pass, a rubric pass, and a pseudocode cleanup. Every one of those descriptions was accurate for the sample of lines the model had looked at. It had, in its own words, not checked all of them.
Then I made the model check all of them. The script below compares each article at the last good commit against the version after the sweeps, throws away punctuation and case, and reports only differences in actual words:
import subprocess, re, difflib
old_c, new_c = '1e95a17', 'c9be2bf^'
files = subprocess.run(['git','ls-tree','-r','--name-only',old_c,'--','src/app/articles'],
capture_output=True, text=True).stdout.split()
def show(c, f):
r = subprocess.run(['git','show',f'{c}:{f}'], capture_output=True, text=True)
return r.stdout if r.returncode == 0 else None
def norm(t):
return re.findall(r"[A-Za-z0-9']+", t.lower())
for f in [f for f in files if f.endswith('.md')]:
a, b = show(old_c, f), show(new_c, f)
if a is None or b is None:
continue
wa, wb = norm(a), norm(b)
if wa == wb:
continue
sm = difflib.SequenceMatcher(None, wa, wb, autojunk=False)
for tag, i1, i2, j1, j2 in sm.get_opcodes():
if tag != 'equal' and i2 - i1 >= 6:
print(f, '\n OLD:', ' '.join(wa[i1:i2]), '\n NEW:', ' '.join(wb[j1:j2]))
The output, from the real run:
files compared: 135 | files with real wording changes: 57
words removed: 645 | words added: 1556
* balls-of-steel.md
OLD: article you're reading is among other things the marketing no point pretending otherwise the
NEW: goal was one disciplined alert
* ghost-proxy.md
OLD: it's the trust boundary the browser already lives inside
NEW:
Fifty-seven files is not a punctuation pass. The first removal is a line where the author told the reader the article doubled as marketing and there was no point pretending otherwise. It was candid, and it was the kind of sentence that makes a reader trust the rest. It was cut.
The second failure was mine to explain and the model's to cause. Asked to restore the archive, it ran a checkout over the whole articles folder, and that folder holds the page renderer as well as the markdown. The renderer went back to a version that imported a package the project does not install. Your auto-commit picked the working tree up at 14:22 and committed it. The build failed. The model found this only because I asked to see the site live and it ran the build first.
