Skip to content

fix(ctx_memory): honor category in update - #438

Merged
ualtinok merged 5 commits into
cortexkit:masterfrom
G0-0000:fix/ctx-memory-update-category
Sep 12, 2026
Merged

fix(ctx_memory): honor category in update#438
ualtinok merged 5 commits into
cortexkit:masterfrom
G0-0000:fix/ctx-memory-update-category

Conversation

@G0-0000

@G0-0000 G0-0000 commented Sep 11, 2026

Copy link
Copy Markdown

Fixes #436

Summary

ctx_memory update accepted category in the tool schema but never wrote it. The UPDATE statement only set content / normalized_hash / updated_at, and three follow-up sites still used the stored category.

Root cause: updateMemoryContentInCurrentTransaction never received a target category, so duplicate hashing, queueMemoryMutation, and the success echo all stayed on memory.category.

Fix (TS path):

  • A valid v2 category (PROJECT_RULES / ARCHITECTURE / CONSTRAINTS / CONFIG_VALUES / NAMING) retargets the row.
  • Omitted or invalid category keeps the current category (backward compatible).
  • Duplicate check, mutation log, and Updated memory [ID: …] in ${…} all use the target category.
  • Schema description now states that update may recategorize; omit to keep.

Tests

Four new cases in packages/plugin/src/tools/ctx-memory/tools.test.ts:

  • valid category persists
  • omitted category keeps the current class
  • invalid category falls back to the current class
  • content rewrite still succeeds in both recategorize and omit paths

Local gates:

  • bun run typecheck passed
  • bun run lint passed (pre-existing pi-plugin warning only)
  • bun run build passed
  • packages/plugin ctx-memory suite: 76/76 passed

Scope

TypeScript packages/plugin path only. When authorityState === "MODULE", update still delegates to the private Rust module; that path is unchanged and should be followed up separately for parity.

Prompt-surface A1 golden and docs/specs/prompt-surface/budget-fixture.json were updated only because the category parameter description changed (serialized schema 840/201 → 912/216 tokens).

Live validation

Against pi-magic-context 0.41.4 with the same semantics locally:

  • valid category on update → persisted category changes
  • omitted category → category unchanged
  • invalid category → category unchanged
  • content-only update → content rewritten

Residual / Note

Local full bun run test (plugin --parallel --timeout 30000, same as CI check-plugin) twice hit two unrelated timeouts under parallel load:

  • AFT warm inventory sends only boundary-owned seeds with one raw batch (~43s vs 7.8s alone)
  • createTransform > hydrates only dropped rows for visible-target replay with 98% active tags (~37s vs 11.9s alone)

This change does not touch those tests. Isolated reruns passed. typecheck / lint / build and the ctx-memory 76/76 suite all passed.


View with [code]smith Autofix with [code]smith
Need help on this PR? Tag @codesmith-bot with what you need. Autofix is disabled.


Summary by cubic

Makes ctx_memory update honor the category argument so a valid v2 category recategorizes the row, and surfaces that category in memory-updates deltas.

  • Omitted or invalid category keeps the current one, so existing callers are unaffected.
  • Duplicate detection runs inside the same transaction against the stored path; a unique-constraint race falls back to the friendly duplicate error across bun and node sqlite error shapes.
  • <updated> elements carry a category attribute in the TypeScript, pi-plugin, and Rust renderers.
  • The schema now says update may recategorize; omit category to keep the current one.
  • Tests cover valid, omitted, invalid, content-only, legacy raw-path, and constraint-race recategorization paths.
  • The Rust module's update execution still doesn't write the category; that parity follow-up remains.

Written for commit b8a8648. Summary will update on new commits.

Review in cubic

Greptile Summary

This PR makes TypeScript ctx_memory update persist valid category changes and consistently use the resulting category for duplicate detection, mutation logging, rendering, and the success response.

  • Keeps the existing category when the argument is omitted or invalid.
  • Performs duplicate detection against the row’s stored project path inside the update transaction.
  • Converts supported SQLite uniqueness races into the established duplicate-memory response.
  • Adds category attributes to update deltas across TypeScript, pi-plugin, and Rust renderers.
  • Expands coverage for recategorization, legacy paths, rollback behavior, and adapter-specific constraint errors.

Confidence Score: 5/5

The PR appears safe to merge; no actionable regression remains in the changes since the previous review.

The previously reported legacy-path duplicate failure and adapter-specific uniqueness fallback findings are resolved, and the latest fallback recognizes remapped or absent SQLite codes without swallowing unrelated current transaction errors.

Important Files Changed

Filename Overview
packages/plugin/src/tools/ctx-memory/tools.ts Persists update-time recategorization and handles duplicate checks and uniqueness races consistently.
packages/plugin/src/tools/ctx-memory/tools.test.ts Adds coverage for category persistence, legacy stored paths, duplicate handling, rollback, and SQLite error-shape compatibility.
packages/plugin/src/hooks/magic-context/inject-compartments.ts Includes escaped categories on ordinary update delta elements while excluding the internal visibility marker.
packages/pi-plugin/src/inject-compartments-pi.ts Mirrors categorized update-delta rendering in the pi-plugin implementation.
crates/mc-module/src/memory_render.rs Mirrors categorized update-delta rendering in Rust with XML attribute escaping and visibility-marker filtering.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A[ctx_memory update] --> B[Load active memory]
    B --> C{Valid v2 category supplied?}
    C -->|Yes| D[Use supplied category]
    C -->|No| E[Keep stored category]
    D --> F[BEGIN IMMEDIATE]
    E --> F
    F --> G{Duplicate on stored path/category/hash?}
    G -->|Yes| H[Return friendly duplicate error]
    G -->|No| I[Update content, category, and hash]
    I --> J[Queue categorized mutation]
    J --> K[Commit]
    K --> L[Render updated element with category]
Loading

Reviews (5): Last reviewed commit: "fix(ctx_memory): recognize constraint er..." | Re-trigger Greptile

Comment thread packages/plugin/src/tools/ctx-memory/tools.ts Outdated

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No issues found across 4 files

Re-trigger cubic

@G0-0000

G0-0000 commented Sep 11, 2026

Copy link
Copy Markdown
Author

Fixed the Greptile P1 on packages/plugin/src/tools/ctx-memory/tools.ts (legacy duplicate lookup).

Duplicate detection now uses the row's actual stored project_path (raw or already-normalized) so it matches the UPDATE scope, which leaves that path unchanged. Recategorizing a legacy raw-path memory onto an existing (project_path, category, normalized_hash) collision therefore returns the duplicate-memory error instead of throwing the uniqueness constraint.

Added two regression tests for the legacy raw-path case (duplicate rejected; recategorize succeeds when no same-content row exists). bun run typecheck, bun run build, and bun test src/tools/ctx-memory/tools.test.ts all passed (78 tests).

@magic-alfonso magic-alfonso Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, G0-0000, for implementing category retargeting and for the follow-up that aligns the legacy raw-path duplicate lookup with the stored uniqueness key. The main update behavior, the mutation-log category, the targeted ctx-memory suite, the full plugin suite, typecheck, and the light-preset budget (1822/1825) all check out on your current head merged onto master.

Three merge blockers, each from an executed probe:

  1. Please move the target-category duplicate lookup inside the same BEGIN IMMEDIATE transaction as the update/log write, and keep a friendly unique-constraint fallback. A race probe currently rejects with the raw UNIQUE constraint failed: memories.project_path, memories.category, memories.normalized_hash. The same hole applies to legacy rows stored under a raw project_path (the lookup uses the normalized identity while the row keeps the raw path), which greptile also flagged.

  2. Please make <memory-updates> carry the new category. The log records CONSTRAINTS, but a CONFIG_VALUES → CONSTRAINTS probe renders only <updated id="1">new category fact</updated>, so an agent reading the delta never learns the memory moved. We will carry the Pi and Rust renderer twins on our side after merge.

  3. Please rerun export-agent-surface.ts and commit its complete output: the golden heading still says ctx_memory params ~201 / total ~435, while the generator emits ~216 / ~450.

Hygiene: the branch now has two commits authored g0 <g0@localhost> with no trailer. We squash-merge, so this is not blocking; add your intended identity if you want it on the merge commit.

Once these land we run one more adversarial review pass on the PR and merge. Thanks again — the scoped implementation is close.

@G0-0000

G0-0000 commented Sep 11, 2026

Copy link
Copy Markdown
Author

Addressing the three merge blockers:

  1. Target-category duplicate lookup now shares the same BEGIN IMMEDIATE transaction as the update/log write, with a UNIQUE-constraint-friendly fallback if a concurrent insert still races the probe. Recategorizing onto an existing duplicate returns the existing duplicate-memory error instead of UNIQUE constraint failed: memories.project_path, memories.category, memories.normalized_hash (including legacy rows stored under a raw project_path). Coverage: rejects recategorizing onto an existing duplicate without throwing a constraint plus a prepare-hijack mock that forces the unique-constraint fallback (returns a friendly duplicate error after a unique-constraint fallback).

  2. <memory-updates> now carries the new category on <updated> (<updated id="1" category="CONSTRAINTS">new category fact</updated>). The OpenCode renderer, Pi renderer twin, and Rust renderer twin all emit the same attribute; memory-update-delta-parity.json is updated with them. Visibility-only mutations (__mc_visibility__) still omit the attribute.

  3. packages/plugin/scripts/export-agent-surface.ts was rerun; its complete output matches prompt-surface-a1-golden.md (473 lines, including the ctx_memory heading ~216 / ~450). The regenerated file is committed.

Hygiene: squash-merge is fine as-is. Identity remains g0 <g0@localhost> unless you want a different author on the merge commit.

Landed on 60956fd63e2714b588c37b50ec4181c8aef70482. Plugin tests: 149 pass / 0 fail across tools.test.ts + inject-compartments.test.ts. bun run typecheck and bun run build both green.

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All reported issues were addressed across 8 files (changes from recent commits).

Tip: Review your code locally with the cubic CLI to iterate faster.

Re-trigger cubic

Comment thread packages/plugin/src/tools/ctx-memory/tools.ts Outdated
Comment thread crates/mc-module/src/memory_render.rs
Comment thread packages/plugin/src/hooks/magic-context/inject-compartments.ts Outdated
@G0-0000

G0-0000 commented Sep 11, 2026

Copy link
Copy Markdown
Author

Addressed the three cubic-dev-ai notes on 60956fd:

  • P2 (tools.ts UNIQUE fallback): narrowed to an exact SQLITE_CONSTRAINT_UNIQUE code match, matching the existing store/tagger style so non-unique failures (authority refusal, etc.) are no longer reported as duplicates.
  • P3 ×2 (memory_render.rs, inject-compartments.ts): both sentinel checks now reuse MEMORY_VISIBILITY_MUTATION_CATEGORY (Rust via mc_store; TS via the existing mutation-log export).

Gates: bun run typecheck, bun run build, and bun test src/tools/ctx-memory/tools.test.ts src/hooks/magic-context/inject-compartments.test.ts (149 pass).

Comment thread packages/plugin/src/tools/ctx-memory/tools.ts

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All reported issues were addressed across 5 files (changes from recent commits).

Tip: Review your code locally with the cubic CLI to iterate faster.

Re-trigger cubic

Comment thread packages/plugin/src/tools/ctx-memory/tools.ts Outdated
@G0-0000

G0-0000 commented Sep 11, 2026

Copy link
Copy Markdown
Author

Layered unique-constraint detection: exact SQLITE_CONSTRAINT_UNIQUE plus a guarded UNIQUE constraint failed message fallback. This reconciles cubic's P2 (don't swallow non-unique errors) with Greptile's P1 (recognize node:sqlite shapes that omit or remap the code). Added tests for the remapped-code message path and a negative authority-error case that must rethrow rather than map to duplicate.

ualtinok added a commit that referenced this pull request Sep 12, 2026
Co-authored-by: Alfonso <alfonso-magic-context@users.noreply.github.com>
@ualtinok
ualtinok merged commit b98cdd3 into cortexkit:master Sep 12, 2026
5 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

ctx_memory update ignores category (schema description misleading)

2 participants