Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
154 commits
Select commit Hold shift + click to select a range
c7b2816
Replace JSON.NET with System.Text.Json across the codebase
niemyjski Feb 28, 2026
f4fdd73
fix: address STJ migration bugs and PR review feedback
niemyjski Mar 1, 2026
859b8d7
Migrate serializer, config, and bootstrapper to Elastic.Clients.Elast…
niemyjski Mar 22, 2026
d0b102a
Migrate index configurations to new Elasticsearch 8 fluent API
niemyjski Mar 22, 2026
4b7f7ee
Migrate queries and repositories to Elastic.Clients.Elasticsearch
niemyjski Mar 22, 2026
189abd6
Migrate jobs, migrations, and controllers to Elastic.Clients.Elastics…
niemyjski Mar 22, 2026
c852c93
fix: remove duplicate Id mapping in EventIndex
niemyjski Mar 22, 2026
e767f4a
Fix STJ serialization test failures
niemyjski Mar 22, 2026
07205d7
Address PR review feedback
niemyjski Mar 22, 2026
cb951cc
Fix EmptyCollectionModifier, deserialization, and test quality
niemyjski Mar 22, 2026
3248743
Fix return→continue in event upgraders, address review feedback
niemyjski Mar 22, 2026
04be116
Quote interpolated values in FilterExpression to prevent query injection
niemyjski Mar 22, 2026
82cc23e
Fix whitespace body check in DeserializeResponseAsync
niemyjski Mar 22, 2026
08bb810
Replace all Lucene FilterExpression strings with typed queries
niemyjski Mar 22, 2026
86f90bc
Fix TokenRepository int enum mapping and SerializerTests
niemyjski Mar 23, 2026
c181c84
Add enum serialization, fix response models, improve test coverage
niemyjski Mar 23, 2026
11a6860
Revert enum string serialization, fix CodeQL issues
niemyjski Mar 23, 2026
05d87a9
Fix API contract preservation, code quality, and test migration
niemyjski Mar 23, 2026
78af2ab
Fix query visitor ternary, preserve ShouldSerialize predicates
niemyjski Mar 23, 2026
920bbd2
Fix JsonExtensionData and SummaryData.Data serialization issues
niemyjski Mar 23, 2026
5855ff7
Fix GetValue<T> deserialization for PascalCase dictionary keys
niemyjski Mar 30, 2026
4755150
Fix nested snake_case deserialization in Error.Inner
niemyjski Mar 30, 2026
bac4099
Fix STJ review findings: case-insensitive dicts, DateTime.MinValue Ki…
niemyjski Mar 30, 2026
9f36e44
Eliminate reflection-based property counting in DataDictionary.GetVal…
niemyjski Mar 31, 2026
20c8502
Replace ElasticSystemTextJsonSerializer with DefaultSourceSerializer
niemyjski Mar 31, 2026
b51fc08
Use FieldEquals and StackStatus enum instead of raw TermQuery/strings
niemyjski Mar 31, 2026
8e3e257
Fix OrganizationRepository suspended filter logic
niemyjski Mar 31, 2026
c75d71e
Use JsonSerializerOptions directly in JsonEventParserPlugin instead o…
niemyjski Mar 31, 2026
ab677f9
Remove dead Foundatio.JsonNet dependency; use type-safe converter rem…
niemyjski Mar 31, 2026
d34699a
Remove unnecessary DateTime converters; restore test assertions
niemyjski Apr 2, 2026
1148ead
Update Foundatio packages and adapt to NRT API changes
niemyjski Apr 21, 2026
bc2c0c4
pr feedback
niemyjski Apr 27, 2026
667bcc0
Address Copilot PR review feedback
niemyjski Apr 28, 2026
7f37744
Remove all Newtonsoft.Json usage, address PR feedback
niemyjski Apr 29, 2026
8282c4f
fix: restore SizeField mapping in EventIndex for mapper-size plugin
niemyjski Apr 29, 2026
9e78777
Replace incompatible AspNetCore.HealthChecks.Elasticsearch with inlin…
niemyjski Apr 29, 2026
3da3f84
fix: StackStatus enum FieldEquals mismatch + nullable response arrays
niemyjski Apr 29, 2026
1f7d7ae
Update Foundatio.Repositories preview
niemyjski May 11, 2026
f676a10
fix: prevent extension data from overwriting explicit Data entries
niemyjski May 11, 2026
43ec0a9
fix: ToFormattedString now uses DeepClone to avoid mutating input node
niemyjski May 11, 2026
3212fa3
fix: apply PascalCase fallback to JSON string deserialization path
niemyjski May 11, 2026
d10613b
fix: improve GetSlackToken error handling and TypeHelper dict comparison
niemyjski May 11, 2026
09a6e1b
fix: use ILogger instead of Debug.WriteLine in GetSlackToken
niemyjski May 11, 2026
65a1fa4
test: add serialization tests for 6 previously untested data models
niemyjski May 11, 2026
27ba592
fix: add ObjectToInferredTypesConverter to fallback deserialization o…
niemyjski May 11, 2026
c49c1c2
Revert unnecessary PascalCase fallback machinery
niemyjski May 11, 2026
fd94cf5
Switch to JsonNamingPolicy.SnakeCaseLower with JsonPropertyName overr…
niemyjski May 11, 2026
c819c0a
Updated to latest repositories
niemyjski May 12, 2026
8b089d3
fix: write back mutated error to Event.Data after SetTargetInfo
niemyjski May 11, 2026
2f5b6c4
refactor: migrate repository queries to Foundatio expression-based API
niemyjski May 11, 2026
d152c1e
chore: improve STJ serialization code with documentation and pattern …
niemyjski May 11, 2026
7bab012
test: add @target integration tests and fix test infrastructure
niemyjski May 11, 2026
682acd8
test: add repository query migration coverage
niemyjski May 11, 2026
e9a0798
refactor: remove unnecessary TryDeserializeWithFallback
niemyjski May 11, 2026
759bd74
fix: V2 event upgrader produces snake_case @user/@user_description nodes
niemyjski May 11, 2026
bfbe49a
refactor: repository query API + organization naming + test improvements
niemyjski May 14, 2026
15404dc
fix: GetValue<T> dictionary normalization + cleanup review findings
niemyjski May 14, 2026
3f39710
docs: add comprehensive STJ serialization architecture document
niemyjski May 14, 2026
553971e
fix: remove DictionaryKeyPolicy to prevent user data key corruption
niemyjski May 14, 2026
717abde
Remove incorrect snake_case test fixture and add Foundatio issues doc
niemyjski May 14, 2026
b3a9ca6
Fix V1 webhook data extraction for legacy PascalCase dictionary values
niemyjski May 14, 2026
6a93f0b
Add logger parameter to EventExtensions GetValue methods to surface d…
niemyjski May 14, 2026
14b54d3
Make logger parameter required in EventExtensions Get* methods
niemyjski May 15, 2026
651a348
Upgrade Foundatio to 8.0.0-beta1.3, remove StackRepository workaround
niemyjski May 15, 2026
d724ffa
Fix CodeQL: use TryGetValue instead of ContainsKey+indexer
niemyjski May 15, 2026
91d0fd7
test: add main-validated serialization regressions
niemyjski May 16, 2026
e2629bf
Fix STJ serialization edge cases for production readiness
niemyjski May 16, 2026
a8eff01
fix: prevent OverflowException in ConvertJsonElementNumber for large …
niemyjski May 18, 2026
da8726f
fix: prevent ArgumentException when Rename target key already exists
niemyjski May 18, 2026
a80f2d3
chore: annotate triple-serialization path with PERF comment
niemyjski May 18, 2026
1208b5a
test: fix misleading test name and add assertions for OnDeserialized …
niemyjski May 18, 2026
7ca8a83
fix: normalize ProblemDetails traceId to snake_case across all error …
niemyjski May 18, 2026
bea80fc
fix: update golden test to match FluentRest 11.1.0.0 version string
niemyjski May 18, 2026
c832d86
test: strengthen weak conditional assertions in EventController tests
niemyjski May 18, 2026
32d4235
fix: preserve null fields in webhook payloads for backwards compatibi…
niemyjski May 19, 2026
bf5698f
fix: pass JsonSerializerOptions in Delta.TrySetPropertyValue for Json…
niemyjski May 19, 2026
1b5ecc5
fix: use UTF-8 encoding for WebSocket messages to prevent non-ASCII c…
niemyjski May 19, 2026
cfd1a18
fix: prevent ES index alias collisions in parallel test runs
niemyjski May 19, 2026
61bd325
fix: log correct orphaned event count for project/organization cleanup
niemyjski May 19, 2026
5e76af9
fix: correct misleading XSS comment on JavaScriptEncoder
niemyjski May 19, 2026
74d4be9
test: add extensive multi-tenant cleanup job coverage
niemyjski May 19, 2026
7612a83
fix: resolve rebase conflicts - deduplicate packages, migrate SavedVi…
niemyjski May 21, 2026
5dc1ee7
fix: improve date parsing consistency and array contract clarity
niemyjski May 21, 2026
64ff97b
fix: EmptyCollectionModifier null/HashSet handling, response records,…
niemyjski May 21, 2026
778560a
refactor: simplify core serialization code and remove unnecessary logic
niemyjski May 21, 2026
43bae06
chore: remove unused packages and variables
niemyjski May 21, 2026
fe8837f
docs: improve logging and code comments
niemyjski May 21, 2026
5ea55e0
test: simplify test infrastructure and remove workarounds
niemyjski May 21, 2026
810d4e5
test: improve test structure and assertions
niemyjski May 21, 2026
576fe8f
test: update webhook tests and expected files for consistent behavior
niemyjski May 21, 2026
c7fc673
test: cleanup formatting, IDs, and comments
niemyjski May 21, 2026
fdbed3b
chore: cleanup config and remove temp migration doc
niemyjski May 21, 2026
51562d6
test: isolate Elasticsearch audit indices
niemyjski May 21, 2026
75fd018
fix: scope orphan cleanup to configured indices
niemyjski May 21, 2026
f8d03b0
fix: preserve event payload casing semantics
niemyjski May 21, 2026
c3cb07c
fix: preserve legacy API serialization contracts
niemyjski May 21, 2026
b1b3c5d
fix: restore saved view slug contract
niemyjski May 21, 2026
74310eb
test: address review coverage gaps
niemyjski May 21, 2026
c95b51a
fix: document typed data fallback failures
niemyjski May 21, 2026
95d739b
chore: address remaining review cleanup
niemyjski May 21, 2026
7ea4d76
fix: address review bot cleanup
niemyjski May 21, 2026
1592076
chore: clarify serializer fallback comments
niemyjski May 21, 2026
67f8f28
fix: avoid slack token fallback exceptions
niemyjski May 21, 2026
63132bf
fix: preserve organization app filters
niemyjski May 21, 2026
443194b
fix: preserve filter and admin array contracts
niemyjski May 21, 2026
d012799
test: tighten serializer and repository assertions
niemyjski May 21, 2026
84bac32
fix: centralize API serialization contracts
niemyjski May 21, 2026
992a8d5
removed transitive deps
niemyjski May 22, 2026
093bdc7
Merge remote-tracking branch 'origin/main' into feature/system-text-j…
niemyjski May 22, 2026
f051653
fix: preserve event data keys during STJ capture
niemyjski May 22, 2026
947063b
fix: clarify webhook serializer selection
niemyjski May 22, 2026
509a275
test: tighten review-driven serializer assertions
niemyjski May 22, 2026
90ff175
fix: align saved view slug validation
niemyjski May 22, 2026
0cb8205
test: clarify strict JsonAssert comparison
niemyjski May 22, 2026
9c19c19
test: keep serialization audit as manual tooling
niemyjski May 22, 2026
fcc1c27
fix: scope duplicate stack cleanup
niemyjski May 22, 2026
92a6d21
test: simplify integration test reset
niemyjski May 22, 2026
72ffa28
fix: use standard api datetime serialization
niemyjski May 22, 2026
6845c9f
fix: align saved view openapi contracts
niemyjski May 22, 2026
9aa4b61
fix: restore legacy json naming policy
niemyjski May 22, 2026
adf565f
fix: use ordinal organization id comparisons
niemyjski May 22, 2026
99b3459
Revert "fix: restore legacy json naming policy"
niemyjski May 22, 2026
e0b731e
fix: support camelCase/PascalCase binding for webhook, token, and pro…
niemyjski May 22, 2026
0366eac
fix: prevent date mangling in audit script pretty-print
niemyjski May 22, 2026
4d889f5
Fix FixDuplicateStacksMigrationTests alias conflict with persistent E…
niemyjski May 22, 2026
404840d
Revert "fix: support camelCase/PascalCase binding for webhook, token,…
niemyjski May 22, 2026
bb5568b
Revert "Fix FixDuplicateStacksMigrationTests alias conflict with pers…
niemyjski May 22, 2026
7bb5cd0
feat: Add thermo-nuclear code quality review agent and skill
niemyjski May 22, 2026
ed2f01e
refactor: Standardize cancellable async delays and improve JSON clarity
niemyjski May 22, 2026
8b46303
fix: preserve serializer compatibility edges
niemyjski May 22, 2026
be23f33
refactor: move JsonNode snapshot formatting to tests
niemyjski May 22, 2026
022b64d
fix: centralize saved view slug regex
niemyjski May 22, 2026
b2f62a6
refactor: remove unnecessary DateTime OpenAPI transformer
niemyjski May 22, 2026
27b3657
test: revert host factory churn and trim spacing
niemyjski May 22, 2026
7390466
docs: refresh serialization architecture notes
niemyjski May 22, 2026
8b7a725
Delete docs/foundatio-issues.md
niemyjski May 22, 2026
2c54186
refactor: derive event index fields from model metadata
niemyjski May 22, 2026
d083ab6
fix: preserve scoped range query output
niemyjski May 22, 2026
d63c7b4
fix: address saved view review follow-ups
niemyjski May 22, 2026
427bc02
Merge remote-tracking branch 'origin/feature/system-text-json-v2' int…
niemyjski May 22, 2026
5a742d0
Apply suggestion from @niemyjski
niemyjski May 23, 2026
c75b07b
Merge remote-tracking branch 'origin/main' into feature/system-text-j…
niemyjski May 23, 2026
c2ae23a
fix: update Foundatio package and remove obsolete query visitor
niemyjski May 23, 2026
6872875
fix: resolve serializer ordering and test date issues
niemyjski May 23, 2026
e786d23
Fix PR review comments: pattern matching, merge loops, restore comment
niemyjski May 23, 2026
347e04c
fix: whitespace
niemyjski May 23, 2026
73bc9ea
fix: revert unrelated SavedView slug changes
niemyjski May 23, 2026
8258665
Revert "fix: revert unrelated SavedView slug changes"
niemyjski May 23, 2026
9902f84
fix: use stable date in casing tests
niemyjski May 23, 2026
f528bf7
fix: preserve elastic index mapping parity
niemyjski May 23, 2026
eb0d4fc
fix: keep json number inference stable
niemyjski May 23, 2026
7d62799
test: stabilize casing regression coverage
niemyjski May 23, 2026
2fd9d31
test: cover environment info os details
niemyjski May 23, 2026
5f0c509
test: add serialization audit test infrastructure
niemyjski May 23, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
122 changes: 122 additions & 0 deletions .agents/skills/serialization-audit/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
---
name: serialization-audit
description: >
Use this skill when verifying serialization behavior across branches, testing for backwards
compatibility in JSON serialization changes, or comparing API request/response/storage formats
between implementations. Apply when migrating serializers (e.g., Newtonsoft to System.Text.Json),
adding new JSON converters, or changing naming policies.
---

# Serialization Audit Skill

## Overview

The serialization audit workflow generates branch-specific JSON snapshots of API behavior and compares them to detect behavioral differences. It exercises the full pipeline: API submission → queue → job processing → Elasticsearch storage → API response.

## Workflow

### 1. Run Audit Script on Both Branches

The audit runner lives at `.agents/skills/serialization-audit/scripts/audit-api-surface.ps1`. It:
- Submit events with different JSON casing conventions (snake_case, PascalCase, camelCase, mixed)
- Capture the raw request body, Elasticsearch stored document, and API response
- Save each to `audit-output/{audit-run-id}/{branch-name}/{scenario}/` with files like:
- `request.json` — what was submitted
- `elastic.json` — what was stored
- `response.json` — what the API returned

```bash
# Start Exceptionless locally first:
aspire run

# On main branch:
git checkout main
pwsh .agents/skills/serialization-audit/scripts/audit-api-surface.ps1 \
-BranchName main \
-AuditRunId live-serialization

# On feature branch:
git checkout feature/system-text-json-v2
pwsh .agents/skills/serialization-audit/scripts/audit-api-surface.ps1 \
-BranchName feature-system-text-json-v2 \
-AuditRunId live-serialization
```

**Requirements:** API and Elasticsearch must be running locally through Aspire.

### 2. Diff the Output

```bash
diff -r audit-output/main/ audit-output/feature-system-text-json-v2/ | head -100
```

Or for structured comparison:
```bash
# Compare specific test outputs
diff audit-output/main/events-post-snake-case/elastic.json \
audit-output/feature-system-text-json-v2/events-post-snake-case/elastic.json
```

### 3. Categorize Differences

Common difference categories:
| Category | Example | Severity |
|----------|---------|----------|
| Casing binding failure | `ReferenceId` in ExtensionData instead of property | CRITICAL |
| Date parsing expansion | `"2026-01-15"` → `"2026-01-15T00:00:00+00:00"` | MEDIUM |
| Numeric precision | `0` vs `0.0` | LOW |
| Empty collection omission | `"tags": []` omitted | LOW/EXPECTED |
| Character encoding | `&` vs `\u0026` | LOW |

### 4. Write Targeted Tests

For each difference found, write a **unit test** that reproduces it in isolation:

```csharp
// In tests/Exceptionless.Tests/Serializer/CasingCompatibilityTests.cs
[Theory]
[InlineData("reference_id")] // snake_case - should always work
[InlineData("ReferenceId")] // PascalCase - must also work
[InlineData("referenceId")] // camelCase - must also work
public void Deserialize_ReferenceId_MatchesAllCasings(string key)
{
string json = $$"""{"type": "error", "{{key}}": "test-ref-123"}""";
var ev = _serializer.Deserialize<PersistentEvent>(json);
Assert.Equal("test-ref-123", ev.ReferenceId);
}
```

### 5. Implement Fixes

Common fix patterns:
- **Multi-word property casing:** Add fallback in `IJsonOnDeserialized.OnDeserialized()` to check ExtensionData for alternate casings
- **Date-only string parsing:** Check for time separator ('T') before calling `TryGetDateTimeOffset` in `ObjectToInferredTypesConverter`
- **Naming policy mismatches:** Use `[JsonPropertyName]` attributes or TypeInfo modifiers

### 6. Re-run Audit

After fixes, run the audit into a new output directory (or the same branch directory — it overwrites):

```bash
pwsh .agents/skills/serialization-audit/scripts/audit-api-surface.ps1 -AuditRunId post-fixes
```

Compare again to verify differences are resolved.

## Key Files

| File | Purpose |
|------|---------|
| `tests/Exceptionless.Tests/Serializer/CasingCompatibilityTests.cs` | Unit tests for specific casing/format issues |
| `src/Exceptionless.Core/Serialization/ObjectToInferredTypesConverter.cs` | Type inference for untyped JSON values |
| `src/Exceptionless.Core/Serialization/JsonSerializerOptionsExtensions.cs` | STJ configuration (naming policy, converters) |
| `src/Exceptionless.Core/Models/Event.cs` | Event model with `OnDeserialized` fallback logic |
| `.agents/skills/serialization-audit/scripts/audit-api-surface.ps1` | Live localhost audit runner |
| `audit-output/` | Generated comparison files (gitignored) |

## Design Principles

1. **Backwards compatibility first:** Any payload that worked with Newtonsoft must still work with STJ
2. **Snake_case output, any-case input:** Serialize as snake_case, but accept PascalCase, camelCase, and snake_case on deserialization
3. **Preserve user data types:** Don't expand date-only strings to DateTimeOffset — users may store non-date strings that happen to look like dates
4. **Test the full pipeline:** Unit tests catch the bug, integration tests prove the fix works end-to-end
Loading