panatgithub_AnkiHeadingSync/docs/card-answer-cutoff-decisions.md
Dusk 4052eff0e7 feat: 新增 cardAnswerCutoffMode 卡片正文截止模式,支持 heading-block / double-blank-lines,并统一 marker/GI 写回归整规则
feat: add cardAnswerCutoffMode with heading-block / double-blank-lines and unify marker/GI writeback normalization.
2026-04-23 10:16:41 +08:00

120 lines
No EOL
4.9 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Card Answer Cutoff Decisions
Date: 2026-04-23
## Decision 1: Add a new explicit settings enum
- Add `cardAnswerCutoffMode` to `PluginSettings` as:
- `heading-block`
- `double-blank-lines`
- Default value is `heading-block`.
- Validation rejects anything else.
Reason:
- This matches the plan and keeps the new behavior fully explicit in persistence, tests, and fingerprint invalidation.
## Decision 2: Use one shared boundary helper for all three parsing routes
- Introduce a shared helper under manual-sync parsing services.
- The helper will accept:
- source lines for the current region
- absolute start line
- fallback line for empty content
- cutoff mode
- marker matcher/parser callbacks
- The helper will return at least:
- `contentLines`
- `trailingLines`
- `contentEndLine`
- `markerLine`
- `markerIndent`
- marker parse result when valid
- marker presence state
Reason:
- The actual repository currently duplicates this logic three times. Consolidation is the smallest change that enforces plan-wide consistency.
## Decision 3: Marker precedence scans the whole region, not only the last non-empty line
- The helper will search for the first valid marker candidate inside the region.
- A valid marker always wins over blank-line cutoff.
- Only valid markers lock the cutoff boundary.
- Invalid marker candidates do not lock the boundary.
- If no valid marker exists and mode is `double-blank-lines`, the first run of 2 or more consecutive blank lines ends the content.
- If neither applies, fallback remains the full heading block / child region / group block.
Reason:
- The plan requires old layout compatibility and new layout support where marker/GI is moved before remarks.
## Decision 4: Preserve current hashing semantics except for intentional cutoff changes
- Normal QA/Cloze `rawBlockText` stays `heading + trimmed content lines`.
- Semantic QA `rawBlockText` stays `semantic-qa child identity + parent display title + child label + bodyMarkdown`.
- QA Group `rawBlockText` stays based on stem, parsed items, and normalized body lines.
- The only intended hash shifts are those caused by the new cutoff rule excluding remarks/trailing content from the answer region.
Reason:
- This keeps state recovery behavior as stable as possible while still honoring the new contract.
## Decision 5: Normalize marker/GI writeback with a shared blank-tail routine
- Card and group marker services will share a common normalization helper.
- The writeback contract is:
- trim blank lines immediately after the answer region
- remove existing marker line when replacing
- insert the new marker at `contentEndLine`
- remove any blank lines between marker and trailing content
- if trailing non-blank content exists, insert exactly two blank lines after the marker
- preserve trailing non-blank content exactly as scanned
- QA Group writeback will continue to strip legacy inner ID markers.
Reason:
- The current services already do most of this. Sharing the normalization step reduces divergence and makes the plans rule explicit.
## Decision 6: Thread cutoff mode through indexing context only
- Add the setting to `CardIndexingContext`.
- `FileIndexerService` passes it into `CardIndexingService.index()` for both vault and single-file indexing.
- No rendering-layer contract changes are needed.
Reason:
- The feature affects indexing and writeback placement, not render output formatting.
## Decision 7: Put cutoff mode into the deck-rules fingerprint path
- Update `createDeckRulesFingerprint()` to include `cardAnswerCutoffMode`.
- Keep the existing fingerprint path rather than adding a parallel reindex fingerprint.
Reason:
- The repository already uses this fingerprint to force rereads on unchanged files. Reusing it is the smallest compatible integration.
## Decision 8: Keep the settings UI shape consistent with the repository
- Add one dropdown setting labeled with the two cutoff modes.
- Add concise zh/en descriptions that mirror the user-facing semantics from the plan.
- Cover both locales in existing settings tab tests.
Reason:
- The existing settings page relies on dropdown/toggle controls and is already tested that way.
## Decision 9: Test coverage will be expanded at the service level first
- Primary behavior tests go into:
- `CardIndexingService.test.ts`
- `SemanticQaListParser.test.ts`
- `CardMarkerService.test.ts`
- `GroupMarkerService.test.ts`
- `FileIndexerService.test.ts`
- `ManualSyncService.test.ts`
- `PluginSettings.test.ts`
- `PluginSettingTab.test.ts`
- Add QA Group parser/service tests only where the cutoff or writeback behavior actually changes.
Reason:
- These files already exercise the real runtime path and minimize new test scaffolding.
## Confirmed Non-Goals
- No expansion of QA Group answer modeling beyond the existing “first second-level item” contract.
- No new sync pipeline or new persistence store shape.
- No unrelated deck, render, or note-field-mapping refactor.