@pcircle/memesh 4.9.3 → 4.10.1

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.
Files changed (132) hide show
  1. package/.claude-plugin/marketplace.json +1 -1
  2. package/.claude-plugin/plugin.json +1 -1
  3. package/.codex-plugin/plugin.json +1 -1
  4. package/AGENTS.md +35 -4
  5. package/README.de.md +3 -3
  6. package/README.md +3 -3
  7. package/README.zh-TW.md +3 -3
  8. package/dashboard/dist/index.html +8 -8
  9. package/dist/cli/view-live.d.ts.map +1 -1
  10. package/dist/cli/view-live.js +0 -427
  11. package/dist/cli/view-live.js.map +1 -1
  12. package/dist/core/briefing-index.d.ts +30 -0
  13. package/dist/core/briefing-index.d.ts.map +1 -0
  14. package/dist/core/briefing-index.js +140 -0
  15. package/dist/core/briefing-index.js.map +1 -0
  16. package/dist/core/briefing.d.ts +4 -0
  17. package/dist/core/briefing.d.ts.map +1 -1
  18. package/dist/core/briefing.js +42 -4
  19. package/dist/core/briefing.js.map +1 -1
  20. package/dist/core/capture-liveness.d.ts +136 -0
  21. package/dist/core/capture-liveness.d.ts.map +1 -0
  22. package/dist/core/capture-liveness.js +447 -0
  23. package/dist/core/capture-liveness.js.map +1 -0
  24. package/dist/core/config.d.ts +1 -0
  25. package/dist/core/config.d.ts.map +1 -1
  26. package/dist/core/config.js +3 -1
  27. package/dist/core/config.js.map +1 -1
  28. package/dist/core/delegation.d.ts +47 -0
  29. package/dist/core/delegation.d.ts.map +1 -0
  30. package/dist/core/delegation.js +174 -0
  31. package/dist/core/delegation.js.map +1 -0
  32. package/dist/core/doctor-fixes.d.ts +1 -0
  33. package/dist/core/doctor-fixes.d.ts.map +1 -1
  34. package/dist/core/doctor-fixes.js +21 -0
  35. package/dist/core/doctor-fixes.js.map +1 -1
  36. package/dist/core/doctor.d.ts +8 -0
  37. package/dist/core/doctor.d.ts.map +1 -1
  38. package/dist/core/doctor.js +148 -3
  39. package/dist/core/doctor.js.map +1 -1
  40. package/dist/core/note-derive.d.ts +14 -0
  41. package/dist/core/note-derive.d.ts.map +1 -0
  42. package/dist/core/note-derive.js +66 -0
  43. package/dist/core/note-derive.js.map +1 -0
  44. package/dist/core/note-ingest.d.ts +34 -0
  45. package/dist/core/note-ingest.d.ts.map +1 -0
  46. package/dist/core/note-ingest.js +445 -0
  47. package/dist/core/note-ingest.js.map +1 -0
  48. package/dist/core/operations.d.ts +10 -1
  49. package/dist/core/operations.d.ts.map +1 -1
  50. package/dist/core/operations.js +129 -14
  51. package/dist/core/operations.js.map +1 -1
  52. package/dist/core/paths.d.ts.map +1 -1
  53. package/dist/core/paths.js.map +1 -1
  54. package/dist/core/schema-export.d.ts.map +1 -1
  55. package/dist/core/schema-export.js +10 -4
  56. package/dist/core/schema-export.js.map +1 -1
  57. package/dist/core/serializer.d.ts.map +1 -1
  58. package/dist/core/serializer.js +3 -0
  59. package/dist/core/serializer.js.map +1 -1
  60. package/dist/core/session-insight.d.ts +44 -0
  61. package/dist/core/session-insight.d.ts.map +1 -0
  62. package/dist/core/session-insight.js +216 -0
  63. package/dist/core/session-insight.js.map +1 -0
  64. package/dist/core/task-state-store.d.ts +4 -0
  65. package/dist/core/task-state-store.d.ts.map +1 -1
  66. package/dist/core/task-state-store.js +18 -5
  67. package/dist/core/task-state-store.js.map +1 -1
  68. package/dist/core/turn-signal.d.ts +22 -0
  69. package/dist/core/turn-signal.d.ts.map +1 -0
  70. package/dist/core/turn-signal.js +89 -0
  71. package/dist/core/turn-signal.js.map +1 -0
  72. package/dist/core/types.d.ts +12 -3
  73. package/dist/core/types.d.ts.map +1 -1
  74. package/dist/core/update-entrypoint.d.ts +19 -0
  75. package/dist/core/update-entrypoint.d.ts.map +1 -0
  76. package/dist/core/update-entrypoint.js +222 -0
  77. package/dist/core/update-entrypoint.js.map +1 -0
  78. package/dist/core/update-notice.d.ts +69 -0
  79. package/dist/core/update-notice.d.ts.map +1 -0
  80. package/dist/core/update-notice.js +188 -0
  81. package/dist/core/update-notice.js.map +1 -0
  82. package/dist/host-runtime/codex-session.d.ts +10 -0
  83. package/dist/host-runtime/codex-session.d.ts.map +1 -1
  84. package/dist/host-runtime/codex-session.js +1 -1
  85. package/dist/host-runtime/codex-session.js.map +1 -1
  86. package/dist/knowledge-graph.d.ts.map +1 -1
  87. package/dist/knowledge-graph.js +24 -3
  88. package/dist/knowledge-graph.js.map +1 -1
  89. package/dist/mcp/THIRD_PARTY_NOTICES.txt +2 -2
  90. package/dist/mcp/server.js +1079 -90
  91. package/dist/mcp/server.js.map +3 -3
  92. package/dist/skills-manifest.json +49 -24
  93. package/dist/transports/cli/cli.d.ts.map +1 -1
  94. package/dist/transports/cli/cli.js +7702 -5764
  95. package/dist/transports/cli/cli.js.map +3 -3
  96. package/dist/transports/http/server.d.ts.map +1 -1
  97. package/dist/transports/http/server.js +38 -27
  98. package/dist/transports/http/server.js.map +1 -1
  99. package/dist/transports/mcp/handlers.d.ts +25 -5
  100. package/dist/transports/mcp/handlers.d.ts.map +1 -1
  101. package/dist/transports/mcp/handlers.js +43 -5
  102. package/dist/transports/mcp/handlers.js.map +1 -1
  103. package/dist/transports/schemas.d.ts +4 -2
  104. package/dist/transports/schemas.d.ts.map +1 -1
  105. package/dist/transports/schemas.js +29 -3
  106. package/dist/transports/schemas.js.map +1 -1
  107. package/docs/platforms/README.md +1 -0
  108. package/docs/platforms/agent-messaging.md +22 -5
  109. package/package.json +17 -4
  110. package/scripts/check-plugin-hook-artifact.mjs +212 -0
  111. package/scripts/hooks/_generated/briefing-index.js +147 -0
  112. package/scripts/hooks/_generated/capture-liveness.js +454 -0
  113. package/scripts/hooks/_generated/update-notice.js +195 -0
  114. package/scripts/hooks/_shared.js +302 -14
  115. package/scripts/hooks/_stop-notes.js +504 -0
  116. package/scripts/hooks/auto-update-runner.mjs +22 -0
  117. package/scripts/hooks/decision-nudge.js +32 -5
  118. package/scripts/hooks/guard-check.js +30 -3
  119. package/scripts/hooks/post-commit.js +329 -133
  120. package/scripts/hooks/pre-compact.js +17 -2
  121. package/scripts/hooks/pre-edit-recall.js +32 -1
  122. package/scripts/hooks/session-start.js +361 -78
  123. package/scripts/hooks/session-summary.js +217 -41
  124. package/scripts/hooks/user-prompt-intent.js +89 -19
  125. package/scripts/lib/npm-bin.mjs +123 -0
  126. package/scripts/upgrade-plugin.sh +24 -0
  127. package/skills/memesh/SKILL.md +20 -8
  128. package/dist/cli/assets/d3.v7.min.js +0 -2
  129. package/dist/core/graph.d.ts +0 -26
  130. package/dist/core/graph.d.ts.map +0 -1
  131. package/dist/core/graph.js +0 -74
  132. package/dist/core/graph.js.map +0 -1
@@ -0,0 +1,123 @@
1
+ import { execFileSync, execSync } from 'node:child_process';
2
+
3
+ /**
4
+ * Run npm / npx from a build script, on every platform we support.
5
+ *
6
+ * Two separate Windows problems, and fixing only the first is what made this
7
+ * take two attempts:
8
+ *
9
+ * 1. npm ships on Windows as `npm.cmd`. `execFileSync('npm', …)` does not
10
+ * consult `PATHEXT` — that is a shell behaviour and execFile uses no
11
+ * shell — so it fails with `spawnSync npm ENOENT` while the identical
12
+ * command typed into a terminal works.
13
+ *
14
+ * 2. Naming it `npm.cmd` then fails with `spawnSync npm.cmd EINVAL`. Since
15
+ * the fix for CVE-2024-27980, Node refuses to spawn `.cmd` and `.bat`
16
+ * files without `shell: true`, because the Windows command interpreter
17
+ * re-parses the argument list. On Windows there is no shell-free way to
18
+ * invoke npm.
19
+ *
20
+ * So `shell: true` is required there, not a shortcut — and it is scoped to
21
+ * Windows, so macOS and Linux keep passing arguments as an array with no
22
+ * interpreter in the path at all.
23
+ *
24
+ * What `shell: true` costs is argument re-parsing, which matters only for
25
+ * arguments that are not literals. There is exactly one — the tarball name
26
+ * `npm pack` prints — and `assertSafeShellArg()` below is how it is made safe
27
+ * rather than assumed safe. Call it on anything that did not come from this
28
+ * repository's own source.
29
+ *
30
+ * Both scripts on the publish path had written this by hand:
31
+ *
32
+ * check-consumer-audit.mjs -> audit:prod -> verify:release -> prepublishOnly
33
+ * run-tests-isolated.mjs -> test:isolated -> prepublishOnly
34
+ *
35
+ * One owner, so a third caller cannot get it wrong a third way.
36
+ */
37
+ const isWindows = process.platform === 'win32';
38
+
39
+ export const NPM = isWindows ? 'npm.cmd' : 'npm';
40
+ export const NPX = isWindows ? 'npx.cmd' : 'npx';
41
+
42
+ /**
43
+ * Reject anything that could mean something to a command interpreter.
44
+ *
45
+ * Deliberately an allow-list. A deny-list of shell metacharacters has to be
46
+ * complete to be correct, and `cmd.exe` gives `%`, `^` and `&` meanings that a
47
+ * POSIX-shaped deny-list would miss.
48
+ */
49
+ export function assertSafeShellArg(value, what) {
50
+ // `:` and `~` are here for one reason: Windows absolute paths
51
+ // (`C:\Users\RUNNER~1\AppData\Local\Temp\...` — 8.3 short names carry the `~`,
52
+ // and that is literally what `os.tmpdir()` returns on a Windows runner).
53
+ // `smoke-packed-artifact.mjs` passes an absolute `os.tmpdir()` path to
54
+ // `npm pack --pack-destination` and to `npm install`, so without it
55
+ // `npm run test:packaged` throws on Windows before packing anything —
56
+ // fail-closed, but it means the packaged smoke test cannot run there at all.
57
+ // Neither has meaning to cmd.exe (`~` is a POSIX-shell nicety, and the POSIX
58
+ // branch never reaches here — it uses execFileSync with no shell at all).
59
+ // Every character that DOES mean something to cmd.exe (`%^&|<>"'` and
60
+ // whitespace) stays excluded.
61
+ if (typeof value !== 'string' || !/^[A-Za-z0-9._@:~\-+=/\\]+$/.test(value)) {
62
+ throw new Error(
63
+ `${what} is not a safe argument to pass through a shell: ${JSON.stringify(value)}`
64
+ );
65
+ }
66
+ return value;
67
+ }
68
+
69
+ /**
70
+ * Spawn `bin` with `args`.
71
+ *
72
+ * POSIX: no shell, arguments stay an array, nothing is re-parsed.
73
+ *
74
+ * Windows: every argument is validated, then the command line is built here and
75
+ * handed to `execSync`. Passing an ARRAY together with `shell: true` is
76
+ * deprecated (DEP0190) precisely because the arguments are concatenated without
77
+ * escaping — doing the concatenation ourselves, after checking each part, is
78
+ * the same operation with the check that makes it sound, and it does not print
79
+ * a deprecation warning on every release gate.
80
+ *
81
+ * The usual advice — "use execFile with an argument array, never build a shell
82
+ * string" — is right, and is what the POSIX branch does. It does not apply to
83
+ * the Windows branch because there is no execFile that works: npm is a `.cmd`,
84
+ * and Node refuses to exec one without a shell. The choice there is not
85
+ * array-vs-string, it is checked-vs-unchecked. Every argument reaching the
86
+ * concatenation has passed `assertSafeShellArg`, which is an allow-list, so no
87
+ * character with meaning to `cmd.exe` can be in one. `tests/consumer-audit-
88
+ * gate.test.ts` pins that, including the `%` and `^` forms a POSIX-shaped
89
+ * deny-list would miss.
90
+ */
91
+ function runSync(bin, args, opts) {
92
+ if (!isWindows) return execFileSync(bin, args, opts);
93
+ const safeArgs = args.map((arg, i) => assertSafeShellArg(arg, `${bin} argument ${i} (${arg})`));
94
+ return execSync([bin, ...safeArgs].join(' '), opts);
95
+ }
96
+
97
+ /** `npm <args>`, spawned correctly for the platform. */
98
+ export function npmSync(args, opts = {}) {
99
+ return runSync(NPM, args, opts);
100
+ }
101
+
102
+ /** `npx <args>`, spawned correctly for the platform. */
103
+ export function npxSync(args, opts = {}) {
104
+ return runSync(NPX, args, opts);
105
+ }
106
+
107
+ /**
108
+ * `baseEnv` with every spelling of `npm_config_cache` removed and the private
109
+ * cache set. Windows environment names are case-insensitive and Node keeps
110
+ * the lexicographically first of two keys that differ only in case (`N`
111
+ * before `n`); Vitest adds an upper-cased copy of every variable to its
112
+ * Windows workers. So `{ ...process.env, npm_config_cache }` handed npm the
113
+ * runner's `NPM_CONFIG_CACHE=C:\npm\cache` and never the private directory —
114
+ * measured on windows-latest with the fake npm in
115
+ * `tests/consumer-audit-gate.test.ts`.
116
+ */
117
+ export function envWithNpmCache(cacheDir, baseEnv = process.env) {
118
+ const env = Object.fromEntries(
119
+ Object.entries(baseEnv).filter(([key]) => key.toLowerCase() !== 'npm_config_cache'),
120
+ );
121
+ env.npm_config_cache = cacheDir;
122
+ return env;
123
+ }
@@ -91,6 +91,11 @@ MARKETPLACE_DIR="$CLAUDE_CONFIG_ROOT/plugins/marketplaces/pcircle-memesh"
91
91
  INSTALL_REGISTRY="$CLAUDE_CONFIG_ROOT/plugins/installed_plugins.json"
92
92
  CACHE_ROOT="$CLAUDE_CONFIG_ROOT/plugins/cache/pcircle-memesh/memesh"
93
93
  LOCK_DIR="$CACHE_ROOT.lock"
94
+ # Use the checker shipped beside this upgrade script, not a file newly staged
95
+ # from the target commit. This keeps upgrades from legacy marketplace commits
96
+ # testable and prevents a target archive from disabling its own validation.
97
+ UPGRADE_SCRIPT_DIR="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)"
98
+ PLUGIN_ARTIFACT_CHECKER="$UPGRADE_SCRIPT_DIR/check-plugin-hook-artifact.mjs"
94
99
 
95
100
  # ─── Pre-flight ────────────────────────────────────────────────────────────
96
101
  if [ ! -d "$MARKETPLACE_DIR" ]; then
@@ -514,6 +519,25 @@ echo "==> Installing runtime deps (this may take a minute)..."
514
519
  exit 1
515
520
  }
516
521
 
522
+ # Validate a real staged plugin before moving it into the live cache. The
523
+ # host registry may load hooks immediately after the swap; a manifest that
524
+ # names a missing script would otherwise surface as a frightening `127` in the
525
+ # user's next session. Tiny legacy marketplace fixtures (and genuinely old
526
+ # plugin archives) have no plugin wiring to validate, so preserve their
527
+ # historical cache-refresh behavior; once wiring is present, the checker is
528
+ # mandatory and fail-closed. The checker itself comes from this script's
529
+ # installed release, never from the target archive being validated.
530
+ if [ -f "$STAGE_PATH/hooks/hooks.json" ] || [ -f "$STAGE_PATH/.claude-plugin/plugin.json" ] || [ -f "$STAGE_PATH/.codex-plugin/plugin.json" ]; then
531
+ if [ ! -f "$PLUGIN_ARTIFACT_CHECKER" ]; then
532
+ echo "ERROR: plugin artifact checker is missing beside the upgrade script — the live cache at $NEW_INSTALL_PATH was not touched" >&2
533
+ exit 1
534
+ fi
535
+ if ! node "$PLUGIN_ARTIFACT_CHECKER" --root "$STAGE_PATH" --skip-pack; then
536
+ echo "ERROR: staged plugin artifact integrity check failed — the live cache at $NEW_INSTALL_PATH was not touched" >&2
537
+ exit 1
538
+ fi
539
+ fi
540
+
517
541
  # ─── 5. Swap the staged copy in ───────────────────────────────────────────
518
542
  if [ -e "$NEW_INSTALL_PATH" ] || [ -L "$NEW_INSTALL_PATH" ]; then
519
543
  HAD_LIVE_CACHE=1
@@ -28,14 +28,14 @@ All examples below use CLI. MCP tools accept the same parameters as JSON objects
28
28
  | Tool | Purpose |
29
29
  |---|---|
30
30
  | `work_package` | Prepare one bounded untrusted `digest` (calendar cluster) or `transcript` package from the newest Claude Code session under the client's single matching MCP workspace root; submit exactly one strict result or defer. Submit only stages pending human review and retains bounded redacted source turns for comparison; agents cannot apply or reject. No hidden reasoning, raw transcript, transcript path, API key, LLM, embedding, or vector data is exposed or used; hashes identify freshness and workspace scope rather than authentication. |
31
- | `remember` | Store knowledge as an entity with observations, tags, and relations |
31
+ | `remember` | Store knowledge as an entity with observations, tags, and relations; `note` (free text) derives title/observations/name; `replace: true` rewrites a named memory, keeping history |
32
32
  | `recall` | Search stored knowledge; empty query lists recent memories |
33
33
  | `forget` | Archive an entity or remove one exact observation |
34
34
  | `export` | Export memories as portable JSON |
35
35
  | `import` | Import a JSON export with the required skip, append, or overwrite strategy |
36
36
  | `learn` | Record a structured lesson with error, fix, root cause, and prevention |
37
37
  | `task_state` | Read or update user-stated goal, next step, blocker, and finished work |
38
- | `briefing` | Assemble the current project's work topology |
38
+ | `briefing` | Assemble the current project's work topology, closing with a capped index of its durable memories |
39
39
  | `user_patterns` | Analyze work schedule, tool preferences, and focus areas |
40
40
  | `improvement` | Propose an evidence-linked product improvement or read its status; only a human may accept or reject it |
41
41
  | `message` | Discover live agents in one project, then contact one exact recipient with a bounded, untrusted payload. Native size and availability failures are distinct; acceptance, discovery, polling, and fetching do not acknowledge |
@@ -101,6 +101,8 @@ Call the `briefing` MCP tool or run `memesh briefing`. It returns the assembled
101
101
  work topology: where the work was left off (goal / next / blocked / done),
102
102
  decisions and direction, lessons not to repeat, what is known, recent activity.
103
103
  One call is cheaper than re-exploring the repo to reconstruct the same picture.
104
+ `memesh briefing --index` returns only the index of durable memories — what is
105
+ known here, one line each, without the ranked sections.
104
106
  Generic briefing and SessionStart context do not report unread durable messages:
105
107
  they have no recipient identity. If you already know the exact logical
106
108
  recipient, pass `recipient` with `project` (MCP) or use
@@ -154,7 +156,7 @@ With the Claude Code plugin, the first eight rows happen **without any action fr
154
156
  | **UserPromptSubmit** | When you submit a prompt | Detects "remember this" intent (5 languages) and reminds Claude to use memesh |
155
157
  | **PostToolUse (Bash)** | After `git commit` | Auto-tracks the commit with diff stats as a memory entity |
156
158
  | **PostToolUse (ExitPlanMode/AskUserQuestion)** | A plan is approved or you answer a question | Reminds Claude to `remember` the decision if it's worth keeping — once per tool per session |
157
- | **Stop** | Session ends | Auto-captures session knowledge and applies the configured update policy |
159
+ | **Stop** | Session ends | Auto-captures session knowledge, ingests the project's Claude Code memory directory (frontmatter notes → `source:note-file` memories), shows one line when the turn made a decision-shaped move and stored no memory, and applies the configured update policy. The two writes (session capture, note-directory ingestion) stop when auto-capture is off (`memesh config set autoCapture false` / `MEMESH_AUTO_CAPTURE=false`); the advisory line still runs |
158
160
  | **PreCompact** | Before context compaction | Saves important knowledge before history is compressed |
159
161
  | **PreToolUse (Bash)** | Before a command runs | Fires accepted lesson-guards — warns when a recorded mistake is about to repeat |
160
162
  | **SessionStart/SessionEnd (Codex)** | An ordinary Codex CLI plugin session starts, resumes, or ends | Launches the detached exact-thread companion, replaces its generation on resume, and retires it after the bounded idle queue window; a matching owner-private config may override its project/principal |
@@ -174,7 +176,8 @@ and retiring outdated info.
174
176
  | Situation | Action |
175
177
  |-----------|--------|
176
178
  | User states what they're working on / what's next / what's blocking | `memesh task --goal "…"` / `--next "…"` / `--blocked "…"` |
177
- | Design decision made | `memesh remember --name "auth-choice" --type decision --obs "Use OAuth 2.0 with PKCE" --tags "project:myapp"` |
179
+ | Design decision made | `memesh remember "Use OAuth 2.0 with PKCE for the API" --type decision --tags "project:myapp"` (or `remember({ note })` over MCP) |
180
+ | A stored memory is wrong | `memesh remember --name "auth-choice" --obs "the corrected fact" --replace` — the memory keeps its type and the old version moves to `metadata.replaced_history` (add `--type` only to reclassify it) |
178
181
  | Bug fixed | `memesh learn --error "what broke" --fix "what fixed it" --root-cause "why" --severity major` |
179
182
  | Starting work on a feature | `memesh recall "feature-name" --json` |
180
183
  | User asks "what did we decide?" | `memesh recall "topic" --tag "project:myapp"` |
@@ -211,7 +214,13 @@ memesh remember \
211
214
  Use a **stable name** (`db-choice`, not `db-choice-2026-08-16`): reusing the
212
215
  name appends to the same entity instead of scattering duplicates. `--title` is
213
216
  the human-readable headline; the name stays the machine key. If this replaces
214
- an older decision, add `--supersedes "old-db-choice"`.
217
+ an older decision, add `--supersedes "old-db-choice"`. To correct it instead
218
+ of adding to it, repeat the call with `--replace`.
219
+
220
+ Quicker when the text is all you have: `memesh remember "SQLite for local-first
221
+ storage"` (MCP: `remember({ note: "…" })`). The first line becomes the title,
222
+ each following paragraph an observation, and the name is derived from the text,
223
+ so repeating the same text does not create a duplicate.
215
224
  Types: `decision` `pattern` `lesson_learned` `bug_fix` `architecture` `convention` `feature` `best_practice` `concept` `tool` `note`
216
225
 
217
226
  ### You need context on a specific topic
@@ -245,9 +254,12 @@ memesh reindex --fts # rebuild the local keyword index
245
254
 
246
255
  ## Memory hygiene
247
256
 
248
- 1. **Stable names append.** Remembering under an existing name adds
249
- observations and dedupes tags it never replaces the entity. Reuse the
250
- name to grow one memory; do not mint `-v2` / dated variants of it.
257
+ 1. **Stable names append — unless you ask to replace.** Remembering under an
258
+ existing name adds observations and dedupes tags by default. Pass
259
+ `replace: true` (CLI: `--replace`) to rewrite the entity's observations,
260
+ tags and title instead — the previous version moves to
261
+ `metadata.replaced_history`, not lost. Reuse the name to grow or correct
262
+ one memory; do not mint `-v2` / dated variants of it.
251
263
  2. **`supersedes` retires the loser.** When a new memory replaces an old one,
252
264
  record it with `--supersedes <old-name>` (MCP: a relation of type
253
265
  `supersedes`). The old entity is archived — recoverable, out of recall.