Skip to content

Commit e7e6b9c

Browse files
committed
feat: wrap up data feature matrix & optimize example runs
1 parent f2e3b2c commit e7e6b9c

27 files changed

Lines changed: 669 additions & 499 deletions

File tree

.claude/skills/flowthru-contributing/SKILL.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,3 +16,5 @@ When adding or modifying Flowthru internals:
1616
- Add pre-flight validation for environmental concerns (files, connections, external schemas).
1717
- Reserve runtime error handling for truly unpredictable failures.
1818
- Ask not just "Will this work?" but "When will it break?"
19+
20+
Flowthru also depends on, and connects to, many other projects. Projects that may be helpful to directly introspect can be found in `docs/reference/misc/external/*/repo` subdirectories. If a source's `repo` subdirectory is missing, it can be pulled by running `nx run xdocs:pull <source>`.

docs/project.json

Lines changed: 26 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
"sourceRoot": "./docs",
66
"targets": {
77
"_build-reference": {
8-
"//": "Generates markdown API reference from C# docstrings into docs/reference/src/. Inputs are scoped to the C# source + the docfx script — hand-written docs (tutorials/, guides/, explanation/) do NOT invalidate this cache, since docfx doesn't read them.",
8+
"//": "Generates markdown API reference from C# docstrings into docs/reference/src/. Inputs are scoped to the C# source + the docfx script — hand-written docs (tutorials/, guides/, explanation/) do NOT invalidate this cache, since docfx doesn't read them. Private subtarget; composed into docs:build.",
99
"executor": "nx:run-commands",
1010
"dependsOn": [ "flowthru:restore" ],
1111
"cache": true,
@@ -24,25 +24,40 @@
2424
"parallel": false
2525
}
2626
},
27-
"build": {
28-
"//": "Umbrella docs build target. Inputs mirror _build-reference so this stays in sync with the underlying docfx run; downstream consumers (site:_ingest-docs) read the produced reference/src/ tree directly.",
27+
"_build-capability-matrix": {
28+
"//": "Regenerates docs/reference/extensions/capability-matrix.md by running the file-based C# program at scripts/_test/capability-matrix.cs. The same script is exercised in freshness mode by tests:_test:capability-matrix-freshness; this target is the generation half. Private subtarget; composed into docs:build. Inputs scoped to the format-extension surface the generator reflects on plus the script itself, so unrelated source changes don't invalidate the cache.",
2929
"executor": "nx:run-commands",
30-
"dependsOn": [ "_build-reference" ],
3130
"cache": true,
3231
"inputs": [
33-
"{workspaceRoot}/src/**/*.cs",
34-
"{workspaceRoot}/src/**/*.csproj",
35-
"{workspaceRoot}/scripts/docfx-metadata.sh",
36-
"{workspaceRoot}/Directory.Build.props",
37-
"{workspaceRoot}/Directory.Build.targets"
32+
"{workspaceRoot}/src/core/Flowthru.Core/Data/Capabilities/FormatRowFeatures.cs",
33+
"{workspaceRoot}/src/core/Flowthru.Core/Data/Storage/IFormatBase.cs",
34+
"{workspaceRoot}/src/core/Flowthru.Core/Data/Storage/IFormatRowReader.cs",
35+
"{workspaceRoot}/src/core/Flowthru.Core/Data/Storage/IFormatRowWriter.cs",
36+
"{workspaceRoot}/src/core/Flowthru.Core/Data/Storage/IFormatStreamReader.cs",
37+
"{workspaceRoot}/src/core/Flowthru.Core/Data/Storage/IFormatSerializer.cs",
38+
"{workspaceRoot}/src/core/Flowthru.Core/Data/Serialization/OptOutOfPropertyPlannerAttribute.cs",
39+
"{workspaceRoot}/src/core/Flowthru.Core/Data/Storage/Format/JsonFormatSerializer.cs",
40+
"{workspaceRoot}/src/extensions/Flowthru.Extensions.Csv/Data/Storage/Format/CsvFormatSerializer.cs",
41+
"{workspaceRoot}/src/extensions/Flowthru.Extensions.Excel/Data/Storage/Format/ExcelFormatSerializer.cs",
42+
"{workspaceRoot}/src/extensions/Flowthru.Extensions.Parquet/Data/Storage/Format/ParquetFormatSerializer.cs",
43+
"{workspaceRoot}/scripts/_test/capability-matrix.cs"
3844
],
39-
"outputs": [ "{workspaceRoot}/docs/reference/src" ],
45+
"outputs": [ "{workspaceRoot}/docs/reference/extensions/capability-matrix.md" ],
4046
"options": {
4147
"commands": [
42-
"echo 'Docs Build Complete!'"
48+
"dotnet run scripts/_test/capability-matrix.cs --verbosity quiet"
4349
],
50+
"cwd": "{workspaceRoot}",
4451
"parallel": false
4552
}
53+
},
54+
"build": {
55+
"//": "Public docs build barrel. Composes private _build-* subtargets via dependsOn — each subtarget owns its own input/output footprint and caches independently. Adding a new MD generator (e.g., a future schema-gallery or diagnostic-id catalog) is a new _build-<name> private subtarget plus one line here. Mirrors the tests:test pattern.",
56+
"executor": "nx:noop",
57+
"dependsOn": [
58+
"_build-reference",
59+
"_build-capability-matrix"
60+
]
4661
}
4762
}
4863
}
Lines changed: 36 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,38 @@
11
# Flowthru Format Extension Capability Matrix
22

3-
This document is **auto-generated** from each format extension's `IFormatSerializer<TRow>.RowFeatures` declaration. Do not edit by hand — the `_test:capability-matrix-freshness` meta-test fails on drift.
3+
This document is **auto-generated** from each format extension's `IFormatBase<TRow>.RowFeatures` declaration and which capability segments it implements (`IFormatRowReader<TRow>`, `IFormatRowWriter<TRow>`, `IFormatStreamReader<TRow>`). Do not edit by hand — the `_test:capability-matrix-freshness` meta-test fails on drift.
44

5-
Regenerate locally via `nx run tests:_test:capability-matrix-freshness` or directly via the `Flowthru.Tools.CapabilityMatrix` tool.
5+
Regenerate locally via `nx run tests:_test:capability-matrix-freshness`, `nx run docs:build`, or directly via `dotnet run scripts/_test/capability-matrix.cs`.
6+
7+
## Universal baseline
8+
9+
All four formats round-trip the universal row-shape baseline:
10+
11+
- CLR primitives (`int`, `string`, `bool`, `double`, `decimal`, …)
12+
- BCL scalar structs (`Guid`, `DateTime`, `TimeSpan`, `DateTimeOffset`, …)
13+
- `Nullable<T>` value types and nullable reference types
14+
- `[SerializedLabel("…")]` field-name mapping
15+
- `[SerializedEnum("…")]` enum value mapping
16+
- `required` members and positional-record activation
17+
18+
These features are intrinsic to the planner's classification cascade and don't vary across formats. The matrix below tracks capabilities **on top of** that baseline — features where format-by-format support genuinely differs.
619

720
## Row-shape Features
821

9-
Each format declares which row-shape features it round-trips. A `` cell means the format claims support and the corresponding kit conformance fixture (under `tests/helpers/Flowthru.Tests.Kits/Fixtures/`) round-trips successfully. A `` cell means the format declares the feature unsupported — kit fixtures requiring that feature skip vacuously for this format.
22+
Each format declares which row-shape features it round-trips on top of the universal baseline. Cell semantics:
1023

11-
| Format | IScalar wrappers | byte[] columns | Nested rows |
12-
|---|:---:|:---:|:---:|
13-
| **CSV** (Flowthru.Extensions.Csv) ||||
14-
| **Excel** (Flowthru.Extensions.Excel) ||||
15-
| **Parquet** (Flowthru.Extensions.Parquet) ||||
16-
| **JSON** (Flowthru.Core (built-in)) ||||
24+
- **``** — format claims support; the matching kit conformance fixture round-trips successfully.
25+
- **``** — format claims false; could be implemented but isn't. Tracked as a follow-up; kit fixtures requiring the feature skip vacuously.
26+
- **``** — structurally not applicable; the format's generic constraint (`where TRow : IFlatSchema`) prevents the schema shape from compiling. The matching fixture cannot be wired against this format.
27+
28+
| Format | Schema shape | IScalar wrappers | Nested rows |
29+
|---|---|:---:|:---:|
30+
| **CSV** (Flowthru.Extensions.Csv) | Flat-only |||
31+
| **Excel** (Flowthru.Extensions.Excel) | Flat-only |||
32+
| **Parquet** (Flowthru.Extensions.Parquet) | Flat-only |||
33+
| **JSON** (Flowthru.Core (built-in)) | Flat or nested |||
34+
35+
Primitive-level format mechanics (`byte[]` blobs handled as base64/binary, timezone semantics on `DateTimeOffset`, etc.) are intrinsic to each format's underlying serialization library and aren't tracked here.
1736

1837
## Property Mapping
1938

@@ -30,10 +49,16 @@ Format extensions are expected to consume Core's `PropertyMappingPlanner` for pe
3049

3150
Medium-level capabilities of each format. See `Flowthru.Core.Data.Capabilities.StorageTraits` for the full surface.
3251

52+
**Read / Write / Stream columns** carry two signals. Phase D (capability-segmented interfaces) split the format surface into `IFormatRowReader<TRow>`, `IFormatRowWriter<TRow>`, and `IFormatStreamReader<TRow>` (a sub-interface of the row reader, marking bounded-memory decoding). A format that does not implement a segment is *structurally* incapable of that operation — the absence is enforced by the type system, not a runtime trait flag. A format that implements the segment but reports `Traits.CanWrite = false` (etc.) is *runtime*-disabled.
53+
54+
- **``** — segment implemented and runtime trait permits.
55+
- **``** — segment not implemented (structural / compile-time signal). Calling code paths against the missing segment fail at compile time.
56+
- **``** — segment implemented but runtime trait reports unavailable (e.g., medium pointed at a read-only file system).
57+
3358
| Format | Read | Write | Stream | Append | Transactional |
3459
|---|:---:|:---:|:---:|:---:|:---:|
3560
| **CSV** ||||||
36-
| **Excel** || | |||
61+
| **Excel** || | |||
3762
| **Parquet** ||||||
38-
| **JSON** ||| |||
63+
| **JSON** ||| |||
3964

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
SOURCE_TYPE=repo
2+
SOURCE_ADDRESS=https://github.com/akkadotnet/akka.net.git
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
SOURCE_TYPE=repo
2+
SOURCE_ADDRESS=https://github.com/CommunityToolkit/dotnet.git
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
SOURCE_TYPE=repo
2+
SOURCE_ADDRESS=https://github.com/dapr/dotnet-sdk.git
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
SOURCE_TYPE=repo
2+
SOURCE_ADDRESS=https://github.com/MassTransit/MassTransit.git
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
SOURCE_TYPE=repo
2+
SOURCE_ADDRESS=https://github.com/microsoft/codecoverage.git
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
SOURCE_TYPE=repo
2+
SOURCE_ADDRESS=https://github.com/dotnet/orleans.git

docs/reference/src/core/Flowthru.Core/Flowthru.Core.Data.Storage.ComposedStorageAdapter-2.md

Lines changed: 37 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,9 @@ as explicit interface implementations to avoid polluting the base interface.
8686

8787
### <a id="Flowthru_Core_Data_Storage_ComposedStorageAdapter_2__ctor_Flowthru_Core_Data_Storage_IStorageMedium_Flowthru_Core_Data_Storage_IFormatSerializer__1__Flowthru_Core_Data_Storage_IContainerAdapter__0__1__"></a> ComposedStorageAdapter\(IStorageMedium, IFormatSerializer<TRow\>, IContainerAdapter<TContainer, TRow\>\)
8888

89-
Creates a new composed storage adapter.
89+
Creates a new composed storage adapter from a write-capable format serializer.
90+
Backward-compatible entry point: any <xref href="Flowthru.Core.Data.Storage.IFormatSerializer%601" data-throw-if-not-resolved="false"></xref> is
91+
both a reader and a writer and is wired into both segments.
9092

9193
```csharp
9294
public ComposedStorageAdapter(IStorageMedium medium, IFormatSerializer<TRow> format, IContainerAdapter<TContainer, TRow> container)
@@ -96,15 +98,46 @@ public ComposedStorageAdapter(IStorageMedium medium, IFormatSerializer<TRow> for
9698

9799
`medium` [IStorageMedium](Flowthru.Core.Data.Storage.IStorageMedium.md)
98100

99-
The storage medium (file, memory, etc.)
101+
The storage medium (file, memory, etc.).
100102

101103
`format` [IFormatSerializer](Flowthru.Core.Data.Storage.IFormatSerializer\-1.md)<TRow\>
102104

103-
The format serializer (CSV, JSON, etc.)
105+
The full-duplex format serializer (CSV, JSON, Parquet).
104106

105107
`container` [IContainerAdapter](Flowthru.Core.Data.Storage.IContainerAdapter\-2.md)<TContainer, TRow\>
106108

107-
The container adapter (IEnumerable, IDataView, etc.)
109+
The container adapter (IEnumerable, IDataView, etc.).
110+
111+
### <a id="Flowthru_Core_Data_Storage_ComposedStorageAdapter_2__ctor_Flowthru_Core_Data_Storage_IStorageMedium_Flowthru_Core_Data_Storage_IFormatRowReader__1__Flowthru_Core_Data_Storage_IFormatRowWriter__1__Flowthru_Core_Data_Storage_IContainerAdapter__0__1__"></a> ComposedStorageAdapter\(IStorageMedium, IFormatRowReader<TRow\>, IFormatRowWriter<TRow\>?, IContainerAdapter<TContainer, TRow\>\)
112+
113+
Creates a new composed storage adapter with separate reader and writer segments
114+
(Phase D capability-segmented interfaces). Read-only formatse.g.,
115+
<code>ExcelFormatSerializer</code> implementing only <xref href="Flowthru.Core.Data.Storage.IFormatRowReader%601" data-throw-if-not-resolved="false"></xref> —
116+
pass <a href="https://learn.microsoft.com/dotnet/csharp/language-reference/keywords/null">null</a> for the writer; the resulting adapter exposes
117+
<xref href="Flowthru.Core.Data.Storage.ComposedStorageAdapter%602.Traits" data-throw-if-not-resolved="false"></xref>.<xref href="Flowthru.Core.Data.Capabilities.StorageTraits.CanWrite" data-throw-if-not-resolved="false"></xref> as <a href="https://learn.microsoft.com/dotnet/csharp/language-reference/builtin-types/bool">false</a>
118+
and <xref href="Flowthru.Core.Data.Storage.ComposedStorageAdapter%602.Save(%600)" data-throw-if-not-resolved="false"></xref> fails fast.
119+
120+
```csharp
121+
public ComposedStorageAdapter(IStorageMedium medium, IFormatRowReader<TRow> reader, IFormatRowWriter<TRow>? writer, IContainerAdapter<TContainer, TRow> container)
122+
```
123+
124+
#### Parameters
125+
126+
`medium` [IStorageMedium](Flowthru.Core.Data.Storage.IStorageMedium.md)
127+
128+
The storage medium.
129+
130+
`reader` [IFormatRowReader](Flowthru.Core.Data.Storage.IFormatRowReader\-1.md)<TRow\>
131+
132+
Format reader segment. Required.
133+
134+
`writer` [IFormatRowWriter](Flowthru.Core.Data.Storage.IFormatRowWriter\-1.md)<TRow\>?
135+
136+
Format writer segment. <a href="https://learn.microsoft.com/dotnet/csharp/language-reference/keywords/null">null</a> for read-only formats.
137+
138+
`container` [IContainerAdapter](Flowthru.Core.Data.Storage.IContainerAdapter\-2.md)<TContainer, TRow\>
139+
140+
The container adapter.
108141

109142
## Properties
110143

0 commit comments

Comments
 (0)