CultLib/contracts/cultnet/cultnet.error.schema.json

46 lines
2.8 KiB
JSON
Raw Normal View History

{
"$schema": "https://json-schema.org/draft/2020-12/schema",
Consolidate CultNet schema contracts into CultLib/contracts/cultnet REC-032 commit 1: move the canonical 33 TS + witness-artifact-bundle schema files (34 total) into runtime-neutral CultLib/contracts/cultnet, move the interop-note schema (and delete the zero-consumer discovery-* schemas per D3, tagged parked/cultnet-discovery-contracts) into contracts/cultnet/interop, and delete the 27 C# and 24 Rust duplicate copies after confirming byte-for-byte equivalence (only cultnet.snapshot-request differs: TS carries shardId/shardEpoch, a known drift already resolved in favor of the TS shape). Rewrite every $id from https://github.com/GameCult/cultnet-ts/contracts/ and .../cultnet-ts/integration/contracts/ to https://github.com/GameCult/CultLib/contracts/cultnet/(interop/); give the two shard-catalog schemas URL ids per D1, replacing the bare cultnet.shard_catalog_*.v0 identifiers; leave ghostlight.agent-state's Ghostlight-owned $id untouched per D5. Repoint every runtime's load path and id literal at the new location: C# csproj EmbeddedResource + LogicalName, Rust include_str! paths, TS contracts.ts imports + swarm-contracts manifest/tooling + package.json files/prepack, and the id/path literals in the C#, Rust, Python and Kotlin interop tests and peers. Python and Kotlin still build their own schema JSON in-process (D2); only their base constants, id literals, and (for Kotlin) contentHash literals were swapped. Every Kotlin contentHash was recomputed from the final canonical files using the runtime's own stable-stringify + SHA-256 function; all matched the planner's precomputed values except cultnet.schema-catalog-response, where the planner's proposed value did not match recomputation and the freshly computed value was used instead. REC-032, decisions D1/D2/D3/D5. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-13 17:27:41 +02:00
"$id": "https://github.com/GameCult/CultLib/contracts/cultnet/cultnet.error.schema.json",
"title": "CultNet Error Message",
Fix batch 4 (R-X, S-4/S-10): the error schema matches the wire, and the validator refuses a keyword it does not implement CultNetErrorMessage is a MessagePack-CSharp map-mode object, so every declared key is written on the wire, nil included - the same fact R-S already established for the raw document header. cultnet.error.schema.json was missing routingHint entirely and typed code/details as always-present non-null values; Soul's P7 found real bytes failing it on exactly this. routingHint, code and details are now `required`, with nullable types matching CultNetErrorMessage/CultNetErrorDetails. A new test decodes real bytes for all four refusal codes (selection_invalid, cursor_stale, cursor_invalid, reference_outside_target) against the schema. MiniJsonSchemaValidator: - implements minimum, maximum, maxLength and maxItems, which were declared in committed schemas (fieldPredicate's number pattern, selection.limit, ...) but silently never checked; - anchors `pattern` to a full match (Index==0 && Length==value.Length) instead of Regex.IsMatch's "search anywhere", so .NET's `$` (which, unlike ECMA-262's, matches immediately before one trailing newline even without RegexOptions.Multiline) can no longer let e.g. "5\n" pass a schema author wrote as "exactly one digit"; - refuses a schema node that uses a keyword this validator gives no constraint semantics to, instead of silently ignoring it. Running every committed contracts/cultnet/*.schema.json schema through this found 12 such uses, none reached by any existing test: `allOf`/`if`/`then`/`else` in cultnet.database-change-raw.schema.json, and `uniqueItems` (six places) plus one `anyOf` in the cultmesh.verse-catalog-*.schema.json pair. contentEncoding, $schema/$id/$defs/title/description/default and the x-cult-runtime-type vendor extension are treated as metadata with no constraint semantics to implement, not refused. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-22 21:12:23 +02:00
"description": "R-X (docs/cultnet-selection-cut.md, fix batch 4): CultNetErrorMessage is a MessagePack-CSharp map-mode object, so every declared key is written on the wire, nil included - routingHint, code and details are `required` here the same as cultnet.raw-document-header.schema.json's nullable fields, not optional just because a given refusal leaves them null.",
"type": "object",
"required": [
"schemaVersion",
Fix batch 4 (R-X, S-4/S-10): the error schema matches the wire, and the validator refuses a keyword it does not implement CultNetErrorMessage is a MessagePack-CSharp map-mode object, so every declared key is written on the wire, nil included - the same fact R-S already established for the raw document header. cultnet.error.schema.json was missing routingHint entirely and typed code/details as always-present non-null values; Soul's P7 found real bytes failing it on exactly this. routingHint, code and details are now `required`, with nullable types matching CultNetErrorMessage/CultNetErrorDetails. A new test decodes real bytes for all four refusal codes (selection_invalid, cursor_stale, cursor_invalid, reference_outside_target) against the schema. MiniJsonSchemaValidator: - implements minimum, maximum, maxLength and maxItems, which were declared in committed schemas (fieldPredicate's number pattern, selection.limit, ...) but silently never checked; - anchors `pattern` to a full match (Index==0 && Length==value.Length) instead of Regex.IsMatch's "search anywhere", so .NET's `$` (which, unlike ECMA-262's, matches immediately before one trailing newline even without RegexOptions.Multiline) can no longer let e.g. "5\n" pass a schema author wrote as "exactly one digit"; - refuses a schema node that uses a keyword this validator gives no constraint semantics to, instead of silently ignoring it. Running every committed contracts/cultnet/*.schema.json schema through this found 12 such uses, none reached by any existing test: `allOf`/`if`/`then`/`else` in cultnet.database-change-raw.schema.json, and `uniqueItems` (six places) plus one `anyOf` in the cultmesh.verse-catalog-*.schema.json pair. contentEncoding, $schema/$id/$defs/title/description/default and the x-cult-runtime-type vendor extension are treated as metadata with no constraint semantics to implement, not refused. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-22 21:12:23 +02:00
"error",
"routingHint",
"code",
"details"
],
"additionalProperties": false,
"properties": {
"schemaVersion": { "const": "cultnet.error.v0" },
Fix batch 3: R-N wire refusal codes, R-P one authorizer id, R-T removal/cites gaps R-N: cultnet.error.v0 gains additive code/details fields (contracts/cultnet). CultNetErrorMessage grows ForSelectionInvalid/ForCursor/ForReferenceOutsideTarget factories; both C# servers (CultNetDatabaseServer for snapshot+live, CultNetDatabaseSubscriptionServer) use them at every existing catch site, plus two sites that previously let the exception escape uncaught instead of reaching the peer (CultNetDatabaseServer's v1 subscribe snapshot branch, CultNetDatabaseSubscriptionServer's Subscribe around CreateProjectedSnapshot). CultNetSelectionCursorException now carries AsOf/Current for cursor_stale. R-P: CultNetDatabaseSubscriptionServer.CreateMatchedRecord (the live fast path) authorized against descriptor.SchemaId; the snapshot path (CreateProjectedSnapshot) already authorized against the wire id. Both now call the same CultNetDocumentRegistry.WireSchemaId (made internal, was private) so one id reaches the authorizer on the snapshot, live and reconcile paths alike. R-T(a): CultNetSelectionEvaluator.MatchesSchemaKeysFields no longer reads a Removed change's (always-null) document against Fields - it matches on keys/schemas alone and treats a field predicate as unknown instead of throwing TryGetIndexValue(null). R-T(b): EnsureWithinDeclaredTarget no longer skips the out-of-target check when TargetType is null; it checks against every registered leaf (unconstrained is a real, checked target set, not a bypass). CultCache's ResolveReferenceTarget also now infers the target from a many reference's CultRecordRef<T> element when no explicit [CultReference(typeof(...))] is declared, which was the one remaining source of a null TargetType reaching that check on a real, testable path. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-22 19:44:18 +02:00
"error": { "type": "string", "minLength": 1 },
Fix batch 4 (R-X, S-4/S-10): the error schema matches the wire, and the validator refuses a keyword it does not implement CultNetErrorMessage is a MessagePack-CSharp map-mode object, so every declared key is written on the wire, nil included - the same fact R-S already established for the raw document header. cultnet.error.schema.json was missing routingHint entirely and typed code/details as always-present non-null values; Soul's P7 found real bytes failing it on exactly this. routingHint, code and details are now `required`, with nullable types matching CultNetErrorMessage/CultNetErrorDetails. A new test decodes real bytes for all four refusal codes (selection_invalid, cursor_stale, cursor_invalid, reference_outside_target) against the schema. MiniJsonSchemaValidator: - implements minimum, maximum, maxLength and maxItems, which were declared in committed schemas (fieldPredicate's number pattern, selection.limit, ...) but silently never checked; - anchors `pattern` to a full match (Index==0 && Length==value.Length) instead of Regex.IsMatch's "search anywhere", so .NET's `$` (which, unlike ECMA-262's, matches immediately before one trailing newline even without RegexOptions.Multiline) can no longer let e.g. "5\n" pass a schema author wrote as "exactly one digit"; - refuses a schema node that uses a keyword this validator gives no constraint semantics to, instead of silently ignoring it. Running every committed contracts/cultnet/*.schema.json schema through this found 12 such uses, none reached by any existing test: `allOf`/`if`/`then`/`else` in cultnet.database-change-raw.schema.json, and `uniqueItems` (six places) plus one `anyOf` in the cultmesh.verse-catalog-*.schema.json pair. contentEncoding, $schema/$id/$defs/title/description/default and the x-cult-runtime-type vendor extension are treated as metadata with no constraint semantics to implement, not refused. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-22 21:12:23 +02:00
"routingHint": {
"description": "Optional shard routing detail for an authority failure. Null for every selection/cursor refusal code (R-N).",
"type": ["object", "null"],
"additionalProperties": false,
"required": ["shard", "reason"],
"properties": {
"shard": { "type": ["object", "null"] },
"reason": { "type": "string" }
}
},
Fix batch 3: R-N wire refusal codes, R-P one authorizer id, R-T removal/cites gaps R-N: cultnet.error.v0 gains additive code/details fields (contracts/cultnet). CultNetErrorMessage grows ForSelectionInvalid/ForCursor/ForReferenceOutsideTarget factories; both C# servers (CultNetDatabaseServer for snapshot+live, CultNetDatabaseSubscriptionServer) use them at every existing catch site, plus two sites that previously let the exception escape uncaught instead of reaching the peer (CultNetDatabaseServer's v1 subscribe snapshot branch, CultNetDatabaseSubscriptionServer's Subscribe around CreateProjectedSnapshot). CultNetSelectionCursorException now carries AsOf/Current for cursor_stale. R-P: CultNetDatabaseSubscriptionServer.CreateMatchedRecord (the live fast path) authorized against descriptor.SchemaId; the snapshot path (CreateProjectedSnapshot) already authorized against the wire id. Both now call the same CultNetDocumentRegistry.WireSchemaId (made internal, was private) so one id reaches the authorizer on the snapshot, live and reconcile paths alike. R-T(a): CultNetSelectionEvaluator.MatchesSchemaKeysFields no longer reads a Removed change's (always-null) document against Fields - it matches on keys/schemas alone and treats a field predicate as unknown instead of throwing TryGetIndexValue(null). R-T(b): EnsureWithinDeclaredTarget no longer skips the out-of-target check when TargetType is null; it checks against every registered leaf (unconstrained is a real, checked target set, not a bypass). CultCache's ResolveReferenceTarget also now infers the target from a many reference's CultRecordRef<T> element when no explicit [CultReference(typeof(...))] is declared, which was the one remaining source of a null TargetType reaching that check on a real, testable path. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-22 19:44:18 +02:00
"code": {
"description": "Machine-readable refusal code (R-N). Additive: a v0 peer that does not know this field ignores it. The set is a closed enum: Rust and TypeScript refuse a message whose code is not listed, so adding a code is one coordinated change across every runtime (this schema, the C# factory, the Rust CultNetErrorCode, and a captured-bytes case for each).",
Fix batch 4 (R-X, S-4/S-10): the error schema matches the wire, and the validator refuses a keyword it does not implement CultNetErrorMessage is a MessagePack-CSharp map-mode object, so every declared key is written on the wire, nil included - the same fact R-S already established for the raw document header. cultnet.error.schema.json was missing routingHint entirely and typed code/details as always-present non-null values; Soul's P7 found real bytes failing it on exactly this. routingHint, code and details are now `required`, with nullable types matching CultNetErrorMessage/CultNetErrorDetails. A new test decodes real bytes for all four refusal codes (selection_invalid, cursor_stale, cursor_invalid, reference_outside_target) against the schema. MiniJsonSchemaValidator: - implements minimum, maximum, maxLength and maxItems, which were declared in committed schemas (fieldPredicate's number pattern, selection.limit, ...) but silently never checked; - anchors `pattern` to a full match (Index==0 && Length==value.Length) instead of Regex.IsMatch's "search anywhere", so .NET's `$` (which, unlike ECMA-262's, matches immediately before one trailing newline even without RegexOptions.Multiline) can no longer let e.g. "5\n" pass a schema author wrote as "exactly one digit"; - refuses a schema node that uses a keyword this validator gives no constraint semantics to, instead of silently ignoring it. Running every committed contracts/cultnet/*.schema.json schema through this found 12 such uses, none reached by any existing test: `allOf`/`if`/`then`/`else` in cultnet.database-change-raw.schema.json, and `uniqueItems` (six places) plus one `anyOf` in the cultmesh.verse-catalog-*.schema.json pair. contentEncoding, $schema/$id/$defs/title/description/default and the x-cult-runtime-type vendor extension are treated as metadata with no constraint semantics to implement, not refused. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-22 21:12:23 +02:00
"type": ["string", "null"],
"enum": [null, "selection_invalid", "cursor_stale", "cursor_invalid", "reference_outside_target", "variant_unsupported", "unowned_schema"]
Fix batch 3: R-N wire refusal codes, R-P one authorizer id, R-T removal/cites gaps R-N: cultnet.error.v0 gains additive code/details fields (contracts/cultnet). CultNetErrorMessage grows ForSelectionInvalid/ForCursor/ForReferenceOutsideTarget factories; both C# servers (CultNetDatabaseServer for snapshot+live, CultNetDatabaseSubscriptionServer) use them at every existing catch site, plus two sites that previously let the exception escape uncaught instead of reaching the peer (CultNetDatabaseServer's v1 subscribe snapshot branch, CultNetDatabaseSubscriptionServer's Subscribe around CreateProjectedSnapshot). CultNetSelectionCursorException now carries AsOf/Current for cursor_stale. R-P: CultNetDatabaseSubscriptionServer.CreateMatchedRecord (the live fast path) authorized against descriptor.SchemaId; the snapshot path (CreateProjectedSnapshot) already authorized against the wire id. Both now call the same CultNetDocumentRegistry.WireSchemaId (made internal, was private) so one id reaches the authorizer on the snapshot, live and reconcile paths alike. R-T(a): CultNetSelectionEvaluator.MatchesSchemaKeysFields no longer reads a Removed change's (always-null) document against Fields - it matches on keys/schemas alone and treats a field predicate as unknown instead of throwing TryGetIndexValue(null). R-T(b): EnsureWithinDeclaredTarget no longer skips the out-of-target check when TargetType is null; it checks against every registered leaf (unconstrained is a real, checked target set, not a bypass). CultCache's ResolveReferenceTarget also now infers the target from a many reference's CultRecordRef<T> element when no explicit [CultReference(typeof(...))] is declared, which was the one remaining source of a null TargetType reaching that check on a real, testable path. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-22 19:44:18 +02:00
},
"details": {
Fix batch 4 (R-X, S-4/S-10): the error schema matches the wire, and the validator refuses a keyword it does not implement CultNetErrorMessage is a MessagePack-CSharp map-mode object, so every declared key is written on the wire, nil included - the same fact R-S already established for the raw document header. cultnet.error.schema.json was missing routingHint entirely and typed code/details as always-present non-null values; Soul's P7 found real bytes failing it on exactly this. routingHint, code and details are now `required`, with nullable types matching CultNetErrorMessage/CultNetErrorDetails. A new test decodes real bytes for all four refusal codes (selection_invalid, cursor_stale, cursor_invalid, reference_outside_target) against the schema. MiniJsonSchemaValidator: - implements minimum, maximum, maxLength and maxItems, which were declared in committed schemas (fieldPredicate's number pattern, selection.limit, ...) but silently never checked; - anchors `pattern` to a full match (Index==0 && Length==value.Length) instead of Regex.IsMatch's "search anywhere", so .NET's `$` (which, unlike ECMA-262's, matches immediately before one trailing newline even without RegexOptions.Multiline) can no longer let e.g. "5\n" pass a schema author wrote as "exactly one digit"; - refuses a schema node that uses a keyword this validator gives no constraint semantics to, instead of silently ignoring it. Running every committed contracts/cultnet/*.schema.json schema through this found 12 such uses, none reached by any existing test: `allOf`/`if`/`then`/`else` in cultnet.database-change-raw.schema.json, and `uniqueItems` (six places) plus one `anyOf` in the cultmesh.verse-catalog-*.schema.json pair. contentEncoding, $schema/$id/$defs/title/description/default and the x-cult-runtime-type vendor extension are treated as metadata with no constraint semantics to implement, not refused. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-22 21:12:23 +02:00
"description": "Code-specific structured detail (R-N). Every field is populated only for the code that defines it; the others are null, not omitted.",
"type": ["object", "null"],
Fix batch 3: R-N wire refusal codes, R-P one authorizer id, R-T removal/cites gaps R-N: cultnet.error.v0 gains additive code/details fields (contracts/cultnet). CultNetErrorMessage grows ForSelectionInvalid/ForCursor/ForReferenceOutsideTarget factories; both C# servers (CultNetDatabaseServer for snapshot+live, CultNetDatabaseSubscriptionServer) use them at every existing catch site, plus two sites that previously let the exception escape uncaught instead of reaching the peer (CultNetDatabaseServer's v1 subscribe snapshot branch, CultNetDatabaseSubscriptionServer's Subscribe around CreateProjectedSnapshot). CultNetSelectionCursorException now carries AsOf/Current for cursor_stale. R-P: CultNetDatabaseSubscriptionServer.CreateMatchedRecord (the live fast path) authorized against descriptor.SchemaId; the snapshot path (CreateProjectedSnapshot) already authorized against the wire id. Both now call the same CultNetDocumentRegistry.WireSchemaId (made internal, was private) so one id reaches the authorizer on the snapshot, live and reconcile paths alike. R-T(a): CultNetSelectionEvaluator.MatchesSchemaKeysFields no longer reads a Removed change's (always-null) document against Fields - it matches on keys/schemas alone and treats a field predicate as unknown instead of throwing TryGetIndexValue(null). R-T(b): EnsureWithinDeclaredTarget no longer skips the out-of-target check when TargetType is null; it checks against every registered leaf (unconstrained is a real, checked target set, not a bypass). CultCache's ResolveReferenceTarget also now infers the target from a many reference's CultRecordRef<T> element when no explicit [CultReference(typeof(...))] is declared, which was the one remaining source of a null TargetType reaching that check on a real, testable path. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-22 19:44:18 +02:00
"additionalProperties": false,
Fix batch 4 (R-X, S-4/S-10): the error schema matches the wire, and the validator refuses a keyword it does not implement CultNetErrorMessage is a MessagePack-CSharp map-mode object, so every declared key is written on the wire, nil included - the same fact R-S already established for the raw document header. cultnet.error.schema.json was missing routingHint entirely and typed code/details as always-present non-null values; Soul's P7 found real bytes failing it on exactly this. routingHint, code and details are now `required`, with nullable types matching CultNetErrorMessage/CultNetErrorDetails. A new test decodes real bytes for all four refusal codes (selection_invalid, cursor_stale, cursor_invalid, reference_outside_target) against the schema. MiniJsonSchemaValidator: - implements minimum, maximum, maxLength and maxItems, which were declared in committed schemas (fieldPredicate's number pattern, selection.limit, ...) but silently never checked; - anchors `pattern` to a full match (Index==0 && Length==value.Length) instead of Regex.IsMatch's "search anywhere", so .NET's `$` (which, unlike ECMA-262's, matches immediately before one trailing newline even without RegexOptions.Multiline) can no longer let e.g. "5\n" pass a schema author wrote as "exactly one digit"; - refuses a schema node that uses a keyword this validator gives no constraint semantics to, instead of silently ignoring it. Running every committed contracts/cultnet/*.schema.json schema through this found 12 such uses, none reached by any existing test: `allOf`/`if`/`then`/`else` in cultnet.database-change-raw.schema.json, and `uniqueItems` (six places) plus one `anyOf` in the cultmesh.verse-catalog-*.schema.json pair. contentEncoding, $schema/$id/$defs/title/description/default and the x-cult-runtime-type vendor extension are treated as metadata with no constraint semantics to implement, not refused. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-22 21:12:23 +02:00
"required": ["field", "value", "asOf", "current"],
Fix batch 3: R-N wire refusal codes, R-P one authorizer id, R-T removal/cites gaps R-N: cultnet.error.v0 gains additive code/details fields (contracts/cultnet). CultNetErrorMessage grows ForSelectionInvalid/ForCursor/ForReferenceOutsideTarget factories; both C# servers (CultNetDatabaseServer for snapshot+live, CultNetDatabaseSubscriptionServer) use them at every existing catch site, plus two sites that previously let the exception escape uncaught instead of reaching the peer (CultNetDatabaseServer's v1 subscribe snapshot branch, CultNetDatabaseSubscriptionServer's Subscribe around CreateProjectedSnapshot). CultNetSelectionCursorException now carries AsOf/Current for cursor_stale. R-P: CultNetDatabaseSubscriptionServer.CreateMatchedRecord (the live fast path) authorized against descriptor.SchemaId; the snapshot path (CreateProjectedSnapshot) already authorized against the wire id. Both now call the same CultNetDocumentRegistry.WireSchemaId (made internal, was private) so one id reaches the authorizer on the snapshot, live and reconcile paths alike. R-T(a): CultNetSelectionEvaluator.MatchesSchemaKeysFields no longer reads a Removed change's (always-null) document against Fields - it matches on keys/schemas alone and treats a field predicate as unknown instead of throwing TryGetIndexValue(null). R-T(b): EnsureWithinDeclaredTarget no longer skips the out-of-target check when TargetType is null; it checks against every registered leaf (unconstrained is a real, checked target set, not a bypass). CultCache's ResolveReferenceTarget also now infers the target from a many reference's CultRecordRef<T> element when no explicit [CultReference(typeof(...))] is declared, which was the one remaining source of a null TargetType reaching that check on a real, testable path. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-22 19:44:18 +02:00
"properties": {
"field": { "description": "selection_invalid: the selection field that failed. variant_unsupported: \"subscriptionId\", when a subscription was ended. unowned_schema: \"schemaId\".", "type": ["string", "null"] },
"value": { "description": "selection_invalid: the offending value, when there is one string worth naming. variant_unsupported: the id of the subscription that ended. unowned_schema: the schema id no shard owns.", "type": ["string", "null"] },
Fix batch 4 (R-X, S-4/S-10): the error schema matches the wire, and the validator refuses a keyword it does not implement CultNetErrorMessage is a MessagePack-CSharp map-mode object, so every declared key is written on the wire, nil included - the same fact R-S already established for the raw document header. cultnet.error.schema.json was missing routingHint entirely and typed code/details as always-present non-null values; Soul's P7 found real bytes failing it on exactly this. routingHint, code and details are now `required`, with nullable types matching CultNetErrorMessage/CultNetErrorDetails. A new test decodes real bytes for all four refusal codes (selection_invalid, cursor_stale, cursor_invalid, reference_outside_target) against the schema. MiniJsonSchemaValidator: - implements minimum, maximum, maxLength and maxItems, which were declared in committed schemas (fieldPredicate's number pattern, selection.limit, ...) but silently never checked; - anchors `pattern` to a full match (Index==0 && Length==value.Length) instead of Regex.IsMatch's "search anywhere", so .NET's `$` (which, unlike ECMA-262's, matches immediately before one trailing newline even without RegexOptions.Multiline) can no longer let e.g. "5\n" pass a schema author wrote as "exactly one digit"; - refuses a schema node that uses a keyword this validator gives no constraint semantics to, instead of silently ignoring it. Running every committed contracts/cultnet/*.schema.json schema through this found 12 such uses, none reached by any existing test: `allOf`/`if`/`then`/`else` in cultnet.database-change-raw.schema.json, and `uniqueItems` (six places) plus one `anyOf` in the cultmesh.verse-catalog-*.schema.json pair. contentEncoding, $schema/$id/$defs/title/description/default and the x-cult-runtime-type vendor extension are treated as metadata with no constraint semantics to implement, not refused. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-22 21:12:23 +02:00
"asOf": { "description": "cursor_stale: the cursor's own minted asOf.", "type": ["integer", "null"], "minimum": 0 },
"current": { "description": "cursor_stale: the answering server's current asOf.", "type": ["integer", "null"], "minimum": 0 }
Fix batch 3: R-N wire refusal codes, R-P one authorizer id, R-T removal/cites gaps R-N: cultnet.error.v0 gains additive code/details fields (contracts/cultnet). CultNetErrorMessage grows ForSelectionInvalid/ForCursor/ForReferenceOutsideTarget factories; both C# servers (CultNetDatabaseServer for snapshot+live, CultNetDatabaseSubscriptionServer) use them at every existing catch site, plus two sites that previously let the exception escape uncaught instead of reaching the peer (CultNetDatabaseServer's v1 subscribe snapshot branch, CultNetDatabaseSubscriptionServer's Subscribe around CreateProjectedSnapshot). CultNetSelectionCursorException now carries AsOf/Current for cursor_stale. R-P: CultNetDatabaseSubscriptionServer.CreateMatchedRecord (the live fast path) authorized against descriptor.SchemaId; the snapshot path (CreateProjectedSnapshot) already authorized against the wire id. Both now call the same CultNetDocumentRegistry.WireSchemaId (made internal, was private) so one id reaches the authorizer on the snapshot, live and reconcile paths alike. R-T(a): CultNetSelectionEvaluator.MatchesSchemaKeysFields no longer reads a Removed change's (always-null) document against Fields - it matches on keys/schemas alone and treats a field predicate as unknown instead of throwing TryGetIndexValue(null). R-T(b): EnsureWithinDeclaredTarget no longer skips the out-of-target check when TargetType is null; it checks against every registered leaf (unconstrained is a real, checked target set, not a bypass). CultCache's ResolveReferenceTarget also now infers the target from a many reference's CultRecordRef<T> element when no explicit [CultReference(typeof(...))] is declared, which was the one remaining source of a null TargetType reaching that check on a real, testable path. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-22 19:44:18 +02:00
}
}
}
}