Skip to content

feat(capture): ordered create-if-not-found location for reverse-chrono logs (#481)#1365

Merged
chhoumann merged 3 commits into
masterfrom
chhoumann/481-reverse-chrono-daily-log
Jun 16, 2026
Merged

feat(capture): ordered create-if-not-found location for reverse-chrono logs (#481)#1365
chhoumann merged 3 commits into
masterfrom
chhoumann/481-reverse-chrono-daily-log

Conversation

@chhoumann

@chhoumann chhoumann commented Jun 16, 2026

Copy link
Copy Markdown
Owner

Summary

Adds a fourth "Create line if not found" location to Capture's Insert afterOrdered — that creates a missing target heading at its sorted position among same-level sibling headings, instead of only at the top/bottom/cursor.

This is the generic primitive behind the long-standing request in #481 ("combining multiple insert-afters"): a reverse-chronological daily log where a fixed title/intro stays pinned, each new day's ## YYYY-MM-DD heading is auto-created below the intro and above older days, and the newest entry sits at the top of each day. The same one mechanism also covers semver changelogs, year-grouped lists, alphabetical/numeric section logs, etc. via configuration.

Closes #481.

How it works

When the insert-after heading (e.g. ## {{DATE:YYYY-MM-DD}}) is missing, the new Ordered location sorts it into place among its same-level siblings:

  • SectionOrdering (by: insertion / lexical / numeric / date / semver, direction: asc/desc, dateFormat, unparseable) — read only when createIfNotFoundLocation === "ordered". Fully additive: no migration, no version bump; existing choices are byte-identical.
  • A pure, frontmatter- and fence-aware placement helper (orderedSectionPlacement.ts).
  • A byte-preserving splice (existing line endings untouched → minimal diff).
  • Idempotent: the heading is created once; later captures find it and use the normal found-path. Within-day ordering uses the existing Insert at end of section toggle.
  • Builder UI: a 4th create-location option + an ordered sub-panel; Ordered is mutually exclusive with Inline insertion.

Requirement structure falls out of the design: the title/intro stays pinned because it's a different heading level (and frontmatter is excluded entirely); the day heading is the ordered create; within-day order is the existing insertAtEnd.

Example (#481)

# My Daily Log

A short intro that always stays at the top.

## 2026-06-16
- 09:40 reviewed the code
- 09:13 started the design

## 2026-06-14
- 09:00 older entry

Testing

  • 51 new tests (pure-helper placement matrix, full-handler integration, Load migration) — full suite green (2368 passing); tsc, svelte-check, and eslint clean; docs site builds.
  • End-to-end verified in a real Obsidian vault (isolated worktree instance): the [FEATURE REQUEST] combining multiple insert-afters #481 daily log (incl. rendered screenshot), a semver changelog, the Keep-a-Changelog [1.10.0] bracket form, frontmatter-preserving captures, mixed/CRLF EOL preservation, and idempotent repeat captures.

Review

Iterated through multiple review rounds (multi-lens + cross-model adversarial). Fixes that came out of review include: frontmatter-aware placement (prevented a YAML-corruption path), byte-preserving mixed-EOL/EOF splice, multi-line-anchor de-duplication (idempotency), fence-aware heading detection, builder reactivity that never clobbers a saved sort config, and the documented requirement that the capture format end in a newline.

Deferred (documented limitations)

  • Sorting is over all same-level headings in the note (not scoped per parent section) — correct for the single-group layouts above; scopeToParent is a future extension.
  • Full SemVer pre-release precedence (build/pre-release metadata is dropped from the comparable core).
  • "Re-sort an existing note's sections" is a separate future command (this only places the new section).

Docs

New "Ordered section placement" subsection in docs/docs/Choices/CaptureChoice.md (Next/unreleased) with the daily-log recipe, sort options, changelog & books-by-year examples, and the limits.

Summary by CodeRabbit

  • New Features
    • Added an ordered placement mode for “insert after” captures to create missing headings at the correct sorted position using configurable sort strategies (insertion order, text, number, date, and semver).
    • Updated the UI and capture-choice loading to support ordered options and enforce ordered vs inline compatibility.
    • Ordered inserts now display success messages referencing the resolved target heading.
  • Documentation
    • Expanded capture documentation with detailed ordered placement rules, constraints, and examples.
  • Tests
    • Added comprehensive coverage for ordered section placement logic, edge cases, and document formatting behavior.

When an insert-after target heading (e.g. "## {{DATE:YYYY-MM-DD}}") is missing,
the new "Ordered" create location inserts it at its sorted position among
same-level sibling headings instead of at the top/bottom of the note. Enables
reverse-chronological daily logs (newest day on top, newest entry under each
day), semver changelogs, year-grouped lists, etc. from one composable mechanism.

- New SectionOrdering (by: insertion/lexical/numeric/date/semver, direction,
  dateFormat, unparseable) read only when createIfNotFoundLocation === "ordered".
- Pure, frontmatter- and fence-aware placement helper (orderedSectionPlacement.ts).
- Byte-preserving splice (existing line endings untouched; minimal diff).
- Idempotent: never duplicates a heading; later captures take the found-path.
- Builder UI: 4th create-location option + ordered sub-panel; inline is mutually
  exclusive with ordered.

Closes #481
Add an 'Ordered section placement' subsection to the Capture choice docs:
the daily-log (newest-first) recipe, the sort options (insertion/text/number/
date/semver x asc/desc), worked changelog and books-by-year examples, and the
notes/limits (idempotent stable-token requirement, global same-level scoping,
no re-sort of existing sections, mutually exclusive with inline).
@coderabbitai

coderabbitai Bot commented Jun 16, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 46f0f6aa-8414-411b-966a-1d8c813b770b

📥 Commits

Reviewing files that changed from the base of the PR and between fb84c07 and 8d18ee7.

📒 Files selected for processing (3)
  • src/formatters/captureChoiceFormatter-481-ordered.test.ts
  • src/formatters/captureChoiceFormatter.ts
  • src/types/choices/CaptureChoice.ts
🚧 Files skipped from review as they are similar to previous changes (3)
  • src/formatters/captureChoiceFormatter.ts
  • src/formatters/captureChoiceFormatter-481-ordered.test.ts
  • src/types/choices/CaptureChoice.ts

📝 Walkthrough

Walkthrough

Implements an "Ordered" create-if-not-found placement mode for Capture choices. A new SectionOrdering type contract drives a pure computeOrderedSectionInsertIndex algorithm that slots a missing heading at its correct sorted position among same-level siblings. CaptureChoiceFormatter integrates the algorithm with EOL-preserving splicing, CaptureChoiceEngine captures the resolved heading for success notices, InsertAfterFields.svelte gains a configuration panel, and documentation is updated.

Changes

Ordered Section Placement Feature

Layer / File(s) Summary
Ordering types and constant definition
src/types/choices/ICaptureChoice.ts, src/constants.ts, src/types/choices/CaptureChoice.ts, src/types/choices/CaptureChoice.test.ts
Adds SectionOrderBy, SectionOrderDirection, UnparseableKeyPolicy, SectionOrdering interface, and CREATE_IF_NOT_FOUND_ORDERED constant; extends ICaptureChoice with optional orderBy; adds CaptureChoice.Load backward-compat invariant enforcement (backfill default ordering, force inline=false) with Vitest coverage.
Pure placement algorithm
src/formatters/helpers/orderedSectionPlacement.ts, src/formatters/helpers/orderedSectionPlacement.test.ts
Implements maskFencedHeadings, parseKey (lexical/numeric/date/semver), compareValues, and computeOrderedSectionInsertIndex; handles zero-sibling fallback, frontmatter exclusion, fenced-block masking, and tie behavior. 404-line Vitest suite covers all sort strategies and structural edge cases.
Formatter — ordered splicing and resolved heading
src/formatters/captureChoiceFormatter.ts, src/formatters/captureChoiceFormatter-481-ordered.test.ts
Routes CREATE_IF_NOT_FOUND_ORDERED through new createInsertAfterOrdered/spliceOrderedSection methods with YAML exclusion and byte-preserving EOL-aware splicing; adds getResolvedInsertAfterHeading() getter. 530-line Vitest suite validates placement, idempotency, CRLF, fence-aware dedup, and frontmatter.
Engine — resolved heading for notices
src/engine/CaptureChoiceEngine.ts
Adds captureResolvedOrderedHeading() helper that reads the formatter's resolved heading into resolvedInsertAfterHeading; calls it after file content production and after canvas text formatting.
Settings UI — ordered configuration panel
src/gui/ChoiceBuilder/components/InsertAfterFields.svelte
Adds ordered/inline exclusivity gating, detectDateFormatFromAfter auto-detection, reactive orderBy seeding effect, and handlers to manage location changes and sort-by pinning. Updates inline toggle to disable under ordered mode and wires location dropdown to change handler. Renders conditional ordered sub-panel with sort key/direction dropdowns, date format entry, unparseable ranking, and auto-detect warning.
Documentation
docs/docs/Choices/CaptureChoice.md
Replaces brief placement description with full "Ordered section placement" reference covering all sort options (insertion order, text, number, date, semver), daily-log and changelog examples, and the ordered/inline exclusivity constraint.

Sequence Diagram(s)

sequenceDiagram
  participant User
  participant InsertAfterFields as InsertAfterFields.svelte
  participant CaptureChoiceEngine
  participant CaptureChoiceFormatter
  participant computeOrderedSectionInsertIndex

  User->>InsertAfterFields: selects "Ordered" placement + sort config
  InsertAfterFields->>InsertAfterFields: sets orderBy on insertAfter, forces inline=false
  User->>CaptureChoiceEngine: triggers capture run()
  CaptureChoiceEngine->>CaptureChoiceFormatter: formatContent(choice, fileContent)
  CaptureChoiceFormatter->>CaptureChoiceFormatter: createInsertAfterOrdered: mask fenced headings, get bodyStart
  CaptureChoiceFormatter->>computeOrderedSectionInsertIndex: lines, newHeaderFirstLine, level, SectionOrdering, moment
  computeOrderedSectionInsertIndex-->>CaptureChoiceFormatter: OrderedSlot
  CaptureChoiceFormatter->>CaptureChoiceFormatter: spliceOrderedSection (EOL-preserving)
  CaptureChoiceFormatter->>CaptureChoiceFormatter: store lastResolvedInsertAfterHeading
  CaptureChoiceFormatter-->>CaptureChoiceEngine: formatted content
  CaptureChoiceEngine->>CaptureChoiceEngine: captureResolvedOrderedHeading() → resolvedInsertAfterHeading
  CaptureChoiceEngine->>User: success notice with real heading name
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

  • chhoumann/quickadd#1330: Modifies the same InsertAfterFields.svelte component where this PR adds ordered placement state, UI controls, and auto-detection logic.
  • chhoumann/quickadd#1348: Touches the same CaptureChoiceEngine.ts and captureChoiceFormatter.ts resolved-heading plumbing that this PR extends for ordered heading notices.
  • chhoumann/quickadd#1063: Extends CaptureChoiceFormatter's insertAfter flow with inline insertion path; this PR adds the ordered create-if-not-found insertion path to the same handler.

Poem

🐇 A heading without a home, lost in the doc,
Now sorted by date with a tick of the clock.
## 2024-01-15 slots right in between,
The neatest of sections the vault's ever seen!
No inline confusion, no frontmatter snare —
Just ordered insertions with bunny-like flair! 🌿

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 50.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main change: adding ordered create-if-not-found placement for reverse-chrono logs, which is the primary feature across all modified files.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch chhoumann/481-reverse-chrono-daily-log

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@cloudflare-workers-and-pages

cloudflare-workers-and-pages Bot commented Jun 16, 2026

Copy link
Copy Markdown

Deploying quickadd with  Cloudflare Pages  Cloudflare Pages

Latest commit: 8d18ee7
Status: ✅  Deploy successful!
Preview URL: https://6a609e31.quickadd.pages.dev
Branch Preview URL: https://chhoumann-481-reverse-chrono.quickadd.pages.dev

View logs

@chatgpt-codex-connector chatgpt-codex-connector 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: fb84c07dbc

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/formatters/captureChoiceFormatter.ts

@coderabbitai coderabbitai 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.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/types/choices/CaptureChoice.ts`:
- Around line 159-175: The orderBy backfill is currently happening whenever
createIfNotFoundLocation is "ordered", even if the createIfNotFound feature is
disabled, which causes unnecessary mutations of inert configs. Add an additional
condition to check that loaded.createIfNotFound is true before backfilling the
orderBy property within the CREATE_IF_NOT_FOUND_ORDERED block. Keep the inline
safety normalization (loaded.insertAfter.inline = false;) unchanged, but gate
only the orderBy backfill logic behind both the createIfNotFound and
createIfNotFoundLocation checks.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 6259c380-5795-4200-8fb6-5e4535b40fe4

📥 Commits

Reviewing files that changed from the base of the PR and between 507f9d4 and fb84c07.

📒 Files selected for processing (11)
  • docs/docs/Choices/CaptureChoice.md
  • src/constants.ts
  • src/engine/CaptureChoiceEngine.ts
  • src/formatters/captureChoiceFormatter-481-ordered.test.ts
  • src/formatters/captureChoiceFormatter.ts
  • src/formatters/helpers/orderedSectionPlacement.test.ts
  • src/formatters/helpers/orderedSectionPlacement.ts
  • src/gui/ChoiceBuilder/components/InsertAfterFields.svelte
  • src/types/choices/CaptureChoice.test.ts
  • src/types/choices/CaptureChoice.ts
  • src/types/choices/ICaptureChoice.ts

Comment thread src/types/choices/CaptureChoice.ts
…e; gate orderBy backfill

Address PR #1365 review feedback:
- Ordered target search now ignores headings inside YAML frontmatter or fenced
  code blocks (Codex P2): a single-line target like "## 2026-06-16" that only
  appears in a ```markdown example or a frontmatter value no longer matches as
  "found" and gets the capture inserted there — it creates the real sorted
  section instead. Masking preserves line indices so the found-path math is intact.
- CaptureChoice.Load only backfills orderBy when createIfNotFound is on, so an
  inert ordered config isn't mutated on load (CodeRabbit).
@chhoumann chhoumann merged commit 6838026 into master Jun 16, 2026
10 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.

[FEATURE REQUEST] combining multiple insert-afters

1 participant