Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
70 changes: 70 additions & 0 deletions KNOWN-LIMITS.md
Original file line number Diff line number Diff line change
Expand Up @@ -2199,3 +2199,73 @@ is limit 53 again.
as a defect; it did that, and stopped at the reader. Limit 53 is why the digest
cannot say what changed. Limit 63 is the narrow stamp being narrower than it claims;
this is the wide one not being anywhere it matters.

## 65. The freshness pin binds the code, and never the log it lives in

Limit 29 gave `KNOWN-LIMITS.md` a pin: a comment block at the top naming the commit
the log was verified against, plus `npm run limits-pin -- --check` so a reader in a
different checkout is told they are reading a description of somewhere else. That
works, and the design decision underneath it is right: the pin names **the last
commit that touched `src/`**, not `HEAD`, because stamping is itself a commit that
edits only this file. A `HEAD`-based pin could only ever name its own parent and
would read `diverged` for every reader forever, training them to ignore it.

**The consequence was not carried through.** A commit that edits only this log does
not move the last `src/` commit either. So the pin cannot notice it. The check
answers "has the code moved since the log was stamped?" and has no way to answer
"is this the log that was stamped?"

**Measured on a synthetic tree, not reasoned** (the real repository was not written
to; `writePin`/`checkPin` were the shipped functions, and the commit resolution was
reproduced verbatim from `resolvePinTarget`):

| what changed after stamping | `src/` commit | reported |
|---|---|---|
| nothing | unmoved | `current` |
| a new entry appended | unmoved | `current` |
| an entry deleted, and another's claim reversed | unmoved | `current` |
| a source file edited | moved | `diverged` |

The third row is the one that matters. An entry can be added that was never held
against any code, an entry can be deleted, and a limit's claim can be inverted from
"this is not covered" to "this is covered", and the checker reports `current` and
exits **0**. It does not merely fail to complain. It certifies.

**What a reader should not conclude from `current`.** Not that the entries were
verified. Not that the log is the one the stamp was applied to. Only that `src/` has
not moved since somebody last ran `--stamp`. The pin block's own wording invites the
stronger reading, because it says entry numbering, entry presence, and every claim
are guaranteed for the pinned commit, and a reader who sees `current` will take that
guarantee as live.

**Why this is not the residual already declared.** `src/limits/pin.js` declares two:
that a commit can carry a false pin, which review catches, and that touching code
without re-stamping leaves a stale pin, which `--check` surfaces as divergence. Both
are about the code half. This is the log half, it is silent rather than surfaced, and
it needs no liar and no reviewer error. The mechanism working exactly as designed
produces it.

**Aggravating, and worth stating plainly: nothing runs the check.** It is not in
`npm test`, and this repository has no CI at all. The shipped pin has been diverged
since 2026-08-23 (pinned `2173d23`, last `src/` commit `9b8b862` at the time of
writing) and no automated reader has said so once.

**The repair, drafted and gated.** Add `body-sha256` to the pin block, covering the
file with the pin block itself removed so that stamping stays stable and limit 29's
self-invalidation problem does not return. A pin whose commit matches but whose
digest does not is a third status, `edited`: the code is where the log says it is,
and the log is not. Exit 1, like divergence, so a future CI can gate on it. A v1 pin
with no digest keeps v1 semantics exactly, so old pins are not retroactively failed;
re-stamping upgrades them. **The patch was written and the gate refused it** as a
self-modification of `src/`, correctly, so it queues for a signing sitting rather
than landing with this disclosure.

**Residual after that repair.** A digest binds the text and says nothing about
whether the text is true, which is limit 1 in a different coat. Re-stamping still
asserts verification that nobody checks, and a liar re-stamps. The digest converts a
silent gap into a prompt to re-verify; it does not perform the verification.

**Related.** Limit 29 is the pin this extends. Limit 53 is why a digest detects
without explaining. Limits 63 and 64 are the same family read three ways: 63 is a
stamp narrower than it claims, 64 is a wide stamp wired somewhere it does not
persist, and this is a stamp that covers the wrong artifact entirely.
107 changes: 107 additions & 0 deletions test/known-limits-pin-body.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
/**
* KNOWN-LIMITS 65: the freshness pin binds the code, and never the log it lives in.
*
* These are CHARACTERIZATION tests. They assert the behaviour as it ships today,
* which is the gap, so that the gap is visible in the suite instead of only in the
* confession log. They are written to FAIL once the `body-sha256` repair lands,
* which is deliberate: the failure is the prompt to rewrite them as the assertions
* for the fixed behaviour. Each one names what it should say after the repair.
*
* The repair itself edits `src/limits/pin.js` and was refused by the self-mod gate,
* so it queues for a signing sitting. This file does not need the gate: it only
* reads the shipped functions.
*/

import { describe, it } from 'node:test';
import assert from 'node:assert';
import { writePin, readPin, checkPin } from '../src/limits/pin.js';
import fs from 'node:fs';
import os from 'node:os';
import path from 'node:path';

const SRC_COMMIT = '2173d2316c1923998d473e2c8351543bce9c1c47';

const BODY = `# Known Limits

## 1. Self-attested capture

Tamper-evidence begins at signing time.

## 2. Outbound message capture

Outbound activity is captured by a hook.
`;

/** Stamp a temp log against SRC_COMMIT and return its path. */
function stampedLog() {
const dir = fs.mkdtempSync(path.join(os.tmpdir(), 'l65-'));
const file = path.join(dir, 'KNOWN-LIMITS.md');
fs.writeFileSync(file, BODY);
writePin(file, { commit: SRC_COMMIT, subject: 'opaque-exec: gate local scripts', date: '2026-08-23' });
return file;
}

/**
* The reader's verdict. `head` is the last commit touching src/, which is what
* bin/limits-pin.js resolves and passes -- NOT HEAD. A log-only commit leaves it
* unmoved, which is the whole point of these tests.
*/
const verdict = (file) =>
checkPin({ pinText: fs.readFileSync(file, 'utf8'), head: SRC_COMMIT, dirty: false });

describe('L65: the pin does not bind the log body', () => {
it('a freshly stamped, unmodified log reads current', () => {
assert.strictEqual(verdict(stampedLog()).status, 'current');
});

it('GAP: an entry APPENDED after stamping still reads current', () => {
const file = stampedLog();
fs.appendFileSync(file, '\n## 99. A limit never held against any code\n\nAppended after the stamp.\n');

// After the repair this must be 'edited'.
assert.strictEqual(
verdict(file).status,
'current',
'characterization: the shipped pin cannot see an appended entry'
);
});

it('GAP: an entry DELETED and a claim REVERSED still read current', () => {
const file = stampedLog();
const mangled = fs
.readFileSync(file, 'utf8')
.replace(/## 2\. Outbound message capture\n\nOutbound activity is captured by a hook\.\n/, '')
.replace('Tamper-evidence begins at signing time.', 'Tamper-evidence is complete and covers capture.');
fs.writeFileSync(file, mangled);

const v = verdict(file);
// After the repair this must be 'edited'.
assert.strictEqual(v.status, 'current', 'characterization: deletion and reversal are both invisible');
assert.ok(
/matches your checkout/.test(v.message),
'and the message actively reassures the reader, which is the sharp end of this limit'
);
});

it('the pin records a commit and carries no digest of its own body', () => {
const file = stampedLog();
const pin = readPin(fs.readFileSync(file, 'utf8'));
assert.strictEqual(pin.commit, SRC_COMMIT);
// After the repair: assert pin.bodySha256 is a 64-char hex string.
assert.strictEqual(
pin.bodySha256,
undefined,
'characterization: nothing in the pin block measures the text around it'
);
});

it('CONTROL: a moved src/ commit is still correctly reported as diverged', () => {
const file = stampedLog();
const v = checkPin({
pinText: fs.readFileSync(file, 'utf8'),
head: '9b8b86216ee0d3c8a99487a8f9a5b610cfbc9fba',
dirty: false
});
assert.strictEqual(v.status, 'diverged', 'the code half of the pin works and must keep working');
});
});