instar 1.2.69 → 1.2.70

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- {"version":3,"file":"installCodexHooks.d.ts","sourceRoot":"","sources":["../../src/core/installCodexHooks.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AAKH,oFAAoF;AACpF,eAAO,MAAM,uBAAuB,0BAA0B,CAAC;AAE/D,UAAU,gBAAgB;IACxB,IAAI,EAAE,SAAS,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AACD,UAAU,cAAc;IACtB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,gBAAgB,EAAE,CAAC;CAC3B;AAMD,2FAA2F;AAC3F,wBAAgB,0BAA0B,CACxC,UAAU,EAAE,MAAM,GACjB,MAAM,CAAC,MAAM,EAAE,cAAc,EAAE,CAAC,CA4ClC;AAQD;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,CAwB5D"}
1
+ {"version":3,"file":"installCodexHooks.d.ts","sourceRoot":"","sources":["../../src/core/installCodexHooks.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AAKH,oFAAoF;AACpF,eAAO,MAAM,uBAAuB,0BAA0B,CAAC;AAE/D,UAAU,gBAAgB;IACxB,IAAI,EAAE,SAAS,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AACD,UAAU,cAAc;IACtB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,gBAAgB,EAAE,CAAC;CAC3B;AAMD,2FAA2F;AAC3F,wBAAgB,0BAA0B,CACxC,UAAU,EAAE,MAAM,GACjB,MAAM,CAAC,MAAM,EAAE,cAAc,EAAE,CAAC,CAiDlC;AAQD;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,CAwB5D"}
@@ -66,9 +66,14 @@ export function buildInstarCodexHookGroups(projectDir) {
66
66
  PermissionRequest: [
67
67
  { matcher: '.*', hooks: [node('external-operation-gate.js')] },
68
68
  ],
69
- // End-of-turn review: coherence/tone + deferral detection.
69
+ // End-of-turn review: coherence/tone + deferral + scope-coherence checkpoint.
70
+ // All three are framework-neutral (read stdin, POST to the local server). Codex
71
+ // honors `{decision:"block", reason}` on Stop (verified in the 0.133 binary's
72
+ // StopCommandOutputWire) — the same grounding-pause semantics as Claude, NOT a
73
+ // hard termination. scope-coherence defaults to `approve` and self-throttles
74
+ // (depth threshold + 30-min cooldown), so it can't loop an autonomous Codex run.
70
75
  Stop: [
71
- { matcher: '', hooks: [{ ...node('response-review.js'), timeout: 10000 }, node('deferral-detector.js')] },
76
+ { matcher: '', hooks: [{ ...node('response-review.js'), timeout: 10000 }, node('deferral-detector.js'), node('scope-coherence-checkpoint.js')] },
72
77
  ],
73
78
  // Identity/context injection.
74
79
  SessionStart: [
@@ -1 +1 @@
1
- {"version":3,"file":"installCodexHooks.js","sourceRoot":"","sources":["../../src/core/installCodexHooks.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"installCodexHooks.js","sourceRoot":"","sources":["../../src/core/installCodexHooks.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,65 @@
1
+ /**
2
+ * Codex hook-contract canary.
3
+ *
4
+ * The Codex enforcement layer (installCodexHooks → .codex/hooks.json) rests on
5
+ * a handful of load-bearing, empirically-won assumptions about Codex's hook
6
+ * contract. Two of them were silent-failure bugs we already paid for live
7
+ * (see docs/specs/codex-enforcement-hook-layer.md §P5c):
8
+ * 1. The PreToolUse `matcher` is a REGEX against the tool name — a bare `*`
9
+ * matches NOTHING, so the guard silently never fires. It must be `.*`.
10
+ * 2. Codex's shell tool is `exec_command` and carries the command in
11
+ * `tool_input.cmd` (not Claude's `tool_input.command`); the guard shim
12
+ * reads both.
13
+ * If a future Codex version renames the hook events, drops PreToolUse, or
14
+ * changes the deny mechanism, the gates would silently no-op again — "looks
15
+ * installed, blocks nothing." This canary fails loudly instead.
16
+ *
17
+ * Two layers:
18
+ * (A) DETERMINISTIC invariant lock (always runs, env-independent): asserts
19
+ * buildInstarCodexHookGroups still emits the load-bearing shape — `.*`
20
+ * matcher, dangerous-command-guard on PreToolUse, the full Stop review
21
+ * trio. A refactor that regresses any of these fails the canary in CI.
22
+ * (B) BEST-EFFORT live-binary contract check: if a codex binary is
23
+ * resolvable on this host, read its embedded hook-event schema and
24
+ * assert the events instar depends on (PreToolUse, PermissionRequest,
25
+ * Stop, SessionStart, UserPromptSubmit) are still present. No binary →
26
+ * status 'skip' for layer B (NOT fail — most hosts/CI have no codex).
27
+ *
28
+ * RULE 3.1 RATIONALE
29
+ * Criticality: critical — a silent no-op guard is a false sense of safety on
30
+ * Codex's main destructive surface (shell/exec).
31
+ * Frequency: startup/CI canary (deterministic layer is a unit-test drift lock;
32
+ * binary layer is best-effort per host).
33
+ * Stability: semi-stable — Codex changes hook vocabulary across minor versions.
34
+ * Fallback: none — failure is a code-fix surface, surfaced via DegradationReporter.
35
+ * Verdict: deterministic structural assertion (A) + version-tolerant
36
+ * binary-schema probe (B); no LLM fallback needed.
37
+ */
38
+ /** Hook events instar's enforcement layer registers and depends on. */
39
+ export declare const REQUIRED_CODEX_HOOK_EVENTS: readonly ["PreToolUse", "PermissionRequest", "Stop", "SessionStart", "UserPromptSubmit"];
40
+ export interface CodexHookContractCanaryResult {
41
+ status: 'pass' | 'fail' | 'skip';
42
+ message: string;
43
+ details: {
44
+ /** Layer A — deterministic invariant lock. */
45
+ matcherIsRegex: boolean;
46
+ dangerousGuardOnPreToolUse: boolean;
47
+ stopReviewTrioWired: boolean;
48
+ /** Layer B — live-binary probe. */
49
+ binaryProbed: boolean;
50
+ binaryPath?: string;
51
+ missingEventsInBinary: string[];
52
+ failures: string[];
53
+ };
54
+ }
55
+ /**
56
+ * Resolve a codex binary path, best-effort. Returns null if none found —
57
+ * the binary layer is then skipped, not failed.
58
+ */
59
+ export declare function resolveCodexBinaryForCanary(): string | null;
60
+ /**
61
+ * Run the canary. Layer A is synchronous and always meaningful. Layer B
62
+ * probes a codex binary if one resolves; otherwise that layer is skipped.
63
+ */
64
+ export declare function runCodexHookContractCanary(): CodexHookContractCanaryResult;
65
+ //# sourceMappingURL=codexHookContractCanary.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"codexHookContractCanary.d.ts","sourceRoot":"","sources":["../../../../../src/providers/adapters/openai-codex/canary/codexHookContractCanary.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoCG;AAQH,uEAAuE;AACvE,eAAO,MAAM,0BAA0B,0FAM7B,CAAC;AAEX,MAAM,WAAW,6BAA6B;IAC5C,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,MAAM,CAAC;IACjC,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE;QACP,8CAA8C;QAC9C,cAAc,EAAE,OAAO,CAAC;QACxB,0BAA0B,EAAE,OAAO,CAAC;QACpC,mBAAmB,EAAE,OAAO,CAAC;QAC7B,mCAAmC;QACnC,YAAY,EAAE,OAAO,CAAC;QACtB,UAAU,CAAC,EAAE,MAAM,CAAC;QACpB,qBAAqB,EAAE,MAAM,EAAE,CAAC;QAChC,QAAQ,EAAE,MAAM,EAAE,CAAC;KACpB,CAAC;CACH;AAID;;;GAGG;AACH,wBAAgB,2BAA2B,IAAI,MAAM,GAAG,IAAI,CAqB3D;AAkBD;;;GAGG;AACH,wBAAgB,0BAA0B,IAAI,6BAA6B,CAqF1E"}
@@ -0,0 +1,178 @@
1
+ /**
2
+ * Codex hook-contract canary.
3
+ *
4
+ * The Codex enforcement layer (installCodexHooks → .codex/hooks.json) rests on
5
+ * a handful of load-bearing, empirically-won assumptions about Codex's hook
6
+ * contract. Two of them were silent-failure bugs we already paid for live
7
+ * (see docs/specs/codex-enforcement-hook-layer.md §P5c):
8
+ * 1. The PreToolUse `matcher` is a REGEX against the tool name — a bare `*`
9
+ * matches NOTHING, so the guard silently never fires. It must be `.*`.
10
+ * 2. Codex's shell tool is `exec_command` and carries the command in
11
+ * `tool_input.cmd` (not Claude's `tool_input.command`); the guard shim
12
+ * reads both.
13
+ * If a future Codex version renames the hook events, drops PreToolUse, or
14
+ * changes the deny mechanism, the gates would silently no-op again — "looks
15
+ * installed, blocks nothing." This canary fails loudly instead.
16
+ *
17
+ * Two layers:
18
+ * (A) DETERMINISTIC invariant lock (always runs, env-independent): asserts
19
+ * buildInstarCodexHookGroups still emits the load-bearing shape — `.*`
20
+ * matcher, dangerous-command-guard on PreToolUse, the full Stop review
21
+ * trio. A refactor that regresses any of these fails the canary in CI.
22
+ * (B) BEST-EFFORT live-binary contract check: if a codex binary is
23
+ * resolvable on this host, read its embedded hook-event schema and
24
+ * assert the events instar depends on (PreToolUse, PermissionRequest,
25
+ * Stop, SessionStart, UserPromptSubmit) are still present. No binary →
26
+ * status 'skip' for layer B (NOT fail — most hosts/CI have no codex).
27
+ *
28
+ * RULE 3.1 RATIONALE
29
+ * Criticality: critical — a silent no-op guard is a false sense of safety on
30
+ * Codex's main destructive surface (shell/exec).
31
+ * Frequency: startup/CI canary (deterministic layer is a unit-test drift lock;
32
+ * binary layer is best-effort per host).
33
+ * Stability: semi-stable — Codex changes hook vocabulary across minor versions.
34
+ * Fallback: none — failure is a code-fix surface, surfaced via DegradationReporter.
35
+ * Verdict: deterministic structural assertion (A) + version-tolerant
36
+ * binary-schema probe (B); no LLM fallback needed.
37
+ */
38
+ import fs from 'node:fs';
39
+ import path from 'node:path';
40
+ import os from 'node:os';
41
+ import { execFileSync } from 'node:child_process';
42
+ import { buildInstarCodexHookGroups } from '../../../../core/installCodexHooks.js';
43
+ /** Hook events instar's enforcement layer registers and depends on. */
44
+ export const REQUIRED_CODEX_HOOK_EVENTS = [
45
+ 'PreToolUse',
46
+ 'PermissionRequest',
47
+ 'Stop',
48
+ 'SessionStart',
49
+ 'UserPromptSubmit',
50
+ ];
51
+ const PROBE_PROJECT_DIR = '/tmp/__codex_hook_canary__';
52
+ /**
53
+ * Resolve a codex binary path, best-effort. Returns null if none found —
54
+ * the binary layer is then skipped, not failed.
55
+ */
56
+ export function resolveCodexBinaryForCanary() {
57
+ // 1. asdf shim / PATH lookup (the host's real, doc-matching codex).
58
+ for (const probe of ['codex']) {
59
+ try {
60
+ const out = execFileSync('which', [probe], { encoding: 'utf-8', stdio: ['ignore', 'pipe', 'ignore'] }).trim();
61
+ if (out && fs.existsSync(out))
62
+ return out;
63
+ }
64
+ catch {
65
+ /* not on PATH */
66
+ }
67
+ }
68
+ // 2. Known npm-global vendor locations (asdf node installs).
69
+ const home = os.homedir();
70
+ const candidates = [
71
+ '/usr/local/bin/codex',
72
+ '/opt/homebrew/bin/codex',
73
+ path.join(home, '.asdf', 'shims', 'codex'),
74
+ ];
75
+ for (const c of candidates) {
76
+ if (fs.existsSync(c))
77
+ return c;
78
+ }
79
+ return null;
80
+ }
81
+ /**
82
+ * Read a (possibly large) binary and test whether its embedded hook-event
83
+ * schema enumerates the given event name. We look for the quoted event name
84
+ * adjacent to the schema's hook-event vocabulary rather than anywhere in the
85
+ * file, to avoid coincidental matches. Tolerant: returns true on match.
86
+ */
87
+ function binaryDeclaresEvent(binaryText, event) {
88
+ // The schema serializes events as `"const": "PreToolUse"` (HookSpecificOutput
89
+ // wires) and as enum members `"PreToolUse"` inside HookEventNameWire. Either
90
+ // form proves the event is part of the contract.
91
+ return (binaryText.includes(`"const": "${event}"`) ||
92
+ binaryText.includes(`"${event}"`));
93
+ }
94
+ /**
95
+ * Run the canary. Layer A is synchronous and always meaningful. Layer B
96
+ * probes a codex binary if one resolves; otherwise that layer is skipped.
97
+ */
98
+ export function runCodexHookContractCanary() {
99
+ const failures = [];
100
+ // ---- Layer A: deterministic invariant lock ----
101
+ const groups = buildInstarCodexHookGroups(PROBE_PROJECT_DIR);
102
+ const preMatcher = groups.PreToolUse?.[0]?.matcher;
103
+ const matcherIsRegex = preMatcher === '.*';
104
+ if (!matcherIsRegex) {
105
+ failures.push(`PreToolUse matcher is '${preMatcher}', expected '.*' (a bare '*' matches nothing — gate would silently never fire)`);
106
+ }
107
+ const preCommands = (groups.PreToolUse?.[0]?.hooks ?? []).map((h) => h.command);
108
+ const dangerousGuardOnPreToolUse = preCommands.some((c) => c.includes('dangerous-command-guard.sh'));
109
+ if (!dangerousGuardOnPreToolUse) {
110
+ failures.push('dangerous-command-guard.sh missing from PreToolUse — Codex shell/exec would pass ungated');
111
+ }
112
+ const stopCommands = (groups.Stop?.[0]?.hooks ?? []).map((h) => h.command);
113
+ const stopReviewTrioWired = stopCommands.some((c) => c.includes('response-review.js')) &&
114
+ stopCommands.some((c) => c.includes('deferral-detector.js')) &&
115
+ stopCommands.some((c) => c.includes('scope-coherence-checkpoint.js'));
116
+ if (!stopReviewTrioWired) {
117
+ failures.push('Stop review trio incomplete — expected response-review + deferral-detector + scope-coherence-checkpoint');
118
+ }
119
+ // ---- Layer B: best-effort live-binary contract probe ----
120
+ const binaryPath = resolveCodexBinaryForCanary();
121
+ let binaryProbed = false;
122
+ const missingEventsInBinary = [];
123
+ if (binaryPath) {
124
+ try {
125
+ const text = fs.readFileSync(binaryPath, 'latin1');
126
+ // Sanity: only treat it as a probe if the binary actually carries the
127
+ // hook schema (resolves the "wrong binary" / shim-script case gracefully).
128
+ const looksLikeCodexHooks = text.includes('hook_event_name') || text.includes('HookEventNameWire');
129
+ if (looksLikeCodexHooks) {
130
+ binaryProbed = true;
131
+ for (const ev of REQUIRED_CODEX_HOOK_EVENTS) {
132
+ if (!binaryDeclaresEvent(text, ev))
133
+ missingEventsInBinary.push(ev);
134
+ }
135
+ if (missingEventsInBinary.length > 0) {
136
+ failures.push(`codex binary (${binaryPath}) no longer declares hook events: ${missingEventsInBinary.join(', ')} — the enforcement layer would not fire`);
137
+ }
138
+ }
139
+ // If it doesn't look like a hooks-capable codex (e.g. a shim wrapper or
140
+ // an old version), leave binaryProbed=false → layer B skipped, not failed.
141
+ }
142
+ catch {
143
+ // Unreadable binary → skip layer B rather than fail.
144
+ }
145
+ }
146
+ const layerASolid = matcherIsRegex && dangerousGuardOnPreToolUse && stopReviewTrioWired;
147
+ let status;
148
+ let message;
149
+ if (failures.length > 0) {
150
+ status = 'fail';
151
+ message = `codex hook-contract canary: FAILED — ${failures.join('; ')}`;
152
+ }
153
+ else if (!binaryProbed) {
154
+ // Layer A passed but no codex binary to confirm the live contract.
155
+ status = 'skip';
156
+ message = layerASolid
157
+ ? 'codex hook-contract canary: invariants intact (no codex binary on host — live-contract probe skipped)'
158
+ : 'codex hook-contract canary: invariants intact';
159
+ }
160
+ else {
161
+ status = 'pass';
162
+ message = `codex hook-contract canary: invariants intact + binary (${binaryPath}) declares all required hook events`;
163
+ }
164
+ return {
165
+ status,
166
+ message,
167
+ details: {
168
+ matcherIsRegex,
169
+ dangerousGuardOnPreToolUse,
170
+ stopReviewTrioWired,
171
+ binaryProbed,
172
+ binaryPath: binaryPath ?? undefined,
173
+ missingEventsInBinary,
174
+ failures,
175
+ },
176
+ };
177
+ }
178
+ //# sourceMappingURL=codexHookContractCanary.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"codexHookContractCanary.js","sourceRoot":"","sources":["../../../../../src/providers/adapters/openai-codex/canary/codexHookContractCanary.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "instar",
3
- "version": "1.2.69",
3
+ "version": "1.2.70",
4
4
  "description": "Coherence infrastructure for self-evolving AI agents — on the Claude Code or Codex subscription you already have.",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "$schema": "./builtin-manifest.schema.json",
3
3
  "schemaVersion": 1,
4
- "generatedAt": "2026-05-25T03:15:08.421Z",
5
- "instarVersion": "1.2.69",
4
+ "generatedAt": "2026-05-25T03:32:30.612Z",
5
+ "instarVersion": "1.2.70",
6
6
  "entryCount": 191,
7
7
  "entries": {
8
8
  "hook:session-start": {
@@ -0,0 +1,72 @@
1
+ # Upgrade Guide — vNEXT
2
+
3
+ <!-- bump: patch -->
4
+ <!-- patch = bug fixes, refactors, test additions, doc updates -->
5
+
6
+ ## What Changed
7
+
8
+ Two pieces of Codex-parity hardening on the enforcement-hook layer, both within
9
+ the approved spec (`docs/specs/codex-enforcement-hook-layer.md`):
10
+
11
+ 1. **Scope-coherence checkpoint now runs on Codex.** `installCodexHooks` wires
12
+ `scope-coherence-checkpoint.js` into Codex's `Stop` event, joining the
13
+ `response-review` + `deferral-detector` pair already there. This completes the
14
+ spec §4.1 Stop mapping ("deferral / scope checkpoint → Stop") — previously only
15
+ deferral was wired. The script is framework-neutral (reads stdin, POSTs to the
16
+ local server) and Codex honors `{decision:"block", reason}` on `Stop` (verified
17
+ in the 0.133 binary's `StopCommandOutputWire`), so it gives Codex agents the same
18
+ structural "zoom out and re-read scope" grounding pause Claude agents get — not a
19
+ hard termination. It defaults to approve and self-throttles (depth threshold +
20
+ 30-minute cooldown), so it cannot loop an autonomous run. Existing Codex agents
21
+ pick it up on update: the script already ships via always-overwrite migration and
22
+ `migrateHooks` re-runs `installCodexHooks` for codex-cli agents.
23
+
24
+ 2. **A hook-contract drift canary** (`codexHookContractCanary.ts`). Layer A is an
25
+ env-independent invariant lock: it asserts the Codex hook config still has the
26
+ load-bearing shape that two earlier live silent-no-op bugs taught us to protect —
27
+ the `.*` tool matcher (a bare `*` matches nothing), `dangerous-command-guard` on
28
+ PreToolUse, and the full Stop review trio. A refactor that regresses any of these
29
+ fails CI. Layer B is best-effort: when a real codex binary is resolvable, it reads
30
+ the binary's embedded hook-event schema and confirms the events instar depends on
31
+ are still declared (catching real Codex-side contract drift). No binary present →
32
+ the binary layer skips rather than fails.
33
+
34
+ Also recorded honestly: a WIP that would have wired compaction-recovery to Codex's
35
+ `PostCompact` event was set aside after verifying against the 0.133 binary schema
36
+ that `PostCompact` has no `additionalContext` field — the only channel that
37
+ re-injects context into the model. It would have installed a hook that does nothing.
38
+ Codex compaction-recovery parity needs a different mechanism and is tracked.
39
+
40
+ ## What to Tell Your User
41
+
42
+ - **Codex agents now get the same scope-grounding check Claude agents have**: "When
43
+ I've been heads-down implementing for a long stretch, I now get a structural nudge
44
+ to step back and re-check I'm building the right thing — on the Codex engine too,
45
+ not just on Claude."
46
+ - **A watchdog for the Codex safety guards**: "There's now an automatic check that
47
+ notices if the Codex safety guards ever stop firing or if Codex changes its format
48
+ underneath us — so a guard can't silently turn into a no-op without us catching it."
49
+ - Nothing for you to do — both ship automatically on update.
50
+
51
+ ## Summary of New Capabilities
52
+
53
+ | Capability | How to Use |
54
+ |-----------|-----------|
55
+ | Scope-coherence checkpoint on Codex Stop | Automatic (installed via init + update migration) |
56
+ | Codex hook-contract drift canary | Automatic (CI invariant lock; best-effort binary probe) |
57
+
58
+ ## Evidence
59
+
60
+ - **Codex Stop schema honors `decision:block`**: verified directly against the
61
+ codex-cli 0.133.0 binary — `strings` shows `StopCommandOutputWire` plus the error
62
+ string `"Stop hook returned decision:block without a non-empty reason"`, confirming
63
+ the block-with-reason contract the scope-coherence script relies on.
64
+ - **PostCompact cannot re-inject context** (why that WIP was dropped): the binary's
65
+ `post-compact.command.output` schema enumerates only `continue/stopReason/`
66
+ `suppressOutput/systemMessage` — no `additionalContext`. Only the `SessionStart`
67
+ and `UserPromptSubmit` output wires carry `additionalContext`, and `SessionStart`
68
+ triggers are `startup/resume/clear` (no `compact`). Verified by extracting the
69
+ embedded JSON schema from the binary.
70
+ - **Tests**: `installCodexHooks.test.ts` 8 green (incl. new Stop-trio assertion);
71
+ `codexHookContractCanary.test.ts` 6 green (layer-A invariants always asserted;
72
+ layer-B skip-not-fail with no binary). `tsc` clean.
@@ -0,0 +1,34 @@
1
+ # Side-Effects Review: Codex parity — Stop scope-coherence + hook-contract canary (P6)
2
+
3
+ ## Change
4
+ Two changes to the Codex enforcement layer, both within the approved spec (`docs/specs/codex-enforcement-hook-layer.md`):
5
+
6
+ 1. **`installCodexHooks.ts`** — added `scope-coherence-checkpoint.js` to the Codex `Stop` event, alongside the existing `response-review.js` + `deferral-detector.js`. Completes the spec §4.1 mapping ("deferral / scope checkpoint → Stop"), which previously wired only deferral.
7
+ 2. **`codexHookContractCanary.ts`** (new) — the P6 hook-contract drift canary. Two layers: (A) a deterministic, env-independent invariant lock asserting `buildInstarCodexHookGroups` still emits the load-bearing shape (`.*` matcher, `dangerous-command-guard` on PreToolUse, the full Stop review trio); (B) a best-effort probe of a resolvable codex binary's embedded hook-event schema, asserting the events instar depends on are still declared.
8
+
9
+ ## Why
10
+ - **Scope-coherence on Stop**: the spec intends it; without it, Codex agents drift deep into implementation without the structural zoom-out that Claude agents get. The script is framework-neutral (reads stdin, POSTs to the local server) and Codex honors `{decision:'block', reason}` on Stop (verified in the 0.133 binary's `StopCommandOutputWire`). Same grounding-pause semantics as Claude — not a hard termination.
11
+ - **Canary**: P5c paid for two silent-no-op bugs live (a `*` matcher that matched nothing; the `cmd` vs `command` field). Layer A is the regression lock against that exact class — a refactor that regresses any invariant fails CI. Layer B catches real Codex-side drift (renamed/dropped hook events) when a binary is present.
12
+
13
+ ## Scope / blast radius
14
+ - `scope-coherence-checkpoint.js` already ships to all agents via always-overwrite migration (`PostUpdateMigrator` line ~1698) and `installCodexHooks` is called from `migrateHooks` gated on codex-cli (line ~1655) — so existing Codex agents pick up the new Stop wiring on update (migration parity satisfied, no new migration needed). `validateHookReferences` guards against a dangling reference.
15
+ - The canary is invoked only from its unit test (the established pattern for the existing Codex canaries — CI drift lock), so it adds zero runtime cost on the hot path.
16
+
17
+ ## Signal vs Authority
18
+ - Unchanged. scope-coherence is a low-context Stop-trigger that routes to the server; it never holds blocking authority of its own beyond the existing grounding-pause. The canary is pure verification — no authority, no runtime gating.
19
+
20
+ ## Over-block / autonomy risk
21
+ - scope-coherence defaults to `approve` and self-throttles (depth threshold + 30-min cooldown), so it cannot loop an autonomous Codex run. The deferral-detector already runs on Codex Stop the same way (proven-compatible precedent).
22
+
23
+ ## Honesty note — PostCompact NOT shipped
24
+ - A WIP that wired `compaction-recovery.sh` to Codex's `PostCompact` event was set aside this session after verifying (against the 0.133 binary schema) that `PostCompact` exposes only `continue/stopReason/suppressOutput/systemMessage` — no `additionalContext`, the only field that re-injects context. Only `SessionStart`/`UserPromptSubmit` carry it, and Codex's `SessionStart` triggers are `startup/resume/clear` (no `compact`). So that wiring would have installed a hook that cannot re-inject identity — dead on arrival. Compaction-recovery parity on Codex needs a different mechanism; tracked, not shipped.
25
+
26
+ ## Rollback
27
+ - Revert the one-line `Stop` array edit + delete the canary module + test. No data migration, no config change.
28
+
29
+ ## Tests
30
+ - `installCodexHooks.test.ts`: +1 test asserting the full Stop review trio (response-review + deferral + scope-coherence). 8 green.
31
+ - `codexHookContractCanary.test.ts`: 6 tests — layer-A invariants always asserted; layer-B skip-not-fail when no binary; binary-probed branch asserts all required events. Green.
32
+
33
+ ## Publish
34
+ - Feature branch `echo/codex-parity-audit`. Targets a patch release on merge.