Skip to content

Commit e97bf30

Browse files
committed
Validate canonical keys and complete document mutation acceptance
1 parent fabff69 commit e97bf30

38 files changed

Lines changed: 12943 additions & 259 deletions

‎Directory.Packages.props‎

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@
1313
<PackageVersion Include="ManagedCode.Communication.Orleans" Version="10.2.6" />
1414
<PackageVersion Include="ManagedCode.TimeSeries" Version="10.0.3" />
1515
<PackageVersion Include="ManagedCode.Storage.FileSystem" Version="10.0.13" />
16-
<PackageVersion Include="ManagedCode.Storage.Orleans" Version="10.0.13" />
1716
<PackageVersion Include="ManagedCode.Orleans.Graph" Version="10.0.6" />
1817
<PackageVersion Include="ModelContextProtocol.AspNetCore" Version="2.2.0" />
1918
<PackageVersion Include="ModelContextProtocol.Core" Version="2.2.0" />

‎README.md‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,8 @@ The server uses ZoneTree.FullTextSearch for bounded derived text candidates whil
4747

4848
A bounded lossless time-series chunk codec has [development evidence](docs/implementation/sample-chunk-codec-development-2026-10-03.json) from full Aspire unit/scalar suites and matched native-codec controls. Canonical chunk storage, rewrite/recovery and RF3 qualification remain in progress under KL-078.
4949

50+
Canonical key validation and persisted document permissions have [development evidence](docs/implementation/keycodec-crud-development-2026-10-04.json): 2,889 tests pass in each Aspire normal/scalar suite and 228 recovery tests pass, with 1,000 unique atomic process-crash trials. This includes invariant decimal keys, malformed-input bounds, owned storage bytes, CRUD revisions, index rollback and isolated field/row authorization controls. Complete delivered-source Linux and Docker/Aspire RF3 qualification remain pending.
51+
5052
## Get started
5153

5254
Install the .NET SDK selected in [global.json](global.json) and Docker, then build from the repository root:

‎docs/ADR/ADR-005-canonical-keyspace-codec.md‎

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,3 +32,77 @@ flowchart LR
3232
Store --> Range[Deterministic bounded range]
3333
Codec --> Golden[Golden compatibility vectors]
3434
```
35+
36+
## 2026-10-04 v1 validation and ownership completion
37+
38+
KL-007 adds REQ-KEYCODEC-001..004 and AC-KEYCODEC-001..004 in
39+
[StorageRecovery](../Features/StorageRecovery.md). This freezes validation of
40+
the existing format; every byte emitted for a supported valid existing key
41+
remains unchanged. Identity digests, native aliases/Ids, data epoch6, journals,
42+
RF3 and public wire DTOs remain unchanged. No format migration is introduced.
43+
44+
The v1 type order is missing10, null11, bool20, int64/normalized int30, decimal31,
45+
finite double32, UTC timestamp40, UTF-8 string50, and byte array60 (hex tags).
46+
Guid is an existing input convenience normalized to its lowercase `N` string;
47+
it is not a separate tagged type. Timestamps normalize their comparison identity
48+
to UTC; decimal scale and floating signed zero normalize numeric identity.
49+
Different numeric tags remain different types. Preserve these mappings and
50+
UTF-8 ordinal ordering, including zero escaping and composite prefix ordering.
51+
52+
| Boundary | Frozen result |
53+
|---|---|
54+
| Encode0..256 components | Exact existing valid writer bytes; empty composite is version byte1 |
55+
| Encode257+ components | ResourceExhausted before buffer creation or component encoding |
56+
| Unsupported CLR component | Existing UnsupportedCapability |
57+
| Nonfinite double or invalid UTF-16 string | Validation with a constant safe message |
58+
| Empty/unknown key version | Existing FormatUnsupported |
59+
| Invalid/truncated tag, scalar, escape, UTF-8, timestamp or decimal | Corruption with a constant safe message |
60+
| Decode257+ components | Corruption before decoding component257 |
61+
| Noncanonical negative-zero double or nonzero-form decimal zero | Corruption; these bytes are never emitted by the valid v1 writer |
62+
| Noncanonical decimal leading/trailing zero, exponent, precision or scale | Corruption; reject rounding/underflow rather than aliasing another canonical key |
63+
64+
Decimal decoding must accept every value emitted by the existing writer,
65+
including its extrema and all scales0..28. Bound canonical nonzero exponents
66+
and significant digits before parsing; use the BCL decimal parser with exact
67+
representability checks. Both parse-text construction and parsing must use
68+
InvariantCulture: a changed CurrentCulture or custom non-ASCII negative sign
69+
cannot change a durable key's meaning. Pin literal positive/negative fractional
70+
decimal v1 vectors and decode them under such a culture, restoring the caller's
71+
culture in finally. TASK-KEYCODEC-CULTURE assigns only this invariant construction
72+
and new KeyCodecCultureContractTests to query_wave Luna/high before the final
73+
normal/scalar/recovery source freeze. Do not add a duplicate decimal serializer or re-encode
74+
every decoded key. Keep successful hot paths free of new full-envelope copies.
75+
Invalid UTF text and timestamps use narrow validation; never retain offending
76+
data in an error or relax existing malformed guards.
77+
78+
The immutable payload-envelope requirement means storage captures independently
79+
owned key/value bytes at staging and preserves their committed content across
80+
caller/pool reuse and returned-result mutation. Its existing carriers are
81+
StorageMutation and KeyValueRecord with permanent aliases/Ids. The read result
82+
is an independently owned copy; this does not promise a deeply immutable CLR
83+
backing array. Test the actual authoritative storage isolation, native envelope
84+
roundtrip and reopen, rather than changing those carriers or adding a new API.
85+
86+
Ordered implementation: root freezes this contract, feature mapping and task
87+
graph; query_wave Luna/high owns only KeyCodec.cs, KeyCodecDecimal.cs,
88+
KeyCodecReadPrimitives.cs and cohesive new Features/StorageRecovery/KeyCodec*
89+
validation helpers if needed; lifecycle_wave Luna/high owns new KeyCodec*
90+
UnitTests/Features/StorageRecovery corpus, malformed, golden and real-store
91+
ownership tests; root reviews every diff and joins full build/formatter,
92+
Aspire normal/scalar/recovery and exact-source Linux/RF3 originals.
93+
Existing10,000 decimal cases and all golden vectors remain intact; add an
94+
independent10,000 generated mixed-type/composite corpus and literal corruption
95+
vectors. No skips, mock provider, suppressed diagnostic or altered tolerance.
96+
97+
Rollout is a homogeneous current-format build after qualification. No canonical
98+
writer output changes, rewrite or dual-version reader is allowed. Rollback
99+
restores prior validation while preserving valid durable keys; its malformed
100+
exception leaks remain explicitly unqualified. SDK/MCP/frontend changes N/A:
101+
unchanged database operations. Dependency repair N/A: the defect is KeyLoad-owned.
102+
103+
The [2026-10-04 local receipt](../implementation/keycodec-crud-development-2026-10-04.json)
104+
records14 new KeyCodec cases and4 original cases in unchanged full Aspire
105+
normal/scalar suites at2889/2889 each, recovery228/228 and1000 unique actual
106+
atomic process cuts. Literal fractional decimal goldens pass under invariant
107+
and custom-sign cultures. Exact delivered-source Linux/RF3 originals, endurance,
108+
power-loss and measured acceleration remain separate required gates.

‎docs/ADR/ADR-060-native-internal-serialization.md‎

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -470,3 +470,39 @@ retain every tracked base file and only its declared overlays. Its results prove
470470
only that image, not a green shared checkout or delivered GitHub qualification.
471471
Images containing cancelled R19 overlays remain historical evidence and cannot
472472
qualify the final five-source delivery. Required exact-source CI/RF3 gates remain.
473+
474+
## 2026-10-04 same-body nullable allocation warmup
475+
476+
TASK-IS-ALLOCATION-WARM-BODY is accepted under the owner's complete104-task
477+
acceptance instruction. The original full Aspire normal report again measured
478+
Normalize262480B and Require262144B on unchanged production serialization source,
479+
while all other2885 cases passed. Scheduling isolation alone therefore does not
480+
establish a repeatable warmed measurement. Preserve that original failed report;
481+
no specific CLR/GC/cache cause is proven by its336B difference.
482+
483+
Root owns only NativeWireSupportedScalarAllocationTests and this mapped
484+
REQ/AC-IS-PERF005 verification correction. Its nullable control uses two named,
485+
non-inlined synchronous measurement helpers, each containing the original4096
486+
iterations, existing types and current-thread allocation counters. Warm those
487+
EXACT helper bodies32 times before measuring each once. This supersedes only the
488+
old warmup-loop shape: it warms the actual measured IL instead of a separate
489+
short loop. Terminal0B control, exact nullable equality, last-normalized type,
490+
NotInParallel exclusion and all production code remain unchanged. Both counters,
491+
data creation and assertions retain their original synchronous/outside-window
492+
boundaries. No tolerance, inequality, min selection, retries, GC manipulation,
493+
runtime switch, skip or package replacement is accepted.
494+
495+
Review the one-file diff, run the strict build/formatter/governance, then run the
496+
focused allocation control and complete normal/scalar/recovery suites through
497+
Aspire. Retain source/runtime before/after inventories and original reports;
498+
exact delivered-source Linux qualification remains separate. Rollback restores
499+
only the test helper/warmup shape. No persisted/public format or product boundary
500+
changes, so the existing ADR is sufficient.
501+
502+
The [2026-10-04 development receipt](../implementation/keycodec-crud-development-2026-10-04.json)
503+
retains the failed nullable allocation control and the same-body warmup repair.
504+
Both original exact controls pass in full Aspire normal/scalar2889/2889 suites;
505+
recovery228/228 passes with unchanged complete source/runtime inventories.
506+
No tolerance, product cache, runtime switch or allocation bound was changed.
507+
This is local development evidence; exact delivered-source Linux and RF3
508+
qualification and comparative performance remain required.

‎docs/Features/DocumentStorage.md‎

Lines changed: 35 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -34,9 +34,9 @@ The current root-level files are documented migration debt under ADR-032, not th
3434

3535
| Requirement | Measurable acceptance | Existing TUnit evidence or planned test |
3636
|---|---|---|
37-
| REQ-DSTORE-001: validate scoped CRUD, revisions, and document authority | AC-DSTORE-001 passes when create/read/replace/patch/delete produce monotone revisions, exact-CAS concurrency has one winner, and invalid/stale writes or direct mutation of event-authoritative resources are rejected without partial state. | Existing `ConcurrentCompareAndSwapHasOneWinner`; planned `DocumentCrudRevisionAuthorityAndValidationCases` for create/missing/delete/invalid JSON/authority matrix. CI qualification pending. |
38-
| REQ-DSTORE-002: maintain declared scalar indexes atomically | AC-DSTORE-002 passes when replacing/deleting a document removes its old keys, writes new keys, and a duplicate partition-unique value rejects the full mutation batch. | Existing `UniqueConflictRollsBackDocumentIndexEventAndEnqueue`, `AcMp003PointAndIndexDereferenceConsumeTheSameRawReadBudget`; planned persisted old/new index transition matrix. CI qualification pending. |
39-
| REQ-DSTORE-003: enforce row/field policy at every document boundary | AC-DSTORE-003 passes when unauthorized row writes/reads and protected field use fail or project according to policy; tenant or row ownership cannot be supplied to gain access. | Existing `NestedSensitiveFieldsAreOmittedAndAliasedPredicateAndSortAreDenied`, `RowScopeAndTenantCannotBeForged`; planned focused document CRUD authorization matrix if existing cases do not cover every mutation. CI qualification pending. |
37+
| REQ-DSTORE-001: validate scoped CRUD, revisions, and document authority | AC-DSTORE-001 passes when create/read/replace/patch/delete produce monotone revisions, exact-CAS concurrency has one winner, and invalid/stale writes or direct mutation of event-authoritative resources are rejected without partial state. | Existing `ConcurrentCompareAndSwapHasOneWinner`; actual `DocumentCrudRevisionTests` and `DocumentPutValidationAtomicityTests` cover create/missing/delete/invalid JSON/authority. Local full-suite evidence below; exact-source CI qualification pending. |
38+
| REQ-DSTORE-002: maintain declared scalar indexes atomically | AC-DSTORE-002 passes when replacing/deleting a document removes its old keys, writes new keys, and a duplicate partition-unique value rejects the full mutation batch. | Existing `UniqueConflictRollsBackDocumentIndexEventAndEnqueue`, `AcMp003PointAndIndexDereferenceConsumeTheSameRawReadBudget`; actual `DocumentScalarIndexMutationTests` covers persisted old/new index transitions and rollback. Local full-suite evidence below; exact-source CI qualification pending. |
39+
| REQ-DSTORE-003: enforce row/field policy at every document boundary | AC-DSTORE-003 passes when unauthorized row writes/reads and protected field use fail or project according to policy; tenant or row ownership cannot be supplied to gain access. | Existing `NestedSensitiveFieldsAreOmittedAndAliasedPredicateAndSortAreDenied`, `RowScopeAndTenantCannotBeForged`; actual field/row/tenant matrix plus isolated replacement-write and Delete-index-use controls. Local full-suite evidence below; exact-source CI qualification pending. |
4040
| REQ-DSTORE-004: share an atomic transaction domain with eligible events and queues | AC-DSTORE-004 passes when document + event + local enqueue commit together or all remain absent, same command retry returns the stored outcome, and identical partition-key text in unrelated domains stays isolated. | Existing `DocumentEventAndQueueCommitTogetherAndCommandRetryDoesNotRepeatEffects`, `UniqueConflictRollsBackDocumentIndexEventAndEnqueue`, `SameLiteralPartitionKeyCannotCrossTransactionDomains`. CI qualification pending. |
4141
| REQ-DSTORE-005: reuse transaction-scoped document images | AC-DSTORE-005 passes when one before-record lookup supplies CRUD and outbox; no final staged lookup/decode is required; exact bytes, revisions, tombstones, indexes, authorization, quotas and sequential same-ID mutations remain intact. | TASK-MP-007I in ADR-035; new real-store paired-size/counter and before/after/failure cases plus existing transaction/change-feed/recovery/RF3 regressions; GitHub evidence pending. |
4242

@@ -46,6 +46,37 @@ AtomicMutationApplication caller integration to the lead. Internal context/resul
4646
carriers stay under Features/DocumentStorage and within one atomic transaction.
4747
UI/SDK/MCP schema migration is N/A: public contracts and persisted bytes stay exact.
4848

49+
The2026-10-04 regression-completion stage maps AC-DSTORE-001 to
50+
DocumentCrudRevisionTests and DocumentPutValidationAtomicityTests, AC-DSTORE-002
51+
to DocumentScalarIndexMutationTests, and AC-DSTORE-003 to
52+
DocumentFieldMutationAuthorizationTests and DocumentRowTenantMutationAuthorizationTests.
53+
These use actual TestDatabase/ZoneTree and the existing contracts: no new product
54+
semantics or mutation DTO. Root owns this mapping and join; cluster_wave Luna/high
55+
owns only these new UnitTests/Features/DocumentStorage files and their cohesive
56+
fixture. Include duplicate JSON members, document-byte/depth bounds after an
57+
earlier staged indexed mutation, exact rollback, tombstone/recreate revisions,
58+
unique-index isolation, persisted field grants and healthy owner follow-up.
59+
60+
Field-write grants gate create/replacement/patch of protected fields. Whole-row
61+
Delete follows the existing DocumentsWrite capability and row-write policy,
62+
plus any index-field-use grant required for strict maintenance. It does not
63+
introduce a field-write requirement for whole-row deletion. This distinguishes
64+
the current lifecycle and field-mutation contracts in REQ-AUTH-006; neither
65+
client-supplied row ownership nor an administrator label establishes authority.
66+
67+
TASK-DSTORE-FIELD-MUTATION-ORACLES closes the remaining AC-DSTORE-003 boundaries
68+
with separate DocumentReplacementFieldAuthorizationTests and
69+
DocumentDeleteIndexAuthorizationTests. Replacement denial uses a principal that
70+
already has DocumentsWrite, field-read and indexed field-use grants, isolating the missing
71+
field-write grant; exact original revision/JSON/index entries remain unchanged,
72+
and a principal with both grants replaces successfully. Delete denial isolates
73+
the missing indexed field-use grant and preserves the live record/index; its
74+
allowed control has field-use but no field-write grant and produces the exact
75+
next tombstone revision while removing the index entry. These are existing
76+
persisted-policy semantics, not a public contract or schema change. cluster_wave
77+
Luna/high owns only the two new files; root reviews and integrates actual Aspire
78+
normal/scalar/recovery and exact delivered-source Linux/RF3 qualification.
79+
4980
## Flows and failure behavior
5081

5182
Positive: authorized valid JSON mutation passes catalog and CAS checks, updates document and affected indexes in one atomic command, and returns its committed revision/receipt. Negative: malformed JSON, stale CAS, denied row/field access, event-authoritative direct write, or unique collision rejects the operation. Edge: replacing indexed values removes old entries; delete creates a tombstone; patch of missing/deleted document fails; duplicate command identity is resolved by persisted outcome. Error responses must not disclose protected payload values. Query pages and index scans remain subject to the shared read budgets.
@@ -63,4 +94,4 @@ flowchart LR
6394
Commit --> Read[Authorized projected read or bounded query]
6495
```
6596

66-
Named tests are source mappings, not passing results. Product build, TUnit, process-recovery and Aspire RF3 qualification run only in GitHub Actions under the repository policy. Required official MCP parity through Aspire RF3 is pending; no MCP implementation or result is claimed. No document-specific UI, cross-partition unique constraint, or production-readiness claim is introduced by this specification.
97+
The [2026-10-04 development receipt](../implementation/keycodec-crud-development-2026-10-04.json) records8 new real-ZoneTree CRUD cases in full Aspire normal/scalar suites at2889/2889 each and recovery228/228, with unchanged source/runtime and1000 unique atomic process cuts. Local development verification is authorized through unified Aspire; delivered-source qualification still requires complete Linux GitHub original build/TUnit/recovery/Docker RF3 artifacts. Required official MCP parity through Aspire RF3 remains pending. Document-specific UI is N/A; cross-partition unique constraints and production readiness remain unqualified.

‎docs/Features/InternalSerialization.md‎

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,3 +96,11 @@ remain separate from the historical image that produced this pair.
9696
The owner cancelled the unrelated process-helper repair branch. This delivery
9797
contains only the admission shortcut and its four scalar regression files;
9898
source-image results containing cancelled helpers remain historical evidence.
99+
100+
The 2026-10-04 ADR060 verification correction warms the nullable allocation
101+
control's exact non-inlined synchronous measurement helpers32 times, using the
102+
same4096-iteration bodies subsequently measured once. Exact0B/equality and all
103+
production serialization semantics remain unchanged. The original full-suite
104+
336B baseline-only difference remains retained as a failed run; this correction
105+
requires fresh complete Aspire normal/scalar reports and exact-source Linux
106+
qualification before claiming the gate.

0 commit comments

Comments
 (0)