diff --git a/evidence/compatibility-environment-v1.10.17.json b/evidence/compatibility-environment-v1.10.17.json index 7bf377b..dc65397 100644 --- a/evidence/compatibility-environment-v1.10.17.json +++ b/evidence/compatibility-environment-v1.10.17.json @@ -55,7 +55,7 @@ { "id": "native-framing-draft", "reference": "spec/v1.9/iicp-framing.md", - "sha256": "803a0a20620df53c8bbcc7534d05e8ddd391d0d3d55752541bc1478764e914cf" + "sha256": "75a11f6d5c75f2ee77827989d2180ff98add5c4b44ae979f8503a567e8fc1bf4" } ], "identity_and_security_profiles": [ diff --git a/research/native-ai-infrastructure/fixtures/native-framing-fixture-manifest-v1.json b/research/native-ai-infrastructure/fixtures/native-framing-fixture-manifest-v1.json index db4bcc0..b03a58e 100644 --- a/research/native-ai-infrastructure/fixtures/native-framing-fixture-manifest-v1.json +++ b/research/native-ai-infrastructure/fixtures/native-framing-fixture-manifest-v1.json @@ -5,7 +5,7 @@ { "path": "native-framing-v1.json", "fixture_version": "1.0.0-draft", - "sha256": "795516349af7b8b1167357f12add10e56b467b80d1441c898dd48c97f3da1672" + "sha256": "945c5086f0f7173beb7708478a36be74c0a4256ca4a4efd1a855e0e0057c3376" } ] } diff --git a/research/native-ai-infrastructure/fixtures/native-framing-v1.json b/research/native-ai-infrastructure/fixtures/native-framing-v1.json index fb2993b..46b9daf 100644 --- a/research/native-ai-infrastructure/fixtures/native-framing-v1.json +++ b/research/native-ai-infrastructure/fixtures/native-framing-v1.json @@ -1,7 +1,7 @@ { "fixture_version": "1.0.0-draft", "status": "implementation-backed-pre-ratification", - "purpose": "Cross-implementation native framing vectors for the current ordered-stream binding. They cover bounded frame decoding only; dispatch, TLS, lifecycle, experimental relay opcodes, logical fragmentation and unsupported QUIC behavior are outside this fixture.", + "purpose": "Cross-implementation native framing vectors for the current ordered-stream binding. They cover bounded frame decoding and the fail-closed stable task-session type boundary. Dispatch direction, TLS, lifecycle, dedicated experimental relay sessions, logical fragmentation and unsupported QUIC behavior remain outside this fixture.", "frame": { "framing_version": 1, "header_bytes": 12, @@ -48,6 +48,33 @@ "max_payload_bytes": 16777216, "length_semantics": "payload_bytes_excluding_12_byte_header" }, + "stable_task_profile": { + "status": "implementation_backed_pre_ratification", + "accepted_message_types": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 13, + 14 + ], + "conflicted_message_types": [ + 11, + 12 + ], + "conflict": "0x0B/0x0C are CONTROL/ADVERTISE in the draft registry but RELAY_BIND/RELAY_ACK in maintained relay experiments; stable task sessions reject both bytes before proportional allocation.", + "relay_boundary": "Experimental relay sessions remain isolated on their dedicated transport and do not count as stable task-profile conformance.", + "extension_boundary": "0xF0-0xFE require negotiated extension state; the current stable task profile negotiates none and rejects them before proportional allocation.", + "production_security_disposition": "open_qualify_or_exclude", + "plaintext_scope": "development_only", + "stable_claim": "not_admitted" + }, "scenarios": [ { "name": "ping_empty", @@ -137,5 +164,76 @@ "reason": "payload_too_large" } } + ], + "stable_task_type_scenarios": [ + { + "name": "init_is_in_stable_task_profile", + "message_type": 1, + "expected": { + "outcome": "accept" + } + }, + { + "name": "call_is_in_stable_task_profile", + "message_type": 5, + "expected": { + "outcome": "accept" + } + }, + { + "name": "observe_is_in_stable_task_profile", + "message_type": 13, + "expected": { + "outcome": "accept" + } + }, + { + "name": "zero_is_invalid", + "message_type": 0, + "expected": { + "outcome": "reject", + "reason": "invalid_type" + } + }, + { + "name": "control_relay_bind_collision_is_rejected", + "message_type": 11, + "expected": { + "outcome": "reject", + "reason": "conflicted_type" + } + }, + { + "name": "advertise_relay_ack_collision_is_rejected", + "message_type": 12, + "expected": { + "outcome": "reject", + "reason": "conflicted_type" + } + }, + { + "name": "future_core_type_is_unknown", + "message_type": 15, + "expected": { + "outcome": "reject", + "reason": "unknown_type" + } + }, + { + "name": "unnegotiated_private_extension_is_rejected", + "message_type": 240, + "expected": { + "outcome": "reject", + "reason": "unsupported_extension" + } + }, + { + "name": "maximum_type_is_invalid", + "message_type": 255, + "expected": { + "outcome": "reject", + "reason": "invalid_type" + } + } ] } diff --git a/spec/v1.9/iicp-framing.md b/spec/v1.9/iicp-framing.md index 213bdff..637632a 100644 --- a/spec/v1.9/iicp-framing.md +++ b/spec/v1.9/iicp-framing.md @@ -1,7 +1,7 @@ # IICP Binary Framing Layer **Document**: `spec/iicp-framing.md` -**Version**: 0.1.10-draft +**Version**: 0.1.11-draft **Date**: 2026-08-28 **Status**: Draft — NOT YET RATIFIED (see §12) **Authority**: Protocol Steward @@ -81,6 +81,10 @@ Receivers that receive an unknown Type in the range 0x0F–0xEF MUST send a `CLOSE` frame with error code `unknown_type` and close the connection. Receivers that receive a Type in the CUSTOM range (0xF0–0xFE) and have not negotiated that type via INIT MUST send a `CLOSE` frame with error code `unsupported_extension`. +The receiver MUST validate the Type after the fixed header and before allocating +or waiting for a buffer proportional to Length. The current stable task-session +profile accepts `0x01`–`0x0A` and `0x0D`–`0x0E`. It rejects `0x0B`/`0x0C` with +`conflicted_type` until the pre-ratification relay collision in §3 is resolved. #### Flags (1 byte) @@ -162,6 +166,12 @@ The 256-value type byte is partitioned as follows: > support for any of these four messages on `0x0B`/`0x0C`. Existing relay use > remains experimental and cannot count as stable framing conformance. +The maintained relay experiment uses a dedicated session implementation. Its +`RELAY_BIND`/`RELAY_ACK` frames MUST NOT enter the stable task-session decoder, +and rejection of `0x0B`/`0x0C` there does not alter the isolated experimental +relay behavior. Type direction and connection-state checks remain additional to +this header-level allowlist. + --- ## 4. CBOR Payload Encoding @@ -362,7 +372,7 @@ terminal RESPONSE requirement. | 2 | message | tstr | MAY | Human-readable description | | 3 | session_id | tstr | MAY | Session being closed | -Standard close reason codes: `graceful`, `unknown_type`, `unsupported_extension`, +Standard close reason codes: `graceful`, `unknown_type`, `unsupported_extension`, `conflicted_type`, `frame_too_large`, `payload_too_large`, `version_mismatch`, `auth_failed`, `idle_timeout`, `protocol_error`. @@ -743,6 +753,7 @@ security principle: fail closed, fail cheap, fail loudly (log at warn level). | Version unknown and peer rejected downgrade | Version negotiation §6 | Send CLOSE(version_mismatch); close connection | `version_mismatch` | | Type = 0x00 (RESERVED) | Header parse | Send CLOSE(invalid_type); reject | `invalid_type` | | Type = 0xFF (RESERVED) | Header parse | Send CLOSE(invalid_type); reject | `invalid_type` | +| Type = 0x0B or 0x0C in the stable task profile | Header parse | Reject before proportional allocation; dedicated experimental relay sessions remain separate | `conflicted_type` | | Type in 0x0F–0xEF (future IICP reserved) | Header parse | Send CLOSE(unknown_type) if not forward-compat; MUST NOT process payload | `unknown_type` | | Type in 0xF0–0xFE and no capability negotiated | Header parse | Send CLOSE(unsupported_extension); reject | `unsupported_extension` | | Flags: unknown bits set | Header parse | MUST ignore unknown flag bits; process frame normally | — (extensibility rule) | @@ -1150,3 +1161,4 @@ mechanisms are complementary. | 0.1.8-draft | 2026-08-08 | Protocol Steward | Resolved the base-versus-profile RESPONSE contradiction: base CALLs remain buffered and single-terminal; negotiated service-lifecycle streaming uses incremental partials plus one terminal response. Clarified accounting, HTTP fallback, QUIC closure, sequence ownership and fragmentation terminology. No base-frame or required-field change. | | 0.1.9-draft | 2026-08-08 | Protocol Steward | Specifies the negotiated lifecycle-envelope location in RESPONSE key 13 and OBSERVE `data`, including call/task correlation, status/finality mapping and native negative vectors. Key 13 remains profile-only; no base-frame or required-field change. | | 0.1.10-draft | 2026-08-28 | Protocol Steward | Aligns the draft with the transport decision: native TCP remains optional, QUIC is research-only, Length is payload-only, 64 KiB is not a stream/datagram boundary, logical fragmentation is not stable, reassembly defaults are true maxima, deterministic-CBOR receive scope is explicit, and the unresolved `0x0B`/`0x0C` relay collision is recorded. | +| 0.1.11-draft | 2026-08-28 | Protocol Steward | Defines the finite stable task-session type allowlist, requires type rejection before proportional allocation, isolates dedicated experimental relay opcodes, and keeps production native TCP at the open qualify-or-exclude security gate. | diff --git a/spec/v1.9/release-integrity-manifest.json b/spec/v1.9/release-integrity-manifest.json index 624ba14..aec7a21 100644 --- a/spec/v1.9/release-integrity-manifest.json +++ b/spec/v1.9/release-integrity-manifest.json @@ -57,7 +57,7 @@ "ecosystem/repositories.json": "ab3565df543623420465a11f5284fe8ae64b554289be070fbcb480042deb0e9e", "evidence/clean-room-interoperability-record-v1.json": "907a769090908ec1169c04f8e276396bb644765c0cb98bee735320467c449bc9", "evidence/compatibility-environment-v1.10.16.json": "9571cefa0823d21433bc092bac4bb8c537d074bcf03c36be3c7f9704ddb5d994", - "evidence/compatibility-environment-v1.10.17.json": "e7b65bf9b93b976ec7a6e2f28e8f06b1e8857b862a5558b0eb485d21d3f28c0a", + "evidence/compatibility-environment-v1.10.17.json": "10abf903bcc011c86d0dd150150d178c60bf3c506dd3590c9a406267cdd9a112", "evidence/external-participation-campaign-v1.json": "f19f85b4767b008c8754d82c959143426d3d502cb1b2e79b82e5d15cc80a2a9f", "evidence/newcomer-validation-record-v1.json": "5fad1491f8c85a0517164b5aed0a13d7992747b2f211efd27bdec7e287ec5181", "evidence/public-evidence-access-v1.json": "fc06068de5bb842e182cf22626abfb9f23bdc299d058cfed255d4828f5b37e8b", @@ -93,8 +93,8 @@ "registry/schemas/translate-v1-input.json": "197067000ec2acfeba9ab463c61d733008a302a4a836bebc5ba02eec228823e4", "registry/source-classification.json": "fe01d4cc22394fd74c1b734aaf469e5f6201b8229d792f30ca570c6a124f44b1", "research/RESEARCH.md": "323dd757c9871aba21bf5933715ee746745fbecfc615d709f046deca7a6b58c5", - "research/native-ai-infrastructure/fixtures/native-framing-fixture-manifest-v1.json": "decfb39bb293877689197ba259f3c1b8a09ec290b6bb523edc119937ce3f3112", - "research/native-ai-infrastructure/fixtures/native-framing-v1.json": "795516349af7b8b1167357f12add10e56b467b80d1441c898dd48c97f3da1672", + "research/native-ai-infrastructure/fixtures/native-framing-fixture-manifest-v1.json": "d48cd3528563bec9796115289a6fe1391646a145cbc9b67dcdd3d84c1fda9c9b", + "research/native-ai-infrastructure/fixtures/native-framing-v1.json": "945c5086f0f7173beb7708478a36be74c0a4256ca4a4efd1a855e0e0057c3376", "research/native-ai-infrastructure/fixtures/service-profiles-v1.json": "69fa2693d44a7d596cdabf433b284c07d27f4ab27433e2936c137de444cdaa9f", "research/pre-normative-profiles/README.md": "5a25e689919e373bdd2cb9cd3fbf63ac1ed51b7a8729c9b5efcbc5ff3012a219", "research/pre-normative-profiles/fixtures/README.md": "b69f8f0eb066d41f027798d012f00a8938d80e62a4a1b2797a53634cfc282185", @@ -163,7 +163,7 @@ "spec/v1.9/iicp-dir.md": "3b626dea03ed7d4906cca12e766e9077a464eae319f461b0439deff41f8799ef", "spec/v1.9/iicp-extensions.md": "c1e0443c2e365abe54c7503dcdeb59a1efdc25d48faafee4429e4aed13f87ce9", "spec/v1.9/iicp-federated-directory.md": "ebb7c237111da0c3e5baa376426ea1b3720b33fe76bc894fda3fcbba5355f3f6", - "spec/v1.9/iicp-framing.md": "803a0a20620df53c8bbcc7534d05e8ddd391d0d3d55752541bc1478764e914cf", + "spec/v1.9/iicp-framing.md": "75a11f6d5c75f2ee77827989d2180ff98add5c4b44ae979f8503a567e8fc1bf4", "spec/v1.9/iicp-identity-slot.md": "837342eb79ef6be07b93f1a6b8041accfa23fd6a9bf858cafd4470d97d70f14c", "spec/v1.9/iicp-mcp-binding.md": "eac9dce25ab74ed7685a05b0c9dbb286e8c0b5fef96c80e51b10109d72fcf6c6", "spec/v1.9/iicp-provider-admission-profile.md": "5ae8f4ff485fe939e7d61c405ea1209ea63125f9a3e048bda0440bd552e9f364", @@ -206,7 +206,7 @@ "tools/check_identity_evidence_layering.py": "6ec6e752944db65559867490f7e7479875380692760356f7f585effa90526a07", "tools/check_intent_registry.py": "58103bc020f2609ead76a4d52db7b6cebdabbba6a5f01ccb909c9b0dd154855f", "tools/check_intent_registry_schema.py": "d868bb821d4dc278dbddefe8e449033d9f20c4e243c1843142e2047ab0429c8c", - "tools/check_native_framing_fixtures.py": "5c263e21d328fdfe9d116c2b64afc6bf39045ab03fdd34f7f382d700dfb5acb0", + "tools/check_native_framing_fixtures.py": "499e3b941be7ff373687443ae674e6804bbbd722437d20b2d47971c161365c3b", "tools/check_newcomer_validation_record.py": "4cf42b3059a82066c7276f69be11b991994280d58e9799eebcddc0fc661cacd9", "tools/check_operator_onboarding_recovery.py": "c7b8023b918a3ba936b4dbd7f41760b6d2f798daa399140b335ff0f63b0a5536", "tools/check_profile_security_candidate.py": "505afe261598c302ebef4f743f0ba45eef6c7e401c5f80c1ce0c7f5239e3d9e9", diff --git a/tools/check_native_framing_fixtures.py b/tools/check_native_framing_fixtures.py index 2d5f454..7249340 100644 --- a/tools/check_native_framing_fixtures.py +++ b/tools/check_native_framing_fixtures.py @@ -70,6 +70,46 @@ def main() -> int: errors.append(f"missing required negative vector: {name}") elif scenario.get("expected", {}).get("reason") != reason: errors.append(f"{name}: expected reason must be {reason}") + task_profile = data.get("stable_task_profile", {}) + if task_profile.get("accepted_message_types") != [*range(1, 11), 13, 14]: + errors.append("stable task accepted types must be 0x01-0x0A and 0x0D-0x0E") + if task_profile.get("conflicted_message_types") != [11, 12]: + errors.append("stable task conflicted types must be 0x0B and 0x0C") + if task_profile.get("production_security_disposition") != "open_qualify_or_exclude": + errors.append("production security disposition must remain open qualify-or-exclude") + if task_profile.get("plaintext_scope") != "development_only": + errors.append("plaintext native TCP must remain development-only") + if task_profile.get("stable_claim") != "not_admitted": + errors.append("native TCP must not be admitted to the stable claim by this fixture") + type_scenarios = data.get("stable_task_type_scenarios", []) + type_names = [scenario.get("name") for scenario in type_scenarios] + if len(type_names) != len(set(type_names)): + errors.append("stable task type scenario names must be unique") + by_type = {scenario.get("message_type"): scenario for scenario in type_scenarios} + required_types = { + 0: "invalid_type", + 1: None, + 5: None, + 11: "conflicted_type", + 12: "conflicted_type", + 13: None, + 15: "unknown_type", + 240: "unsupported_extension", + 255: "invalid_type", + } + for message_type, reason in required_types.items(): + scenario = by_type.get(message_type) + if scenario is None: + errors.append(f"missing stable task type vector: 0x{message_type:02x}") + continue + expected_result = scenario.get("expected", {}) + expected_outcome = "accept" if reason is None else "reject" + if expected_result.get("outcome") != expected_outcome: + errors.append( + f"type 0x{message_type:02x}: expected outcome must be {expected_outcome}" + ) + if expected_result.get("reason") != reason: + errors.append(f"type 0x{message_type:02x}: expected reason must be {reason}") for copy in args.copy: if not copy.is_file(): errors.append(f"missing SDK fixture copy: {copy}")