Files
LexAI/docs/LESSONS_LEARNED.md
john kevin asprec 2a2fecbfdd
Some checks failed
CI — Test & Build / Test & Build (push) Has been cancelled
docs: add changelog-accuracy lesson and pre-tag eval
2026-08-12 07:54:03 +08:00

5.0 KiB
Raw Blame History

Lessons learned — LexAI

Evidence-backed invariants and guardrails for this codebase. Not a transcript or issue tracker. The one-line active rules live in CLAUDE.md## Lessons; the detail lives here.

Active guardrails

CLAUDE.md## Lessons is the canonical active list loaded every session. The entries below are the established codebase invariants (from Phase 1 and the 2026-07-13 code read) that break things silently when violated.

L-CORE-01 — onMessage listener must return true

  • Root cause / failure boundary: async provider responses need the message channel held open; a listener that doesn't return true drops every response with no error.
  • Prevention: never remove return true from the chrome.runtime.onMessage handler in background.ts.
  • Eval: manual (candidate: a unit test asserting the listener returns true).

L-CORE-02 — Snapshot selection before any await

  • Root cause / failure boundary: focus shifts to the toolbar and the live selection is gone by the time an async response returns.
  • Prevention: in content.ts, capture active element + offsets eagerly (mouseup + button mousedown) and snapshot before awaiting; Replace uses the snapshot. Handle textarea/input (selectionStart/End) and contenteditable/DOM (Range API).
  • Eval: E-BASE-04 manual; DOM test tracked in TASKS #10.

L-CORE-03 — Keep both ANALYZE_TEXT message shapes

  • Root cause / failure boundary: callers send both { payload: {…} } and flat { text, action, style }; dropping either breaks a call path. fix normalizes to grammar.
  • Prevention: if you touch the handler, keep both shapes and the action normalization.

L-CORE-04 — Preserve the data-lexai="true" guard

  • Root cause / failure boundary: without it, LexAI's own injected UI re-triggers selection/click handlers.
  • Prevention: set data-lexai="true" on every injected node; handlers skip target.closest('[data-lexai="true"]').

L-CORE-05 — Never expose the API key; keep the plaintext fallback

  • Root cause / failure boundary: the key is a user secret; and legacy installs still have plaintext apiKey.
  • Prevention: prefer apiKeyEnc + encKey; never log the key; never send it anywhere except the user's selected provider endpoint; don't drop the plaintext apiKey fallback without a migration.

L-CORE-06 — Provider code is duplicated (callX + callXWithPrompt)

  • Root cause / failure boundary: each provider has two near-identical functions; a request-shape change to one silently diverges from the other.
  • Prevention: update both until the layer is refactored (TASKS #4). Keep error handling uniform (network → friendly string; !res.ok → provider message; empty → explicit message).

L-CORE-07 — Content script / popup must not call providers

  • Root cause / failure boundary: CORS and key handling belong in the service worker; a direct provider fetch from content/popup leaks the key path and fails CORS.
  • Prevention: route everything through ANALYZE_TEXT / COPY_AS to background.ts.

L-CORE-08 — Version lives in two files

  • Root cause / failure boundary: manifest version comes from wxt.config.ts; package.json has its own — they drift and have caused git churn.
  • Prevention: bump version in both package.json and wxt.config.ts (until T-16 single-sources it). A v*.*.* tag triggers the CWS deploy.

L-CORE-09 — UI is inline styles; Tailwind is inactive

  • Root cause / failure boundary: Tailwind is installed but WXT PostCSS was never wired; Tailwind classes silently do nothing.
  • Prevention: style with inline objects and the existing dark palette; don't add Tailwind classes unless the task is explicitly to wire PostCSS.

L-RELEASE-01 — Verify CHANGELOG against code before tagging

  • Root cause / failure boundary: release notes authored from commit subjects and handoff summaries are not facts; two false claims in v1.1.0 CHANGELOG were caught pre-tag: (1) off-by-one count of actions (12 … plus Auto when auto is one of 12), (2) feature listed for 1.0.1 that doesn't exist in code (commit subject claimed it but Options.tsx has no such tab).
  • Prevention: before git tag v*.*.*, verify at least 23 user-visible changes claimed in CHANGELOG against the actual code diff or feature. Check version in CHANGELOG matches package.json.
  • Eval: E-RELEASE-01.

Recording policy

Add a lesson only after a material, evidenced learning signal (correction, unexpected failure, regression, rejected review, proven wrong assumption). Each needs a durable prevention; link a deterministic eval when possible. No secrets, credentials, personal data, or raw transcripts.

Lesson template

### L-YYYY-MM-DD-NN — [short imperative guardrail]
- **Status:** active | archived | superseded by [ID]
- **Trigger / Root cause / Prevention / Evidence / Eval / Owner-review**

Archive

Historical lessons move here with their original IDs and a one-line archival reason.