Skip to content

Conversation

@perber
Copy link
Owner

@perber perber commented Jan 8, 2026

No description provided.

Copilot AI review requested due to automatic review settings January 8, 2026 13:16
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR implements a major version upgrade to schema v2, introducing YAML frontmatter support for markdown files and migrating from Go's standard log package to structured logging with slog. The changes enable better metadata management and improve logging consistency across the application.

Key changes:

  • Schema migration system enhanced to support incremental migrations with per-version schema file updates
  • New frontmatter parsing and generation functionality with robust handling of edge cases
  • Migration to structured logging using slog with configurable log levels

Reviewed changes

Copilot reviewed 10 out of 11 changed files in this pull request and generated 8 comments.

Show a summary per file
File Description
internal/core/tree/frontmatter.go New file implementing YAML frontmatter parsing, splitting, and building functions with heuristic detection
internal/core/tree/frontmatter_test.go Comprehensive test coverage for frontmatter functionality including edge cases
internal/core/tree/tree_service.go Enhanced migration system, added v2 migration for frontmatter backfill, migrated to slog
internal/core/tree/tree_service_test.go New migration tests and updated existing tests for frontmatter support, translated German comments
internal/core/tree/page_store.go Updated CRUD operations to include frontmatter in all file operations, new ReadPageRaw method
internal/core/tree/page_store_test.go Updated test expectations to account for frontmatter in created files
internal/core/tree/schema.go Bumped CurrentSchemaVersion from 1 to 2
internal/core/tree/errors.go Added ErrFrontmatterParse and ErrFileNotFound error types
cmd/leafwiki/main.go Added structured logging setup with LOG_LEVEL environment variable support
go.mod Added gopkg.in/yaml.v3 dependency for YAML parsing
go.sum Updated with new yaml.v3 and transitive dependencies

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +156 to +166
// migrateToV2 migrates the tree to the v2 schema
// Adds frontmatter to all existing pages if missing
Copy link

Copilot AI Jan 8, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The migrateToV2 function lacks documentation about error handling behavior. Specifically, it's unclear to users what happens when files are missing or when frontmatter parsing fails during migration. Consider adding a detailed function comment that explains the migration process, error handling strategy, and what files are skipped versus which errors cause migration to fail.

Suggested change
// migrateToV2 migrates the tree to the v2 schema
// Adds frontmatter to all existing pages if missing
// migrateToV2 migrates the tree to the v2 schema.
//
// The migration traverses all pages in the tree and ensures that each page
// has frontmatter. For pages that already have valid frontmatter, the
// existing frontmatter is preserved. For pages without frontmatter, a new
// frontmatter block is added based on the current metadata.
//
// Error handling:
// - If the underlying page file does not exist (os.ErrNotExist or
// ErrFileNotFound), the function logs a warning, skips adding
// frontmatter for that node, but still recurses into and processes
// all of its children. Migration continues for the rest of the tree.
// - If reading the page content fails for any other reason, the error is
// logged and returned, and the migration is aborted.
// - If parsing frontmatter fails for a page, the error is logged and
// returned, and the migration is aborted.
//
// As a result, benign missing-file conditions are tolerated (those nodes are
// skipped), while unexpected I/O or parsing errors cause migrateToV2 to fail.

Copilot uses AI. Check for mistakes.

_, content, _, err := ParseFrontmatter(string(raw))
if err != nil {
return string(raw), err
Copy link

Copilot AI Jan 8, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The ReadPageContent function returns the raw content when frontmatter parsing fails, but still returns the parsing error. This is inconsistent - if parsing fails, the caller gets potentially corrupted data along with an error. Consider either returning an empty string with the error, or logging the error and returning only the body portion that could be extracted.

Suggested change
return string(raw), err
return "", err

Copilot uses AI. Check for mistakes.
Comment on lines +212 to +228
t.log.Error("could not build markdown with frontmatter", "nodeID", node.ID, "error", err)
return fmt.Errorf("could not build markdown with frontmatter for node %s: %w", node.ID, err)
Copy link

Copilot AI Jan 8, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The error message uses inconsistent capitalization. The log message starts with lowercase "could not" while error messages in Go conventionally start with lowercase letters, but the fmt.Errorf wrapping should maintain consistency with other error messages in the same function. Consider using "could not build markdown with frontmatter" consistently across both the log and error messages.

Copilot uses AI. Check for mistakes.
// Create the file
content := []byte("# " + newEntry.Title + "\n")
if err := writeFileAtomic(newFilename, content, 0o644); err != nil {
fm := Frontmatter{LeafWikiID: newEntry.ID}
Copy link

Copilot AI Jan 8, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's an inconsistency in how frontmatter is created between CreatePage and UpdatePage. CreatePage only sets the LeafWikiID field in frontmatter, while UpdatePage sets both LeafWikiID and LeafWikiTitle. This means pages will have different frontmatter structure depending on whether they were just created or have been updated. Consider making CreatePage also include the title for consistency, or document why this difference exists.

Suggested change
fm := Frontmatter{LeafWikiID: newEntry.ID}
fm := Frontmatter{LeafWikiID: newEntry.ID, LeafWikiTitle: newEntry.Title}

Copilot uses AI. Check for mistakes.
fm, body, has, err := ParseFrontmatter(content)
if err != nil {
t.log.Error("Could not parse frontmatter for node", "nodeID", node.ID, "error", err)
return fmt.Errorf("could not parse frontmatter for node %s: %v", node.ID, err)
Copy link

Copilot AI Jan 8, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When ParseFrontmatter returns an error during migration, the migration immediately fails and stops processing other pages. This could leave the wiki in a partially migrated state where some pages have frontmatter and others don't. Consider logging the error and continuing with the migration for other pages, or at least document this all-or-nothing behavior so users understand that a single corrupted file will prevent migration.

Suggested change
return fmt.Errorf("could not parse frontmatter for node %s: %v", node.ID, err)
// On parse errors, skip updating this node but continue migrating children
for _, child := range node.Children {
if errChild := addFrontmatter(child); errChild != nil {
t.log.Error("Error adding frontmatter to child node", "nodeID", child.ID, "error", errChild)
}
}
return nil

Copilot uses AI. Check for mistakes.
Comment on lines 222 to 228
if err := writeFileAtomic(filePath, []byte(newContent), 0o644); err != nil {
t.log.Error("could not write updated page content", "nodeID", node.ID, "filePath", filePath, "error", err)
return fmt.Errorf("could not write updated page content for node %s: %w", node.ID, err)
}

t.log.Info("frontmatter backfilled", "nodeID", node.ID, "path", filePath)
}
Copy link

Copilot AI Jan 8, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The migration function writes each file atomically using writeFileAtomic, which is good for data safety. However, for large wikis with many pages, this could be slow as each write involves creating a temporary file and renaming it. Consider adding progress logging to inform users about migration progress, especially since there's already logging for successful frontmatter backfills but no indication of overall progress.

Copilot uses AI. Check for mistakes.
Comment on lines 232 to 233
fm := Frontmatter{LeafWikiID: entry.ID, LeafWikiTitle: entry.Title}
contentWithFM, err := BuildMarkdownWithFrontmatter(fm, content)
Copy link

Copilot AI Jan 8, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The UpdatePage function unconditionally overwrites the frontmatter title field with the entry's title from the tree structure. This could overwrite user-provided custom titles in the frontmatter. Consider either preserving the existing frontmatter title when it differs from the tree title, or only updating the ID field while preserving any existing title in the frontmatter.

Copilot uses AI. Check for mistakes.
@perber perber marked this pull request as draft January 8, 2026 15:08
@perber perber changed the title Release/v0.8.0 release: v0.8.0 Jan 8, 2026
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.

2 participants