fix(#3841): express the anchor semantically so the pretty payload still verifies

The remote matrix caught a regression I introduced in the previous commit. The
anchor check was implemented as a byte-prefix match against IDENTITY_RAW_PREFIX,
which describes the `--raw` wire format -- but `cmdRuntimeIdentity` without that
flag pretty-prints at indent 2, and the classifier is handed BOTH serializations.
Only the shell is restricted to `--raw`. The pre-existing test that runs the real
verb with no flag went red: `+ 'unparseable' - 'ok'`.

No local gate caught it. build:lib, eslint and lint:ci were green throughout,
because none of them execute tests.

The anchor now reproduces its two properties semantically instead of byte-wise,
and both hold for either serialization: the payload begins at the first byte of
stdout, and `packageName` serializes first. IDENTITY_RAW_PREFIX stays exported
with its own tests -- it is the wire contract for the shell, not a general
classifier predicate, and conflating those was the error.

Adds the two rows the matrix was missing: the default pretty serialization
verifies, and a pretty payload with `packageName` not first does not. The design
and matrix now record that they enumerated only the inputs the SHELL produces
and assumed the classifier's input set was the same.

Refs #3841

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
sim
2026-08-25 08:53:49 -04:00
committed by Tom Boucher
parent 5e997de5f0
commit 67335c498c
2 changed files with 29 additions and 10 deletions

View File

@@ -190,16 +190,22 @@ export function classifyIdentityProbe(
const version = typeof record.version === 'string' ? record.version : undefined;
if (actual !== expected) return { reason: 'identity_mismatch', expected, actual, version };
// ANCHOR PARITY (#3841). The shell preamble cannot parse JSON; it matches
// a `case` pattern anchored at the START of stdout, so `packageName` must
// serialize first. A structural parse alone would accept
// `{"note":"x","packageName":"<us>"}` — a shape this package never emits —
// while the shell rejected it, so the two surfaces would disagree in the
// FAIL-OPEN direction. Honoring the anchor here is also what the module
// already claims to do: IDENTITY_RAW_PREFIX is documented as "ANCHORED,
// never a substring search", and buildIdentityPayload inserts packageName
// first precisely so a genuine payload always satisfies it.
if (!probe.stdout.startsWith(IDENTITY_RAW_PREFIX)) {
// ANCHOR PARITY (#3841). The shell preamble cannot parse JSON: it matches
// a `case` pattern anchored at the START of stdout, so a payload only
// verifies there when it begins at the first byte and serializes
// `packageName` first. A purely structural parse would accept
// `{"note":"x","packageName":"<us>"}` and a leading-whitespace payload
// that the shell rejects -- a FAIL-OPEN disagreement between the two
// surfaces.
//
// Reproduce those two properties SEMANTICALLY rather than byte-matching
// IDENTITY_RAW_PREFIX. The prefix describes the `--raw` wire format, but
// this classifier is also handed the DEFAULT pretty serialization
// (`runtime-identity` with no `--raw`, which is two-space indented) --
// byte-matching the compact prefix rejected that, which the remote matrix
// caught. `startsWith('{')` and a first-key check hold for both.
const firstKey = Object.keys(record)[0];
if (!probe.stdout.startsWith('{') || firstKey !== 'packageName') {
return {
reason: 'unparseable',
expected,

View File

@@ -190,6 +190,19 @@ describe('classifyIdentityProbe', () => {
assert.equal(v.reason, 'unparseable');
});
test('the default PRETTY serialization still verifies (not just --raw)', () => {
// The classifier is handed both serializations: the shell only ever sees
// `--raw`, but `runtime-identity` with no flag emits two-space-indented
// JSON. An anchor expressed as a compact byte prefix rejected this.
const pretty = JSON.stringify({ packageName: EXPECTED_PACKAGE_NAME, version: '9.9.9' }, null, 2);
assert.equal(classifyIdentityProbe({ stdout: `${pretty}\n`, exitCode: 0 }).reason, 'ok');
});
test('a pretty payload with packageName not first does not verify', () => {
const pretty = JSON.stringify({ note: 'x', packageName: EXPECTED_PACKAGE_NAME }, null, 2);
assert.equal(classifyIdentityProbe({ stdout: `${pretty}\n`, exitCode: 0 }).reason, 'unparseable');
});
test('a foreign packageName is a mismatch wherever it appears in the object', () => {
const stdout = '{"note":"x","packageName":"get-shit-done-cc"}';
const v = classifyIdentityProbe({ stdout, exitCode: 0 });