diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml
new file mode 100644
index 0000000..68f9515
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/bug_report.yml
@@ -0,0 +1,49 @@
+name: Bug report
+description: Report a defect in a FunctionFoundry package
+labels: ["bug"]
+body:
+ - type: dropdown
+ id: package
+ attributes:
+ label: Package
+ options:
+ - FunctionFoundry.Security
+ - FunctionFoundry.Storage
+ - FunctionFoundry.Integrity
+ - FunctionFoundry.Observability
+ - FunctionFoundry.Data
+ - FunctionFoundry.Text
+ - FunctionFoundry.Resilience
+ - FunctionFoundry.Networking
+ - FunctionFoundry.Distributed
+ - FunctionFoundry.Scheduling
+ - Repository / CI / docs
+ validations:
+ required: true
+ - type: input
+ id: version
+ attributes:
+ label: Package version
+ placeholder: 1.0.0
+ validations:
+ required: true
+ - type: textarea
+ id: description
+ attributes:
+ label: Description
+ description: What went wrong?
+ validations:
+ required: true
+ - type: textarea
+ id: repro
+ attributes:
+ label: Reproduction steps
+ description: Minimal code or steps to reproduce.
+ validations:
+ required: true
+ - type: textarea
+ id: expected
+ attributes:
+ label: Expected behavior
+ validations:
+ required: true
diff --git a/.github/ISSUE_TEMPLATE/feature_request.yml b/.github/ISSUE_TEMPLATE/feature_request.yml
new file mode 100644
index 0000000..7b18ba6
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/feature_request.yml
@@ -0,0 +1,36 @@
+name: Feature request
+description: Propose a capability for a FunctionFoundry package
+labels: ["enhancement"]
+body:
+ - type: dropdown
+ id: package
+ attributes:
+ label: Package
+ options:
+ - FunctionFoundry.Security
+ - FunctionFoundry.Storage
+ - FunctionFoundry.Integrity
+ - FunctionFoundry.Observability
+ - FunctionFoundry.Data
+ - FunctionFoundry.Text
+ - FunctionFoundry.Resilience
+ - FunctionFoundry.Networking
+ - FunctionFoundry.Distributed
+ - FunctionFoundry.Scheduling
+ - New package / cross-cutting
+ validations:
+ required: true
+ - type: textarea
+ id: problem
+ attributes:
+ label: Problem
+ description: What specialized capability is missing that the BCL does not already provide well?
+ validations:
+ required: true
+ - type: textarea
+ id: proposal
+ attributes:
+ label: Proposal
+ description: API sketch, guarantees, and non-goals.
+ validations:
+ required: true
diff --git a/.github/dependabot.yml b/.github/dependabot.yml
new file mode 100644
index 0000000..3f9a01d
--- /dev/null
+++ b/.github/dependabot.yml
@@ -0,0 +1,13 @@
+version: 2
+updates:
+ - package-ecosystem: github-actions
+ directory: /
+ schedule:
+ interval: weekly
+ open-pull-requests-limit: 5
+
+ - package-ecosystem: nuget
+ directory: /
+ schedule:
+ interval: weekly
+ open-pull-requests-limit: 10
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 6018d66..c58f355 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -14,7 +14,11 @@ env:
jobs:
build:
- runs-on: ubuntu-latest
+ strategy:
+ fail-fast: false
+ matrix:
+ os: [ubuntu-latest, windows-latest]
+ runs-on: ${{ matrix.os }}
steps:
- name: Checkout
uses: actions/checkout@v4
@@ -25,26 +29,34 @@ jobs:
global-json-file: global.json
- name: Verify pinned SDK
+ shell: bash
run: |
SDK_VERSION=$(dotnet --version)
echo "Installed SDK: $SDK_VERSION"
- test "$SDK_VERSION" = "10.0.301"
+ EXPECTED=$(python -c "import json; print(json.load(open('global.json'))['sdk']['version'])")
+ test "$SDK_VERSION" = "$EXPECTED"
- - name: Restore (locked mode when lock files exist)
- run: |
- if find . -name 'packages.lock.json' | grep -q .; then
- dotnet restore --locked-mode
- else
- dotnet restore
- fi
+ - name: Restore (locked mode)
+ run: dotnet restore --locked-mode
- name: Verify formatting
+ if: matrix.os == 'ubuntu-latest'
run: dotnet format --verify-no-changes --verbosity diagnostic
- name: Build Release
run: dotnet build -c Release --no-restore
+ - name: Build samples
+ shell: bash
+ run: |
+ set -e
+ for proj in samples/*/*.csproj; do
+ echo "=== Building $proj ==="
+ dotnet build -c Release --no-restore "$proj"
+ done
+
- name: Test with coverage
+ shell: bash
run: |
set +e
FAILURES=0
@@ -78,12 +90,72 @@ jobs:
exit 1
fi
+ - name: Enforce line coverage threshold
+ if: matrix.os == 'ubuntu-latest'
+ shell: bash
+ run: |
+ python3 <<'PY'
+ import pathlib, sys, xml.etree.ElementTree as ET
+
+ threshold = 85.0
+ files = list(pathlib.Path("artifacts/test-results").rglob("coverage.cobertura.xml"))
+ if not files:
+ print("::error::No cobertura coverage files found.", file=sys.stderr)
+ sys.exit(1)
+
+ # Deduplicate by package name so multi-project Coverlet runs do not double-count.
+ package_stats: dict[str, tuple[int, int]] = {}
+ for path in files:
+ root = ET.parse(path).getroot()
+ for package in root.findall(".//package"):
+ name = package.attrib.get("name", "")
+ if not name or ".Tests" in name or ".Sample" in name or ".Benchmarks" in name:
+ continue
+ if "FunctionFoundry." not in name:
+ continue
+ covered = 0
+ valid = 0
+ for line in package.findall(".//line"):
+ valid += 1
+ if int(line.attrib.get("hits", "0")) > 0:
+ covered += 1
+ previous = package_stats.get(name)
+ if previous is None or valid > previous[1]:
+ package_stats[name] = (covered, valid)
+
+ if not package_stats:
+ # Fallback to document totals when package names are unavailable.
+ covered = valid = 0
+ for path in files:
+ root = ET.parse(path).getroot()
+ covered += int(float(root.attrib.get("lines-covered", "0")))
+ valid += int(float(root.attrib.get("lines-valid", "0")))
+ else:
+ covered = sum(c for c, _ in package_stats.values())
+ valid = sum(v for _, v in package_stats.values())
+ for name, (c, v) in sorted(package_stats.items()):
+ pct_pkg = 100.0 * c / v if v else 0.0
+ print(f" {name}: {pct_pkg:.1f}% ({c}/{v})")
+
+ if valid == 0:
+ print("::error::Coverage files contained zero valid lines.", file=sys.stderr)
+ sys.exit(1)
+
+ pct = 100.0 * covered / valid
+ print(f"Aggregated line coverage: {pct:.2f}% ({covered}/{valid}) across {len(package_stats) or len(files)} packages/files")
+ if pct + 1e-9 < threshold:
+ print(f"::error::Line coverage {pct:.2f}% is below required {threshold:.1f}%.", file=sys.stderr)
+ sys.exit(1)
+ PY
+
- name: Pack
+ if: matrix.os == 'ubuntu-latest'
run: |
mkdir -p artifacts/packages
dotnet pack -c Release --no-build -o artifacts/packages
- name: Upload artifacts
+ if: matrix.os == 'ubuntu-latest'
uses: actions/upload-artifact@v4
with:
name: packages-and-tests
@@ -100,4 +172,3 @@ jobs:
steps:
- uses: actions/checkout@v4
- uses: actions/dependency-review-action@v4
- continue-on-error: true
diff --git a/.github/workflows/publish-nuget.yml b/.github/workflows/publish-nuget.yml
new file mode 100644
index 0000000..2777a59
--- /dev/null
+++ b/.github/workflows/publish-nuget.yml
@@ -0,0 +1,72 @@
+name: Publish NuGet
+
+on:
+ workflow_dispatch:
+ inputs:
+ version:
+ description: SemVer package version to publish (e.g. 1.0.0)
+ required: true
+ default: "1.0.0"
+ release:
+ types: [published]
+
+env:
+ DOTNET_NOLOGO: true
+ DOTNET_CLI_TELEMETRY_OPTOUT: true
+ DOTNET_SKIP_FIRST_TIME_EXPERIENCE: true
+ CI: true
+ FF_RELEASE_PACK: true
+
+jobs:
+ publish:
+ runs-on: ubuntu-latest
+ permissions:
+ contents: read
+ steps:
+ - name: Checkout
+ uses: actions/checkout@v4
+
+ - name: Resolve version
+ id: ver
+ shell: bash
+ run: |
+ if [ "${{ github.event_name }}" = "release" ]; then
+ TAG="${{ github.event.release.tag_name }}"
+ VERSION="${TAG#v}"
+ else
+ VERSION="${{ inputs.version }}"
+ fi
+ echo "version=$VERSION" >> "$GITHUB_OUTPUT"
+ echo "Publishing version $VERSION"
+
+ - name: Setup .NET SDK
+ uses: actions/setup-dotnet@v4
+ with:
+ global-json-file: global.json
+
+ - name: Restore / build / pack (no -local suffix)
+ run: |
+ dotnet restore --locked-mode
+ dotnet build -c Release --no-restore -p:Version=${{ steps.ver.outputs.version }} -p:VersionSuffix=
+ mkdir -p artifacts/packages
+ dotnet pack -c Release --no-build -o artifacts/packages -p:Version=${{ steps.ver.outputs.version }} -p:VersionSuffix=
+
+ - name: Push to NuGet.org
+ env:
+ NUGET_API_KEY: ${{ secrets.NUGET_API_KEY }}
+ shell: bash
+ run: |
+ if [ -z "$NUGET_API_KEY" ]; then
+ echo "::error::NUGET_API_KEY secret is not configured."
+ exit 1
+ fi
+ shopt -s nullglob
+ packages=(artifacts/packages/FunctionFoundry.*.${{ steps.ver.outputs.version }}.nupkg)
+ if [ ${#packages[@]} -eq 0 ]; then
+ echo "::error::No nupkg files found for version ${{ steps.ver.outputs.version }}."
+ exit 1
+ fi
+ for pkg in "${packages[@]}"; do
+ echo "Pushing $pkg"
+ dotnet nuget push "$pkg" --api-key "$NUGET_API_KEY" --source https://api.nuget.org/v3/index.json --skip-duplicate
+ done
diff --git a/CHANGELOG.md b/CHANGELOG.md
index c9c0a01..1a9278f 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -9,7 +9,23 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Changed
-* Relicensed from MIT to **Apache License 2.0** with an attribution `NOTICE` file. Free use remains allowed; FunctionFoundry must be credited when used or redistributed.
+* Pin .NET SDK **10.0.302** (maintenance upgrade from 10.0.301; roll-forward still disabled).
+* Local packs keep the `-local` version suffix; CI and `FF_RELEASE_PACK=true` produce clean SemVer packages suitable for NuGet.org.
+* CI now runs on Ubuntu and Windows, builds all samples, restores with lock files, and fails when aggregated line coverage is below 85%.
+* `FunctionFoundry.Networking` downloader now adapts chunk size within min/max from observed throughput and performs corrupt-chunk / digest repair passes.
+* Security reporting documents GitHub Security Advisories as the private channel.
+
+### Added
+
+* `.github/workflows/publish-nuget.yml` for clean version publishes (requires `NUGET_API_KEY`).
+* Dependabot for GitHub Actions and NuGet.
+* `CODE_OF_CONDUCT.md`.
+* Package lock files (`packages.lock.json`) for reproducible restores.
+
+### Fixed
+
+* Documentation drift (test counts, tag naming, release/NuGet status) in `STATE.md` and `docs/FINAL_REPORT.md`.
+* Changelog now records the Apache 2.0 relicense under 1.0.0 (was incorrectly left only under Unreleased).
## [1.0.0] - 2026-07-14
@@ -25,9 +41,14 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
* `FunctionFoundry.Networking` — resumable parallel downloader, mirror selector, transfer plan, streaming integrity verifier.
* `FunctionFoundry.Distributed` — weighted rendezvous hashing, version clocks, phi-accrual detector, quorum aggregator.
* `FunctionFoundry.Scheduling` — interval-set algebra, recurring availability, business calendars, critical-path scheduler.
-* Repository engineering foundation (SDK 10.0.301 pin, analyzers, CI, ADRs, documentation).
+* Repository engineering foundation (SDK pin, analyzers, CI, ADRs, documentation).
+
+### Changed
+
+* Licensed under the **Apache License 2.0** with an attribution `NOTICE` file. Free use remains allowed; FunctionFoundry must be credited when used or redistributed.
### Notes
-* Feature 1 packages were hardened as the conceptual v0.5.0 baseline; Feature 2 completion is released as v1.0.0 local package artifacts.
+* Feature 1 packages were hardened as the conceptual v0.5.0 baseline; Feature 2 completion is released as v1.0.0.
* No mandatory aggregate package. Core packages have zero third-party runtime dependencies.
+* An accidental NuGet publish of `1.0.0-local` should be replaced by a clean `1.0.0` using the Publish NuGet workflow.
diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md
new file mode 100644
index 0000000..5cee24c
--- /dev/null
+++ b/CODE_OF_CONDUCT.md
@@ -0,0 +1,28 @@
+# Code of Conduct
+
+## Our pledge
+
+We pledge to make participation in FunctionFoundry a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, sex characteristics, gender identity and expression, experience level, education, socio-economic status, nationality, personal appearance, race, religion, or sexual identity and orientation.
+
+## Our standards
+
+Examples of behavior that contributes to a positive environment include:
+
+* Using welcoming and inclusive language
+* Being respectful of differing viewpoints and experiences
+* Gracefully accepting constructive criticism
+* Focusing on what is best for the community
+
+Examples of unacceptable behavior include:
+
+* Harassment, trolling, insulting or derogatory comments
+* Publishing others' private information without permission
+* Other conduct which could reasonably be considered inappropriate in a professional setting
+
+## Enforcement
+
+Report unacceptable behavior privately using the channels in [SECURITY.md](SECURITY.md) for sensitive matters, or contact the repository maintainers via GitHub for conduct issues. Maintainers will review and take appropriate action.
+
+## Attribution
+
+This Code of Conduct is adapted from the [Contributor Covenant](https://www.contributor-covenant.org/), version 2.1.
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 18f4a72..ff1ef39 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -4,16 +4,26 @@ Thank you for contributing. This repository builds specialized .NET libraries, n
## Development setup
-1. Install .NET SDK **10.0.301** exactly (see `global.json`).
+1. Install .NET SDK **10.0.302** exactly (see `global.json`).
2. Restore, build, and test:
```bash
-dotnet restore
+dotnet restore --locked-mode
dotnet build -c Release
dotnet test -c Release --collect:"XPlat Code Coverage"
dotnet pack -c Release
```
+Release packs without the `-local` suffix:
+
+```bash
+# Linux / macOS
+FF_RELEASE_PACK=true ./build/publish-release.sh
+
+# Windows
+set FF_RELEASE_PACK=true&& build\publish-release.cmd
+```
+
## Coding standards
* Target `net10.0`, C# 14, nullable enabled, warnings as errors.
diff --git a/Directory.Build.props b/Directory.Build.props
index a74585b..5f14f8d 100644
--- a/Directory.Build.props
+++ b/Directory.Build.props
@@ -23,7 +23,9 @@
true
snupkg
1.0.0
- local
+
+ local
+ true
$(MSBuildThisFileDirectory)artifacts
$(ArtifactsPath)/packages
diff --git a/README.md b/README.md
index d2a8420..c15ab1b 100644
--- a/README.md
+++ b/README.md
@@ -1,10 +1,10 @@
# FunctionFoundry
[](https://github.com/Chookees/FunctionFoundry/actions/workflows/ci.yml)
-[](global.json)
-[](docs/coverage-summary.md)
-[](docs/coverage-summary.md)
-[](docs/coverage-summary.md)
+[](global.json)
+[](docs/coverage-summary.md)
+[](docs/coverage-summary.md)
+[](docs/coverage-summary.md)
[](docs/coverage-summary.md)
[](LICENSE)
[](#packages)
@@ -32,12 +32,14 @@ Each product has a dedicated README under `src//README.md` describing e
## Requirements
-* .NET SDK **10.0.301** (pinned in `global.json`; roll-forward disabled)
+* .NET SDK **10.0.302** (pinned in `global.json`; roll-forward disabled)
* Target framework: `net10.0`
* C# 14.0
SDK versions receive explicit maintenance upgrades only. Do not silently change the pinned feature band.
+Local `dotnet pack` produces `*-local` package versions by design. Release packs (CI or `FF_RELEASE_PACK=true` / publish workflow) omit the suffix.
+
## Build
```bash
diff --git a/SECURITY.md b/SECURITY.md
index 202fa63..4ab97f7 100644
--- a/SECURITY.md
+++ b/SECURITY.md
@@ -2,11 +2,15 @@
## Supported versions
-Security updates are provided for the latest released major version of FunctionFoundry packages (currently targeting the v1.0 line once released).
+Security updates are provided for the latest released major version of FunctionFoundry packages (currently the v1.0 line).
## Reporting a vulnerability
-Please report security vulnerabilities privately. Do not open a public GitHub issue for undisclosed defects.
+Please report security vulnerabilities **privately**. Do not open a public GitHub issue for undisclosed defects.
+
+**Preferred channel:** use [GitHub Security Advisories → Report a vulnerability](https://github.com/Chookees/FunctionFoundry/security/advisories/new) on this repository.
+
+If you cannot use GitHub Security Advisories, email the maintainers via the contact listed on the [GitHub organization / repository security contacts](https://github.com/Chookees/FunctionFoundry#security) once configured, or open a private maintainer contact request without including exploit details in a public issue.
Include:
diff --git a/STATE.md b/STATE.md
index e19d0a6..7fac73b 100644
--- a/STATE.md
+++ b/STATE.md
@@ -4,73 +4,44 @@ Resume this file instead of conversation context.
## Current Feature
-FF-F02 complete; FunctionFoundry v1.0.0 local artifacts generated.
+Health-scan remediation on branch `chore/health-scan-remediation` (SDK pin, NuGet release path, CI gates, Networking adaptive/repair, docs honesty).
## Current PBI
-All PBIs PBI-01..PBI-12 delivered on branch `cursor/functionfoundry-v1-482e` / `main`.
+All PBIs PBI-01..PBI-12 delivered on `main`. Follow-up hardening in progress on remediation branch.
## Completed Tasks
-* PBI-01 foundation
-* PBI-02 Security
-* PBI-03 Storage
-* PBI-04 Integrity
-* PBI-05 Observability
-* PBI-06 hardening report / size report / docs
-* PBI-07 Data
-* PBI-08 Text
-* PBI-09 Resilience
-* PBI-10 Networking
-* PBI-11 Distributed
-* PBI-12 Scheduling + v1.0 packaging
+* PBI-01..PBI-12 (v1.0 feature set)
+* Git tag `1.0.0` on origin (no `v` prefix)
+* Local and CI package production for 10 libraries
## Remaining Tasks
-* Optional: NuGet.org publish (requires credentials/permission)
-* Optional: git tags `v0.5.0` / `v1.0.0` if tagging succeeds on remote
-* Optional: Native AOT/trimming smoke apps before claiming IsAotCompatible
+* Publish clean NuGet `1.0.0` via `.github/workflows/publish-nuget.yml` (requires `NUGET_API_KEY` secret); unlist or leave `1.0.0-local` as accidental pre-release
+* Optional: Native AOT/trimming smoke apps before claiming `IsAotCompatible`
+* Optional: raise branch coverage toward ≥90% on critical algorithms (Distributed/Integrity still the weakest)
## Last successful commands
-* `dotnet build -c Release` — 0 warnings/errors (all 10 packages + tests/samples/benchmarks)
-* `dotnet test -c Release` — **182 passed**
-* `dotnet pack -c Release -o artifacts/packages /p:Version=1.0.0` — 10 nupkg + snupkg
-
-## Last successful commit
-
-Recorded after hardening commit / main fast-forward (see git log).
-
-## Main-branch PBI commits (expected)
-
-* PBI-01: `86bc024` build(repo)...
-* PBI-02: `b89ed86` feat(security)...
-* PBI-04: `ba3a4fb` feat(integrity)...
-* PBI-05: `1a5a724` feat(observability)...
-* PBI-03: `f50a08e` feat(storage)...
-* PBI-07..12: see `git log --oneline` on delivery branch (Data/Text/Resilience/Networking/Distributed/Scheduling)
+* Target: `dotnet build -c Release` / `dotnet test -c Release` on SDK **10.0.302**
+* Unit tests: **242** passed
+* Line coverage: **85.8%** (CI gate ≥85%). Branch coverage not re-gated yet.
## Open technical risks
* Full Unicode confusable table not shipped (compact v1 subset documented).
-* Networking adaptive chunk resize and auto-repair of corrupt chunks are partial relative to maximal interpretation of the brief.
* Observability redaction uses bounded reflection.
-* IsTrimmable/IsAotCompatible not claimed.
-* Coverage thresholds not yet enforced via CI report thresholds tooling (tests pass; coverage gate not numerically asserted in CI YAML).
-* Package validation against a prior published baseline not applicable for first release.
+* `IsTrimmable` / `IsAotCompatible` not claimed.
+* First stable NuGet line was mistakenly published as `1.0.0-local`; clean `1.0.0` publish still pending credentials.
+* Package validation baseline against published `1.0.0` should be enabled after the clean publish.
## Decisions made
-* ADRs 0001-0005
-* Modular independent DLLs; no FunctionProvider code copied
-* Zero third-party runtime dependencies across all core packages
-
-## Known deviations
-
-* Cloud agent branches use `cursor/...-482e` naming.
-* PBI commit order on main is not strictly numeric (Integrity/Observability landed before Storage).
-* Separate Feature 1 `v0.5.0` git tag may be skipped if tagging Focuses on `v1.0.0` only.
+* ADRs 0001-0006
+* Modular independent DLLs; zero third-party runtime dependencies
+* Local packs keep `-local` suffix; release packs clear `VersionSuffix` (`CI=true` or `FF_RELEASE_PACK=true`)
## Exact next action
-Commit hardening docs, push delivery branch + main, open PR, attempt `v1.0.0` tag.
+Land remediation PR, configure `NUGET_API_KEY`, run Publish NuGet workflow for `1.0.0`, then set `PackageValidationBaselineVersion` to `1.0.0`.
diff --git a/benchmarks/FunctionFoundry.Data.Benchmarks/packages.lock.json b/benchmarks/FunctionFoundry.Data.Benchmarks/packages.lock.json
new file mode 100644
index 0000000..8286fa2
--- /dev/null
+++ b/benchmarks/FunctionFoundry.Data.Benchmarks/packages.lock.json
@@ -0,0 +1,166 @@
+{
+ "version": 2,
+ "dependencies": {
+ "net10.0": {
+ "BenchmarkDotNet": {
+ "type": "Direct",
+ "requested": "[0.15.2, )",
+ "resolved": "0.15.2",
+ "contentHash": "5vl4nQFUGTKgOVE5LNoLpv/X/wFQ7wE5yiaJAXCpzgNtUADtfEwbuufKI4o5E2De0VTXNEeom5Hnv8S8vuBZtg==",
+ "dependencies": {
+ "BenchmarkDotNet.Annotations": "0.15.2",
+ "CommandLineParser": "2.9.1",
+ "Gee.External.Capstone": "2.3.0",
+ "Iced": "1.21.0",
+ "Microsoft.CodeAnalysis.CSharp": "4.14.0",
+ "Microsoft.Diagnostics.Runtime": "3.1.512801",
+ "Microsoft.Diagnostics.Tracing.TraceEvent": "3.1.21",
+ "Microsoft.DotNet.PlatformAbstractions": "3.1.6",
+ "Perfolizer": "[0.5.3]",
+ "System.Management": "9.0.5"
+ }
+ },
+ "BenchmarkDotNet.Annotations": {
+ "type": "Transitive",
+ "resolved": "0.15.2",
+ "contentHash": "a7rVlVmXQRrp3J+HF/FtjwiFcshU6BAuv6U1xtAbqCUYepOEnNGaPeOFvy4It17QZwwofm6U/GAfW3JrFMXszg=="
+ },
+ "CommandLineParser": {
+ "type": "Transitive",
+ "resolved": "2.9.1",
+ "contentHash": "OE0sl1/sQ37bjVsPKKtwQlWDgqaxWgtme3xZz7JssWUzg5JpMIyHgCTY9MVMxOg48fJ1AgGT3tgdH5m/kQ5xhA=="
+ },
+ "Gee.External.Capstone": {
+ "type": "Transitive",
+ "resolved": "2.3.0",
+ "contentHash": "2ap/rYmjtzCOT8hxrnEW/QeiOt+paD8iRrIcdKX0cxVwWLFa1e+JDBNeECakmccXrSFeBQuu5AV8SNkipFMMMw=="
+ },
+ "Iced": {
+ "type": "Transitive",
+ "resolved": "1.21.0",
+ "contentHash": "dv5+81Q1TBQvVMSOOOmRcjJmvWcX3BZPZsIq31+RLc5cNft0IHAyNlkdb7ZarOWG913PyBoFDsDXoCIlKmLclg=="
+ },
+ "Microsoft.CodeAnalysis.Analyzers": {
+ "type": "Transitive",
+ "resolved": "3.11.0",
+ "contentHash": "v/EW3UE8/lbEYHoC2Qq7AR/DnmvpgdtAMndfQNmpuIMx/Mto8L5JnuCfdBYtgvalQOtfNCnxFejxuRrryvUTsg=="
+ },
+ "Microsoft.CodeAnalysis.Common": {
+ "type": "Transitive",
+ "resolved": "4.14.0",
+ "contentHash": "PC3tuwZYnC+idaPuoC/AZpEdwrtX7qFpmnrfQkgobGIWiYmGi5MCRtl5mx6QrfMGQpK78X2lfIEoZDLg/qnuHg==",
+ "dependencies": {
+ "Microsoft.CodeAnalysis.Analyzers": "3.11.0"
+ }
+ },
+ "Microsoft.CodeAnalysis.CSharp": {
+ "type": "Transitive",
+ "resolved": "4.14.0",
+ "contentHash": "568a6wcTivauIhbeWcCwfWwIn7UV7MeHEBvFB2uzGIpM2OhJ4eM/FZ8KS0yhPoNxnSpjGzz7x7CIjTxhslojQA==",
+ "dependencies": {
+ "Microsoft.CodeAnalysis.Analyzers": "3.11.0",
+ "Microsoft.CodeAnalysis.Common": "[4.14.0]"
+ }
+ },
+ "Microsoft.Diagnostics.NETCore.Client": {
+ "type": "Transitive",
+ "resolved": "0.2.510501",
+ "contentHash": "juoqJYMDs+lRrrZyOkXXMImJHneCF23cuvO4waFRd2Ds7j+ZuGIPbJm0Y/zz34BdeaGiiwGWraMUlln05W1PCQ==",
+ "dependencies": {
+ "Microsoft.Extensions.Logging": "6.0.0"
+ }
+ },
+ "Microsoft.Diagnostics.Runtime": {
+ "type": "Transitive",
+ "resolved": "3.1.512801",
+ "contentHash": "0lMUDr2oxNZa28D6NH5BuSQEe5T9tZziIkvkD44YkkCGQXPJqvFjLq5ZQq1hYLl3RjQJrY+hR0jFgap+EWPDTw==",
+ "dependencies": {
+ "Microsoft.Diagnostics.NETCore.Client": "0.2.410101"
+ }
+ },
+ "Microsoft.Diagnostics.Tracing.TraceEvent": {
+ "type": "Transitive",
+ "resolved": "3.1.21",
+ "contentHash": "/OrJFKaojSR6TkUKtwh8/qA9XWNtxLrXMqvEb89dBSKCWjaGVTbKMYodIUgF5deCEtmd6GXuRerciXGl5bhZ7Q==",
+ "dependencies": {
+ "Microsoft.Diagnostics.NETCore.Client": "0.2.510501",
+ "System.Reflection.TypeExtensions": "4.7.0"
+ }
+ },
+ "Microsoft.DotNet.PlatformAbstractions": {
+ "type": "Transitive",
+ "resolved": "3.1.6",
+ "contentHash": "jek4XYaQ/PGUwDKKhwR8K47Uh1189PFzMeLqO83mXrXQVIpARZCcfuDedH50YDTepBkfijCZN5U/vZi++erxtg=="
+ },
+ "Microsoft.Extensions.DependencyInjection": {
+ "type": "Transitive",
+ "resolved": "6.0.0",
+ "contentHash": "k6PWQMuoBDGGHOQTtyois2u4AwyVcIwL2LaSLlTZQm2CYcJ1pxbt6jfAnpWmzENA/wfrYRI/X9DTLoUkE4AsLw==",
+ "dependencies": {
+ "Microsoft.Extensions.DependencyInjection.Abstractions": "6.0.0"
+ }
+ },
+ "Microsoft.Extensions.DependencyInjection.Abstractions": {
+ "type": "Transitive",
+ "resolved": "6.0.0",
+ "contentHash": "xlzi2IYREJH3/m6+lUrQlujzX8wDitm4QGnUu6kUXTQAWPuZY8i+ticFJbzfqaetLA6KR/rO6Ew/HuYD+bxifg=="
+ },
+ "Microsoft.Extensions.Logging": {
+ "type": "Transitive",
+ "resolved": "6.0.0",
+ "contentHash": "eIbyj40QDg1NDz0HBW0S5f3wrLVnKWnDJ/JtZ+yJDFnDj90VoPuoPmFkeaXrtu+0cKm5GRAwoDf+dBWXK0TUdg==",
+ "dependencies": {
+ "Microsoft.Extensions.DependencyInjection": "6.0.0",
+ "Microsoft.Extensions.DependencyInjection.Abstractions": "6.0.0",
+ "Microsoft.Extensions.Logging.Abstractions": "6.0.0",
+ "Microsoft.Extensions.Options": "6.0.0"
+ }
+ },
+ "Microsoft.Extensions.Logging.Abstractions": {
+ "type": "Transitive",
+ "resolved": "6.0.0",
+ "contentHash": "/HggWBbTwy8TgebGSX5DBZ24ndhzi93sHUBDvP1IxbZD7FDokYzdAr6+vbWGjw2XAfR2EJ1sfKUotpjHnFWPxA=="
+ },
+ "Microsoft.Extensions.Options": {
+ "type": "Transitive",
+ "resolved": "6.0.0",
+ "contentHash": "dzXN0+V1AyjOe2xcJ86Qbo233KHuLEY0njf/P2Kw8SfJU+d45HNS2ctJdnEnrWbM9Ye2eFgaC5Mj9otRMU6IsQ==",
+ "dependencies": {
+ "Microsoft.Extensions.DependencyInjection.Abstractions": "6.0.0",
+ "Microsoft.Extensions.Primitives": "6.0.0"
+ }
+ },
+ "Microsoft.Extensions.Primitives": {
+ "type": "Transitive",
+ "resolved": "6.0.0",
+ "contentHash": "9+PnzmQFfEFNR9J2aDTfJGGupShHjOuGw4VUv+JB044biSHrnmCIMD+mJHmb2H7YryrfBEXDurxQ47gJZdCKNQ=="
+ },
+ "Perfolizer": {
+ "type": "Transitive",
+ "resolved": "0.5.3",
+ "contentHash": "EhHo0s4y+tHJKhZHgQvPgFWhAhnQpHHuFzutRzfqfv5z763wvhzXh849ZtpVePQNxXWoFafh1Ta2tZgnSIVsYQ=="
+ },
+ "System.CodeDom": {
+ "type": "Transitive",
+ "resolved": "9.0.5",
+ "contentHash": "cuzLM2MWutf9ZBEMPYYfd0DXwYdvntp7VCT6a/wvbKCa2ZuvGmW74xi+YBa2mrfEieAXqM4TNKlMmSnfAfpUoQ=="
+ },
+ "System.Management": {
+ "type": "Transitive",
+ "resolved": "9.0.5",
+ "contentHash": "n6o9PZm9p25+zAzC3/48K0oHnaPKTInRrxqFq1fi/5TPbMLjuoCm/h//mS3cUmSy+9AO1Z+qsC/Ilt/ZFatv5Q==",
+ "dependencies": {
+ "System.CodeDom": "9.0.5"
+ }
+ },
+ "System.Reflection.TypeExtensions": {
+ "type": "Transitive",
+ "resolved": "4.7.0",
+ "contentHash": "VybpaOQQhqE6siHppMktjfGBw1GCwvCqiufqmP8F1nj7fTUNtW35LOEt3UZTEsECfo+ELAl/9o9nJx3U91i7vA=="
+ },
+ "functionfoundry.data": {
+ "type": "Project"
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/benchmarks/FunctionFoundry.Distributed.Benchmarks/packages.lock.json b/benchmarks/FunctionFoundry.Distributed.Benchmarks/packages.lock.json
new file mode 100644
index 0000000..fdb89e0
--- /dev/null
+++ b/benchmarks/FunctionFoundry.Distributed.Benchmarks/packages.lock.json
@@ -0,0 +1,166 @@
+{
+ "version": 2,
+ "dependencies": {
+ "net10.0": {
+ "BenchmarkDotNet": {
+ "type": "Direct",
+ "requested": "[0.15.2, )",
+ "resolved": "0.15.2",
+ "contentHash": "5vl4nQFUGTKgOVE5LNoLpv/X/wFQ7wE5yiaJAXCpzgNtUADtfEwbuufKI4o5E2De0VTXNEeom5Hnv8S8vuBZtg==",
+ "dependencies": {
+ "BenchmarkDotNet.Annotations": "0.15.2",
+ "CommandLineParser": "2.9.1",
+ "Gee.External.Capstone": "2.3.0",
+ "Iced": "1.21.0",
+ "Microsoft.CodeAnalysis.CSharp": "4.14.0",
+ "Microsoft.Diagnostics.Runtime": "3.1.512801",
+ "Microsoft.Diagnostics.Tracing.TraceEvent": "3.1.21",
+ "Microsoft.DotNet.PlatformAbstractions": "3.1.6",
+ "Perfolizer": "[0.5.3]",
+ "System.Management": "9.0.5"
+ }
+ },
+ "BenchmarkDotNet.Annotations": {
+ "type": "Transitive",
+ "resolved": "0.15.2",
+ "contentHash": "a7rVlVmXQRrp3J+HF/FtjwiFcshU6BAuv6U1xtAbqCUYepOEnNGaPeOFvy4It17QZwwofm6U/GAfW3JrFMXszg=="
+ },
+ "CommandLineParser": {
+ "type": "Transitive",
+ "resolved": "2.9.1",
+ "contentHash": "OE0sl1/sQ37bjVsPKKtwQlWDgqaxWgtme3xZz7JssWUzg5JpMIyHgCTY9MVMxOg48fJ1AgGT3tgdH5m/kQ5xhA=="
+ },
+ "Gee.External.Capstone": {
+ "type": "Transitive",
+ "resolved": "2.3.0",
+ "contentHash": "2ap/rYmjtzCOT8hxrnEW/QeiOt+paD8iRrIcdKX0cxVwWLFa1e+JDBNeECakmccXrSFeBQuu5AV8SNkipFMMMw=="
+ },
+ "Iced": {
+ "type": "Transitive",
+ "resolved": "1.21.0",
+ "contentHash": "dv5+81Q1TBQvVMSOOOmRcjJmvWcX3BZPZsIq31+RLc5cNft0IHAyNlkdb7ZarOWG913PyBoFDsDXoCIlKmLclg=="
+ },
+ "Microsoft.CodeAnalysis.Analyzers": {
+ "type": "Transitive",
+ "resolved": "3.11.0",
+ "contentHash": "v/EW3UE8/lbEYHoC2Qq7AR/DnmvpgdtAMndfQNmpuIMx/Mto8L5JnuCfdBYtgvalQOtfNCnxFejxuRrryvUTsg=="
+ },
+ "Microsoft.CodeAnalysis.Common": {
+ "type": "Transitive",
+ "resolved": "4.14.0",
+ "contentHash": "PC3tuwZYnC+idaPuoC/AZpEdwrtX7qFpmnrfQkgobGIWiYmGi5MCRtl5mx6QrfMGQpK78X2lfIEoZDLg/qnuHg==",
+ "dependencies": {
+ "Microsoft.CodeAnalysis.Analyzers": "3.11.0"
+ }
+ },
+ "Microsoft.CodeAnalysis.CSharp": {
+ "type": "Transitive",
+ "resolved": "4.14.0",
+ "contentHash": "568a6wcTivauIhbeWcCwfWwIn7UV7MeHEBvFB2uzGIpM2OhJ4eM/FZ8KS0yhPoNxnSpjGzz7x7CIjTxhslojQA==",
+ "dependencies": {
+ "Microsoft.CodeAnalysis.Analyzers": "3.11.0",
+ "Microsoft.CodeAnalysis.Common": "[4.14.0]"
+ }
+ },
+ "Microsoft.Diagnostics.NETCore.Client": {
+ "type": "Transitive",
+ "resolved": "0.2.510501",
+ "contentHash": "juoqJYMDs+lRrrZyOkXXMImJHneCF23cuvO4waFRd2Ds7j+ZuGIPbJm0Y/zz34BdeaGiiwGWraMUlln05W1PCQ==",
+ "dependencies": {
+ "Microsoft.Extensions.Logging": "6.0.0"
+ }
+ },
+ "Microsoft.Diagnostics.Runtime": {
+ "type": "Transitive",
+ "resolved": "3.1.512801",
+ "contentHash": "0lMUDr2oxNZa28D6NH5BuSQEe5T9tZziIkvkD44YkkCGQXPJqvFjLq5ZQq1hYLl3RjQJrY+hR0jFgap+EWPDTw==",
+ "dependencies": {
+ "Microsoft.Diagnostics.NETCore.Client": "0.2.410101"
+ }
+ },
+ "Microsoft.Diagnostics.Tracing.TraceEvent": {
+ "type": "Transitive",
+ "resolved": "3.1.21",
+ "contentHash": "/OrJFKaojSR6TkUKtwh8/qA9XWNtxLrXMqvEb89dBSKCWjaGVTbKMYodIUgF5deCEtmd6GXuRerciXGl5bhZ7Q==",
+ "dependencies": {
+ "Microsoft.Diagnostics.NETCore.Client": "0.2.510501",
+ "System.Reflection.TypeExtensions": "4.7.0"
+ }
+ },
+ "Microsoft.DotNet.PlatformAbstractions": {
+ "type": "Transitive",
+ "resolved": "3.1.6",
+ "contentHash": "jek4XYaQ/PGUwDKKhwR8K47Uh1189PFzMeLqO83mXrXQVIpARZCcfuDedH50YDTepBkfijCZN5U/vZi++erxtg=="
+ },
+ "Microsoft.Extensions.DependencyInjection": {
+ "type": "Transitive",
+ "resolved": "6.0.0",
+ "contentHash": "k6PWQMuoBDGGHOQTtyois2u4AwyVcIwL2LaSLlTZQm2CYcJ1pxbt6jfAnpWmzENA/wfrYRI/X9DTLoUkE4AsLw==",
+ "dependencies": {
+ "Microsoft.Extensions.DependencyInjection.Abstractions": "6.0.0"
+ }
+ },
+ "Microsoft.Extensions.DependencyInjection.Abstractions": {
+ "type": "Transitive",
+ "resolved": "6.0.0",
+ "contentHash": "xlzi2IYREJH3/m6+lUrQlujzX8wDitm4QGnUu6kUXTQAWPuZY8i+ticFJbzfqaetLA6KR/rO6Ew/HuYD+bxifg=="
+ },
+ "Microsoft.Extensions.Logging": {
+ "type": "Transitive",
+ "resolved": "6.0.0",
+ "contentHash": "eIbyj40QDg1NDz0HBW0S5f3wrLVnKWnDJ/JtZ+yJDFnDj90VoPuoPmFkeaXrtu+0cKm5GRAwoDf+dBWXK0TUdg==",
+ "dependencies": {
+ "Microsoft.Extensions.DependencyInjection": "6.0.0",
+ "Microsoft.Extensions.DependencyInjection.Abstractions": "6.0.0",
+ "Microsoft.Extensions.Logging.Abstractions": "6.0.0",
+ "Microsoft.Extensions.Options": "6.0.0"
+ }
+ },
+ "Microsoft.Extensions.Logging.Abstractions": {
+ "type": "Transitive",
+ "resolved": "6.0.0",
+ "contentHash": "/HggWBbTwy8TgebGSX5DBZ24ndhzi93sHUBDvP1IxbZD7FDokYzdAr6+vbWGjw2XAfR2EJ1sfKUotpjHnFWPxA=="
+ },
+ "Microsoft.Extensions.Options": {
+ "type": "Transitive",
+ "resolved": "6.0.0",
+ "contentHash": "dzXN0+V1AyjOe2xcJ86Qbo233KHuLEY0njf/P2Kw8SfJU+d45HNS2ctJdnEnrWbM9Ye2eFgaC5Mj9otRMU6IsQ==",
+ "dependencies": {
+ "Microsoft.Extensions.DependencyInjection.Abstractions": "6.0.0",
+ "Microsoft.Extensions.Primitives": "6.0.0"
+ }
+ },
+ "Microsoft.Extensions.Primitives": {
+ "type": "Transitive",
+ "resolved": "6.0.0",
+ "contentHash": "9+PnzmQFfEFNR9J2aDTfJGGupShHjOuGw4VUv+JB044biSHrnmCIMD+mJHmb2H7YryrfBEXDurxQ47gJZdCKNQ=="
+ },
+ "Perfolizer": {
+ "type": "Transitive",
+ "resolved": "0.5.3",
+ "contentHash": "EhHo0s4y+tHJKhZHgQvPgFWhAhnQpHHuFzutRzfqfv5z763wvhzXh849ZtpVePQNxXWoFafh1Ta2tZgnSIVsYQ=="
+ },
+ "System.CodeDom": {
+ "type": "Transitive",
+ "resolved": "9.0.5",
+ "contentHash": "cuzLM2MWutf9ZBEMPYYfd0DXwYdvntp7VCT6a/wvbKCa2ZuvGmW74xi+YBa2mrfEieAXqM4TNKlMmSnfAfpUoQ=="
+ },
+ "System.Management": {
+ "type": "Transitive",
+ "resolved": "9.0.5",
+ "contentHash": "n6o9PZm9p25+zAzC3/48K0oHnaPKTInRrxqFq1fi/5TPbMLjuoCm/h//mS3cUmSy+9AO1Z+qsC/Ilt/ZFatv5Q==",
+ "dependencies": {
+ "System.CodeDom": "9.0.5"
+ }
+ },
+ "System.Reflection.TypeExtensions": {
+ "type": "Transitive",
+ "resolved": "4.7.0",
+ "contentHash": "VybpaOQQhqE6siHppMktjfGBw1GCwvCqiufqmP8F1nj7fTUNtW35LOEt3UZTEsECfo+ELAl/9o9nJx3U91i7vA=="
+ },
+ "functionfoundry.distributed": {
+ "type": "Project"
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/benchmarks/FunctionFoundry.Integrity.Benchmarks/packages.lock.json b/benchmarks/FunctionFoundry.Integrity.Benchmarks/packages.lock.json
new file mode 100644
index 0000000..feb2af7
--- /dev/null
+++ b/benchmarks/FunctionFoundry.Integrity.Benchmarks/packages.lock.json
@@ -0,0 +1,166 @@
+{
+ "version": 2,
+ "dependencies": {
+ "net10.0": {
+ "BenchmarkDotNet": {
+ "type": "Direct",
+ "requested": "[0.15.2, )",
+ "resolved": "0.15.2",
+ "contentHash": "5vl4nQFUGTKgOVE5LNoLpv/X/wFQ7wE5yiaJAXCpzgNtUADtfEwbuufKI4o5E2De0VTXNEeom5Hnv8S8vuBZtg==",
+ "dependencies": {
+ "BenchmarkDotNet.Annotations": "0.15.2",
+ "CommandLineParser": "2.9.1",
+ "Gee.External.Capstone": "2.3.0",
+ "Iced": "1.21.0",
+ "Microsoft.CodeAnalysis.CSharp": "4.14.0",
+ "Microsoft.Diagnostics.Runtime": "3.1.512801",
+ "Microsoft.Diagnostics.Tracing.TraceEvent": "3.1.21",
+ "Microsoft.DotNet.PlatformAbstractions": "3.1.6",
+ "Perfolizer": "[0.5.3]",
+ "System.Management": "9.0.5"
+ }
+ },
+ "BenchmarkDotNet.Annotations": {
+ "type": "Transitive",
+ "resolved": "0.15.2",
+ "contentHash": "a7rVlVmXQRrp3J+HF/FtjwiFcshU6BAuv6U1xtAbqCUYepOEnNGaPeOFvy4It17QZwwofm6U/GAfW3JrFMXszg=="
+ },
+ "CommandLineParser": {
+ "type": "Transitive",
+ "resolved": "2.9.1",
+ "contentHash": "OE0sl1/sQ37bjVsPKKtwQlWDgqaxWgtme3xZz7JssWUzg5JpMIyHgCTY9MVMxOg48fJ1AgGT3tgdH5m/kQ5xhA=="
+ },
+ "Gee.External.Capstone": {
+ "type": "Transitive",
+ "resolved": "2.3.0",
+ "contentHash": "2ap/rYmjtzCOT8hxrnEW/QeiOt+paD8iRrIcdKX0cxVwWLFa1e+JDBNeECakmccXrSFeBQuu5AV8SNkipFMMMw=="
+ },
+ "Iced": {
+ "type": "Transitive",
+ "resolved": "1.21.0",
+ "contentHash": "dv5+81Q1TBQvVMSOOOmRcjJmvWcX3BZPZsIq31+RLc5cNft0IHAyNlkdb7ZarOWG913PyBoFDsDXoCIlKmLclg=="
+ },
+ "Microsoft.CodeAnalysis.Analyzers": {
+ "type": "Transitive",
+ "resolved": "3.11.0",
+ "contentHash": "v/EW3UE8/lbEYHoC2Qq7AR/DnmvpgdtAMndfQNmpuIMx/Mto8L5JnuCfdBYtgvalQOtfNCnxFejxuRrryvUTsg=="
+ },
+ "Microsoft.CodeAnalysis.Common": {
+ "type": "Transitive",
+ "resolved": "4.14.0",
+ "contentHash": "PC3tuwZYnC+idaPuoC/AZpEdwrtX7qFpmnrfQkgobGIWiYmGi5MCRtl5mx6QrfMGQpK78X2lfIEoZDLg/qnuHg==",
+ "dependencies": {
+ "Microsoft.CodeAnalysis.Analyzers": "3.11.0"
+ }
+ },
+ "Microsoft.CodeAnalysis.CSharp": {
+ "type": "Transitive",
+ "resolved": "4.14.0",
+ "contentHash": "568a6wcTivauIhbeWcCwfWwIn7UV7MeHEBvFB2uzGIpM2OhJ4eM/FZ8KS0yhPoNxnSpjGzz7x7CIjTxhslojQA==",
+ "dependencies": {
+ "Microsoft.CodeAnalysis.Analyzers": "3.11.0",
+ "Microsoft.CodeAnalysis.Common": "[4.14.0]"
+ }
+ },
+ "Microsoft.Diagnostics.NETCore.Client": {
+ "type": "Transitive",
+ "resolved": "0.2.510501",
+ "contentHash": "juoqJYMDs+lRrrZyOkXXMImJHneCF23cuvO4waFRd2Ds7j+ZuGIPbJm0Y/zz34BdeaGiiwGWraMUlln05W1PCQ==",
+ "dependencies": {
+ "Microsoft.Extensions.Logging": "6.0.0"
+ }
+ },
+ "Microsoft.Diagnostics.Runtime": {
+ "type": "Transitive",
+ "resolved": "3.1.512801",
+ "contentHash": "0lMUDr2oxNZa28D6NH5BuSQEe5T9tZziIkvkD44YkkCGQXPJqvFjLq5ZQq1hYLl3RjQJrY+hR0jFgap+EWPDTw==",
+ "dependencies": {
+ "Microsoft.Diagnostics.NETCore.Client": "0.2.410101"
+ }
+ },
+ "Microsoft.Diagnostics.Tracing.TraceEvent": {
+ "type": "Transitive",
+ "resolved": "3.1.21",
+ "contentHash": "/OrJFKaojSR6TkUKtwh8/qA9XWNtxLrXMqvEb89dBSKCWjaGVTbKMYodIUgF5deCEtmd6GXuRerciXGl5bhZ7Q==",
+ "dependencies": {
+ "Microsoft.Diagnostics.NETCore.Client": "0.2.510501",
+ "System.Reflection.TypeExtensions": "4.7.0"
+ }
+ },
+ "Microsoft.DotNet.PlatformAbstractions": {
+ "type": "Transitive",
+ "resolved": "3.1.6",
+ "contentHash": "jek4XYaQ/PGUwDKKhwR8K47Uh1189PFzMeLqO83mXrXQVIpARZCcfuDedH50YDTepBkfijCZN5U/vZi++erxtg=="
+ },
+ "Microsoft.Extensions.DependencyInjection": {
+ "type": "Transitive",
+ "resolved": "6.0.0",
+ "contentHash": "k6PWQMuoBDGGHOQTtyois2u4AwyVcIwL2LaSLlTZQm2CYcJ1pxbt6jfAnpWmzENA/wfrYRI/X9DTLoUkE4AsLw==",
+ "dependencies": {
+ "Microsoft.Extensions.DependencyInjection.Abstractions": "6.0.0"
+ }
+ },
+ "Microsoft.Extensions.DependencyInjection.Abstractions": {
+ "type": "Transitive",
+ "resolved": "6.0.0",
+ "contentHash": "xlzi2IYREJH3/m6+lUrQlujzX8wDitm4QGnUu6kUXTQAWPuZY8i+ticFJbzfqaetLA6KR/rO6Ew/HuYD+bxifg=="
+ },
+ "Microsoft.Extensions.Logging": {
+ "type": "Transitive",
+ "resolved": "6.0.0",
+ "contentHash": "eIbyj40QDg1NDz0HBW0S5f3wrLVnKWnDJ/JtZ+yJDFnDj90VoPuoPmFkeaXrtu+0cKm5GRAwoDf+dBWXK0TUdg==",
+ "dependencies": {
+ "Microsoft.Extensions.DependencyInjection": "6.0.0",
+ "Microsoft.Extensions.DependencyInjection.Abstractions": "6.0.0",
+ "Microsoft.Extensions.Logging.Abstractions": "6.0.0",
+ "Microsoft.Extensions.Options": "6.0.0"
+ }
+ },
+ "Microsoft.Extensions.Logging.Abstractions": {
+ "type": "Transitive",
+ "resolved": "6.0.0",
+ "contentHash": "/HggWBbTwy8TgebGSX5DBZ24ndhzi93sHUBDvP1IxbZD7FDokYzdAr6+vbWGjw2XAfR2EJ1sfKUotpjHnFWPxA=="
+ },
+ "Microsoft.Extensions.Options": {
+ "type": "Transitive",
+ "resolved": "6.0.0",
+ "contentHash": "dzXN0+V1AyjOe2xcJ86Qbo233KHuLEY0njf/P2Kw8SfJU+d45HNS2ctJdnEnrWbM9Ye2eFgaC5Mj9otRMU6IsQ==",
+ "dependencies": {
+ "Microsoft.Extensions.DependencyInjection.Abstractions": "6.0.0",
+ "Microsoft.Extensions.Primitives": "6.0.0"
+ }
+ },
+ "Microsoft.Extensions.Primitives": {
+ "type": "Transitive",
+ "resolved": "6.0.0",
+ "contentHash": "9+PnzmQFfEFNR9J2aDTfJGGupShHjOuGw4VUv+JB044biSHrnmCIMD+mJHmb2H7YryrfBEXDurxQ47gJZdCKNQ=="
+ },
+ "Perfolizer": {
+ "type": "Transitive",
+ "resolved": "0.5.3",
+ "contentHash": "EhHo0s4y+tHJKhZHgQvPgFWhAhnQpHHuFzutRzfqfv5z763wvhzXh849ZtpVePQNxXWoFafh1Ta2tZgnSIVsYQ=="
+ },
+ "System.CodeDom": {
+ "type": "Transitive",
+ "resolved": "9.0.5",
+ "contentHash": "cuzLM2MWutf9ZBEMPYYfd0DXwYdvntp7VCT6a/wvbKCa2ZuvGmW74xi+YBa2mrfEieAXqM4TNKlMmSnfAfpUoQ=="
+ },
+ "System.Management": {
+ "type": "Transitive",
+ "resolved": "9.0.5",
+ "contentHash": "n6o9PZm9p25+zAzC3/48K0oHnaPKTInRrxqFq1fi/5TPbMLjuoCm/h//mS3cUmSy+9AO1Z+qsC/Ilt/ZFatv5Q==",
+ "dependencies": {
+ "System.CodeDom": "9.0.5"
+ }
+ },
+ "System.Reflection.TypeExtensions": {
+ "type": "Transitive",
+ "resolved": "4.7.0",
+ "contentHash": "VybpaOQQhqE6siHppMktjfGBw1GCwvCqiufqmP8F1nj7fTUNtW35LOEt3UZTEsECfo+ELAl/9o9nJx3U91i7vA=="
+ },
+ "functionfoundry.integrity": {
+ "type": "Project"
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/benchmarks/FunctionFoundry.Networking.Benchmarks/packages.lock.json b/benchmarks/FunctionFoundry.Networking.Benchmarks/packages.lock.json
new file mode 100644
index 0000000..77f8193
--- /dev/null
+++ b/benchmarks/FunctionFoundry.Networking.Benchmarks/packages.lock.json
@@ -0,0 +1,166 @@
+{
+ "version": 2,
+ "dependencies": {
+ "net10.0": {
+ "BenchmarkDotNet": {
+ "type": "Direct",
+ "requested": "[0.15.2, )",
+ "resolved": "0.15.2",
+ "contentHash": "5vl4nQFUGTKgOVE5LNoLpv/X/wFQ7wE5yiaJAXCpzgNtUADtfEwbuufKI4o5E2De0VTXNEeom5Hnv8S8vuBZtg==",
+ "dependencies": {
+ "BenchmarkDotNet.Annotations": "0.15.2",
+ "CommandLineParser": "2.9.1",
+ "Gee.External.Capstone": "2.3.0",
+ "Iced": "1.21.0",
+ "Microsoft.CodeAnalysis.CSharp": "4.14.0",
+ "Microsoft.Diagnostics.Runtime": "3.1.512801",
+ "Microsoft.Diagnostics.Tracing.TraceEvent": "3.1.21",
+ "Microsoft.DotNet.PlatformAbstractions": "3.1.6",
+ "Perfolizer": "[0.5.3]",
+ "System.Management": "9.0.5"
+ }
+ },
+ "BenchmarkDotNet.Annotations": {
+ "type": "Transitive",
+ "resolved": "0.15.2",
+ "contentHash": "a7rVlVmXQRrp3J+HF/FtjwiFcshU6BAuv6U1xtAbqCUYepOEnNGaPeOFvy4It17QZwwofm6U/GAfW3JrFMXszg=="
+ },
+ "CommandLineParser": {
+ "type": "Transitive",
+ "resolved": "2.9.1",
+ "contentHash": "OE0sl1/sQ37bjVsPKKtwQlWDgqaxWgtme3xZz7JssWUzg5JpMIyHgCTY9MVMxOg48fJ1AgGT3tgdH5m/kQ5xhA=="
+ },
+ "Gee.External.Capstone": {
+ "type": "Transitive",
+ "resolved": "2.3.0",
+ "contentHash": "2ap/rYmjtzCOT8hxrnEW/QeiOt+paD8iRrIcdKX0cxVwWLFa1e+JDBNeECakmccXrSFeBQuu5AV8SNkipFMMMw=="
+ },
+ "Iced": {
+ "type": "Transitive",
+ "resolved": "1.21.0",
+ "contentHash": "dv5+81Q1TBQvVMSOOOmRcjJmvWcX3BZPZsIq31+RLc5cNft0IHAyNlkdb7ZarOWG913PyBoFDsDXoCIlKmLclg=="
+ },
+ "Microsoft.CodeAnalysis.Analyzers": {
+ "type": "Transitive",
+ "resolved": "3.11.0",
+ "contentHash": "v/EW3UE8/lbEYHoC2Qq7AR/DnmvpgdtAMndfQNmpuIMx/Mto8L5JnuCfdBYtgvalQOtfNCnxFejxuRrryvUTsg=="
+ },
+ "Microsoft.CodeAnalysis.Common": {
+ "type": "Transitive",
+ "resolved": "4.14.0",
+ "contentHash": "PC3tuwZYnC+idaPuoC/AZpEdwrtX7qFpmnrfQkgobGIWiYmGi5MCRtl5mx6QrfMGQpK78X2lfIEoZDLg/qnuHg==",
+ "dependencies": {
+ "Microsoft.CodeAnalysis.Analyzers": "3.11.0"
+ }
+ },
+ "Microsoft.CodeAnalysis.CSharp": {
+ "type": "Transitive",
+ "resolved": "4.14.0",
+ "contentHash": "568a6wcTivauIhbeWcCwfWwIn7UV7MeHEBvFB2uzGIpM2OhJ4eM/FZ8KS0yhPoNxnSpjGzz7x7CIjTxhslojQA==",
+ "dependencies": {
+ "Microsoft.CodeAnalysis.Analyzers": "3.11.0",
+ "Microsoft.CodeAnalysis.Common": "[4.14.0]"
+ }
+ },
+ "Microsoft.Diagnostics.NETCore.Client": {
+ "type": "Transitive",
+ "resolved": "0.2.510501",
+ "contentHash": "juoqJYMDs+lRrrZyOkXXMImJHneCF23cuvO4waFRd2Ds7j+ZuGIPbJm0Y/zz34BdeaGiiwGWraMUlln05W1PCQ==",
+ "dependencies": {
+ "Microsoft.Extensions.Logging": "6.0.0"
+ }
+ },
+ "Microsoft.Diagnostics.Runtime": {
+ "type": "Transitive",
+ "resolved": "3.1.512801",
+ "contentHash": "0lMUDr2oxNZa28D6NH5BuSQEe5T9tZziIkvkD44YkkCGQXPJqvFjLq5ZQq1hYLl3RjQJrY+hR0jFgap+EWPDTw==",
+ "dependencies": {
+ "Microsoft.Diagnostics.NETCore.Client": "0.2.410101"
+ }
+ },
+ "Microsoft.Diagnostics.Tracing.TraceEvent": {
+ "type": "Transitive",
+ "resolved": "3.1.21",
+ "contentHash": "/OrJFKaojSR6TkUKtwh8/qA9XWNtxLrXMqvEb89dBSKCWjaGVTbKMYodIUgF5deCEtmd6GXuRerciXGl5bhZ7Q==",
+ "dependencies": {
+ "Microsoft.Diagnostics.NETCore.Client": "0.2.510501",
+ "System.Reflection.TypeExtensions": "4.7.0"
+ }
+ },
+ "Microsoft.DotNet.PlatformAbstractions": {
+ "type": "Transitive",
+ "resolved": "3.1.6",
+ "contentHash": "jek4XYaQ/PGUwDKKhwR8K47Uh1189PFzMeLqO83mXrXQVIpARZCcfuDedH50YDTepBkfijCZN5U/vZi++erxtg=="
+ },
+ "Microsoft.Extensions.DependencyInjection": {
+ "type": "Transitive",
+ "resolved": "6.0.0",
+ "contentHash": "k6PWQMuoBDGGHOQTtyois2u4AwyVcIwL2LaSLlTZQm2CYcJ1pxbt6jfAnpWmzENA/wfrYRI/X9DTLoUkE4AsLw==",
+ "dependencies": {
+ "Microsoft.Extensions.DependencyInjection.Abstractions": "6.0.0"
+ }
+ },
+ "Microsoft.Extensions.DependencyInjection.Abstractions": {
+ "type": "Transitive",
+ "resolved": "6.0.0",
+ "contentHash": "xlzi2IYREJH3/m6+lUrQlujzX8wDitm4QGnUu6kUXTQAWPuZY8i+ticFJbzfqaetLA6KR/rO6Ew/HuYD+bxifg=="
+ },
+ "Microsoft.Extensions.Logging": {
+ "type": "Transitive",
+ "resolved": "6.0.0",
+ "contentHash": "eIbyj40QDg1NDz0HBW0S5f3wrLVnKWnDJ/JtZ+yJDFnDj90VoPuoPmFkeaXrtu+0cKm5GRAwoDf+dBWXK0TUdg==",
+ "dependencies": {
+ "Microsoft.Extensions.DependencyInjection": "6.0.0",
+ "Microsoft.Extensions.DependencyInjection.Abstractions": "6.0.0",
+ "Microsoft.Extensions.Logging.Abstractions": "6.0.0",
+ "Microsoft.Extensions.Options": "6.0.0"
+ }
+ },
+ "Microsoft.Extensions.Logging.Abstractions": {
+ "type": "Transitive",
+ "resolved": "6.0.0",
+ "contentHash": "/HggWBbTwy8TgebGSX5DBZ24ndhzi93sHUBDvP1IxbZD7FDokYzdAr6+vbWGjw2XAfR2EJ1sfKUotpjHnFWPxA=="
+ },
+ "Microsoft.Extensions.Options": {
+ "type": "Transitive",
+ "resolved": "6.0.0",
+ "contentHash": "dzXN0+V1AyjOe2xcJ86Qbo233KHuLEY0njf/P2Kw8SfJU+d45HNS2ctJdnEnrWbM9Ye2eFgaC5Mj9otRMU6IsQ==",
+ "dependencies": {
+ "Microsoft.Extensions.DependencyInjection.Abstractions": "6.0.0",
+ "Microsoft.Extensions.Primitives": "6.0.0"
+ }
+ },
+ "Microsoft.Extensions.Primitives": {
+ "type": "Transitive",
+ "resolved": "6.0.0",
+ "contentHash": "9+PnzmQFfEFNR9J2aDTfJGGupShHjOuGw4VUv+JB044biSHrnmCIMD+mJHmb2H7YryrfBEXDurxQ47gJZdCKNQ=="
+ },
+ "Perfolizer": {
+ "type": "Transitive",
+ "resolved": "0.5.3",
+ "contentHash": "EhHo0s4y+tHJKhZHgQvPgFWhAhnQpHHuFzutRzfqfv5z763wvhzXh849ZtpVePQNxXWoFafh1Ta2tZgnSIVsYQ=="
+ },
+ "System.CodeDom": {
+ "type": "Transitive",
+ "resolved": "9.0.5",
+ "contentHash": "cuzLM2MWutf9ZBEMPYYfd0DXwYdvntp7VCT6a/wvbKCa2ZuvGmW74xi+YBa2mrfEieAXqM4TNKlMmSnfAfpUoQ=="
+ },
+ "System.Management": {
+ "type": "Transitive",
+ "resolved": "9.0.5",
+ "contentHash": "n6o9PZm9p25+zAzC3/48K0oHnaPKTInRrxqFq1fi/5TPbMLjuoCm/h//mS3cUmSy+9AO1Z+qsC/Ilt/ZFatv5Q==",
+ "dependencies": {
+ "System.CodeDom": "9.0.5"
+ }
+ },
+ "System.Reflection.TypeExtensions": {
+ "type": "Transitive",
+ "resolved": "4.7.0",
+ "contentHash": "VybpaOQQhqE6siHppMktjfGBw1GCwvCqiufqmP8F1nj7fTUNtW35LOEt3UZTEsECfo+ELAl/9o9nJx3U91i7vA=="
+ },
+ "functionfoundry.networking": {
+ "type": "Project"
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/benchmarks/FunctionFoundry.Observability.Benchmarks/packages.lock.json b/benchmarks/FunctionFoundry.Observability.Benchmarks/packages.lock.json
new file mode 100644
index 0000000..9e71489
--- /dev/null
+++ b/benchmarks/FunctionFoundry.Observability.Benchmarks/packages.lock.json
@@ -0,0 +1,166 @@
+{
+ "version": 2,
+ "dependencies": {
+ "net10.0": {
+ "BenchmarkDotNet": {
+ "type": "Direct",
+ "requested": "[0.15.2, )",
+ "resolved": "0.15.2",
+ "contentHash": "5vl4nQFUGTKgOVE5LNoLpv/X/wFQ7wE5yiaJAXCpzgNtUADtfEwbuufKI4o5E2De0VTXNEeom5Hnv8S8vuBZtg==",
+ "dependencies": {
+ "BenchmarkDotNet.Annotations": "0.15.2",
+ "CommandLineParser": "2.9.1",
+ "Gee.External.Capstone": "2.3.0",
+ "Iced": "1.21.0",
+ "Microsoft.CodeAnalysis.CSharp": "4.14.0",
+ "Microsoft.Diagnostics.Runtime": "3.1.512801",
+ "Microsoft.Diagnostics.Tracing.TraceEvent": "3.1.21",
+ "Microsoft.DotNet.PlatformAbstractions": "3.1.6",
+ "Perfolizer": "[0.5.3]",
+ "System.Management": "9.0.5"
+ }
+ },
+ "BenchmarkDotNet.Annotations": {
+ "type": "Transitive",
+ "resolved": "0.15.2",
+ "contentHash": "a7rVlVmXQRrp3J+HF/FtjwiFcshU6BAuv6U1xtAbqCUYepOEnNGaPeOFvy4It17QZwwofm6U/GAfW3JrFMXszg=="
+ },
+ "CommandLineParser": {
+ "type": "Transitive",
+ "resolved": "2.9.1",
+ "contentHash": "OE0sl1/sQ37bjVsPKKtwQlWDgqaxWgtme3xZz7JssWUzg5JpMIyHgCTY9MVMxOg48fJ1AgGT3tgdH5m/kQ5xhA=="
+ },
+ "Gee.External.Capstone": {
+ "type": "Transitive",
+ "resolved": "2.3.0",
+ "contentHash": "2ap/rYmjtzCOT8hxrnEW/QeiOt+paD8iRrIcdKX0cxVwWLFa1e+JDBNeECakmccXrSFeBQuu5AV8SNkipFMMMw=="
+ },
+ "Iced": {
+ "type": "Transitive",
+ "resolved": "1.21.0",
+ "contentHash": "dv5+81Q1TBQvVMSOOOmRcjJmvWcX3BZPZsIq31+RLc5cNft0IHAyNlkdb7ZarOWG913PyBoFDsDXoCIlKmLclg=="
+ },
+ "Microsoft.CodeAnalysis.Analyzers": {
+ "type": "Transitive",
+ "resolved": "3.11.0",
+ "contentHash": "v/EW3UE8/lbEYHoC2Qq7AR/DnmvpgdtAMndfQNmpuIMx/Mto8L5JnuCfdBYtgvalQOtfNCnxFejxuRrryvUTsg=="
+ },
+ "Microsoft.CodeAnalysis.Common": {
+ "type": "Transitive",
+ "resolved": "4.14.0",
+ "contentHash": "PC3tuwZYnC+idaPuoC/AZpEdwrtX7qFpmnrfQkgobGIWiYmGi5MCRtl5mx6QrfMGQpK78X2lfIEoZDLg/qnuHg==",
+ "dependencies": {
+ "Microsoft.CodeAnalysis.Analyzers": "3.11.0"
+ }
+ },
+ "Microsoft.CodeAnalysis.CSharp": {
+ "type": "Transitive",
+ "resolved": "4.14.0",
+ "contentHash": "568a6wcTivauIhbeWcCwfWwIn7UV7MeHEBvFB2uzGIpM2OhJ4eM/FZ8KS0yhPoNxnSpjGzz7x7CIjTxhslojQA==",
+ "dependencies": {
+ "Microsoft.CodeAnalysis.Analyzers": "3.11.0",
+ "Microsoft.CodeAnalysis.Common": "[4.14.0]"
+ }
+ },
+ "Microsoft.Diagnostics.NETCore.Client": {
+ "type": "Transitive",
+ "resolved": "0.2.510501",
+ "contentHash": "juoqJYMDs+lRrrZyOkXXMImJHneCF23cuvO4waFRd2Ds7j+ZuGIPbJm0Y/zz34BdeaGiiwGWraMUlln05W1PCQ==",
+ "dependencies": {
+ "Microsoft.Extensions.Logging": "6.0.0"
+ }
+ },
+ "Microsoft.Diagnostics.Runtime": {
+ "type": "Transitive",
+ "resolved": "3.1.512801",
+ "contentHash": "0lMUDr2oxNZa28D6NH5BuSQEe5T9tZziIkvkD44YkkCGQXPJqvFjLq5ZQq1hYLl3RjQJrY+hR0jFgap+EWPDTw==",
+ "dependencies": {
+ "Microsoft.Diagnostics.NETCore.Client": "0.2.410101"
+ }
+ },
+ "Microsoft.Diagnostics.Tracing.TraceEvent": {
+ "type": "Transitive",
+ "resolved": "3.1.21",
+ "contentHash": "/OrJFKaojSR6TkUKtwh8/qA9XWNtxLrXMqvEb89dBSKCWjaGVTbKMYodIUgF5deCEtmd6GXuRerciXGl5bhZ7Q==",
+ "dependencies": {
+ "Microsoft.Diagnostics.NETCore.Client": "0.2.510501",
+ "System.Reflection.TypeExtensions": "4.7.0"
+ }
+ },
+ "Microsoft.DotNet.PlatformAbstractions": {
+ "type": "Transitive",
+ "resolved": "3.1.6",
+ "contentHash": "jek4XYaQ/PGUwDKKhwR8K47Uh1189PFzMeLqO83mXrXQVIpARZCcfuDedH50YDTepBkfijCZN5U/vZi++erxtg=="
+ },
+ "Microsoft.Extensions.DependencyInjection": {
+ "type": "Transitive",
+ "resolved": "6.0.0",
+ "contentHash": "k6PWQMuoBDGGHOQTtyois2u4AwyVcIwL2LaSLlTZQm2CYcJ1pxbt6jfAnpWmzENA/wfrYRI/X9DTLoUkE4AsLw==",
+ "dependencies": {
+ "Microsoft.Extensions.DependencyInjection.Abstractions": "6.0.0"
+ }
+ },
+ "Microsoft.Extensions.DependencyInjection.Abstractions": {
+ "type": "Transitive",
+ "resolved": "6.0.0",
+ "contentHash": "xlzi2IYREJH3/m6+lUrQlujzX8wDitm4QGnUu6kUXTQAWPuZY8i+ticFJbzfqaetLA6KR/rO6Ew/HuYD+bxifg=="
+ },
+ "Microsoft.Extensions.Logging": {
+ "type": "Transitive",
+ "resolved": "6.0.0",
+ "contentHash": "eIbyj40QDg1NDz0HBW0S5f3wrLVnKWnDJ/JtZ+yJDFnDj90VoPuoPmFkeaXrtu+0cKm5GRAwoDf+dBWXK0TUdg==",
+ "dependencies": {
+ "Microsoft.Extensions.DependencyInjection": "6.0.0",
+ "Microsoft.Extensions.DependencyInjection.Abstractions": "6.0.0",
+ "Microsoft.Extensions.Logging.Abstractions": "6.0.0",
+ "Microsoft.Extensions.Options": "6.0.0"
+ }
+ },
+ "Microsoft.Extensions.Logging.Abstractions": {
+ "type": "Transitive",
+ "resolved": "6.0.0",
+ "contentHash": "/HggWBbTwy8TgebGSX5DBZ24ndhzi93sHUBDvP1IxbZD7FDokYzdAr6+vbWGjw2XAfR2EJ1sfKUotpjHnFWPxA=="
+ },
+ "Microsoft.Extensions.Options": {
+ "type": "Transitive",
+ "resolved": "6.0.0",
+ "contentHash": "dzXN0+V1AyjOe2xcJ86Qbo233KHuLEY0njf/P2Kw8SfJU+d45HNS2ctJdnEnrWbM9Ye2eFgaC5Mj9otRMU6IsQ==",
+ "dependencies": {
+ "Microsoft.Extensions.DependencyInjection.Abstractions": "6.0.0",
+ "Microsoft.Extensions.Primitives": "6.0.0"
+ }
+ },
+ "Microsoft.Extensions.Primitives": {
+ "type": "Transitive",
+ "resolved": "6.0.0",
+ "contentHash": "9+PnzmQFfEFNR9J2aDTfJGGupShHjOuGw4VUv+JB044biSHrnmCIMD+mJHmb2H7YryrfBEXDurxQ47gJZdCKNQ=="
+ },
+ "Perfolizer": {
+ "type": "Transitive",
+ "resolved": "0.5.3",
+ "contentHash": "EhHo0s4y+tHJKhZHgQvPgFWhAhnQpHHuFzutRzfqfv5z763wvhzXh849ZtpVePQNxXWoFafh1Ta2tZgnSIVsYQ=="
+ },
+ "System.CodeDom": {
+ "type": "Transitive",
+ "resolved": "9.0.5",
+ "contentHash": "cuzLM2MWutf9ZBEMPYYfd0DXwYdvntp7VCT6a/wvbKCa2ZuvGmW74xi+YBa2mrfEieAXqM4TNKlMmSnfAfpUoQ=="
+ },
+ "System.Management": {
+ "type": "Transitive",
+ "resolved": "9.0.5",
+ "contentHash": "n6o9PZm9p25+zAzC3/48K0oHnaPKTInRrxqFq1fi/5TPbMLjuoCm/h//mS3cUmSy+9AO1Z+qsC/Ilt/ZFatv5Q==",
+ "dependencies": {
+ "System.CodeDom": "9.0.5"
+ }
+ },
+ "System.Reflection.TypeExtensions": {
+ "type": "Transitive",
+ "resolved": "4.7.0",
+ "contentHash": "VybpaOQQhqE6siHppMktjfGBw1GCwvCqiufqmP8F1nj7fTUNtW35LOEt3UZTEsECfo+ELAl/9o9nJx3U91i7vA=="
+ },
+ "functionfoundry.observability": {
+ "type": "Project"
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/benchmarks/FunctionFoundry.Resilience.Benchmarks/packages.lock.json b/benchmarks/FunctionFoundry.Resilience.Benchmarks/packages.lock.json
new file mode 100644
index 0000000..c985007
--- /dev/null
+++ b/benchmarks/FunctionFoundry.Resilience.Benchmarks/packages.lock.json
@@ -0,0 +1,166 @@
+{
+ "version": 2,
+ "dependencies": {
+ "net10.0": {
+ "BenchmarkDotNet": {
+ "type": "Direct",
+ "requested": "[0.15.2, )",
+ "resolved": "0.15.2",
+ "contentHash": "5vl4nQFUGTKgOVE5LNoLpv/X/wFQ7wE5yiaJAXCpzgNtUADtfEwbuufKI4o5E2De0VTXNEeom5Hnv8S8vuBZtg==",
+ "dependencies": {
+ "BenchmarkDotNet.Annotations": "0.15.2",
+ "CommandLineParser": "2.9.1",
+ "Gee.External.Capstone": "2.3.0",
+ "Iced": "1.21.0",
+ "Microsoft.CodeAnalysis.CSharp": "4.14.0",
+ "Microsoft.Diagnostics.Runtime": "3.1.512801",
+ "Microsoft.Diagnostics.Tracing.TraceEvent": "3.1.21",
+ "Microsoft.DotNet.PlatformAbstractions": "3.1.6",
+ "Perfolizer": "[0.5.3]",
+ "System.Management": "9.0.5"
+ }
+ },
+ "BenchmarkDotNet.Annotations": {
+ "type": "Transitive",
+ "resolved": "0.15.2",
+ "contentHash": "a7rVlVmXQRrp3J+HF/FtjwiFcshU6BAuv6U1xtAbqCUYepOEnNGaPeOFvy4It17QZwwofm6U/GAfW3JrFMXszg=="
+ },
+ "CommandLineParser": {
+ "type": "Transitive",
+ "resolved": "2.9.1",
+ "contentHash": "OE0sl1/sQ37bjVsPKKtwQlWDgqaxWgtme3xZz7JssWUzg5JpMIyHgCTY9MVMxOg48fJ1AgGT3tgdH5m/kQ5xhA=="
+ },
+ "Gee.External.Capstone": {
+ "type": "Transitive",
+ "resolved": "2.3.0",
+ "contentHash": "2ap/rYmjtzCOT8hxrnEW/QeiOt+paD8iRrIcdKX0cxVwWLFa1e+JDBNeECakmccXrSFeBQuu5AV8SNkipFMMMw=="
+ },
+ "Iced": {
+ "type": "Transitive",
+ "resolved": "1.21.0",
+ "contentHash": "dv5+81Q1TBQvVMSOOOmRcjJmvWcX3BZPZsIq31+RLc5cNft0IHAyNlkdb7ZarOWG913PyBoFDsDXoCIlKmLclg=="
+ },
+ "Microsoft.CodeAnalysis.Analyzers": {
+ "type": "Transitive",
+ "resolved": "3.11.0",
+ "contentHash": "v/EW3UE8/lbEYHoC2Qq7AR/DnmvpgdtAMndfQNmpuIMx/Mto8L5JnuCfdBYtgvalQOtfNCnxFejxuRrryvUTsg=="
+ },
+ "Microsoft.CodeAnalysis.Common": {
+ "type": "Transitive",
+ "resolved": "4.14.0",
+ "contentHash": "PC3tuwZYnC+idaPuoC/AZpEdwrtX7qFpmnrfQkgobGIWiYmGi5MCRtl5mx6QrfMGQpK78X2lfIEoZDLg/qnuHg==",
+ "dependencies": {
+ "Microsoft.CodeAnalysis.Analyzers": "3.11.0"
+ }
+ },
+ "Microsoft.CodeAnalysis.CSharp": {
+ "type": "Transitive",
+ "resolved": "4.14.0",
+ "contentHash": "568a6wcTivauIhbeWcCwfWwIn7UV7MeHEBvFB2uzGIpM2OhJ4eM/FZ8KS0yhPoNxnSpjGzz7x7CIjTxhslojQA==",
+ "dependencies": {
+ "Microsoft.CodeAnalysis.Analyzers": "3.11.0",
+ "Microsoft.CodeAnalysis.Common": "[4.14.0]"
+ }
+ },
+ "Microsoft.Diagnostics.NETCore.Client": {
+ "type": "Transitive",
+ "resolved": "0.2.510501",
+ "contentHash": "juoqJYMDs+lRrrZyOkXXMImJHneCF23cuvO4waFRd2Ds7j+ZuGIPbJm0Y/zz34BdeaGiiwGWraMUlln05W1PCQ==",
+ "dependencies": {
+ "Microsoft.Extensions.Logging": "6.0.0"
+ }
+ },
+ "Microsoft.Diagnostics.Runtime": {
+ "type": "Transitive",
+ "resolved": "3.1.512801",
+ "contentHash": "0lMUDr2oxNZa28D6NH5BuSQEe5T9tZziIkvkD44YkkCGQXPJqvFjLq5ZQq1hYLl3RjQJrY+hR0jFgap+EWPDTw==",
+ "dependencies": {
+ "Microsoft.Diagnostics.NETCore.Client": "0.2.410101"
+ }
+ },
+ "Microsoft.Diagnostics.Tracing.TraceEvent": {
+ "type": "Transitive",
+ "resolved": "3.1.21",
+ "contentHash": "/OrJFKaojSR6TkUKtwh8/qA9XWNtxLrXMqvEb89dBSKCWjaGVTbKMYodIUgF5deCEtmd6GXuRerciXGl5bhZ7Q==",
+ "dependencies": {
+ "Microsoft.Diagnostics.NETCore.Client": "0.2.510501",
+ "System.Reflection.TypeExtensions": "4.7.0"
+ }
+ },
+ "Microsoft.DotNet.PlatformAbstractions": {
+ "type": "Transitive",
+ "resolved": "3.1.6",
+ "contentHash": "jek4XYaQ/PGUwDKKhwR8K47Uh1189PFzMeLqO83mXrXQVIpARZCcfuDedH50YDTepBkfijCZN5U/vZi++erxtg=="
+ },
+ "Microsoft.Extensions.DependencyInjection": {
+ "type": "Transitive",
+ "resolved": "6.0.0",
+ "contentHash": "k6PWQMuoBDGGHOQTtyois2u4AwyVcIwL2LaSLlTZQm2CYcJ1pxbt6jfAnpWmzENA/wfrYRI/X9DTLoUkE4AsLw==",
+ "dependencies": {
+ "Microsoft.Extensions.DependencyInjection.Abstractions": "6.0.0"
+ }
+ },
+ "Microsoft.Extensions.DependencyInjection.Abstractions": {
+ "type": "Transitive",
+ "resolved": "6.0.0",
+ "contentHash": "xlzi2IYREJH3/m6+lUrQlujzX8wDitm4QGnUu6kUXTQAWPuZY8i+ticFJbzfqaetLA6KR/rO6Ew/HuYD+bxifg=="
+ },
+ "Microsoft.Extensions.Logging": {
+ "type": "Transitive",
+ "resolved": "6.0.0",
+ "contentHash": "eIbyj40QDg1NDz0HBW0S5f3wrLVnKWnDJ/JtZ+yJDFnDj90VoPuoPmFkeaXrtu+0cKm5GRAwoDf+dBWXK0TUdg==",
+ "dependencies": {
+ "Microsoft.Extensions.DependencyInjection": "6.0.0",
+ "Microsoft.Extensions.DependencyInjection.Abstractions": "6.0.0",
+ "Microsoft.Extensions.Logging.Abstractions": "6.0.0",
+ "Microsoft.Extensions.Options": "6.0.0"
+ }
+ },
+ "Microsoft.Extensions.Logging.Abstractions": {
+ "type": "Transitive",
+ "resolved": "6.0.0",
+ "contentHash": "/HggWBbTwy8TgebGSX5DBZ24ndhzi93sHUBDvP1IxbZD7FDokYzdAr6+vbWGjw2XAfR2EJ1sfKUotpjHnFWPxA=="
+ },
+ "Microsoft.Extensions.Options": {
+ "type": "Transitive",
+ "resolved": "6.0.0",
+ "contentHash": "dzXN0+V1AyjOe2xcJ86Qbo233KHuLEY0njf/P2Kw8SfJU+d45HNS2ctJdnEnrWbM9Ye2eFgaC5Mj9otRMU6IsQ==",
+ "dependencies": {
+ "Microsoft.Extensions.DependencyInjection.Abstractions": "6.0.0",
+ "Microsoft.Extensions.Primitives": "6.0.0"
+ }
+ },
+ "Microsoft.Extensions.Primitives": {
+ "type": "Transitive",
+ "resolved": "6.0.0",
+ "contentHash": "9+PnzmQFfEFNR9J2aDTfJGGupShHjOuGw4VUv+JB044biSHrnmCIMD+mJHmb2H7YryrfBEXDurxQ47gJZdCKNQ=="
+ },
+ "Perfolizer": {
+ "type": "Transitive",
+ "resolved": "0.5.3",
+ "contentHash": "EhHo0s4y+tHJKhZHgQvPgFWhAhnQpHHuFzutRzfqfv5z763wvhzXh849ZtpVePQNxXWoFafh1Ta2tZgnSIVsYQ=="
+ },
+ "System.CodeDom": {
+ "type": "Transitive",
+ "resolved": "9.0.5",
+ "contentHash": "cuzLM2MWutf9ZBEMPYYfd0DXwYdvntp7VCT6a/wvbKCa2ZuvGmW74xi+YBa2mrfEieAXqM4TNKlMmSnfAfpUoQ=="
+ },
+ "System.Management": {
+ "type": "Transitive",
+ "resolved": "9.0.5",
+ "contentHash": "n6o9PZm9p25+zAzC3/48K0oHnaPKTInRrxqFq1fi/5TPbMLjuoCm/h//mS3cUmSy+9AO1Z+qsC/Ilt/ZFatv5Q==",
+ "dependencies": {
+ "System.CodeDom": "9.0.5"
+ }
+ },
+ "System.Reflection.TypeExtensions": {
+ "type": "Transitive",
+ "resolved": "4.7.0",
+ "contentHash": "VybpaOQQhqE6siHppMktjfGBw1GCwvCqiufqmP8F1nj7fTUNtW35LOEt3UZTEsECfo+ELAl/9o9nJx3U91i7vA=="
+ },
+ "functionfoundry.resilience": {
+ "type": "Project"
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/benchmarks/FunctionFoundry.Scheduling.Benchmarks/packages.lock.json b/benchmarks/FunctionFoundry.Scheduling.Benchmarks/packages.lock.json
new file mode 100644
index 0000000..450d3b9
--- /dev/null
+++ b/benchmarks/FunctionFoundry.Scheduling.Benchmarks/packages.lock.json
@@ -0,0 +1,166 @@
+{
+ "version": 2,
+ "dependencies": {
+ "net10.0": {
+ "BenchmarkDotNet": {
+ "type": "Direct",
+ "requested": "[0.15.2, )",
+ "resolved": "0.15.2",
+ "contentHash": "5vl4nQFUGTKgOVE5LNoLpv/X/wFQ7wE5yiaJAXCpzgNtUADtfEwbuufKI4o5E2De0VTXNEeom5Hnv8S8vuBZtg==",
+ "dependencies": {
+ "BenchmarkDotNet.Annotations": "0.15.2",
+ "CommandLineParser": "2.9.1",
+ "Gee.External.Capstone": "2.3.0",
+ "Iced": "1.21.0",
+ "Microsoft.CodeAnalysis.CSharp": "4.14.0",
+ "Microsoft.Diagnostics.Runtime": "3.1.512801",
+ "Microsoft.Diagnostics.Tracing.TraceEvent": "3.1.21",
+ "Microsoft.DotNet.PlatformAbstractions": "3.1.6",
+ "Perfolizer": "[0.5.3]",
+ "System.Management": "9.0.5"
+ }
+ },
+ "BenchmarkDotNet.Annotations": {
+ "type": "Transitive",
+ "resolved": "0.15.2",
+ "contentHash": "a7rVlVmXQRrp3J+HF/FtjwiFcshU6BAuv6U1xtAbqCUYepOEnNGaPeOFvy4It17QZwwofm6U/GAfW3JrFMXszg=="
+ },
+ "CommandLineParser": {
+ "type": "Transitive",
+ "resolved": "2.9.1",
+ "contentHash": "OE0sl1/sQ37bjVsPKKtwQlWDgqaxWgtme3xZz7JssWUzg5JpMIyHgCTY9MVMxOg48fJ1AgGT3tgdH5m/kQ5xhA=="
+ },
+ "Gee.External.Capstone": {
+ "type": "Transitive",
+ "resolved": "2.3.0",
+ "contentHash": "2ap/rYmjtzCOT8hxrnEW/QeiOt+paD8iRrIcdKX0cxVwWLFa1e+JDBNeECakmccXrSFeBQuu5AV8SNkipFMMMw=="
+ },
+ "Iced": {
+ "type": "Transitive",
+ "resolved": "1.21.0",
+ "contentHash": "dv5+81Q1TBQvVMSOOOmRcjJmvWcX3BZPZsIq31+RLc5cNft0IHAyNlkdb7ZarOWG913PyBoFDsDXoCIlKmLclg=="
+ },
+ "Microsoft.CodeAnalysis.Analyzers": {
+ "type": "Transitive",
+ "resolved": "3.11.0",
+ "contentHash": "v/EW3UE8/lbEYHoC2Qq7AR/DnmvpgdtAMndfQNmpuIMx/Mto8L5JnuCfdBYtgvalQOtfNCnxFejxuRrryvUTsg=="
+ },
+ "Microsoft.CodeAnalysis.Common": {
+ "type": "Transitive",
+ "resolved": "4.14.0",
+ "contentHash": "PC3tuwZYnC+idaPuoC/AZpEdwrtX7qFpmnrfQkgobGIWiYmGi5MCRtl5mx6QrfMGQpK78X2lfIEoZDLg/qnuHg==",
+ "dependencies": {
+ "Microsoft.CodeAnalysis.Analyzers": "3.11.0"
+ }
+ },
+ "Microsoft.CodeAnalysis.CSharp": {
+ "type": "Transitive",
+ "resolved": "4.14.0",
+ "contentHash": "568a6wcTivauIhbeWcCwfWwIn7UV7MeHEBvFB2uzGIpM2OhJ4eM/FZ8KS0yhPoNxnSpjGzz7x7CIjTxhslojQA==",
+ "dependencies": {
+ "Microsoft.CodeAnalysis.Analyzers": "3.11.0",
+ "Microsoft.CodeAnalysis.Common": "[4.14.0]"
+ }
+ },
+ "Microsoft.Diagnostics.NETCore.Client": {
+ "type": "Transitive",
+ "resolved": "0.2.510501",
+ "contentHash": "juoqJYMDs+lRrrZyOkXXMImJHneCF23cuvO4waFRd2Ds7j+ZuGIPbJm0Y/zz34BdeaGiiwGWraMUlln05W1PCQ==",
+ "dependencies": {
+ "Microsoft.Extensions.Logging": "6.0.0"
+ }
+ },
+ "Microsoft.Diagnostics.Runtime": {
+ "type": "Transitive",
+ "resolved": "3.1.512801",
+ "contentHash": "0lMUDr2oxNZa28D6NH5BuSQEe5T9tZziIkvkD44YkkCGQXPJqvFjLq5ZQq1hYLl3RjQJrY+hR0jFgap+EWPDTw==",
+ "dependencies": {
+ "Microsoft.Diagnostics.NETCore.Client": "0.2.410101"
+ }
+ },
+ "Microsoft.Diagnostics.Tracing.TraceEvent": {
+ "type": "Transitive",
+ "resolved": "3.1.21",
+ "contentHash": "/OrJFKaojSR6TkUKtwh8/qA9XWNtxLrXMqvEb89dBSKCWjaGVTbKMYodIUgF5deCEtmd6GXuRerciXGl5bhZ7Q==",
+ "dependencies": {
+ "Microsoft.Diagnostics.NETCore.Client": "0.2.510501",
+ "System.Reflection.TypeExtensions": "4.7.0"
+ }
+ },
+ "Microsoft.DotNet.PlatformAbstractions": {
+ "type": "Transitive",
+ "resolved": "3.1.6",
+ "contentHash": "jek4XYaQ/PGUwDKKhwR8K47Uh1189PFzMeLqO83mXrXQVIpARZCcfuDedH50YDTepBkfijCZN5U/vZi++erxtg=="
+ },
+ "Microsoft.Extensions.DependencyInjection": {
+ "type": "Transitive",
+ "resolved": "6.0.0",
+ "contentHash": "k6PWQMuoBDGGHOQTtyois2u4AwyVcIwL2LaSLlTZQm2CYcJ1pxbt6jfAnpWmzENA/wfrYRI/X9DTLoUkE4AsLw==",
+ "dependencies": {
+ "Microsoft.Extensions.DependencyInjection.Abstractions": "6.0.0"
+ }
+ },
+ "Microsoft.Extensions.DependencyInjection.Abstractions": {
+ "type": "Transitive",
+ "resolved": "6.0.0",
+ "contentHash": "xlzi2IYREJH3/m6+lUrQlujzX8wDitm4QGnUu6kUXTQAWPuZY8i+ticFJbzfqaetLA6KR/rO6Ew/HuYD+bxifg=="
+ },
+ "Microsoft.Extensions.Logging": {
+ "type": "Transitive",
+ "resolved": "6.0.0",
+ "contentHash": "eIbyj40QDg1NDz0HBW0S5f3wrLVnKWnDJ/JtZ+yJDFnDj90VoPuoPmFkeaXrtu+0cKm5GRAwoDf+dBWXK0TUdg==",
+ "dependencies": {
+ "Microsoft.Extensions.DependencyInjection": "6.0.0",
+ "Microsoft.Extensions.DependencyInjection.Abstractions": "6.0.0",
+ "Microsoft.Extensions.Logging.Abstractions": "6.0.0",
+ "Microsoft.Extensions.Options": "6.0.0"
+ }
+ },
+ "Microsoft.Extensions.Logging.Abstractions": {
+ "type": "Transitive",
+ "resolved": "6.0.0",
+ "contentHash": "/HggWBbTwy8TgebGSX5DBZ24ndhzi93sHUBDvP1IxbZD7FDokYzdAr6+vbWGjw2XAfR2EJ1sfKUotpjHnFWPxA=="
+ },
+ "Microsoft.Extensions.Options": {
+ "type": "Transitive",
+ "resolved": "6.0.0",
+ "contentHash": "dzXN0+V1AyjOe2xcJ86Qbo233KHuLEY0njf/P2Kw8SfJU+d45HNS2ctJdnEnrWbM9Ye2eFgaC5Mj9otRMU6IsQ==",
+ "dependencies": {
+ "Microsoft.Extensions.DependencyInjection.Abstractions": "6.0.0",
+ "Microsoft.Extensions.Primitives": "6.0.0"
+ }
+ },
+ "Microsoft.Extensions.Primitives": {
+ "type": "Transitive",
+ "resolved": "6.0.0",
+ "contentHash": "9+PnzmQFfEFNR9J2aDTfJGGupShHjOuGw4VUv+JB044biSHrnmCIMD+mJHmb2H7YryrfBEXDurxQ47gJZdCKNQ=="
+ },
+ "Perfolizer": {
+ "type": "Transitive",
+ "resolved": "0.5.3",
+ "contentHash": "EhHo0s4y+tHJKhZHgQvPgFWhAhnQpHHuFzutRzfqfv5z763wvhzXh849ZtpVePQNxXWoFafh1Ta2tZgnSIVsYQ=="
+ },
+ "System.CodeDom": {
+ "type": "Transitive",
+ "resolved": "9.0.5",
+ "contentHash": "cuzLM2MWutf9ZBEMPYYfd0DXwYdvntp7VCT6a/wvbKCa2ZuvGmW74xi+YBa2mrfEieAXqM4TNKlMmSnfAfpUoQ=="
+ },
+ "System.Management": {
+ "type": "Transitive",
+ "resolved": "9.0.5",
+ "contentHash": "n6o9PZm9p25+zAzC3/48K0oHnaPKTInRrxqFq1fi/5TPbMLjuoCm/h//mS3cUmSy+9AO1Z+qsC/Ilt/ZFatv5Q==",
+ "dependencies": {
+ "System.CodeDom": "9.0.5"
+ }
+ },
+ "System.Reflection.TypeExtensions": {
+ "type": "Transitive",
+ "resolved": "4.7.0",
+ "contentHash": "VybpaOQQhqE6siHppMktjfGBw1GCwvCqiufqmP8F1nj7fTUNtW35LOEt3UZTEsECfo+ELAl/9o9nJx3U91i7vA=="
+ },
+ "functionfoundry.scheduling": {
+ "type": "Project"
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/benchmarks/FunctionFoundry.Security.Benchmarks/packages.lock.json b/benchmarks/FunctionFoundry.Security.Benchmarks/packages.lock.json
new file mode 100644
index 0000000..592e3a0
--- /dev/null
+++ b/benchmarks/FunctionFoundry.Security.Benchmarks/packages.lock.json
@@ -0,0 +1,166 @@
+{
+ "version": 2,
+ "dependencies": {
+ "net10.0": {
+ "BenchmarkDotNet": {
+ "type": "Direct",
+ "requested": "[0.15.2, )",
+ "resolved": "0.15.2",
+ "contentHash": "5vl4nQFUGTKgOVE5LNoLpv/X/wFQ7wE5yiaJAXCpzgNtUADtfEwbuufKI4o5E2De0VTXNEeom5Hnv8S8vuBZtg==",
+ "dependencies": {
+ "BenchmarkDotNet.Annotations": "0.15.2",
+ "CommandLineParser": "2.9.1",
+ "Gee.External.Capstone": "2.3.0",
+ "Iced": "1.21.0",
+ "Microsoft.CodeAnalysis.CSharp": "4.14.0",
+ "Microsoft.Diagnostics.Runtime": "3.1.512801",
+ "Microsoft.Diagnostics.Tracing.TraceEvent": "3.1.21",
+ "Microsoft.DotNet.PlatformAbstractions": "3.1.6",
+ "Perfolizer": "[0.5.3]",
+ "System.Management": "9.0.5"
+ }
+ },
+ "BenchmarkDotNet.Annotations": {
+ "type": "Transitive",
+ "resolved": "0.15.2",
+ "contentHash": "a7rVlVmXQRrp3J+HF/FtjwiFcshU6BAuv6U1xtAbqCUYepOEnNGaPeOFvy4It17QZwwofm6U/GAfW3JrFMXszg=="
+ },
+ "CommandLineParser": {
+ "type": "Transitive",
+ "resolved": "2.9.1",
+ "contentHash": "OE0sl1/sQ37bjVsPKKtwQlWDgqaxWgtme3xZz7JssWUzg5JpMIyHgCTY9MVMxOg48fJ1AgGT3tgdH5m/kQ5xhA=="
+ },
+ "Gee.External.Capstone": {
+ "type": "Transitive",
+ "resolved": "2.3.0",
+ "contentHash": "2ap/rYmjtzCOT8hxrnEW/QeiOt+paD8iRrIcdKX0cxVwWLFa1e+JDBNeECakmccXrSFeBQuu5AV8SNkipFMMMw=="
+ },
+ "Iced": {
+ "type": "Transitive",
+ "resolved": "1.21.0",
+ "contentHash": "dv5+81Q1TBQvVMSOOOmRcjJmvWcX3BZPZsIq31+RLc5cNft0IHAyNlkdb7ZarOWG913PyBoFDsDXoCIlKmLclg=="
+ },
+ "Microsoft.CodeAnalysis.Analyzers": {
+ "type": "Transitive",
+ "resolved": "3.11.0",
+ "contentHash": "v/EW3UE8/lbEYHoC2Qq7AR/DnmvpgdtAMndfQNmpuIMx/Mto8L5JnuCfdBYtgvalQOtfNCnxFejxuRrryvUTsg=="
+ },
+ "Microsoft.CodeAnalysis.Common": {
+ "type": "Transitive",
+ "resolved": "4.14.0",
+ "contentHash": "PC3tuwZYnC+idaPuoC/AZpEdwrtX7qFpmnrfQkgobGIWiYmGi5MCRtl5mx6QrfMGQpK78X2lfIEoZDLg/qnuHg==",
+ "dependencies": {
+ "Microsoft.CodeAnalysis.Analyzers": "3.11.0"
+ }
+ },
+ "Microsoft.CodeAnalysis.CSharp": {
+ "type": "Transitive",
+ "resolved": "4.14.0",
+ "contentHash": "568a6wcTivauIhbeWcCwfWwIn7UV7MeHEBvFB2uzGIpM2OhJ4eM/FZ8KS0yhPoNxnSpjGzz7x7CIjTxhslojQA==",
+ "dependencies": {
+ "Microsoft.CodeAnalysis.Analyzers": "3.11.0",
+ "Microsoft.CodeAnalysis.Common": "[4.14.0]"
+ }
+ },
+ "Microsoft.Diagnostics.NETCore.Client": {
+ "type": "Transitive",
+ "resolved": "0.2.510501",
+ "contentHash": "juoqJYMDs+lRrrZyOkXXMImJHneCF23cuvO4waFRd2Ds7j+ZuGIPbJm0Y/zz34BdeaGiiwGWraMUlln05W1PCQ==",
+ "dependencies": {
+ "Microsoft.Extensions.Logging": "6.0.0"
+ }
+ },
+ "Microsoft.Diagnostics.Runtime": {
+ "type": "Transitive",
+ "resolved": "3.1.512801",
+ "contentHash": "0lMUDr2oxNZa28D6NH5BuSQEe5T9tZziIkvkD44YkkCGQXPJqvFjLq5ZQq1hYLl3RjQJrY+hR0jFgap+EWPDTw==",
+ "dependencies": {
+ "Microsoft.Diagnostics.NETCore.Client": "0.2.410101"
+ }
+ },
+ "Microsoft.Diagnostics.Tracing.TraceEvent": {
+ "type": "Transitive",
+ "resolved": "3.1.21",
+ "contentHash": "/OrJFKaojSR6TkUKtwh8/qA9XWNtxLrXMqvEb89dBSKCWjaGVTbKMYodIUgF5deCEtmd6GXuRerciXGl5bhZ7Q==",
+ "dependencies": {
+ "Microsoft.Diagnostics.NETCore.Client": "0.2.510501",
+ "System.Reflection.TypeExtensions": "4.7.0"
+ }
+ },
+ "Microsoft.DotNet.PlatformAbstractions": {
+ "type": "Transitive",
+ "resolved": "3.1.6",
+ "contentHash": "jek4XYaQ/PGUwDKKhwR8K47Uh1189PFzMeLqO83mXrXQVIpARZCcfuDedH50YDTepBkfijCZN5U/vZi++erxtg=="
+ },
+ "Microsoft.Extensions.DependencyInjection": {
+ "type": "Transitive",
+ "resolved": "6.0.0",
+ "contentHash": "k6PWQMuoBDGGHOQTtyois2u4AwyVcIwL2LaSLlTZQm2CYcJ1pxbt6jfAnpWmzENA/wfrYRI/X9DTLoUkE4AsLw==",
+ "dependencies": {
+ "Microsoft.Extensions.DependencyInjection.Abstractions": "6.0.0"
+ }
+ },
+ "Microsoft.Extensions.DependencyInjection.Abstractions": {
+ "type": "Transitive",
+ "resolved": "6.0.0",
+ "contentHash": "xlzi2IYREJH3/m6+lUrQlujzX8wDitm4QGnUu6kUXTQAWPuZY8i+ticFJbzfqaetLA6KR/rO6Ew/HuYD+bxifg=="
+ },
+ "Microsoft.Extensions.Logging": {
+ "type": "Transitive",
+ "resolved": "6.0.0",
+ "contentHash": "eIbyj40QDg1NDz0HBW0S5f3wrLVnKWnDJ/JtZ+yJDFnDj90VoPuoPmFkeaXrtu+0cKm5GRAwoDf+dBWXK0TUdg==",
+ "dependencies": {
+ "Microsoft.Extensions.DependencyInjection": "6.0.0",
+ "Microsoft.Extensions.DependencyInjection.Abstractions": "6.0.0",
+ "Microsoft.Extensions.Logging.Abstractions": "6.0.0",
+ "Microsoft.Extensions.Options": "6.0.0"
+ }
+ },
+ "Microsoft.Extensions.Logging.Abstractions": {
+ "type": "Transitive",
+ "resolved": "6.0.0",
+ "contentHash": "/HggWBbTwy8TgebGSX5DBZ24ndhzi93sHUBDvP1IxbZD7FDokYzdAr6+vbWGjw2XAfR2EJ1sfKUotpjHnFWPxA=="
+ },
+ "Microsoft.Extensions.Options": {
+ "type": "Transitive",
+ "resolved": "6.0.0",
+ "contentHash": "dzXN0+V1AyjOe2xcJ86Qbo233KHuLEY0njf/P2Kw8SfJU+d45HNS2ctJdnEnrWbM9Ye2eFgaC5Mj9otRMU6IsQ==",
+ "dependencies": {
+ "Microsoft.Extensions.DependencyInjection.Abstractions": "6.0.0",
+ "Microsoft.Extensions.Primitives": "6.0.0"
+ }
+ },
+ "Microsoft.Extensions.Primitives": {
+ "type": "Transitive",
+ "resolved": "6.0.0",
+ "contentHash": "9+PnzmQFfEFNR9J2aDTfJGGupShHjOuGw4VUv+JB044biSHrnmCIMD+mJHmb2H7YryrfBEXDurxQ47gJZdCKNQ=="
+ },
+ "Perfolizer": {
+ "type": "Transitive",
+ "resolved": "0.5.3",
+ "contentHash": "EhHo0s4y+tHJKhZHgQvPgFWhAhnQpHHuFzutRzfqfv5z763wvhzXh849ZtpVePQNxXWoFafh1Ta2tZgnSIVsYQ=="
+ },
+ "System.CodeDom": {
+ "type": "Transitive",
+ "resolved": "9.0.5",
+ "contentHash": "cuzLM2MWutf9ZBEMPYYfd0DXwYdvntp7VCT6a/wvbKCa2ZuvGmW74xi+YBa2mrfEieAXqM4TNKlMmSnfAfpUoQ=="
+ },
+ "System.Management": {
+ "type": "Transitive",
+ "resolved": "9.0.5",
+ "contentHash": "n6o9PZm9p25+zAzC3/48K0oHnaPKTInRrxqFq1fi/5TPbMLjuoCm/h//mS3cUmSy+9AO1Z+qsC/Ilt/ZFatv5Q==",
+ "dependencies": {
+ "System.CodeDom": "9.0.5"
+ }
+ },
+ "System.Reflection.TypeExtensions": {
+ "type": "Transitive",
+ "resolved": "4.7.0",
+ "contentHash": "VybpaOQQhqE6siHppMktjfGBw1GCwvCqiufqmP8F1nj7fTUNtW35LOEt3UZTEsECfo+ELAl/9o9nJx3U91i7vA=="
+ },
+ "functionfoundry.security": {
+ "type": "Project"
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/benchmarks/FunctionFoundry.Storage.Benchmarks/packages.lock.json b/benchmarks/FunctionFoundry.Storage.Benchmarks/packages.lock.json
new file mode 100644
index 0000000..22342b8
--- /dev/null
+++ b/benchmarks/FunctionFoundry.Storage.Benchmarks/packages.lock.json
@@ -0,0 +1,166 @@
+{
+ "version": 2,
+ "dependencies": {
+ "net10.0": {
+ "BenchmarkDotNet": {
+ "type": "Direct",
+ "requested": "[0.15.2, )",
+ "resolved": "0.15.2",
+ "contentHash": "5vl4nQFUGTKgOVE5LNoLpv/X/wFQ7wE5yiaJAXCpzgNtUADtfEwbuufKI4o5E2De0VTXNEeom5Hnv8S8vuBZtg==",
+ "dependencies": {
+ "BenchmarkDotNet.Annotations": "0.15.2",
+ "CommandLineParser": "2.9.1",
+ "Gee.External.Capstone": "2.3.0",
+ "Iced": "1.21.0",
+ "Microsoft.CodeAnalysis.CSharp": "4.14.0",
+ "Microsoft.Diagnostics.Runtime": "3.1.512801",
+ "Microsoft.Diagnostics.Tracing.TraceEvent": "3.1.21",
+ "Microsoft.DotNet.PlatformAbstractions": "3.1.6",
+ "Perfolizer": "[0.5.3]",
+ "System.Management": "9.0.5"
+ }
+ },
+ "BenchmarkDotNet.Annotations": {
+ "type": "Transitive",
+ "resolved": "0.15.2",
+ "contentHash": "a7rVlVmXQRrp3J+HF/FtjwiFcshU6BAuv6U1xtAbqCUYepOEnNGaPeOFvy4It17QZwwofm6U/GAfW3JrFMXszg=="
+ },
+ "CommandLineParser": {
+ "type": "Transitive",
+ "resolved": "2.9.1",
+ "contentHash": "OE0sl1/sQ37bjVsPKKtwQlWDgqaxWgtme3xZz7JssWUzg5JpMIyHgCTY9MVMxOg48fJ1AgGT3tgdH5m/kQ5xhA=="
+ },
+ "Gee.External.Capstone": {
+ "type": "Transitive",
+ "resolved": "2.3.0",
+ "contentHash": "2ap/rYmjtzCOT8hxrnEW/QeiOt+paD8iRrIcdKX0cxVwWLFa1e+JDBNeECakmccXrSFeBQuu5AV8SNkipFMMMw=="
+ },
+ "Iced": {
+ "type": "Transitive",
+ "resolved": "1.21.0",
+ "contentHash": "dv5+81Q1TBQvVMSOOOmRcjJmvWcX3BZPZsIq31+RLc5cNft0IHAyNlkdb7ZarOWG913PyBoFDsDXoCIlKmLclg=="
+ },
+ "Microsoft.CodeAnalysis.Analyzers": {
+ "type": "Transitive",
+ "resolved": "3.11.0",
+ "contentHash": "v/EW3UE8/lbEYHoC2Qq7AR/DnmvpgdtAMndfQNmpuIMx/Mto8L5JnuCfdBYtgvalQOtfNCnxFejxuRrryvUTsg=="
+ },
+ "Microsoft.CodeAnalysis.Common": {
+ "type": "Transitive",
+ "resolved": "4.14.0",
+ "contentHash": "PC3tuwZYnC+idaPuoC/AZpEdwrtX7qFpmnrfQkgobGIWiYmGi5MCRtl5mx6QrfMGQpK78X2lfIEoZDLg/qnuHg==",
+ "dependencies": {
+ "Microsoft.CodeAnalysis.Analyzers": "3.11.0"
+ }
+ },
+ "Microsoft.CodeAnalysis.CSharp": {
+ "type": "Transitive",
+ "resolved": "4.14.0",
+ "contentHash": "568a6wcTivauIhbeWcCwfWwIn7UV7MeHEBvFB2uzGIpM2OhJ4eM/FZ8KS0yhPoNxnSpjGzz7x7CIjTxhslojQA==",
+ "dependencies": {
+ "Microsoft.CodeAnalysis.Analyzers": "3.11.0",
+ "Microsoft.CodeAnalysis.Common": "[4.14.0]"
+ }
+ },
+ "Microsoft.Diagnostics.NETCore.Client": {
+ "type": "Transitive",
+ "resolved": "0.2.510501",
+ "contentHash": "juoqJYMDs+lRrrZyOkXXMImJHneCF23cuvO4waFRd2Ds7j+ZuGIPbJm0Y/zz34BdeaGiiwGWraMUlln05W1PCQ==",
+ "dependencies": {
+ "Microsoft.Extensions.Logging": "6.0.0"
+ }
+ },
+ "Microsoft.Diagnostics.Runtime": {
+ "type": "Transitive",
+ "resolved": "3.1.512801",
+ "contentHash": "0lMUDr2oxNZa28D6NH5BuSQEe5T9tZziIkvkD44YkkCGQXPJqvFjLq5ZQq1hYLl3RjQJrY+hR0jFgap+EWPDTw==",
+ "dependencies": {
+ "Microsoft.Diagnostics.NETCore.Client": "0.2.410101"
+ }
+ },
+ "Microsoft.Diagnostics.Tracing.TraceEvent": {
+ "type": "Transitive",
+ "resolved": "3.1.21",
+ "contentHash": "/OrJFKaojSR6TkUKtwh8/qA9XWNtxLrXMqvEb89dBSKCWjaGVTbKMYodIUgF5deCEtmd6GXuRerciXGl5bhZ7Q==",
+ "dependencies": {
+ "Microsoft.Diagnostics.NETCore.Client": "0.2.510501",
+ "System.Reflection.TypeExtensions": "4.7.0"
+ }
+ },
+ "Microsoft.DotNet.PlatformAbstractions": {
+ "type": "Transitive",
+ "resolved": "3.1.6",
+ "contentHash": "jek4XYaQ/PGUwDKKhwR8K47Uh1189PFzMeLqO83mXrXQVIpARZCcfuDedH50YDTepBkfijCZN5U/vZi++erxtg=="
+ },
+ "Microsoft.Extensions.DependencyInjection": {
+ "type": "Transitive",
+ "resolved": "6.0.0",
+ "contentHash": "k6PWQMuoBDGGHOQTtyois2u4AwyVcIwL2LaSLlTZQm2CYcJ1pxbt6jfAnpWmzENA/wfrYRI/X9DTLoUkE4AsLw==",
+ "dependencies": {
+ "Microsoft.Extensions.DependencyInjection.Abstractions": "6.0.0"
+ }
+ },
+ "Microsoft.Extensions.DependencyInjection.Abstractions": {
+ "type": "Transitive",
+ "resolved": "6.0.0",
+ "contentHash": "xlzi2IYREJH3/m6+lUrQlujzX8wDitm4QGnUu6kUXTQAWPuZY8i+ticFJbzfqaetLA6KR/rO6Ew/HuYD+bxifg=="
+ },
+ "Microsoft.Extensions.Logging": {
+ "type": "Transitive",
+ "resolved": "6.0.0",
+ "contentHash": "eIbyj40QDg1NDz0HBW0S5f3wrLVnKWnDJ/JtZ+yJDFnDj90VoPuoPmFkeaXrtu+0cKm5GRAwoDf+dBWXK0TUdg==",
+ "dependencies": {
+ "Microsoft.Extensions.DependencyInjection": "6.0.0",
+ "Microsoft.Extensions.DependencyInjection.Abstractions": "6.0.0",
+ "Microsoft.Extensions.Logging.Abstractions": "6.0.0",
+ "Microsoft.Extensions.Options": "6.0.0"
+ }
+ },
+ "Microsoft.Extensions.Logging.Abstractions": {
+ "type": "Transitive",
+ "resolved": "6.0.0",
+ "contentHash": "/HggWBbTwy8TgebGSX5DBZ24ndhzi93sHUBDvP1IxbZD7FDokYzdAr6+vbWGjw2XAfR2EJ1sfKUotpjHnFWPxA=="
+ },
+ "Microsoft.Extensions.Options": {
+ "type": "Transitive",
+ "resolved": "6.0.0",
+ "contentHash": "dzXN0+V1AyjOe2xcJ86Qbo233KHuLEY0njf/P2Kw8SfJU+d45HNS2ctJdnEnrWbM9Ye2eFgaC5Mj9otRMU6IsQ==",
+ "dependencies": {
+ "Microsoft.Extensions.DependencyInjection.Abstractions": "6.0.0",
+ "Microsoft.Extensions.Primitives": "6.0.0"
+ }
+ },
+ "Microsoft.Extensions.Primitives": {
+ "type": "Transitive",
+ "resolved": "6.0.0",
+ "contentHash": "9+PnzmQFfEFNR9J2aDTfJGGupShHjOuGw4VUv+JB044biSHrnmCIMD+mJHmb2H7YryrfBEXDurxQ47gJZdCKNQ=="
+ },
+ "Perfolizer": {
+ "type": "Transitive",
+ "resolved": "0.5.3",
+ "contentHash": "EhHo0s4y+tHJKhZHgQvPgFWhAhnQpHHuFzutRzfqfv5z763wvhzXh849ZtpVePQNxXWoFafh1Ta2tZgnSIVsYQ=="
+ },
+ "System.CodeDom": {
+ "type": "Transitive",
+ "resolved": "9.0.5",
+ "contentHash": "cuzLM2MWutf9ZBEMPYYfd0DXwYdvntp7VCT6a/wvbKCa2ZuvGmW74xi+YBa2mrfEieAXqM4TNKlMmSnfAfpUoQ=="
+ },
+ "System.Management": {
+ "type": "Transitive",
+ "resolved": "9.0.5",
+ "contentHash": "n6o9PZm9p25+zAzC3/48K0oHnaPKTInRrxqFq1fi/5TPbMLjuoCm/h//mS3cUmSy+9AO1Z+qsC/Ilt/ZFatv5Q==",
+ "dependencies": {
+ "System.CodeDom": "9.0.5"
+ }
+ },
+ "System.Reflection.TypeExtensions": {
+ "type": "Transitive",
+ "resolved": "4.7.0",
+ "contentHash": "VybpaOQQhqE6siHppMktjfGBw1GCwvCqiufqmP8F1nj7fTUNtW35LOEt3UZTEsECfo+ELAl/9o9nJx3U91i7vA=="
+ },
+ "functionfoundry.storage": {
+ "type": "Project"
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/benchmarks/FunctionFoundry.Text.Benchmarks/packages.lock.json b/benchmarks/FunctionFoundry.Text.Benchmarks/packages.lock.json
new file mode 100644
index 0000000..0e228fe
--- /dev/null
+++ b/benchmarks/FunctionFoundry.Text.Benchmarks/packages.lock.json
@@ -0,0 +1,166 @@
+{
+ "version": 2,
+ "dependencies": {
+ "net10.0": {
+ "BenchmarkDotNet": {
+ "type": "Direct",
+ "requested": "[0.15.2, )",
+ "resolved": "0.15.2",
+ "contentHash": "5vl4nQFUGTKgOVE5LNoLpv/X/wFQ7wE5yiaJAXCpzgNtUADtfEwbuufKI4o5E2De0VTXNEeom5Hnv8S8vuBZtg==",
+ "dependencies": {
+ "BenchmarkDotNet.Annotations": "0.15.2",
+ "CommandLineParser": "2.9.1",
+ "Gee.External.Capstone": "2.3.0",
+ "Iced": "1.21.0",
+ "Microsoft.CodeAnalysis.CSharp": "4.14.0",
+ "Microsoft.Diagnostics.Runtime": "3.1.512801",
+ "Microsoft.Diagnostics.Tracing.TraceEvent": "3.1.21",
+ "Microsoft.DotNet.PlatformAbstractions": "3.1.6",
+ "Perfolizer": "[0.5.3]",
+ "System.Management": "9.0.5"
+ }
+ },
+ "BenchmarkDotNet.Annotations": {
+ "type": "Transitive",
+ "resolved": "0.15.2",
+ "contentHash": "a7rVlVmXQRrp3J+HF/FtjwiFcshU6BAuv6U1xtAbqCUYepOEnNGaPeOFvy4It17QZwwofm6U/GAfW3JrFMXszg=="
+ },
+ "CommandLineParser": {
+ "type": "Transitive",
+ "resolved": "2.9.1",
+ "contentHash": "OE0sl1/sQ37bjVsPKKtwQlWDgqaxWgtme3xZz7JssWUzg5JpMIyHgCTY9MVMxOg48fJ1AgGT3tgdH5m/kQ5xhA=="
+ },
+ "Gee.External.Capstone": {
+ "type": "Transitive",
+ "resolved": "2.3.0",
+ "contentHash": "2ap/rYmjtzCOT8hxrnEW/QeiOt+paD8iRrIcdKX0cxVwWLFa1e+JDBNeECakmccXrSFeBQuu5AV8SNkipFMMMw=="
+ },
+ "Iced": {
+ "type": "Transitive",
+ "resolved": "1.21.0",
+ "contentHash": "dv5+81Q1TBQvVMSOOOmRcjJmvWcX3BZPZsIq31+RLc5cNft0IHAyNlkdb7ZarOWG913PyBoFDsDXoCIlKmLclg=="
+ },
+ "Microsoft.CodeAnalysis.Analyzers": {
+ "type": "Transitive",
+ "resolved": "3.11.0",
+ "contentHash": "v/EW3UE8/lbEYHoC2Qq7AR/DnmvpgdtAMndfQNmpuIMx/Mto8L5JnuCfdBYtgvalQOtfNCnxFejxuRrryvUTsg=="
+ },
+ "Microsoft.CodeAnalysis.Common": {
+ "type": "Transitive",
+ "resolved": "4.14.0",
+ "contentHash": "PC3tuwZYnC+idaPuoC/AZpEdwrtX7qFpmnrfQkgobGIWiYmGi5MCRtl5mx6QrfMGQpK78X2lfIEoZDLg/qnuHg==",
+ "dependencies": {
+ "Microsoft.CodeAnalysis.Analyzers": "3.11.0"
+ }
+ },
+ "Microsoft.CodeAnalysis.CSharp": {
+ "type": "Transitive",
+ "resolved": "4.14.0",
+ "contentHash": "568a6wcTivauIhbeWcCwfWwIn7UV7MeHEBvFB2uzGIpM2OhJ4eM/FZ8KS0yhPoNxnSpjGzz7x7CIjTxhslojQA==",
+ "dependencies": {
+ "Microsoft.CodeAnalysis.Analyzers": "3.11.0",
+ "Microsoft.CodeAnalysis.Common": "[4.14.0]"
+ }
+ },
+ "Microsoft.Diagnostics.NETCore.Client": {
+ "type": "Transitive",
+ "resolved": "0.2.510501",
+ "contentHash": "juoqJYMDs+lRrrZyOkXXMImJHneCF23cuvO4waFRd2Ds7j+ZuGIPbJm0Y/zz34BdeaGiiwGWraMUlln05W1PCQ==",
+ "dependencies": {
+ "Microsoft.Extensions.Logging": "6.0.0"
+ }
+ },
+ "Microsoft.Diagnostics.Runtime": {
+ "type": "Transitive",
+ "resolved": "3.1.512801",
+ "contentHash": "0lMUDr2oxNZa28D6NH5BuSQEe5T9tZziIkvkD44YkkCGQXPJqvFjLq5ZQq1hYLl3RjQJrY+hR0jFgap+EWPDTw==",
+ "dependencies": {
+ "Microsoft.Diagnostics.NETCore.Client": "0.2.410101"
+ }
+ },
+ "Microsoft.Diagnostics.Tracing.TraceEvent": {
+ "type": "Transitive",
+ "resolved": "3.1.21",
+ "contentHash": "/OrJFKaojSR6TkUKtwh8/qA9XWNtxLrXMqvEb89dBSKCWjaGVTbKMYodIUgF5deCEtmd6GXuRerciXGl5bhZ7Q==",
+ "dependencies": {
+ "Microsoft.Diagnostics.NETCore.Client": "0.2.510501",
+ "System.Reflection.TypeExtensions": "4.7.0"
+ }
+ },
+ "Microsoft.DotNet.PlatformAbstractions": {
+ "type": "Transitive",
+ "resolved": "3.1.6",
+ "contentHash": "jek4XYaQ/PGUwDKKhwR8K47Uh1189PFzMeLqO83mXrXQVIpARZCcfuDedH50YDTepBkfijCZN5U/vZi++erxtg=="
+ },
+ "Microsoft.Extensions.DependencyInjection": {
+ "type": "Transitive",
+ "resolved": "6.0.0",
+ "contentHash": "k6PWQMuoBDGGHOQTtyois2u4AwyVcIwL2LaSLlTZQm2CYcJ1pxbt6jfAnpWmzENA/wfrYRI/X9DTLoUkE4AsLw==",
+ "dependencies": {
+ "Microsoft.Extensions.DependencyInjection.Abstractions": "6.0.0"
+ }
+ },
+ "Microsoft.Extensions.DependencyInjection.Abstractions": {
+ "type": "Transitive",
+ "resolved": "6.0.0",
+ "contentHash": "xlzi2IYREJH3/m6+lUrQlujzX8wDitm4QGnUu6kUXTQAWPuZY8i+ticFJbzfqaetLA6KR/rO6Ew/HuYD+bxifg=="
+ },
+ "Microsoft.Extensions.Logging": {
+ "type": "Transitive",
+ "resolved": "6.0.0",
+ "contentHash": "eIbyj40QDg1NDz0HBW0S5f3wrLVnKWnDJ/JtZ+yJDFnDj90VoPuoPmFkeaXrtu+0cKm5GRAwoDf+dBWXK0TUdg==",
+ "dependencies": {
+ "Microsoft.Extensions.DependencyInjection": "6.0.0",
+ "Microsoft.Extensions.DependencyInjection.Abstractions": "6.0.0",
+ "Microsoft.Extensions.Logging.Abstractions": "6.0.0",
+ "Microsoft.Extensions.Options": "6.0.0"
+ }
+ },
+ "Microsoft.Extensions.Logging.Abstractions": {
+ "type": "Transitive",
+ "resolved": "6.0.0",
+ "contentHash": "/HggWBbTwy8TgebGSX5DBZ24ndhzi93sHUBDvP1IxbZD7FDokYzdAr6+vbWGjw2XAfR2EJ1sfKUotpjHnFWPxA=="
+ },
+ "Microsoft.Extensions.Options": {
+ "type": "Transitive",
+ "resolved": "6.0.0",
+ "contentHash": "dzXN0+V1AyjOe2xcJ86Qbo233KHuLEY0njf/P2Kw8SfJU+d45HNS2ctJdnEnrWbM9Ye2eFgaC5Mj9otRMU6IsQ==",
+ "dependencies": {
+ "Microsoft.Extensions.DependencyInjection.Abstractions": "6.0.0",
+ "Microsoft.Extensions.Primitives": "6.0.0"
+ }
+ },
+ "Microsoft.Extensions.Primitives": {
+ "type": "Transitive",
+ "resolved": "6.0.0",
+ "contentHash": "9+PnzmQFfEFNR9J2aDTfJGGupShHjOuGw4VUv+JB044biSHrnmCIMD+mJHmb2H7YryrfBEXDurxQ47gJZdCKNQ=="
+ },
+ "Perfolizer": {
+ "type": "Transitive",
+ "resolved": "0.5.3",
+ "contentHash": "EhHo0s4y+tHJKhZHgQvPgFWhAhnQpHHuFzutRzfqfv5z763wvhzXh849ZtpVePQNxXWoFafh1Ta2tZgnSIVsYQ=="
+ },
+ "System.CodeDom": {
+ "type": "Transitive",
+ "resolved": "9.0.5",
+ "contentHash": "cuzLM2MWutf9ZBEMPYYfd0DXwYdvntp7VCT6a/wvbKCa2ZuvGmW74xi+YBa2mrfEieAXqM4TNKlMmSnfAfpUoQ=="
+ },
+ "System.Management": {
+ "type": "Transitive",
+ "resolved": "9.0.5",
+ "contentHash": "n6o9PZm9p25+zAzC3/48K0oHnaPKTInRrxqFq1fi/5TPbMLjuoCm/h//mS3cUmSy+9AO1Z+qsC/Ilt/ZFatv5Q==",
+ "dependencies": {
+ "System.CodeDom": "9.0.5"
+ }
+ },
+ "System.Reflection.TypeExtensions": {
+ "type": "Transitive",
+ "resolved": "4.7.0",
+ "contentHash": "VybpaOQQhqE6siHppMktjfGBw1GCwvCqiufqmP8F1nj7fTUNtW35LOEt3UZTEsECfo+ELAl/9o9nJx3U91i7vA=="
+ },
+ "functionfoundry.text": {
+ "type": "Project"
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/build/publish-release.cmd b/build/publish-release.cmd
index 6ddbcc5..19b2f61 100644
--- a/build/publish-release.cmd
+++ b/build/publish-release.cmd
@@ -10,6 +10,7 @@ set "STAGE_PACKAGES=%RELEASE_DIR%\packages"
set "DOTNET_NOLOGO=1"
set "DOTNET_CLI_TELEMETRY_OPTOUT=1"
+if not defined FF_RELEASE_PACK set "FF_RELEASE_PACK=true"
echo ==> Repository root: %ROOT%
echo ==> Cleaning %RELEASE_DIR%
@@ -18,17 +19,17 @@ mkdir "%STAGE_BIN%"
mkdir "%STAGE_PACKAGES%"
echo ==> Restoring
-dotnet restore FunctionFoundry.slnx
+dotnet restore --locked-mode FunctionFoundry.slnx
if errorlevel 1 exit /b 1
echo ==> Building Release
-dotnet build FunctionFoundry.slnx -c Release --no-restore
+dotnet build FunctionFoundry.slnx -c Release --no-restore -p:VersionSuffix=
if errorlevel 1 exit /b 1
echo ==> Packing NuGet packages
if exist "%ROOT%\artifacts\packages" rmdir /s /q "%ROOT%\artifacts\packages"
mkdir "%ROOT%\artifacts\packages"
-dotnet pack FunctionFoundry.slnx -c Release --no-build -o "%ROOT%\artifacts\packages"
+dotnet pack FunctionFoundry.slnx -c Release --no-build -o "%ROOT%\artifacts\packages" -p:VersionSuffix=
if errorlevel 1 exit /b 1
echo ==> Collecting library binaries
diff --git a/build/publish-release.sh b/build/publish-release.sh
index 860c990..29de8dc 100755
--- a/build/publish-release.sh
+++ b/build/publish-release.sh
@@ -7,6 +7,7 @@ cd "$ROOT"
export DOTNET_NOLOGO="${DOTNET_NOLOGO:-1}"
export DOTNET_CLI_TELEMETRY_OPTOUT="${DOTNET_CLI_TELEMETRY_OPTOUT:-1}"
+export FF_RELEASE_PACK="${FF_RELEASE_PACK:-true}"
RELEASE_DIR="$ROOT/Release"
STAGE_BIN="$RELEASE_DIR/bin"
@@ -18,15 +19,15 @@ rm -rf "$RELEASE_DIR"
mkdir -p "$STAGE_BIN" "$STAGE_PACKAGES"
echo "==> Restoring"
-dotnet restore FunctionFoundry.slnx
+dotnet restore --locked-mode FunctionFoundry.slnx
echo "==> Building Release"
-dotnet build FunctionFoundry.slnx -c Release --no-restore
+dotnet build FunctionFoundry.slnx -c Release --no-restore -p:VersionSuffix=
echo "==> Packing NuGet packages"
rm -rf "$ROOT/artifacts/packages"
mkdir -p "$ROOT/artifacts/packages"
-dotnet pack FunctionFoundry.slnx -c Release --no-build -o "$ROOT/artifacts/packages"
+dotnet pack FunctionFoundry.slnx -c Release --no-build -o "$ROOT/artifacts/packages" -p:VersionSuffix=
echo "==> Collecting library binaries"
shopt -s nullglob
diff --git a/docs/FINAL_REPORT.md b/docs/FINAL_REPORT.md
index 668c5ba..668d7c2 100644
--- a/docs/FINAL_REPORT.md
+++ b/docs/FINAL_REPORT.md
@@ -7,7 +7,7 @@
* `tests/` — per-package xUnit projects + Engineering.Tests
* `samples/` / `benchmarks/` — per-package executables
* `docs/adr`, `docs/packages`, CI under `.github/workflows`
-* Central build: `Directory.Build.props/targets`, `Directory.Packages.props`, `global.json` (10.0.301)
+* Central build: `Directory.Build.props/targets`, `Directory.Packages.props`, `global.json` (**10.0.302**)
## 2. Delivered packages
@@ -40,17 +40,18 @@ Listed above (also `git log --grep='\[PBI-'`).
## 6. Test counts and coverage
-* **182** tests passed (`dotnet test -c Release`)
-* Breakdown: Engineering 3, Security 12, Storage 33, Integrity 36, Observability 22, Data 13, Text 13, Resilience 14, Networking 10, Distributed 16, Scheduling 10
-* Formal cobertura threshold gate not numerically asserted in CI YAML (tests pass; coverage collector configured)
+* **242** unit tests passed on remediation branch (pre-remediation baseline was 224 in `docs/coverage-summary.md`)
+* Line coverage baseline **84.8%**, branch **72.3%** (pre-remediation figures)
+* CI now enforces ≥**85%** aggregated line coverage and builds all samples
+* Branch coverage remains below the aspirational ≥90% critical-algorithm target; Distributed and Integrity received additional tests on the remediation branch
## 7. Benchmark summary
-BenchmarkDotNet projects exist for all ten packages. Initial baseline environment: .NET 10.0.301 / linux-x64. Benchmarks were compiled; long full BenchmarkDotNet runs were not used as CI gates.
+BenchmarkDotNet projects exist for all ten packages. Benchmarks compile; long full BenchmarkDotNet runs are not CI gates.
## 8. DLL and NuGet sizes
-See `docs/packages/size-and-compatibility-report-v1.md` (Storage nupkg ~47KB largest; Security ~21KB smallest).
+See `docs/packages/size-and-compatibility-report-v1.md`.
## 9. Runtime dependency list
@@ -60,8 +61,7 @@ See `docs/packages/size-and-compatibility-report-v1.md` (Storage nupkg ~47KB lar
## 10. Security review summary
* Security package uses only BCL crypto (AES-GCM, HMAC-SHA256, RNG)
-* Auth failures clear plaintext buffers; fixed-time compare helper
-* Threat model in ADR-0005 and package docs; no formal proof claims
+* Threat model in ADR-0005; private reporting via GitHub Security Advisories (see `SECURITY.md`)
* Secret scanner / redaction are heuristic and documented as such
## 11. XML documentation status
@@ -72,28 +72,27 @@ See `docs/packages/size-and-compatibility-report-v1.md` (Storage nupkg ~47KB lar
## 12. Package-validation status
* `EnablePackageValidation=true` for packable projects
-* First release: no prior baseline package to validate against
+* Baseline version should be set to published `1.0.0` after the clean NuGet publish (not the accidental `1.0.0-local`)
## 13. Generated artifact locations
-* `artifacts/packages/FunctionFoundry.*.1.0.0.nupkg` (+ `.snupkg`)
+* `artifacts/packages/FunctionFoundry.*.nupkg` (+ `.snupkg`)
* `artifacts/bin/**/release/*.dll`
+* Release bundle via `build/publish-release.*` (sets `FF_RELEASE_PACK=true` for clean versions)
-## 14. Tags / releases that succeeded
+## 14. Tags / releases
-* Git tag **`v1.0.0`** pushed to origin
-* NuGet.org publish: **not performed** (no publish credentials/permission invoked)
-* GitHub Release asset upload: not claimed
+* Git tag **`1.0.0`** on origin (docs previously said `v1.0.0`; the published tag has no `v` prefix)
+* NuGet.org: accidental **`1.0.0-local`** present; clean **`1.0.0`** publish pending `NUGET_API_KEY` + Publish workflow
+* GitHub Release `1.0.0` exists (verify release notes reference `Chookees/FunctionFoundry`, not prior repo names)
## 15. Deviations
* Cloud branch naming `cursor/...-482e` instead of `pbi/...`
* PBI commit order on main not strictly 01→12
-* Separate `v0.5.0` tag omitted; Feature 1 hardening folded into `8a90d76` / v1.0 docs
+* Separate `v0.5.0` tag omitted
* Unicode confusables: compact subset, not full UCD
-* Some Networking adaptive-repair behaviors are partial (documented by implementers)
-* CI does not yet fail on cobertura % threshold numbers
-* `IsAotCompatible` not claimed
+* SDK maintenance upgrade **10.0.301 → 10.0.302**
## 16. Remaining known risks
diff --git a/docs/adr/0003-sdk-pinning-policy.md b/docs/adr/0003-sdk-pinning-policy.md
index a24289a..3263253 100644
--- a/docs/adr/0003-sdk-pinning-policy.md
+++ b/docs/adr/0003-sdk-pinning-policy.md
@@ -1,7 +1,8 @@
-# ADR-0003: Pin .NET SDK 10.0.301 with explicit upgrades
+# ADR-0003: Pin .NET SDK with explicit upgrades
* **Status:** Accepted
* **Date:** 2026-07-14
+* **Updated:** 2026-08-03
* **Deciders:** FunctionFoundry architects
## Context
@@ -10,7 +11,7 @@ Silent SDK roll-forward can change analyzer behavior, pack outputs, and language
## Decision
-* Pin SDK `10.0.301` in `global.json`.
+* Pin SDK `10.0.302` in `global.json` (maintenance upgrade from `10.0.301`).
* Set `rollForward` to `disable`.
* Target `net10.0` and C# 14.0.
* Treat future SDK moves as explicit maintenance upgrades with changelog notes and CI verification.
diff --git a/docs/coverage-summary.md b/docs/coverage-summary.md
index c117fea..6e071ba 100644
--- a/docs/coverage-summary.md
+++ b/docs/coverage-summary.md
@@ -1,32 +1,32 @@
# Unit test coverage summary
-Measured with Coverlet Cobertura on a Release `net10.0` build (SDK 10.0.301).
+Measured with Coverlet Cobertura on a Release `net10.0` build (SDK **10.0.302**), aggregated by unique package name (same methodology as CI).
-**Unit tests:** 224 passed, 0 failed, 0 skipped.
+**Unit tests:** 242 passed, 0 failed, 0 skipped.
## Overall
| Metric | Value |
|---|---:|
-| Line coverage (`src/` libraries) | **84.8%** (4327 / 5103) |
-| Branch coverage (`src/` libraries) | **72.3%** (1791 / 2478) |
+| Line coverage (`src/` libraries) | **85.8%** (8858 / 10326) |
+| CI gate | ≥ **85%** line (enforced) |
## By package
-| Package | Line coverage | Branch coverage |
-|---|---:|---:|
-| `FunctionFoundry.Data` | 81.6% (496/608) | 72.6% (231/318) |
-| `FunctionFoundry.Distributed` | 77.8% (346/445) | 62.1% (154/248) |
-| `FunctionFoundry.Integrity` | 84.6% (468/553) | 67.8% (213/314) |
-| `FunctionFoundry.Networking` | 91.7% (287/313) | 76.0% (111/146) |
-| `FunctionFoundry.Observability` | 85.5% (523/612) | 71.3% (231/324) |
-| `FunctionFoundry.Resilience` | 81.2% (428/527) | 70.9% (139/196) |
-| `FunctionFoundry.Scheduling` | 84.1% (392/466) | 75.6% (186/246) |
-| `FunctionFoundry.Security` | 90.4% (293/324) | 72.8% (99/136) |
-| `FunctionFoundry.Storage` | 85.7% (683/797) | 75.5% (240/318) |
-| `FunctionFoundry.Text` | 89.7% (411/458) | 80.6% (187/232) |
-| **Overall (src libraries)** | **84.8% (4327/5103)** | **72.3% (1791/2478)** |
+| Package | Line coverage |
+|---|---:|
+| `FunctionFoundry.Data` | 81.6% (992/1216) |
+| `FunctionFoundry.Distributed` | 87.9% (782/890) |
+| `FunctionFoundry.Integrity` | 85.9% (952/1108) |
+| `FunctionFoundry.Networking` | 90.3% (672/744) |
+| `FunctionFoundry.Observability` | 85.6% (1048/1224) |
+| `FunctionFoundry.Resilience` | 81.2% (856/1054) |
+| `FunctionFoundry.Scheduling` | 84.1% (784/932) |
+| `FunctionFoundry.Security` | 90.4% (586/648) |
+| `FunctionFoundry.Storage` | 85.6% (1364/1594) |
+| `FunctionFoundry.Text` | 89.7% (822/916) |
+| **Overall (src libraries)** | **85.8% (8858/10326)** |
## Pipeline note
-Latest verified green CI for the expanded test branch: https://github.com/Chookees/FunctionFoundry/actions/runs/29378869693
+CI fails when aggregated line coverage is below 85%. Branch-coverage ≥90% for critical algorithms remains an aspirational target (not yet a hard gate).
diff --git a/docs/packages/FunctionFoundry.Networking.md b/docs/packages/FunctionFoundry.Networking.md
index d1c63bd..40743dc 100644
--- a/docs/packages/FunctionFoundry.Networking.md
+++ b/docs/packages/FunctionFoundry.Networking.md
@@ -14,6 +14,6 @@ Capability is detected with a lightweight `Range: bytes=0-0` probe. When ranges
Download and transfer checkpoints are persisted through abstractions so hosts can use files, object storage, or databases. Incompatible checkpoints (changed ETag, size, or plan version) are rejected explicitly.
-### Integrity
+### Adaptive chunks and repair
-`StreamingIntegrityVerifier` maintains per-chunk digests and a rolling full-object hash without buffering entire files in memory.
+`ResumableParallelDownloader` smooths chunk size within configured min/max bounds from observed per-chunk throughput. Length-mismatched range responses are reassigned via `TransferPlan.GetRepairAssignments`. When the final object digest fails, optional repair passes re-download the plan's chunks (`MaxRepairPasses`).
diff --git a/eng/README.md b/eng/README.md
index 72fd7f8..126bcb7 100644
--- a/eng/README.md
+++ b/eng/README.md
@@ -24,7 +24,8 @@ Set `IsTrimmable` / `IsAotCompatible` only after smoke tests pass.
* Framework: xUnit
* Deterministic seeds for randomized tests
* No mocking frameworks unless interaction-based mocking is required
-* Coverage target ≥85% line across production code
+* Target: ≥85% line coverage across production `src/` (enforced in CI)
+* Prefer ≥90% branch coverage on critical algorithms where practical; document justified exclusions
## Benchmark conventions
diff --git a/global.json b/global.json
index a5f940e..c66295e 100644
--- a/global.json
+++ b/global.json
@@ -1,6 +1,6 @@
{
"sdk": {
- "version": "10.0.301",
+ "version": "10.0.302",
"rollForward": "disable",
"allowPrerelease": false
}
diff --git a/samples/FunctionFoundry.Data.Sample/packages.lock.json b/samples/FunctionFoundry.Data.Sample/packages.lock.json
new file mode 100644
index 0000000..97c0c5c
--- /dev/null
+++ b/samples/FunctionFoundry.Data.Sample/packages.lock.json
@@ -0,0 +1,10 @@
+{
+ "version": 2,
+ "dependencies": {
+ "net10.0": {
+ "functionfoundry.data": {
+ "type": "Project"
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/samples/FunctionFoundry.Distributed.Sample/packages.lock.json b/samples/FunctionFoundry.Distributed.Sample/packages.lock.json
new file mode 100644
index 0000000..27d4b34
--- /dev/null
+++ b/samples/FunctionFoundry.Distributed.Sample/packages.lock.json
@@ -0,0 +1,10 @@
+{
+ "version": 2,
+ "dependencies": {
+ "net10.0": {
+ "functionfoundry.distributed": {
+ "type": "Project"
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/samples/FunctionFoundry.Integrity.Sample/packages.lock.json b/samples/FunctionFoundry.Integrity.Sample/packages.lock.json
new file mode 100644
index 0000000..11cad9e
--- /dev/null
+++ b/samples/FunctionFoundry.Integrity.Sample/packages.lock.json
@@ -0,0 +1,10 @@
+{
+ "version": 2,
+ "dependencies": {
+ "net10.0": {
+ "functionfoundry.integrity": {
+ "type": "Project"
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/samples/FunctionFoundry.Networking.Sample/packages.lock.json b/samples/FunctionFoundry.Networking.Sample/packages.lock.json
new file mode 100644
index 0000000..a3a8d88
--- /dev/null
+++ b/samples/FunctionFoundry.Networking.Sample/packages.lock.json
@@ -0,0 +1,10 @@
+{
+ "version": 2,
+ "dependencies": {
+ "net10.0": {
+ "functionfoundry.networking": {
+ "type": "Project"
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/samples/FunctionFoundry.Observability.Sample/packages.lock.json b/samples/FunctionFoundry.Observability.Sample/packages.lock.json
new file mode 100644
index 0000000..2f7ce41
--- /dev/null
+++ b/samples/FunctionFoundry.Observability.Sample/packages.lock.json
@@ -0,0 +1,10 @@
+{
+ "version": 2,
+ "dependencies": {
+ "net10.0": {
+ "functionfoundry.observability": {
+ "type": "Project"
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/samples/FunctionFoundry.Resilience.Sample/packages.lock.json b/samples/FunctionFoundry.Resilience.Sample/packages.lock.json
new file mode 100644
index 0000000..74a1a17
--- /dev/null
+++ b/samples/FunctionFoundry.Resilience.Sample/packages.lock.json
@@ -0,0 +1,10 @@
+{
+ "version": 2,
+ "dependencies": {
+ "net10.0": {
+ "functionfoundry.resilience": {
+ "type": "Project"
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/samples/FunctionFoundry.Scheduling.Sample/packages.lock.json b/samples/FunctionFoundry.Scheduling.Sample/packages.lock.json
new file mode 100644
index 0000000..fb2ca62
--- /dev/null
+++ b/samples/FunctionFoundry.Scheduling.Sample/packages.lock.json
@@ -0,0 +1,10 @@
+{
+ "version": 2,
+ "dependencies": {
+ "net10.0": {
+ "functionfoundry.scheduling": {
+ "type": "Project"
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/samples/FunctionFoundry.Security.Sample/packages.lock.json b/samples/FunctionFoundry.Security.Sample/packages.lock.json
new file mode 100644
index 0000000..cfe2447
--- /dev/null
+++ b/samples/FunctionFoundry.Security.Sample/packages.lock.json
@@ -0,0 +1,10 @@
+{
+ "version": 2,
+ "dependencies": {
+ "net10.0": {
+ "functionfoundry.security": {
+ "type": "Project"
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/samples/FunctionFoundry.Storage.Sample/packages.lock.json b/samples/FunctionFoundry.Storage.Sample/packages.lock.json
new file mode 100644
index 0000000..d3f197c
--- /dev/null
+++ b/samples/FunctionFoundry.Storage.Sample/packages.lock.json
@@ -0,0 +1,10 @@
+{
+ "version": 2,
+ "dependencies": {
+ "net10.0": {
+ "functionfoundry.storage": {
+ "type": "Project"
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/samples/FunctionFoundry.Text.Sample/packages.lock.json b/samples/FunctionFoundry.Text.Sample/packages.lock.json
new file mode 100644
index 0000000..aed157a
--- /dev/null
+++ b/samples/FunctionFoundry.Text.Sample/packages.lock.json
@@ -0,0 +1,10 @@
+{
+ "version": 2,
+ "dependencies": {
+ "net10.0": {
+ "functionfoundry.text": {
+ "type": "Project"
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/FunctionFoundry.Data/packages.lock.json b/src/FunctionFoundry.Data/packages.lock.json
new file mode 100644
index 0000000..04d70a3
--- /dev/null
+++ b/src/FunctionFoundry.Data/packages.lock.json
@@ -0,0 +1,27 @@
+{
+ "version": 2,
+ "dependencies": {
+ "net10.0": {
+ "Microsoft.SourceLink.GitHub": {
+ "type": "Direct",
+ "requested": "[8.0.0, )",
+ "resolved": "8.0.0",
+ "contentHash": "G5q7OqtwIyGTkeIOAc3u2ZuV/kicQaec5EaRnc0pIeSnh9LUjj+PYQrJYBURvDt7twGl2PKA7nSN0kz1Zw5bnQ==",
+ "dependencies": {
+ "Microsoft.Build.Tasks.Git": "8.0.0",
+ "Microsoft.SourceLink.Common": "8.0.0"
+ }
+ },
+ "Microsoft.Build.Tasks.Git": {
+ "type": "Transitive",
+ "resolved": "8.0.0",
+ "contentHash": "bZKfSIKJRXLTuSzLudMFte/8CempWjVamNUR5eHJizsy+iuOuO/k2gnh7W0dHJmYY0tBf+gUErfluCv5mySAOQ=="
+ },
+ "Microsoft.SourceLink.Common": {
+ "type": "Transitive",
+ "resolved": "8.0.0",
+ "contentHash": "dk9JPxTCIevS75HyEQ0E4OVAFhB2N+V9ShCXf8Q6FkUQZDkgLI12y679Nym1YqsiSysuQskT7Z+6nUf3yab6Vw=="
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/FunctionFoundry.Distributed/packages.lock.json b/src/FunctionFoundry.Distributed/packages.lock.json
new file mode 100644
index 0000000..04d70a3
--- /dev/null
+++ b/src/FunctionFoundry.Distributed/packages.lock.json
@@ -0,0 +1,27 @@
+{
+ "version": 2,
+ "dependencies": {
+ "net10.0": {
+ "Microsoft.SourceLink.GitHub": {
+ "type": "Direct",
+ "requested": "[8.0.0, )",
+ "resolved": "8.0.0",
+ "contentHash": "G5q7OqtwIyGTkeIOAc3u2ZuV/kicQaec5EaRnc0pIeSnh9LUjj+PYQrJYBURvDt7twGl2PKA7nSN0kz1Zw5bnQ==",
+ "dependencies": {
+ "Microsoft.Build.Tasks.Git": "8.0.0",
+ "Microsoft.SourceLink.Common": "8.0.0"
+ }
+ },
+ "Microsoft.Build.Tasks.Git": {
+ "type": "Transitive",
+ "resolved": "8.0.0",
+ "contentHash": "bZKfSIKJRXLTuSzLudMFte/8CempWjVamNUR5eHJizsy+iuOuO/k2gnh7W0dHJmYY0tBf+gUErfluCv5mySAOQ=="
+ },
+ "Microsoft.SourceLink.Common": {
+ "type": "Transitive",
+ "resolved": "8.0.0",
+ "contentHash": "dk9JPxTCIevS75HyEQ0E4OVAFhB2N+V9ShCXf8Q6FkUQZDkgLI12y679Nym1YqsiSysuQskT7Z+6nUf3yab6Vw=="
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/FunctionFoundry.Integrity/StreamingHashManifest.cs b/src/FunctionFoundry.Integrity/StreamingHashManifest.cs
index 18a6024..2f67a2d 100644
--- a/src/FunctionFoundry.Integrity/StreamingHashManifest.cs
+++ b/src/FunctionFoundry.Integrity/StreamingHashManifest.cs
@@ -280,6 +280,7 @@ internal StreamingHashManifestBuilder(ManifestHashAlgorithm algorithm, ManifestM
/// Thrown when the path is unsafe or size metadata is disallowed.
public ManifestEntry AddEntry(string relativePath, Stream content, bool includeSize = true)
{
+ ArgumentNullException.ThrowIfNull(content);
string normalized = PathSafety.NormalizeRelativePath(relativePath);
(string hashHex, long size) = StreamingHashManifest.HashStream(content, _algorithm);
long? recordedSize = includeSize && _metadataPolicy.AllowFileSize ? size : null;
diff --git a/src/FunctionFoundry.Integrity/packages.lock.json b/src/FunctionFoundry.Integrity/packages.lock.json
new file mode 100644
index 0000000..04d70a3
--- /dev/null
+++ b/src/FunctionFoundry.Integrity/packages.lock.json
@@ -0,0 +1,27 @@
+{
+ "version": 2,
+ "dependencies": {
+ "net10.0": {
+ "Microsoft.SourceLink.GitHub": {
+ "type": "Direct",
+ "requested": "[8.0.0, )",
+ "resolved": "8.0.0",
+ "contentHash": "G5q7OqtwIyGTkeIOAc3u2ZuV/kicQaec5EaRnc0pIeSnh9LUjj+PYQrJYBURvDt7twGl2PKA7nSN0kz1Zw5bnQ==",
+ "dependencies": {
+ "Microsoft.Build.Tasks.Git": "8.0.0",
+ "Microsoft.SourceLink.Common": "8.0.0"
+ }
+ },
+ "Microsoft.Build.Tasks.Git": {
+ "type": "Transitive",
+ "resolved": "8.0.0",
+ "contentHash": "bZKfSIKJRXLTuSzLudMFte/8CempWjVamNUR5eHJizsy+iuOuO/k2gnh7W0dHJmYY0tBf+gUErfluCv5mySAOQ=="
+ },
+ "Microsoft.SourceLink.Common": {
+ "type": "Transitive",
+ "resolved": "8.0.0",
+ "contentHash": "dk9JPxTCIevS75HyEQ0E4OVAFhB2N+V9ShCXf8Q6FkUQZDkgLI12y679Nym1YqsiSysuQskT7Z+6nUf3yab6Vw=="
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/FunctionFoundry.Networking/PACKAGE.md b/src/FunctionFoundry.Networking/PACKAGE.md
index ef45141..c4575d8 100644
--- a/src/FunctionFoundry.Networking/PACKAGE.md
+++ b/src/FunctionFoundry.Networking/PACKAGE.md
@@ -4,9 +4,9 @@ Resumable, integrity-aware HTTP transfer orchestration using caller-provided `Ht
## Capabilities
-* **Resumable parallel downloader** — HTTP ranges with ETag/Last-Modified validation, adaptive chunks, checkpoint resume, and final digest verification
+* **Resumable parallel downloader** — HTTP ranges with ETag/Last-Modified validation, adaptive chunk sizing within configured min/max bounds, checkpoint resume, corrupt-chunk repair passes, and final digest verification
* **Mirror selector** — multi-signal scoring with failure decay, hysteresis, and exportable evidence
-* **Transfer plan** — chunk assignments independent of execution with overlap detection and corrupt-chunk repair
+* **Transfer plan** — chunk assignments independent of execution with overlap detection and corrupt-chunk repair assignment helpers
* **Streaming integrity verifier** — bounded-memory incremental per-chunk and full-object digest verification
## Runtime dependencies
@@ -16,3 +16,5 @@ None beyond the .NET shared framework.
## Usage note
Always inject a shared `HttpClient` (or `IHttpClientFactory`-managed instance). This library never creates per-request `HttpClient` instances.
+
+Adaptive sizing observes per-chunk throughput and smooths the next recommended chunk size within `MinChunkSizeBytes`/`MaxChunkSizeBytes`. Repair re-downloads length-mismatched chunks immediately and can re-fetch the full plan when the final object digest fails (`MaxRepairPasses`).
diff --git a/src/FunctionFoundry.Networking/README.md b/src/FunctionFoundry.Networking/README.md
index 9e6efd4..ef926ad 100644
--- a/src/FunctionFoundry.Networking/README.md
+++ b/src/FunctionFoundry.Networking/README.md
@@ -13,6 +13,8 @@ Downloads large objects using HTTP range requests when available:
* ETag / Last-Modified validation
* persistent checkpoint format
* configurable parallelism
+* adaptive chunk sizing within min/max bounds (throughput-smoothed)
+* corrupt-chunk repair (length mismatch + optional full-digest repair passes)
* partial-file integrity and final cryptographic verification
* safe restart after interruption
* capability detection and correct fallback when ranges are unsupported
diff --git a/src/FunctionFoundry.Networking/ResumableParallelDownloader.cs b/src/FunctionFoundry.Networking/ResumableParallelDownloader.cs
index 33573b0..f2614aa 100644
--- a/src/FunctionFoundry.Networking/ResumableParallelDownloader.cs
+++ b/src/FunctionFoundry.Networking/ResumableParallelDownloader.cs
@@ -1,3 +1,4 @@
+using System.Diagnostics;
using System.Net;
using System.Net.Http.Headers;
@@ -29,7 +30,13 @@ public sealed record DownloadCheckpoint(
/// Whether final digest verification succeeded.
/// Whether a prior checkpoint was used.
/// Whether range requests were used.
-public sealed record DownloadResult(long BytesWritten, bool Verified, bool ResumedFromCheckpoint, bool UsedRangeRequests);
+/// Number of chunks re-downloaded during corrupt-chunk repair.
+public sealed record DownloadResult(
+ long BytesWritten,
+ bool Verified,
+ bool ResumedFromCheckpoint,
+ bool UsedRangeRequests,
+ int RepairedChunkCount = 0);
///
/// Options for .
@@ -56,6 +63,18 @@ public sealed class ResumableParallelDownloaderOptions
///
public int MaxParallelism { get; set; } = 4;
+ ///
+ /// Gets or sets whether chunk size may grow or shrink within min/max based on observed throughput.
+ /// Defaults to .
+ ///
+ public bool EnableAdaptiveChunkSizing { get; set; } = true;
+
+ ///
+ /// Gets or sets the maximum number of full-object repair passes after digest verification fails.
+ /// Defaults to 1.
+ ///
+ public int MaxRepairPasses { get; set; } = 1;
+
///
/// Validates option ranges.
///
@@ -75,6 +94,11 @@ public void Validate()
{
throw new ArgumentOutOfRangeException(nameof(MaxParallelism), "MaxParallelism must be positive.");
}
+
+ if (MaxRepairPasses < 0)
+ {
+ throw new ArgumentOutOfRangeException(nameof(MaxRepairPasses), "MaxRepairPasses cannot be negative.");
+ }
}
}
@@ -124,13 +148,14 @@ public Task SaveAsync(DownloadCheckpoint checkpoint, CancellationToken cancellat
}
///
-/// Downloads content with resumable HTTP range support and integrity verification.
+/// Downloads content with resumable HTTP range support, adaptive chunk sizing, and integrity-aware repair.
///
public sealed class ResumableParallelDownloader
{
private readonly HttpClient _httpClient;
private readonly IDownloadCheckpointStore _checkpointStore;
private readonly ResumableParallelDownloaderOptions _options;
+ private int _adaptiveChunkSizeBytes;
///
/// Initializes a new downloader using the caller-provided .
@@ -147,6 +172,7 @@ public ResumableParallelDownloader(
_checkpointStore = checkpointStore ?? throw new ArgumentNullException(nameof(checkpointStore));
_options = options ?? new ResumableParallelDownloaderOptions();
_options.Validate();
+ _adaptiveChunkSizeBytes = _options.InitialChunkSizeBytes;
}
///
@@ -154,6 +180,11 @@ public ResumableParallelDownloader(
///
public ResumableParallelDownloaderOptions Options => _options;
+ ///
+ /// Gets the current adaptive chunk size recommendation in bytes.
+ ///
+ public int AdaptiveChunkSizeBytes => _adaptiveChunkSizeBytes;
+
///
/// Downloads content into a seekable stream.
///
@@ -189,6 +220,7 @@ public async Task DownloadAsync(
{
totalSize = probeResponse.Content.Headers.ContentLength ?? 0;
}
+
string? etag = probeResponse.Headers.ETag?.Tag;
string? lastModified = probeResponse.Content.Headers.LastModified?.ToString("R");
@@ -200,16 +232,17 @@ public async Task DownloadAsync(
resumed = false;
}
- int chunkSize = existing?.ChunkSizeBytes ?? _options.InitialChunkSizeBytes;
+ int chunkSize = existing?.ChunkSizeBytes ?? ChooseChunkSize(totalSize);
TransferPlan plan = TransferPlan.Create(totalSize, chunkSize);
- HashSet completed = existing?.CompletedChunkIndices.ToHashSet() ?? new HashSet();
- using StreamingIntegrityVerifier verifier = new();
+ HashSet completed = existing?.CompletedChunkIndices.ToHashSet() ?? [];
+ int repairedChunkCount = 0;
if (!supportsRanges || totalSize <= 0)
{
byte[] full = await DownloadFullAsync(url, cancellationToken).ConfigureAwait(false);
destination.SetLength(0);
await destination.WriteAsync(full, cancellationToken).ConfigureAwait(false);
+ using StreamingIntegrityVerifier verifier = new();
verifier.AppendChunk(0, full);
FullVerificationResult verification = verifier.VerifyFull(expectedSha256Hex);
await SaveCheckpointAsync(url, totalSize, etag, lastModified, chunkSize, completed, supportsRanges, cancellationToken).ConfigureAwait(false);
@@ -221,9 +254,80 @@ public async Task DownloadAsync(
destination.SetLength(totalSize);
}
+ await DownloadChunksAsync(url, destination, plan, completed, etag, cancellationToken).ConfigureAwait(false);
+
+ FullVerificationResult fullVerification = await VerifyDestinationAsync(destination, plan, expectedSha256Hex, cancellationToken).ConfigureAwait(false);
+ for (int repairPass = 0; !fullVerification.IsValid && repairPass < _options.MaxRepairPasses; repairPass++)
+ {
+ IReadOnlyList repair = plan.GetRepairAssignments(plan.Chunks.Select(static c => c.Index));
+ if (repair.Count == 0)
+ {
+ break;
+ }
+
+ foreach (TransferChunkAssignment chunk in repair)
+ {
+ completed.Remove(chunk.Index);
+ }
+
+ await DownloadChunksAsync(url, destination, plan, completed, etag, cancellationToken).ConfigureAwait(false);
+ repairedChunkCount += repair.Count;
+ fullVerification = await VerifyDestinationAsync(destination, plan, expectedSha256Hex, cancellationToken).ConfigureAwait(false);
+ }
+
+ await SaveCheckpointAsync(url, totalSize, etag, lastModified, chunkSize, completed, supportsRanges, cancellationToken).ConfigureAwait(false);
+ return new DownloadResult(totalSize, fullVerification.IsValid, resumed, true, repairedChunkCount);
+ }
+
+ private int ChooseChunkSize(long totalSizeBytes)
+ {
+ int candidate = _options.EnableAdaptiveChunkSizing ? _adaptiveChunkSizeBytes : _options.InitialChunkSizeBytes;
+ if (_options.EnableAdaptiveChunkSizing && totalSizeBytes > 0)
+ {
+ // Prefer fewer chunks for large objects and smaller chunks for tiny objects.
+ if (totalSizeBytes < _options.MinChunkSizeBytes * 4L)
+ {
+ candidate = Math.Min(candidate, _options.MinChunkSizeBytes);
+ }
+ else if (totalSizeBytes > _options.MaxChunkSizeBytes * 8L)
+ {
+ candidate = Math.Max(candidate, Math.Min(_options.MaxChunkSizeBytes, _options.InitialChunkSizeBytes * 2));
+ }
+ }
+
+ return Math.Clamp(candidate, _options.MinChunkSizeBytes, _options.MaxChunkSizeBytes);
+ }
+
+ private void ObserveChunkThroughput(int bytes, TimeSpan elapsed)
+ {
+ if (!_options.EnableAdaptiveChunkSizing || bytes <= 0 || elapsed <= TimeSpan.Zero)
+ {
+ return;
+ }
+
+ double bytesPerSecond = bytes / Math.Max(elapsed.TotalSeconds, 0.001);
+ // Target roughly 250–750 ms per chunk.
+ const double targetSeconds = 0.5;
+ int suggested = (int)Math.Clamp(bytesPerSecond * targetSeconds, _options.MinChunkSizeBytes, _options.MaxChunkSizeBytes);
+ // Smooth toward the suggestion to avoid oscillation.
+ _adaptiveChunkSizeBytes = (_adaptiveChunkSizeBytes + suggested) / 2;
+ _adaptiveChunkSizeBytes = Math.Clamp(_adaptiveChunkSizeBytes, _options.MinChunkSizeBytes, _options.MaxChunkSizeBytes);
+ }
+
+ private async Task DownloadChunksAsync(
+ Uri url,
+ Stream destination,
+ TransferPlan plan,
+ HashSet completed,
+ string? etag,
+ CancellationToken cancellationToken)
+ {
IReadOnlyList pending = plan.GetPendingChunks(completed);
using SemaphoreSlim gate = new(_options.MaxParallelism, _options.MaxParallelism);
+ using SemaphoreSlim ioGate = new(1, 1);
List workers = [];
+ List failedChunks = [];
+ object failedLock = new();
foreach (TransferChunkAssignment chunk in pending)
{
@@ -232,26 +336,25 @@ public async Task DownloadAsync(
await Task.WhenAll(workers).ConfigureAwait(false);
- foreach (TransferChunkAssignment chunk in plan.Chunks.OrderBy(static c => c.Index))
+ if (failedChunks.Count > 0)
{
- destination.Position = chunk.Offset;
- byte[] buffer = new byte[chunk.Length];
- int read = await destination.ReadAsync(buffer.AsMemory(0, chunk.Length), cancellationToken).ConfigureAwait(false);
- if (read > 0)
+ IReadOnlyList repair = plan.GetRepairAssignments(failedChunks);
+ List repairWorkers = [];
+ foreach (TransferChunkAssignment chunk in repair)
{
- verifier.AppendChunk(chunk.Index, buffer.AsSpan(0, read));
+ completed.Remove(chunk.Index);
+ repairWorkers.Add(DownloadChunkAsync(chunk));
}
- }
- FullVerificationResult fullVerification = verifier.VerifyFull(expectedSha256Hex);
- await SaveCheckpointAsync(url, totalSize, etag, lastModified, chunkSize, completed, supportsRanges, cancellationToken).ConfigureAwait(false);
- return new DownloadResult(totalSize, fullVerification.IsValid, resumed, true);
+ await Task.WhenAll(repairWorkers).ConfigureAwait(false);
+ }
async Task DownloadChunkAsync(TransferChunkAssignment chunk)
{
await gate.WaitAsync(cancellationToken).ConfigureAwait(false);
try
{
+ Stopwatch timer = Stopwatch.StartNew();
using HttpRequestMessage request = new(HttpMethod.Get, url);
long end = chunk.Offset + chunk.Length - 1;
request.Headers.Range = new RangeHeaderValue(chunk.Offset, end);
@@ -265,12 +368,28 @@ async Task DownloadChunkAsync(TransferChunkAssignment chunk)
byte[] data = await response.Content.ReadAsByteArrayAsync(cancellationToken).ConfigureAwait(false);
if (data.Length != chunk.Length)
{
- throw new InvalidOperationException($"Chunk {chunk.Index} length mismatch.");
+ lock (failedLock)
+ {
+ failedChunks.Add(chunk.Index);
+ }
+
+ return;
}
- destination.Position = chunk.Offset;
- await destination.WriteAsync(data, cancellationToken).ConfigureAwait(false);
- completed.Add(chunk.Index);
+ await ioGate.WaitAsync(cancellationToken).ConfigureAwait(false);
+ try
+ {
+ destination.Position = chunk.Offset;
+ await destination.WriteAsync(data, cancellationToken).ConfigureAwait(false);
+ completed.Add(chunk.Index);
+ }
+ finally
+ {
+ ioGate.Release();
+ }
+
+ timer.Stop();
+ ObserveChunkThroughput(data.Length, timer.Elapsed);
}
finally
{
@@ -279,6 +398,27 @@ async Task DownloadChunkAsync(TransferChunkAssignment chunk)
}
}
+ private static async Task VerifyDestinationAsync(
+ Stream destination,
+ TransferPlan plan,
+ string expectedSha256Hex,
+ CancellationToken cancellationToken)
+ {
+ using StreamingIntegrityVerifier verifier = new();
+ foreach (TransferChunkAssignment chunk in plan.Chunks.OrderBy(static c => c.Index))
+ {
+ destination.Position = chunk.Offset;
+ byte[] buffer = new byte[chunk.Length];
+ int read = await destination.ReadAsync(buffer.AsMemory(0, chunk.Length), cancellationToken).ConfigureAwait(false);
+ if (read > 0)
+ {
+ verifier.AppendChunk(chunk.Index, buffer.AsSpan(0, read));
+ }
+ }
+
+ return verifier.VerifyFull(expectedSha256Hex);
+ }
+
private async Task DownloadFullAsync(Uri url, CancellationToken cancellationToken)
{
using HttpResponseMessage response = await _httpClient.GetAsync(url, cancellationToken).ConfigureAwait(false);
diff --git a/src/FunctionFoundry.Networking/packages.lock.json b/src/FunctionFoundry.Networking/packages.lock.json
new file mode 100644
index 0000000..04d70a3
--- /dev/null
+++ b/src/FunctionFoundry.Networking/packages.lock.json
@@ -0,0 +1,27 @@
+{
+ "version": 2,
+ "dependencies": {
+ "net10.0": {
+ "Microsoft.SourceLink.GitHub": {
+ "type": "Direct",
+ "requested": "[8.0.0, )",
+ "resolved": "8.0.0",
+ "contentHash": "G5q7OqtwIyGTkeIOAc3u2ZuV/kicQaec5EaRnc0pIeSnh9LUjj+PYQrJYBURvDt7twGl2PKA7nSN0kz1Zw5bnQ==",
+ "dependencies": {
+ "Microsoft.Build.Tasks.Git": "8.0.0",
+ "Microsoft.SourceLink.Common": "8.0.0"
+ }
+ },
+ "Microsoft.Build.Tasks.Git": {
+ "type": "Transitive",
+ "resolved": "8.0.0",
+ "contentHash": "bZKfSIKJRXLTuSzLudMFte/8CempWjVamNUR5eHJizsy+iuOuO/k2gnh7W0dHJmYY0tBf+gUErfluCv5mySAOQ=="
+ },
+ "Microsoft.SourceLink.Common": {
+ "type": "Transitive",
+ "resolved": "8.0.0",
+ "contentHash": "dk9JPxTCIevS75HyEQ0E4OVAFhB2N+V9ShCXf8Q6FkUQZDkgLI12y679Nym1YqsiSysuQskT7Z+6nUf3yab6Vw=="
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/FunctionFoundry.Observability/packages.lock.json b/src/FunctionFoundry.Observability/packages.lock.json
new file mode 100644
index 0000000..04d70a3
--- /dev/null
+++ b/src/FunctionFoundry.Observability/packages.lock.json
@@ -0,0 +1,27 @@
+{
+ "version": 2,
+ "dependencies": {
+ "net10.0": {
+ "Microsoft.SourceLink.GitHub": {
+ "type": "Direct",
+ "requested": "[8.0.0, )",
+ "resolved": "8.0.0",
+ "contentHash": "G5q7OqtwIyGTkeIOAc3u2ZuV/kicQaec5EaRnc0pIeSnh9LUjj+PYQrJYBURvDt7twGl2PKA7nSN0kz1Zw5bnQ==",
+ "dependencies": {
+ "Microsoft.Build.Tasks.Git": "8.0.0",
+ "Microsoft.SourceLink.Common": "8.0.0"
+ }
+ },
+ "Microsoft.Build.Tasks.Git": {
+ "type": "Transitive",
+ "resolved": "8.0.0",
+ "contentHash": "bZKfSIKJRXLTuSzLudMFte/8CempWjVamNUR5eHJizsy+iuOuO/k2gnh7W0dHJmYY0tBf+gUErfluCv5mySAOQ=="
+ },
+ "Microsoft.SourceLink.Common": {
+ "type": "Transitive",
+ "resolved": "8.0.0",
+ "contentHash": "dk9JPxTCIevS75HyEQ0E4OVAFhB2N+V9ShCXf8Q6FkUQZDkgLI12y679Nym1YqsiSysuQskT7Z+6nUf3yab6Vw=="
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/FunctionFoundry.Resilience/packages.lock.json b/src/FunctionFoundry.Resilience/packages.lock.json
new file mode 100644
index 0000000..04d70a3
--- /dev/null
+++ b/src/FunctionFoundry.Resilience/packages.lock.json
@@ -0,0 +1,27 @@
+{
+ "version": 2,
+ "dependencies": {
+ "net10.0": {
+ "Microsoft.SourceLink.GitHub": {
+ "type": "Direct",
+ "requested": "[8.0.0, )",
+ "resolved": "8.0.0",
+ "contentHash": "G5q7OqtwIyGTkeIOAc3u2ZuV/kicQaec5EaRnc0pIeSnh9LUjj+PYQrJYBURvDt7twGl2PKA7nSN0kz1Zw5bnQ==",
+ "dependencies": {
+ "Microsoft.Build.Tasks.Git": "8.0.0",
+ "Microsoft.SourceLink.Common": "8.0.0"
+ }
+ },
+ "Microsoft.Build.Tasks.Git": {
+ "type": "Transitive",
+ "resolved": "8.0.0",
+ "contentHash": "bZKfSIKJRXLTuSzLudMFte/8CempWjVamNUR5eHJizsy+iuOuO/k2gnh7W0dHJmYY0tBf+gUErfluCv5mySAOQ=="
+ },
+ "Microsoft.SourceLink.Common": {
+ "type": "Transitive",
+ "resolved": "8.0.0",
+ "contentHash": "dk9JPxTCIevS75HyEQ0E4OVAFhB2N+V9ShCXf8Q6FkUQZDkgLI12y679Nym1YqsiSysuQskT7Z+6nUf3yab6Vw=="
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/FunctionFoundry.Scheduling/packages.lock.json b/src/FunctionFoundry.Scheduling/packages.lock.json
new file mode 100644
index 0000000..04d70a3
--- /dev/null
+++ b/src/FunctionFoundry.Scheduling/packages.lock.json
@@ -0,0 +1,27 @@
+{
+ "version": 2,
+ "dependencies": {
+ "net10.0": {
+ "Microsoft.SourceLink.GitHub": {
+ "type": "Direct",
+ "requested": "[8.0.0, )",
+ "resolved": "8.0.0",
+ "contentHash": "G5q7OqtwIyGTkeIOAc3u2ZuV/kicQaec5EaRnc0pIeSnh9LUjj+PYQrJYBURvDt7twGl2PKA7nSN0kz1Zw5bnQ==",
+ "dependencies": {
+ "Microsoft.Build.Tasks.Git": "8.0.0",
+ "Microsoft.SourceLink.Common": "8.0.0"
+ }
+ },
+ "Microsoft.Build.Tasks.Git": {
+ "type": "Transitive",
+ "resolved": "8.0.0",
+ "contentHash": "bZKfSIKJRXLTuSzLudMFte/8CempWjVamNUR5eHJizsy+iuOuO/k2gnh7W0dHJmYY0tBf+gUErfluCv5mySAOQ=="
+ },
+ "Microsoft.SourceLink.Common": {
+ "type": "Transitive",
+ "resolved": "8.0.0",
+ "contentHash": "dk9JPxTCIevS75HyEQ0E4OVAFhB2N+V9ShCXf8Q6FkUQZDkgLI12y679Nym1YqsiSysuQskT7Z+6nUf3yab6Vw=="
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/FunctionFoundry.Security/packages.lock.json b/src/FunctionFoundry.Security/packages.lock.json
new file mode 100644
index 0000000..04d70a3
--- /dev/null
+++ b/src/FunctionFoundry.Security/packages.lock.json
@@ -0,0 +1,27 @@
+{
+ "version": 2,
+ "dependencies": {
+ "net10.0": {
+ "Microsoft.SourceLink.GitHub": {
+ "type": "Direct",
+ "requested": "[8.0.0, )",
+ "resolved": "8.0.0",
+ "contentHash": "G5q7OqtwIyGTkeIOAc3u2ZuV/kicQaec5EaRnc0pIeSnh9LUjj+PYQrJYBURvDt7twGl2PKA7nSN0kz1Zw5bnQ==",
+ "dependencies": {
+ "Microsoft.Build.Tasks.Git": "8.0.0",
+ "Microsoft.SourceLink.Common": "8.0.0"
+ }
+ },
+ "Microsoft.Build.Tasks.Git": {
+ "type": "Transitive",
+ "resolved": "8.0.0",
+ "contentHash": "bZKfSIKJRXLTuSzLudMFte/8CempWjVamNUR5eHJizsy+iuOuO/k2gnh7W0dHJmYY0tBf+gUErfluCv5mySAOQ=="
+ },
+ "Microsoft.SourceLink.Common": {
+ "type": "Transitive",
+ "resolved": "8.0.0",
+ "contentHash": "dk9JPxTCIevS75HyEQ0E4OVAFhB2N+V9ShCXf8Q6FkUQZDkgLI12y679Nym1YqsiSysuQskT7Z+6nUf3yab6Vw=="
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/FunctionFoundry.Storage/packages.lock.json b/src/FunctionFoundry.Storage/packages.lock.json
new file mode 100644
index 0000000..04d70a3
--- /dev/null
+++ b/src/FunctionFoundry.Storage/packages.lock.json
@@ -0,0 +1,27 @@
+{
+ "version": 2,
+ "dependencies": {
+ "net10.0": {
+ "Microsoft.SourceLink.GitHub": {
+ "type": "Direct",
+ "requested": "[8.0.0, )",
+ "resolved": "8.0.0",
+ "contentHash": "G5q7OqtwIyGTkeIOAc3u2ZuV/kicQaec5EaRnc0pIeSnh9LUjj+PYQrJYBURvDt7twGl2PKA7nSN0kz1Zw5bnQ==",
+ "dependencies": {
+ "Microsoft.Build.Tasks.Git": "8.0.0",
+ "Microsoft.SourceLink.Common": "8.0.0"
+ }
+ },
+ "Microsoft.Build.Tasks.Git": {
+ "type": "Transitive",
+ "resolved": "8.0.0",
+ "contentHash": "bZKfSIKJRXLTuSzLudMFte/8CempWjVamNUR5eHJizsy+iuOuO/k2gnh7W0dHJmYY0tBf+gUErfluCv5mySAOQ=="
+ },
+ "Microsoft.SourceLink.Common": {
+ "type": "Transitive",
+ "resolved": "8.0.0",
+ "contentHash": "dk9JPxTCIevS75HyEQ0E4OVAFhB2N+V9ShCXf8Q6FkUQZDkgLI12y679Nym1YqsiSysuQskT7Z+6nUf3yab6Vw=="
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/FunctionFoundry.Text/packages.lock.json b/src/FunctionFoundry.Text/packages.lock.json
new file mode 100644
index 0000000..04d70a3
--- /dev/null
+++ b/src/FunctionFoundry.Text/packages.lock.json
@@ -0,0 +1,27 @@
+{
+ "version": 2,
+ "dependencies": {
+ "net10.0": {
+ "Microsoft.SourceLink.GitHub": {
+ "type": "Direct",
+ "requested": "[8.0.0, )",
+ "resolved": "8.0.0",
+ "contentHash": "G5q7OqtwIyGTkeIOAc3u2ZuV/kicQaec5EaRnc0pIeSnh9LUjj+PYQrJYBURvDt7twGl2PKA7nSN0kz1Zw5bnQ==",
+ "dependencies": {
+ "Microsoft.Build.Tasks.Git": "8.0.0",
+ "Microsoft.SourceLink.Common": "8.0.0"
+ }
+ },
+ "Microsoft.Build.Tasks.Git": {
+ "type": "Transitive",
+ "resolved": "8.0.0",
+ "contentHash": "bZKfSIKJRXLTuSzLudMFte/8CempWjVamNUR5eHJizsy+iuOuO/k2gnh7W0dHJmYY0tBf+gUErfluCv5mySAOQ=="
+ },
+ "Microsoft.SourceLink.Common": {
+ "type": "Transitive",
+ "resolved": "8.0.0",
+ "contentHash": "dk9JPxTCIevS75HyEQ0E4OVAFhB2N+V9ShCXf8Q6FkUQZDkgLI12y679Nym1YqsiSysuQskT7Z+6nUf3yab6Vw=="
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/tests/FunctionFoundry.Data.Tests/packages.lock.json b/tests/FunctionFoundry.Data.Tests/packages.lock.json
new file mode 100644
index 0000000..0b0f816
--- /dev/null
+++ b/tests/FunctionFoundry.Data.Tests/packages.lock.json
@@ -0,0 +1,107 @@
+{
+ "version": 2,
+ "dependencies": {
+ "net10.0": {
+ "coverlet.collector": {
+ "type": "Direct",
+ "requested": "[6.0.4, )",
+ "resolved": "6.0.4",
+ "contentHash": "lkhqpF8Pu2Y7IiN7OntbsTtdbpR1syMsm2F3IgX6ootA4ffRqWL5jF7XipHuZQTdVuWG/gVAAcf8mjk8Tz0xPg=="
+ },
+ "Microsoft.NET.Test.Sdk": {
+ "type": "Direct",
+ "requested": "[17.14.1, )",
+ "resolved": "17.14.1",
+ "contentHash": "HJKqKOE+vshXra2aEHpi2TlxYX7Z9VFYkr+E5rwEvHC8eIXiyO+K9kNm8vmNom3e2rA56WqxU+/N9NJlLGXsJQ==",
+ "dependencies": {
+ "Microsoft.CodeCoverage": "17.14.1",
+ "Microsoft.TestPlatform.TestHost": "17.14.1"
+ }
+ },
+ "xunit": {
+ "type": "Direct",
+ "requested": "[2.9.3, )",
+ "resolved": "2.9.3",
+ "contentHash": "TlXQBinK35LpOPKHAqbLY4xlEen9TBafjs0V5KnA4wZsoQLQJiirCR4CbIXvOH8NzkW4YeJKP5P/Bnrodm0h9Q==",
+ "dependencies": {
+ "xunit.analyzers": "1.18.0",
+ "xunit.assert": "2.9.3",
+ "xunit.core": "[2.9.3]"
+ }
+ },
+ "xunit.runner.visualstudio": {
+ "type": "Direct",
+ "requested": "[3.1.4, )",
+ "resolved": "3.1.4",
+ "contentHash": "5mj99LvCqrq3CNi06xYdyIAXOEh+5b33F2nErCzI5zWiDdLHXiPXEWFSUAF8zlIv0ZWqjZNCwHTQeAPYbF3pCg=="
+ },
+ "Microsoft.CodeCoverage": {
+ "type": "Transitive",
+ "resolved": "17.14.1",
+ "contentHash": "pmTrhfFIoplzFVbhVwUquT+77CbGH+h4/3mBpdmIlYtBi9nAB+kKI6dN3A/nV4DFi3wLLx/BlHIPK+MkbQ6Tpg=="
+ },
+ "Microsoft.TestPlatform.ObjectModel": {
+ "type": "Transitive",
+ "resolved": "17.14.1",
+ "contentHash": "xTP1W6Mi6SWmuxd3a+jj9G9UoC850WGwZUps1Wah9r1ZxgXhdJfj1QqDLJkFjHDCvN42qDL2Ps5KjQYWUU0zcQ=="
+ },
+ "Microsoft.TestPlatform.TestHost": {
+ "type": "Transitive",
+ "resolved": "17.14.1",
+ "contentHash": "d78LPzGKkJwsJXAQwsbJJ7LE7D1wB+rAyhHHAaODF+RDSQ0NgMjDFkSA1Djw18VrxO76GlKAjRUhl+H8NL8Z+Q==",
+ "dependencies": {
+ "Microsoft.TestPlatform.ObjectModel": "17.14.1",
+ "Newtonsoft.Json": "13.0.3"
+ }
+ },
+ "Newtonsoft.Json": {
+ "type": "Transitive",
+ "resolved": "13.0.3",
+ "contentHash": "HrC5BXdl00IP9zeV+0Z848QWPAoCr9P3bDEZguI+gkLcBKAOxix/tLEAAHC+UvDNPv4a2d18lOReHMOagPa+zQ=="
+ },
+ "xunit.abstractions": {
+ "type": "Transitive",
+ "resolved": "2.0.3",
+ "contentHash": "pot1I4YOxlWjIb5jmwvvQNbTrZ3lJQ+jUGkGjWE3hEFM0l5gOnBWS+H3qsex68s5cO52g+44vpGzhAt+42vwKg=="
+ },
+ "xunit.analyzers": {
+ "type": "Transitive",
+ "resolved": "1.18.0",
+ "contentHash": "OtFMHN8yqIcYP9wcVIgJrq01AfTxijjAqVDy/WeQVSyrDC1RzBWeQPztL49DN2syXRah8TYnfvk035s7L95EZQ=="
+ },
+ "xunit.assert": {
+ "type": "Transitive",
+ "resolved": "2.9.3",
+ "contentHash": "/Kq28fCE7MjOV42YLVRAJzRF0WmEqsmflm0cfpMjGtzQ2lR5mYVj1/i0Y8uDAOLczkL3/jArrwehfMD0YogMAA=="
+ },
+ "xunit.core": {
+ "type": "Transitive",
+ "resolved": "2.9.3",
+ "contentHash": "BiAEvqGvyme19wE0wTKdADH+NloYqikiU0mcnmiNyXaF9HyHmE6sr/3DC5vnBkgsWaE6yPyWszKSPSApWdRVeQ==",
+ "dependencies": {
+ "xunit.extensibility.core": "[2.9.3]",
+ "xunit.extensibility.execution": "[2.9.3]"
+ }
+ },
+ "xunit.extensibility.core": {
+ "type": "Transitive",
+ "resolved": "2.9.3",
+ "contentHash": "kf3si0YTn2a8J8eZNb+zFpwfoyvIrQ7ivNk5ZYA5yuYk1bEtMe4DxJ2CF/qsRgmEnDr7MnW1mxylBaHTZ4qErA==",
+ "dependencies": {
+ "xunit.abstractions": "2.0.3"
+ }
+ },
+ "xunit.extensibility.execution": {
+ "type": "Transitive",
+ "resolved": "2.9.3",
+ "contentHash": "yMb6vMESlSrE3Wfj7V6cjQ3S4TXdXpRqYeNEI3zsX31uTsGMJjEw6oD5F5u1cHnMptjhEECnmZSsPxB6ChZHDQ==",
+ "dependencies": {
+ "xunit.extensibility.core": "[2.9.3]"
+ }
+ },
+ "functionfoundry.data": {
+ "type": "Project"
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/tests/FunctionFoundry.Distributed.Tests/QuorumAndPhiExtraTests.cs b/tests/FunctionFoundry.Distributed.Tests/QuorumAndPhiExtraTests.cs
new file mode 100644
index 0000000..292f1bc
--- /dev/null
+++ b/tests/FunctionFoundry.Distributed.Tests/QuorumAndPhiExtraTests.cs
@@ -0,0 +1,34 @@
+using FunctionFoundry.Distributed;
+
+namespace FunctionFoundry.Distributed.Tests;
+
+public sealed class QuorumAndPhiExtraTests
+{
+ [Fact]
+ public void Quorum_policy_rejects_invalid_counts()
+ {
+ Assert.Throws(() => new QuorumPolicy(0, 3).Validate());
+ Assert.Throws(() => new QuorumPolicy(2, 0).Validate());
+ Assert.Throws(() => new QuorumPolicy(4, 3).Validate());
+ }
+
+ [Fact]
+ public async Task Quorum_aggregator_rejects_mismatched_task_count()
+ {
+ var aggregator = new QuorumResultAggregator();
+ await Assert.ThrowsAsync(() => aggregator.AggregateAsync(
+ [System.Threading.Tasks.Task.FromResult(1)],
+ new QuorumPolicy(1, 2)));
+ await Assert.ThrowsAsync(() => aggregator.AggregateAsync(null!, new QuorumPolicy(1, 1)));
+ }
+
+ [Fact]
+ public void Phi_detector_snapshot_before_heartbeats_is_warming_up()
+ {
+ var clock = new SimulatedClock(10);
+ var detector = new PhiAccrualFailureDetector(clock);
+ PhiAccrualSnapshot snapshot = detector.GetSnapshot();
+ Assert.True(snapshot.IsWarmingUp);
+ Assert.Equal(0, snapshot.Phi);
+ }
+}
diff --git a/tests/FunctionFoundry.Distributed.Tests/VersionClockExtraTests.cs b/tests/FunctionFoundry.Distributed.Tests/VersionClockExtraTests.cs
new file mode 100644
index 0000000..63c995a
--- /dev/null
+++ b/tests/FunctionFoundry.Distributed.Tests/VersionClockExtraTests.cs
@@ -0,0 +1,88 @@
+using FunctionFoundry.Distributed;
+
+namespace FunctionFoundry.Distributed.Tests;
+
+public sealed class VersionClockExtraTests
+{
+ [Fact]
+ public void VersionClockOptions_rejects_non_positive_max_entries()
+ {
+ Assert.Throws(() => new VersionClockOptions { MaxNodeEntries = 0 }.Validate());
+ Assert.Throws(() => new VectorClock(new VersionClockOptions { MaxNodeEntries = -1 }));
+ }
+
+ [Fact]
+ public void Vector_clock_rejects_blank_node_ids_and_invalid_serialization()
+ {
+ var clock = new VectorClock();
+ Assert.Throws(() => clock.Increment(" "));
+ Assert.Throws(() => new VectorClock([new KeyValuePair("", 1)]));
+ Assert.Throws(() => VectorClock.Deserialize("a"));
+ Assert.Throws(() => VectorClock.Deserialize("a=x"));
+ Assert.Equal(string.Empty, new VectorClock().Serialize());
+ Assert.Equal(VersionClockRelation.Equal, VectorClock.Deserialize(string.Empty).CompareTo(new VectorClock()));
+ }
+
+ [Fact]
+ public void Vector_clock_happens_before_and_equal_paths()
+ {
+ var ancestor = new VectorClock();
+ ancestor.Increment("a");
+ var descendant = new VectorClock(ancestor.Entries);
+ descendant.Increment("a");
+ Assert.Equal(VersionClockRelation.HappensBefore, ancestor.CompareTo(descendant));
+ Assert.Equal(VersionClockRelation.HappensAfter, descendant.CompareTo(ancestor));
+ Assert.Equal(VersionClockRelation.Equal, ancestor.CompareTo(new VectorClock(ancestor.Entries)));
+ }
+
+ [Fact]
+ public void Vector_clock_compact_removes_lowest_counters()
+ {
+ var clock = new VectorClock(new VersionClockOptions { MaxNodeEntries = 3 });
+ clock.Increment("a");
+ clock.Increment("b");
+ clock.Increment("b");
+ clock.Increment("c");
+ clock.Increment("c");
+ clock.Increment("c");
+ int removed = clock.Compact();
+ Assert.Equal(0, removed);
+ clock.Increment("d");
+ Assert.Equal(3, clock.Entries.Count);
+ Assert.False(clock.Entries.ContainsKey("a"));
+ }
+
+ [Fact]
+ public void Dotted_clock_rejects_invalid_serialization_and_compacts()
+ {
+ Assert.Throws(() => DottedVersionClock.Deserialize("bad"));
+ Assert.Throws(() => DottedVersionClock.Deserialize("n=x"));
+ Assert.Throws(() => DottedVersionClock.Deserialize("n=1:z"));
+
+ var clock = new DottedVersionClock(new VersionClockOptions { MaxNodeEntries = 2 });
+ clock.Increment("a");
+ clock.Increment("b");
+ clock.Increment("c");
+ Assert.Equal(2, clock.Entries.Count);
+ Assert.Equal(0, clock.Compact());
+ }
+
+ [Fact]
+ public void Dotted_clock_dominates_false_when_missing_node_or_dot()
+ {
+ var left = new DottedVersionClock();
+ var right = new DottedVersionClock();
+ left.Increment("a");
+ right.Increment("b");
+ Assert.False(left.Dominates(right));
+
+ // Counter advanced without recording the superseded value as a dot.
+ var advanced = DottedVersionClock.Deserialize("a=3");
+ var earlier = DottedVersionClock.Deserialize("a=2");
+ Assert.False(advanced.Dominates(earlier));
+
+ var withDots = DottedVersionClock.Deserialize("a=3:1.2");
+ Assert.True(withDots.Dominates(DottedVersionClock.Deserialize("a=1")));
+ Assert.True(withDots.Dominates(DottedVersionClock.Deserialize("a=2")));
+ }
+}
diff --git a/tests/FunctionFoundry.Distributed.Tests/packages.lock.json b/tests/FunctionFoundry.Distributed.Tests/packages.lock.json
new file mode 100644
index 0000000..8a8c224
--- /dev/null
+++ b/tests/FunctionFoundry.Distributed.Tests/packages.lock.json
@@ -0,0 +1,107 @@
+{
+ "version": 2,
+ "dependencies": {
+ "net10.0": {
+ "coverlet.collector": {
+ "type": "Direct",
+ "requested": "[6.0.4, )",
+ "resolved": "6.0.4",
+ "contentHash": "lkhqpF8Pu2Y7IiN7OntbsTtdbpR1syMsm2F3IgX6ootA4ffRqWL5jF7XipHuZQTdVuWG/gVAAcf8mjk8Tz0xPg=="
+ },
+ "Microsoft.NET.Test.Sdk": {
+ "type": "Direct",
+ "requested": "[17.14.1, )",
+ "resolved": "17.14.1",
+ "contentHash": "HJKqKOE+vshXra2aEHpi2TlxYX7Z9VFYkr+E5rwEvHC8eIXiyO+K9kNm8vmNom3e2rA56WqxU+/N9NJlLGXsJQ==",
+ "dependencies": {
+ "Microsoft.CodeCoverage": "17.14.1",
+ "Microsoft.TestPlatform.TestHost": "17.14.1"
+ }
+ },
+ "xunit": {
+ "type": "Direct",
+ "requested": "[2.9.3, )",
+ "resolved": "2.9.3",
+ "contentHash": "TlXQBinK35LpOPKHAqbLY4xlEen9TBafjs0V5KnA4wZsoQLQJiirCR4CbIXvOH8NzkW4YeJKP5P/Bnrodm0h9Q==",
+ "dependencies": {
+ "xunit.analyzers": "1.18.0",
+ "xunit.assert": "2.9.3",
+ "xunit.core": "[2.9.3]"
+ }
+ },
+ "xunit.runner.visualstudio": {
+ "type": "Direct",
+ "requested": "[3.1.4, )",
+ "resolved": "3.1.4",
+ "contentHash": "5mj99LvCqrq3CNi06xYdyIAXOEh+5b33F2nErCzI5zWiDdLHXiPXEWFSUAF8zlIv0ZWqjZNCwHTQeAPYbF3pCg=="
+ },
+ "Microsoft.CodeCoverage": {
+ "type": "Transitive",
+ "resolved": "17.14.1",
+ "contentHash": "pmTrhfFIoplzFVbhVwUquT+77CbGH+h4/3mBpdmIlYtBi9nAB+kKI6dN3A/nV4DFi3wLLx/BlHIPK+MkbQ6Tpg=="
+ },
+ "Microsoft.TestPlatform.ObjectModel": {
+ "type": "Transitive",
+ "resolved": "17.14.1",
+ "contentHash": "xTP1W6Mi6SWmuxd3a+jj9G9UoC850WGwZUps1Wah9r1ZxgXhdJfj1QqDLJkFjHDCvN42qDL2Ps5KjQYWUU0zcQ=="
+ },
+ "Microsoft.TestPlatform.TestHost": {
+ "type": "Transitive",
+ "resolved": "17.14.1",
+ "contentHash": "d78LPzGKkJwsJXAQwsbJJ7LE7D1wB+rAyhHHAaODF+RDSQ0NgMjDFkSA1Djw18VrxO76GlKAjRUhl+H8NL8Z+Q==",
+ "dependencies": {
+ "Microsoft.TestPlatform.ObjectModel": "17.14.1",
+ "Newtonsoft.Json": "13.0.3"
+ }
+ },
+ "Newtonsoft.Json": {
+ "type": "Transitive",
+ "resolved": "13.0.3",
+ "contentHash": "HrC5BXdl00IP9zeV+0Z848QWPAoCr9P3bDEZguI+gkLcBKAOxix/tLEAAHC+UvDNPv4a2d18lOReHMOagPa+zQ=="
+ },
+ "xunit.abstractions": {
+ "type": "Transitive",
+ "resolved": "2.0.3",
+ "contentHash": "pot1I4YOxlWjIb5jmwvvQNbTrZ3lJQ+jUGkGjWE3hEFM0l5gOnBWS+H3qsex68s5cO52g+44vpGzhAt+42vwKg=="
+ },
+ "xunit.analyzers": {
+ "type": "Transitive",
+ "resolved": "1.18.0",
+ "contentHash": "OtFMHN8yqIcYP9wcVIgJrq01AfTxijjAqVDy/WeQVSyrDC1RzBWeQPztL49DN2syXRah8TYnfvk035s7L95EZQ=="
+ },
+ "xunit.assert": {
+ "type": "Transitive",
+ "resolved": "2.9.3",
+ "contentHash": "/Kq28fCE7MjOV42YLVRAJzRF0WmEqsmflm0cfpMjGtzQ2lR5mYVj1/i0Y8uDAOLczkL3/jArrwehfMD0YogMAA=="
+ },
+ "xunit.core": {
+ "type": "Transitive",
+ "resolved": "2.9.3",
+ "contentHash": "BiAEvqGvyme19wE0wTKdADH+NloYqikiU0mcnmiNyXaF9HyHmE6sr/3DC5vnBkgsWaE6yPyWszKSPSApWdRVeQ==",
+ "dependencies": {
+ "xunit.extensibility.core": "[2.9.3]",
+ "xunit.extensibility.execution": "[2.9.3]"
+ }
+ },
+ "xunit.extensibility.core": {
+ "type": "Transitive",
+ "resolved": "2.9.3",
+ "contentHash": "kf3si0YTn2a8J8eZNb+zFpwfoyvIrQ7ivNk5ZYA5yuYk1bEtMe4DxJ2CF/qsRgmEnDr7MnW1mxylBaHTZ4qErA==",
+ "dependencies": {
+ "xunit.abstractions": "2.0.3"
+ }
+ },
+ "xunit.extensibility.execution": {
+ "type": "Transitive",
+ "resolved": "2.9.3",
+ "contentHash": "yMb6vMESlSrE3Wfj7V6cjQ3S4TXdXpRqYeNEI3zsX31uTsGMJjEw6oD5F5u1cHnMptjhEECnmZSsPxB6ChZHDQ==",
+ "dependencies": {
+ "xunit.extensibility.core": "[2.9.3]"
+ }
+ },
+ "functionfoundry.distributed": {
+ "type": "Project"
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/tests/FunctionFoundry.Engineering.Tests/SdkPinningTests.cs b/tests/FunctionFoundry.Engineering.Tests/SdkPinningTests.cs
index 848b9e4..61a7774 100644
--- a/tests/FunctionFoundry.Engineering.Tests/SdkPinningTests.cs
+++ b/tests/FunctionFoundry.Engineering.Tests/SdkPinningTests.cs
@@ -10,7 +10,7 @@ public void GlobalJson_pins_exact_sdk_without_roll_forward()
string path = FindRepoFile("global.json");
using JsonDocument document = JsonDocument.Parse(File.ReadAllText(path));
JsonElement sdk = document.RootElement.GetProperty("sdk");
- Assert.Equal("10.0.301", sdk.GetProperty("version").GetString());
+ Assert.Equal("10.0.302", sdk.GetProperty("version").GetString());
Assert.Equal("disable", sdk.GetProperty("rollForward").GetString());
Assert.False(sdk.GetProperty("allowPrerelease").GetBoolean());
}
diff --git a/tests/FunctionFoundry.Engineering.Tests/packages.lock.json b/tests/FunctionFoundry.Engineering.Tests/packages.lock.json
new file mode 100644
index 0000000..16cb228
--- /dev/null
+++ b/tests/FunctionFoundry.Engineering.Tests/packages.lock.json
@@ -0,0 +1,104 @@
+{
+ "version": 2,
+ "dependencies": {
+ "net10.0": {
+ "coverlet.collector": {
+ "type": "Direct",
+ "requested": "[6.0.4, )",
+ "resolved": "6.0.4",
+ "contentHash": "lkhqpF8Pu2Y7IiN7OntbsTtdbpR1syMsm2F3IgX6ootA4ffRqWL5jF7XipHuZQTdVuWG/gVAAcf8mjk8Tz0xPg=="
+ },
+ "Microsoft.NET.Test.Sdk": {
+ "type": "Direct",
+ "requested": "[17.14.1, )",
+ "resolved": "17.14.1",
+ "contentHash": "HJKqKOE+vshXra2aEHpi2TlxYX7Z9VFYkr+E5rwEvHC8eIXiyO+K9kNm8vmNom3e2rA56WqxU+/N9NJlLGXsJQ==",
+ "dependencies": {
+ "Microsoft.CodeCoverage": "17.14.1",
+ "Microsoft.TestPlatform.TestHost": "17.14.1"
+ }
+ },
+ "xunit": {
+ "type": "Direct",
+ "requested": "[2.9.3, )",
+ "resolved": "2.9.3",
+ "contentHash": "TlXQBinK35LpOPKHAqbLY4xlEen9TBafjs0V5KnA4wZsoQLQJiirCR4CbIXvOH8NzkW4YeJKP5P/Bnrodm0h9Q==",
+ "dependencies": {
+ "xunit.analyzers": "1.18.0",
+ "xunit.assert": "2.9.3",
+ "xunit.core": "[2.9.3]"
+ }
+ },
+ "xunit.runner.visualstudio": {
+ "type": "Direct",
+ "requested": "[3.1.4, )",
+ "resolved": "3.1.4",
+ "contentHash": "5mj99LvCqrq3CNi06xYdyIAXOEh+5b33F2nErCzI5zWiDdLHXiPXEWFSUAF8zlIv0ZWqjZNCwHTQeAPYbF3pCg=="
+ },
+ "Microsoft.CodeCoverage": {
+ "type": "Transitive",
+ "resolved": "17.14.1",
+ "contentHash": "pmTrhfFIoplzFVbhVwUquT+77CbGH+h4/3mBpdmIlYtBi9nAB+kKI6dN3A/nV4DFi3wLLx/BlHIPK+MkbQ6Tpg=="
+ },
+ "Microsoft.TestPlatform.ObjectModel": {
+ "type": "Transitive",
+ "resolved": "17.14.1",
+ "contentHash": "xTP1W6Mi6SWmuxd3a+jj9G9UoC850WGwZUps1Wah9r1ZxgXhdJfj1QqDLJkFjHDCvN42qDL2Ps5KjQYWUU0zcQ=="
+ },
+ "Microsoft.TestPlatform.TestHost": {
+ "type": "Transitive",
+ "resolved": "17.14.1",
+ "contentHash": "d78LPzGKkJwsJXAQwsbJJ7LE7D1wB+rAyhHHAaODF+RDSQ0NgMjDFkSA1Djw18VrxO76GlKAjRUhl+H8NL8Z+Q==",
+ "dependencies": {
+ "Microsoft.TestPlatform.ObjectModel": "17.14.1",
+ "Newtonsoft.Json": "13.0.3"
+ }
+ },
+ "Newtonsoft.Json": {
+ "type": "Transitive",
+ "resolved": "13.0.3",
+ "contentHash": "HrC5BXdl00IP9zeV+0Z848QWPAoCr9P3bDEZguI+gkLcBKAOxix/tLEAAHC+UvDNPv4a2d18lOReHMOagPa+zQ=="
+ },
+ "xunit.abstractions": {
+ "type": "Transitive",
+ "resolved": "2.0.3",
+ "contentHash": "pot1I4YOxlWjIb5jmwvvQNbTrZ3lJQ+jUGkGjWE3hEFM0l5gOnBWS+H3qsex68s5cO52g+44vpGzhAt+42vwKg=="
+ },
+ "xunit.analyzers": {
+ "type": "Transitive",
+ "resolved": "1.18.0",
+ "contentHash": "OtFMHN8yqIcYP9wcVIgJrq01AfTxijjAqVDy/WeQVSyrDC1RzBWeQPztL49DN2syXRah8TYnfvk035s7L95EZQ=="
+ },
+ "xunit.assert": {
+ "type": "Transitive",
+ "resolved": "2.9.3",
+ "contentHash": "/Kq28fCE7MjOV42YLVRAJzRF0WmEqsmflm0cfpMjGtzQ2lR5mYVj1/i0Y8uDAOLczkL3/jArrwehfMD0YogMAA=="
+ },
+ "xunit.core": {
+ "type": "Transitive",
+ "resolved": "2.9.3",
+ "contentHash": "BiAEvqGvyme19wE0wTKdADH+NloYqikiU0mcnmiNyXaF9HyHmE6sr/3DC5vnBkgsWaE6yPyWszKSPSApWdRVeQ==",
+ "dependencies": {
+ "xunit.extensibility.core": "[2.9.3]",
+ "xunit.extensibility.execution": "[2.9.3]"
+ }
+ },
+ "xunit.extensibility.core": {
+ "type": "Transitive",
+ "resolved": "2.9.3",
+ "contentHash": "kf3si0YTn2a8J8eZNb+zFpwfoyvIrQ7ivNk5ZYA5yuYk1bEtMe4DxJ2CF/qsRgmEnDr7MnW1mxylBaHTZ4qErA==",
+ "dependencies": {
+ "xunit.abstractions": "2.0.3"
+ }
+ },
+ "xunit.extensibility.execution": {
+ "type": "Transitive",
+ "resolved": "2.9.3",
+ "contentHash": "yMb6vMESlSrE3Wfj7V6cjQ3S4TXdXpRqYeNEI3zsX31uTsGMJjEw6oD5F5u1cHnMptjhEECnmZSsPxB6ChZHDQ==",
+ "dependencies": {
+ "xunit.extensibility.core": "[2.9.3]"
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/tests/FunctionFoundry.Integrity.Tests/IntegrityExtraBranchTests.cs b/tests/FunctionFoundry.Integrity.Tests/IntegrityExtraBranchTests.cs
new file mode 100644
index 0000000..e31d438
--- /dev/null
+++ b/tests/FunctionFoundry.Integrity.Tests/IntegrityExtraBranchTests.cs
@@ -0,0 +1,77 @@
+using System.Text;
+using FunctionFoundry.Integrity;
+
+namespace FunctionFoundry.Integrity.Tests;
+
+public sealed class IntegrityExtraBranchTests
+{
+ [Fact]
+ public void CanonicalJson_rejects_empty_input_and_invalid_buffer_size()
+ {
+ Assert.Throws(() => CanonicalJson.Canonicalize(ReadOnlySpan.Empty));
+ Assert.Throws(() => CanonicalJson.Canonicalize(string.Empty));
+ using var input = new MemoryStream("{}"u8.ToArray());
+ using var output = new MemoryStream();
+ Assert.Throws(() => CanonicalJson.Canonicalize(input, output, bufferSize: 0));
+ }
+
+ [Fact]
+ public void CanonicalJson_TryCanonicalize_succeeds_for_valid_json()
+ {
+ bool ok = CanonicalJson.TryCanonicalize("{\"b\":1,\"a\":2}"u8, out byte[]? canonical, out string? error);
+ Assert.True(ok);
+ Assert.Null(error);
+ Assert.Equal("{\"a\":2,\"b\":1}", Encoding.UTF8.GetString(canonical!));
+ }
+
+ [Fact]
+ public void CanonicalJson_nested_objects_and_arrays_sort_recursively()
+ {
+ const string Input = "{\"z\":[{\"b\":1,\"a\":2},true],\"a\":{\"y\":null,\"x\":false}}";
+ string actual = Encoding.UTF8.GetString(CanonicalJson.Canonicalize(Input));
+ Assert.Equal("{\"a\":{\"x\":false,\"y\":null},\"z\":[{\"a\":2,\"b\":1},true]}", actual);
+ }
+
+ [Fact]
+ public void MerkleTree_rejects_empty_leaves_and_verifies_all_indices()
+ {
+ Assert.Throws(() => MerkleTree.Build(Array.Empty()));
+ byte[][] leaves = ["a"u8.ToArray(), "b"u8.ToArray(), "c"u8.ToArray(), "d"u8.ToArray()];
+ MerkleTree tree = MerkleTree.Build(leaves);
+ for (int i = 0; i < leaves.Length; i++)
+ {
+ MerkleProof proof = tree.CreateProof(i);
+ MerkleProofVerificationResult result = MerkleTree.VerifyProof(tree.Root.Span, leaves[i], proof);
+ Assert.True(result.IsValid);
+ }
+ }
+
+ [Fact]
+ public void HashChain_rejects_null_records_and_detects_sequence_gaps()
+ {
+ Assert.Throws(() => HashChain.Verify(null!));
+ HashChainRecord genesis = HashChain.CreateGenesis("g"u8);
+ HashChainRecord second = HashChain.Append(genesis, "ok"u8);
+ var gapped = second with { Sequence = 5 };
+ HashChainVerificationResult result = HashChain.Verify([genesis, gapped]);
+ Assert.False(result.IsValid);
+ Assert.NotNull(result.FirstInvalidRecord);
+ }
+
+ [Fact]
+ public void StreamingHashManifest_rejects_null_content_and_verifies_valid_set()
+ {
+ var builder = StreamingHashManifest.CreateBuilder();
+ Stream? content = null;
+ Assert.Throws(() => builder.AddEntry("x.txt", content!));
+ builder.AddEntry("x.txt", new MemoryStream("payload"u8.ToArray()), includeSize: true);
+ StreamingHashManifestDocument manifest = StreamingHashManifest.Parse(builder.Build());
+ ManifestVerificationResult ok = StreamingHashManifest.Verify(
+ manifest,
+ new Dictionary { ["x.txt"] = new MemoryStream("payload"u8.ToArray()) });
+ Assert.True(ok.IsValid);
+ Assert.Empty(ok.MissingPaths);
+ Assert.Empty(ok.UnexpectedPaths);
+ Assert.Empty(ok.HashMismatches);
+ }
+}
diff --git a/tests/FunctionFoundry.Integrity.Tests/packages.lock.json b/tests/FunctionFoundry.Integrity.Tests/packages.lock.json
new file mode 100644
index 0000000..d5e9225
--- /dev/null
+++ b/tests/FunctionFoundry.Integrity.Tests/packages.lock.json
@@ -0,0 +1,107 @@
+{
+ "version": 2,
+ "dependencies": {
+ "net10.0": {
+ "coverlet.collector": {
+ "type": "Direct",
+ "requested": "[6.0.4, )",
+ "resolved": "6.0.4",
+ "contentHash": "lkhqpF8Pu2Y7IiN7OntbsTtdbpR1syMsm2F3IgX6ootA4ffRqWL5jF7XipHuZQTdVuWG/gVAAcf8mjk8Tz0xPg=="
+ },
+ "Microsoft.NET.Test.Sdk": {
+ "type": "Direct",
+ "requested": "[17.14.1, )",
+ "resolved": "17.14.1",
+ "contentHash": "HJKqKOE+vshXra2aEHpi2TlxYX7Z9VFYkr+E5rwEvHC8eIXiyO+K9kNm8vmNom3e2rA56WqxU+/N9NJlLGXsJQ==",
+ "dependencies": {
+ "Microsoft.CodeCoverage": "17.14.1",
+ "Microsoft.TestPlatform.TestHost": "17.14.1"
+ }
+ },
+ "xunit": {
+ "type": "Direct",
+ "requested": "[2.9.3, )",
+ "resolved": "2.9.3",
+ "contentHash": "TlXQBinK35LpOPKHAqbLY4xlEen9TBafjs0V5KnA4wZsoQLQJiirCR4CbIXvOH8NzkW4YeJKP5P/Bnrodm0h9Q==",
+ "dependencies": {
+ "xunit.analyzers": "1.18.0",
+ "xunit.assert": "2.9.3",
+ "xunit.core": "[2.9.3]"
+ }
+ },
+ "xunit.runner.visualstudio": {
+ "type": "Direct",
+ "requested": "[3.1.4, )",
+ "resolved": "3.1.4",
+ "contentHash": "5mj99LvCqrq3CNi06xYdyIAXOEh+5b33F2nErCzI5zWiDdLHXiPXEWFSUAF8zlIv0ZWqjZNCwHTQeAPYbF3pCg=="
+ },
+ "Microsoft.CodeCoverage": {
+ "type": "Transitive",
+ "resolved": "17.14.1",
+ "contentHash": "pmTrhfFIoplzFVbhVwUquT+77CbGH+h4/3mBpdmIlYtBi9nAB+kKI6dN3A/nV4DFi3wLLx/BlHIPK+MkbQ6Tpg=="
+ },
+ "Microsoft.TestPlatform.ObjectModel": {
+ "type": "Transitive",
+ "resolved": "17.14.1",
+ "contentHash": "xTP1W6Mi6SWmuxd3a+jj9G9UoC850WGwZUps1Wah9r1ZxgXhdJfj1QqDLJkFjHDCvN42qDL2Ps5KjQYWUU0zcQ=="
+ },
+ "Microsoft.TestPlatform.TestHost": {
+ "type": "Transitive",
+ "resolved": "17.14.1",
+ "contentHash": "d78LPzGKkJwsJXAQwsbJJ7LE7D1wB+rAyhHHAaODF+RDSQ0NgMjDFkSA1Djw18VrxO76GlKAjRUhl+H8NL8Z+Q==",
+ "dependencies": {
+ "Microsoft.TestPlatform.ObjectModel": "17.14.1",
+ "Newtonsoft.Json": "13.0.3"
+ }
+ },
+ "Newtonsoft.Json": {
+ "type": "Transitive",
+ "resolved": "13.0.3",
+ "contentHash": "HrC5BXdl00IP9zeV+0Z848QWPAoCr9P3bDEZguI+gkLcBKAOxix/tLEAAHC+UvDNPv4a2d18lOReHMOagPa+zQ=="
+ },
+ "xunit.abstractions": {
+ "type": "Transitive",
+ "resolved": "2.0.3",
+ "contentHash": "pot1I4YOxlWjIb5jmwvvQNbTrZ3lJQ+jUGkGjWE3hEFM0l5gOnBWS+H3qsex68s5cO52g+44vpGzhAt+42vwKg=="
+ },
+ "xunit.analyzers": {
+ "type": "Transitive",
+ "resolved": "1.18.0",
+ "contentHash": "OtFMHN8yqIcYP9wcVIgJrq01AfTxijjAqVDy/WeQVSyrDC1RzBWeQPztL49DN2syXRah8TYnfvk035s7L95EZQ=="
+ },
+ "xunit.assert": {
+ "type": "Transitive",
+ "resolved": "2.9.3",
+ "contentHash": "/Kq28fCE7MjOV42YLVRAJzRF0WmEqsmflm0cfpMjGtzQ2lR5mYVj1/i0Y8uDAOLczkL3/jArrwehfMD0YogMAA=="
+ },
+ "xunit.core": {
+ "type": "Transitive",
+ "resolved": "2.9.3",
+ "contentHash": "BiAEvqGvyme19wE0wTKdADH+NloYqikiU0mcnmiNyXaF9HyHmE6sr/3DC5vnBkgsWaE6yPyWszKSPSApWdRVeQ==",
+ "dependencies": {
+ "xunit.extensibility.core": "[2.9.3]",
+ "xunit.extensibility.execution": "[2.9.3]"
+ }
+ },
+ "xunit.extensibility.core": {
+ "type": "Transitive",
+ "resolved": "2.9.3",
+ "contentHash": "kf3si0YTn2a8J8eZNb+zFpwfoyvIrQ7ivNk5ZYA5yuYk1bEtMe4DxJ2CF/qsRgmEnDr7MnW1mxylBaHTZ4qErA==",
+ "dependencies": {
+ "xunit.abstractions": "2.0.3"
+ }
+ },
+ "xunit.extensibility.execution": {
+ "type": "Transitive",
+ "resolved": "2.9.3",
+ "contentHash": "yMb6vMESlSrE3Wfj7V6cjQ3S4TXdXpRqYeNEI3zsX31uTsGMJjEw6oD5F5u1cHnMptjhEECnmZSsPxB6ChZHDQ==",
+ "dependencies": {
+ "xunit.extensibility.core": "[2.9.3]"
+ }
+ },
+ "functionfoundry.integrity": {
+ "type": "Project"
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/tests/FunctionFoundry.Networking.Tests/ResumableParallelDownloaderTests.cs b/tests/FunctionFoundry.Networking.Tests/ResumableParallelDownloaderTests.cs
index d61e4bb..db59ed3 100644
--- a/tests/FunctionFoundry.Networking.Tests/ResumableParallelDownloaderTests.cs
+++ b/tests/FunctionFoundry.Networking.Tests/ResumableParallelDownloaderTests.cs
@@ -114,6 +114,55 @@ public async Task Falls_back_to_full_download_when_ranges_unsupported()
Assert.False(result.UsedRangeRequests);
}
+ [Fact]
+ public async Task Adaptive_chunk_size_stays_within_bounds_after_download()
+ {
+ const string content = "abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
+ byte[] payload = Encoding.UTF8.GetBytes(content);
+ string hash = Hashing.Sha256Hex(payload);
+ using var handler = new FakeDownloadHandler(content);
+ using var client = new HttpClient(handler);
+ var options = new ResumableParallelDownloaderOptions
+ {
+ InitialChunkSizeBytes = 16,
+ MinChunkSizeBytes = 8,
+ MaxChunkSizeBytes = 32,
+ MaxParallelism = 2,
+ EnableAdaptiveChunkSizing = true,
+ };
+ var downloader = new ResumableParallelDownloader(client, new InMemoryDownloadCheckpointStore(), options);
+ await using MemoryStream destination = new();
+ DownloadResult result = await downloader.DownloadAsync(new Uri("https://example.test/adaptive"), destination, hash);
+ Assert.True(result.Verified);
+ Assert.InRange(downloader.AdaptiveChunkSizeBytes, options.MinChunkSizeBytes, options.MaxChunkSizeBytes);
+ }
+
+ [Fact]
+ public async Task Corrupt_chunk_length_is_repaired()
+ {
+ const string content = "0123456789abcdef";
+ byte[] payload = Encoding.UTF8.GetBytes(content);
+ string hash = Hashing.Sha256Hex(payload);
+ using var handler = new FlakyLengthHandler(payload, corruptOnceChunkIndex: 1);
+ using var client = new HttpClient(handler);
+ var downloader = new ResumableParallelDownloader(
+ client,
+ new InMemoryDownloadCheckpointStore(),
+ new ResumableParallelDownloaderOptions
+ {
+ InitialChunkSizeBytes = 4,
+ MinChunkSizeBytes = 4,
+ MaxChunkSizeBytes = 8,
+ MaxParallelism = 1,
+ MaxRepairPasses = 1,
+ });
+
+ await using MemoryStream destination = new();
+ DownloadResult result = await downloader.DownloadAsync(new Uri("https://example.test/repair"), destination, hash);
+ Assert.True(result.Verified);
+ Assert.True(handler.CorruptResponses > 0);
+ }
+
private sealed class FullOnlyHandler : HttpMessageHandler
{
private readonly byte[] _payload;
@@ -130,4 +179,52 @@ protected override Task SendAsync(HttpRequestMessage reques
return Task.FromResult(response);
}
}
+
+ private sealed class FlakyLengthHandler : HttpMessageHandler
+ {
+ private readonly byte[] _payload;
+ private readonly int _corruptOnceChunkIndex;
+ private int _rangeCalls;
+
+ public FlakyLengthHandler(byte[] payload, int corruptOnceChunkIndex)
+ {
+ _payload = payload;
+ _corruptOnceChunkIndex = corruptOnceChunkIndex;
+ }
+
+ public int CorruptResponses { get; private set; }
+
+ protected override Task SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
+ {
+ if (request.Headers.Range is RangeHeaderValue range && range.Ranges.Count > 0)
+ {
+ RangeItemHeaderValue item = range.Ranges.First();
+ long from = item.From ?? 0;
+ long to = item.To ?? (_payload.Length - 1);
+ int length = (int)(to - from + 1);
+ int call = Interlocked.Increment(ref _rangeCalls) - 1;
+ byte[] slice = _payload.AsSpan((int)from, length).ToArray();
+ if (call == _corruptOnceChunkIndex)
+ {
+ CorruptResponses++;
+ slice = slice.AsSpan(0, Math.Max(1, slice.Length - 1)).ToArray();
+ }
+
+ var response = new HttpResponseMessage(HttpStatusCode.PartialContent)
+ {
+ Content = new ByteArrayContent(slice),
+ };
+ response.Content.Headers.ContentRange = new ContentRangeHeaderValue(from, to, _payload.Length);
+ response.Headers.ETag = new EntityTagHeaderValue("\"v1\"");
+ return Task.FromResult(response);
+ }
+
+ var full = new HttpResponseMessage(HttpStatusCode.OK)
+ {
+ Content = new ByteArrayContent(_payload),
+ };
+ full.Content.Headers.ContentLength = _payload.Length;
+ return Task.FromResult(full);
+ }
+ }
}
diff --git a/tests/FunctionFoundry.Networking.Tests/packages.lock.json b/tests/FunctionFoundry.Networking.Tests/packages.lock.json
new file mode 100644
index 0000000..f326913
--- /dev/null
+++ b/tests/FunctionFoundry.Networking.Tests/packages.lock.json
@@ -0,0 +1,107 @@
+{
+ "version": 2,
+ "dependencies": {
+ "net10.0": {
+ "coverlet.collector": {
+ "type": "Direct",
+ "requested": "[6.0.4, )",
+ "resolved": "6.0.4",
+ "contentHash": "lkhqpF8Pu2Y7IiN7OntbsTtdbpR1syMsm2F3IgX6ootA4ffRqWL5jF7XipHuZQTdVuWG/gVAAcf8mjk8Tz0xPg=="
+ },
+ "Microsoft.NET.Test.Sdk": {
+ "type": "Direct",
+ "requested": "[17.14.1, )",
+ "resolved": "17.14.1",
+ "contentHash": "HJKqKOE+vshXra2aEHpi2TlxYX7Z9VFYkr+E5rwEvHC8eIXiyO+K9kNm8vmNom3e2rA56WqxU+/N9NJlLGXsJQ==",
+ "dependencies": {
+ "Microsoft.CodeCoverage": "17.14.1",
+ "Microsoft.TestPlatform.TestHost": "17.14.1"
+ }
+ },
+ "xunit": {
+ "type": "Direct",
+ "requested": "[2.9.3, )",
+ "resolved": "2.9.3",
+ "contentHash": "TlXQBinK35LpOPKHAqbLY4xlEen9TBafjs0V5KnA4wZsoQLQJiirCR4CbIXvOH8NzkW4YeJKP5P/Bnrodm0h9Q==",
+ "dependencies": {
+ "xunit.analyzers": "1.18.0",
+ "xunit.assert": "2.9.3",
+ "xunit.core": "[2.9.3]"
+ }
+ },
+ "xunit.runner.visualstudio": {
+ "type": "Direct",
+ "requested": "[3.1.4, )",
+ "resolved": "3.1.4",
+ "contentHash": "5mj99LvCqrq3CNi06xYdyIAXOEh+5b33F2nErCzI5zWiDdLHXiPXEWFSUAF8zlIv0ZWqjZNCwHTQeAPYbF3pCg=="
+ },
+ "Microsoft.CodeCoverage": {
+ "type": "Transitive",
+ "resolved": "17.14.1",
+ "contentHash": "pmTrhfFIoplzFVbhVwUquT+77CbGH+h4/3mBpdmIlYtBi9nAB+kKI6dN3A/nV4DFi3wLLx/BlHIPK+MkbQ6Tpg=="
+ },
+ "Microsoft.TestPlatform.ObjectModel": {
+ "type": "Transitive",
+ "resolved": "17.14.1",
+ "contentHash": "xTP1W6Mi6SWmuxd3a+jj9G9UoC850WGwZUps1Wah9r1ZxgXhdJfj1QqDLJkFjHDCvN42qDL2Ps5KjQYWUU0zcQ=="
+ },
+ "Microsoft.TestPlatform.TestHost": {
+ "type": "Transitive",
+ "resolved": "17.14.1",
+ "contentHash": "d78LPzGKkJwsJXAQwsbJJ7LE7D1wB+rAyhHHAaODF+RDSQ0NgMjDFkSA1Djw18VrxO76GlKAjRUhl+H8NL8Z+Q==",
+ "dependencies": {
+ "Microsoft.TestPlatform.ObjectModel": "17.14.1",
+ "Newtonsoft.Json": "13.0.3"
+ }
+ },
+ "Newtonsoft.Json": {
+ "type": "Transitive",
+ "resolved": "13.0.3",
+ "contentHash": "HrC5BXdl00IP9zeV+0Z848QWPAoCr9P3bDEZguI+gkLcBKAOxix/tLEAAHC+UvDNPv4a2d18lOReHMOagPa+zQ=="
+ },
+ "xunit.abstractions": {
+ "type": "Transitive",
+ "resolved": "2.0.3",
+ "contentHash": "pot1I4YOxlWjIb5jmwvvQNbTrZ3lJQ+jUGkGjWE3hEFM0l5gOnBWS+H3qsex68s5cO52g+44vpGzhAt+42vwKg=="
+ },
+ "xunit.analyzers": {
+ "type": "Transitive",
+ "resolved": "1.18.0",
+ "contentHash": "OtFMHN8yqIcYP9wcVIgJrq01AfTxijjAqVDy/WeQVSyrDC1RzBWeQPztL49DN2syXRah8TYnfvk035s7L95EZQ=="
+ },
+ "xunit.assert": {
+ "type": "Transitive",
+ "resolved": "2.9.3",
+ "contentHash": "/Kq28fCE7MjOV42YLVRAJzRF0WmEqsmflm0cfpMjGtzQ2lR5mYVj1/i0Y8uDAOLczkL3/jArrwehfMD0YogMAA=="
+ },
+ "xunit.core": {
+ "type": "Transitive",
+ "resolved": "2.9.3",
+ "contentHash": "BiAEvqGvyme19wE0wTKdADH+NloYqikiU0mcnmiNyXaF9HyHmE6sr/3DC5vnBkgsWaE6yPyWszKSPSApWdRVeQ==",
+ "dependencies": {
+ "xunit.extensibility.core": "[2.9.3]",
+ "xunit.extensibility.execution": "[2.9.3]"
+ }
+ },
+ "xunit.extensibility.core": {
+ "type": "Transitive",
+ "resolved": "2.9.3",
+ "contentHash": "kf3si0YTn2a8J8eZNb+zFpwfoyvIrQ7ivNk5ZYA5yuYk1bEtMe4DxJ2CF/qsRgmEnDr7MnW1mxylBaHTZ4qErA==",
+ "dependencies": {
+ "xunit.abstractions": "2.0.3"
+ }
+ },
+ "xunit.extensibility.execution": {
+ "type": "Transitive",
+ "resolved": "2.9.3",
+ "contentHash": "yMb6vMESlSrE3Wfj7V6cjQ3S4TXdXpRqYeNEI3zsX31uTsGMJjEw6oD5F5u1cHnMptjhEECnmZSsPxB6ChZHDQ==",
+ "dependencies": {
+ "xunit.extensibility.core": "[2.9.3]"
+ }
+ },
+ "functionfoundry.networking": {
+ "type": "Project"
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/tests/FunctionFoundry.Observability.Tests/packages.lock.json b/tests/FunctionFoundry.Observability.Tests/packages.lock.json
new file mode 100644
index 0000000..a31f6e3
--- /dev/null
+++ b/tests/FunctionFoundry.Observability.Tests/packages.lock.json
@@ -0,0 +1,107 @@
+{
+ "version": 2,
+ "dependencies": {
+ "net10.0": {
+ "coverlet.collector": {
+ "type": "Direct",
+ "requested": "[6.0.4, )",
+ "resolved": "6.0.4",
+ "contentHash": "lkhqpF8Pu2Y7IiN7OntbsTtdbpR1syMsm2F3IgX6ootA4ffRqWL5jF7XipHuZQTdVuWG/gVAAcf8mjk8Tz0xPg=="
+ },
+ "Microsoft.NET.Test.Sdk": {
+ "type": "Direct",
+ "requested": "[17.14.1, )",
+ "resolved": "17.14.1",
+ "contentHash": "HJKqKOE+vshXra2aEHpi2TlxYX7Z9VFYkr+E5rwEvHC8eIXiyO+K9kNm8vmNom3e2rA56WqxU+/N9NJlLGXsJQ==",
+ "dependencies": {
+ "Microsoft.CodeCoverage": "17.14.1",
+ "Microsoft.TestPlatform.TestHost": "17.14.1"
+ }
+ },
+ "xunit": {
+ "type": "Direct",
+ "requested": "[2.9.3, )",
+ "resolved": "2.9.3",
+ "contentHash": "TlXQBinK35LpOPKHAqbLY4xlEen9TBafjs0V5KnA4wZsoQLQJiirCR4CbIXvOH8NzkW4YeJKP5P/Bnrodm0h9Q==",
+ "dependencies": {
+ "xunit.analyzers": "1.18.0",
+ "xunit.assert": "2.9.3",
+ "xunit.core": "[2.9.3]"
+ }
+ },
+ "xunit.runner.visualstudio": {
+ "type": "Direct",
+ "requested": "[3.1.4, )",
+ "resolved": "3.1.4",
+ "contentHash": "5mj99LvCqrq3CNi06xYdyIAXOEh+5b33F2nErCzI5zWiDdLHXiPXEWFSUAF8zlIv0ZWqjZNCwHTQeAPYbF3pCg=="
+ },
+ "Microsoft.CodeCoverage": {
+ "type": "Transitive",
+ "resolved": "17.14.1",
+ "contentHash": "pmTrhfFIoplzFVbhVwUquT+77CbGH+h4/3mBpdmIlYtBi9nAB+kKI6dN3A/nV4DFi3wLLx/BlHIPK+MkbQ6Tpg=="
+ },
+ "Microsoft.TestPlatform.ObjectModel": {
+ "type": "Transitive",
+ "resolved": "17.14.1",
+ "contentHash": "xTP1W6Mi6SWmuxd3a+jj9G9UoC850WGwZUps1Wah9r1ZxgXhdJfj1QqDLJkFjHDCvN42qDL2Ps5KjQYWUU0zcQ=="
+ },
+ "Microsoft.TestPlatform.TestHost": {
+ "type": "Transitive",
+ "resolved": "17.14.1",
+ "contentHash": "d78LPzGKkJwsJXAQwsbJJ7LE7D1wB+rAyhHHAaODF+RDSQ0NgMjDFkSA1Djw18VrxO76GlKAjRUhl+H8NL8Z+Q==",
+ "dependencies": {
+ "Microsoft.TestPlatform.ObjectModel": "17.14.1",
+ "Newtonsoft.Json": "13.0.3"
+ }
+ },
+ "Newtonsoft.Json": {
+ "type": "Transitive",
+ "resolved": "13.0.3",
+ "contentHash": "HrC5BXdl00IP9zeV+0Z848QWPAoCr9P3bDEZguI+gkLcBKAOxix/tLEAAHC+UvDNPv4a2d18lOReHMOagPa+zQ=="
+ },
+ "xunit.abstractions": {
+ "type": "Transitive",
+ "resolved": "2.0.3",
+ "contentHash": "pot1I4YOxlWjIb5jmwvvQNbTrZ3lJQ+jUGkGjWE3hEFM0l5gOnBWS+H3qsex68s5cO52g+44vpGzhAt+42vwKg=="
+ },
+ "xunit.analyzers": {
+ "type": "Transitive",
+ "resolved": "1.18.0",
+ "contentHash": "OtFMHN8yqIcYP9wcVIgJrq01AfTxijjAqVDy/WeQVSyrDC1RzBWeQPztL49DN2syXRah8TYnfvk035s7L95EZQ=="
+ },
+ "xunit.assert": {
+ "type": "Transitive",
+ "resolved": "2.9.3",
+ "contentHash": "/Kq28fCE7MjOV42YLVRAJzRF0WmEqsmflm0cfpMjGtzQ2lR5mYVj1/i0Y8uDAOLczkL3/jArrwehfMD0YogMAA=="
+ },
+ "xunit.core": {
+ "type": "Transitive",
+ "resolved": "2.9.3",
+ "contentHash": "BiAEvqGvyme19wE0wTKdADH+NloYqikiU0mcnmiNyXaF9HyHmE6sr/3DC5vnBkgsWaE6yPyWszKSPSApWdRVeQ==",
+ "dependencies": {
+ "xunit.extensibility.core": "[2.9.3]",
+ "xunit.extensibility.execution": "[2.9.3]"
+ }
+ },
+ "xunit.extensibility.core": {
+ "type": "Transitive",
+ "resolved": "2.9.3",
+ "contentHash": "kf3si0YTn2a8J8eZNb+zFpwfoyvIrQ7ivNk5ZYA5yuYk1bEtMe4DxJ2CF/qsRgmEnDr7MnW1mxylBaHTZ4qErA==",
+ "dependencies": {
+ "xunit.abstractions": "2.0.3"
+ }
+ },
+ "xunit.extensibility.execution": {
+ "type": "Transitive",
+ "resolved": "2.9.3",
+ "contentHash": "yMb6vMESlSrE3Wfj7V6cjQ3S4TXdXpRqYeNEI3zsX31uTsGMJjEw6oD5F5u1cHnMptjhEECnmZSsPxB6ChZHDQ==",
+ "dependencies": {
+ "xunit.extensibility.core": "[2.9.3]"
+ }
+ },
+ "functionfoundry.observability": {
+ "type": "Project"
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/tests/FunctionFoundry.Resilience.Tests/packages.lock.json b/tests/FunctionFoundry.Resilience.Tests/packages.lock.json
new file mode 100644
index 0000000..0a1b6d7
--- /dev/null
+++ b/tests/FunctionFoundry.Resilience.Tests/packages.lock.json
@@ -0,0 +1,107 @@
+{
+ "version": 2,
+ "dependencies": {
+ "net10.0": {
+ "coverlet.collector": {
+ "type": "Direct",
+ "requested": "[6.0.4, )",
+ "resolved": "6.0.4",
+ "contentHash": "lkhqpF8Pu2Y7IiN7OntbsTtdbpR1syMsm2F3IgX6ootA4ffRqWL5jF7XipHuZQTdVuWG/gVAAcf8mjk8Tz0xPg=="
+ },
+ "Microsoft.NET.Test.Sdk": {
+ "type": "Direct",
+ "requested": "[17.14.1, )",
+ "resolved": "17.14.1",
+ "contentHash": "HJKqKOE+vshXra2aEHpi2TlxYX7Z9VFYkr+E5rwEvHC8eIXiyO+K9kNm8vmNom3e2rA56WqxU+/N9NJlLGXsJQ==",
+ "dependencies": {
+ "Microsoft.CodeCoverage": "17.14.1",
+ "Microsoft.TestPlatform.TestHost": "17.14.1"
+ }
+ },
+ "xunit": {
+ "type": "Direct",
+ "requested": "[2.9.3, )",
+ "resolved": "2.9.3",
+ "contentHash": "TlXQBinK35LpOPKHAqbLY4xlEen9TBafjs0V5KnA4wZsoQLQJiirCR4CbIXvOH8NzkW4YeJKP5P/Bnrodm0h9Q==",
+ "dependencies": {
+ "xunit.analyzers": "1.18.0",
+ "xunit.assert": "2.9.3",
+ "xunit.core": "[2.9.3]"
+ }
+ },
+ "xunit.runner.visualstudio": {
+ "type": "Direct",
+ "requested": "[3.1.4, )",
+ "resolved": "3.1.4",
+ "contentHash": "5mj99LvCqrq3CNi06xYdyIAXOEh+5b33F2nErCzI5zWiDdLHXiPXEWFSUAF8zlIv0ZWqjZNCwHTQeAPYbF3pCg=="
+ },
+ "Microsoft.CodeCoverage": {
+ "type": "Transitive",
+ "resolved": "17.14.1",
+ "contentHash": "pmTrhfFIoplzFVbhVwUquT+77CbGH+h4/3mBpdmIlYtBi9nAB+kKI6dN3A/nV4DFi3wLLx/BlHIPK+MkbQ6Tpg=="
+ },
+ "Microsoft.TestPlatform.ObjectModel": {
+ "type": "Transitive",
+ "resolved": "17.14.1",
+ "contentHash": "xTP1W6Mi6SWmuxd3a+jj9G9UoC850WGwZUps1Wah9r1ZxgXhdJfj1QqDLJkFjHDCvN42qDL2Ps5KjQYWUU0zcQ=="
+ },
+ "Microsoft.TestPlatform.TestHost": {
+ "type": "Transitive",
+ "resolved": "17.14.1",
+ "contentHash": "d78LPzGKkJwsJXAQwsbJJ7LE7D1wB+rAyhHHAaODF+RDSQ0NgMjDFkSA1Djw18VrxO76GlKAjRUhl+H8NL8Z+Q==",
+ "dependencies": {
+ "Microsoft.TestPlatform.ObjectModel": "17.14.1",
+ "Newtonsoft.Json": "13.0.3"
+ }
+ },
+ "Newtonsoft.Json": {
+ "type": "Transitive",
+ "resolved": "13.0.3",
+ "contentHash": "HrC5BXdl00IP9zeV+0Z848QWPAoCr9P3bDEZguI+gkLcBKAOxix/tLEAAHC+UvDNPv4a2d18lOReHMOagPa+zQ=="
+ },
+ "xunit.abstractions": {
+ "type": "Transitive",
+ "resolved": "2.0.3",
+ "contentHash": "pot1I4YOxlWjIb5jmwvvQNbTrZ3lJQ+jUGkGjWE3hEFM0l5gOnBWS+H3qsex68s5cO52g+44vpGzhAt+42vwKg=="
+ },
+ "xunit.analyzers": {
+ "type": "Transitive",
+ "resolved": "1.18.0",
+ "contentHash": "OtFMHN8yqIcYP9wcVIgJrq01AfTxijjAqVDy/WeQVSyrDC1RzBWeQPztL49DN2syXRah8TYnfvk035s7L95EZQ=="
+ },
+ "xunit.assert": {
+ "type": "Transitive",
+ "resolved": "2.9.3",
+ "contentHash": "/Kq28fCE7MjOV42YLVRAJzRF0WmEqsmflm0cfpMjGtzQ2lR5mYVj1/i0Y8uDAOLczkL3/jArrwehfMD0YogMAA=="
+ },
+ "xunit.core": {
+ "type": "Transitive",
+ "resolved": "2.9.3",
+ "contentHash": "BiAEvqGvyme19wE0wTKdADH+NloYqikiU0mcnmiNyXaF9HyHmE6sr/3DC5vnBkgsWaE6yPyWszKSPSApWdRVeQ==",
+ "dependencies": {
+ "xunit.extensibility.core": "[2.9.3]",
+ "xunit.extensibility.execution": "[2.9.3]"
+ }
+ },
+ "xunit.extensibility.core": {
+ "type": "Transitive",
+ "resolved": "2.9.3",
+ "contentHash": "kf3si0YTn2a8J8eZNb+zFpwfoyvIrQ7ivNk5ZYA5yuYk1bEtMe4DxJ2CF/qsRgmEnDr7MnW1mxylBaHTZ4qErA==",
+ "dependencies": {
+ "xunit.abstractions": "2.0.3"
+ }
+ },
+ "xunit.extensibility.execution": {
+ "type": "Transitive",
+ "resolved": "2.9.3",
+ "contentHash": "yMb6vMESlSrE3Wfj7V6cjQ3S4TXdXpRqYeNEI3zsX31uTsGMJjEw6oD5F5u1cHnMptjhEECnmZSsPxB6ChZHDQ==",
+ "dependencies": {
+ "xunit.extensibility.core": "[2.9.3]"
+ }
+ },
+ "functionfoundry.resilience": {
+ "type": "Project"
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/tests/FunctionFoundry.Scheduling.Tests/packages.lock.json b/tests/FunctionFoundry.Scheduling.Tests/packages.lock.json
new file mode 100644
index 0000000..864ea43
--- /dev/null
+++ b/tests/FunctionFoundry.Scheduling.Tests/packages.lock.json
@@ -0,0 +1,107 @@
+{
+ "version": 2,
+ "dependencies": {
+ "net10.0": {
+ "coverlet.collector": {
+ "type": "Direct",
+ "requested": "[6.0.4, )",
+ "resolved": "6.0.4",
+ "contentHash": "lkhqpF8Pu2Y7IiN7OntbsTtdbpR1syMsm2F3IgX6ootA4ffRqWL5jF7XipHuZQTdVuWG/gVAAcf8mjk8Tz0xPg=="
+ },
+ "Microsoft.NET.Test.Sdk": {
+ "type": "Direct",
+ "requested": "[17.14.1, )",
+ "resolved": "17.14.1",
+ "contentHash": "HJKqKOE+vshXra2aEHpi2TlxYX7Z9VFYkr+E5rwEvHC8eIXiyO+K9kNm8vmNom3e2rA56WqxU+/N9NJlLGXsJQ==",
+ "dependencies": {
+ "Microsoft.CodeCoverage": "17.14.1",
+ "Microsoft.TestPlatform.TestHost": "17.14.1"
+ }
+ },
+ "xunit": {
+ "type": "Direct",
+ "requested": "[2.9.3, )",
+ "resolved": "2.9.3",
+ "contentHash": "TlXQBinK35LpOPKHAqbLY4xlEen9TBafjs0V5KnA4wZsoQLQJiirCR4CbIXvOH8NzkW4YeJKP5P/Bnrodm0h9Q==",
+ "dependencies": {
+ "xunit.analyzers": "1.18.0",
+ "xunit.assert": "2.9.3",
+ "xunit.core": "[2.9.3]"
+ }
+ },
+ "xunit.runner.visualstudio": {
+ "type": "Direct",
+ "requested": "[3.1.4, )",
+ "resolved": "3.1.4",
+ "contentHash": "5mj99LvCqrq3CNi06xYdyIAXOEh+5b33F2nErCzI5zWiDdLHXiPXEWFSUAF8zlIv0ZWqjZNCwHTQeAPYbF3pCg=="
+ },
+ "Microsoft.CodeCoverage": {
+ "type": "Transitive",
+ "resolved": "17.14.1",
+ "contentHash": "pmTrhfFIoplzFVbhVwUquT+77CbGH+h4/3mBpdmIlYtBi9nAB+kKI6dN3A/nV4DFi3wLLx/BlHIPK+MkbQ6Tpg=="
+ },
+ "Microsoft.TestPlatform.ObjectModel": {
+ "type": "Transitive",
+ "resolved": "17.14.1",
+ "contentHash": "xTP1W6Mi6SWmuxd3a+jj9G9UoC850WGwZUps1Wah9r1ZxgXhdJfj1QqDLJkFjHDCvN42qDL2Ps5KjQYWUU0zcQ=="
+ },
+ "Microsoft.TestPlatform.TestHost": {
+ "type": "Transitive",
+ "resolved": "17.14.1",
+ "contentHash": "d78LPzGKkJwsJXAQwsbJJ7LE7D1wB+rAyhHHAaODF+RDSQ0NgMjDFkSA1Djw18VrxO76GlKAjRUhl+H8NL8Z+Q==",
+ "dependencies": {
+ "Microsoft.TestPlatform.ObjectModel": "17.14.1",
+ "Newtonsoft.Json": "13.0.3"
+ }
+ },
+ "Newtonsoft.Json": {
+ "type": "Transitive",
+ "resolved": "13.0.3",
+ "contentHash": "HrC5BXdl00IP9zeV+0Z848QWPAoCr9P3bDEZguI+gkLcBKAOxix/tLEAAHC+UvDNPv4a2d18lOReHMOagPa+zQ=="
+ },
+ "xunit.abstractions": {
+ "type": "Transitive",
+ "resolved": "2.0.3",
+ "contentHash": "pot1I4YOxlWjIb5jmwvvQNbTrZ3lJQ+jUGkGjWE3hEFM0l5gOnBWS+H3qsex68s5cO52g+44vpGzhAt+42vwKg=="
+ },
+ "xunit.analyzers": {
+ "type": "Transitive",
+ "resolved": "1.18.0",
+ "contentHash": "OtFMHN8yqIcYP9wcVIgJrq01AfTxijjAqVDy/WeQVSyrDC1RzBWeQPztL49DN2syXRah8TYnfvk035s7L95EZQ=="
+ },
+ "xunit.assert": {
+ "type": "Transitive",
+ "resolved": "2.9.3",
+ "contentHash": "/Kq28fCE7MjOV42YLVRAJzRF0WmEqsmflm0cfpMjGtzQ2lR5mYVj1/i0Y8uDAOLczkL3/jArrwehfMD0YogMAA=="
+ },
+ "xunit.core": {
+ "type": "Transitive",
+ "resolved": "2.9.3",
+ "contentHash": "BiAEvqGvyme19wE0wTKdADH+NloYqikiU0mcnmiNyXaF9HyHmE6sr/3DC5vnBkgsWaE6yPyWszKSPSApWdRVeQ==",
+ "dependencies": {
+ "xunit.extensibility.core": "[2.9.3]",
+ "xunit.extensibility.execution": "[2.9.3]"
+ }
+ },
+ "xunit.extensibility.core": {
+ "type": "Transitive",
+ "resolved": "2.9.3",
+ "contentHash": "kf3si0YTn2a8J8eZNb+zFpwfoyvIrQ7ivNk5ZYA5yuYk1bEtMe4DxJ2CF/qsRgmEnDr7MnW1mxylBaHTZ4qErA==",
+ "dependencies": {
+ "xunit.abstractions": "2.0.3"
+ }
+ },
+ "xunit.extensibility.execution": {
+ "type": "Transitive",
+ "resolved": "2.9.3",
+ "contentHash": "yMb6vMESlSrE3Wfj7V6cjQ3S4TXdXpRqYeNEI3zsX31uTsGMJjEw6oD5F5u1cHnMptjhEECnmZSsPxB6ChZHDQ==",
+ "dependencies": {
+ "xunit.extensibility.core": "[2.9.3]"
+ }
+ },
+ "functionfoundry.scheduling": {
+ "type": "Project"
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/tests/FunctionFoundry.Security.Tests/packages.lock.json b/tests/FunctionFoundry.Security.Tests/packages.lock.json
new file mode 100644
index 0000000..c4130d2
--- /dev/null
+++ b/tests/FunctionFoundry.Security.Tests/packages.lock.json
@@ -0,0 +1,107 @@
+{
+ "version": 2,
+ "dependencies": {
+ "net10.0": {
+ "coverlet.collector": {
+ "type": "Direct",
+ "requested": "[6.0.4, )",
+ "resolved": "6.0.4",
+ "contentHash": "lkhqpF8Pu2Y7IiN7OntbsTtdbpR1syMsm2F3IgX6ootA4ffRqWL5jF7XipHuZQTdVuWG/gVAAcf8mjk8Tz0xPg=="
+ },
+ "Microsoft.NET.Test.Sdk": {
+ "type": "Direct",
+ "requested": "[17.14.1, )",
+ "resolved": "17.14.1",
+ "contentHash": "HJKqKOE+vshXra2aEHpi2TlxYX7Z9VFYkr+E5rwEvHC8eIXiyO+K9kNm8vmNom3e2rA56WqxU+/N9NJlLGXsJQ==",
+ "dependencies": {
+ "Microsoft.CodeCoverage": "17.14.1",
+ "Microsoft.TestPlatform.TestHost": "17.14.1"
+ }
+ },
+ "xunit": {
+ "type": "Direct",
+ "requested": "[2.9.3, )",
+ "resolved": "2.9.3",
+ "contentHash": "TlXQBinK35LpOPKHAqbLY4xlEen9TBafjs0V5KnA4wZsoQLQJiirCR4CbIXvOH8NzkW4YeJKP5P/Bnrodm0h9Q==",
+ "dependencies": {
+ "xunit.analyzers": "1.18.0",
+ "xunit.assert": "2.9.3",
+ "xunit.core": "[2.9.3]"
+ }
+ },
+ "xunit.runner.visualstudio": {
+ "type": "Direct",
+ "requested": "[3.1.4, )",
+ "resolved": "3.1.4",
+ "contentHash": "5mj99LvCqrq3CNi06xYdyIAXOEh+5b33F2nErCzI5zWiDdLHXiPXEWFSUAF8zlIv0ZWqjZNCwHTQeAPYbF3pCg=="
+ },
+ "Microsoft.CodeCoverage": {
+ "type": "Transitive",
+ "resolved": "17.14.1",
+ "contentHash": "pmTrhfFIoplzFVbhVwUquT+77CbGH+h4/3mBpdmIlYtBi9nAB+kKI6dN3A/nV4DFi3wLLx/BlHIPK+MkbQ6Tpg=="
+ },
+ "Microsoft.TestPlatform.ObjectModel": {
+ "type": "Transitive",
+ "resolved": "17.14.1",
+ "contentHash": "xTP1W6Mi6SWmuxd3a+jj9G9UoC850WGwZUps1Wah9r1ZxgXhdJfj1QqDLJkFjHDCvN42qDL2Ps5KjQYWUU0zcQ=="
+ },
+ "Microsoft.TestPlatform.TestHost": {
+ "type": "Transitive",
+ "resolved": "17.14.1",
+ "contentHash": "d78LPzGKkJwsJXAQwsbJJ7LE7D1wB+rAyhHHAaODF+RDSQ0NgMjDFkSA1Djw18VrxO76GlKAjRUhl+H8NL8Z+Q==",
+ "dependencies": {
+ "Microsoft.TestPlatform.ObjectModel": "17.14.1",
+ "Newtonsoft.Json": "13.0.3"
+ }
+ },
+ "Newtonsoft.Json": {
+ "type": "Transitive",
+ "resolved": "13.0.3",
+ "contentHash": "HrC5BXdl00IP9zeV+0Z848QWPAoCr9P3bDEZguI+gkLcBKAOxix/tLEAAHC+UvDNPv4a2d18lOReHMOagPa+zQ=="
+ },
+ "xunit.abstractions": {
+ "type": "Transitive",
+ "resolved": "2.0.3",
+ "contentHash": "pot1I4YOxlWjIb5jmwvvQNbTrZ3lJQ+jUGkGjWE3hEFM0l5gOnBWS+H3qsex68s5cO52g+44vpGzhAt+42vwKg=="
+ },
+ "xunit.analyzers": {
+ "type": "Transitive",
+ "resolved": "1.18.0",
+ "contentHash": "OtFMHN8yqIcYP9wcVIgJrq01AfTxijjAqVDy/WeQVSyrDC1RzBWeQPztL49DN2syXRah8TYnfvk035s7L95EZQ=="
+ },
+ "xunit.assert": {
+ "type": "Transitive",
+ "resolved": "2.9.3",
+ "contentHash": "/Kq28fCE7MjOV42YLVRAJzRF0WmEqsmflm0cfpMjGtzQ2lR5mYVj1/i0Y8uDAOLczkL3/jArrwehfMD0YogMAA=="
+ },
+ "xunit.core": {
+ "type": "Transitive",
+ "resolved": "2.9.3",
+ "contentHash": "BiAEvqGvyme19wE0wTKdADH+NloYqikiU0mcnmiNyXaF9HyHmE6sr/3DC5vnBkgsWaE6yPyWszKSPSApWdRVeQ==",
+ "dependencies": {
+ "xunit.extensibility.core": "[2.9.3]",
+ "xunit.extensibility.execution": "[2.9.3]"
+ }
+ },
+ "xunit.extensibility.core": {
+ "type": "Transitive",
+ "resolved": "2.9.3",
+ "contentHash": "kf3si0YTn2a8J8eZNb+zFpwfoyvIrQ7ivNk5ZYA5yuYk1bEtMe4DxJ2CF/qsRgmEnDr7MnW1mxylBaHTZ4qErA==",
+ "dependencies": {
+ "xunit.abstractions": "2.0.3"
+ }
+ },
+ "xunit.extensibility.execution": {
+ "type": "Transitive",
+ "resolved": "2.9.3",
+ "contentHash": "yMb6vMESlSrE3Wfj7V6cjQ3S4TXdXpRqYeNEI3zsX31uTsGMJjEw6oD5F5u1cHnMptjhEECnmZSsPxB6ChZHDQ==",
+ "dependencies": {
+ "xunit.extensibility.core": "[2.9.3]"
+ }
+ },
+ "functionfoundry.security": {
+ "type": "Project"
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/tests/FunctionFoundry.Storage.Tests/packages.lock.json b/tests/FunctionFoundry.Storage.Tests/packages.lock.json
new file mode 100644
index 0000000..aa250e8
--- /dev/null
+++ b/tests/FunctionFoundry.Storage.Tests/packages.lock.json
@@ -0,0 +1,107 @@
+{
+ "version": 2,
+ "dependencies": {
+ "net10.0": {
+ "coverlet.collector": {
+ "type": "Direct",
+ "requested": "[6.0.4, )",
+ "resolved": "6.0.4",
+ "contentHash": "lkhqpF8Pu2Y7IiN7OntbsTtdbpR1syMsm2F3IgX6ootA4ffRqWL5jF7XipHuZQTdVuWG/gVAAcf8mjk8Tz0xPg=="
+ },
+ "Microsoft.NET.Test.Sdk": {
+ "type": "Direct",
+ "requested": "[17.14.1, )",
+ "resolved": "17.14.1",
+ "contentHash": "HJKqKOE+vshXra2aEHpi2TlxYX7Z9VFYkr+E5rwEvHC8eIXiyO+K9kNm8vmNom3e2rA56WqxU+/N9NJlLGXsJQ==",
+ "dependencies": {
+ "Microsoft.CodeCoverage": "17.14.1",
+ "Microsoft.TestPlatform.TestHost": "17.14.1"
+ }
+ },
+ "xunit": {
+ "type": "Direct",
+ "requested": "[2.9.3, )",
+ "resolved": "2.9.3",
+ "contentHash": "TlXQBinK35LpOPKHAqbLY4xlEen9TBafjs0V5KnA4wZsoQLQJiirCR4CbIXvOH8NzkW4YeJKP5P/Bnrodm0h9Q==",
+ "dependencies": {
+ "xunit.analyzers": "1.18.0",
+ "xunit.assert": "2.9.3",
+ "xunit.core": "[2.9.3]"
+ }
+ },
+ "xunit.runner.visualstudio": {
+ "type": "Direct",
+ "requested": "[3.1.4, )",
+ "resolved": "3.1.4",
+ "contentHash": "5mj99LvCqrq3CNi06xYdyIAXOEh+5b33F2nErCzI5zWiDdLHXiPXEWFSUAF8zlIv0ZWqjZNCwHTQeAPYbF3pCg=="
+ },
+ "Microsoft.CodeCoverage": {
+ "type": "Transitive",
+ "resolved": "17.14.1",
+ "contentHash": "pmTrhfFIoplzFVbhVwUquT+77CbGH+h4/3mBpdmIlYtBi9nAB+kKI6dN3A/nV4DFi3wLLx/BlHIPK+MkbQ6Tpg=="
+ },
+ "Microsoft.TestPlatform.ObjectModel": {
+ "type": "Transitive",
+ "resolved": "17.14.1",
+ "contentHash": "xTP1W6Mi6SWmuxd3a+jj9G9UoC850WGwZUps1Wah9r1ZxgXhdJfj1QqDLJkFjHDCvN42qDL2Ps5KjQYWUU0zcQ=="
+ },
+ "Microsoft.TestPlatform.TestHost": {
+ "type": "Transitive",
+ "resolved": "17.14.1",
+ "contentHash": "d78LPzGKkJwsJXAQwsbJJ7LE7D1wB+rAyhHHAaODF+RDSQ0NgMjDFkSA1Djw18VrxO76GlKAjRUhl+H8NL8Z+Q==",
+ "dependencies": {
+ "Microsoft.TestPlatform.ObjectModel": "17.14.1",
+ "Newtonsoft.Json": "13.0.3"
+ }
+ },
+ "Newtonsoft.Json": {
+ "type": "Transitive",
+ "resolved": "13.0.3",
+ "contentHash": "HrC5BXdl00IP9zeV+0Z848QWPAoCr9P3bDEZguI+gkLcBKAOxix/tLEAAHC+UvDNPv4a2d18lOReHMOagPa+zQ=="
+ },
+ "xunit.abstractions": {
+ "type": "Transitive",
+ "resolved": "2.0.3",
+ "contentHash": "pot1I4YOxlWjIb5jmwvvQNbTrZ3lJQ+jUGkGjWE3hEFM0l5gOnBWS+H3qsex68s5cO52g+44vpGzhAt+42vwKg=="
+ },
+ "xunit.analyzers": {
+ "type": "Transitive",
+ "resolved": "1.18.0",
+ "contentHash": "OtFMHN8yqIcYP9wcVIgJrq01AfTxijjAqVDy/WeQVSyrDC1RzBWeQPztL49DN2syXRah8TYnfvk035s7L95EZQ=="
+ },
+ "xunit.assert": {
+ "type": "Transitive",
+ "resolved": "2.9.3",
+ "contentHash": "/Kq28fCE7MjOV42YLVRAJzRF0WmEqsmflm0cfpMjGtzQ2lR5mYVj1/i0Y8uDAOLczkL3/jArrwehfMD0YogMAA=="
+ },
+ "xunit.core": {
+ "type": "Transitive",
+ "resolved": "2.9.3",
+ "contentHash": "BiAEvqGvyme19wE0wTKdADH+NloYqikiU0mcnmiNyXaF9HyHmE6sr/3DC5vnBkgsWaE6yPyWszKSPSApWdRVeQ==",
+ "dependencies": {
+ "xunit.extensibility.core": "[2.9.3]",
+ "xunit.extensibility.execution": "[2.9.3]"
+ }
+ },
+ "xunit.extensibility.core": {
+ "type": "Transitive",
+ "resolved": "2.9.3",
+ "contentHash": "kf3si0YTn2a8J8eZNb+zFpwfoyvIrQ7ivNk5ZYA5yuYk1bEtMe4DxJ2CF/qsRgmEnDr7MnW1mxylBaHTZ4qErA==",
+ "dependencies": {
+ "xunit.abstractions": "2.0.3"
+ }
+ },
+ "xunit.extensibility.execution": {
+ "type": "Transitive",
+ "resolved": "2.9.3",
+ "contentHash": "yMb6vMESlSrE3Wfj7V6cjQ3S4TXdXpRqYeNEI3zsX31uTsGMJjEw6oD5F5u1cHnMptjhEECnmZSsPxB6ChZHDQ==",
+ "dependencies": {
+ "xunit.extensibility.core": "[2.9.3]"
+ }
+ },
+ "functionfoundry.storage": {
+ "type": "Project"
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/tests/FunctionFoundry.Text.Tests/packages.lock.json b/tests/FunctionFoundry.Text.Tests/packages.lock.json
new file mode 100644
index 0000000..195a4e1
--- /dev/null
+++ b/tests/FunctionFoundry.Text.Tests/packages.lock.json
@@ -0,0 +1,107 @@
+{
+ "version": 2,
+ "dependencies": {
+ "net10.0": {
+ "coverlet.collector": {
+ "type": "Direct",
+ "requested": "[6.0.4, )",
+ "resolved": "6.0.4",
+ "contentHash": "lkhqpF8Pu2Y7IiN7OntbsTtdbpR1syMsm2F3IgX6ootA4ffRqWL5jF7XipHuZQTdVuWG/gVAAcf8mjk8Tz0xPg=="
+ },
+ "Microsoft.NET.Test.Sdk": {
+ "type": "Direct",
+ "requested": "[17.14.1, )",
+ "resolved": "17.14.1",
+ "contentHash": "HJKqKOE+vshXra2aEHpi2TlxYX7Z9VFYkr+E5rwEvHC8eIXiyO+K9kNm8vmNom3e2rA56WqxU+/N9NJlLGXsJQ==",
+ "dependencies": {
+ "Microsoft.CodeCoverage": "17.14.1",
+ "Microsoft.TestPlatform.TestHost": "17.14.1"
+ }
+ },
+ "xunit": {
+ "type": "Direct",
+ "requested": "[2.9.3, )",
+ "resolved": "2.9.3",
+ "contentHash": "TlXQBinK35LpOPKHAqbLY4xlEen9TBafjs0V5KnA4wZsoQLQJiirCR4CbIXvOH8NzkW4YeJKP5P/Bnrodm0h9Q==",
+ "dependencies": {
+ "xunit.analyzers": "1.18.0",
+ "xunit.assert": "2.9.3",
+ "xunit.core": "[2.9.3]"
+ }
+ },
+ "xunit.runner.visualstudio": {
+ "type": "Direct",
+ "requested": "[3.1.4, )",
+ "resolved": "3.1.4",
+ "contentHash": "5mj99LvCqrq3CNi06xYdyIAXOEh+5b33F2nErCzI5zWiDdLHXiPXEWFSUAF8zlIv0ZWqjZNCwHTQeAPYbF3pCg=="
+ },
+ "Microsoft.CodeCoverage": {
+ "type": "Transitive",
+ "resolved": "17.14.1",
+ "contentHash": "pmTrhfFIoplzFVbhVwUquT+77CbGH+h4/3mBpdmIlYtBi9nAB+kKI6dN3A/nV4DFi3wLLx/BlHIPK+MkbQ6Tpg=="
+ },
+ "Microsoft.TestPlatform.ObjectModel": {
+ "type": "Transitive",
+ "resolved": "17.14.1",
+ "contentHash": "xTP1W6Mi6SWmuxd3a+jj9G9UoC850WGwZUps1Wah9r1ZxgXhdJfj1QqDLJkFjHDCvN42qDL2Ps5KjQYWUU0zcQ=="
+ },
+ "Microsoft.TestPlatform.TestHost": {
+ "type": "Transitive",
+ "resolved": "17.14.1",
+ "contentHash": "d78LPzGKkJwsJXAQwsbJJ7LE7D1wB+rAyhHHAaODF+RDSQ0NgMjDFkSA1Djw18VrxO76GlKAjRUhl+H8NL8Z+Q==",
+ "dependencies": {
+ "Microsoft.TestPlatform.ObjectModel": "17.14.1",
+ "Newtonsoft.Json": "13.0.3"
+ }
+ },
+ "Newtonsoft.Json": {
+ "type": "Transitive",
+ "resolved": "13.0.3",
+ "contentHash": "HrC5BXdl00IP9zeV+0Z848QWPAoCr9P3bDEZguI+gkLcBKAOxix/tLEAAHC+UvDNPv4a2d18lOReHMOagPa+zQ=="
+ },
+ "xunit.abstractions": {
+ "type": "Transitive",
+ "resolved": "2.0.3",
+ "contentHash": "pot1I4YOxlWjIb5jmwvvQNbTrZ3lJQ+jUGkGjWE3hEFM0l5gOnBWS+H3qsex68s5cO52g+44vpGzhAt+42vwKg=="
+ },
+ "xunit.analyzers": {
+ "type": "Transitive",
+ "resolved": "1.18.0",
+ "contentHash": "OtFMHN8yqIcYP9wcVIgJrq01AfTxijjAqVDy/WeQVSyrDC1RzBWeQPztL49DN2syXRah8TYnfvk035s7L95EZQ=="
+ },
+ "xunit.assert": {
+ "type": "Transitive",
+ "resolved": "2.9.3",
+ "contentHash": "/Kq28fCE7MjOV42YLVRAJzRF0WmEqsmflm0cfpMjGtzQ2lR5mYVj1/i0Y8uDAOLczkL3/jArrwehfMD0YogMAA=="
+ },
+ "xunit.core": {
+ "type": "Transitive",
+ "resolved": "2.9.3",
+ "contentHash": "BiAEvqGvyme19wE0wTKdADH+NloYqikiU0mcnmiNyXaF9HyHmE6sr/3DC5vnBkgsWaE6yPyWszKSPSApWdRVeQ==",
+ "dependencies": {
+ "xunit.extensibility.core": "[2.9.3]",
+ "xunit.extensibility.execution": "[2.9.3]"
+ }
+ },
+ "xunit.extensibility.core": {
+ "type": "Transitive",
+ "resolved": "2.9.3",
+ "contentHash": "kf3si0YTn2a8J8eZNb+zFpwfoyvIrQ7ivNk5ZYA5yuYk1bEtMe4DxJ2CF/qsRgmEnDr7MnW1mxylBaHTZ4qErA==",
+ "dependencies": {
+ "xunit.abstractions": "2.0.3"
+ }
+ },
+ "xunit.extensibility.execution": {
+ "type": "Transitive",
+ "resolved": "2.9.3",
+ "contentHash": "yMb6vMESlSrE3Wfj7V6cjQ3S4TXdXpRqYeNEI3zsX31uTsGMJjEw6oD5F5u1cHnMptjhEECnmZSsPxB6ChZHDQ==",
+ "dependencies": {
+ "xunit.extensibility.core": "[2.9.3]"
+ }
+ },
+ "functionfoundry.text": {
+ "type": "Project"
+ }
+ }
+ }
+}
\ No newline at end of file