mirror of
https://github.com/panatgithub/AnkiHeadingSync.git
synced 2026-07-22 06:51:43 +00:00
feat: add cardAnswerCutoffMode with heading-block / double-blank-lines and unify marker/GI writeback normalization.
120 lines
No EOL
4.9 KiB
Markdown
120 lines
No EOL
4.9 KiB
Markdown
# 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 plan’s 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. |