instar 0.28.117 → 0.28.119

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.
@@ -0,0 +1,91 @@
1
+ /**
2
+ * FrameworkParitySentinel — consumer of the Layer-3 parity rules registry.
3
+ *
4
+ * Spec: specs/instar-foundations/framework-parity-sentinel.md
5
+ *
6
+ * Walks the registry on its scan cadence (and on triggers), calls each rule's
7
+ * verify() per instance, surfaces drift via events + degradation reports, and
8
+ * (per rule's remediationPolicy) optionally calls remediate() to re-render
9
+ * canonical into the framework-native shape.
10
+ *
11
+ * v0.1 scope:
12
+ * - Registry walker (consume listParityRules → iterate → collect verify).
13
+ * - State file persistence (.instar/state/framework-parity-sentinel.json).
14
+ * - Interval trigger (single setInterval; no chokidar watcher yet).
15
+ * - EventEmitter wiring (5 events: gap-found, remediated, remediation-refused,
16
+ * orphan-found, scan-complete).
17
+ * - Degradation reporter on persistent unresolved gaps.
18
+ *
19
+ * v0.2 deferred: chokidar source-change watcher, per-instance remediate HTTP
20
+ * route, trust-level integration for mirror-trust gating, backfill migration.
21
+ */
22
+ import { EventEmitter } from 'node:events';
23
+ import { getParityRule } from '../providers/parity/registry.js';
24
+ import type { IntelligenceFramework } from '../core/intelligenceProviderFactory.js';
25
+ export interface FrameworkParitySentinelConfig {
26
+ /** Project root (passed to each rule's verify/remediate). */
27
+ projectRoot: string;
28
+ /** State directory (typically `.instar`). */
29
+ stateDir: string;
30
+ /** Which frameworks are currently enabled for this agent. */
31
+ enabledFrameworks: ReadonlyArray<IntelligenceFramework>;
32
+ /** Scan interval in ms. Default: 1_800_000 (30 min). */
33
+ scanIntervalMs?: number;
34
+ /** Initial scan delay in ms. Default: 60_000 (1 min after start). */
35
+ initialScanDelayMs?: number;
36
+ /** If true, mirror-trust rules call remediate(); if false, all rules are flag-only. */
37
+ remediationEnabled?: boolean;
38
+ }
39
+ interface PerInstanceCursor {
40
+ lastScanAt: string;
41
+ lastResult: 'ok' | 'drift' | 'conflict' | 'error';
42
+ lastDetail?: string;
43
+ /** Number of consecutive scans with unresolved drift — used for degradation reporting. */
44
+ unresolvedCount: number;
45
+ }
46
+ export interface ParityScanReport {
47
+ scannedAt: string;
48
+ rulesWalked: number;
49
+ instancesChecked: number;
50
+ gapsFound: number;
51
+ remediated: number;
52
+ remediationRefused: number;
53
+ orphansFound: number;
54
+ }
55
+ export declare class FrameworkParitySentinel extends EventEmitter {
56
+ private config;
57
+ private state;
58
+ private statePath;
59
+ private interval;
60
+ private initialTimeout;
61
+ private isScanning;
62
+ constructor(config: FrameworkParitySentinelConfig);
63
+ start(): void;
64
+ stop(): void;
65
+ /**
66
+ * Run a full scan immediately. Returns a structured report. Safe to call
67
+ * concurrently — overlapping calls are short-circuited.
68
+ */
69
+ scan(): Promise<ParityScanReport>;
70
+ /**
71
+ * Returns the current scan state — used by the HTTP /api/framework-parity/status route.
72
+ */
73
+ getStatus(): {
74
+ lastScanAt: string | null;
75
+ cursors: Record<string, PerInstanceCursor>;
76
+ };
77
+ private scanRule;
78
+ private attemptRemediate;
79
+ private shouldRemediate;
80
+ private recordRuleError;
81
+ private loadState;
82
+ private saveState;
83
+ }
84
+ /**
85
+ * Lookup a single rule by primitive. Re-exported here so the sentinel's
86
+ * tests and the HTTP routes have a single import surface.
87
+ * @internal
88
+ */
89
+ export declare const _getParityRuleForTest: typeof getParityRule;
90
+ export {};
91
+ //# sourceMappingURL=FrameworkParitySentinel.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"FrameworkParitySentinel.d.ts","sourceRoot":"","sources":["../../src/monitoring/FrameworkParitySentinel.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAG3C,OAAO,EAEL,aAAa,EACd,MAAM,iCAAiC,CAAC;AAMzC,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,wCAAwC,CAAC;AAKpF,MAAM,WAAW,6BAA6B;IAC5C,6DAA6D;IAC7D,WAAW,EAAE,MAAM,CAAC;IACpB,6CAA6C;IAC7C,QAAQ,EAAE,MAAM,CAAC;IACjB,6DAA6D;IAC7D,iBAAiB,EAAE,aAAa,CAAC,qBAAqB,CAAC,CAAC;IACxD,wDAAwD;IACxD,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,qEAAqE;IACrE,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,uFAAuF;IACvF,kBAAkB,CAAC,EAAE,OAAO,CAAC;CAC9B;AAED,UAAU,iBAAiB;IACzB,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,IAAI,GAAG,OAAO,GAAG,UAAU,GAAG,OAAO,CAAC;IAClD,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,0FAA0F;IAC1F,eAAe,EAAE,MAAM,CAAC;CACzB;AASD,MAAM,WAAW,gBAAgB;IAC/B,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,MAAM,CAAC;IACpB,gBAAgB,EAAE,MAAM,CAAC;IACzB,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;IACnB,kBAAkB,EAAE,MAAM,CAAC;IAC3B,YAAY,EAAE,MAAM,CAAC;CACtB;AAUD,qBAAa,uBAAwB,SAAQ,YAAY;IACvD,OAAO,CAAC,MAAM,CAAgC;IAC9C,OAAO,CAAC,KAAK,CAAgB;IAC7B,OAAO,CAAC,SAAS,CAAS;IAC1B,OAAO,CAAC,QAAQ,CAA+C;IAC/D,OAAO,CAAC,cAAc,CAA8C;IACpE,OAAO,CAAC,UAAU,CAAS;gBAEf,MAAM,EAAE,6BAA6B;IASjD,KAAK,IAAI,IAAI;IAsBb,IAAI,IAAI,IAAI;IAaZ;;;OAGG;IACG,IAAI,IAAI,OAAO,CAAC,gBAAgB,CAAC;IAkDvC;;OAEG;IACH,SAAS,IAAI;QAAE,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;QAAC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,iBAAiB,CAAC,CAAA;KAAE;YASxE,QAAQ;YAiFR,gBAAgB;IA4B9B,OAAO,CAAC,eAAe;IAMvB,OAAO,CAAC,eAAe;IAcvB,OAAO,CAAC,SAAS;IAWjB,OAAO,CAAC,SAAS;CAWlB;AAID;;;;GAIG;AACH,eAAO,MAAM,qBAAqB,sBAAgB,CAAC"}
@@ -0,0 +1,286 @@
1
+ /**
2
+ * FrameworkParitySentinel — consumer of the Layer-3 parity rules registry.
3
+ *
4
+ * Spec: specs/instar-foundations/framework-parity-sentinel.md
5
+ *
6
+ * Walks the registry on its scan cadence (and on triggers), calls each rule's
7
+ * verify() per instance, surfaces drift via events + degradation reports, and
8
+ * (per rule's remediationPolicy) optionally calls remediate() to re-render
9
+ * canonical into the framework-native shape.
10
+ *
11
+ * v0.1 scope:
12
+ * - Registry walker (consume listParityRules → iterate → collect verify).
13
+ * - State file persistence (.instar/state/framework-parity-sentinel.json).
14
+ * - Interval trigger (single setInterval; no chokidar watcher yet).
15
+ * - EventEmitter wiring (5 events: gap-found, remediated, remediation-refused,
16
+ * orphan-found, scan-complete).
17
+ * - Degradation reporter on persistent unresolved gaps.
18
+ *
19
+ * v0.2 deferred: chokidar source-change watcher, per-instance remediate HTTP
20
+ * route, trust-level integration for mirror-trust gating, backfill migration.
21
+ */
22
+ import { EventEmitter } from 'node:events';
23
+ import fs from 'node:fs';
24
+ import path from 'node:path';
25
+ import { listParityRules, getParityRule, } from '../providers/parity/registry.js';
26
+ import { DegradationReporter } from './DegradationReporter.js';
27
+ // ── Helpers ───────────────────────────────────────────────────────
28
+ function cursorKey(primitive, instance) {
29
+ return `${primitive}::${instance}`;
30
+ }
31
+ // ── Implementation ────────────────────────────────────────────────
32
+ export class FrameworkParitySentinel extends EventEmitter {
33
+ config;
34
+ state;
35
+ statePath;
36
+ interval = null;
37
+ initialTimeout = null;
38
+ isScanning = false;
39
+ constructor(config) {
40
+ super();
41
+ this.config = config;
42
+ this.statePath = path.join(config.stateDir, 'state', 'framework-parity-sentinel.json');
43
+ this.state = this.loadState();
44
+ }
45
+ // ── Lifecycle ──────────────────────────────────────────────────
46
+ start() {
47
+ if (this.interval)
48
+ return;
49
+ const intervalMs = this.config.scanIntervalMs ?? 1_800_000;
50
+ const initialDelay = this.config.initialScanDelayMs ?? 60_000;
51
+ this.initialTimeout = setTimeout(() => {
52
+ void this.scan();
53
+ }, initialDelay);
54
+ this.initialTimeout.unref?.();
55
+ this.interval = setInterval(() => {
56
+ void this.scan();
57
+ }, intervalMs);
58
+ this.interval.unref?.();
59
+ console.log(`[FrameworkParitySentinel] started — interval ${Math.round(intervalMs / 60_000)}m, ` +
60
+ `first scan in ${Math.round(initialDelay / 1000)}s`);
61
+ }
62
+ stop() {
63
+ if (this.initialTimeout) {
64
+ clearTimeout(this.initialTimeout);
65
+ this.initialTimeout = null;
66
+ }
67
+ if (this.interval) {
68
+ clearInterval(this.interval);
69
+ this.interval = null;
70
+ }
71
+ }
72
+ // ── Public API ─────────────────────────────────────────────────
73
+ /**
74
+ * Run a full scan immediately. Returns a structured report. Safe to call
75
+ * concurrently — overlapping calls are short-circuited.
76
+ */
77
+ async scan() {
78
+ if (this.isScanning) {
79
+ return {
80
+ scannedAt: new Date().toISOString(),
81
+ rulesWalked: 0,
82
+ instancesChecked: 0,
83
+ gapsFound: 0,
84
+ remediated: 0,
85
+ remediationRefused: 0,
86
+ orphansFound: 0,
87
+ };
88
+ }
89
+ this.isScanning = true;
90
+ const scannedAt = new Date().toISOString();
91
+ const report = {
92
+ scannedAt,
93
+ rulesWalked: 0,
94
+ instancesChecked: 0,
95
+ gapsFound: 0,
96
+ remediated: 0,
97
+ remediationRefused: 0,
98
+ orphansFound: 0,
99
+ };
100
+ try {
101
+ const rules = listParityRules();
102
+ for (const rule of rules) {
103
+ report.rulesWalked += 1;
104
+ await this.scanRule(rule, report);
105
+ }
106
+ this.state.lastScanAt = scannedAt;
107
+ this.saveState();
108
+ this.emit('parity:scan-complete', report);
109
+ return report;
110
+ }
111
+ catch (err) {
112
+ DegradationReporter.getInstance().report({
113
+ feature: 'FrameworkParitySentinel.scan',
114
+ primary: 'Walk parity rules registry + verify',
115
+ fallback: 'Scan aborted; cursors not advanced',
116
+ reason: `Scan error: ${err instanceof Error ? err.message : String(err)}`,
117
+ impact: 'Cross-framework drift may go undetected until next successful scan',
118
+ });
119
+ console.error('[FrameworkParitySentinel] scan error:', err);
120
+ return report;
121
+ }
122
+ finally {
123
+ this.isScanning = false;
124
+ }
125
+ }
126
+ /**
127
+ * Returns the current scan state — used by the HTTP /api/framework-parity/status route.
128
+ */
129
+ getStatus() {
130
+ return {
131
+ lastScanAt: this.state.lastScanAt,
132
+ cursors: { ...this.state.cursors },
133
+ };
134
+ }
135
+ // ── Scan implementation ────────────────────────────────────────
136
+ async scanRule(rule, report) {
137
+ let instances;
138
+ try {
139
+ instances = await rule.listInstances(this.config.projectRoot);
140
+ }
141
+ catch (err) {
142
+ this.recordRuleError(rule, err);
143
+ return;
144
+ }
145
+ for (const instance of instances) {
146
+ report.instancesChecked += 1;
147
+ const key = cursorKey(rule.primitive, instance);
148
+ let result = 'ok';
149
+ let detail;
150
+ try {
151
+ const verifyResult = await rule.verify(this.config.projectRoot, instance);
152
+ if (!verifyResult.ok) {
153
+ report.gapsFound += verifyResult.mismatches.length;
154
+ const hasConflict = verifyResult.mismatches.some((m) => m.reasonCode === 'user-edit-conflict');
155
+ result = hasConflict ? 'conflict' : 'drift';
156
+ detail = verifyResult.mismatches.map((m) => `${m.framework}: ${m.detail}`).join('; ');
157
+ for (const m of verifyResult.mismatches) {
158
+ this.emit('parity:gap-found', m);
159
+ }
160
+ if (result === 'drift' && this.shouldRemediate(rule)) {
161
+ for (const m of verifyResult.mismatches) {
162
+ if (m.framework === 'canonical')
163
+ continue; // can't remediate canonical drift
164
+ await this.attemptRemediate(rule, instance, m.framework, report);
165
+ }
166
+ }
167
+ else if (result === 'conflict') {
168
+ for (const m of verifyResult.mismatches) {
169
+ this.emit('parity:remediation-refused', m);
170
+ report.remediationRefused += 1;
171
+ }
172
+ }
173
+ }
174
+ }
175
+ catch (err) {
176
+ result = 'error';
177
+ detail = err instanceof Error ? err.message : String(err);
178
+ }
179
+ const prior = this.state.cursors[key];
180
+ const unresolvedCount = result === 'ok'
181
+ ? 0
182
+ : (prior?.unresolvedCount ?? 0) + 1;
183
+ this.state.cursors[key] = {
184
+ lastScanAt: report.scannedAt,
185
+ lastResult: result,
186
+ lastDetail: detail,
187
+ unresolvedCount,
188
+ };
189
+ if (unresolvedCount >= 3 && result !== 'ok') {
190
+ DegradationReporter.getInstance().report({
191
+ feature: `parity:${rule.primitive}:${instance}`,
192
+ primary: 'Cross-framework parity for this instance',
193
+ fallback: 'Drift persists across multiple scans',
194
+ reason: detail ?? 'unknown',
195
+ impact: `Drift unresolved for ${unresolvedCount} consecutive scans`,
196
+ });
197
+ }
198
+ }
199
+ // Orphan detection (per rule)
200
+ try {
201
+ const orphans = await rule.listOrphans(this.config.projectRoot);
202
+ for (const o of orphans) {
203
+ report.orphansFound += 1;
204
+ this.emit('parity:orphan-found', o);
205
+ }
206
+ }
207
+ catch (err) {
208
+ this.recordRuleError(rule, err);
209
+ }
210
+ }
211
+ async attemptRemediate(rule, instance, framework, report) {
212
+ if (framework === 'canonical')
213
+ return;
214
+ if (!this.config.enabledFrameworks.includes(framework))
215
+ return;
216
+ try {
217
+ await rule.remediate(this.config.projectRoot, instance, framework);
218
+ report.remediated += 1;
219
+ this.emit('parity:remediated', {
220
+ primitive: rule.primitive,
221
+ instance,
222
+ framework,
223
+ });
224
+ }
225
+ catch (err) {
226
+ report.remediationRefused += 1;
227
+ this.emit('parity:remediation-refused', {
228
+ primitive: rule.primitive,
229
+ instanceName: instance,
230
+ framework,
231
+ reasonCode: 'user-edit-conflict',
232
+ detail: err instanceof Error ? err.message : String(err),
233
+ });
234
+ }
235
+ }
236
+ shouldRemediate(rule) {
237
+ if (rule.remediationPolicy === 'flag-only')
238
+ return false;
239
+ if (this.config.remediationEnabled === false)
240
+ return false;
241
+ return true;
242
+ }
243
+ recordRuleError(rule, err) {
244
+ const detail = err instanceof Error ? err.message : String(err);
245
+ console.error(`[FrameworkParitySentinel] rule ${rule.primitive} error: ${detail}`);
246
+ DegradationReporter.getInstance().report({
247
+ feature: `parity:${rule.primitive}`,
248
+ primary: 'Walk this primitive\'s parity rule',
249
+ fallback: 'Skip this rule for this scan; other rules unaffected',
250
+ reason: detail,
251
+ impact: `Drift detection for ${rule.primitive} primitive paused until next successful scan`,
252
+ });
253
+ }
254
+ // ── Persistence ────────────────────────────────────────────────
255
+ loadState() {
256
+ try {
257
+ if (fs.existsSync(this.statePath)) {
258
+ return JSON.parse(fs.readFileSync(this.statePath, 'utf-8'));
259
+ }
260
+ }
261
+ catch {
262
+ /* start fresh */
263
+ }
264
+ return { cursors: {}, lastScanAt: null };
265
+ }
266
+ saveState() {
267
+ try {
268
+ const dir = path.dirname(this.statePath);
269
+ fs.mkdirSync(dir, { recursive: true });
270
+ const tmpPath = `${this.statePath}.${process.pid}.tmp`;
271
+ fs.writeFileSync(tmpPath, JSON.stringify(this.state, null, 2));
272
+ fs.renameSync(tmpPath, this.statePath);
273
+ }
274
+ catch {
275
+ // @silent-fallback-ok — state loss just re-scans on next pass
276
+ }
277
+ }
278
+ }
279
+ // ── Test seam ─────────────────────────────────────────────────────
280
+ /**
281
+ * Lookup a single rule by primitive. Re-exported here so the sentinel's
282
+ * tests and the HTTP routes have a single import surface.
283
+ * @internal
284
+ */
285
+ export const _getParityRuleForTest = getParityRule;
286
+ //# sourceMappingURL=FrameworkParitySentinel.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"FrameworkParitySentinel.js","sourceRoot":"","sources":["../../src/monitoring/FrameworkParitySentinel.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../../../src/providers/parity/registry.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,mBAAmB,EAAE,MAAM,YAAY,CAAC;AASlE,wBAAgB,aAAa,CAAC,SAAS,EAAE,mBAAmB,GAAG,UAAU,GAAG,SAAS,CAEpF;AAED,wBAAgB,eAAe,IAAI,aAAa,CAAC,UAAU,CAAC,CAE3D;AAED;;;;GAIG;AACH,wBAAgB,yBAAyB,CAAC,SAAS,EAAE,mBAAmB,EAAE,IAAI,EAAE,UAAU,GAAG,MAAM,IAAI,CAOtG"}
1
+ {"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../../../src/providers/parity/registry.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,mBAAmB,EAAE,MAAM,YAAY,CAAC;AAWlE,wBAAgB,aAAa,CAAC,SAAS,EAAE,mBAAmB,GAAG,UAAU,GAAG,SAAS,CAEpF;AAED,wBAAgB,eAAe,IAAI,aAAa,CAAC,UAAU,CAAC,CAE3D;AAED;;;;GAIG;AACH,wBAAgB,yBAAyB,CAAC,SAAS,EAAE,mBAAmB,EAAE,IAAI,EAAE,UAAU,GAAG,MAAM,IAAI,CAOtG"}
@@ -13,9 +13,11 @@
13
13
  */
14
14
  import { skillParityRule } from './rules/skillParityRule.js';
15
15
  import { hookParityRule } from './rules/hookParityRule.js';
16
+ import { memoryParityRule } from './rules/memoryParityRule.js';
16
17
  const RULES = new Map([
17
18
  [skillParityRule.primitive, skillParityRule],
18
19
  [hookParityRule.primitive, hookParityRule],
20
+ [memoryParityRule.primitive, memoryParityRule],
19
21
  ]);
20
22
  export function getParityRule(primitive) {
21
23
  return RULES.get(primitive);
@@ -1 +1 @@
1
- {"version":3,"file":"registry.js","sourceRoot":"","sources":["../../../src/providers/parity/registry.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAGH,OAAO,EAAE,eAAe,EAAE,MAAM,4BAA4B,CAAC;AAC7D,OAAO,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAE3D,MAAM,KAAK,GAAyC,IAAI,GAAG,CAAC;IAC1D,CAAC,eAAe,CAAC,SAAS,EAAE,eAAe,CAAC;IAC5C,CAAC,cAAc,CAAC,SAAS,EAAE,cAAc,CAAC;CAC3C,CAAC,CAAC;AAEH,MAAM,UAAU,aAAa,CAAC,SAA8B;IAC1D,OAAO,KAAK,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;AAC9B,CAAC;AAED,MAAM,UAAU,eAAe;IAC7B,OAAO,CAAC,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC,CAAC;AAC7B,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,yBAAyB,CAAC,SAA8B,EAAE,IAAgB;IACxF,MAAM,KAAK,GAAG,KAAK,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;IACnC,KAAK,CAAC,GAAG,CAAC,SAAS,EAAE,IAAI,CAAC,CAAC;IAC3B,OAAO,GAAG,EAAE;QACV,IAAI,KAAK;YAAE,KAAK,CAAC,GAAG,CAAC,SAAS,EAAE,KAAK,CAAC,CAAC;;YAClC,KAAK,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;IAC/B,CAAC,CAAC;AACJ,CAAC"}
1
+ {"version":3,"file":"registry.js","sourceRoot":"","sources":["../../../src/providers/parity/registry.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAGH,OAAO,EAAE,eAAe,EAAE,MAAM,4BAA4B,CAAC;AAC7D,OAAO,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAC3D,OAAO,EAAE,gBAAgB,EAAE,MAAM,6BAA6B,CAAC;AAE/D,MAAM,KAAK,GAAyC,IAAI,GAAG,CAAC;IAC1D,CAAC,eAAe,CAAC,SAAS,EAAE,eAAe,CAAC;IAC5C,CAAC,cAAc,CAAC,SAAS,EAAE,cAAc,CAAC;IAC1C,CAAC,gBAAgB,CAAC,SAAS,EAAE,gBAAgB,CAAC;CAC/C,CAAC,CAAC;AAEH,MAAM,UAAU,aAAa,CAAC,SAA8B;IAC1D,OAAO,KAAK,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;AAC9B,CAAC;AAED,MAAM,UAAU,eAAe;IAC7B,OAAO,CAAC,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC,CAAC;AAC7B,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,yBAAyB,CAAC,SAA8B,EAAE,IAAgB;IACxF,MAAM,KAAK,GAAG,KAAK,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;IACnC,KAAK,CAAC,GAAG,CAAC,SAAS,EAAE,IAAI,CAAC,CAAC;IAC3B,OAAO,GAAG,EAAE;QACV,IAAI,KAAK;YAAE,KAAK,CAAC,GAAG,CAAC,SAAS,EAAE,KAAK,CAAC,CAAC;;YAClC,KAAK,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;IAC/B,CAAC,CAAC;AACJ,CAAC"}
@@ -0,0 +1,31 @@
1
+ /**
2
+ * memoryParityRule — parity rule for the Memory functional primitive.
3
+ *
4
+ * Specs:
5
+ * - specs/instar-concepts/memory.md (canonical shape)
6
+ * - specs/frameworks/claude-code/memory.md
7
+ * - specs/frameworks/codex-cli/memory.md
8
+ *
9
+ * Memory is substrate-bound: the canonical artifacts (`.instar/AGENT.md`,
10
+ * `.instar/USER.md`, `.instar/MEMORY.md`, `.instar/state/topic-memory.sqlite`)
11
+ * are framework-agnostic files on disk. This rule's verify() confirms each
12
+ * required artifact is present, non-empty, and (for markdown) parses cleanly.
13
+ *
14
+ * v0.1 deliberately does NOT auto-remediate. Memory contains agent identity
15
+ * and accumulated learnings — silent regeneration would erase intentional
16
+ * drift. remediate() throws with a structured detail pointing to the documented
17
+ * repair procedure.
18
+ *
19
+ * Loading canonical Memory into framework system-prompts (CLAUDE.md / AGENTS.md
20
+ * references) is the InstructionFile primitive's responsibility — separate.
21
+ */
22
+ import type { ParityRule } from '../types.js';
23
+ /**
24
+ * The Memory primitive has a fixed canonical artifact set, not user-named
25
+ * instances like Skill/Hook. listInstances() returns the artifact paths so the
26
+ * sentinel can iterate verify() over each, but verify() is also defined to
27
+ * accept any artifact path and return ok:true if it's not in the known set
28
+ * (defensive: sentinel might call with stale names after a config change).
29
+ */
30
+ export declare const memoryParityRule: ParityRule;
31
+ //# sourceMappingURL=memoryParityRule.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"memoryParityRule.d.ts","sourceRoot":"","sources":["../../../../src/providers/parity/rules/memoryParityRule.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAMH,OAAO,KAAK,EACV,UAAU,EAGX,MAAM,aAAa,CAAC;AAiLrB;;;;;;GAMG;AACH,eAAO,MAAM,gBAAgB,EAAE,UAmD9B,CAAC"}
@@ -0,0 +1,198 @@
1
+ /**
2
+ * memoryParityRule — parity rule for the Memory functional primitive.
3
+ *
4
+ * Specs:
5
+ * - specs/instar-concepts/memory.md (canonical shape)
6
+ * - specs/frameworks/claude-code/memory.md
7
+ * - specs/frameworks/codex-cli/memory.md
8
+ *
9
+ * Memory is substrate-bound: the canonical artifacts (`.instar/AGENT.md`,
10
+ * `.instar/USER.md`, `.instar/MEMORY.md`, `.instar/state/topic-memory.sqlite`)
11
+ * are framework-agnostic files on disk. This rule's verify() confirms each
12
+ * required artifact is present, non-empty, and (for markdown) parses cleanly.
13
+ *
14
+ * v0.1 deliberately does NOT auto-remediate. Memory contains agent identity
15
+ * and accumulated learnings — silent regeneration would erase intentional
16
+ * drift. remediate() throws with a structured detail pointing to the documented
17
+ * repair procedure.
18
+ *
19
+ * Loading canonical Memory into framework system-prompts (CLAUDE.md / AGENTS.md
20
+ * references) is the InstructionFile primitive's responsibility — separate.
21
+ */
22
+ import { promises as fs } from 'node:fs';
23
+ import path from 'node:path';
24
+ import yaml from 'js-yaml';
25
+ const ARTIFACTS = [
26
+ {
27
+ relPath: '.instar/AGENT.md',
28
+ kind: 'markdown',
29
+ required: true,
30
+ label: 'agent identity',
31
+ },
32
+ {
33
+ relPath: '.instar/USER.md',
34
+ kind: 'markdown',
35
+ required: true,
36
+ label: 'user profile',
37
+ },
38
+ {
39
+ relPath: '.instar/MEMORY.md',
40
+ kind: 'markdown',
41
+ required: true,
42
+ label: 'persistent learnings',
43
+ },
44
+ {
45
+ relPath: '.instar/state/topic-memory.sqlite',
46
+ kind: 'sqlite',
47
+ required: false,
48
+ label: 'topic memory store',
49
+ },
50
+ ];
51
+ const SQLITE_MAGIC = 'SQLite format 3\0';
52
+ class CanonicalMemoryError extends Error {
53
+ artifact;
54
+ reasonCode;
55
+ constructor(artifact, reasonCode, message) {
56
+ super(message);
57
+ this.name = 'CanonicalMemoryError';
58
+ this.artifact = artifact;
59
+ this.reasonCode = reasonCode;
60
+ }
61
+ }
62
+ async function pathExists(p) {
63
+ try {
64
+ await fs.access(p);
65
+ return true;
66
+ }
67
+ catch {
68
+ return false;
69
+ }
70
+ }
71
+ async function verifyMarkdownArtifact(absPath, artifact) {
72
+ let raw;
73
+ try {
74
+ raw = await fs.readFile(absPath, 'utf-8');
75
+ }
76
+ catch (err) {
77
+ throw new CanonicalMemoryError(artifact.relPath, 'canonical-read-error', `cannot read ${artifact.label} at ${artifact.relPath}: ${err.message}`);
78
+ }
79
+ if (raw.trim().length === 0) {
80
+ throw new CanonicalMemoryError(artifact.relPath, 'canonical-read-error', `${artifact.label} at ${artifact.relPath} is empty — repair required`);
81
+ }
82
+ // Optional frontmatter — if it starts with `---`, parse it. If it doesn't,
83
+ // that's fine (USER.md / MEMORY.md often have no frontmatter).
84
+ if (raw.startsWith('---\n')) {
85
+ const close = raw.indexOf('\n---', 4);
86
+ if (close < 0) {
87
+ throw new CanonicalMemoryError(artifact.relPath, 'canonical-read-error', `${artifact.label} at ${artifact.relPath} has unterminated frontmatter`);
88
+ }
89
+ const fm = raw.slice(4, close);
90
+ try {
91
+ yaml.load(fm, { schema: yaml.FAILSAFE_SCHEMA, json: false });
92
+ }
93
+ catch (err) {
94
+ throw new CanonicalMemoryError(artifact.relPath, 'canonical-read-error', `${artifact.label} at ${artifact.relPath}: YAML frontmatter parse error: ${err.message}`);
95
+ }
96
+ }
97
+ }
98
+ async function verifySqliteArtifact(absPath, artifact) {
99
+ let fh;
100
+ try {
101
+ fh = await fs.open(absPath, 'r');
102
+ }
103
+ catch (err) {
104
+ throw new CanonicalMemoryError(artifact.relPath, 'canonical-read-error', `cannot open ${artifact.label} at ${artifact.relPath}: ${err.message}`);
105
+ }
106
+ try {
107
+ const buf = Buffer.alloc(SQLITE_MAGIC.length);
108
+ const { bytesRead } = await fh.read(buf, 0, buf.length, 0);
109
+ if (bytesRead < buf.length || buf.toString('binary') !== SQLITE_MAGIC) {
110
+ throw new CanonicalMemoryError(artifact.relPath, 'canonical-read-error', `${artifact.label} at ${artifact.relPath} is not a valid SQLite file (magic bytes mismatch)`);
111
+ }
112
+ }
113
+ finally {
114
+ await fh.close();
115
+ }
116
+ }
117
+ async function verifyArtifact(projectRoot, artifact) {
118
+ const abs = path.join(projectRoot, artifact.relPath);
119
+ const exists = await pathExists(abs);
120
+ if (!exists) {
121
+ if (!artifact.required)
122
+ return null;
123
+ return {
124
+ primitive: 'memory',
125
+ instanceName: artifact.relPath,
126
+ framework: 'canonical',
127
+ reasonCode: 'canonical-read-error',
128
+ detail: `${artifact.label} at ${artifact.relPath} is missing — required artifact for the Memory primitive`,
129
+ };
130
+ }
131
+ try {
132
+ if (artifact.kind === 'markdown') {
133
+ await verifyMarkdownArtifact(abs, artifact);
134
+ }
135
+ else {
136
+ await verifySqliteArtifact(abs, artifact);
137
+ }
138
+ }
139
+ catch (err) {
140
+ if (err instanceof CanonicalMemoryError) {
141
+ return {
142
+ primitive: 'memory',
143
+ instanceName: artifact.relPath,
144
+ framework: 'canonical',
145
+ reasonCode: err.reasonCode,
146
+ detail: err.message,
147
+ };
148
+ }
149
+ throw err;
150
+ }
151
+ return null;
152
+ }
153
+ /**
154
+ * The Memory primitive has a fixed canonical artifact set, not user-named
155
+ * instances like Skill/Hook. listInstances() returns the artifact paths so the
156
+ * sentinel can iterate verify() over each, but verify() is also defined to
157
+ * accept any artifact path and return ok:true if it's not in the known set
158
+ * (defensive: sentinel might call with stale names after a config change).
159
+ */
160
+ export const memoryParityRule = {
161
+ primitive: 'memory',
162
+ // Memory is framework-agnostic — the verifier ignores framework, but we
163
+ // declare both so the sentinel includes Memory in every framework's matrix
164
+ // cell and surfaces drift consistently.
165
+ frameworks: ['claude-code', 'codex-cli'],
166
+ remediationPolicy: 'flag-only',
167
+ async verify(projectRoot, instanceName) {
168
+ const artifact = ARTIFACTS.find((a) => a.relPath === instanceName);
169
+ if (!artifact) {
170
+ return { ok: true, mismatches: [] };
171
+ }
172
+ const mismatch = await verifyArtifact(projectRoot, artifact);
173
+ return mismatch
174
+ ? { ok: false, mismatches: [mismatch] }
175
+ : { ok: true, mismatches: [] };
176
+ },
177
+ async listInstances(_projectRoot) {
178
+ return ARTIFACTS.map((a) => a.relPath);
179
+ },
180
+ async remediate(_projectRoot, instanceName, _framework) {
181
+ const artifact = ARTIFACTS.find((a) => a.relPath === instanceName);
182
+ const label = artifact?.label ?? instanceName;
183
+ throw new Error(`memory primitive: refused to remediate ${instanceName} (${label}) — ` +
184
+ `Memory artifacts are user/agent-authored and never auto-regenerated. ` +
185
+ `Repair procedure: AGENT.md/USER.md → re-init via \`instar init\`; ` +
186
+ `MEMORY.md → restore from git history or backup; ` +
187
+ `topic-memory.sqlite → restore from backup. ` +
188
+ `See specs/instar-concepts/memory.md for full procedure.`);
189
+ },
190
+ async listOrphans(_projectRoot) {
191
+ // No rendering callsites in v0.1; no orphans possible.
192
+ return [];
193
+ },
194
+ async removeOrphans(_projectRoot, _framework) {
195
+ return [];
196
+ },
197
+ };
198
+ //# sourceMappingURL=memoryParityRule.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"memoryParityRule.js","sourceRoot":"","sources":["../../../../src/providers/parity/rules/memoryParityRule.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,43 @@
1
+ /**
2
+ * toolNameMapping — canonical tool-name vocabulary + per-framework mapping.
3
+ *
4
+ * Specs:
5
+ * - specs/instar-concepts/tool.md
6
+ * - specs/frameworks/claude-code/tools.md
7
+ * - specs/frameworks/codex-cli/tools.md
8
+ *
9
+ * Consumed by other Layer-3 primitives' renderers when they need to map
10
+ * a canonical `allowed-tools` list to framework-native tool names.
11
+ *
12
+ * v0.1: ships the table + lookup helpers. The Skill primitive's `allowed-tools`
13
+ * rendering (the C3 deferral from Skill convergence) wires in next.
14
+ */
15
+ import type { IntelligenceFramework } from '../../core/intelligenceProviderFactory.js';
16
+ export interface ToolNameEntry {
17
+ canonical: string;
18
+ claude: string;
19
+ codex: string;
20
+ }
21
+ export declare const TOOL_NAME_MAPPING: ReadonlyArray<ToolNameEntry>;
22
+ /**
23
+ * Translate one canonical tool name into its framework-native form.
24
+ *
25
+ * Returns null if the canonical name is unknown. Callers should treat null
26
+ * as a hard error (don't silently drop tool restrictions — that widens the
27
+ * permission surface).
28
+ */
29
+ export declare function renderCanonicalToolName(canonical: string, framework: IntelligenceFramework): string | null;
30
+ /**
31
+ * Translate an array of canonical tool names. Returns a parallel array where
32
+ * each element is either the framework-native name or null (for unknown).
33
+ * Useful in renderers that want to surface unknowns to the operator.
34
+ */
35
+ export declare function renderCanonicalToolList(canonicals: ReadonlyArray<string>, framework: IntelligenceFramework): Array<{
36
+ canonical: string;
37
+ native: string | null;
38
+ }>;
39
+ /**
40
+ * List all known canonical tool names (for documentation + validation).
41
+ */
42
+ export declare function listCanonicalToolNames(): ReadonlyArray<string>;
43
+ //# sourceMappingURL=toolNameMapping.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"toolNameMapping.d.ts","sourceRoot":"","sources":["../../../src/providers/parity/toolNameMapping.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,2CAA2C,CAAC;AAEvF,MAAM,WAAW,aAAa;IAC5B,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;CACf;AAED,eAAO,MAAM,iBAAiB,EAAE,aAAa,CAAC,aAAa,CAa1D,CAAC;AAQF;;;;;;GAMG;AACH,wBAAgB,uBAAuB,CACrC,SAAS,EAAE,MAAM,EACjB,SAAS,EAAE,qBAAqB,GAC/B,MAAM,GAAG,IAAI,CAWf;AAED;;;;GAIG;AACH,wBAAgB,uBAAuB,CACrC,UAAU,EAAE,aAAa,CAAC,MAAM,CAAC,EACjC,SAAS,EAAE,qBAAqB,GAC/B,KAAK,CAAC;IAAE,SAAS,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAA;CAAE,CAAC,CAErD;AAED;;GAEG;AACH,wBAAgB,sBAAsB,IAAI,aAAa,CAAC,MAAM,CAAC,CAE9D"}
@@ -0,0 +1,65 @@
1
+ /**
2
+ * toolNameMapping — canonical tool-name vocabulary + per-framework mapping.
3
+ *
4
+ * Specs:
5
+ * - specs/instar-concepts/tool.md
6
+ * - specs/frameworks/claude-code/tools.md
7
+ * - specs/frameworks/codex-cli/tools.md
8
+ *
9
+ * Consumed by other Layer-3 primitives' renderers when they need to map
10
+ * a canonical `allowed-tools` list to framework-native tool names.
11
+ *
12
+ * v0.1: ships the table + lookup helpers. The Skill primitive's `allowed-tools`
13
+ * rendering (the C3 deferral from Skill convergence) wires in next.
14
+ */
15
+ export const TOOL_NAME_MAPPING = [
16
+ { canonical: 'read', claude: 'Read', codex: 'view' },
17
+ { canonical: 'edit', claude: 'Edit', codex: 'apply_patch' },
18
+ { canonical: 'write', claude: 'Write', codex: 'apply_patch' },
19
+ { canonical: 'multi-edit', claude: 'MultiEdit', codex: 'apply_patch' },
20
+ { canonical: 'bash', claude: 'Bash', codex: 'shell' },
21
+ { canonical: 'grep', claude: 'Grep', codex: 'grep' },
22
+ { canonical: 'glob', claude: 'Glob', codex: 'glob' },
23
+ { canonical: 'web-fetch', claude: 'WebFetch', codex: 'read_url' },
24
+ { canonical: 'web-search', claude: 'WebSearch', codex: 'web_search' },
25
+ { canonical: 'task', claude: 'Task', codex: 'multi_agent' },
26
+ { canonical: 'todo-write', claude: 'TodoWrite', codex: 'todo_write' },
27
+ { canonical: 'notebook-edit', claude: 'NotebookEdit', codex: 'notebook_edit' },
28
+ ];
29
+ const CANONICAL_INDEX = new Map(TOOL_NAME_MAPPING.map((e) => [e.canonical, e]));
30
+ const MCP_CANONICAL_RE = /^mcp:([a-z0-9][a-z0-9-]*):([a-z0-9][a-z0-9_-]*)$/i;
31
+ /**
32
+ * Translate one canonical tool name into its framework-native form.
33
+ *
34
+ * Returns null if the canonical name is unknown. Callers should treat null
35
+ * as a hard error (don't silently drop tool restrictions — that widens the
36
+ * permission surface).
37
+ */
38
+ export function renderCanonicalToolName(canonical, framework) {
39
+ const mcp = canonical.match(MCP_CANONICAL_RE);
40
+ if (mcp) {
41
+ const [, server, tool] = mcp;
42
+ return framework === 'claude-code'
43
+ ? `mcp__${server}__${tool}`
44
+ : `mcp.${server}.${tool}`;
45
+ }
46
+ const entry = CANONICAL_INDEX.get(canonical);
47
+ if (!entry)
48
+ return null;
49
+ return framework === 'claude-code' ? entry.claude : entry.codex;
50
+ }
51
+ /**
52
+ * Translate an array of canonical tool names. Returns a parallel array where
53
+ * each element is either the framework-native name or null (for unknown).
54
+ * Useful in renderers that want to surface unknowns to the operator.
55
+ */
56
+ export function renderCanonicalToolList(canonicals, framework) {
57
+ return canonicals.map((c) => ({ canonical: c, native: renderCanonicalToolName(c, framework) }));
58
+ }
59
+ /**
60
+ * List all known canonical tool names (for documentation + validation).
61
+ */
62
+ export function listCanonicalToolNames() {
63
+ return TOOL_NAME_MAPPING.map((e) => e.canonical);
64
+ }
65
+ //# sourceMappingURL=toolNameMapping.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"toolNameMapping.js","sourceRoot":"","sources":["../../../src/providers/parity/toolNameMapping.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAUH,MAAM,CAAC,MAAM,iBAAiB,GAAiC;IAC7D,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE;IACpD,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,aAAa,EAAE;IAC3D,EAAE,SAAS,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,KAAK,EAAE,aAAa,EAAE;IAC7D,EAAE,SAAS,EAAE,YAAY,EAAE,MAAM,EAAE,WAAW,EAAE,KAAK,EAAE,aAAa,EAAE;IACtE,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,EAAE;IACrD,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE;IACpD,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE;IACpD,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,EAAE,UAAU,EAAE,KAAK,EAAE,UAAU,EAAE;IACjE,EAAE,SAAS,EAAE,YAAY,EAAE,MAAM,EAAE,WAAW,EAAE,KAAK,EAAE,YAAY,EAAE;IACrE,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,aAAa,EAAE;IAC3D,EAAE,SAAS,EAAE,YAAY,EAAE,MAAM,EAAE,WAAW,EAAE,KAAK,EAAE,YAAY,EAAE;IACrE,EAAE,SAAS,EAAE,eAAe,EAAE,MAAM,EAAE,cAAc,EAAE,KAAK,EAAE,eAAe,EAAE;CAC/E,CAAC;AAEF,MAAM,eAAe,GAAG,IAAI,GAAG,CAC7B,iBAAiB,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,SAAS,EAAE,CAAC,CAAC,CAAC,CAC/C,CAAC;AAEF,MAAM,gBAAgB,GAAG,mDAAmD,CAAC;AAE7E;;;;;;GAMG;AACH,MAAM,UAAU,uBAAuB,CACrC,SAAiB,EACjB,SAAgC;IAEhC,MAAM,GAAG,GAAG,SAAS,CAAC,KAAK,CAAC,gBAAgB,CAAC,CAAC;IAC9C,IAAI,GAAG,EAAE,CAAC;QACR,MAAM,CAAC,EAAE,MAAM,EAAE,IAAI,CAAC,GAAG,GAAG,CAAC;QAC7B,OAAO,SAAS,KAAK,aAAa;YAChC,CAAC,CAAC,QAAQ,MAAM,KAAK,IAAI,EAAE;YAC3B,CAAC,CAAC,OAAO,MAAM,IAAI,IAAI,EAAE,CAAC;IAC9B,CAAC;IACD,MAAM,KAAK,GAAG,eAAe,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;IAC7C,IAAI,CAAC,KAAK;QAAE,OAAO,IAAI,CAAC;IACxB,OAAO,SAAS,KAAK,aAAa,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC;AAClE,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,uBAAuB,CACrC,UAAiC,EACjC,SAAgC;IAEhC,OAAO,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,SAAS,EAAE,CAAC,EAAE,MAAM,EAAE,uBAAuB,CAAC,CAAC,EAAE,SAAS,CAAC,EAAE,CAAC,CAAC,CAAC;AAClG,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,sBAAsB;IACpC,OAAO,iBAAiB,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC;AACnD,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "instar",
3
- "version": "0.28.117",
3
+ "version": "0.28.119",
4
4
  "description": "Persistent autonomy infrastructure for AI agents",
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-19T01:38:36.605Z",
5
- "instarVersion": "0.28.117",
4
+ "generatedAt": "2026-05-19T02:38:16.455Z",
5
+ "instarVersion": "0.28.119",
6
6
  "entryCount": 189,
7
7
  "entries": {
8
8
  "hook:session-start": {
@@ -0,0 +1,35 @@
1
+ # Upgrade Guide — v1.0.4
2
+
3
+ <!-- bump: patch -->
4
+
5
+ ## What Changed
6
+
7
+ Lands the remaining three Layer-3 functional primitives from the framework-functional-parity rollout: **Agent**, **Tool**, and **Memory**. Batched into a single PR because each ships a relatively small surface (concept spec + framework specs + small code artifact) and they share the same conceptual frame (canonical-source-of-truth + per-framework rendering).
8
+
9
+ **Agent primitive (v0.1):** concept spec + ELI16 + per-framework specs. No parity rule yet — pending Codex subagent surface research. The current Claude implementation pattern (.claude/agents/<name>.md) is documented but not yet wired to a canonical source. Tracked as a v0.2 follow-up; ships now to lock the cross-framework contract.
10
+
11
+ **Tool primitive (v0.1):** concept spec + ELI16 + per-framework specs + TOOL_NAME_MAPPING table as code (src/providers/parity/toolNameMapping.ts). Provides the canonical tool-name vocabulary (read, bash, web-fetch, mcp:server:tool) and helpers (renderCanonicalToolName, renderCanonicalToolList) that other primitives' renderers will consume when wiring allowed-tools fields. The C3 deferral from Skill convergence (Claude allowed-tools frontmatter + Codex dependencies.tools rendering) unblocks here — but the wiring itself happens when Skill v0.2 lands.
12
+
13
+ **Memory primitive (v0.1):** concept spec + ELI16 + per-framework specs + memoryParityRule (verifier-only). Confirms canonical Memory artifacts (.instar/AGENT.md, .instar/USER.md, .instar/MEMORY.md, .instar/state/topic-memory.sqlite) are present, non-empty, and well-formed. Deliberately does NOT auto-remediate — Memory contains agent identity and accumulated learnings, so silent regeneration would erase intentional drift. Corruption is loudly surfaced, repair is human-authorized. Loading canonical Memory into framework system-prompts (CLAUDE.md / AGENTS.md references) is the InstructionFile primitive's responsibility (next, separate spec).
14
+
15
+ Registry now exposes three rules: skill, hook, memory. Agent + Tool deliberately have no registry entry yet (Agent: rule pending; Tool: substrate-bound, ships as code-importable mapping rather than as a per-instance rule).
16
+
17
+ ## What to Tell Your User
18
+
19
+ - "Three more functional primitives now have their canonical contracts in place: Agent (the spec is locked; the parity rule comes after Codex subagent research), Tool (a canonical vocabulary of names like read, bash, web-fetch that maps to each framework's native naming), and Memory (a verifier that confirms your AGENT.md, USER.md, and MEMORY.md files in the instar folder are present and well-formed)."
20
+ - "Memory verification is deliberately non-destructive — if it detects corruption, you'll get a clear repair pointer instead of an auto-overwrite that could wipe your identity drift."
21
+
22
+ ## Summary of New Capabilities
23
+
24
+ | Capability | How to Use |
25
+ |-----------|-----------|
26
+ | Canonical tool-name vocabulary | Import renderCanonicalToolName or renderCanonicalToolList from src/providers/parity/toolNameMapping.js to translate canonical names into framework-native form. |
27
+ | Memory parity rule (programmatic) | Available via the parity registry — getParityRule('memory'). Verifier-only in v0.1; no auto-fix. |
28
+ | Agent + Tool + Memory concept specs | Read specs/instar-concepts/{agent,tool,memory}.md (+ .eli16.md companions) for the cross-framework contracts. |
29
+
30
+ ## Deferred (Tracked Follow-ups)
31
+
32
+ - Agent parity rule (pending Codex subagent surface research).
33
+ - Tool: wire TOOL_NAME_MAPPING into Skill v0.2's allowed-tools rendering (resolves the C3 deferral from Skill convergence).
34
+ - Memory: schema validation beyond YAML-parse + body-non-empty (e.g. AGENT.md required identity sections).
35
+ - InstructionFile primitive — the loading-vehicle for canonical Memory into framework system-prompts. Separate spec, next.
@@ -0,0 +1,37 @@
1
+ # Upgrade Guide — v1.0.5
2
+
3
+ <!-- bump: patch -->
4
+
5
+ ## What Changed
6
+
7
+ Lands the FrameworkParitySentinel — the class that walks the Layer-3 parity rules registry (Skill / Hook / Memory), runs each rule's verify() per instance, and routes drift to events (or to remediation, per the rule's declared policy).
8
+
9
+ v0.1 ships the sentinel as a building block — class + 12 unit tests. HTTP routes (GET /api/framework-parity/status, POST /api/framework-parity/scan) and server.ts boot integration are deferred to a focused follow-up PR. This matches the precedent set by Skill / Hook / Memory parity rules: each shipped as a registry building block first, with operational wiring as a separate step.
10
+
11
+ Key safety locks: per-rule remediationPolicy is the authority (flag-only never auto-remediates; mirror-trust does); the sentinel-level remediationEnabled config can DOWNGRADE mirror-trust to flag-only but never UPGRADE flag-only. Memory's sacrosanct status is preserved unconditionally. Concurrent scan calls short-circuit to prevent pileup. User-edit-conflict refuses remediation and emits a structured event.
12
+
13
+ Five new events: parity:gap-found, parity:remediated, parity:remediation-refused, parity:orphan-found, parity:scan-complete. Persistent state at .instar/state/framework-parity-sentinel.json with per (primitive × instance) cursors.
14
+
15
+ Spec at specs/instar-foundations/framework-parity-sentinel.md (converged + approved). ELI16 companion + convergence report alongside. Original 2026-05-18 proposal at specs/provider-portability/13-framework-parity-sentinel.md is now superseded — left in place for historical reference, frontmatter unchanged.
16
+
17
+ ## What to Tell Your User
18
+
19
+ - "The piece that runs the cross-framework drift checks is now built. It walks the parity rules every 30 minutes (when wired into the server, coming next), spots when your canonical files have drifted from their rendered forms on Claude or Codex, and either re-renders or flags the drift for you — based on the rule's safety policy."
20
+ - "Memory stays sacrosanct: the sentinel will never auto-regenerate your AGENT.md, USER.md, or MEMORY.md. If they're corrupted, you get a structured alert pointing at the repair procedure."
21
+
22
+ ## Summary of New Capabilities
23
+
24
+ | Capability | How to Use |
25
+ |-----------|-----------|
26
+ | FrameworkParitySentinel class | Import from src/monitoring/FrameworkParitySentinel.js. Construct with projectRoot + stateDir + enabledFrameworks. Call scan() for one pass or start() for interval mode. |
27
+ | Per-instance scan cursors | sentinel.getStatus() returns the per (primitive × instance) cursor state — used by the upcoming HTTP route. |
28
+ | Five EventEmitter events | parity:gap-found, parity:remediated, parity:remediation-refused, parity:orphan-found, parity:scan-complete. |
29
+
30
+ ## Deferred (Tracked Follow-ups)
31
+
32
+ - HTTP routes (GET /api/framework-parity/status, POST /api/framework-parity/scan).
33
+ - server.ts boot integration (construction + start + RouteContext wiring).
34
+ - Integration + E2E tests (land with the HTTP wiring).
35
+ - chokidar source-change watcher (v0.2).
36
+ - Per-instance POST /api/framework-parity/remediate route (v0.2 — pending trust integration).
37
+ - Conversational-action layer wiring (Step 6 of the rollout).
@@ -0,0 +1,94 @@
1
+ # Side-Effects Review — FrameworkParitySentinel v0.1 (building block)
2
+
3
+ **Version / slug:** `feat-framework-parity-sentinel`
4
+ **Date:** 2026-05-19
5
+ **Author:** Echo (autonomous mode, hybrid C)
6
+
7
+ ## Summary of the change
8
+
9
+ Lands the FrameworkParitySentinel as a **building block** — the class that walks the Layer-3 parity rules registry, calls each rule's `verify()` per instance, surfaces drift via events, and (per rule's `remediationPolicy`) optionally calls `remediate()`. Ships with unit tests and structured spec docs.
10
+
11
+ **Deliberately scoped narrow:** HTTP routes (`GET /api/framework-parity/status`, `POST /api/framework-parity/scan`) and server.ts boot integration are deferred to a follow-up PR. This matches the precedent set by Skill/Hook/Memory parity rules in PRs #252/#253/#254 — each shipped as a building block via the parity registry, with boot integration as a separate step. Shipping the sentinel class now unblocks the registry consumer side; the follow-up wires it into the server lifecycle.
12
+
13
+ **Files changed (specs):**
14
+ - specs/instar-foundations/framework-parity-sentinel.md (new, converged + approved per pre-auth)
15
+ - specs/instar-foundations/framework-parity-sentinel.eli16.md (new)
16
+ - docs/specs/reports/framework-parity-sentinel-convergence.md (new)
17
+
18
+ **Files changed (source):**
19
+ - src/monitoring/FrameworkParitySentinel.ts (new — class + lifecycle + scan + state I/O + EventEmitter)
20
+
21
+ **Files changed (tests):**
22
+ - tests/unit/monitoring/FrameworkParitySentinel.test.ts (new — 12 tests)
23
+
24
+ **Files changed (release notes):**
25
+ - upgrades/NEXT.md (new)
26
+ - package.json (version bump)
27
+
28
+ ## Decision-point inventory
29
+
30
+ - **Building-block scope**: ships the class + unit tests; HTTP routes + boot wiring as a follow-up. Matches PR #252/#253/#254 precedent.
31
+ - **Scan cadence default**: 30 min (1_800_000 ms). Configurable.
32
+ - **Initial scan delay**: 60s (allows server to settle before first pass).
33
+ - **Concurrent-scan short-circuit**: second concurrent `scan()` call returns an empty report; prevents pileup on slow rules.
34
+ - **Remediation gating**: per-rule `remediationPolicy` is the authority. Sentinel-level `remediationEnabled` config can DOWNGRADE mirror-trust to flag-only but never UPGRADE flag-only to mirror-trust.
35
+ - **State schema**: `cursors[primitive::instance]` with `lastScanAt`, `lastResult`, `lastDetail`, `unresolvedCount`. Atomic writes via tempfile+rename.
36
+ - **Degradation threshold**: 3 consecutive scans with unresolved drift trips a `DegradationReporter.report()`.
37
+ - **Canonical-side mismatches are signal-only**: when `verify()` returns `framework: 'canonical'` (e.g. missing AGENT.md), the sentinel emits `parity:gap-found` but does NOT call `remediate()` — only the rule can mutate canonical, and Memory's rule throws by design.
38
+ - **Event vocabulary**: `parity:gap-found`, `parity:remediated`, `parity:remediation-refused`, `parity:orphan-found`, `parity:scan-complete`.
39
+ - **Orphan removal is opt-in**: `listOrphans()` always runs; `removeOrphans()` requires explicit operator action (no auto-fire in v0.1).
40
+
41
+ ## Over-block / under-block analysis
42
+
43
+ **Over-block risk:** the sentinel never blocks operations — it scans + emits + (optionally) re-renders. Worst case is a noisy event stream, filterable at the EventEmitter consumer.
44
+
45
+ **Under-block risk:** if a rule's `verify()` throws, the sentinel marks that rule failed (via DegradationReporter) and continues with other rules. The failed rule's instances stay at their prior cursor state — drift may persist longer than 30 min until the rule's verify recovers. Mitigated by Degradation reporting (3-consecutive-failure trip) so operators are notified.
46
+
47
+ **Under-block risk (concurrent scan):** the short-circuit returns an empty report. If a user POSTs `/scan` while an interval scan is in flight (when routes ship), they get back empty + the interval scan continues. Acceptable for v0.1 — adding queue/wait complicates state.
48
+
49
+ ## Level-of-abstraction fit
50
+
51
+ - Sentinel is the orchestrator. It owns scan timing, state, event emission. Routes/wiring are NOT in v0.1.
52
+ - Rules own canonical definitions, rendering, verification, remediation.
53
+ - Boundary is clean — sentinel never reads canonical formats directly, never knows what a "skill" or "hook" is. Just the registry interface.
54
+
55
+ ## Signal-vs-authority compliance
56
+
57
+ - Sentinel emits signals (`parity:gap-found`). Rules' `remediationPolicy` and sentinel's `remediationEnabled` are the layered authority.
58
+ - Sentinel never overrides a rule's `flag-only` policy (cannot upgrade).
59
+ - Sentinel respects `user-edit-conflict` by short-circuiting remediation and emitting `parity:remediation-refused`.
60
+
61
+ ## Interaction surface
62
+
63
+ - Adds one new class under `src/monitoring/`. No HTTP routes, no server.ts wiring, no config additions in v0.1.
64
+ - Optional state file at `.instar/state/framework-parity-sentinel.json` — only written when `scan()` is called. Cold-start safe.
65
+ - No changes to existing rules, registries, or per-primitive infrastructure.
66
+ - No migrations needed (cold-start is a no-op until the follow-up wires it in).
67
+
68
+ ## Rollback cost
69
+
70
+ - Pure-add. Revert removes the sentinel + tests + spec + state file. No data migrations.
71
+ - Worst-case bug: spurious remediation on healthy artifacts when the follow-up wires it. Mitigated by user-edit-conflict short-circuit + per-rule policy + future `remediationEnabled` kill-switch.
72
+ - Operator emergency (post-follow-up): set `frameworkParity.remediationEnabled: false` in `.instar/config.json` and restart — sentinel becomes signal-only.
73
+
74
+ ## Test coverage
75
+
76
+ - Unit: 12 tests covering rule walking, event emission for all 5 events, remediation policy routing (mirror-trust + flag-only + user-edit-conflict + config override), concurrent-scan short-circuit, state persistence round-trip, start/stop lifecycle idempotency.
77
+ - Integration + E2E: deferred to the follow-up PR that wires HTTP routes — matches PR #252/#253/#254 precedent (the parity rules in those PRs also shipped unit-tests-only as building blocks).
78
+
79
+ ## Documentation
80
+
81
+ - Concept spec + ELI16 at `specs/instar-foundations/`.
82
+ - Convergence report at `docs/specs/reports/`.
83
+ - NEXT.md with "What to Tell Your User" entries.
84
+
85
+ ## Deferred (tracked, not silent)
86
+
87
+ - **HTTP routes** (`GET /api/framework-parity/status`, `POST /api/framework-parity/scan`) — follow-up PR.
88
+ - **server.ts boot integration** (construction + start + RouteContext wiring) — follow-up PR.
89
+ - **Integration + E2E tests** — land with the HTTP wiring.
90
+ - **chokidar source-change watcher** — v0.2.
91
+ - **POST /api/framework-parity/remediate per-instance route** — v0.2 (pending trust integration).
92
+ - **Trust-level integration** for mirror-trust gating (v0.2 — hardcodes allow for v0.1).
93
+ - **Backfill migration** of existing-agent installed base (separate one-shot tool).
94
+ - **Conversational-action layer** (Step 6 of the rollout).
@@ -0,0 +1,105 @@
1
+ # Side-Effects Review — Agent + Tool + Memory primitives (batched)
2
+
3
+ **Version / slug:** `feat-primitives-batch`
4
+ **Date:** 2026-05-19
5
+ **Author:** Echo (autonomous mode, hybrid C)
6
+
7
+ ## Summary of the change
8
+
9
+ Lands the remaining three Layer-3 functional primitive specs from the framework-functional-parity rollout as one batched PR: **Agent**, **Tool**, **Memory**. Each ships a small surface (concept spec + framework specs + small code artifact where applicable) and they share the same conceptual frame, so batching avoids three near-identical PR review cycles.
10
+
11
+ **Files changed (specs):**
12
+ - specs/instar-concepts/agent.md (new, converged + approved per pre-auth)
13
+ - specs/instar-concepts/agent.eli16.md (new)
14
+ - specs/instar-concepts/tool.md (new, converged + approved per pre-auth)
15
+ - specs/instar-concepts/tool.eli16.md (new)
16
+ - specs/instar-concepts/memory.md (new, converged + approved per pre-auth)
17
+ - specs/instar-concepts/memory.eli16.md (new)
18
+ - specs/frameworks/claude-code/agents.md (new)
19
+ - specs/frameworks/claude-code/tools.md (new)
20
+ - specs/frameworks/claude-code/memory.md (new)
21
+ - specs/frameworks/codex-cli/agents.md (new)
22
+ - specs/frameworks/codex-cli/tools.md (new)
23
+ - specs/frameworks/codex-cli/memory.md (new)
24
+ - docs/specs/reports/agent-concept-convergence.md (new)
25
+ - docs/specs/reports/tool-concept-convergence.md (new)
26
+ - docs/specs/reports/memory-concept-convergence.md (new)
27
+
28
+ **Files changed (source):**
29
+ - src/providers/parity/toolNameMapping.ts (new — TOOL_NAME_MAPPING table + renderers)
30
+ - src/providers/parity/rules/memoryParityRule.ts (new — verifier-only)
31
+ - src/providers/parity/registry.ts (memoryParityRule registered)
32
+
33
+ **Files changed (tests):**
34
+ - tests/unit/providers/parity/toolNameMapping.test.ts (new — 21 tests)
35
+ - tests/unit/providers/parity/memoryParityRule.test.ts (new — 18 tests)
36
+ - tests/unit/providers/parity/registry.test.ts (updated for 3-rule registry)
37
+
38
+ **Files changed (release notes):**
39
+ - upgrades/NEXT.md (rewritten for v1.0.4)
40
+ - package.json (version bump 1.0.3 → 1.0.4)
41
+
42
+ ## Decision-point inventory
43
+
44
+ - **Batching three primitives in one PR**: justified by shared frame + small surfaces; each gets its own concept spec + ELI16 + framework specs + convergence report, so review traceability per primitive is preserved.
45
+ - **Agent primitive ships without a parity rule**: deliberate — Codex subagent surface (whether/how subagent spawning is exposed) needs live research. Spec ships now to lock the cross-framework contract; rule lands when research completes. Tracked in spec's "v0.1 deferred items" section.
46
+ - **Tool primitive ships TOOL_NAME_MAPPING as code, not as a per-instance rule**: Tools are framework-provided, not user-authored. The "instance" of a Tool isn't something to render; the cross-framework concern is the vocabulary, which lives in a shared mapping table. No registry entry — other primitives' renderers import the helpers directly.
47
+ - **Memory primitive uses flag-only remediation policy**: Memory contains agent identity + learnings. Silent regeneration would erase intentional drift. remediate() throws with a documented repair procedure; corruption surfaces loudly via verify().
48
+ - **SQLite verification depth**: v0.1 checks magic bytes only (cheap, fail-loud). Full schema validation deferred — the topic-memory.sqlite schema is owned by its own substrate primitive.
49
+ - **Memory artifact set is fixed at four**: AGENT.md, USER.md, MEMORY.md (required); topic-memory.sqlite (optional). Other `.instar/` files (config.json, jobs.json, state/*) are NOT Memory — they belong to other primitives (Config, Job, State).
50
+ - **MCP canonical syntax `mcp:server:tool`**: matches the spec convention. Renders to `mcp__server__tool` (Claude) / `mcp.server.tool` (Codex).
51
+
52
+ ## Over-block / under-block analysis
53
+
54
+ **Over-block risk (Tool):** if a canonical tool name isn't in TOOL_NAME_MAPPING, `renderCanonicalToolName` returns null. Callers are documented to treat this as a hard error (don't silently drop, that widens the permission surface). v0.1 has no callers yet; risk surfaces when Skill v0.2 wires `allowed-tools`.
55
+
56
+ **Under-block risk (Memory):** the verifier checks presence + parseability, not semantic correctness. A syntactically-valid but content-wrong AGENT.md (e.g. missing the identity section) passes verify in v0.1. Acceptable for v0.1 — schema validation deferred. Under-block is loud (logged at sentinel scan time) rather than silent.
57
+
58
+ **Over-block risk (Memory remediate):** remediate always throws. If a future caller expects auto-fix as the default, this throws instead. Behavior is documented in the spec + in the rule's docstring + in the convergence report. Sentinel-level policy is `flag-only`, so the sentinel will never call remediate on Memory.
59
+
60
+ ## Level-of-abstraction fit
61
+
62
+ - Tool name mapping: pure data table + tiny renderer. No state, no I/O. Appropriate for the substrate-bound primitive.
63
+ - Memory verifier: pure file I/O + YAML parse + magic-byte check. No mutation. No state.
64
+ - Both rules sit alongside skillParityRule + hookParityRule at the right abstraction layer (per-primitive verifiers consumed by the future FrameworkParitySentinel).
65
+
66
+ ## Signal-vs-authority compliance
67
+
68
+ - toolNameMapping returns null for unknown — that's a signal to the caller, never a silent permission grant. Caller is the authority.
69
+ - memoryParityRule.verify returns structured mismatches — signal. The sentinel (not yet built) is the authority that decides what to do with the signal.
70
+ - memoryParityRule.remediate refuses unconditionally — this is the rule asserting authority over its own scope (Memory is sacrosanct), consistent with the "Memory is human-authorized" principle in the spec.
71
+
72
+ ## Interaction surface
73
+
74
+ - Registry: third rule added (`memory`). No interactions with skill or hook rules.
75
+ - toolNameMapping: importable from `src/providers/parity/toolNameMapping.js`. No consumers in v0.1 (intentional — Skill v0.2 wires it).
76
+ - No changes to existing rules, scaffold, hooks, settings.json, or migration paths.
77
+ - No new HTTP routes. No new server-side state.
78
+
79
+ ## Rollback cost
80
+
81
+ - Pure-add change. Revert is `git revert` on the merge commit. No data migration, no on-disk state created on existing agents, no settings.json mutations, no schema changes.
82
+ - Worst-case bug in Memory verifier: false-positive on existing agents that have unusual but valid Memory artifacts. Mitigation: rule is consumed only by the sentinel (not yet built), so v1.0.4 has zero runtime impact on agents.
83
+ - Worst-case bug in toolNameMapping: a canonical name renders wrong. Mitigation: no callers in v0.1; bug is caught when Skill v0.2 wires in.
84
+
85
+ ## Test coverage
86
+
87
+ - toolNameMapping: 21 tests covering every entry's cross-framework resolution, MCP prefix handling, unknown-name null return, list ordering, mapping table invariants.
88
+ - memoryParityRule: 18 tests covering required vs optional artifacts, presence checks, empty content, YAML parse errors, unterminated frontmatter, SQLite magic byte verification, remediate-refuses behavior, orphan-empty behavior, rule metadata.
89
+ - registry: updated to assert the 3-rule shape.
90
+
91
+ ## Documentation
92
+
93
+ - 3 concept specs (Agent, Tool, Memory).
94
+ - 3 ELI16 companions.
95
+ - 6 framework specs (3 × 2 frameworks).
96
+ - 3 convergence reports.
97
+ - NEXT.md updated.
98
+
99
+ ## Deferred (tracked, not silent)
100
+
101
+ - Agent parity rule (pending Codex subagent surface research) — documented in `specs/instar-concepts/agent.md` "v0.1 deferred items".
102
+ - Skill v0.2 wiring of TOOL_NAME_MAPPING into `allowed-tools` — documented in `specs/instar-concepts/tool.md` + NEXT.md.
103
+ - Memory schema validation beyond YAML-parse — documented in `specs/instar-concepts/memory.md` "v0.1 deferred items".
104
+ - InstructionFile primitive (the loading-vehicle for canonical Memory into framework system prompts) — separate primitive, next.
105
+ - Migration backfill (Memory verifier is no-op on existing agents because canonical Memory already lives in `.instar/` — no migration needed).