Commit Graph

9 Commits

Author SHA1 Message Date
Ralph Chang 4309cb855f fix: promotion accounting, sessionID extraction, and strengthened regression tests
Architecture review fixes:

- Promotion accounting: only clear pending memories that survived
  workspace memory normalization/cap limits. Use retainedKeys from
  the returned normalized store instead of attemptedKeys.

- Shared sessionID extraction: add sessionIDFromEventProperties()
  helper and use it in both session.compacted and session.deleted,
  fixing the previous gap where session.deleted only read info.id.

- Strengthen compaction refresh test: seed workspace memory before
  first transform so firstSystem1 is non-empty, then assert
  refreshed system[1] preserves existing entries AND contains
  promoted memories.
2026-04-27 10:02:18 +08:00
Ralph Chang 2437a9dc71 fix: clarify cache epoch semantics and add regression tests
- Update plugin.ts comments to describe 'session cache epoch' instead
  of misleading 'session lifetime' wording
- Add regression test: same-session explicit memory does not mutate
  frozen system[1]; pending memory goes to ephemeral system[2+]
- Add regression test: session.compacted intentionally refreshes
  system[1] as a new cache epoch boundary (promotes pending memories,
  clears frozen cache, next transform re-renders workspace memory)
- Both tests use one plugin instance with mutable mock client to
  preserve in-memory frozen cache across turns
2026-04-27 09:55:03 +08:00
Ralph Chang e7c7a5cfb2 feat: add durable pending memory journal 2026-04-27 02:20:26 +08:00
Ralph Chang 026c75a5e4 feat: freeze rendered workspace memory snapshot 2026-04-27 01:57:41 +08:00
Ralph Chang 5e9ada6859 fix: replace default compaction template to prevent purple italic rendering
Root cause: OpenCode's default compaction template uses --- separators.
When our plugin adds structured context (Memory candidates: format), the
model strictly follows the template, outputting --- at position 0. The
markdown textmate grammar treats this as YAML frontmatter, applying the
'comment' syntax scope (purple + italic in themes like palenight).

Fix: Set output.prompt in the compacting hook to replace the entire
template with a ---free version. Uses only ## Markdown headings and
explicitly forbids YAML frontmatter, horizontal rules, and delimiter
lines. Preserves context from other plugins by merging output.context.

- Replace compactionContextHeader() with buildCompactionPrompt()
- Set output.prompt instead of pushing to output.context
- Merge existing output.context from other plugins before clearing
- Add 'Instructions' section to the template (per architect review)
- Update tests: verify output.prompt, ---free format, context merging
2026-04-26 15:46:41 +08:00
Ralph Chang 721544e7a8 fix: use plain text labels instead of Markdown headers
- Changed '## Memory Candidates' to 'Memory candidates:' in compaction context
- Changed '## Pending Todos' to 'Pending todos:' in todo rendering
- Updated extractCandidateBlock() to parse plain text format (primary)
- Removed stripXmlTags() function (no longer needed)
- All 42 tests pass

Root cause: Markdown headings (##) render as purple in OpenCode UI,
same issue as XML tags and HTML comments. Plain text labels avoid
all special markup rendering.
2026-04-26 15:13:58 +08:00
Ralph Chang eff0d3784c fix: change compaction output to HTML comment, prevent Markdown rendering issues
Root cause: Model was instructed to output <workspace_memory_candidates> XML
tags in the user-visible compaction summary, causing purple/italic rendering
when combined with --- delimiters in Markdown.

Fixes:
- compactionContextHeader(): Now instructs model to use HTML comment format
  <!-- workspace_memory_candidates ... --> which is hidden from users
- extractCandidateBlock(): New function supports 3 formats:
  1. HTML comment (preferred, hidden from user)
  2. Markdown section (visible but clean)
  3. Legacy XML (backward compatible)
- Added "DO NOT use XML tags" and "DO NOT start with ---" instructions

Tests:
- Verify compaction context header uses HTML comment format
- Test parser accepts all 3 formats (HTML comment, Markdown, legacy XML)
2026-04-26 14:49:38 +08:00
Ralph Chang 92e90124de fix: prevent XML tags in compaction context from causing Markdown rendering issues
- Add stripXmlTags() to convert <workspace_memory>, <hot_session_state>, <pending_todos> to Markdown headers for compaction context
- Add [PRIVATE COMPACTION CONTEXT - DO NOT OUTPUT] wrapper to prevent model from copying input context to output
- Rename renderTodos to renderTodosForCompaction for clarity
- Add test to verify compaction context contains no XML tags

This fixes the issue where compaction summary would render with purple italic text
due to --- delimiters interacting with XML-like tags in Markdown.
2026-04-26 14:34:55 +08:00
Ralph Chang 1bba0511bb fix: PR-1 memory plugin quality fixes
## Task 1: Fix exitCode undefined false positive
- Add `typeof exitCode !== "number"` check in plugin.ts
- Only extract errors when exitCode is explicitly non-zero
- Prevent git-log/cat with "errors" text from creating false positives

## Task 2: Fix workspace memory XML truncation
- Budget-aware line-by-line rendering
- Always include closing </workspace_memory> tag
- Return empty string when budget too small
- Bonus: canonical exact deduplication with source priority

## Task 3: Remove "always" as trigger
- Replace "always" with "going forward" in patterns
- Add word boundary via `g` flag and matchAll loop
- "from now on" still works as expected

## Task 4: Verification
- 22 tests passing
- typecheck passing

Tests cover:
- git log/cat with loose "errors" ignored
- TS2345/TypeError strong signals captured
- undefined exitCode: no create, no clear
- exitCode 0: clears errors
- exitCode non-zero: creates error
- XML never truncated mid-tag
- "always" not a trigger
2026-04-26 12:52:21 +08:00