BAML for C 托管契约探针(ManagedContractProbe):公共类型与翻译证据的编译期验证指南
编程语言AI Agent编译器CLI人工智能【免费下载链接】bamlThe programming language for agents项目地址https://gitcode.com/gh_mirrors/ba/baml点击查看免费下载导读Baml.Bridge.ManagedContractProbe是 BAML C# 桥接层baml-bridge.NET 10 运行时内部的一组编译期设计证据探针用于在产物发布之前把 gate B5、B6、B10 尚未定案的托管契约证据optionality 与 nullability 的正交性、语义部分状态、不可变请求/客户端/媒体、SafeHandle 所有权、全部动态值种类与描述符身份、规范泛型绑定、生成代码注册、拥有型集合与字节、精确数值边界、显式不支持的 CLR 形状、环检测、冻结图限制编译并逐项验证。读完本文你将掌握该探针的验证矩阵、每个主题域的底层类型设计、关键常量与 ABI 数值以及如何在仓库中定位与复跑这些证据。探针的定位编译期证据而非最终运行时包ManagedContractProbe/README.md 开宗明义这是一个repository-only仅存在于仓库内的 .NET 10 可执行程序它编译compile的是 gate B5、B6、B10 的未解决unresolved托管契约证据。它与 baml-bridge 运行时说明 描述的正式运行时、NuGet 包是两层东西运行时baml-bridge是随 BAML CLI 生成的 C# 客户端共同发布的 .NET 10 托管运行时 原生资产面向osx-arm64、osx-x64、linux-arm64、linux-musl-arm64、linux-x64、linux-musl-x64、win-x64、win-arm64等 RID支持普通 JIT 与裁剪trimmed部署但不支持 NativeAOT以BAML0019失败构建。探针ManagedContractProbe及其同类 probe 是仓库内专用工程不对外发布职责是在设计阶段把尚存争议的托管契约钉死成可编译、可断言、可审计的证据。因此README 特别声明These definitions are compiled design evidence, not the final runtime package.这些定义是编译后的设计证据不是最终运行时包。相应地arity 3–32 的联合类型、生成的 V1 接缝seam、异常/取消身份、原生媒体还原、流生命周期、程序与原生引导等既有结论仍由仓库中其他探针保持权威本探针不越俎代庖。工程配置本身也体现了证据的苛刻性——Baml.Bridge.ManagedContractProbe.csproj 设置了net10.0LangVersion 14.0、Nullable enable、TreatWarningsAsErrors、Deterministic并且开启EnableTrimAnalyzer与IsTrimmable让任何警告、非确定性输出或裁剪分析问题都会直接失败编译。验证入口与检查清单Main 输出的契约摘要探针入口 Program.cs 依次执行七组验证最终输出一组keyvalue的契约摘要输出键断言值语义optional_nullableorthogonal_completeoptionality 与 nullability 正交且完整stream_statepending_incomplete_complete流状态三态Pending/Incomplete/Completemedia_values4x_url_bytes_base64_file_owned四类媒体的四种来源路径全部拥有数据http_requestimmutable_duplicate_headers_fresh_messages请求不可变、保留重复头、每次转换生成新消息client_retryimmutable_structural_checked客户端/重试策略不可变且结构相等handlesafe_clone_lease_dispose_identitySafeHandle 克隆/租约/释放身份正确baml_valuekinds_14_structural_typed14 种动态值种类结构相等且类型化descriptor_kindsunknown_plus_14_value_shapes描述符含 Unknown 加 14 种值形状descriptorsalias_literal_nominal_generic_union别名/字面量/名义/泛型/联合描述符dynamic_inspectionenum_class_union_public动态值的 enum/class/union 可公开检查dynamic_nullexplicit_nullable_onlyBAML null 只允许显式可空目标collectionsowned_readonly_canonical_maps拥有型只读集合与规范 mapgeneric_bindercanonical_and_fail_closed泛型绑定只接受规范闭包、失败关闭limitsdepth_collection_bytes_nodes_bigint_cycle深度/集合/字节/节点/bigint/环限制partial_projectionsemantic_states语义部分投影unsupported_clrexplicit不支持的 CLR 形状显式拒绝public_contractaudited公共契约经反射审计每组验证都有独立方法VerifyOptionalNullableAndPartialState、VerifyMediaAsync、VerifyRequestClientAndHandleAsync、VerifyDynamicValues、VerifyGenericBinder、VerifyLimitsAndCycles、VerifyPublicShapeInvariants并依赖两个自建断言助手Require(condition, message)与ExpectTException(Action)Program.cs#L1138-L1160任何违反都抛出带明确消息的InvalidOperationException。可选性与可空性正交的三种状态模型README 点名的第一个主题是optionality versus nullability可选性与可空性。探针以 OptionalNullableState.cs 中的两个只读结构体承载这个正交模型BamlOptionalT表达调用方是否提供了参数。核心是IsSet、Unset、FromValue(value)、TryGetValue(out T)并提供从T的隐式转换。未设置时访问Value抛InvalidOperationException。BamlNullableT表达值本身是否为空。核心是IsNull、Null、FromValue(value)、TryGetValue(out T)与模式匹配用的Match(onNull, onValue)两个委托均拒绝 null 参数。关键语义BamlNullableT.FromValue(null!)会坍缩为 null 态构造时hasValue value is not null这与BamlOptionalT.FromValue(null)截然不同——后者保持IsSet true且值为 null。VerifyOptionalNullableAndPartialState 逐条钉死了不变量显式默认值不坍缩BamlOptionallong.FromValue(0)必须IsSet true且Value 0绝不因为等于默认值而变成 unset显式 null 不坍缩BamlOptionalstring?.FromValue(null)必须IsSet true且值就是 null且! default组合保留全部状态BamlOptionalBamlNullablelong的default未提供、BamlNullable.Nulllong()提供了但为空、BamlNullable.FromValue(42L)提供了且有值三者必须能区分——这正是正交的含义流状态三态BamlStreamStateT的Pending尚未产生部分值、Incomplete携带部分值如par、Complete最终值可以是 null必须各自成立且Complete(null) Complete(null)。配套的语义部分投影证据在 Program.cs#L190-L206ResumePartial类型的RequiredWhenReady、DoneField为可空字段、NonNullPartial为必填子对象、WithState携带BamlStreamStatestring?——验证部分投影不会把未就绪字段错误地当成缺失标记。这一设计与 src/README.md 的运行时约定完全一致普通可空值位置在无歧义时直接用 C# 可空类型泛型可空引用绑定因为 CLR 无法区分typeof(string)与typeof(string?)必须使用BamlNullableT。不可变请求、客户端与媒体快照与脱敏HTTP 请求BamlHttpRequest在 VerifyRequestClientAndHandleAsync 中验证构造时请求 ID、方法、URL、头列表、content-type、body 字节即做拥有型快照——调用方随后headers.Clear()、修改body[0]均不影响快照ToHttpRequestMessage()每次返回全新的HttpRequestMessage与Content!ReferenceEquals(first, second)且重复头X-Trace: one、X-Trace: two被完整保留对第一个消息Dispose后再读第二个消息的 body结果不受影响。ToString()则脱敏 URL 中的secret与 body 内容。客户端与重试策略BamlRetryPolicy(maxRetries, initialDelayMilliseconds, maxDelayMilliseconds, multiplier)与BamlClient(name, type, subClients, retry, counter)均不可变探针把构造时传入的sourceChildren数组在事后篡改为mutatedclient.SubClients[0].Name仍须是child结构相等要求client.Equals(equivalent)且GetHashCode()一致。负的重试次数、非法BamlClientType值都会抛ArgumentOutOfRangeException。BamlClient.FromShorthand(name)得到BamlClientType.Primitive。四类媒体Media.cs 定义了共享的MediaPayloadFromUrl存 URL、FromBytes/FromBase64/FromFileAsync都复制字节为快照bytes?.ToArray()FromFileAsync在删除源文件后仍能取回完整内容eagerly owned。BamlImage/BamlAudio/BamlVideo/BamlPdf四类 sealed 值类型均提供FromUrl、FromBytes、FromBase64、FromFileAsync与TryGetUrl/TryGetBytes。VerifyMediaAsync 验证字节复制传入可变数组后篡改首字节取回的快照首字节仍是原始值URL 脱敏带?tokensecret#fragment的 URL 在结构化值中保留完整 URLvideoUrl.Contains(tokensecret)但ToString()不得泄露tokensecret或fragment文件急切拥有BamlPdf.FromFileAsync读入后删除文件TryGetBytes仍返回完整 PDF 头%PDF结构相等/哈希bytes 与 base64 同内容相等URL 与 bytes 形式不相等GetHashCode一致。SafeHandle 所有权克隆、租约、释放README 点名 SafeHandle ownership。探针在 Program.cs#L386-L432 中通过BamlHandle与原生引用计数表NativeReferenceTable.Releases验证Clone()产生独立所有者!ReferenceEquals(original, clone)但两个包装器指向同一原生资源租约返回相同 identityDispose()幂等且独立original.Dispose()两次后original.IsClosed但clone仍可租约对已关闭句柄Clone()抛ObjectDisposedException释放恰好一次两个包装器各自释放后原生表Releases精确 2并发安全64 个并发租约任务与 1 个Dispose竞态最终必须正常关闭且不产生悬挂访问。这也解释了 VerifyPublicShapeInvariants 的反射断言媒体类型与BamlHttpRequest不实现IDisposable无原生句柄而BamlHandle必须实现BamlHandle的任何公共属性类型都不得是IntPtr或SafeHandle原始原生键绝不暴露给应用BamlValue的任何公共属性也不得是裸object。动态值14 种种类与描述符身份DynamicValues.cs 定义了动态值载体与两种枚举枚举数值取值BamlValueKind : int0–13Null、Bool、Int、Float、BigInt、String、Bytes、List、Map、Enum、Class、Union、Media、HandleBamlTypeDescriptorKind : int0–14Unknown 上述 14 种形状一一对应、偏移 1BamlTypeDescriptor公开只读属性恰好为Kind、Fqn、Arguments、IsNullable、Alias、Literal有严格形状校验DynamicValues.cs#L151-L182Enum/Class/Handle必须携带 BAML FQNList恰好 1 个类型参数、Map恰好 2 个、Union至少 2 个、其余必须为空构造参数数组被复制为ReadOnlyCollection任何 null 参数都拒绝。VerifyDynamicValues 验证 14 种BamlValue工厂Null、Bool、Int、Float、BigInt、String、Bytes、List、Map、Enum、Class、Union、Media、Handle与Enum.GetValuesBamlValueKind()完全一一对应且顺序一致再验证描述符身份BamlValue.Alias(probe.UserId, ...)的Type.Alias必须保留普通BamlValue.String(fixed)的Alias/Literal为 nullLiteral元数据与载荷矛盾如Int(1)配01抛异常上下文无关解码不猜测带 alias/literal 的值TryGetstring()必须失败不能脱离出现点猜类型Union 的激活臂元数据与载荷矛盾必须抛异常null 的纪律BamlValue.Null只允许解码到BamlValue、long?、BamlNullablestring解码到object、string、Person、接口/具体集合一律拒绝BamlValue.Fromobject?(null)、Fromstring?(null)、FromListlong?(null)一律抛BamlTypeMappingException隐式 nulllong? input null经BamlValue.From必须得到BamlValue.Null同构容器不猜类型空列表/异构列表的类型参数为Unknown异构列表TryGetIReadOnlyListlong必须失败公共检查方法TryGetEnumVariant、TryGetClassFields返回拥有 wire 顺序的只读快照、TryGetUnion只能对正确种类返回 true否则返回 false 且 out 参数为 null。规范泛型绑定白名单闭包与显式拒绝Union2AndBinder.cs 中的BamlClrTypeBinder.Describe(type, path)实现了canonical generic binding支持的闭包bool、long、double、BigInteger、string、ReadOnlyMemorybyte、BamlValue→Unknown、四类媒体→Media、BamlHandle→Handle、已注册类型以及NullableT/BamlNullableT→ 内层描述符 IsNullabletrue、IReadOnlyListT→List、IReadOnlyDictionaryK,V→Map键必须是string、生成枚举或字面量否则拒绝。显式拒绝的 CLR 形状VerifyGenericBinder 中的完整列表short、int、uint、ulong、float、decimal、Listlong、Dictionarystring,long、long[]、object、JsonElement、JsonNode、JsonDocument、DateTime、DateTimeOffset、DateOnly、Guid、Uri、ValueTuplelong,string、BamlOptionallong、BamlUnionstring,long、BamlNullableBamlNullablestring冗余嵌套会坍缩 BAML null 状态、IReadOnlyDictionarylong,string非规范键。每一个失败都必须是BamlTypeMappingException且Path以$T开头。非规范数值的诊断替代int的CanonicalReplacement long、float的CanonicalReplacement double——诊断会明确告诉你该用什么规范类型而不是笼统报错。生成代码注册类型描述符与动态编解码器RegisterGeneratedTypes 演示了生成代码侧的注册模式BamlClrTypeBinder.Register(typeof(Person), personDescriptor)把 CLR 类型绑定到 BAML 描述符probe.Person、probe.Color、泛型probe.Box重复注册抛InvalidOperationExceptionBamlDynamicRegistry.RegisterPerson(encode, decode)注册名义类型的双向编解码器解码端要求载荷描述符匹配、可通过TryGetClassFields公开检查再映射回Person { Name, Age }BamlDynamicRegistry.RegisterCanonicalListlong()与RegisterCanonicalStringMaplong()注册规范集合编解码解码产物为ReadOnlyCollectionT/ReadOnlyDictionarystring,TDynamicValues.cs#L840-L978。注册之后BamlValue.From(person)/classValue.AsPerson()、BamlValue.From(listInput)/encodedList.AsIReadOnlyListlong()便可在反射之外工作——这正是 src/README.md 强调的生成代码的字段编解码器与工厂从不通过反射发现模型成员、可裁剪安全的实现证据。拥有型集合与精确数值边界BamlValue.List与BamlValue.Map构造即复制快照List 用ReadOnlyCollectionBamlValueMap 按键StringComparer.Ordinal排序、拒绝重复键与 null 值/键DynamicValues.cs#L270-L355。探针验证解码结果也是只读的对decodedList执行((IListlong)...)[0] 0抛NotSupportedException对decodedMap执行Add同样抛异常Program.cs#L581-L616。数值边界方面BAMLint映射到long且必须落在 BAML 范围[-2^62, 2^62-1]BamlInteger校验探针用BamlInteger.Max构造BamlValue.Intbigint的十六进制编码长度受BamlBigIntCodec.MaxHexLength (1 28) / 4 2约束超限抛BamlTypeMappingExceptionDynamicValues.cs#L823-L838。冻结图限制与环检测README 点名all frozen managed graph limits全部冻结的托管图限制。BamlValueLimits 定义了四组硬限制任何构造或图遍历都会校验限制值触发路径MaxDepth64嵌套深度超过即抛MaxCollectionItems1_000_000单集合元素数超限即抛MaxBytes64 × 1024 × 102464 MiB字节/媒体负载超限即抛MaxNodes2_000_000图总节点数超限即抛VerifyLimitsAndCycles 用两个特制测试桩验证限制必须在访问前拒绝CountOnlyValues只报告Count、不真正枚举触发MaxCollectionItems 1拒绝OversizeMemoryMemoryManagerbyte子类GetSpan直接抛触发MaxBytes 1拒绝——证明大小校验发生在读取内容之前。环检测由GeneratedCodecTraversalUnion2AndBinder.cs#L356-L387用引用相等集合完成Node.Next node的自环在遍历到$.next时抛出且异常Path精确为$.next、消息包含 cycle。公共表面审计反射钉死的 ABIVerifyPublicShapeInvariantsProgram.cs#L874-L1118用反射把公共契约审计到字节级BamlTypeDescriptor公开实例属性必须恰好是{Alias, Arguments, Fqn, IsNullable, Kind, Literal}且没有公开构造函数只能由内部工厂/生成代码构造BamlValue公开属性恰好{Kind, Null, Type}公开方法恰好{As, BigInt, Bool, Bytes, Equals, Float, From, GetHashCode, Int, List, Map, String, ToString, TryGet, TryGetClassFields, TryGetEnumVariant, TryGetUnion}Equals重载计一次同样无公开构造函数桥接层自有枚举的 ABI 数值被冻结BamlValueKind底层int且取值为 0–13BamlTypeDescriptorKind底层int且为 0–14BamlStreamStateKind底层int且为 0/1/2BamlClientType底层long且为 1/2/3——任何偏移都会使反射断言失败密封性BamlImage、BamlValue、BamlTypeDescriptor、BamlClient、BamlHttpRequest必须 sealed描述符泛型参数快照构造Box描述符后篡改源mutableArguments数组描述符的Arguments[0].Kind仍须是Int。Union 的二分证据与既有探针的分工Union2AndBinder.cs#L5-L141 只实现BamlUnionT0, T1arity 2并验证显式工厂FromT0/FromT1激活分支用内部caseIndex1/2区分default(BamlUnionT0,T1)caseIndex 0不合法IsT0/IsT1均为 false访问AsT0抛uninitializedMatch/Switch二分支函数式访问访问未激活分支抛InvalidOperationException内部编解码视图ActiveCaseForCodec1→0、2→1与ValueForCodec仅限生成代码使用公开面不暴露公开属性恰好{AsT0, AsT1, IsT0, IsT1}且没有CaseIndex/IsValid这类会泄露未初始化合法性的属性。这正是 README 分工声明的落点BamlUnion的 arity 2 形状由本探针钉死而arity 3–32 的联合、生成的 V1 接缝、异常/取消身份、原生媒体还原、流生命周期、程序/原生引导仍由仓库中既有的其他探针保持权威参见 bridge_csharp 测试目录 下的EnumDiscriminantProbe、FailureCancellationProbe、GeneratedCodeContractProbe、StreamMediaAbiProbe、ProgramBootstrapProbe、NuGetPackageSmoke等兄弟工程。如何查看与复跑证据探针是仓库内普通 .NET 工程可以像查看任何源码一样阅读 Program.cs 与同目录的 DynamicValues.cs、Media.cs、OptionalNullableState.cs、Union2AndBinder.cs。若本机具备 .NET 10 SDK 与 C# 14 编译器也可以在仓库内通过dotnet run工程已启用Deterministic与TreatWarningsAsErrors任何警告都会被当作错误执行该探针它不依赖任何外部 NuGet 包或原生二进制纯托管、自包含全部断言通过后返回退出码 0 并打印上文那张契约摘要表。需要提醒的是该探针是设计证据而非公开发行的 SDK 组件运行时契约的正式落地仍以 baml-bridge 运行时说明 与 BAML CLI 生成的baml_sdk/为准——探针的作用是让这些契约在进入最终产物之前先以最严格、最可复现的方式被编译并钉死。赞分享编程语言AI Agent编译器CLI人工智能【免费下载链接】bamlThe programming language for agents项目地址https://gitcode.com/gh_mirrors/ba/baml点击查看免费下载相关推荐BAML C Bridge 泛型与可空性编译证据矩阵GenericCompileProbe 探针设计与验证实践BAML C Bridge 泛型与可空性编译证据矩阵GenericCompileProbe 探针设计与验证实践 导读 本文围绕 BAMLThe progra编程语言AI Agent编译器CLI人工智能BAML C 桥接层程序引导证据探针从编译器字节恒等到原生初始化失败缓存的完整验证BAML C 桥接层程序引导证据探针从编译器字节恒等到原生初始化失败缓存的完整验证 导读 BAML 编译器输出的 .baml 程序字节码最终要进入 C 运行时编程语言AI Agent编译器CLI人工智能BAML C Bridge 失败与取消契约冻结深入 FailureCancellationProbe 探针BAML C Bridge 失败与取消契约冻结深入 FailureCancellationProbe 探针 本文以 baml_language/sdks/cs编程语言AI Agent编译器CLI人工智能上一篇Vortex OpenCL开发实战从零开始编写你的第一个GPU加速程序下一篇LunarVim 启动器教程创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考