Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
2ca465d
- Swapped Codecov for ReportGenerator, producing HTML + Cobertura + M…
df49b9cd Nov 18, 2025
425090c
allow ci to write to pr's
df49b9cd Nov 18, 2025
9f18c54
Changes
df49b9cd Nov 18, 2025
2ff3233
- Added missing Result streaming coverage: new unit checks for linked…
df49b9cd Nov 18, 2025
37558ca
- src/Hugo/Results/Result.Operators.cs:123-139 now absorbs compensati…
df49b9cd Nov 18, 2025
9b9d7ac
- Added targeted unit coverage for Result streaming channels (cancell…
df49b9cd Nov 18, 2025
5bdc559
Changes
df49b9cd Nov 18, 2025
f1515bc
Added targeted Result streaming unit coverage for the cancellation s…
df49b9cd Nov 18, 2025
965e969
fixing windowasync
df49b9cd Nov 18, 2025
a0e83ea
WindowAsync to valuetask
df49b9cd Nov 18, 2025
e095a29
removed outdated agents.md
df49b9cd Nov 20, 2025
fdd05d8
• Created AGENTS.md with repository-specific “Repository Guidelines” …
df49b9cd Nov 20, 2025
c19773e
- Added shared config (benchmarks/Hugo.Benchmarks/BenchmarkConfig.c…
df49b9cd Nov 20, 2025
8106ad3
• Implemented new benchmark coverage for key gaps:
df49b9cd Nov 20, 2025
ab27556
Added several new benchmark suites and diagnostics job so we can meas…
df49b9cd Nov 20, 2025
c5c99ae
dotnet-performance-guidelines
df49b9cd Nov 20, 2025
3adc6a4
• Added more coverage aligned with docs/perf/dotnet-performance-guide…
df49b9cd Nov 20, 2025
438da36
Completed guideline fixes:
df49b9cd Nov 20, 2025
a2181b2
update performance guidelines
df49b9cd Nov 20, 2025
e8503f4
Progress:
df49b9cd Nov 20, 2025
7a8042a
• Changes made for deterministic, guideline-aligned timing:
df49b9cd Nov 20, 2025
4197580
• - Added comprehensive streaming suite in benchmarks/Hugo.Benchmarks…
df49b9cd Nov 20, 2025
b2f405a
benchmark results for streaming
df49b9cd Nov 20, 2025
3fd5ffb
- right-sized collection buffers to avoid reallocation on hot paths…
df49b9cd Nov 20, 2025
32e5caf
• Optimizations applied to Go helpers with perf-guideline focus:
df49b9cd Nov 20, 2025
0a9c6a9
all
df49b9cd Nov 20, 2025
23c47bb
• - Turned QueueEnvelope into a readonly record struct and adjusted T…
df49b9cd Nov 20, 2025
919d094
• - Refined error code lookup to a frozen dictionary for cache-friend…
df49b9cd Nov 20, 2025
c122181
• - Added span-friendly metadata paths in src/Hugo/Primitives/Error.c…
df49b9cd Nov 20, 2025
ea6e231
error
df49b9cd Nov 20, 2025
a418ac5
• - Cached lane case array in src/Hugo/PrioritizedChannel.cs so WaitT…
df49b9cd Nov 20, 2025
9359166
dotnet format
df49b9cd Nov 20, 2025
3e4c8f9
• - Reworked replication serialization to be Native AOT–safe: TaskQue…
df49b9cd Nov 20, 2025
e2fe1c6
Added an AOT-/trim-safe JSON pipeline for task queue replication: Tas…
df49b9cd Nov 20, 2025
bd16a17
stuff
df49b9cd Nov 20, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 27 additions & 7 deletions .github/workflows/docker-ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ permissions:
contents: write
packages: write
id-token: write
pull-requests: write

env:
DOTNET_NOLOGO: 1
Expand Down Expand Up @@ -112,14 +113,31 @@ jobs:
path: artifacts/test-results/**/*.trx
reporter: dotnet-trx

- name: Upload coverage to Codecov
- name: Generate coverage report
if: ${{ steps.extract-artifacts.outcome == 'success' }}
uses: codecov/codecov-action@v5
uses: danielpalme/ReportGenerator-GitHub-Action@v5
with:
token: ${{ secrets.CODECOV_TOKEN }}
files: artifacts/coverage/**/*.xml
fail_ci_if_error: false
verbose: true
reports: artifacts/coverage/**/coverage.cobertura.xml
targetdir: artifacts/coverage-report
reporttypes: Html;Cobertura;MarkdownSummaryGithub

- name: Publish coverage summary
if: ${{ steps.extract-artifacts.outcome == 'success' }}
run: cat artifacts/coverage-report/SummaryGithub.md >> "$GITHUB_STEP_SUMMARY"

- name: Comment coverage summary on PR
if: ${{ steps.extract-artifacts.outcome == 'success' && github.event_name == 'pull_request' }}
uses: actions/github-script@v7
with:
script: |
const fs = require('fs');
const body = fs.readFileSync('artifacts/coverage-report/SummaryGithub.md', 'utf8');
await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: context.issue.number,
body
});
Comment on lines +128 to +140
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Add issues permission for PR coverage comments

The new actions/github-script step calls github.rest.issues.createComment but the workflow’s permission block only grants contents, packages, and id-token. Because unspecified scopes default to none, the GITHUB_TOKEN does not have issues (or pull-requests) write access and this step will return 403 whenever the job runs on a pull request, causing the workflow to fail. Grant issues: write or pull-requests: write before attempting to create the comment.

Useful? React with 👍 / 👎.


- name: Upload Test Results
if: ${{ steps.extract-artifacts.outcome == 'success' }}
Expand All @@ -135,7 +153,9 @@ jobs:
uses: actions/upload-artifact@v5
with:
name: coverage
path: artifacts/coverage
path: |
artifacts/coverage
artifacts/coverage-report
if-no-files-found: ignore

- name: Upload Package Artifacts
Expand Down
119 changes: 46 additions & 73 deletions AGENTS.md
Original file line number Diff line number Diff line change
@@ -1,73 +1,46 @@
# Hugo Agent Handbook
- Public APIs must expose XML documentation comments, guard clauses, cancellation tokens and return `Result<T>` instead of throwing exceptions.
- Place braces on their own lines and prefer expression clarity over terseness.
- Use descriptive test names (e.g. `ErrGroupTests.WaitAsync_ShouldReturnSuccess`).

Commit messages follow the **Conventional Commits** specification (`feat:`, `fix:`, `docs:` etc.), remain focused. Before opening a pull request, ensure that builds pass on .NET 10, that all unit, integration and deterministic tests succeed, and that coverage has been collected. Fill out the PR template, link issues (`Fixes #123`), summarise behavioural changes and respond promptly. Squash merge is the default strategy.

## Core Concepts

### Concurrency Primitives

Hugo exposes a set of primitives under the `Hugo.Go` namespace:

**WaitGroup** – Tracks asynchronous operations and delays shutdown until tasks complete. Use `WaitGroup.Go` to schedule work, `WaitGroup.Add` to increment counters, `WaitGroup.Done` to signal completion and `WaitGroup.WaitAsync` to await completion. Cancelling a wait group surfaces `Error.Canceled`, and metrics such as `waitgroup.additions` and `waitgroup.completions` are emitted when diagnostics are configured.

**Mutex** and **RwMutex** – Provide mutual exclusion for exclusive or shared access. Asynchronous locks honour cancellation tokens and must be released via `await using`.

**Channels** – Use `MakeChannel<T>` to create bounded or unbounded channels for message passing. Prioritised channels allow multiple priority levels, and DI‑friendly builders register channel readers and writers automatically. Bounded channels respect full modes (`DropOldest`, `Wait`, etc.), and `TryComplete` propagates faults to readers.

**TaskQueue<T>** – Builds cooperative leasing semantics on top of channels: producers enqueue work items, workers lease them for a configurable duration and can heartbeat, complete or fail each lease. The queue automatically requeues expired leases and supports draining/restore operations for rolling upgrades. Task queue health checks and backpressure monitors integrate with ASP.NET Core health probes and rate limiters.

**Select and Fan‑In Helpers** – Await whichever channel case becomes ready first (`SelectAsync`), or merge multiple channels into one (`FanInAsync`). These helpers capture attempts, completions, latency, timeouts and cancellations in diagnostics. See the [fan‑in how‑to guide](docs/how-to/fan-in-channels.md) for a worked example.

### Result Pipelines

The `Result<T>` type models success or failure explicitly and supports functional composition. Use `Result.Ok`/`Go.Ok` to wrap a value and `Result.Fail`/`Go.Err` to create failures. Inspect state with `IsSuccess`, `IsFailure`, `TryGetValue` and `TryGetError` and extract values with `Switch`/`Match` or `ValueOr`.

Compose pipelines using combinators:

- **Synchronous**: `Then`, `Map`, `Tap`, `Ensure`, `Recover` and `Finally` orchestrate synchronous flows
- **Asynchronous**: `ThenAsync`, `MapAsync`, `TapAsync`, `RecoverAsync` and `EnsureAsync` accept `CancellationToken` and normalise cancellations to `Error.Canceled`. `ValueTask` variants avoid extra allocations when delegates already return `ValueTask<Result<T>>`.
- **Collections and streaming**: Helpers such as `Result.Sequence`, `Result.Traverse`, `MapStreamAsync` and `FanInAsync` aggregate or transform streams of results.
- **Parallel orchestration and retries**: Use `Result.WhenAll`, `Result.WhenAny` and `Result.RetryWithPolicyAsync` to execute operations concurrently, aggregate errors, or apply exponential backoff policies. Tiered fallbacks let you define multiple strategies and switch when one fails.

Errors carry metadata dictionaries and well‑known codes generated at compile time. You can attach custom metadata (for example `age`, `userId`) and extract it when logging. Cancellation is represented by `Error.Canceled` and includes the originating token under the `cancellationToken` key.

### Deterministic Coordination

Long‑running workflows often need to avoid repeating side effects when retries or replays occur. Hugo’s deterministic coordination primitives persist decisions externally:

1. **VersionGate** records an immutable version decision per change identifier using optimistic inserts. Concurrent writers that lose the compare‑and‑swap return an `error.version.conflict` so callers can retry or fallback.
2. **DeterministicEffectStore** captures idempotent side effects keyed by change, version and step. Replays reuse the stored result instead of re‑executing the side effect.
3. **DeterministicGate** combines the two to execute code paths safely across replays. The simplest overload allows you to define upgraded and legacy delegates and specify a version range; repeated executions reuse the persisted result.

For richer coordination, the workflow builder lets you declare branches based on predicates, exact versions or ranges and supply a fallback. Inside branches, use `DeterministicWorkflowContext` to capture side effects and access metadata (version, changeId, stepId). Missing branches or unsupported versions surface `error.version.conflict`, and cancellations or exceptions are converted to structured errors. Instrumentation emits `workflow.*` metrics and activity tags so deterministic replays are observable.

### Diagnostics and Observability

Configuring `GoDiagnostics` registers **System.Diagnostics.Metrics** instruments for wait groups, result pipelines, channel selectors, task queues and workflow execution. Emitted metrics include counters, up/down counters and histograms for operations such as wait‑group additions/completions, channel select attempts/timeouts, task queue leases/enqueues and workflow durations. When using the `Hugo.Diagnostics.OpenTelemetry` package, you can register meters, activity sources and exporters in one call (see *Observability in One Call* above) and configure service names, OTLP endpoints or Prometheus exporters.

## Contributing and Support

Hugo welcomes contributions. To contribute:

1. Fork the repository and create a feature branch.
2. Review `CONTRIBUTING.md` for environment setup, coding standards and workflow expectations.
3. Run `dotnet build` and `dotnet test` across all test projects (unit, integration, feature and deterministic suites) and ensure they pass.
4. Collect code coverage with `dotnet test --collect:"XPlat Code Coverage"` to match CI coverage gates.
5. Follow Conventional Commits and update the changelog. Link issues in your PR description and include context for behaviour changes.

For questions or bug reports, open an issue on GitHub. For security disclosures, contact the maintainer privately before filing a public issue. Hugo is licensed under the MIT License.

## Useful Tips and Best Practices

- **Configure diagnostics early.** Register meters and activity sources before creating channels, wait groups or pipelines so all metrics are emitted.
- **Prefer deterministic stores in production.** Use durable implementations of `IDeterministicStateStore` (e.g. SQL Server, Cosmos DB, Redis) to persist workflow versions and effects. The in‑memory store is suitable only for testing.
- **Enforce backpressure.** Always specify capacities for channels and task queues and tune full modes/lease durations to match your workload. Use backpressure monitors and health checks to ensure service stability.
- **Keep error metadata simple.** Stick to primitive types, records or known DTOs when populating `Error.Metadata` so the linker/AOT compiler can preserve them during trimming.
- **Write deterministic tests.** Use fake time providers (`Microsoft.Extensions.TimeProvider.Testing`) and structure tests to exercise success, failure and cancellation paths. Do not rely on wall‑clock timers; Hugo’s primitives integrate with `TimeProvider` for deterministic scheduling.
- **Use value‑task overloads for performance.** When your delegates already return `ValueTask<Result<T>>`, call `ThenValueTaskAsync`, `MapValueTaskAsync`, etc., to avoid allocations.
- **Emit structured logs.** Attach `Result<T>.Error.Metadata` to log scopes so downstream observability pipelines can slice failures by change/version, user, region and other dimensions.

By following the guidelines in this handbook and exploring the examples and references in the documentation, you can leverage Hugo’s concurrency primitives, result pipelines and deterministic coordination to build robust, observable and testable workflows in .NET.
# Repository Guidelines

## Important Notes
- We must be as performant and efficient as possible due to our focus on Native AOT. Therefore read and understand the 'dotnet-performance-guidelines.md' located in docs/perf.

## Project Structure & Modules
- `src/Hugo` core concurrency + result pipelines; `Hugo.Diagnostics.OpenTelemetry` exposes meters/activity sources.
- Deterministic stores live in `src/Hugo.Deterministic.{Cosmos,Redis,SqlServer}`; task queue components in `src/Hugo.TaskQueues.*`.
- Tests: `tests/Hugo.UnitTests` (fast), `tests/Hugo.IntegrationTests`, `tests/Hugo.FeatureTests`, plus provider-specific deterministic-store suites.
- Docs rendered by DocFX in `docs/`; runnable walkthrough in `samples/Hugo.WorkerSample`; performance harness in `benchmarks/Hugo.Benchmarks`; helper scripts in `tools/` and collector config under `docker/`.

## Build, Test, and Development Commands
- Restore/build: `dotnet build Hugo.slnx` (uses central package management).
- Format: `dotnet format whitespace --verify-no-changes` keeps CI happy.
- Unit/integration/feature tests:
```bash
dotnet test tests/Hugo.UnitTests/Hugo.UnitTests.csproj
cd tests && dotnet test Hugo.IntegrationTests/Hugo.IntegrationTests.csproj
cd tests && dotnet test Hugo.FeatureTests/Hugo.FeatureTests.csproj
```
- Coverage: `dotnet test --collect:"XPlat Code Coverage"` → `coverage-report*/`.
- Pack for local feed: `dotnet pack src/Hugo/Hugo.csproj -o ./artifacts`.
- Samples/benchmarks: `dotnet run --project samples/Hugo.WorkerSample/Hugo.WorkerSample.csproj` and `dotnet run --project benchmarks/Hugo.Benchmarks/Hugo.Benchmarks.csproj -c Release` (bench results under `BenchmarkDotNet.Artifacts/results/`).

## Coding Style & Naming Conventions
- Nullable enabled; guard public inputs early (`ArgumentNullException.ThrowIfNull`).
- Async APIs accept `CancellationToken = default` and use `.ConfigureAwait(false)`; prefer `TimeProvider` over `Task.Delay/DateTime.Now`.
- Favor `Result<T>` + `Error` for controllable failures instead of throwing; attach metadata intentionally.
- Names: intention-revealing public APIs, verb-prefixed private helpers, PascalCase locals/constants/static readonly fields.
- Run formatter; add XML docs for new public types; instrument new primitives via `GoDiagnostics`/activity sources when relevant.

## Testing Guidelines
- Framework: xUnit. Place new tests beside matching project (unit/integration/feature/provider-specific).
- Style: `Method_Scenario_Expectation` naming, short timeouts (≈50–500ms), use fake `TimeProvider` and `TestContext.Current.CancellationToken` to avoid flakes.
- Cover success/failure/edge cases; use xUnit collections when tests need serialization; prefer deterministic schedules for concurrency.

## Commit & Pull Request Guidelines
- Conventional Commits (`feat:`, `fix:`, `docs:`, `test:`, `refactor:`). Branches like `feature/<topic>` or `fix/<issue>`.
- Before pushing: build, format, and run the three main test suites; regenerate coverage if behavior changes.
- PRs should link issues (`Fixes #123`), describe changes/breaking notes, and paste test results; include screenshots only when UI/observability output changes.
- CI runs build + format + tests; resolve all warnings. Squash merge is preferred once approvals are in.

## Security & Configuration Tips
- Report vulnerabilities privately (see `SECURITY.md`); avoid public GitHub issues for security.
- Keep secrets/PII out of `Error.Metadata`; bound channel capacities and metric dimensions to avoid cardinality explosions.
- For task queues, ensure handlers are idempotent because leases may replay; limit dead-letter payload contents.
Loading