@remnic/core 9.3.708 → 9.3.709
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.
- package/dist/access-boundary.d.ts +7 -7
- package/dist/access-boundary.js +8 -8
- package/dist/access-cli.js +111 -24
- package/dist/access-cli.js.map +1 -1
- package/dist/access-http.d.ts +6 -6
- package/dist/access-http.js +12 -12
- package/dist/access-mcp.d.ts +14 -6
- package/dist/access-mcp.js +11 -11
- package/dist/access-operations-batch.js +9 -9
- package/dist/access-operations.d.ts +28 -8
- package/dist/access-operations.js +14 -10
- package/dist/access-schema.d.ts +6 -6
- package/dist/{access-service-j1c1gptF.d.ts → access-service-CoIA0NrG.d.ts} +186 -3
- package/dist/access-service.d.ts +6 -6
- package/dist/access-service.js +7 -7
- package/dist/access-surface-catalog.d.ts +6 -6
- package/dist/access-surface-catalog.js +7 -0
- package/dist/access-surface-catalog.js.map +1 -1
- package/dist/action-confidence.d.ts +1 -1
- package/dist/active-memory-bridge.d.ts +1 -1
- package/dist/active-recall.d.ts +1 -1
- package/dist/active-recall.js +1 -1
- package/dist/behavior-learner.d.ts +1 -1
- package/dist/behavior-signals.d.ts +1 -1
- package/dist/bootstrap.d.ts +4 -4
- package/dist/briefing.d.ts +1 -1
- package/dist/briefing.js +3 -3
- package/dist/buffer-surprise-report.d.ts +1 -1
- package/dist/buffer.d.ts +1 -1
- package/dist/calibration.d.ts +1 -1
- package/dist/capabilities.d.ts +1 -1
- package/dist/{catalog-CKxilpzS.d.ts → catalog-DQCZrBjw.d.ts} +1 -1
- package/dist/causal-behavior.d.ts +1 -1
- package/dist/causal-consolidation.d.ts +1 -1
- package/dist/causal-consolidation.js +4 -4
- package/dist/{chunk-PDJQVAGM.js → chunk-2T4TDXPC.js} +14 -14
- package/dist/{chunk-W2WQ4LE7.js → chunk-35YJ6KCV.js} +2 -2
- package/dist/{chunk-C63MK3WL.js → chunk-3TCRU4JA.js} +2 -2
- package/dist/{chunk-WRGPE6AW.js → chunk-3XHD3XGK.js} +44 -1
- package/dist/chunk-3XHD3XGK.js.map +1 -0
- package/dist/{chunk-GKI6LX5L.js → chunk-54TI5GLV.js} +2 -2
- package/dist/{chunk-IVCQW4C4.js → chunk-7IBEWQLG.js} +2 -2
- package/dist/{chunk-Y6YHAGQP.js → chunk-7NDYFAJS.js} +2 -2
- package/dist/{chunk-SPETAWFE.js → chunk-AZVHBFI3.js} +2 -2
- package/dist/{chunk-MLLTU5FX.js → chunk-BOGENF7P.js} +1 -1
- package/dist/chunk-BOGENF7P.js.map +1 -0
- package/dist/{chunk-3PTOZJOI.js → chunk-BQCFXAMN.js} +2 -2
- package/dist/{chunk-4E2QCH46.js → chunk-CNVIWMQI.js} +2 -2
- package/dist/{chunk-4DZATVK5.js → chunk-CXMXAC5R.js} +3 -3
- package/dist/{chunk-STYMKPFT.js → chunk-EVX52NCY.js} +1459 -21
- package/dist/chunk-EVX52NCY.js.map +1 -0
- package/dist/{chunk-W2S3Z5MT.js → chunk-GMRNKPWO.js} +2 -2
- package/dist/{chunk-HIV5E57C.js → chunk-HSDJCT3V.js} +2 -2
- package/dist/{chunk-NM6TSEGQ.js → chunk-JNOYYWCA.js} +2 -2
- package/dist/{chunk-IONFO7UK.js → chunk-JQ7XVM4V.js} +3 -3
- package/dist/{chunk-2VQYHHWB.js → chunk-JSDZMOT7.js} +11 -2
- package/dist/chunk-JSDZMOT7.js.map +1 -0
- package/dist/{chunk-WSWYIKXX.js → chunk-KOEKDZ6A.js} +62 -5
- package/dist/chunk-KOEKDZ6A.js.map +1 -0
- package/dist/{chunk-WQADZ3ZY.js → chunk-NK3SPJLM.js} +20 -19
- package/dist/chunk-NK3SPJLM.js.map +1 -0
- package/dist/{chunk-WDH3KUZU.js → chunk-NXL5CVE7.js} +2 -2
- package/dist/{chunk-BGAHTI4C.js → chunk-OK7FUX6R.js} +6 -6
- package/dist/{chunk-24FGNOQS.js → chunk-P6PRSI3W.js} +85 -4
- package/dist/chunk-P6PRSI3W.js.map +1 -0
- package/dist/{chunk-66TSLESZ.js → chunk-PKE7EJMX.js} +2 -2
- package/dist/chunk-PKE7EJMX.js.map +1 -0
- package/dist/{chunk-MOXFPLD6.js → chunk-QXNFQKWU.js} +2 -2
- package/dist/{chunk-MRX6ZXHZ.js → chunk-S6FQLQGH.js} +2 -2
- package/dist/{chunk-6HPJMR5I.js → chunk-SKQCFAYU.js} +2 -2
- package/dist/{chunk-EJDAXR7O.js → chunk-VWB3HDY6.js} +56 -8
- package/dist/chunk-VWB3HDY6.js.map +1 -0
- package/dist/{chunk-N75N5SNX.js → chunk-XD33EX2F.js} +3 -3
- package/dist/{chunk-ESMY4RJ4.js → chunk-XKU4YE6Z.js} +2 -2
- package/dist/{chunk-XKMDDM7P.js → chunk-Y6PIFKXX.js} +2 -2
- package/dist/{chunk-RH2OSRQY.js → chunk-Z56IHRVV.js} +2 -2
- package/dist/{cli-CbT-pyM4.d.ts → cli-qex-L3GT.d.ts} +3 -3
- package/dist/cli.d.ts +6 -6
- package/dist/cli.js +26 -26
- package/dist/compounding/engine.d.ts +1 -1
- package/dist/compounding/engine.js +3 -3
- package/dist/compounding/preference-consolidator.d.ts +1 -1
- package/dist/compression-optimizer.d.ts +1 -1
- package/dist/config.d.ts +1 -1
- package/dist/config.js +1 -1
- package/dist/connectors/codex-materialize-runner.d.ts +1 -1
- package/dist/connectors/codex-materialize-runner.js +3 -3
- package/dist/connectors/codex-materialize.d.ts +1 -1
- package/dist/connectors/index.d.ts +1 -1
- package/dist/connectors/index.js +3 -3
- package/dist/consolidation-provenance-check.d.ts +1 -1
- package/dist/consolidation-undo.d.ts +1 -1
- package/dist/contradiction/index.d.ts +1 -1
- package/dist/conversation-index/backend.d.ts +1 -1
- package/dist/conversation-index/chunker.d.ts +1 -1
- package/dist/conversation-index/faiss-adapter.d.ts +1 -1
- package/dist/conversation-index/indexer.d.ts +1 -1
- package/dist/conversation-index/search.d.ts +1 -1
- package/dist/day-summary.d.ts +1 -1
- package/dist/delinearize.d.ts +1 -1
- package/dist/direct-answer-wiring.d.ts +1 -1
- package/dist/direct-answer.d.ts +1 -1
- package/dist/embedding-fallback.d.ts +1 -1
- package/dist/enrichment/index.d.ts +1 -1
- package/dist/entity-retrieval.d.ts +1 -1
- package/dist/entity-retrieval.js +3 -3
- package/dist/entity-schema.d.ts +1 -1
- package/dist/explicit-capture.d.ts +4 -4
- package/dist/extraction-faithfulness.d.ts +1 -1
- package/dist/extraction-judge-telemetry.d.ts +1 -1
- package/dist/extraction-judge-training.d.ts +1 -1
- package/dist/extraction-judge.d.ts +1 -1
- package/dist/extraction.d.ts +1 -1
- package/dist/fallback-llm.d.ts +1 -1
- package/dist/identity-continuity.d.ts +1 -1
- package/dist/importance.d.ts +1 -1
- package/dist/index.d.ts +9 -9
- package/dist/index.js +32 -32
- package/dist/intent.d.ts +1 -1
- package/dist/lcm/engine.d.ts +1 -1
- package/dist/lcm/index.d.ts +1 -1
- package/dist/lcm/tools.d.ts +1 -1
- package/dist/lifecycle.d.ts +1 -1
- package/dist/live-connectors-runner.d.ts +1 -1
- package/dist/local-llm.d.ts +1 -1
- package/dist/maintenance/memory-governance.d.ts +1 -1
- package/dist/maintenance/memory-governance.js +3 -3
- package/dist/maintenance/rebuild-memory-lifecycle-ledger.js +3 -3
- package/dist/maintenance/rebuild-memory-projection.js +4 -4
- package/dist/mcp-memory-inspector-app.d.ts +6 -6
- package/dist/memory-action-policy.d.ts +1 -1
- package/dist/memory-cache.d.ts +1 -1
- package/dist/memory-lifecycle-ledger-utils.d.ts +1 -1
- package/dist/memory-projection-store.d.ts +1 -1
- package/dist/memory-provenance.d.ts +1 -1
- package/dist/memory-worth-outcomes.d.ts +1 -1
- package/dist/models-json.d.ts +1 -1
- package/dist/namespaces/migrate.d.ts +2 -2
- package/dist/namespaces/migrate.js +4 -4
- package/dist/namespaces/principal.d.ts +1 -1
- package/dist/namespaces/search.d.ts +1 -1
- package/dist/namespaces/storage.d.ts +2 -2
- package/dist/namespaces/storage.js +3 -3
- package/dist/native-knowledge.d.ts +1 -1
- package/dist/operator-toolkit.d.ts +1 -1
- package/dist/operator-toolkit.js +9 -9
- package/dist/orchestration/maintenance.d.ts +2 -2
- package/dist/orchestration/maintenance.js +5 -5
- package/dist/{orchestrator-D4ovYV3x.d.ts → orchestrator-DsVKLEBk.d.ts} +3 -3
- package/dist/orchestrator.d.ts +4 -4
- package/dist/orchestrator.js +15 -15
- package/dist/patterns-cli.d.ts +1 -1
- package/dist/policy-runtime.d.ts +1 -1
- package/dist/provenance.d.ts +1 -1
- package/dist/qmd-recall-cache.d.ts +1 -1
- package/dist/qmd.d.ts +1 -1
- package/dist/recall-disclosure-escalation.d.ts +1 -1
- package/dist/recall-explain-renderer.d.ts +1 -1
- package/dist/recall-explain-renderer.js +3 -3
- package/dist/recall-planner-llm.d.ts +1 -1
- package/dist/recall-state.d.ts +1 -1
- package/dist/recall-tag-filter.d.ts +1 -1
- package/dist/recall-xray-cli.d.ts +1 -1
- package/dist/recall-xray-cli.js +4 -4
- package/dist/recall-xray-renderer.d.ts +1 -1
- package/dist/recall-xray-renderer.js +3 -3
- package/dist/recall-xray.d.ts +1 -1
- package/dist/recall-xray.js +2 -2
- package/dist/resolve-auth-token.d.ts +1 -1
- package/dist/resume-bundles.js +2 -2
- package/dist/retrieval-agents.d.ts +1 -1
- package/dist/retrieval-tiers.d.ts +1 -1
- package/dist/routing/engine.d.ts +1 -1
- package/dist/routing/store.d.ts +1 -1
- package/dist/schemas.d.ts +2 -2
- package/dist/search/embed-helper.d.ts +1 -1
- package/dist/search/factory.d.ts +1 -1
- package/dist/search/index.d.ts +1 -1
- package/dist/search/lancedb-backend.d.ts +1 -1
- package/dist/search/meilisearch-backend.d.ts +1 -1
- package/dist/search/noop-backend.d.ts +1 -1
- package/dist/search/orama-backend.d.ts +1 -1
- package/dist/search/port.d.ts +1 -1
- package/dist/search/remote-backend.d.ts +1 -1
- package/dist/{semantic-consolidation-DyMUCsfN.d.ts → semantic-consolidation-_hVxkTuF.d.ts} +1 -1
- package/dist/semantic-consolidation.d.ts +2 -2
- package/dist/semantic-consolidation.js +4 -4
- package/dist/semantic-rule-promotion.js +3 -3
- package/dist/semantic-rule-verifier.d.ts +1 -1
- package/dist/semantic-rule-verifier.js +3 -3
- package/dist/session-observer-bands.d.ts +1 -1
- package/dist/session-observer-state.d.ts +1 -1
- package/dist/shared-context/manager.d.ts +1 -1
- package/dist/signal.d.ts +1 -1
- package/dist/storage.d.ts +8 -1
- package/dist/storage.js +2 -2
- package/dist/summarizer.d.ts +1 -1
- package/dist/summary-snapshot.d.ts +1 -1
- package/dist/temporal-supersession.d.ts +1 -1
- package/dist/temporal-validity.d.ts +1 -1
- package/dist/threading.d.ts +1 -1
- package/dist/tier-migration.d.ts +1 -1
- package/dist/tier-routing.d.ts +1 -1
- package/dist/topics.d.ts +1 -1
- package/dist/transcript.d.ts +1 -1
- package/dist/transfer/types.d.ts +12 -12
- package/dist/{types-Couvz-L3.d.ts → types-DUK4vVnN.d.ts} +27 -0
- package/dist/types.d.ts +1 -1
- package/dist/types.js +1 -1
- package/dist/utility-runtime.d.ts +1 -1
- package/dist/verified-recall.js +3 -3
- package/package.json +2 -2
- package/src/access-boundary.ts +2 -0
- package/src/access-cli.ts +107 -2
- package/src/access-http.ts +70 -1
- package/src/access-mcp.ts +65 -0
- package/src/access-operations.ts +122 -0
- package/src/access-service.ts +92 -0
- package/src/access-surface-catalog.test.ts +6 -1
- package/src/access-surface-catalog.ts +7 -0
- package/src/cli.ts +1 -0
- package/src/config.test.ts +10 -0
- package/src/config.ts +43 -0
- package/src/correction/correction-access-wiring.ts +887 -0
- package/src/correction/correction-contract.ts +416 -0
- package/src/correction/correction-executor.test.ts +742 -0
- package/src/correction/correction-executor.ts +473 -0
- package/src/correction/correction-planner.test.ts +446 -0
- package/src/correction/correction-planner.ts +546 -0
- package/src/correction/correction-service.ts +180 -0
- package/src/correction/correction-surfaces.test.ts +245 -0
- package/src/correction/index.ts +43 -0
- package/src/storage.ts +10 -0
- package/src/types.ts +27 -0
- package/dist/chunk-24FGNOQS.js.map +0 -1
- package/dist/chunk-2VQYHHWB.js.map +0 -1
- package/dist/chunk-66TSLESZ.js.map +0 -1
- package/dist/chunk-EJDAXR7O.js.map +0 -1
- package/dist/chunk-MLLTU5FX.js.map +0 -1
- package/dist/chunk-STYMKPFT.js.map +0 -1
- package/dist/chunk-WQADZ3ZY.js.map +0 -1
- package/dist/chunk-WRGPE6AW.js.map +0 -1
- package/dist/chunk-WSWYIKXX.js.map +0 -1
- /package/dist/{chunk-PDJQVAGM.js.map → chunk-2T4TDXPC.js.map} +0 -0
- /package/dist/{chunk-W2WQ4LE7.js.map → chunk-35YJ6KCV.js.map} +0 -0
- /package/dist/{chunk-C63MK3WL.js.map → chunk-3TCRU4JA.js.map} +0 -0
- /package/dist/{chunk-GKI6LX5L.js.map → chunk-54TI5GLV.js.map} +0 -0
- /package/dist/{chunk-IVCQW4C4.js.map → chunk-7IBEWQLG.js.map} +0 -0
- /package/dist/{chunk-Y6YHAGQP.js.map → chunk-7NDYFAJS.js.map} +0 -0
- /package/dist/{chunk-SPETAWFE.js.map → chunk-AZVHBFI3.js.map} +0 -0
- /package/dist/{chunk-3PTOZJOI.js.map → chunk-BQCFXAMN.js.map} +0 -0
- /package/dist/{chunk-4E2QCH46.js.map → chunk-CNVIWMQI.js.map} +0 -0
- /package/dist/{chunk-4DZATVK5.js.map → chunk-CXMXAC5R.js.map} +0 -0
- /package/dist/{chunk-W2S3Z5MT.js.map → chunk-GMRNKPWO.js.map} +0 -0
- /package/dist/{chunk-HIV5E57C.js.map → chunk-HSDJCT3V.js.map} +0 -0
- /package/dist/{chunk-NM6TSEGQ.js.map → chunk-JNOYYWCA.js.map} +0 -0
- /package/dist/{chunk-IONFO7UK.js.map → chunk-JQ7XVM4V.js.map} +0 -0
- /package/dist/{chunk-WDH3KUZU.js.map → chunk-NXL5CVE7.js.map} +0 -0
- /package/dist/{chunk-BGAHTI4C.js.map → chunk-OK7FUX6R.js.map} +0 -0
- /package/dist/{chunk-MOXFPLD6.js.map → chunk-QXNFQKWU.js.map} +0 -0
- /package/dist/{chunk-MRX6ZXHZ.js.map → chunk-S6FQLQGH.js.map} +0 -0
- /package/dist/{chunk-6HPJMR5I.js.map → chunk-SKQCFAYU.js.map} +0 -0
- /package/dist/{chunk-N75N5SNX.js.map → chunk-XD33EX2F.js.map} +0 -0
- /package/dist/{chunk-ESMY4RJ4.js.map → chunk-XKU4YE6Z.js.map} +0 -0
- /package/dist/{chunk-XKMDDM7P.js.map → chunk-Y6PIFKXX.js.map} +0 -0
- /package/dist/{chunk-RH2OSRQY.js.map → chunk-Z56IHRVV.js.map} +0 -0
package/src/access-http.ts
CHANGED
|
@@ -8,6 +8,7 @@ import { fileURLToPath, URL } from "node:url";
|
|
|
8
8
|
import { gunzipSync } from "node:zlib";
|
|
9
9
|
import { log } from "./logger.js";
|
|
10
10
|
import { EngramAccessInputError, type EngramAccessService, type EngramAccessMemoryResponse, type EngramAccessWriteResponse } from "./access-service.js";
|
|
11
|
+
import { CorrectionContractError } from "./correction/correction-contract.js";
|
|
11
12
|
import { WearablesInputError } from "./wearables/errors.js";
|
|
12
13
|
import { EngramMcpServer } from "./access-mcp.js";
|
|
13
14
|
import { validateRequest, type SchemaName, type SchemaTypeFor } from "./access-schema.js";
|
|
@@ -319,6 +320,7 @@ export class EngramAccessHttpServer {
|
|
|
319
320
|
architectureCardVisible: this.service.architectureCardSurfaceVisible,
|
|
320
321
|
codegraphVisible: this.service.codegraphSurfaceVisible,
|
|
321
322
|
sessionDeltaVisible: this.service.sessionDeltaSurfaceVisible,
|
|
323
|
+
correctionVisible: this.service.correctionSurfaceVisible,
|
|
322
324
|
});
|
|
323
325
|
}
|
|
324
326
|
|
|
@@ -343,6 +345,10 @@ export class EngramAccessHttpServer {
|
|
|
343
345
|
this.respondJson(res, 400, { error: err.message, code: "input_error" });
|
|
344
346
|
return;
|
|
345
347
|
}
|
|
348
|
+
if (err instanceof CorrectionContractError) {
|
|
349
|
+
this.respondJson(res, 400, { error: err.message, code: "correction_contract_error" });
|
|
350
|
+
return;
|
|
351
|
+
}
|
|
346
352
|
if (res.headersSent) {
|
|
347
353
|
res.destroy(err as Error);
|
|
348
354
|
return;
|
|
@@ -1432,6 +1438,58 @@ export class EngramAccessHttpServer {
|
|
|
1432
1438
|
return;
|
|
1433
1439
|
}
|
|
1434
1440
|
|
|
1441
|
+
// ── Correction Contract (issue #1580) — plan / apply / pending ─────────
|
|
1442
|
+
// All three routes dispatch through the boundary operations so schema
|
|
1443
|
+
// validation + namespace policy reach every correction path (rule 22/39).
|
|
1444
|
+
if (req.method === "POST" && pathname === "/engram/v1/correction/plan") {
|
|
1445
|
+
// Planning persists a pending plan JSON file on every successful call
|
|
1446
|
+
// (review thread UhA), so it is a state write for rate-limit purposes —
|
|
1447
|
+
// mirror the apply route's precheck + accounting to bound files under
|
|
1448
|
+
// state/corrections/pending instead of letting an HTTP client create
|
|
1449
|
+
// unbounded plan files without consuming write quota.
|
|
1450
|
+
this.ensureWriteRateLimitAvailable();
|
|
1451
|
+
const body = await this.readJsonBody(req);
|
|
1452
|
+
const op = getOperation("memory_correct_plan");
|
|
1453
|
+
if (!op) {
|
|
1454
|
+
throw new EngramAccessInputError("access-boundary: operation not registered: memory_correct_plan");
|
|
1455
|
+
}
|
|
1456
|
+
const output = (await op.run(body, {
|
|
1457
|
+
service: this.service,
|
|
1458
|
+
authenticatedPrincipal: this.resolveRequestPrincipal(req),
|
|
1459
|
+
})) as { result: unknown };
|
|
1460
|
+
this.recordWriteRateLimitHit();
|
|
1461
|
+
this.respondJson(res, 200, output.result);
|
|
1462
|
+
return;
|
|
1463
|
+
}
|
|
1464
|
+
|
|
1465
|
+
if (req.method === "POST" && pathname === "/engram/v1/correction/apply") {
|
|
1466
|
+
this.ensureWriteRateLimitAvailable();
|
|
1467
|
+
const body = await this.readJsonBody(req);
|
|
1468
|
+
const op = getOperation("memory_correct_apply");
|
|
1469
|
+
if (!op) {
|
|
1470
|
+
throw new EngramAccessInputError("access-boundary: operation not registered: memory_correct_apply");
|
|
1471
|
+
}
|
|
1472
|
+
const output = (await op.run(body, {
|
|
1473
|
+
service: this.service,
|
|
1474
|
+
authenticatedPrincipal: this.resolveRequestPrincipal(req),
|
|
1475
|
+
})) as { result: unknown };
|
|
1476
|
+
this.recordWriteRateLimitHit();
|
|
1477
|
+
this.respondJson(res, 200, output.result);
|
|
1478
|
+
return;
|
|
1479
|
+
}
|
|
1480
|
+
|
|
1481
|
+
if (req.method === "GET" && pathname === "/engram/v1/correction/pending") {
|
|
1482
|
+
const namespace = parsed.searchParams.get("namespace") ?? undefined;
|
|
1483
|
+
const sessionKey = parsed.searchParams.get("sessionKey") ?? undefined;
|
|
1484
|
+
const plans = await this.service.correctionListPending({
|
|
1485
|
+
...(namespace ? { namespace } : {}),
|
|
1486
|
+
...(sessionKey ? { sessionKey } : {}),
|
|
1487
|
+
principal: this.resolveRequestPrincipal(req),
|
|
1488
|
+
});
|
|
1489
|
+
this.respondJson(res, 200, plans);
|
|
1490
|
+
return;
|
|
1491
|
+
}
|
|
1492
|
+
|
|
1435
1493
|
if (req.method === "POST" && pathname === "/engram/v1/suggestions") {
|
|
1436
1494
|
void getOperation("suggestion_submit"); // boundary dispatch (issue #1525)
|
|
1437
1495
|
const body = await this.readValidatedBody(req, "suggestionSubmit");
|
|
@@ -2527,6 +2585,12 @@ export class EngramAccessHttpServer {
|
|
|
2527
2585
|
toolName === "remnic.memory_action_apply"
|
|
2528
2586
|
)
|
|
2529
2587
|
) ||
|
|
2588
|
+
(
|
|
2589
|
+
toolName === "engram.memory_correct_apply" ||
|
|
2590
|
+
toolName === "remnic.memory_correct_apply" ||
|
|
2591
|
+
toolName === "engram.memory_correct_plan" ||
|
|
2592
|
+
toolName === "remnic.memory_correct_plan"
|
|
2593
|
+
) ||
|
|
2530
2594
|
codingDecisionWrite ||
|
|
2531
2595
|
codingArchitectureWrite ||
|
|
2532
2596
|
codegraphWrite
|
|
@@ -2561,7 +2625,12 @@ export class EngramAccessHttpServer {
|
|
|
2561
2625
|
// would consume the write quota despite no mutation occurring
|
|
2562
2626
|
// (issue #1554 review thread: don't bill rejected calls as writes).
|
|
2563
2627
|
const isRejectedCodegraph = structured?.ok === false;
|
|
2564
|
-
|
|
2628
|
+
// A write tool that succeeded without structuredContent (e.g.
|
|
2629
|
+
// memory_correct_apply, which returns a CorrectionOutcome) still
|
|
2630
|
+
// consumed a write — count it. Tools WITH structuredContent use the
|
|
2631
|
+
// dryRun/idempotencyReplay guards.
|
|
2632
|
+
const counts = structured ? this.shouldCountWriteRateLimit(structured) : true;
|
|
2633
|
+
if (!isError && !isRejectedCodegraph && counts) {
|
|
2565
2634
|
this.recordWriteRateLimitHit();
|
|
2566
2635
|
}
|
|
2567
2636
|
}
|
package/src/access-mcp.ts
CHANGED
|
@@ -127,6 +127,9 @@ const MCP_MIGRATED_OPERATIONS: Readonly<Record<string, OperationName>> = {
|
|
|
127
127
|
"engram.codegraph_manage_adr": "codegraph_manage_adr",
|
|
128
128
|
"engram.codegraph_ingest_traces": "codegraph_ingest_traces",
|
|
129
129
|
"engram.coding_delta": "coding_delta",
|
|
130
|
+
// Correction Contract (issue #1580) — one plan/apply pipeline.
|
|
131
|
+
"engram.memory_correct_plan": "memory_correct_plan",
|
|
132
|
+
"engram.memory_correct_apply": "memory_correct_apply",
|
|
130
133
|
};
|
|
131
134
|
|
|
132
135
|
function resolveChatGptInspectorRecallSessionKey(
|
|
@@ -354,6 +357,13 @@ export class EngramMcpServer {
|
|
|
354
357
|
*/
|
|
355
358
|
private readonly codegraphVisible: boolean;
|
|
356
359
|
private readonly sessionDeltaVisible: boolean;
|
|
360
|
+
/**
|
|
361
|
+
* Whether the two correction tools (memory_correct_plan / memory_correct_apply)
|
|
362
|
+
* should appear in `tools/list` (issue #1580). Gated on `correction.enabled`
|
|
363
|
+
* (default true — plan is read-only; safe on). When false the tools array is
|
|
364
|
+
* byte-identical to pre-feature.
|
|
365
|
+
*/
|
|
366
|
+
private readonly correctionVisible: boolean;
|
|
357
367
|
|
|
358
368
|
constructor(
|
|
359
369
|
private readonly service: EngramAccessService,
|
|
@@ -366,6 +376,7 @@ export class EngramMcpServer {
|
|
|
366
376
|
architectureCardVisible?: boolean;
|
|
367
377
|
codegraphVisible?: boolean;
|
|
368
378
|
sessionDeltaVisible?: boolean;
|
|
379
|
+
correctionVisible?: boolean;
|
|
369
380
|
} = {},
|
|
370
381
|
) {
|
|
371
382
|
this.citationsEnabled = options.citationsEnabled === true;
|
|
@@ -375,6 +386,8 @@ export class EngramMcpServer {
|
|
|
375
386
|
this.architectureCardVisible = options.architectureCardVisible === true;
|
|
376
387
|
this.codegraphVisible = options.codegraphVisible === true;
|
|
377
388
|
this.sessionDeltaVisible = options.sessionDeltaVisible === true;
|
|
389
|
+
// correction defaults to visible (enabled by default — plan is read-only).
|
|
390
|
+
this.correctionVisible = options.correctionVisible !== false;
|
|
378
391
|
this.authenticatedPrincipal =
|
|
379
392
|
options.principal?.trim() ||
|
|
380
393
|
readEnvVar("OPENCLAW_ENGRAM_ACCESS_PRINCIPAL")?.trim() ||
|
|
@@ -2149,6 +2162,58 @@ export class EngramMcpServer {
|
|
|
2149
2162
|
);
|
|
2150
2163
|
this.tools = [...this.tools, ...deltaTools];
|
|
2151
2164
|
}
|
|
2165
|
+
if (this.correctionVisible) {
|
|
2166
|
+
// Correction Contract (issue #1580) — one plan/apply pipeline for every
|
|
2167
|
+
// memory correction. Both tools dispatch through the boundary operations
|
|
2168
|
+
// (memory_correct_plan / memory_correct_apply) which delegate to the
|
|
2169
|
+
// CorrectionService.
|
|
2170
|
+
const planTool = withToolAliases(
|
|
2171
|
+
{
|
|
2172
|
+
name: "engram.memory_correct_plan",
|
|
2173
|
+
description:
|
|
2174
|
+
"Plan a memory correction from a plain-language statement (issue #1580). Returns a CorrectionPlan with a diff preview; apply via memory_correct_apply.",
|
|
2175
|
+
inputSchema: {
|
|
2176
|
+
type: "object",
|
|
2177
|
+
properties: {
|
|
2178
|
+
text: {
|
|
2179
|
+
type: "string",
|
|
2180
|
+
description: "The natural-language correction (e.g. \"we migrated to MySQL in March\").",
|
|
2181
|
+
},
|
|
2182
|
+
targetIds: {
|
|
2183
|
+
type: "array",
|
|
2184
|
+
items: { type: "string" },
|
|
2185
|
+
description: "Optional explicit target memory ids. When omitted, the planner searches.",
|
|
2186
|
+
},
|
|
2187
|
+
sessionKey: { type: "string", description: "Session identifier for namespace resolution." },
|
|
2188
|
+
namespace: { type: "string", description: "Optional explicit namespace (validated by policy)." },
|
|
2189
|
+
},
|
|
2190
|
+
required: ["text"],
|
|
2191
|
+
additionalProperties: false,
|
|
2192
|
+
},
|
|
2193
|
+
},
|
|
2194
|
+
this.emitLegacyTools,
|
|
2195
|
+
);
|
|
2196
|
+
const applyTool = withToolAliases(
|
|
2197
|
+
{
|
|
2198
|
+
name: "engram.memory_correct_apply",
|
|
2199
|
+
description:
|
|
2200
|
+
"Apply a planned memory correction by planId (issue #1580). Requires confirm: true when correction.applyRequiresConfirm is on (default).",
|
|
2201
|
+
inputSchema: {
|
|
2202
|
+
type: "object",
|
|
2203
|
+
properties: {
|
|
2204
|
+
planId: { type: "string", description: "The plan id returned by memory_correct_plan." },
|
|
2205
|
+
confirm: { type: "boolean", description: "Must be true to apply (safety guard, rule 48)." },
|
|
2206
|
+
sessionKey: { type: "string", description: "Session identifier for namespace resolution." },
|
|
2207
|
+
namespace: { type: "string", description: "Optional explicit namespace (validated by policy)." },
|
|
2208
|
+
},
|
|
2209
|
+
required: ["planId"],
|
|
2210
|
+
additionalProperties: false,
|
|
2211
|
+
},
|
|
2212
|
+
},
|
|
2213
|
+
this.emitLegacyTools,
|
|
2214
|
+
);
|
|
2215
|
+
this.tools = [...this.tools, ...planTool, ...applyTool];
|
|
2216
|
+
}
|
|
2152
2217
|
}
|
|
2153
2218
|
|
|
2154
2219
|
/** Get clientInfo for a specific MCP session. Returns undefined for non-MCP requests. */
|
package/src/access-operations.ts
CHANGED
|
@@ -16,6 +16,8 @@ import { z } from "zod";
|
|
|
16
16
|
|
|
17
17
|
import { defineOperation } from "./access-boundary.js";
|
|
18
18
|
import { memoryStoreRequestSchema, type MemoryStoreRequest } from "./access-schema.js";
|
|
19
|
+
import { EngramAccessInputError } from "./access-service.js";
|
|
20
|
+
import { CorrectionContractError } from "./correction/correction-contract.js";
|
|
19
21
|
import type {
|
|
20
22
|
EngramAccessMemoryResponse,
|
|
21
23
|
EngramAccessWriteResponse,
|
|
@@ -344,6 +346,124 @@ export const codingDeltaOperation = defineOperation<
|
|
|
344
346
|
},
|
|
345
347
|
});
|
|
346
348
|
|
|
349
|
+
// ---------------------------------------------------------------------------
|
|
350
|
+
// memory_correct_plan / memory_correct_apply — Correction Contract (#1580)
|
|
351
|
+
// ---------------------------------------------------------------------------
|
|
352
|
+
//
|
|
353
|
+
// One plan/apply pipeline for every memory correction (supersession,
|
|
354
|
+
// invalidation, tombstone, edit, rescope, redaction). The MCP/HTTP/CLI
|
|
355
|
+
// surfaces all dispatch through these two ops so the boundary's validation +
|
|
356
|
+
// error mapping reach every correction path (rule 22 / 39).
|
|
357
|
+
|
|
358
|
+
const memoryCorrectPlanSchema = z.preprocess(
|
|
359
|
+
(data) => {
|
|
360
|
+
if (data && typeof data === "object" && !Array.isArray(data)) {
|
|
361
|
+
const out: Record<string, unknown> = {};
|
|
362
|
+
for (const [k, v] of Object.entries(data as Record<string, unknown>)) {
|
|
363
|
+
if (v !== null) out[k] = v;
|
|
364
|
+
}
|
|
365
|
+
return out;
|
|
366
|
+
}
|
|
367
|
+
return data;
|
|
368
|
+
},
|
|
369
|
+
z.object({
|
|
370
|
+
text: z.string().trim().min(1).max(10_000),
|
|
371
|
+
targetIds: z.array(z.string().trim().min(1).max(512)).optional(),
|
|
372
|
+
sessionKey: z.string().trim().max(512).optional(),
|
|
373
|
+
namespace: z.string().trim().max(256).optional(),
|
|
374
|
+
}),
|
|
375
|
+
);
|
|
376
|
+
|
|
377
|
+
export interface MemoryCorrectPlanInput {
|
|
378
|
+
text: string;
|
|
379
|
+
targetIds?: string[];
|
|
380
|
+
sessionKey?: string;
|
|
381
|
+
namespace?: string;
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
export interface MemoryCorrectPlanOutput {
|
|
385
|
+
readonly result: unknown; // CorrectionPlan — opaque to the boundary
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
export const memoryCorrectPlanOperation = defineOperation<
|
|
389
|
+
MemoryCorrectPlanInput,
|
|
390
|
+
MemoryCorrectPlanOutput
|
|
391
|
+
>({
|
|
392
|
+
name: "memory_correct_plan",
|
|
393
|
+
description:
|
|
394
|
+
"Plan a memory correction from a plain-language statement (issue #1580). Returns a CorrectionPlan with a diff preview; apply via memory_correct_apply.",
|
|
395
|
+
schema: memoryCorrectPlanSchema as z.ZodType<MemoryCorrectPlanInput>,
|
|
396
|
+
handler: async (input, ctx) => {
|
|
397
|
+
try {
|
|
398
|
+
const result = await ctx.service.correctionPlan({
|
|
399
|
+
text: input.text,
|
|
400
|
+
...(input.targetIds ? { targetIds: input.targetIds } : {}),
|
|
401
|
+
...(input.sessionKey ? { sessionKey: input.sessionKey } : {}),
|
|
402
|
+
...(input.namespace ? { namespace: input.namespace } : {}),
|
|
403
|
+
...(ctx.authenticatedPrincipal ? { principal: ctx.authenticatedPrincipal } : {}),
|
|
404
|
+
});
|
|
405
|
+
return { result };
|
|
406
|
+
} catch (err) {
|
|
407
|
+
if (err instanceof CorrectionContractError) throw new EngramAccessInputError(err.message);
|
|
408
|
+
throw err;
|
|
409
|
+
}
|
|
410
|
+
},
|
|
411
|
+
});
|
|
412
|
+
|
|
413
|
+
const memoryCorrectApplySchema = z.preprocess(
|
|
414
|
+
(data) => {
|
|
415
|
+
if (data && typeof data === "object" && !Array.isArray(data)) {
|
|
416
|
+
const out: Record<string, unknown> = {};
|
|
417
|
+
for (const [k, v] of Object.entries(data as Record<string, unknown>)) {
|
|
418
|
+
if (v !== null) out[k] = v;
|
|
419
|
+
}
|
|
420
|
+
return out;
|
|
421
|
+
}
|
|
422
|
+
return data;
|
|
423
|
+
},
|
|
424
|
+
z.object({
|
|
425
|
+
planId: z.string().trim().min(1).max(512),
|
|
426
|
+
confirm: z.boolean().optional(),
|
|
427
|
+
sessionKey: z.string().trim().max(512).optional(),
|
|
428
|
+
namespace: z.string().trim().max(256).optional(),
|
|
429
|
+
}),
|
|
430
|
+
);
|
|
431
|
+
|
|
432
|
+
export interface MemoryCorrectApplyInput {
|
|
433
|
+
planId: string;
|
|
434
|
+
confirm?: boolean;
|
|
435
|
+
sessionKey?: string;
|
|
436
|
+
namespace?: string;
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
export interface MemoryCorrectApplyOutput {
|
|
440
|
+
readonly result: unknown; // CorrectionOutcome — opaque to the boundary
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
export const memoryCorrectApplyOperation = defineOperation<
|
|
444
|
+
MemoryCorrectApplyInput,
|
|
445
|
+
MemoryCorrectApplyOutput
|
|
446
|
+
>({
|
|
447
|
+
name: "memory_correct_apply",
|
|
448
|
+
description:
|
|
449
|
+
"Apply a planned memory correction by planId (issue #1580). Requires confirm: true when correction.applyRequiresConfirm is on (default).",
|
|
450
|
+
schema: memoryCorrectApplySchema as z.ZodType<MemoryCorrectApplyInput>,
|
|
451
|
+
handler: async (input, ctx) => {
|
|
452
|
+
try {
|
|
453
|
+
const result = await ctx.service.correctionApply(input.planId, {
|
|
454
|
+
confirm: input.confirm === true,
|
|
455
|
+
...(input.sessionKey ? { sessionKey: input.sessionKey } : {}),
|
|
456
|
+
...(input.namespace ? { namespace: input.namespace } : {}),
|
|
457
|
+
...(ctx.authenticatedPrincipal ? { principal: ctx.authenticatedPrincipal } : {}),
|
|
458
|
+
});
|
|
459
|
+
return { result };
|
|
460
|
+
} catch (err) {
|
|
461
|
+
if (err instanceof CorrectionContractError) throw new EngramAccessInputError(err.message);
|
|
462
|
+
throw err;
|
|
463
|
+
}
|
|
464
|
+
},
|
|
465
|
+
});
|
|
466
|
+
|
|
347
467
|
// ---------------------------------------------------------------------------
|
|
348
468
|
// Surface registration map — what each transport calls the pilot ops
|
|
349
469
|
// ---------------------------------------------------------------------------
|
|
@@ -574,4 +694,6 @@ export const REGISTERED_OPERATIONS = [
|
|
|
574
694
|
codegraphManageAdrOperation.spec.name,
|
|
575
695
|
codegraphIngestTracesOperation.spec.name,
|
|
576
696
|
codingDeltaOperation.spec.name,
|
|
697
|
+
memoryCorrectPlanOperation.spec.name,
|
|
698
|
+
memoryCorrectApplyOperation.spec.name,
|
|
577
699
|
] as const;
|
package/src/access-service.ts
CHANGED
|
@@ -49,6 +49,14 @@ import {
|
|
|
49
49
|
type DeltaSurfaceStorage,
|
|
50
50
|
} from "./coding/session-delta-surfaces.js";
|
|
51
51
|
import { defaultGitInvoker } from "./coding/git-context.js";
|
|
52
|
+
import {
|
|
53
|
+
createCorrectionService,
|
|
54
|
+
isCorrectionFeatureEnabled,
|
|
55
|
+
CorrectionService,
|
|
56
|
+
type CorrectionOutcome,
|
|
57
|
+
type CorrectionPlan,
|
|
58
|
+
type CorrectionRequest,
|
|
59
|
+
} from "./correction/index.js";
|
|
52
60
|
import { createVersion } from "./page-versioning.js";
|
|
53
61
|
import { WorkStorage } from "./work/storage.js";
|
|
54
62
|
import {
|
|
@@ -4715,6 +4723,90 @@ export class EngramAccessService {
|
|
|
4715
4723
|
});
|
|
4716
4724
|
}
|
|
4717
4725
|
|
|
4726
|
+
// -------------------------------------------------------------------------
|
|
4727
|
+
// Correction Contract (issue #1580) — one plan/apply pipeline for every
|
|
4728
|
+
// memory correction. The CorrectionService owns the planner + executor; the
|
|
4729
|
+
// access-service constructs it lazily via the wiring helper and delegates.
|
|
4730
|
+
// Each method below is thin wiring (≤4 lines) per the god-file ratchet.
|
|
4731
|
+
// -------------------------------------------------------------------------
|
|
4732
|
+
/** Whether the memory_correct_plan / memory_correct_apply tools should appear in tools/list (rule 39). Same reader as the runtime gate so visibility + enforcement stay in sync. */
|
|
4733
|
+
get correctionSurfaceVisible(): boolean {
|
|
4734
|
+
return isCorrectionFeatureEnabled(this.orchestrator.config);
|
|
4735
|
+
}
|
|
4736
|
+
|
|
4737
|
+
|
|
4738
|
+
private _correctionService: CorrectionService | null = null;
|
|
4739
|
+
|
|
4740
|
+
/** Lazily construct + cache the CorrectionService with deps wired from the orchestrator. */
|
|
4741
|
+
private correctionService(): CorrectionService {
|
|
4742
|
+
if (this._correctionService) return this._correctionService;
|
|
4743
|
+
const service = createCorrectionService({
|
|
4744
|
+
orchestrator: this.orchestrator,
|
|
4745
|
+
resolveAuthorizedNamespace: async (req) =>
|
|
4746
|
+
this.resolveWritableNamespace(req.namespace, req.sessionKey, req.principal),
|
|
4747
|
+
resolveReadableNamespaces: (req) => {
|
|
4748
|
+
const principal = this.resolveRequestPrincipal(req.sessionKey, req.principal);
|
|
4749
|
+
return recallNamespacesForPrincipal(principal, this.orchestrator.config);
|
|
4750
|
+
},
|
|
4751
|
+
canWriteNamespace: (req) => {
|
|
4752
|
+
// resolveWritableNamespace resolves + checks writability in one step;
|
|
4753
|
+
// reusing it avoids a second ad-hoc namespace-resolution call site.
|
|
4754
|
+
try {
|
|
4755
|
+
this.resolveWritableNamespace(req.namespace, req.sessionKey, req.principal);
|
|
4756
|
+
return Promise.resolve(true);
|
|
4757
|
+
} catch {
|
|
4758
|
+
return Promise.resolve(false);
|
|
4759
|
+
}
|
|
4760
|
+
},
|
|
4761
|
+
// Wire the orchestrator's extraction LLM so classify+draft actually
|
|
4762
|
+
// drafts actions instead of always hitting the deterministic fallback
|
|
4763
|
+
// (review thread PG5). The planner's classifyAndDraft already falls back
|
|
4764
|
+
// on any LLM outage, so returning null (LLM disabled/cooldown) or a
|
|
4765
|
+
// thrown error both degrade safely to the deterministic path (rule 13).
|
|
4766
|
+
llmComplete: async ({ system, user }) => {
|
|
4767
|
+
const result = await this.orchestrator.localLlm.chatCompletion(
|
|
4768
|
+
[
|
|
4769
|
+
{ role: "system", content: system },
|
|
4770
|
+
{ role: "user", content: user },
|
|
4771
|
+
],
|
|
4772
|
+
{ operation: "correction-classify", priority: "background" },
|
|
4773
|
+
);
|
|
4774
|
+
if (!result) {
|
|
4775
|
+
throw new Error("correction classify+draft: local LLM unavailable (disabled or in cooldown)");
|
|
4776
|
+
}
|
|
4777
|
+
return result.content;
|
|
4778
|
+
},
|
|
4779
|
+
});
|
|
4780
|
+
this._correctionService = service;
|
|
4781
|
+
return service;
|
|
4782
|
+
}
|
|
4783
|
+
|
|
4784
|
+
async correctionPlan(request: CorrectionRequest): Promise<CorrectionPlan> {
|
|
4785
|
+
return this.correctionService().plan(request);
|
|
4786
|
+
}
|
|
4787
|
+
|
|
4788
|
+
async correctionApply(
|
|
4789
|
+
planId: string,
|
|
4790
|
+
opts: { confirm?: boolean; namespace?: string; sessionKey?: string; principal?: string },
|
|
4791
|
+
): Promise<CorrectionOutcome> {
|
|
4792
|
+
return this.correctionService().apply(planId, opts);
|
|
4793
|
+
}
|
|
4794
|
+
|
|
4795
|
+
async correctionListPending(opts: {
|
|
4796
|
+
namespace?: string;
|
|
4797
|
+
sessionKey?: string;
|
|
4798
|
+
principal?: string;
|
|
4799
|
+
}): Promise<CorrectionPlan[]> {
|
|
4800
|
+
return this.correctionService().listPending(opts);
|
|
4801
|
+
}
|
|
4802
|
+
|
|
4803
|
+
async correctionDiscard(
|
|
4804
|
+
planId: string,
|
|
4805
|
+
opts: { namespace?: string; sessionKey?: string; principal?: string },
|
|
4806
|
+
): Promise<void> {
|
|
4807
|
+
return this.correctionService().discard(planId, opts);
|
|
4808
|
+
}
|
|
4809
|
+
|
|
4718
4810
|
async memoryBrowse(
|
|
4719
4811
|
request: EngramAccessMemoryBrowseRequest = {},
|
|
4720
4812
|
): Promise<EngramAccessMemoryBrowseResponse> {
|
|
@@ -44,7 +44,12 @@ import {
|
|
|
44
44
|
// catalog-completeness correction: adding routes that were always live but
|
|
45
45
|
// omitted from the catalog (review-caught). Such a bump MUST be accompanied
|
|
46
46
|
// by the newly-cataloged entries; the higher count is the honest baseline.
|
|
47
|
-
|
|
47
|
+
// #1580 Correction Contract adds GET /engram/v1/correction/pending — a read-only
|
|
48
|
+
// list route (namespace/sessionKey query params, no body), so it stays unmigrated
|
|
49
|
+
// alongside the other GET list routes (baseline 80 from #1525 + 1 = 81). Also a
|
|
50
|
+
// catalog-completeness correction: POST /engram/v1/memories (operation memory_store)
|
|
51
|
+
// was always live but omitted from HTTP_ROUTES — it is migrated, so no count change.
|
|
52
|
+
const UNMIGRATED_HANDLER_BASELINE = 81;
|
|
48
53
|
|
|
49
54
|
// Keep the import live — `getOperation` is the call surfaces use at dispatch
|
|
50
55
|
// time; referencing it here pins the registry's lookup contract.
|
|
@@ -72,6 +72,9 @@ export const MCP_TOOLS: readonly McpToolEntry[] = [
|
|
|
72
72
|
{ tool: "memory_get", operation: "memory_get" },
|
|
73
73
|
{ tool: "memory_timeline", operation: null },
|
|
74
74
|
{ tool: "memory_store", operation: "memory_store" },
|
|
75
|
+
// Correction Contract (issue #1580) — one plan/apply pipeline.
|
|
76
|
+
{ tool: "memory_correct_plan", operation: "memory_correct_plan" },
|
|
77
|
+
{ tool: "memory_correct_apply", operation: "memory_correct_apply" },
|
|
75
78
|
{ tool: "coding_decision", operation: "coding_decision" },
|
|
76
79
|
{ tool: "coding_architecture", operation: "coding_architecture" },
|
|
77
80
|
// codegraph parity tools (issue #1554)
|
|
@@ -184,6 +187,10 @@ export const HTTP_ROUTES: readonly HttpRouteEntry[] = [
|
|
|
184
187
|
{ method: "POST", pathname: "/engram/v1/lcm/compaction/flush", operation: "lcm_compaction_flush" },
|
|
185
188
|
{ method: "POST", pathname: "/engram/v1/lcm/compaction/record", operation: "lcm_compaction_record" },
|
|
186
189
|
{ method: "GET", pathname: "/engram/v1/lcm/status", operation: "lcm_status" },
|
|
190
|
+
// Correction Contract (issue #1580) — plan/apply/pending.
|
|
191
|
+
{ method: "POST", pathname: "/engram/v1/correction/plan", operation: "memory_correct_plan" },
|
|
192
|
+
{ method: "POST", pathname: "/engram/v1/correction/apply", operation: "memory_correct_apply" },
|
|
193
|
+
{ method: "GET", pathname: "/engram/v1/correction/pending", operation: null },
|
|
187
194
|
{ method: "POST", pathname: "/engram/v1/memories", operation: "memory_store" },
|
|
188
195
|
{ method: "POST", pathname: "/engram/v1/coding/decisions", operation: "coding_decision" },
|
|
189
196
|
{ method: "POST", pathname: "/engram/v1/coding/architecture", operation: "coding_architecture" },
|
package/src/cli.ts
CHANGED
|
@@ -2807,6 +2807,7 @@ export async function runAccessMcpServeCliCommand(
|
|
|
2807
2807
|
architectureCardVisible: service.architectureCardSurfaceVisible,
|
|
2808
2808
|
codegraphVisible: service.codegraphSurfaceVisible,
|
|
2809
2809
|
sessionDeltaVisible: service.sessionDeltaSurfaceVisible,
|
|
2810
|
+
correctionVisible: service.correctionSurfaceVisible,
|
|
2810
2811
|
});
|
|
2811
2812
|
await server.runStdio(options.stdin ?? process.stdin, options.stdout ?? process.stdout);
|
|
2812
2813
|
return { ok: true };
|
package/src/config.test.ts
CHANGED
|
@@ -2082,3 +2082,13 @@ test("parseConfig extractionFaithfulnessTimeoutMs rejects non-numeric and non-in
|
|
|
2082
2082
|
);
|
|
2083
2083
|
}
|
|
2084
2084
|
});
|
|
2085
|
+
|
|
2086
|
+
test("parseConfig rejects invalid correction.enabled instead of silently enabling (#1580)", () => {
|
|
2087
|
+
assert.throws(() => parseConfig({ correction: { enabled: "flase" } }), /Invalid correction\.enabled/);
|
|
2088
|
+
assert.throws(() => parseConfig({ correctionEnabled: "nope" }), /Invalid correction\.enabled/);
|
|
2089
|
+
assert.throws(() => parseConfig({ correction: { applyRequiresConfirm: "sure" } }), /Invalid correction\.applyRequiresConfirm/);
|
|
2090
|
+
// Valid + absent still resolve correctly (no regression).
|
|
2091
|
+
assert.equal(parseConfig({ correction: { enabled: false } }).correctionEnabled, false);
|
|
2092
|
+
assert.equal(parseConfig({ correctionEnabled: "0" }).correctionEnabled, false);
|
|
2093
|
+
assert.equal(parseConfig({}).correctionEnabled, true);
|
|
2094
|
+
});
|
package/src/config.ts
CHANGED
|
@@ -2097,6 +2097,49 @@ export function parseConfig(
|
|
|
2097
2097
|
// (docs kept honest — review: wire resolver before exposing the gate).
|
|
2098
2098
|
temporalBiTemporal: coerceBool(cfg.temporalBiTemporal) ?? false,
|
|
2099
2099
|
temporalExpiredInInjection: coerceBool(cfg.temporalExpiredInInjection) ?? false,
|
|
2100
|
+
// Correction Contract (issue #1580). Parsed here so operators can actually
|
|
2101
|
+
// set the documented toggles/limits (review thread Txp): parseConfig builds
|
|
2102
|
+
// an explicit output, so without these lines the raw `correction` block /
|
|
2103
|
+
// flat legacy keys are dropped and the runtime always sees defaults. Nested
|
|
2104
|
+
// `correction.<key>` wins; flat `correction<Key>` is the legacy fallback.
|
|
2105
|
+
correctionEnabled: (() => {
|
|
2106
|
+
const nested = (cfg.correction as Record<string, unknown> | undefined)?.enabled;
|
|
2107
|
+
const raw = nested !== undefined ? nested : cfg.correctionEnabled;
|
|
2108
|
+
if (raw === undefined || raw === null) return true;
|
|
2109
|
+
const v = coerceBool(raw);
|
|
2110
|
+
if (v === undefined) {
|
|
2111
|
+
throw new Error(`Invalid correction.enabled: expected a boolean, got ${JSON.stringify(raw)}`);
|
|
2112
|
+
}
|
|
2113
|
+
return v;
|
|
2114
|
+
})(),
|
|
2115
|
+
correctionApplyRequiresConfirm: (() => {
|
|
2116
|
+
const nested = (cfg.correction as Record<string, unknown> | undefined)?.applyRequiresConfirm;
|
|
2117
|
+
const raw = nested !== undefined ? nested : cfg.correctionApplyRequiresConfirm;
|
|
2118
|
+
if (raw === undefined || raw === null) return true;
|
|
2119
|
+
const v = coerceBool(raw);
|
|
2120
|
+
if (v === undefined) {
|
|
2121
|
+
throw new Error(`Invalid correction.applyRequiresConfirm: expected a boolean, got ${JSON.stringify(raw)}`);
|
|
2122
|
+
}
|
|
2123
|
+
return v;
|
|
2124
|
+
})(),
|
|
2125
|
+
correctionMaxAffected: (() => {
|
|
2126
|
+
const rawNested = (cfg.correction as Record<string, unknown> | undefined)?.maxAffected;
|
|
2127
|
+
const raw = rawNested !== undefined ? rawNested : cfg.correctionMaxAffected;
|
|
2128
|
+
if (raw === undefined || raw === null) return 10;
|
|
2129
|
+
const n = coerceNumber(raw);
|
|
2130
|
+
if (n === undefined || !Number.isFinite(n) || n < 1) {
|
|
2131
|
+
throw new Error(`Invalid correction.maxAffected: expected an integer >= 1, got ${JSON.stringify(raw)}`);
|
|
2132
|
+
}
|
|
2133
|
+
return Math.floor(n);
|
|
2134
|
+
})(),
|
|
2135
|
+
correctionPlanTtlHours: (() => {
|
|
2136
|
+
const nested = (cfg.correction as Record<string, unknown> | undefined)?.planTtlHours;
|
|
2137
|
+
const fromNested = nested !== undefined ? coerceNumber(nested) : undefined;
|
|
2138
|
+
if (fromNested !== undefined && fromNested > 0) return fromNested;
|
|
2139
|
+
const fromFlat = coerceNumber(cfg.correctionPlanTtlHours);
|
|
2140
|
+
if (fromFlat !== undefined && fromFlat > 0) return fromFlat;
|
|
2141
|
+
return 24;
|
|
2142
|
+
})(),
|
|
2100
2143
|
// Tombstones — non-resurrection invariant (issue #1579). The invariant is
|
|
2101
2144
|
// the point, so it ships ON by default; `false` restores pre-feature
|
|
2102
2145
|
// behavior for rollback safety (rule 30). Uses coerceBool so CLI string
|