skill-family-harness-node 0.4.0 → 0.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,53 @@
1
1
  # Changelog
2
2
 
3
+ <!-- release-skill:changelog:start version=0.6.0 locale=en baseline=sha256:c67e713aebe53382c651655a2be9e78ace8da6a1b7852c1e6acadcb383ff2422 -->
4
+ ## [0.6.0] - 2026-08-21
5
+
6
+ This release adds bounded subprocess supervision (FND-ADR-012), completes the Foundation strict authority read path with contained nested directory preparation (FG-1), adds pre-persistence URL credential redaction (FG-2), and grows HARNESS_CAPABILITIES from 18 to 21.
7
+
8
+ ### Added
9
+
10
+ - Adds superviseProcess with validateTimeoutPolicy, WATCHDOG_REASONS, TERMINATION_REASONS, PROCESS_STATUSES and ENVELOPE_GUARANTEES (FND-ADR-012) - one bounded spawn, liveness by explicit events, consumer-supplied timeout policy, SIGTERM then grace then SIGKILL against the process group, and a single closed-enum termination envelope; the mechanism never restarts the supervised process and never holds timeout values.
11
+ - Adds readFileStrict (FG-1), the read-side twin of the strict write path - containment first, symlink refusal with O_NOFOLLOW, regular-file identity re-assertion on the opened handle (dev/ino), and a sha256 digest receipt of the exact bytes read; an optional expectedSha256 content guard fails closed before any delivery.
12
+ - Adds the createParents option to publishFileExclusive (FG-1) - the missing portion of the parent chain is prepared as real directories inside the containment layer and every intermediate entry is re-verified as a real directory; symlink components are still refused and no entry is ever replaced.
13
+ - Adds redactUrlCredentials with REDACTED_URL_PLACEHOLDER (FG-2) - strips the userinfo component from any URL before the value reaches disk or logs; unparseable input degrades to an opaque placeholder and never leaks to the output.
14
+ - Re-exports the contracts-owned token estimate consumption contract (consumeTokenEstimate, consumeTokenEstimateStrict and companions) next to estimateTokens, and carries the authoritative token estimator estimateTokens with the skill-family-token-estimate CLI (audit remediation C1).
15
+
16
+ ### Changed
17
+
18
+ - Grows HARNESS_CAPABILITIES from 18 to 21 (adds supervise-process, strict-read and url-credential-redaction); the strict write path keeps its no-replace, byte-verified receipt semantics unchanged.
19
+ - Keeps business semantics, retry/restart policy, budget thresholds, and the decision of which values are URLs under consumer ownership; the harness owns mechanism only.
20
+
21
+ ### Upgrade Notes
22
+
23
+ Version 0.6.0 is the Foundation capability completion line. The createParents option of publishFileExclusive is a Foundation-side profile behavior change under the 2026-08-19 discipline; consumers needing contained nested publication must pin exactly 0.6.0.
24
+ <!-- release-skill:changelog:end version=0.6.0 locale=en -->
25
+
26
+
27
+ <!-- release-skill:changelog:start version=0.5.0 locale=en baseline=sha256:03eca87a8c9bea814e741518168696f17c869bdb71baf2046cef4c3596d9ebf3 -->
28
+ ## [0.5.0] - 2026-08-16
29
+
30
+ This release adds the declared read surface assertion (FND-ADR-010) and the structured surface scanner (FND-ADR-011) to the stable Harness surface, growing HARNESS_CAPABILITIES from 16 to 18 entries, and adds three dependency-reviewed runtime libraries.
31
+
32
+ ### Added
33
+
34
+ - Adds assertDeclaredReadSurface (FND-ADR-010): a no-execution, syntax-surface-only assertion that every node:fs named import inside a declared module set stays inside the consumer-declared read surface, with a closed violation vocabulary and a frozen declared-read-surface-result envelope.
35
+ - Adds scanSurfaceStructured (FND-ADR-011): the structured sibling of scanSurface. IP-shaped candidates enter a single standard parse entry (ipaddr.js) with consumer-declared CIDR approval and fail closed when unparseable; scoped and unscoped coordinates, registries and hosts need consumer-declared approval; format adapters (pnpm-lockfile via @pnpm/lockfile.fs with yaml AST comment regions, and tree-json) parse structurally with no position-level exemptions; binary and symlink policies fail closed. The closed nine-rule vocabulary travels in details.rule of the structured-scan-violation mechanism error.
36
+ - Adds three dependency-reviewed runtime libraries for the structured scanner, reviewed per FND-ADR-006 section-4 analogy (dependency-closure pre-review, executor self-review pending independent review): ipaddr.js 2.5.0 (MIT, zero dependencies), yaml 2.9.0 (ISC), and @pnpm/lockfile.fs 1001.1.35 (MIT, 18 transitive dependencies all inside the approved public coordinates).
37
+ - Grows HARNESS_CAPABILITIES from 16 to 18 entries for the two new mechanisms.
38
+
39
+ ### Changed
40
+
41
+ - Documents the relationship of the two policy documents to workspace-private leak policies: a workspace-private leak-policy.json instance document is not a subset, not isomorphic and not a migration target of the surface-scan-policy or structured-scan-policy schemas — the documents share rule vocabulary and fail-closed semantics by design, but their byte-level shapes are independent and must not be compared for compatibility. scanSurface is the execution-core generalization projection: the public, consumer-parameterized form of the same mechanism family, without any private identity, path, or approval-list interpretation of its own.
42
+ - Records the cost of the dependency-review decision honestly: the harness tarball grows with the @pnpm/lockfile.fs closure, the thin-runtime property changes from zero third-party runtime dependencies to three reviewed ones, and the pnpm-lockfile adapter writes one temporary lockfile copy under the OS temp directory (removed afterwards). The engineering-kit offline-consumer verification gates now derive the complete third-party production closure of the three Foundation packages mechanically (identity-deduplicated, npm: alias-aware, range-scoped override selectors) instead of a single-package closure, so the review decision is continuously verified against the real installed bytes.
43
+ - Keeps mechanism purity: no execution of scanned files, no model calls, no network; symlinked entries are never followed.
44
+
45
+ ### Upgrade Notes
46
+
47
+ Version 0.5.0 is the FND-ADR-010/011 harness line. Mechanism imports use the stable capability names published in HARNESS_CAPABILITIES; structured-scan policies must pass the structured-scan-policy contract validation of contract-spec 1.5.0.
48
+ <!-- release-skill:changelog:end version=0.5.0 locale=en -->
49
+
50
+
3
51
  <!-- release-skill:changelog:start version=0.4.0 locale=en baseline=sha256:72d3fe048ced8eb44a84fabe6f1fdd2eb0c938b4f6bb98740474f72aec04d873 -->
4
52
  ## [0.4.0] - 2026-08-16
5
53
 
@@ -1,5 +1,53 @@
1
1
  # 变更日志
2
2
 
3
+ <!-- release-skill:changelog:start version=0.6.0 locale=zh-CN baseline=sha256:6a4a94f692909faf2090445638988b27841a8bca67a85fd7812864d656299175 -->
4
+ ## [0.6.0] - 2026-08-21
5
+
6
+ 本版新增有界子进程监督(FND-ADR-012),补齐 Foundation 严格权威读取路径与受收容嵌套目录准备(FG-1),新增落盘前 URL 凭证脱敏(FG-2),HARNESS_CAPABILITIES 从 18 项增至 21 项。
7
+
8
+ ### 新增
9
+
10
+ - 新增 superviseProcess 与 validateTimeoutPolicy、WATCHDOG_REASONS、TERMINATION_REASONS、PROCESS_STATUSES、ENVELOPE_GUARANTEES(FND-ADR-012):单次有界 spawn、显式事件判活、消费者提供的超时策略、对进程组 SIGTERM→宽限→SIGKILL、单一闭集枚举终止信封;机制从不重启被监督进程,也从不持有超时数值。
11
+ - 新增 readFileStrict(FG-1):严格写入路径的读取孪生体——先收容、拒绝符号链接(O_NOFOLLOW)、在已打开句柄上复核常规文件身份(dev/ino),并返回所读精确字节的 sha256 摘要回执;可选 expectedSha256 内容守卫在任何交付前失败关闭。
12
+ - publishFileExclusive 新增 createParents 选项(FG-1):父目录链缺失部分在收容层内准备为真实目录,每个中间条目都复核为真实目录;符号链接组件仍被拒绝,任何条目都不被替换。
13
+ - 新增 redactUrlCredentials 与 REDACTED_URL_PLACEHOLDER(FG-2):任何 URL 的 userinfo 部分在数值到达磁盘或日志前剥离;不可解析输入退化为不透明占位符,绝不泄漏到输出。
14
+ - 在 estimateTokens 旁转导出 contracts 拥有的 token 估算消费合同(consumeTokenEstimate、consumeTokenEstimateStrict 及伴生常量),并承载权威词元估算器 estimateTokens 与 skill-family-token-estimate CLI(审计整改 C1)。
15
+
16
+ ### 变更
17
+
18
+ - HARNESS_CAPABILITIES 从 18 项增至 21 项(新增 supervise-process、strict-read、url-credential-redaction);严格写入路径的不替换、字节验证回执语义保持不变。
19
+ - 业务语义、重试/重启策略、预算阈值与「哪些值是 URL」的判定继续归消费者所有;harness 只拥有机制。
20
+
21
+ ### 升级说明
22
+
23
+ 0.6.0 是 Foundation 能力补齐线。publishFileExclusive 的 createParents 选项是按 2026-08-19 纪律的 Foundation 侧 profile 行为变更;需要受收容嵌套发布的消费者必须精确锁定 0.6.0。
24
+ <!-- release-skill:changelog:end version=0.6.0 locale=zh-CN -->
25
+
26
+
27
+ <!-- release-skill:changelog:start version=0.5.0 locale=zh-CN baseline=sha256:003472359596147fe26ad2ba53a82303a217c28cb89a6afacdaa955793001f71 -->
28
+ ## [0.5.0] - 2026-08-16
29
+
30
+ 本版在稳定 Harness 面上新增声明读取表面断言(FND-ADR-010)与结构化表面扫描器(FND-ADR-011),HARNESS_CAPABILITIES 从 16 项增至 18 项,并引入三个经依赖评审的运行时库。
31
+
32
+ ### 新增
33
+
34
+ - 新增 assertDeclaredReadSurface(FND-ADR-010):不执行、仅语法面的断言,声明模块集内的每个 node:fs 具名导入必须落在消费者声明的读取表面内,违规词汇表为闭集,返回冻结的 declared-read-surface-result 信封。
35
+ - 新增 scanSurfaceStructured(FND-ADR-011):scanSurface 的结构化兄弟。IP 形候选统一进入单一标准解析入口(ipaddr.js),按消费者声明的 CIDR 批准,不可解析即失败关闭;坐标(scoped 与非 scoped)、注册表与主机均需消费者声明批准;格式适配器(pnpm-lockfile 经 @pnpm/lockfile.fs + yaml AST 注释区域,tree-json 经 JSON.parse)结构化解析且无位置级豁免;二进制与符号链接策略失败关闭。闭集九规则词汇表经 structured-scan-violation 机制错误的 details.rule 承载。
36
+ - 为结构化扫描器引入三个经依赖评审的运行时库,评审按 FND-ADR-006 第 4 节类比执行(依赖闭包预审,执行者自审,独立复核另行安排):ipaddr.js 2.5.0(MIT,零依赖)、yaml 2.9.0(ISC)、@pnpm/lockfile.fs 1001.1.35(MIT,18 个传递依赖全部在批准公共坐标内)。
37
+ - HARNESS_CAPABILITIES 从 16 项增至 18 项,覆盖两个新机制。
38
+
39
+ ### 变更
40
+
41
+ - 显式说明两个策略文档与工作区私有 leak 策略的关系:工作区私有的 leak-policy.json 实例文档既不是 surface-scan-policy 或 structured-scan-policy schema 的子集、也不同构、更不是迁移目标——两类文档按设计共享规则词汇与失败关闭语义,但字节级形状相互独立,不得比较兼容性。scanSurface 是执行内核通用化投影:同一机制族的公开、消费者参数化形态,自身不解释任何私有身份、路径或批准清单。
42
+ - 如实记录依赖评审决策的成本:harness tarball 随 @pnpm/lockfile.fs 闭包扩大;薄运行时属性从零第三方运行时依赖变为三个经评审依赖;pnpm-lockfile 适配器会在 OS 临时目录写一份临时锁文件副本(用后即删)。engineering-kit 的离线消费者验证门随之把第三方闭包推导从单包闭包机械扩展为三个 Foundation 包的完整生产闭包(真实身份去重、npm: 别名感知、range-scoped override selector),使评审决策持续对着真实安装字节被验证。
43
+ - 保持机制纯度:不执行被扫描文件、无模型调用、无网络;永不跟随符号链接。
44
+
45
+ ### 升级说明
46
+
47
+ 0.5.0 是 FND-ADR-010/011 harness 线。机制导入使用 HARNESS_CAPABILITIES 公布的稳定能力名;structured-scan 策略必须通过契约规格 1.5.0 的 structured-scan-policy 契约校验。
48
+ <!-- release-skill:changelog:end version=0.5.0 locale=zh-CN -->
49
+
50
+
3
51
  <!-- release-skill:changelog:start version=0.4.0 locale=zh-CN baseline=sha256:dafaa1100bf6163a28d53fc982a30e8325d8bd3cab43bbb6daf2e6002befa2c1 -->
4
52
  ## [0.4.0] - 2026-08-16
5
53
 
package/README.md CHANGED
@@ -4,30 +4,31 @@
4
4
 
5
5
  # skill-family-harness-node
6
6
 
7
- <!-- release-skill:release-version: 0.4.0 -->
7
+ <!-- release-skill:release-version: 0.6.0 -->
8
8
 
9
9
  The **single default Node implementation** of the Contracts mechanism protocol. This is a thin runtime: it only implements the mechanism protocol, introduces no business semantics, and does not provide a second-language implementation.
10
10
 
11
11
  <!-- release-skill:managed:start id=latest-release -->
12
- **0.4.0** (2026-08-16)
12
+ **0.6.0** (2026-08-21)
13
13
 
14
- This release adds five finite-closed-semantics mechanisms and a token-lock primitive to the stable Harness surface (FND-ADR-009), grows HARNESS_CAPABILITIES from 9 to 16 entries, and ships the rename-directory-no-replace native-prebuild candidate.
14
+ This release adds bounded subprocess supervision (FND-ADR-012), completes the Foundation strict authority read path with contained nested directory preparation (FG-1), adds pre-persistence URL credential redaction (FG-2), and grows HARNESS_CAPABILITIES from 18 to 21.
15
15
 
16
16
  **Added**
17
17
 
18
- - Adds five finite-closed-semantics mechanisms (FND-ADR-009), namely frozen-baseline materialization with contentGuard, the generic read chokepoint, strategy-driven surface scanning, deterministic token upper-bound estimation, and the generic upper-bound guard.
19
- - Adds the token-lock primitive for exclusive token-file publication and digest verification.
20
- - Grows HARNESS_CAPABILITIES from 9 to 16 entries for the new mechanisms.
21
- - Adds the rename-directory-no-replace candidate, a native-prebuild addon proving no-replace directory renames on darwin-arm64, darwin-x64, linux-arm64-gnu, and linux-x64-gnu, with a release receipt and SBOM.
18
+ - Adds superviseProcess with validateTimeoutPolicy, WATCHDOG_REASONS, TERMINATION_REASONS, PROCESS_STATUSES and ENVELOPE_GUARANTEES (FND-ADR-012) - one bounded spawn, liveness by explicit events, consumer-supplied timeout policy, SIGTERM then grace then SIGKILL against the process group, and a single closed-enum termination envelope; the mechanism never restarts the supervised process and never holds timeout values.
19
+ - Adds readFileStrict (FG-1), the read-side twin of the strict write path - containment first, symlink refusal with O_NOFOLLOW, regular-file identity re-assertion on the opened handle (dev/ino), and a sha256 digest receipt of the exact bytes read; an optional expectedSha256 content guard fails closed before any delivery.
20
+ - Adds the createParents option to publishFileExclusive (FG-1) - the missing portion of the parent chain is prepared as real directories inside the containment layer and every intermediate entry is re-verified as a real directory; symlink components are still refused and no entry is ever replaced.
21
+ - Adds redactUrlCredentials with REDACTED_URL_PLACEHOLDER (FG-2) - strips the userinfo component from any URL before the value reaches disk or logs; unparseable input degrades to an opaque placeholder and never leaks to the output.
22
+ - Re-exports the contracts-owned token estimate consumption contract (consumeTokenEstimate, consumeTokenEstimateStrict and companions) next to estimateTokens, and carries the authoritative token estimator estimateTokens with the skill-family-token-estimate CLI (audit remediation C1).
22
23
 
23
24
  **Changed**
24
25
 
25
- - Keeps the Quickstart Profile v2 Task/Result exchange verification delivered in 0.3.0, including real-byte recomputation for path-backed outputs and evidence, duplicate Resource id rejection, and exact evidence binding verification.
26
- - Leaves method selection, retry policy, and domain result interpretation to the consumer.
26
+ - Grows HARNESS_CAPABILITIES from 18 to 21 (adds supervise-process, strict-read and url-credential-redaction); the strict write path keeps its no-replace, byte-verified receipt semantics unchanged.
27
+ - Keeps business semantics, retry/restart policy, budget thresholds, and the decision of which values are URLs under consumer ownership; the harness owns mechanism only.
27
28
 
28
29
  **Upgrade Notes**
29
30
 
30
- Version 0.4.0 is released on npm and the public mirror. Pin the candidate subpath to exactly 0.4.0; mechanism imports use the stable capability names published in HARNESS_CAPABILITIES.
31
+ Version 0.6.0 is the Foundation capability completion line. The createParents option of publishFileExclusive is a Foundation-side profile behavior change under the 2026-08-19 discipline; consumers needing contained nested publication must pin exactly 0.6.0.
31
32
  <!-- release-skill:managed:end id=latest-release -->
32
33
 
33
34
  ## Problem It Solves
@@ -41,14 +42,14 @@ The Harness consumes `skill-family-contracts` (a workspace dependency), reusing
41
42
  ## Installation and Minimal Example
42
43
 
43
44
  ```sh
44
- npm install skill-family-harness-node@0.4.0
45
+ npm install skill-family-harness-node@0.6.0
45
46
  npm info skill-family-harness-node --help
46
47
  ```
47
48
 
48
49
  The minimal example shows validating a contract document inside Node:
49
50
 
50
51
  ```js
51
- // Run from an empty directory: npm install skill-family-harness-node@0.4.0
52
+ // Run from an empty directory: npm install skill-family-harness-node@0.6.0
52
53
  import { validateContractDocument } from "skill-family-harness-node";
53
54
 
54
55
  const document = {
package/README.zh-CN.md CHANGED
@@ -5,30 +5,31 @@
5
5
 
6
6
  # skill-family-harness-node
7
7
 
8
- <!-- release-skill:release-version: 0.4.0 -->
8
+ <!-- release-skill:release-version: 0.6.0 -->
9
9
 
10
10
  Contracts 机制协议的**唯一默认 Node 实现**。这是一个薄运行时(thin runtime):只实现机制协议,不引入业务语义,不做第二语言实现。
11
11
 
12
12
  <!-- release-skill:managed:start id=latest-release -->
13
- **0.4.0** (2026-08-16)
13
+ **0.6.0** (2026-08-21)
14
14
 
15
- 本版在稳定 Harness 面上新增五项有限封闭语义机制与 token-lock 原语(FND-ADR-009),HARNESS_CAPABILITIES 从 9 项增至 16 项,并随附 rename-directory-no-replace 原生预编译候选。
15
+ 本版新增有界子进程监督(FND-ADR-012),补齐 Foundation 严格权威读取路径与受收容嵌套目录准备(FG-1),新增落盘前 URL 凭证脱敏(FG-2),HARNESS_CAPABILITIES 从 18 项增至 21 项。
16
16
 
17
17
  **新增**
18
18
 
19
- - 新增五项有限封闭语义机制(FND-ADR-009):冻结基线物化 + contentGuard、通用只读 chokepoint、策略化表面扫描、确定性 token 上界估算与通用上限守卫。
20
- - 新增 token-lock 原语:独占 token 文件发布与摘要复验。
21
- - HARNESS_CAPABILITIES 9 项增至 16 项,覆盖上述新机制。
22
- - 新增 rename-directory-no-replace 候选:覆盖 darwin-arm64、darwin-x64、linux-arm64-gnu、linux-x64-gnu 的原生预编译 no-replace 目录改名 addon,附带发布 receipt 与 SBOM。
19
+ - 新增 superviseProcess 与 validateTimeoutPolicy、WATCHDOG_REASONS、TERMINATION_REASONS、PROCESS_STATUSES、ENVELOPE_GUARANTEES(FND-ADR-012):单次有界 spawn、显式事件判活、消费者提供的超时策略、对进程组 SIGTERM→宽限→SIGKILL、单一闭集枚举终止信封;机制从不重启被监督进程,也从不持有超时数值。
20
+ - 新增 readFileStrict(FG-1):严格写入路径的读取孪生体——先收容、拒绝符号链接(O_NOFOLLOW)、在已打开句柄上复核常规文件身份(dev/ino),并返回所读精确字节的 sha256 摘要回执;可选 expectedSha256 内容守卫在任何交付前失败关闭。
21
+ - publishFileExclusive 新增 createParents 选项(FG-1):父目录链缺失部分在收容层内准备为真实目录,每个中间条目都复核为真实目录;符号链接组件仍被拒绝,任何条目都不被替换。
22
+ - 新增 redactUrlCredentials REDACTED_URL_PLACEHOLDER(FG-2):任何 URL userinfo 部分在数值到达磁盘或日志前剥离;不可解析输入退化为不透明占位符,绝不泄漏到输出。
23
+ - 在 estimateTokens 旁转导出 contracts 拥有的 token 估算消费合同(consumeTokenEstimate、consumeTokenEstimateStrict 及伴生常量),并承载权威词元估算器 estimateTokens 与 skill-family-token-estimate CLI(审计整改 C1)。
23
24
 
24
25
  **变更**
25
26
 
26
- - 保持 0.3.0 交付的 Quickstart Profile v2 Task/Result 交换校验:path-backed output 与 evidence 重算真实字节、拒绝重复 Resource idevidence 精确绑定逐项复验。
27
- - 方法选择、重试策略与领域结果解释继续归消费者所有。
27
+ - HARNESS_CAPABILITIES 18 项增至 21 项(新增 supervise-processstrict-read、url-credential-redaction);严格写入路径的不替换、字节验证回执语义保持不变。
28
+ - 业务语义、重试/重启策略、预算阈值与「哪些值是 URL」的判定继续归消费者所有;harness 只拥有机制。
28
29
 
29
30
  **升级说明**
30
31
 
31
- 0.4.0 已发布到 npm public 镜像仓。candidate 子路径必须精确锁定 0.4.0;机制导入使用 HARNESS_CAPABILITIES 公布的稳定能力名。
32
+ 0.6.0 Foundation 能力补齐线。publishFileExclusive createParents 选项是按 2026-08-19 纪律的 Foundation 侧 profile 行为变更;需要受收容嵌套发布的消费者必须精确锁定 0.6.0
32
33
  <!-- release-skill:managed:end id=latest-release -->
33
34
 
34
35
  ## 解决的问题
@@ -42,14 +43,14 @@ Harness 消费 `skill-family-contracts`(工作区依赖),复用其方言
42
43
  ## 安装和最小示例
43
44
 
44
45
  ```sh
45
- npm install skill-family-harness-node@0.4.0
46
+ npm install skill-family-harness-node@0.6.0
46
47
  npm info skill-family-harness-node --help
47
48
  ```
48
49
 
49
50
  最小示例演示在 Node 内校验一份契约文档:
50
51
 
51
52
  ```js
52
- // 从空目录运行:npm install skill-family-harness-node@0.4.0
53
+ // 从空目录运行:npm install skill-family-harness-node@0.6.0
53
54
  import { validateContractDocument } from "skill-family-harness-node";
54
55
 
55
56
  const document = {
package/package.json CHANGED
@@ -1,11 +1,17 @@
1
1
  {
2
2
  "//": "~~ Generated by projen. To modify, edit .projenrc.js and run \"npx projen\".",
3
3
  "author": "广州市风荷科技有限公司",
4
+ "bin": {
5
+ "skill-family-token-estimate": "./src/token-estimate-cli.mjs"
6
+ },
4
7
  "bugs": {
5
8
  "url": "https://github.com/ifoohoo/skill-family-harness-node/issues"
6
9
  },
7
10
  "dependencies": {
8
- "skill-family-contracts": "0.4.0"
11
+ "@pnpm/lockfile.fs": "1001.1.35",
12
+ "ipaddr.js": "2.5.0",
13
+ "skill-family-contracts": "0.6.0",
14
+ "yaml": "2.9.0"
9
15
  },
10
16
  "description": "Thin Node.js mechanism runtime for Skill Family engineering contracts.",
11
17
  "engines": {
@@ -39,7 +45,7 @@
39
45
  "url": "https://github.com/ifoohoo/skill-family-harness-node.git"
40
46
  },
41
47
  "type": "module",
42
- "version": "0.4.0",
48
+ "version": "0.6.0",
43
49
  "scripts": {
44
50
  "check": "node --test",
45
51
  "test": "node --test"
@@ -0,0 +1,29 @@
1
+ version: 0.5.0
2
+ date: 2026-08-16
3
+ locales:
4
+ en:
5
+ summary: This release adds the declared read surface assertion (FND-ADR-010) and the structured surface scanner (FND-ADR-011) to the stable Harness surface, growing HARNESS_CAPABILITIES from 16 to 18 entries, and adds three dependency-reviewed runtime libraries.
6
+ changes:
7
+ added:
8
+ - "Adds assertDeclaredReadSurface (FND-ADR-010): a no-execution, syntax-surface-only assertion that every node:fs named import inside a declared module set stays inside the consumer-declared read surface, with a closed violation vocabulary and a frozen declared-read-surface-result envelope."
9
+ - "Adds scanSurfaceStructured (FND-ADR-011): the structured sibling of scanSurface. IP-shaped candidates enter a single standard parse entry (ipaddr.js) with consumer-declared CIDR approval and fail closed when unparseable; scoped and unscoped coordinates, registries and hosts need consumer-declared approval; format adapters (pnpm-lockfile via @pnpm/lockfile.fs with yaml AST comment regions, and tree-json) parse structurally with no position-level exemptions; binary and symlink policies fail closed. The closed nine-rule vocabulary travels in details.rule of the structured-scan-violation mechanism error."
10
+ - "Adds three dependency-reviewed runtime libraries for the structured scanner, reviewed per FND-ADR-006 section-4 analogy (dependency-closure pre-review, executor self-review pending independent review): ipaddr.js 2.5.0 (MIT, zero dependencies), yaml 2.9.0 (ISC), and @pnpm/lockfile.fs 1001.1.35 (MIT, 18 transitive dependencies all inside the approved public coordinates)."
11
+ - Grows HARNESS_CAPABILITIES from 16 to 18 entries for the two new mechanisms.
12
+ changed:
13
+ - "Documents the relationship of the two policy documents to workspace-private leak policies: a workspace-private leak-policy.json instance document is not a subset, not isomorphic and not a migration target of the surface-scan-policy or structured-scan-policy schemas — the documents share rule vocabulary and fail-closed semantics by design, but their byte-level shapes are independent and must not be compared for compatibility. scanSurface is the execution-core generalization projection: the public, consumer-parameterized form of the same mechanism family, without any private identity, path, or approval-list interpretation of its own."
14
+ - "Records the cost of the dependency-review decision honestly: the harness tarball grows with the @pnpm/lockfile.fs closure, the thin-runtime property changes from zero third-party runtime dependencies to three reviewed ones, and the pnpm-lockfile adapter writes one temporary lockfile copy under the OS temp directory (removed afterwards). The engineering-kit offline-consumer verification gates now derive the complete third-party production closure of the three Foundation packages mechanically (identity-deduplicated, npm: alias-aware, range-scoped override selectors) instead of a single-package closure, so the review decision is continuously verified against the real installed bytes."
15
+ - "Keeps mechanism purity: no execution of scanned files, no model calls, no network; symlinked entries are never followed."
16
+ upgradeNotes: Version 0.5.0 is the FND-ADR-010/011 harness line. Mechanism imports use the stable capability names published in HARNESS_CAPABILITIES; structured-scan policies must pass the structured-scan-policy contract validation of contract-spec 1.5.0.
17
+ zh-CN:
18
+ summary: 本版在稳定 Harness 面上新增声明读取表面断言(FND-ADR-010)与结构化表面扫描器(FND-ADR-011),HARNESS_CAPABILITIES 从 16 项增至 18 项,并引入三个经依赖评审的运行时库。
19
+ changes:
20
+ added:
21
+ - 新增 assertDeclaredReadSurface(FND-ADR-010):不执行、仅语法面的断言,声明模块集内的每个 node:fs 具名导入必须落在消费者声明的读取表面内,违规词汇表为闭集,返回冻结的 declared-read-surface-result 信封。
22
+ - 新增 scanSurfaceStructured(FND-ADR-011):scanSurface 的结构化兄弟。IP 形候选统一进入单一标准解析入口(ipaddr.js),按消费者声明的 CIDR 批准,不可解析即失败关闭;坐标(scoped 与非 scoped)、注册表与主机均需消费者声明批准;格式适配器(pnpm-lockfile 经 @pnpm/lockfile.fs + yaml AST 注释区域,tree-json 经 JSON.parse)结构化解析且无位置级豁免;二进制与符号链接策略失败关闭。闭集九规则词汇表经 structured-scan-violation 机制错误的 details.rule 承载。
23
+ - 为结构化扫描器引入三个经依赖评审的运行时库,评审按 FND-ADR-006 第 4 节类比执行(依赖闭包预审,执行者自审,独立复核另行安排):ipaddr.js 2.5.0(MIT,零依赖)、yaml 2.9.0(ISC)、@pnpm/lockfile.fs 1001.1.35(MIT,18 个传递依赖全部在批准公共坐标内)。
24
+ - HARNESS_CAPABILITIES 从 16 项增至 18 项,覆盖两个新机制。
25
+ changed:
26
+ - 显式说明两个策略文档与工作区私有 leak 策略的关系:工作区私有的 leak-policy.json 实例文档既不是 surface-scan-policy 或 structured-scan-policy schema 的子集、也不同构、更不是迁移目标——两类文档按设计共享规则词汇与失败关闭语义,但字节级形状相互独立,不得比较兼容性。scanSurface 是执行内核通用化投影:同一机制族的公开、消费者参数化形态,自身不解释任何私有身份、路径或批准清单。
27
+ - "如实记录依赖评审决策的成本:harness tarball 随 @pnpm/lockfile.fs 闭包扩大;薄运行时属性从零第三方运行时依赖变为三个经评审依赖;pnpm-lockfile 适配器会在 OS 临时目录写一份临时锁文件副本(用后即删)。engineering-kit 的离线消费者验证门随之把第三方闭包推导从单包闭包机械扩展为三个 Foundation 包的完整生产闭包(真实身份去重、npm: 别名感知、range-scoped override selector),使评审决策持续对着真实安装字节被验证。"
28
+ - 保持机制纯度:不执行被扫描文件、无模型调用、无网络;永不跟随符号链接。
29
+ upgradeNotes: 0.5.0 是 FND-ADR-010/011 harness 线。机制导入使用 HARNESS_CAPABILITIES 公布的稳定能力名;structured-scan 策略必须通过契约规格 1.5.0 的 structured-scan-policy 契约校验。
@@ -0,0 +1,29 @@
1
+ version: 0.6.0
2
+ date: 2026-08-21
3
+ locales:
4
+ en:
5
+ summary: This release adds bounded subprocess supervision (FND-ADR-012), completes the Foundation strict authority read path with contained nested directory preparation (FG-1), adds pre-persistence URL credential redaction (FG-2), and grows HARNESS_CAPABILITIES from 18 to 21.
6
+ changes:
7
+ added:
8
+ - Adds superviseProcess with validateTimeoutPolicy, WATCHDOG_REASONS, TERMINATION_REASONS, PROCESS_STATUSES and ENVELOPE_GUARANTEES (FND-ADR-012) - one bounded spawn, liveness by explicit events, consumer-supplied timeout policy, SIGTERM then grace then SIGKILL against the process group, and a single closed-enum termination envelope; the mechanism never restarts the supervised process and never holds timeout values.
9
+ - Adds readFileStrict (FG-1), the read-side twin of the strict write path - containment first, symlink refusal with O_NOFOLLOW, regular-file identity re-assertion on the opened handle (dev/ino), and a sha256 digest receipt of the exact bytes read; an optional expectedSha256 content guard fails closed before any delivery.
10
+ - Adds the createParents option to publishFileExclusive (FG-1) - the missing portion of the parent chain is prepared as real directories inside the containment layer and every intermediate entry is re-verified as a real directory; symlink components are still refused and no entry is ever replaced.
11
+ - Adds redactUrlCredentials with REDACTED_URL_PLACEHOLDER (FG-2) - strips the userinfo component from any URL before the value reaches disk or logs; unparseable input degrades to an opaque placeholder and never leaks to the output.
12
+ - Re-exports the contracts-owned token estimate consumption contract (consumeTokenEstimate, consumeTokenEstimateStrict and companions) next to estimateTokens, and carries the authoritative token estimator estimateTokens with the skill-family-token-estimate CLI (audit remediation C1).
13
+ changed:
14
+ - Grows HARNESS_CAPABILITIES from 18 to 21 (adds supervise-process, strict-read and url-credential-redaction); the strict write path keeps its no-replace, byte-verified receipt semantics unchanged.
15
+ - Keeps business semantics, retry/restart policy, budget thresholds, and the decision of which values are URLs under consumer ownership; the harness owns mechanism only.
16
+ upgradeNotes: Version 0.6.0 is the Foundation capability completion line. The createParents option of publishFileExclusive is a Foundation-side profile behavior change under the 2026-08-19 discipline; consumers needing contained nested publication must pin exactly 0.6.0.
17
+ zh-CN:
18
+ summary: 本版新增有界子进程监督(FND-ADR-012),补齐 Foundation 严格权威读取路径与受收容嵌套目录准备(FG-1),新增落盘前 URL 凭证脱敏(FG-2),HARNESS_CAPABILITIES 从 18 项增至 21 项。
19
+ changes:
20
+ added:
21
+ - 新增 superviseProcess 与 validateTimeoutPolicy、WATCHDOG_REASONS、TERMINATION_REASONS、PROCESS_STATUSES、ENVELOPE_GUARANTEES(FND-ADR-012):单次有界 spawn、显式事件判活、消费者提供的超时策略、对进程组 SIGTERM→宽限→SIGKILL、单一闭集枚举终止信封;机制从不重启被监督进程,也从不持有超时数值。
22
+ - 新增 readFileStrict(FG-1):严格写入路径的读取孪生体——先收容、拒绝符号链接(O_NOFOLLOW)、在已打开句柄上复核常规文件身份(dev/ino),并返回所读精确字节的 sha256 摘要回执;可选 expectedSha256 内容守卫在任何交付前失败关闭。
23
+ - publishFileExclusive 新增 createParents 选项(FG-1):父目录链缺失部分在收容层内准备为真实目录,每个中间条目都复核为真实目录;符号链接组件仍被拒绝,任何条目都不被替换。
24
+ - 新增 redactUrlCredentials 与 REDACTED_URL_PLACEHOLDER(FG-2):任何 URL 的 userinfo 部分在数值到达磁盘或日志前剥离;不可解析输入退化为不透明占位符,绝不泄漏到输出。
25
+ - 在 estimateTokens 旁转导出 contracts 拥有的 token 估算消费合同(consumeTokenEstimate、consumeTokenEstimateStrict 及伴生常量),并承载权威词元估算器 estimateTokens 与 skill-family-token-estimate CLI(审计整改 C1)。
26
+ changed:
27
+ - HARNESS_CAPABILITIES 从 18 项增至 21 项(新增 supervise-process、strict-read、url-credential-redaction);严格写入路径的不替换、字节验证回执语义保持不变。
28
+ - 业务语义、重试/重启策略、预算阈值与「哪些值是 URL」的判定继续归消费者所有;harness 只拥有机制。
29
+ upgradeNotes: 0.6.0 是 Foundation 能力补齐线。publishFileExclusive 的 createParents 选项是按 2026-08-19 纪律的 Foundation 侧 profile 行为变更;需要受收容嵌套发布的消费者必须精确锁定 0.6.0。
package/src/atomic.mjs CHANGED
@@ -90,7 +90,30 @@ async function runTestHook(name, context) {
90
90
  if (typeof testHooks?.[name] === "function") await testHooks[name](context);
91
91
  }
92
92
 
93
- async function strictTarget(root, relPath, { target = "optional" } = {}) {
93
+ async function createParentDirectory(cursor, relPath) {
94
+ try {
95
+ await mkdir(cursor);
96
+ } catch (cause) {
97
+ // EEXIST is a benign concurrent creation race: re-verify the entry below.
98
+ if (cause?.code !== "EEXIST") {
99
+ throw mechanismError(
100
+ HARNESS_ERROR_KINDS.INVALID_ROOT,
101
+ "strict file operation could not create a missing parent directory",
102
+ { input: relPath, code: cause?.code },
103
+ );
104
+ }
105
+ }
106
+ const created = await lstat(cursor);
107
+ if (created.isSymbolicLink() || !created.isDirectory()) {
108
+ throw mechanismError(
109
+ HARNESS_ERROR_KINDS.UNSAFE_STATE_ENTRY,
110
+ "strict file operation requires real intermediate directories",
111
+ { input: relPath },
112
+ );
113
+ }
114
+ }
115
+
116
+ async function strictTarget(root, relPath, { target = "optional", createParents = false } = {}) {
94
117
  const lexical = await resolveContained(root, relPath);
95
118
  const rootReal = await realpath(root);
96
119
  const relative = path.relative(rootReal, lexical);
@@ -102,6 +125,10 @@ async function strictTarget(root, relPath, { target = "optional" } = {}) {
102
125
  try {
103
126
  stats = await lstat(cursor);
104
127
  } catch (cause) {
128
+ if (createParents && cause?.code === "ENOENT") {
129
+ await createParentDirectory(cursor, relPath);
130
+ continue;
131
+ }
105
132
  throw mechanismError(
106
133
  HARNESS_ERROR_KINDS.INVALID_ROOT,
107
134
  "strict file operation requires every parent directory to exist",
@@ -267,17 +294,25 @@ function strictFailure(kind, operation, cause, relPath, committed, verified) {
267
294
  }
268
295
 
269
296
  /**
270
- * Creates one file without replacing any existing directory entry. The
271
- * parent must already exist and contain no symlink components. The returned
297
+ * Creates one file without replacing any existing directory entry. Every
298
+ * parent must be a real directory and contain no symlink components; with
299
+ * `createParents` enabled, the missing portion of the parent chain is created
300
+ * as real directories (any symlink component is still refused). The returned
272
301
  * receipt is emitted only after byte/mode/identity verification and directory
273
302
  * fsync have completed.
274
303
  */
275
- export async function publishFileExclusive(root, relPath, data, { mode = 0o644 } = {}) {
304
+ export async function publishFileExclusive(
305
+ root,
306
+ relPath,
307
+ data,
308
+ { mode = 0o644, createParents = false } = {},
309
+ ) {
276
310
  assertWritableData(data, "publishFileExclusive");
277
311
  const normalizedMode = normalizeMode(mode);
278
312
  const bytes = bytesOf(data);
279
313
  const { targetPath, directory, directoryStats, directoryReal } = await strictTarget(root, relPath, {
280
314
  target: "absent",
315
+ createParents,
281
316
  });
282
317
  const staging = path.join(
283
318
  directory,
@@ -0,0 +1,198 @@
1
+ import path from "node:path";
2
+ import { readFileSync, readdirSync, statSync } from "node:fs";
3
+ import { HARNESS_ERROR_KINDS, mechanismError } from "./errors.mjs";
4
+
5
+ /**
6
+ * Static declared read surface verification (FND-ADR-010).
7
+ *
8
+ * assertDeclaredReadSurface({ root, declaredReaders }) checks, by static
9
+ * source analysis, that every `.mjs`/`.js` module under `root` only reads
10
+ * node:fs through the consumer-declared reader set:
11
+ *
12
+ * - a module that imports named APIs from "node:fs" without being declared
13
+ * violates rule `undeclared-module-imports-fs`;
14
+ * - a declared module importing an API outside its declared set violates
15
+ * rule `fs-api-outside-declared-set`;
16
+ * - any write-family fs API name appearing anywhere in the tree (whole
17
+ * source substring detection, including comments and string literals)
18
+ * violates rule `write-family-fs-api` (conservative approximation: static
19
+ * syntax-level violations are never under-reported).
20
+ *
21
+ * The verdict semantics mirror the audit tree's P3 check one-to-one; the
22
+ * result is shaped as the contracts `declared-read-surface-result` envelope
23
+ * whose scope, rule enumeration and guarantees are the machine contract.
24
+ * Input is fully parameterized: root and declaredReaders are consumer data,
25
+ * the mechanism knows no audit paths, no workspace layout, and no business
26
+ * meaning of any module.
27
+ *
28
+ * Violations are collected as an evidence list (deterministic order:
29
+ * sorted module list, then rule order per module) rather than stopping at
30
+ * the first hit; `ok` is false exactly when the list is non-empty.
31
+ *
32
+ * Mechanism purity: read-only (never writes, never executes the scanned
33
+ * modules, no model call, no network); symlinked entries under the root are
34
+ * never followed and never scanned (conservative: a symlink may not smuggle
35
+ * a module out of the declared surface).
36
+ */
37
+
38
+ const MODULE_EXTENSIONS = [".mjs", ".js"];
39
+ const FS_NAMED_IMPORT_PATTERN = /import\s*\{([^}]*)\}\s*from\s*"node:fs"/g;
40
+
41
+ // Write-family API names are built by composition so this module's own
42
+ // source never contains the full forbidden names as literals (self-hit
43
+ // hygiene, inherited from the audit tree's P3 check). Detection of scanned
44
+ // modules is unaffected: they would spell the full names.
45
+ const WRITE_FS_VERBS = ["writeFile", "appendFile", "mkdir", "rm", "unlink", "rename", "copyFile"];
46
+ const WRITE_FS_APIS = WRITE_FS_VERBS.map((verb) => `${verb}Sync`).concat([
47
+ `${"createWrite"}Stream`,
48
+ ]);
49
+
50
+ export const DECLARED_READ_SURFACE_RULES = Object.freeze({
51
+ UNDECLARED_MODULE_IMPORTS_FS: "undeclared-module-imports-fs",
52
+ FS_API_OUTSIDE_DECLARED_SET: "fs-api-outside-declared-set",
53
+ WRITE_FAMILY_FS_API: "write-family-fs-api",
54
+ });
55
+
56
+ const RESULT_GUARANTEES = Object.freeze([
57
+ "syntax-surface-only",
58
+ "conservative-approximation",
59
+ "no-execution",
60
+ "no-model-calls",
61
+ "no-network-access",
62
+ ]);
63
+
64
+ function invalidInput(reason, extra) {
65
+ return mechanismError(
66
+ HARNESS_ERROR_KINDS.DECLARED_READ_SURFACE_INVALID,
67
+ `assertDeclaredReadSurface: ${reason}`,
68
+ extra,
69
+ );
70
+ }
71
+
72
+ function assertPlainObject(value, label) {
73
+ if (value === null || typeof value !== "object" || Array.isArray(value)) {
74
+ throw invalidInput(`${label} must be a plain object`);
75
+ }
76
+ }
77
+
78
+ function isValidDeclaredModulePath(modulePath) {
79
+ if (typeof modulePath !== "string" || modulePath.length === 0) return false;
80
+ if (modulePath.includes("\0")) return false;
81
+ if (modulePath.includes("\\")) return false;
82
+ if (path.posix.isAbsolute(modulePath)) return false;
83
+ if (/^[A-Za-z]:/.test(modulePath)) return false;
84
+ const normalized = path.posix.normalize(modulePath);
85
+ if (normalized === "." || normalized === "..") return false;
86
+ if (normalized.split("/").some((segment) => segment === "..")) return false;
87
+ return normalized === modulePath;
88
+ }
89
+
90
+ function collectModules(root) {
91
+ const modules = [];
92
+ const walk = (directory) => {
93
+ const entries = readdirSync(directory, { withFileTypes: true }).sort((a, b) =>
94
+ a.name.localeCompare(b.name),
95
+ );
96
+ for (const entry of entries) {
97
+ if (entry.isSymbolicLink()) continue; // never followed, never scanned
98
+ const fullPath = path.join(directory, entry.name);
99
+ if (entry.isDirectory()) {
100
+ walk(fullPath);
101
+ } else if (entry.isFile() && MODULE_EXTENSIONS.some((ext) => entry.name.endsWith(ext))) {
102
+ modules.push(fullPath);
103
+ }
104
+ }
105
+ };
106
+ walk(root);
107
+ return modules;
108
+ }
109
+
110
+ function namedFsImports(source) {
111
+ return [...source.matchAll(FS_NAMED_IMPORT_PATTERN)].flatMap((match) =>
112
+ match[1].split(",").map((api) => api.trim()).filter(Boolean),
113
+ );
114
+ }
115
+
116
+ /**
117
+ * Static declared read surface verification. Returns the contracts
118
+ * declared-read-surface-result envelope (frozen). Invalid inputs (non-empty
119
+ * root that is not a directory, empty declaredReaders, illegal module path
120
+ * shapes, malformed declared sets) throw SFC2004 with details.kind
121
+ * declared-read-surface-invalid; a detected violation is reported in the
122
+ * result's violations list (ok: false), never as an exception.
123
+ */
124
+ export function assertDeclaredReadSurface({ root, declaredReaders } = {}) {
125
+ if (typeof root !== "string" || root.length === 0) {
126
+ throw invalidInput("root must be a non-empty path");
127
+ }
128
+ assertPlainObject(declaredReaders, "declaredReaders");
129
+ const readerKeys = Object.keys(declaredReaders);
130
+ if (readerKeys.length === 0) {
131
+ throw invalidInput("declaredReaders must declare at least one reader module");
132
+ }
133
+ const declared = new Map();
134
+ for (const key of readerKeys) {
135
+ if (!isValidDeclaredModulePath(key)) {
136
+ throw invalidInput(`declared reader module path has an illegal shape: ${JSON.stringify(key)}`);
137
+ }
138
+ const apis = declaredReaders[key];
139
+ if (!Array.isArray(apis)) {
140
+ throw invalidInput(`declared set for ${key} must be an array of fs API names`);
141
+ }
142
+ for (const api of apis) {
143
+ if (typeof api !== "string" || api.length === 0) {
144
+ throw invalidInput(`declared set for ${key} contains a malformed fs API name`);
145
+ }
146
+ }
147
+ declared.set(key, apis);
148
+ }
149
+
150
+ const rootResolved = path.resolve(root);
151
+ let rootStat;
152
+ try {
153
+ rootStat = statSync(rootResolved);
154
+ } catch {
155
+ throw invalidInput("root does not exist or cannot be inspected", { root: "<opaque>" });
156
+ }
157
+ if (!rootStat.isDirectory()) {
158
+ throw invalidInput("root is not a directory", { root: "<opaque>" });
159
+ }
160
+
161
+ const modules = collectModules(rootResolved);
162
+ const violations = [];
163
+ const pushViolation = (entry) => violations.push(entry);
164
+
165
+ for (const module of modules) {
166
+ const relative = path.relative(rootResolved, module).split(path.sep).join("/");
167
+ const source = readFileSync(module, "utf8");
168
+ const fsImports = namedFsImports(source);
169
+ const allowed = declared.get(relative);
170
+ if (fsImports.length > 0 && allowed === undefined) {
171
+ pushViolation({ module: relative, rule: DECLARED_READ_SURFACE_RULES.UNDECLARED_MODULE_IMPORTS_FS });
172
+ }
173
+ if (allowed !== undefined) {
174
+ for (const api of fsImports) {
175
+ if (!allowed.includes(api)) {
176
+ pushViolation({ module: relative, api, rule: DECLARED_READ_SURFACE_RULES.FS_API_OUTSIDE_DECLARED_SET });
177
+ }
178
+ }
179
+ }
180
+ for (const api of WRITE_FS_APIS) {
181
+ if (source.includes(api)) {
182
+ pushViolation({ module: relative, api, rule: DECLARED_READ_SURFACE_RULES.WRITE_FAMILY_FS_API });
183
+ }
184
+ }
185
+ }
186
+
187
+ return Object.freeze({
188
+ schemaVersion: 1,
189
+ kind: "skill-family.declared-read-surface-result",
190
+ ok: violations.length === 0,
191
+ violations,
192
+ scannedModules: modules.map((module) =>
193
+ path.relative(rootResolved, module).split(path.sep).join("/"),
194
+ ),
195
+ scope: "esm-named-imports-only",
196
+ guarantees: [...RESULT_GUARANTEES],
197
+ });
198
+ }
package/src/errors.mjs CHANGED
@@ -65,7 +65,15 @@ export const HARNESS_ERROR_KINDS = Object.freeze({
65
65
  READ_CHOKEPOINT_REJECTED: "read-chokepoint-rejected",
66
66
  SURFACE_SCAN_VIOLATION: "surface-scan-violation",
67
67
  SCAN_POLICY_INVALID: "scan-policy-invalid",
68
+ DECLARED_READ_SURFACE_VIOLATION: "declared-read-surface-violation",
69
+ DECLARED_READ_SURFACE_INVALID: "declared-read-surface-invalid",
70
+ STRUCTURED_SCAN_VIOLATION: "structured-scan-violation",
71
+ STRUCTURED_SCAN_INVALID: "structured-scan-invalid",
68
72
  UPPER_BOUND_EXCEEDED: "upper-bound-exceeded",
73
+ // Bounded subprocess supervision (FND-ADR-012). Both kinds report through
74
+ // SFC2004 with details.kind; the AUD namespace never enters here.
75
+ TIMEOUT_POLICY_INVALID: "timeout-policy-invalid",
76
+ SUPERVISE_PROCESS_FAILED: "supervise-process-failed",
69
77
  });
70
78
 
71
79
  /**