Skip to content

Writing Release Notes

The analysis is done. Now it is time to turn the data into a document that developers want to read. Phase 4 is the most time-consuming step in the entire workflow, but it is also the most important. No matter how accurate the analysis, it has no value if it becomes a document that is hard to read.

ItemPath
Template.release-notes/TEMPLATE.md
Output.release-notes/RELEASE-$VERSION.md
Terminal window
cp .release-notes/TEMPLATE.md .release-notes/RELEASE-v1.2.0.md
PlaceholderConversion Example
{VERSION}v1.2.0
{DATE}2025-12-19

Fill each section by referencing Phase 3 analysis results. Get commit classifications from phase3-commit-analysis.md and feature groups from phase3-feature-groups.md.

Verify all code examples against the Uber file.

Delete template guide comments (<!-- -->).

These are the sections that must be included in the release notes.

SectionRequiredDescription
FrontmatterYesYAML header (title, description, date)
OverviewYesVersion introduction, key change summary
Breaking ChangesYesChanges breaking API compatibility (state if none)
New FeaturesYesBased on feat commits
Bug FixesBased on fix commits (omit if none)
API ChangesYesSummary of newly added key APIs
InstallationYesInstallation instructions

Never document APIs not in the Uber file. This is the most important rule.

Verification method:
grep "MethodName" .analysis-output/api-changes-build-current/all-api-changes.txt

Include executable code examples for all major features.

Include commit SHAs as comments so all content in the release notes is traceable to actual changes.

<!-- Related commit: abc1234 -->

Feature documentation without a “Why this matters” section is considered incomplete. The reason this rule exists is that what matters more than the existence of a feature is how it changes the developer’s daily life. Simply writing “ErrorCodeFactory was added” leaves the developer unable to answer the question “so why is it important to me?”

Each feature must include all of the following four elements.

  1. Feature Description (What) - What does it do?
  2. Code Example (How) - How do you use it?
  3. Why this matters (Why) - Why is it important?
  4. API Reference (Reference) - Exact API signature
### Functional Error Handling
Provides structured error creation through ErrorCodeFactory.
[Code example]

The problem with this documentation is that the developer cannot know why they should use this feature. It merely conveys the fact that the feature exists, without explaining what problem it solves or what is better than the existing approach.

### Functional Error Handling
Provides structured error creation through ErrorCodeFactory.
[Code example]
**Why this matters:**
- Converts exceptions to functional errors, improving type safety
- Automatic integration with Serilog for structured logging support
- Eliminates boilerplate code (reduces try-catch repetition)
- Consistent error code system shortens debugging time
- Separating business logic from error handling improves code readability

Here, each item connects to a specific problem developers face (type safety, boilerplate, debugging time).

  • State the specific problem developers face
  • Explain how this feature solves that problem
  • Include quantitative benefits (if possible: time saved, code reduced)
  • Include qualitative benefits (readability, maintainability, type safety)
  • Present real use cases
Section titled “Expressions to Avoid vs Recommended Expressions”
Expressions to AvoidRecommended Expressions
”Provides a feature""Provides [specific benefit] by doing ~"
"Supports""Solves [problem] to achieve [result]"
"Has been added""Simplifies [complex task] into [simple method]"
"Can do ~""Improves productivity through [time/code] savings”

The Uber file is the single source of truth.

.analysis-output/api-changes-build-current/all-api-changes.txt

When documenting APIs, always follow this order. First search the Uber file for the API, then check details in the individual API files, extract the complete API signature, and write code examples with the correct signature. Failing to follow this order results in the mistake of documenting non-existent APIs.

Step 1: Search for API in the Uber file
grep -A 10 "ErrorCodeFactory" all-api-changes.txt
Step 2: Check details in the individual API file
cat Src/Functorium/.api/Functorium.cs | grep -A 5 "ErrorCodeFactory"
Step 3: Extract complete API signature
Step 4: Write code examples with correct signature
// Exact signatures confirmed from the Uber file:
public static Error Create(string errorCode, string errorCurrentValue, string errorMessage)
public static Error CreateFromException(string errorCode, Exception exception)
// Correct usage examples:
var error = ErrorCodeFactory.Create("VALIDATION_001", invalidValue, "Value is not valid");
var errorFromEx = ErrorCodeFactory.CreateFromException("SYSTEM_001", exception);

Creating methods or fluent chains that do not actually exist is the most common and dangerous mistake. APIs not in the Uber file must never be used in code examples.

// Wrong: These methods are not in the Uber file
ErrorCodeFactory.Create("error")
.WithDetails(details: "Additional info") // Invented
.WithInnerError(inner: innerError) // Invented
.Build(); // Invented
### Creating Structured Errors from Exceptions
Converts exceptions to structured error codes based on the LanguageExt Error type.
```csharp
using Functorium.Abstractions.Errors;
using LanguageExt.Common;
try
{
await HttpClient.GetAsync(url);
}
catch (HttpRequestException ex)
{
// Create structured error from exception
var error = ErrorCodeFactory.CreateFromException("HTTP_001", ex);
// Automatically logged in structured form to Serilog
Log.Error("API request failed: {@Error}", error);
return Fin<Response>.Fail(error);
}
```
**Why this matters:**
- Converts exceptions to functional errors, improving type safety
- Automatic integration with Serilog for structured logging support
- Eliminates try-catch boilerplate code
- Consistent error code system shortens debugging time
**API:**
```csharp
namespace Functorium.Abstractions.Errors
{
public static class ErrorCodeFactory
{
public static Error CreateFromException(string errorCode, Exception exception);
}
}
```
### Error Handler Interface Name Change
Error handling APIs have been unified for better consistency.
**Before (v1.0):**
```csharp
public class MyHandler : IErrorHandler
{
public void Handle(Error error) { }
}
```
**After (v1.1):**
```csharp
public class MyDestructurer : IErrorDestructurer
{
public LogEventPropertyValue Destructure(Error error, ILogEventPropertyValueFactory factory) { }
}
```
**Migration Guide:**
1. Update all `IErrorHandler` references to `IErrorDestructurer`
2. Replace `Handle` method with `Destructure` method
3. Change return type to `LogEventPropertyValue`
  • Use active voice: “You can now create errors” (O) / “Errors can be created” (X)
  • Write developer-centric: Practical examples that developers can use immediately
  • Write clearly and concisely: Avoid unnecessary jargon or lengthy explanations
  • Specify the language: Always csharp, bash, ```json
  • Show complete examples: Fully working code examples
  • Highlight new features: Mark changed parts with // New feature comments
  • Start with the most impactful changes: Breaking Changes first, then major features
  • Group related features: Combine similar features into unified sections
  • Use descriptive headings: Easy to scan

Save Phase 4’s writing results.

.release-notes/scripts/.analysis-output/work/
├── phase4-draft.md # Release note draft
├── phase4-api-references.md # List of APIs used
└── phase4-code-samples.md # All code examples
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Phase 4: Release Note Writing Complete
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Writing Statistics:
Total Length: 15,380 lines
Sections: 8
Code Examples: 24
API References: 30 types
Key Sections:
1. Overview (Version: v1.0.0-alpha.1)
2. Breaking Changes (0)
3. New Features (8)
4. Bug Fixes (1)
5. API Changes (Summary)
6. Installation
Output File:
.release-notes/RELEASE-v1.0.0-alpha.1.md

Items to verify before document completion.

  • All code examples verified against the Uber file
  • API signature parameter names and types match exactly
  • No invented APIs or commands
  • Complete migration guide for Breaking Changes
  • “Why this matters” section included for all major features
  • Specific problem resolution stated
  • Developer productivity benefits explained
  • Real use cases presented
  • Consistent formatting - matches existing template
  • Clear, developer-centric language
  • Appropriate documentation links

Q1: Why is feature documentation without a “Why this matters” section considered incomplete?

Section titled “Q1: Why is feature documentation without a “Why this matters” section considered incomplete?”

A: “ErrorCodeFactory was added” alone does not tell developers why they should use the feature. The release notes only provide practical help for update decisions when they also explain what problem it solves, what is better than the existing approach, and how much code is reduced.

Q2: What is the specific method for searching the Uber file when documenting APIs?

Section titled “Q2: What is the specific method for searching the Uber file when documenting APIs?”

A: Use the command grep -A 10 "ErrorCodeFactory" all-api-changes.txt to check API existence and exact signature. Parameter names, types, and return values must exactly match the Uber file. Be careful that the order is not swapped when there are multiple methods with similar names.

Section titled “Q3: What is the difference between expressions to avoid (“provides a feature”) and recommended expressions?”

A: Expressions to avoid only announce the feature’s existence, while recommended expressions convey specific benefits. Instead of “supports”, use “solves [problem] to achieve [result]”; instead of “has been added”, use “simplifies [complex task] into [simple method]” — specifying value that developers can tangibly appreciate.

Once release note writing is complete, proceed to Phase 5: Validation for the final quality check.