术语

声明与强制执行的落差

「声明 vs 强制执行」(declared vs. enforced)指的是一个系统的配置允许你写下什么、与它的运行时在执行时真正检查什么之间的那道落差——一条没有任何东西去强制的声明,读起来像一个保证,行为上却只是一句注释。

又称 declared vs enforced声明了但不强制纸面权限要么强制要么删除

在实践中

任何带 schema、策略语言或设置界面的系统,都同时存在两个集合:你被允许声明的键,和真的有东西会依据它行动的键。它们一开始完全重合,然后悄悄分叉。一个标了「必填」、却只有浏览器表单在遵守的字段,于是 API 接受它为空。一项没有任何任务会去读的保留期。一个只有某一条代码路径会检查、而导出接口不检查的权限开关。它们被写下时都是真的,然后在没有任何东西报错的情况下不再是真的——而这恰恰是这道落差能挺过审计的原因:没有东西坏掉,设置还在那儿,界面上还显示着「已开启」。

一旦配置由模型来写、而不是由建这个运行时的人来写,这道落差在结构上就更危险了。模型是从示例和文档里学会一种配置格式的,而这些材料里没有任何东西能区分「运行时会强制的键」和「运行时只是解析一下的键」:两者都出现在示例里,都能通过校验,读起来都很权威。于是 agent 会非常自信地声明一项什么都不做的控制——而最扎手的一点是,评审这份 diff 的人看到的是一行看上去完全正确的配置,然后批准了它。这就是 AI 编写配置的典型失效形态:不是语法错误(那个每个校验器都拦得住),而是合法、可信、却不起作用的声明。它在访问控制上的特例有自己的名字——纸面权限:读起来像一道边界、实际什么都不强制的元数据。一个相关的迹象是,请求层面的过滤与服务端强制的边界从外部看是无法区分的,因为它们都让两个测试账户看到正确的东西。

有一个问题能把这两个集合分开,而且可以对任何一条声明发问:如果我违反它,什么会失败、在哪里失败、动静有多大?如果答案是「什么都不会」,那这一行就是文档而不是控制,就该照文档来标注。于是任何一个可声明的键只剩两条站得住的出路——要么强制它,要么删掉它。留着一个不被强制的键是第三条路,也是真正消耗信誉的那条,因为下游每个人都把它读成一个保证:批准改动的评审者、抽查控制项的审计员,以及现在正从你的示例里生成下一个应用的那个 agent。

ObjectStack 的做法是在编写时点、而不是运行时关掉这道落差:定义面经过 schema 校验,一条运行时不会去强制的声明会在校验门禁上被拒绝,而不是作为一个虚假保证发布出去。而在「检查本身可能悄悄降级」的地方——比如一条行级规则的谓词引擎编译不了——门禁调用的是运行时自己的判定函数,而不是去模拟它的行为,因此「被 linter 拒绝」和「被丢弃、不产生任何强制」是同一个布尔值,不可能漂移成两个不同的答案。

这个术语用在哪里

真正用到这个术语的页面与文章。