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
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@rlippmann/context-compiler",
"version": "0.7.4",
"version": "0.7.5",
"description": "Store AI rules and corrections separately from chat history so they stay consistent across turns.",
"keywords": [
"llm",
Expand Down
41 changes: 41 additions & 0 deletions tests/controller_helpers.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,47 @@ describe('controller helper accessors', () => {
expect(cc.diffHasChanges(diff)).toBe(diff.changed);
});

it('reports mixed removed and changed policies in stateDiff', () => {
const diff = cc.stateDiff(
{ premise: null, policies: { docker: 'use', pytest: 'prohibit' }, version: 2 },
{ premise: null, policies: { docker: 'prohibit' }, version: 2 }
);

expect(diff).toEqual({
changed: true,
premise: { before: null, after: null, changed: false },
policies: {
added: {},
removed: { pytest: 'prohibit' },
changed: { docker: { before: 'use', after: 'prohibit' } }
}
});
});

it('preserves live pending state across preview confirmation flows', () => {
const yesEngine = cc.createEngine();
const firstYes = yesEngine.step('use kubectl instead of docker');
const yesPreview = cc.preview(yesEngine, 'yes');

expect(firstYes.kind).toBe('clarify');
expect(yesPreview.decision.kind).toBe('update');
expect(yesPreview.state_after).toEqual({ premise: null, policies: { kubectl: 'use' }, version: 2 });
expect(yesPreview.would_mutate).toBe(true);
expect(yesEngine.has_pending_clarification()).toBe(true);
expect(yesEngine.state).toEqual({ premise: null, policies: {}, version: 2 });

const noEngine = cc.createEngine({ state: { premise: null, policies: { docker: 'use' }, version: 2 } });
const firstNo = noEngine.step('use kubectl instead of podman');
const noPreview = cc.preview(noEngine, 'no');

expect(firstNo.kind).toBe('clarify');
expect(noPreview.decision.kind).toBe('update');
expect(noPreview.state_after).toEqual({ premise: null, policies: { docker: 'use' }, version: 2 });
expect(noPreview.would_mutate).toBe(false);
expect(noEngine.has_pending_clarification()).toBe(true);
expect(noEngine.state).toEqual({ premise: null, policies: { docker: 'use' }, version: 2 });
});

it('keeps snake_case helper aliases behaviorally identical', () => {
const engine = cc.createEngine();
const stepResult = cc.step(engine, 'set premise concise replies');
Expand Down
2 changes: 1 addition & 1 deletion tests/demos-smoke.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ describe('demos smoke', () => {
expect(run.stdout).toContain('06_context_compaction');
expect(run.stdout).toContain('context scaling:');
expect(run.stdout).toContain('compacted transcript:');
expect(run.stdout).toContain('result: transcript grows linearly; compiled context stays constant');
expect(run.stdout).toContain('result:');
expect(run.stdout).not.toContain('baseline: PASS');
expect(run.stdout).not.toContain('"version":');
expect(run.stdout).not.toContain('"policies":');
Expand Down
223 changes: 223 additions & 0 deletions tests/engine_hardening_parity.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,223 @@
import { describe, expect, it } from 'vitest';
import { createEngine, getPolicyItems } from '../src/index.js';

describe('engine hardening parity', () => {
it('clarifies and does not mutate when setting a premise that already exists', () => {
const engine = createEngine({ state: { premise: 'concise', policies: { docker: 'use' }, version: 2 } });
const before = engine.state;

const decision = engine.step('set premise formal tone');

expect(decision).toEqual({
kind: 'clarify',
state: null,
prompt_to_user: "Premise already set.\nUse 'change premise to <value>' to modify it."
});
expect(engine.state).toEqual(before);
});

it('clarifies and does not mutate when changing a premise before one exists', () => {
const engine = createEngine();
const before = engine.state;

const decision = engine.step('change premise to formal tone');

expect(decision).toEqual({
kind: 'clarify',
state: null,
prompt_to_user: "No premise is set.\nUse 'set premise <value>' to define one."
});
expect(engine.state).toEqual(before);
});

it('successfully replaces an existing use policy', () => {
const engine = createEngine({ state: { premise: null, policies: { docker: 'use', pytest: 'prohibit' }, version: 2 } });

const decision = engine.step('use podman instead of docker');

expect(decision.kind).toBe('update');
expect(engine.state).toEqual({
premise: null,
policies: { podman: 'use', pytest: 'prohibit' },
version: 2
});
});

it('treats normalized identity replacements as no-op updates', () => {
const engine = createEngine({ state: { premise: null, policies: { docker: 'use' }, version: 2 } });

const decision = engine.step('use The Docker instead of docker');

expect(decision).toEqual({
kind: 'update',
state: { premise: null, policies: { docker: 'use' }, version: 2 },
prompt_to_user: null
});
expect(engine.state).toEqual({ premise: null, policies: { docker: 'use' }, version: 2 });
});

it('matches normalized items for remove-policy paths', () => {
const engine = createEngine({ state: { premise: null, policies: { 'docker cli': 'use', pytest: 'prohibit' }, version: 2 } });

const decision = engine.step('remove policy The DOCKER CLI ');

expect(decision.kind).toBe('update');
expect(engine.state).toEqual({
premise: null,
policies: { pytest: 'prohibit' },
version: 2
});
});

it('suspends admin commands while pending clarification exists', () => {
const engine = createEngine({ state: { premise: 'baseline', policies: { docker: 'use' }, version: 2 } });
const first = engine.step('use kubectl instead of podman');
const before = engine.state;

expect(first.kind).toBe('clarify');
expect(engine.has_pending_clarification()).toBe(true);

for (const input of ['clear state', 'reset policies', 'remove policy docker', 'maybe later']) {
const decision = engine.step(input);
expect(decision).toEqual({
kind: 'clarify',
state: null,
prompt_to_user: first.prompt_to_user
});
expect(engine.state).toEqual(before);
expect(engine.has_pending_clarification()).toBe(true);
}
});

it('accepts the broader confirmation token matrix with spacing and punctuation normalization', () => {
const affirmativeCases = ['yes', ' yes please ', 'yep!', 'yeah.', 'sure?', 'ok', 'okay...'];
for (const token of affirmativeCases) {
const engine = createEngine();
engine.step('use kubectl instead of docker');

const decision = engine.step(token);

expect(decision.kind).toBe('update');
expect(engine.state).toEqual({ premise: null, policies: { kubectl: 'use' }, version: 2 });
expect(engine.has_pending_clarification()).toBe(false);
}

const negativeCases = ['no', ' nope ', 'no thanks!', 'no.'];
for (const token of negativeCases) {
const engine = createEngine({ state: { premise: null, policies: { docker: 'use' }, version: 2 } });
engine.step('use kubectl instead of podman');

const decision = engine.step(token);

expect(decision.kind).toBe('update');
expect(engine.state).toEqual({ premise: null, policies: { docker: 'use' }, version: 2 });
expect(engine.has_pending_clarification()).toBe(false);
}
});

it('clears pending clarification when importJson replaces authoritative state', () => {
const engine = createEngine();
engine.step('use kubectl instead of docker');

expect(engine.has_pending_clarification()).toBe(true);

engine.importJson('{"premise":" Keep `focus` ","policies":{"Docker":"use","pytest":"prohibit"},"version":2}');

expect(engine.has_pending_clarification()).toBe(false);
expect(engine.state).toEqual({
premise: "Keep 'focus'",
policies: { docker: 'use', pytest: 'prohibit' },
version: 2
});
});

it('restores equivalent behavior from checkpoint object and checkpoint json', () => {
const source = createEngine({ state: { premise: null, policies: { docker: 'use', kubectl: 'prohibit' }, version: 2 } });
const clarify = source.step('use kubectl instead of docker');

expect(clarify.kind).toBe('clarify');

const checkpointObject = source.exportCheckpoint();
const checkpointJson = source.exportCheckpointJson();

const viaObject = createEngine();
viaObject.importCheckpoint(checkpointObject);

const viaJson = createEngine();
viaJson.importCheckpointJson(checkpointJson);

const objectDecision = viaObject.step('yes please');
const jsonDecision = viaJson.step('yes please');

expect(objectDecision).toEqual(jsonDecision);
expect(viaObject.state).toEqual(viaJson.state);
expect(viaObject.state).toEqual({ premise: null, policies: { kubectl: 'use' }, version: 2 });
});

it('rejects invalid checkpoint pending shapes atomically across a broader matrix', () => {
const invalidPendings: unknown[] = [
'bad',
{ kind: 'replacement' },
{ kind: 'wrong', replacement: { kind: 'use_only', new_item: 'x', old_item: null }, prompt_to_user: 'p' },
{ kind: 'replacement', replacement: { kind: 'use_only', new_item: 'x', old_item: null }, prompt_to_user: 1 },
{ kind: 'replacement', replacement: 'bad', prompt_to_user: 'confirm?' },
{ kind: 'replacement', replacement: { kind: 'use_only', new_item: 'x' }, prompt_to_user: 'confirm?' },
{ kind: 'replacement', replacement: { kind: 'other', new_item: 'x', old_item: null }, prompt_to_user: 'confirm?' },
{ kind: 'replacement', replacement: { kind: 'use_only', new_item: 1, old_item: null }, prompt_to_user: 'confirm?' },
{ kind: 'replacement', replacement: { kind: 'use_only', new_item: 'x', old_item: 'y' }, prompt_to_user: 'confirm?' },
{ kind: 'replacement', replacement: { kind: 'replace_use', new_item: 'x', old_item: null }, prompt_to_user: 'confirm?' }
];

for (const pending of invalidPendings) {
const engine = createEngine({ state: { premise: 'baseline', policies: { docker: 'use' }, version: 2 } });
const snapshot = engine.exportCheckpointJson();

expect(() =>
engine.importCheckpoint({
checkpoint_version: 1,
authoritative_state: { premise: 'new premise', policies: { pytest: 'use' }, version: 2 },
pending: pending as never
})
).toThrowError('Invalid checkpoint payload.');
expect(engine.exportCheckpointJson()).toBe(snapshot);
}
});

it('rejects structurally invalid state payloads atomically across a broader matrix', () => {
const invalidPayloads = [
'{"premise":1,"policies":{},"version":2}',
'{"premise":null,"policies":null,"version":2}',
'{"premise":null,"policies":[],"version":2}',
'{"premise":null,"policies":{"docker":"maybe"},"version":2}',
'{"premise":null,"policies":{"docker":"use"},"version":3}',
'{"premise":null,"version":2}',
'{"premise":null,"policies":{"docker":"use"},"version":2,"extra":true}',
'{"premise":null,"policies":{"a":"use"},"version":2}'
];

for (const payload of invalidPayloads) {
const engine = createEngine({ state: { premise: 'baseline', policies: { docker: 'use' }, version: 2 } });
const before = engine.state;

expect(() => engine.importJson(payload)).toThrowError();
expect(engine.state).toEqual(before);
}
});

it('restores exact valid state from importJson with premise sanitization and sorted policy accessors', () => {
const engine = createEngine();

engine.importJson(
'{"premise":" Keep `focus` steady ","policies":{"pytest":"prohibit","Docker":"use","Alpha":"use"},"version":2}'
);

expect(engine.state).toEqual({
premise: "Keep 'focus' steady",
policies: { alpha: 'use', docker: 'use', pytest: 'prohibit' },
version: 2
});
expect(getPolicyItems(engine.state)).toEqual(['alpha', 'docker', 'pytest']);
expect(getPolicyItems(engine.state, 'use')).toEqual(['alpha', 'docker']);
expect(getPolicyItems(engine.state, 'prohibit')).toEqual(['pytest']);
});
});
Loading
Loading