算法模块提供了一个 CalcLUTParams 接口根据直方图计算图像增强参数。接口约定很简单返回0表示成功返回非0表示失败。测试时发现全黑图会返回-5。而业务上并不希望因此中断显示流程。对于这种场景更合理的行为往往是退化为默认对角线曲线让图像继续显示。于是出现了一个很典型的问题。到底应该算法模块内部直接返回默认参数还是客户端收到-5后自行 fallback。这个问题本身不大。但有意思的是它很容易继续往下延伸。如果接口名叫 CalcLUTParams 那么从直觉上看它似乎应该负责“给出一组可用的 LUT 参数”。既然默认对角线参数本身就是合法结果那么“全黑图返回默认参数”完全可以成为算法模块内部的领域规则。这样调用方只需要得到结果而不需要理解算法内部的“失败”细节这并不是真正意义上的失败而是算法内部正常的分支细节。一方面客户端也并非没有自己的领域目标。算法模块关心的是是否成功计算出了有效增强曲线。显示 SDK 关心的则是图像是否还能继续显示。这两者并不完全相同。于是算法失败并不一定意味着显示失败。客户端收到错误码后决定退化为默认参数同样是合理的。真正有意思的地方正在这里。“全黑图返回默认曲线”这个规则放在算法层是合理的放在显示层似乎也合理。问题开始从“如何 fallback”逐渐变成了“规则属于谁”。复杂系统里很多问题都会慢慢演化成这种形式。最初只是一个局部决策。后来会发现一部分 fallback 在算法层一部分 fallback 在 SDK一部分 fallback 在 Viewer一部分 fallback 在 UI。每一次修改单独看都成立。但系统会开始逐渐失去一种东西稳定的规则中心。这时会出现一种很微妙的状态。系统里的行为并没有立刻错误。相反大部分时候它甚至还能正常工作。只是相同场景在不同模块开始出现不同处理错误码的语义慢慢漂移调用方越来越依赖隐含约定系统行为越来越难以推导。很多复杂系统后期令人不安的地方就在于这种“规则漂移”。规则不再稳定地收敛在某个边界内而是在系统中缓慢扩散。一开始只是一个 fallback。后来会变成大量局部合理、但彼此缺乏统一语义的补丁。我越来越觉得让规则持续收敛是复杂系统真正困难的部分。这件事在 AI 编程时代可能会变得更加明显。LLM 很擅长补局部缺口。哪里失败就补一个 fallback哪里容易中断就增加一个默认值。这些修改从局部上下文看往往都没有问题。但模型天然缺少一种长期、稳定的系统边界感。于是很容易产生一种状态局部越来越合理。整体越来越漂移。现在回头再看最开始的问题其实只是if(ret ! 0)