@cerefox/memory 1.1.0-beta.5 → 1.1.0-beta.6
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/bin/cerefox.js
CHANGED
|
@@ -7438,7 +7438,7 @@ var exports_meta = {};
|
|
|
7438
7438
|
__export(exports_meta, {
|
|
7439
7439
|
PKG_VERSION: () => PKG_VERSION
|
|
7440
7440
|
});
|
|
7441
|
-
var PKG_VERSION = "1.1.0-beta.
|
|
7441
|
+
var PKG_VERSION = "1.1.0-beta.6";
|
|
7442
7442
|
var init_meta = () => {};
|
|
7443
7443
|
|
|
7444
7444
|
// ../../_shared/config/paths.ts
|
|
@@ -78094,7 +78094,7 @@ async function action27(options) {
|
|
|
78094
78094
|
println(c.bold(`Reindexing ${chunks.length} chunk(s) ${reindexAll ? "(--all)" : "(stale only)"}${dryRun ? " — DRY RUN" : ""}`));
|
|
78095
78095
|
warnLargeBulkWrite({
|
|
78096
78096
|
count: chunks.length,
|
|
78097
|
-
threshold:
|
|
78097
|
+
threshold: 5000,
|
|
78098
78098
|
unit: "chunk",
|
|
78099
78099
|
batchHint: "reindex in stages with --document-id"
|
|
78100
78100
|
});
|
|
@@ -78189,7 +78189,7 @@ async function action28(options) {
|
|
|
78189
78189
|
}
|
|
78190
78190
|
warnLargeBulkWrite({
|
|
78191
78191
|
count: targets.length,
|
|
78192
|
-
threshold:
|
|
78192
|
+
threshold: 1000,
|
|
78193
78193
|
unit: "document",
|
|
78194
78194
|
batchHint: "run it in batches with --limit 100"
|
|
78195
78195
|
});
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
-- 0015_conflict_errcode_pt409.sql — stop a permanent conflict masquerading as
|
|
2
|
+
-- a retryable one.
|
|
3
|
+
--
|
|
4
|
+
-- `cerefox_ingest_document` raised CEREFOX_CONFLICT under SQLSTATE '40001'
|
|
5
|
+
-- (serialization_failure). In PostgreSQL, 40001 is the one class that promises
|
|
6
|
+
-- "this failure was transient — retry the transaction and it may succeed", and
|
|
7
|
+
-- PostgREST maps it to a retryable HTTP status. But an optimistic-concurrency
|
|
8
|
+
-- conflict is DETERMINISTIC: the same request, carrying the same stale token,
|
|
9
|
+
-- fails identically forever. Retry-aware infrastructure took the promise at
|
|
10
|
+
-- face value and looped with no exit condition.
|
|
11
|
+
--
|
|
12
|
+
-- Measured on a live project before the fix:
|
|
13
|
+
--
|
|
14
|
+
-- * ONE HTTP request with a stale token executed the function 68,825 times
|
|
15
|
+
-- in 125 seconds, then returned 504 Gateway Timeout.
|
|
16
|
+
-- * The loop OUTLIVED the client: it kept running after the 504, passing
|
|
17
|
+
-- 153,000 executions before the backend was terminated by hand.
|
|
18
|
+
-- * A contributor hit the same loop for roughly a day: ~47 MILLION calls,
|
|
19
|
+
-- which exhausted their project's Disk IO budget and required killing a
|
|
20
|
+
-- hung connection to stop.
|
|
21
|
+
-- * The identical probe raising PT409 executed exactly ONCE and returned
|
|
22
|
+
-- 409 Conflict in 636 ms.
|
|
23
|
+
--
|
|
24
|
+
-- Two changes, both in `cerefox_ingest_document`:
|
|
25
|
+
--
|
|
26
|
+
-- 1. Conflicts now raise SQLSTATE 'PT409'. PostgREST's PTxxx convention maps
|
|
27
|
+
-- it to HTTP 409 Conflict, which nothing retries.
|
|
28
|
+
-- 2. A blank (empty or whitespace) expected_content_hash is treated as
|
|
29
|
+
-- ABSENT rather than stale, so it raises CEREFOX_TOKEN_REQUIRED (400)
|
|
30
|
+
-- instead of a conflict. '' is not NULL, so it used to slip past the
|
|
31
|
+
-- absent-token branch into the conflict branch — and could never match a
|
|
32
|
+
-- real hash, making it a permanent failure. That is the exact shape that
|
|
33
|
+
-- triggered the incident.
|
|
34
|
+
--
|
|
35
|
+
-- Client detection is unaffected: every transport matches on the
|
|
36
|
+
-- `CEREFOX_CONFLICT:` / `CEREFOX_TOKEN_REQUIRED:` message prefix, never on the
|
|
37
|
+
-- SQLSTATE.
|
|
38
|
+
--
|
|
39
|
+
-- This migration only re-applies `rpcs.sql`, which `cerefox server deploy`
|
|
40
|
+
-- does anyway. It exists so the schema version moves and operators are told to
|
|
41
|
+
-- redeploy — the fix is inert until the RPC is replaced.
|
|
42
|
+
--
|
|
43
|
+
-- Idempotent: safe to re-run.
|
|
44
|
+
|
|
45
|
+
DO $$
|
|
46
|
+
BEGIN
|
|
47
|
+
RAISE NOTICE
|
|
48
|
+
'Migration 0015: CEREFOX_CONFLICT now raises PT409 (HTTP 409) instead of 40001. '
|
|
49
|
+
'The change lives in rpcs.sql, which is re-applied by `cerefox server deploy`. '
|
|
50
|
+
'Until that runs, stale-token conflicts remain retryable by infrastructure.';
|
|
51
|
+
END $$;
|
|
@@ -1253,7 +1253,7 @@ $$;
|
|
|
1253
1253
|
-- p_expected_content_hash : optimistic-concurrency token (iter-32). On the UPDATE
|
|
1254
1254
|
-- path this must equal the document's current content_hash —
|
|
1255
1255
|
-- the caller proves they based their edit on the live version.
|
|
1256
|
-
-- Mismatch → CEREFOX_CONFLICT (SQLSTATE
|
|
1256
|
+
-- Mismatch → CEREFOX_CONFLICT (SQLSTATE PT409 → HTTP 409). Absent (NULL)
|
|
1257
1257
|
-- without p_last_write_wins → CEREFOX_TOKEN_REQUIRED (22023).
|
|
1258
1258
|
-- Ignored on the CREATE path.
|
|
1259
1259
|
-- p_last_write_wins : explicit opt-out of the concurrency check (filesystem-sync
|
|
@@ -1368,7 +1368,17 @@ BEGIN
|
|
|
1368
1368
|
-- choose last-write-wins. Message prefixes are machine-detectable:
|
|
1369
1369
|
-- transport handlers map them to agent-first retry instructions.
|
|
1370
1370
|
IF NOT p_last_write_wins THEN
|
|
1371
|
-
|
|
1371
|
+
-- A blank token is an ABSENT token, not a stale one.
|
|
1372
|
+
--
|
|
1373
|
+
-- '' is not NULL, so an empty string used to skip the
|
|
1374
|
+
-- TOKEN_REQUIRED branch and fall into the conflict branch below:
|
|
1375
|
+
-- it can never equal a real hash, so it failed deterministically
|
|
1376
|
+
-- and forever. That is precisely the shape that drove the retry
|
|
1377
|
+
-- storm — a permanent failure reported as a retryable one. Even
|
|
1378
|
+
-- with PT409 now closing the loop, classifying it as a conflict is
|
|
1379
|
+
-- wrong: nobody read '' from a document, so the caller has not
|
|
1380
|
+
-- followed the read-before-write contract, which is a 400.
|
|
1381
|
+
IF NULLIF(BTRIM(p_expected_content_hash), '') IS NULL THEN
|
|
1372
1382
|
RAISE EXCEPTION
|
|
1373
1383
|
'CEREFOX_TOKEN_REQUIRED: content updates require expected_content_hash (the content_hash you read) or last_write_wins=true. Current hash: %',
|
|
1374
1384
|
v_current_hash
|
|
@@ -1377,7 +1387,27 @@ BEGIN
|
|
|
1377
1387
|
RAISE EXCEPTION
|
|
1378
1388
|
'CEREFOX_CONFLICT: document % changed since it was read (expected hash %, current hash %). Re-read the document, merge your changes, and retry with the new hash.',
|
|
1379
1389
|
v_doc_id, p_expected_content_hash, v_current_hash
|
|
1380
|
-
|
|
1390
|
+
-- PT409 → HTTP 409 Conflict (PostgREST's PTxxx convention).
|
|
1391
|
+
--
|
|
1392
|
+
-- This was '40001' (serialization_failure) until v1.1.0-beta.6,
|
|
1393
|
+
-- which was a category error with severe consequences. 40001 is
|
|
1394
|
+
-- the ONE PostgreSQL class that promises "this was transient,
|
|
1395
|
+
-- retry and it may succeed" — but a stale-token conflict is
|
|
1396
|
+
-- DETERMINISTIC: the same request fails identically forever.
|
|
1397
|
+
-- Retry-aware layers took the promise at face value and looped.
|
|
1398
|
+
--
|
|
1399
|
+
-- Measured on a real project: one HTTP request carrying a stale
|
|
1400
|
+
-- hash executed this function 68,825 times in 125s before the
|
|
1401
|
+
-- gateway returned 504 — and kept going after the client was
|
|
1402
|
+
-- gone, passing 153,000 executions before the backend was killed
|
|
1403
|
+
-- manually. A contributor hit the same loop for ~24h and 47
|
|
1404
|
+
-- MILLION calls, which is what depleted their Disk IO budget.
|
|
1405
|
+
-- The same probe raising PT409 executed exactly ONCE and
|
|
1406
|
+
-- returned 409 in 636ms.
|
|
1407
|
+
--
|
|
1408
|
+
-- Rule of thumb: never raise a permanent application error under
|
|
1409
|
+
-- a SQLSTATE whose contract says "retryable".
|
|
1410
|
+
USING ERRCODE = 'PT409';
|
|
1381
1411
|
END IF;
|
|
1382
1412
|
END IF;
|
|
1383
1413
|
|
|
@@ -2234,7 +2264,7 @@ SET search_path = public, pg_catalog
|
|
|
2234
2264
|
AS $$
|
|
2235
2265
|
-- Keep in lockstep with the `@version:` marker in schema.sql (cut_release.ts
|
|
2236
2266
|
-- enforces it). Bump whenever schema.sql OR rpcs.sql changes.
|
|
2237
|
-
SELECT '0.10.
|
|
2267
|
+
SELECT '0.10.2'::TEXT;
|
|
2238
2268
|
$$;
|
|
2239
2269
|
|
|
2240
2270
|
-- ── cerefox_content_format_stats ─────────────────────────────────────────────
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
-- Requires extensions: vector (pgvector), uuid-ossp
|
|
6
6
|
-- These are enabled at the top of db_deploy.py before this file is applied.
|
|
7
7
|
--
|
|
8
|
-
-- @version: 0.10.
|
|
8
|
+
-- @version: 0.10.2
|
|
9
9
|
-- The `@version` marker above is read by the schema-version-mismatch banner
|
|
10
10
|
-- (see /api/v1/schema-version). Bump it whenever schema.sql OR rpcs.sql
|
|
11
11
|
-- changes in a way that requires `cerefox server deploy` to be re-run —
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cerefox/memory",
|
|
3
|
-
"version": "1.1.0-beta.
|
|
3
|
+
"version": "1.1.0-beta.6",
|
|
4
4
|
"description": "Cerefox — user-owned shared memory for AI agents. CLI + stdio MCP server + web UI + ingestion for a knowledge base on your own Supabase project (or fully self-hosted with Cerefox Local).",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"homepage": "https://github.com/fstamatelopoulos/cerefox",
|