跳转至

skill-family-harness-node 公共 API 参考

本页从真实导出(src/index.mjs 与各源模块)核对,不手写无法证明新鲜度的全集。每个公共入口按 hand-off §4.3 说明:签名、输入与输出、是否纯函数、文件/进程/Git/网络副作用、稳定错误码与 details.kind、前置条件与信任锚、sincestability、源文件与正例/负例测试、调用方仍拥有的业务语义。

Harness 是薄运行时:消费 Contracts,只实现业务中立机制;不拥有业务语义、编排、Git、网络与第二语言。包级常量:HARNESS_CAPABILITIES(21 项能力,闭集)、HARNESS_EXCLUSIONS(明确排除 business-semantics / workflow-orchestration / git-writes / model-calls / release-state / remote-network-access)。

能力分组(与 docs/agents/capability-catalog.json 对应):


契约校验 (foundation.harness.contract-validation)

validateContractDocument / getValidator / resolveSchemaContext / validatorCacheSize

  • 签名:
  • validateContractDocument(document, { schemaId, dialect, policy = "strict" } = {})
  • getValidator({ schemaId, dialect, policy = "strict" } = {})
  • resolveSchemaContext({ schemaId, dialect, policy = "strict" } = {})
  • validatorCacheSize()
  • 输入:schema 上下文或契约文档。
  • 输出:校验结果(语义同 Contracts validateDocument,但经 Node 运行时复用缓存);缓存大小查询。
  • 纯函数:否(getValidator / validateContractDocument 写入进程内以 schema 为键的校验器缓存)。
  • 副作用:进程内内存缓存校验器实例;无文件/Git/网络。
  • 稳定错误码与 details.kind:沿用 Contracts SFC1001 / SFC1002 / SFC1006;底层机制失败统一 SFC2004 + HARNESS_ERROR_KINDSkind(如 INVALID_PATH)。
  • 前置条件与信任锚:已安装 skill-family-contracts;Ajv 8.20.0。
  • since / stability0.2.0 / stable
  • 源文件:packages/skill-family-harness-node/src/validation.mjs
  • 正例/负例测试:packages/skill-family-harness-node/test/validation.test.mjs
  • 调用方仍拥有的业务语义:契约业务字段语义(语义定义仍在 Contracts)。

路径收容 (foundation.harness.path-containment)

classifyPathInput / resolveContained / readFileContained

  • 签名:
  • classifyPathInput(input, platform = process.platform)
  • resolveContained(root, relPath)
  • readFileContained(root, relPath, { encoding } = {})
  • 输入:根目录(收容边界)与待解析的相对/绝对路径。
  • 输出:受收容绝对路径或读到的文件内容。
  • 纯函数:classifyPathInput 是;resolveContained / readFileContainedasync,含只读文件系统访问。
  • 副作用:只读文件系统访问(读取/解析);不写。
  • 稳定错误码与 details.kind:机制失败抛 HarnessErrorSFC2004)+ details.kind{PATH_TRAVERSAL, SYMLINK_ESCAPE, REALPATH_ESCAPE, INVALID_ROOT, ABSOLUTE_PATH, WINDOWS_DRIVE_PATH, WINDOWS_PATH, UNC_PATH, INVALID_PATH, READ_FAILED}
  • 前置条件与信任锚:调用方提供明确根目录;所有解析结果必须落在根目录内;Windows 盘符/UNC 逃逸同样拒绝。
  • since / stability0.2.0 / stable
  • 源文件:packages/skill-family-harness-node/src/paths.mjs
  • 正例/负例测试:packages/skill-family-harness-node/test/containment.test.mjsboundaries.test.mjs
  • 调用方仍拥有的业务语义:哪些路径是业务允许的选择规则(业务选择语义留在调用方)。

严格读取 (foundation.harness.strict-read)

readFileStrict

  • 签名:readFileStrict(root, relPath, { encoding?, expectedSha256? } = {})(async)。
  • 输入:收容根目录、相对文件路径,可选的 utf8 编码与小写 sha256 预期摘要。
  • 输出:冻结回执 { path, content, sha256, bytes, mode }。指定 utf8 时,content 是字符串;省略编码时,contentBuffer
  • 纯函数:否,函数只读一个受收容的普通文件。
  • 副作用:执行 lstatopenread 与文件身份复核;不写文件,不访问 Git 或网络。
  • 稳定错误码与 details.kind:失败使用 SFC2004。缺失文件返回 missing-resource,摘要不符返回 content-guard-rejected,目录返回 read-failed,越界路径沿用路径收容的失败种类。
  • 符号链接边界:叶节点符号链接始终拒绝。祖先目录可以是指向根内目录的符号链接;其规范路径仍须受 root 收容。
  • 前置条件与信任锚:expectedSha256 的来源与信任由调用方负责;摘要只覆盖实际读到的字节。
  • since / stability0.6.0 / stable
  • 源文件:packages/skill-family-harness-node/src/strict-read.mjs
  • 正例/负例测试:packages/skill-family-harness-node/test/strict-read.test.mjs
  • 调用方仍拥有的业务语义:选择哪个权威文件、摘要从何而来,以及读取失败后的处置。

身份绑定读取 (foundation.harness.bound-read)

createFilesystemRootBinding / readFileBound

  • 签名:createFilesystemRootBinding(root)readFileBound(root, relPath, { rootBinding, encoding?, expectedSha256? } = {})(均为 async)。
  • 输入:已规范化的绝对真实目录、受收容的相对 POSIX 路径,以及调用方先前批准的冻结根绑定。encoding 仅支持 utf8;权威读取可带小写 sha256 预期摘要。
  • 输出:根绑定为冻结可序列化值;读取回执为冻结 { path, content, sha256, bytes, mode, statMode }mode 保持旧兼容含义(st_mode & 0o777);statMode 是同次原生打开描述符 fstat 得到的完整 POSIX st_mode,包括文件类型与特殊权限位。
  • 语义边界:根与中间目录由固定四平台 N-API 闭包以不跟随符号链接的句柄相对方式获取;叶子必须是单链接普通文件。句柄不会逃逸,调用结束前关闭。绑定读取不提供删除或恢复状态机。
  • 副作用:只读文件系统访问;不写文件、不触 Git、网络或进程。
  • 错误:根身份不符、符号链接组件、缺失资源和摘要不符均失败关闭;不支持的 Darwin/Linux 架构不提供 JavaScript 回退。
  • since / stability0.9.0 / stable
  • 源文件:packages/skill-family-harness-node/src/bound-read.mjssrc/native/
  • 正例/负例测试:packages/skill-family-harness-node/test/bound-read.test.mjs

完整树观察 (foundation.harness.filesystem-tree-observation)

observeFilesystemTree

  • 签名:observeFilesystemTree({ root, rootBinding })(async)。调用方先用既有 createFilesystemRootBinding 批准根目录。
  • 输入:已规范化的真实绝对目录及其根绑定。每次调用重新读取目录和普通文件,空树合法。
  • 输出:私有 filesystem-tree-observation,含按路径排序的完整成员、根绑定和 membersDigest。文件成员包含同次读取的 contentBase64sha256bytes 与完整 POSIX statMode;目录成员只含路径、类型和模式,不伪造文件摘要。
  • 副作用:只读文件系统,不安装、不启动进程、不访问网络。结果含原始文件内容,调用方必须保护敏感数据。
  • 失败语义:参数不合法抛 TypeError,机制失败沿 SFC2004 关闭,不把部分观察报告为成功。
  • 保证边界:每次检查同一根绑定,不使用旧缓存;不承诺整个操作期间的连续路径身份或事务快照。
  • since / stability0.13.0 / candidate。观察完成不等于消费者接受载荷。
  • 源文件:packages/skill-family-harness-node/src/filesystem-observation.mjssrc/native/bound_read.c
  • 正例/负例:packages/skill-family-engineering-kit/test/plugin-verification.test.mjs 的实际树观察与载荷政策组合测试。

固定集合发布 (foundation.harness.fixed-set-publication)

createFixedSetPublicationManifest / publishFixedSet

  • 签名:createFixedSetPublicationManifest({ sourceRoot, targetParent, targetSegment })publishFixedSet({ sourceRoot, targetParent, targetSegment, manifest })(均为 async)。稳定入口也由 skill-family-harness-node/fixed-set-publication 导出。
  • 输入:同一规范父目录下的源目录、目标父目录、一个安全目标段和此前冻结的完整集合 manifest。
  • 输出:完整集合 manifest 与结构化 publication receipt。receipt 终态为 succeededrefusedfailedindeterminate
  • 语义边界:发布使用 Darwin renameatx_np(RENAME_EXCL) 或 Linux renameat2(RENAME_NOREPLACE) 的固定原生闭包;不使用检查后 rename 的 JavaScript 替代,不提供身份保护删除,不自动重试、回滚或恢复 indeterminate
  • 副作用:仅在成功时对目标目录执行一次不替换发布;失败关闭。
  • since / stability0.9.0 / stable
  • 源文件:packages/skill-family-harness-node/src/fixed-set-publication.mjs 与固定原生加载器。
  • 正例/负例测试:packages/skill-family-harness-node/test/stable-filesystem-operations.test.mjs 与既有固定集合边界测试。

原子写 (foundation.harness.atomic-write)

writeFileAtomic

  • 签名:writeFileAtomic(root, relPath, data, { mode = 0o644 } = {})(async)
  • 输入:已收容目标路径、文件内容(stringBuffer)。
  • 输出:写入完成的文件,字节与输入一致。
  • 纯函数:否(落盘)。
  • 副作用:在根目录内创建临时文件,先 fsyncrename 覆盖目标;失败时回滚临时文件、不留残影。
  • 稳定错误码与 details.kind:越界路径抛 SFC2004 + PATH_TRAVERSAL/越界类 kind;非法数据类型 / 写失败 + ATOMIC_WRITE_FAILED
  • 前置条件与信任锚:目标路径经 path-containment 验证在根目录内。
  • since / stability0.2.0 / stable
  • 源文件:packages/skill-family-harness-node/src/atomic.mjs
  • 正例/负例测试:packages/skill-family-harness-node/test/atomic.test.mjs
  • 调用方仍拥有的业务语义:写入内容的业务正确性。

临时工作区 (foundation.harness.temporary-workspace)

TemporaryWorkspace / createTemporaryWorkspace / withTemporaryWorkspace

  • 签名:
  • class TemporaryWorkspace(构造 (options)
  • createTemporaryWorkspace(options)(async)
  • withTemporaryWorkspace(fn, options)(async,回调式生命周期)
  • 输入:可选前缀/标签。
  • 输出:临时工作目录句柄;with 在回调结束后清理。
  • 纯函数:否(创建并删除系统临时目录子目录)。
  • 副作用:在宿主临时目录创建子目录,退出/异常时删除;不持久化。
  • 稳定错误码与 details.kind:创建失败 + WORKSPACE_CREATE_FAILED;清理失败 + WORKSPACE_DISPOSE_FAILED;已释放后使用 + WORKSPACE_DISPOSED
  • 前置条件与信任锚:宿主提供可写临时目录(如 os.tmpdir);路径不逃逸出宿主临时根。
  • since / stability0.2.0 / stable
  • 源文件:packages/skill-family-harness-node/src/workspace.mjs
  • 正例/负例测试:packages/skill-family-harness-node/test/workspace.test.mjs
  • 调用方仍拥有的业务语义:临时产物的最终去处(持久态转 state-store)。

资源闭包 (foundation.harness.resource-closure)

computeResourceClosure / digestBytes / closureContains

  • 签名:
  • computeResourceClosure({ root, resources } = {})(async)
  • digestBytes(bytes)
  • closureContains(closure, relPath)
  • 输入:资源列表(路径 + 内容)。
  • 输出:确定性闭包对象与 sha256 摘要;closureContains 判定某相对路径是否在闭包内。
  • 纯函数:digestBytes / closureContains 是;computeResourceClosure 含按 root 读取资源,属受控只读。
  • 副作用:按 root 只读读取资源;不写。
  • 稳定错误码与 details.kind:非法/重复资源声明抛 SFC2004 + CLOSURE_CONFLICT / MISSING_RESOURCE
  • 前置条件与信任锚:资源为可序列化文本条目(二进制投影明确 unsupported);去重与排序固定。
  • since / stability0.2.0 / stable
  • 源文件:packages/skill-family-harness-node/src/closure.mjs
  • 正例/负例测试:packages/skill-family-harness-node/test/closure.test.mjs
  • 调用方仍拥有的业务语义:资源业务含义。

进程监督 (foundation.harness.supervise-process)

superviseProcess / validateTimeoutPolicy

  • 签名:superviseProcess(options, deps = {})(async);validateTimeoutPolicy(policy)
  • 输入:受约束的 command、args、cwd、环境、超时策略与既有监督选项。0.11.0 可选 rawSink 只接受 { root, stdoutFile, stderrFile, onClosed? }:根必须在打开时已是 fresh canonical 目录,两个文件名必须是不同的单段相对名。
  • 可选每流上限:outputByteLimits{ stdout?, stderr? },至少声明一流,各值为 0 到 Number.MAX_SAFE_INTEGER 的整数。按原始字节独立计数,等于上限允许,首次超过上限进入既有进程组终止流程。
  • 输出:一个既有的 watchdog-termination-enveloperawSink.onClosed 只接收冻结的 stdout/stderr { sha256, bytes } 摘要; 它不创建第二种公开 envelope 或 receipt。
  • 副作用:启动一个受监督子进程。raw sink 在 spawn 前以 exclusive/no-follow、0600 打开两个文件,直到 child close、两个 stream close、全部排队写入、fsync 和 handle close 都完成才结束;exit 后到达的字节仍计入摘要。
  • 限额结果:仅配置上限时,evidence 增加 outputByteLimitsoutputLimitExceeded;超限采用 output_limit_exceeded 终止原因。保存的截断流摘要只覆盖已保存字节。流、进程或写入终态未知时仍优先失败关闭。未配置上限保留旧行为。
  • 身份边界:调用方必须在整个调用期间独占 raw sink 的命名空间。文件句柄保护不会证明调用期间 pathname 或根目录身份始终不变; 前后检查只用于尽早失败。
  • 失败语义:选项形状错误抛 TypeError;机制失败抛 SFC2004,沿既有 supervise-process-failed 错误域失败关闭。rawStreamSink 兼容别名、绝对路径、多段文件名、相同 stdout/stderr 名称与非 fresh 根均被拒绝。
  • since / stability:监督入口自 0.5.0 / stable;受约束 raw sink 自 0.11.0,仅提供机制,不承诺宿主资格、认证、领域 判断或发布状态。
  • 源文件:packages/skill-family-harness-node/src/supervise-process.mjs。正反例测试: packages/skill-family-harness-node/test/supervise-process-validation.test.mjspackages/skill-family-harness-node/test/supervise-process-evidence.test.mjs
  • 调用方仍拥有的业务语义:可执行程序选择、超时策略值、输出解释、认证、重试和发布决定。

请求管线 (foundation.harness.request-processing)

parseRequest / processRequest

  • 签名:
  • parseRequest(raw)
  • processRequest(raw, { now = () => new Date() } = {})(async)
  • 输入:原始请求负载(应符合 kernel 协议结构)。
  • 输出:规范化 operation-request 与终态 operation-result(终态集合固定为 REJECTED / FAILED / SUCCESS)。
  • 纯函数:parseRequest 是;processRequest 为纯函数管线(无外部副作用,默认 now 可注入以保证确定性测试)。
  • 副作用:无文件/Git/网络。
  • 稳定错误码与 details.kind:解析失败进入 REJECTED/FAILED 终态并带 SFC2002 / SFC2003 / SFC2004;机制失败 + EXECUTION_FAILED kind
  • 前置条件与信任锚:请求符合 kernel 协议结构;业务语义由消费者拥有。
  • since / stability0.2.0 / stable
  • 源文件:packages/skill-family-harness-node/src/request.mjs
  • 正例/负例测试:packages/skill-family-harness-node/test/request.test.mjs
  • 调用方仍拥有的业务语义:操作的具体业务语义(状态机/重试转 loop-agent)。

报告 (foundation.harness.report)

validateReportModel / renderReportMarkdown / computeResultDigest / computeModelDigest / digestReport / buildBinding / verifyBinding / checkReport / collectStyleWarnings

  • 签名(节选):
  • validateReportModel(reportModel, { resultDocument } = {})
  • renderReportMarkdown(model)
  • computeResultDigest(resultDocument) / computeModelDigest(reportModel) / digestReport(reportMarkdown)
  • buildBinding(reportModel, resultDocument, reportMarkdown)
  • verifyBinding(binding, { reportModel, resultDocument, reportMarkdown } = {})
  • checkReport({ reportMarkdown, reportModel, resultDocument, binding } = {})
  • collectStyleWarnings(reportMarkdown)
  • 输入:report-model、渲染选项(locale / audience / style);SUPPORTED_REPORT_LOCALES = [zh-CN, en-US]
  • 输出:Markdown 文本、绑定对象、分级检查发现;人类报告由机器结果派生,禁止自由撰写。
  • 纯函数:是(无时钟、无环境、无网络、无模型调用)。
  • 副作用:无文件/Git/网络。
  • 稳定错误码与 details.kindSFC3001REPORT_DIGEST_MISMATCH,绑定摘要不符或报告非模型规范渲染)、SFC3002REPORT_ELEMENT_MISSING,强制元素缺失)、SFC3003REPORT_FACT_DRIFT,报告改写绑定结果事实或字节与确定性再渲染不一致)。风格告警由 collectStyleWarnings 产出,仅建议、不编码、不阻断。
  • 前置条件与信任锚:REPORT_RENDERER_NAME / VERSION 取自各自 package(当前 0.3.0);双输出成组写入并拒绝路径别名与输入覆盖。
  • since / stability0.2.0 / stable
  • 源文件:packages/skill-family-harness-node/src/report.mjs
  • 正例/负例测试:packages/skill-family-harness-node/test/report.test.mjs
  • 调用方仍拥有的业务语义:报告业务结论的解读(编排由 Kit report 子动作负责)。

宿主适配机制 (foundation.harness.host-adapter)

normalizeAdapterSource / buildAdapterClosure / verifyAdapterBuildManifest / verifyPeerAdapterDirectories / materializeAdapterBuild / probeVersionVector

  • 签名:
  • normalizeAdapterSource(input)
  • buildAdapterClosure({ hostId, pathCategory, input } = {})
  • verifyAdapterBuildManifest(manifestInput, { hostId, pathCategory } = {})
  • verifyPeerAdapterDirectories({ request, peerRoots } = {})(async):从两个或更多真实 peer 根目录重算共同闭包、标准 manifest 和完整 logicalMappings
  • materializeAdapterBuild({ targetRoot, build, writer = writeFileAtomic } = {})(async)
  • probeVersionVector({ hostId, capabilities, executable, argv, allowSpawn = false, timeoutMs = 5000, runner = spawnSync } = {})(async)
  • 输入:adapter source、目标路径、probe 选项。
  • 输出:构建闭包、校验后的清单、materialize 产物、版本向量。
  • 纯函数:normalizeAdapterSource / buildAdapterClosure / verifyAdapterBuildManifest 是;materializeAdapterBuild / probeVersionVector 含落盘或进程调用。
  • 副作用:materializeAdapterBuild 在受收容目标创建 sibling staging 并单次 rename;probeVersionVector 默认 allowSpawn=false,不取 PATH、不自动执行宿主二进制。
  • 稳定错误码与 details.kind:清单摘要不符 + MANIFEST_MISMATCH;目标已存在 + PORTABLE_PATH_COLLISION;非受信可执行文件 + UNTRUSTED_EXECUTABLE;构建/探测失败 + HOST_BUILD_FAILED / HOST_PROBE_FAILED;契约不符 + HOST_CONTRACT_INVALID;以上均包于 SFC2004
  • 前置条件与信任锚:adapter source 为已声明文本闭包(content 类型固定 string,仅 utf8;二进制投影 unsupported);受信可执行文件方可 materialize。
  • since / stability0.2.0 / stable
  • 源文件:packages/skill-family-harness-node/src/host.mjs
  • 正例/负例测试:packages/skill-family-harness-node/test/host.test.mjs
  • 调用方仍拥有的业务语义:宿主具体业务语义与本地生命周期决策;Kit 只复用本节的绑定读取、严格不替换发布和原子写机制,不由 Harness 注册宿主别名或 driver。

verifyPeerAdapterDirectories 是只读入口。它逐级枚举和读取真实目录,拒绝符号链接、路径逃逸、非普通文件、缺失/多出或逐字节摘要不一致;mapping 必须唯一覆盖每个真实 SKILL.md。它按 peerId 归一化比较闭包,因此请求顺序不会影响结果。失败使用既有 SFC2003/SFC2004details.kind,不返回部分成功,也不写入 peer 根目录。


持久状态底座 (foundation.harness.state-store)

openStateStore / appendEvent / readEvents / readSnapshot / writeSnapshot / verifyStateStore / rebuildSnapshot / inspectStateStoreLock / recoverStateStoreLock / closeStateStore / close

  • 签名(节选):
  • openStateStore(root, { owner, payloadSchemas, clock } = {})(async)
  • appendEvent(store, event)(async)
  • readEvents(store, { afterSequence = 0 } = {})(async)
  • readSnapshot(store, { reducer, initial = null } = {})(async)
  • writeSnapshot(store, state, { hostSessionRef, reducer, initial = null } = {})(async)
  • verifyStateStore(store, { reducer, initial = null } = {})(async)
  • rebuildSnapshot(store, reducer, { initial = null } = {})(async)
  • inspectStateStoreLock(root, { clock } = {})(async)
  • recoverStateStoreLock(root, { ... } = {})(async)
  • closeStateStore(store) / close(store)(async)
  • 输入:事件负载、快照、锁令牌。
  • 输出:事件、hash chain 校验结果、快照;STATE_GENESIS_DIGEST 作为链起点。
  • 纯函数:否(读写事件日志与快照文件,写协作式单写者锁)。
  • 副作用:在受收容路径读写事件日志与快照;写锁文件用于本地协作式单写者。
  • 稳定错误码与 details.kind:hash chain 断裂 + CHAIN_BROKEN;锁 fencing 冲突 + STORE_LOCKED;锁损坏 + LOCK_CORRUPT;恢复拒绝 + LOCK_RECOVERY_REFUSED;非法事件 + UNSAFE_STATE_ENTRY / EVENT_SCHEMA_INVALID;重复序号 + DUPLICATE_SEQUENCE;幂等冲突 + IDEMPOTENCY_CONFLICT;快照不一致 + SNAPSHOT_MISMATCH;已关闭 + STORE_CLOSED;以上均包于 SFC2004
  • 前置条件与信任锚:事件日志为唯一权威,snapshot 为派生缓存;fencing 不承诺抵御同权限恶意进程;confirmOwnerTerminated 信任锚由调用方提供。
  • since / stability0.2.0 / stable
  • 源文件:packages/skill-family-harness-node/src/state-store.mjs
  • 正例/负例测试:packages/skill-family-harness-node/test/state-store.test.mjs
  • 调用方仍拥有的业务语义:事件业务含义、reducer 转移、owner-terminated 信任锚(业务状态机/终态转 loop-agent)。

机制错误 (foundation.harness.errors)

HarnessError / mechanismError / HARNESS_ERROR_KINDS

  • 签名:
  • class HarnessError extends ContractsError(构造 (code, message, details),未登记码立即抛 TypeError
  • mechanismError(kind, message, extraDetails)(返回 SFC2004 + 稳定 details.kind
  • HARNESS_ERROR_KINDS(冻结对象)
  • 输入:错误 kind、上下文。
  • 输出:带稳定 kind 的错误对象;非法 kindTypeError
  • 纯函数:是。
  • 副作用:无。
  • 稳定错误码与 details.kind:本模块不发明新码——机制失败统一 SFC2004EXECUTION_FAILED),其注册含义为「机制运行时执行合规操作时失败;details 携带机制证据」;details.kind 取下列冻结枚举之一。
  • 前置条件与信任锚:HARNESS_ERROR_KINDS 冻结,新增 SFC 码属 Contracts 变更(不在本包写集)。
  • since / stability0.2.0 / stable
  • 源文件:packages/skill-family-harness-node/src/errors.mjs
  • 正例/负例测试:packages/skill-family-harness-node/test/boundary.test.mjsboundaries.test.mjs
  • 调用方仍拥有的业务语义:错误业务归因。

HARNESS_ERROR_KINDS 冻结枚举(v1):

kind 含义
invalid-path / absolute-path / windows-drive-path / windows-path / unc-path 路径形态非法
path-traversal / symlink-escape / realpath-escape 收容逃逸
invalid-root 根目录非法
atomic-write-failed / read-failed 文件读写失败
missing-resource 资源缺失
workspace-create-failed / workspace-dispose-failed / workspace-disposed 临时工作区异常
closure-conflict / unsupported-policy 闭包/策略冲突
execution-failed / invalid-result 执行/结果异常
store-closed / store-locked / lock-corrupt / lock-recovery-refused 状态锁异常
unsafe-state-entry / event-schema-invalid / duplicate-sequence / idempotency-conflict / chain-broken / snapshot-mismatch 状态事件异常
host-contract-invalid / host-build-failed / host-probe-failed / untrusted-executable / portable-path-collision / manifest-mismatch 宿主适配异常
baseline-mismatch / content-guard-rejected 基线物化失败关闭
read-chokepoint-rejected 只读准入拒绝
surface-scan-violation / scan-policy-invalid 表面扫描失败关闭
upper-bound-exceeded 上限守卫越限

基线物化 (foundation.harness.baseline-materialization)

FND-ADR-009。把冻结基线物化为字节保真的临时副本:物化前校验源摘要、物化后同时校验副本摘要与源摘要(捕获物化中途的任一侧变化);副本内符号链接一律拒绝。

computeDirectoryDigest / materializeBaseline

  • 签名:
  • computeDirectoryDigest(rootDir)(async,返回 64 位小写 sha256 十六进制摘要)
  • materializeBaseline({ baselineDir, baselineDigest, prefix = "sf-baseline-" } = {})(async,返回物化根路径)
  • 输入:基线目录与冻结摘要。
  • 输出:确定性目录摘要;物化后的临时目录根路径。
  • 纯函数:否(读源树、在系统临时目录创建副本)。
  • 副作用:只读源基线;写系统临时目录并在失败时清理。
  • 稳定错误码与 details.kind:摘要不符(物化前或物化后)抛 SFC2004 + baseline-mismatch(details 含 phasepre-materialization / post-materialization);目录不可用抛 invalid-root;建目录失败抛 workspace-create-failed
  • 前置条件与信任锚:调用方持有冻结摘要;同一权限级进程可在物化窗口内改动源,机制以双端摘要捕获并失败关闭,不承诺抵御同权限恶意进程。
  • since / stability0.3.0 / stable
  • 源文件:packages/skill-family-harness-node/src/baseline.mjs
  • 正例/负例测试:packages/skill-family-harness-node/test/baseline.test.mjs
  • 调用方仍拥有的业务语义:残留内容判定(contentGuard 谓词)与副本最终去处。

TemporaryWorkspace.fromBaseline({ baselineDir, baselineDigest, prefix, contentGuard })createTemporaryWorkspace({ baseline: { ... } }) 把物化接入工作区生命周期:contentGuard 缺省为允许(字节保真是机制契约,残留判定归消费者);守卫抛错包装为 content-guard-rejected 并 dispose 副本。


只读 chokepoint (foundation.harness.read-chokepoint)

FND-ADR-009。把受保护区域的读取集中到一个准入入口:允许根集合 + 可选身份谓词;越界、链接逃逸与非授权身份一律 read-chokepoint-rejected

createReadChokepoint

  • 签名:createReadChokepoint({ allowRoots, allowIdentity } = {}){ assertReadAllowed, read }
  • 输入:非空允许根集合;可选身份谓词 (identity) => boolean
  • 输出:准入后的 { root, relPath, absolute } 或受收容读取结果。
  • 纯函数:否(async,含只读文件系统访问)。
  • 副作用:只读 realpath / 收容读取;不写。
  • 稳定错误码与 details.kind:越界/逃逸/非授权抛 SFC2004 + read-chokepoint-rejected;资源缺失抛 missing-resource;参数非法抛 TypeError
  • 前置条件与信任锚:调用方声明允许根集合与身份规则;机制不解释任何私有身份或路径语义。
  • since / stability0.3.0 / stable
  • 源文件:packages/skill-family-harness-node/src/chokepoint.mjs
  • 正例/负例测试:packages/skill-family-harness-node/test/chokepoint.test.mjs
  • 调用方仍拥有的业务语义:允许根集合、身份谓词、准入后读取语义。

字符串输入与 { root, relPath } 输入走同一 resolveContained 收容分类(含 macOS /var → /private/var 等符号链接前缀根的统一规范化)。


策略化表面扫描 (foundation.harness.surface-scan)

FND-ADR-009。按 surface-scan-policy 契约文档对声明表面做路径与内容模式扫描:首个命中即失败关闭;策略非法或模式不可编译同样失败关闭;缺失扫描文件不静默跳过。

scanSurface

  • 签名:scanSurface({ root, relPaths, policy, encoding = "utf8" } = {})(async)
  • 输入:扫描根、相对路径清单、策略契约文档。
  • 输出:{ scanned, bytes, policy }(冻结对象)。
  • 纯函数:否(只读文件系统访问;进程内正则编译,无持久状态)。
  • 副作用:只读;不写。
  • 稳定错误码与 details.kind:命中抛 SFC2004 + surface-scan-violation(details 含 kindOfHitpath / content);策略非法或模式不可编译抛 scan-policy-invalid;缺失文件抛 missing-resource;参数非法抛 TypeError
  • 前置条件与信任锚:策略文档通过契约校验;allowedUses 只携带不解释,命中不被豁免(豁免由消费者层实现)。
  • since / stability0.3.0 / stable
  • 源文件:packages/skill-family-harness-node/src/surface-scan.mjs
  • 正例/负例测试:packages/skill-family-harness-node/test/surface-scan.test.mjs
  • 调用方仍拥有的业务语义:策略内容、允许用途语义与命中后的处置。

注入式自测约定:扫描器无状态——注入模式并扫描后移除注入,再次扫描结果字节一致(自测见测试文件,不冒充独立复核)。


token 上界估算 (foundation.harness.token-estimation)

FND-ADR-009。确定性领域估算原语,两个互相独立的估算器:UTF-8 字节数上界(estimateTokenUpperBound)与按 CJK 码位/空白切分的词元数估算(estimateTokens,算法 cjk-char-whitespace-split)。两者均为无模型、无网络、无 tokenizer 依赖、无持久状态导入的纯函数;字节上界结果符合 token-estimate-result 契约(无时间戳,guarantees 为封闭枚举)。每条词元估算记录携带估算器 id 与版本(SFA-CONTEXT-028:消费方必须能回答结果出自哪个估算器),两个估算器的结果不得静默混用、不得互相替代。

estimateTokenUpperBound

  • 签名:estimateTokenUpperBound(text)(纯函数)
  • 输入:文本字符串。
  • 输出:token-estimate-result 对象(upperBound === inputBytes)。
  • 纯函数:是;零依赖。
  • 副作用:无。
  • 稳定错误码与 details.kind:非字符串输入抛 TypeError(无 SFC 码)。
  • 前置条件与信任锚:输入为 JavaScript 字符串;估算只承诺上界(字节数即上界),不承诺真实 token 计数。
  • since / stability0.3.0 / stable
  • 源文件:packages/skill-family-harness-node/src/token-estimate.mjs
  • 正例/负例测试:packages/skill-family-harness-node/test/token-estimate.test.mjs
  • 调用方仍拥有的业务语义:估算结果的解释与消费侧换算(模型调用与真实 token 计数不在 Foundation)。

estimateTokens / isCjkCodePoint / 估算器常量

  • 签名:
  • estimateTokens(text)(纯函数)
  • isCjkCodePoint(codePoint)(纯函数)
  • 常量:TOKEN_ESTIMATOR_IDskill-family.token-estimator)、TOKEN_ESTIMATOR_VERSION1.0.0)、TOKEN_ESTIMATION_ALGORITHMcjk-char-whitespace-split)、CJK_CODE_POINT_RANGES(冻结码位区间表)
  • 输入:文本字符串;isCjkCodePoint 接收整数码位。
  • 输出:冻结的词元估算记录(kind: skill-family.token-estimate-recordschemaVersion: 1),携带 estimator.id / estimator.version / algorithm、输入统计(codePoints / inputBytes)、切分统计(cjkCharacters / whitespaceSeparators / otherRuns)与 tokensunittokensprecisiondeterministic-heuristicscopecontent-text-only
  • 算法(cjk-char-whitespace-split,逐码位单遍扫描):
  • CJK 码位区间(冻结):U+3400–U+4DBF(扩展 A)、U+4E00–U+9FFF(统一表意文字)、U+F900–U+FAFF(兼容表意文字)、U+20000–U+3134F(扩展 B–G)。
  • 每个 CJK 码位计 1 词元,并立即终结其前尚未闭合的 OTHER 段。
  • 连续的非 CJK、非空白码位构成 OTHER 段,被空白或 CJK 码位分隔时每段计 1 词元。
  • 空白(ECMAScript \s 类)只起分隔作用,不贡献词元。
  • 恒等式:tokens === cjkCharacters + otherRuns;中英混排、纯 CJK、纯 ASCII、空串(0 词元)全部适用。
  • 纯函数:是;零依赖、零 import(模块纯度由测试复检)。
  • 副作用:无。
  • 稳定错误码与 details.kind:非字符串输入抛 TypeError(无 SFC 码)。
  • 前置条件与信任锚:估算是对目标 tokenizer 的确定性启发式近似,不承诺与任何具体模型 tokenizer 相等;比较阈值时同一批次必须使用同一估算器(记录内的 estimatoralgorithm 即裁决依据)。
  • since / stability0.6.0 / stable
  • 源文件:packages/skill-family-harness-node/src/token-estimate.mjs
  • 正例/负例测试:packages/skill-family-harness-node/test/token-estimator.test.mjs(中英混排、纯 CJK、纯 ASCII、空串与空白串、扩展 B 码位、区间边界、记录封闭键集、恒等式、确定性、CLI 子进程行为)。
  • 调用方仍拥有的业务语义:阈值策略与超限处置;把启发式词元数换算为目标模型的真实消耗。

CLI:skill-family-token-estimate

  • 入口:harness 包 bin skill-family-token-estimatesrc/token-estimate-cli.mjs);与工程 Kit 的四命令互不混用。
  • 用法:skill-family-token-estimate (--text <s> | --file <p> | --stdin) [--estimator tokens|upper-bound|both];默认 --estimator tokensboth 输出 { tokens, upperBound } 两个键,明示两个估算器并存而非混合。
  • 输出:stdout 打印 JSON 估算记录(tokens 为估算记录,upper-boundtoken-estimate-result),换行结尾。
  • 副作用:只读取命令行参数、--file 指定文件或 stdin;只写 stdout。
  • 稳定退出码:0 成功;2 用法错误(输入源缺失或互斥、未知参数、--file 目标不是普通文件等,stderr 给出原因);--help 打印用法后退出 0。
  • 前置条件与信任锚:--file 按调用方给定的路径原样读取,CLI 不做路径收容;需要收容时在库内用 readFileContained
  • since / stability0.6.0 / stable
  • 源文件:packages/skill-family-harness-node/src/token-estimate-cli.mjs
  • 正例/负例测试:packages/skill-family-harness-node/test/token-estimator.test.mjs(子进程 CLI 用例:确定性、--file/--stdin/both、用法错误退出码 2、--help)。
  • 调用方仍拥有的业务语义:输入文本的采集与裁剪策略、输出记录的归档位置。

通用上限守卫 (foundation.harness.upper-bound-guard)

FND-ADR-009。复用 state-store 事件账与 token-lock 显式占用实现通用上限守卫:越限事件失败关闭且不写入;上限值、单位类别与超限策略全部由消费者配置,模块不携带任何固定数额或定价词汇。

openUsageGuard / appendUsageEvent / readUsage / closeUsageGuard

  • 签名:
  • openUsageGuard({ stateRoot, owner, payloadSchemas, reducer, initial = 0, upperBound, lockRoot, lockPath, clock } = {})(async)
  • appendUsageEvent(guard, event, { beforeCommit } = {})(async)
  • readUsage(guard)(async)
  • closeUsageGuard(guard)(async)
  • 输入:事件负载、纯归约函数、非负上限、状态根与锁根/锁路径。
  • 输出:追加结果、当前用量读数、守卫句柄。
  • 纯函数:否(写事件账与锁文件)。
  • 副作用:在受收容路径写事件账与锁文件;打开时显式占用锁、关闭时释放。
  • 稳定错误码与 details.kind:越限抛 SFC2004 + upper-bound-exceeded(details 含 upperBound / projected,事件不写入);锁被占用抛 store-locked;事件账断链抛 chain-broken;事件 schema 违规抛 event-schema-invalid
  • 前置条件与信任锚:lockRoot/lockPath 由消费者指定在 state store 根之外;事件账是唯一权威;fencing 不承诺抵御同权限恶意进程。
  • since / stability0.3.0 / stable
  • 源文件:packages/skill-family-harness-node/src/budget-guard.mjs
  • 正例/负例测试:packages/skill-family-harness-node/test/budget-guard.test.mjs
  • 调用方仍拥有的业务语义:事件含义、归约函数、上限数值与超限后的业务处置(定价与计费语义留在消费者)。

Quickstart Profile v2 candidate

规范入口 skill-family-harness-node/quickstart-profile 负责创建 observation Resource、Task 与终态 Result,并复验真实 文件字节、Resource id 全局唯一性、Task digest、operation 身份、逐字段 run/stage/attempt 以及 evidence 精确回指。 历史入口 skill-family-harness-node/candidate/quickstart-profile 在弃用窗口内解析同一模块;消费者应迁移一次。 verifyQuickstartExchange 把机制拒绝转换成结构化结果,抛出式入口继续使用已登记的 SFC2004 与稳定 details.kind

invokeFoundationMechanism

invokeFoundationMechanism(request) 是固定机制桥接。调用方只能选择预先登记的 operation,不能传入模块名、导出名或任意函数。0.8.2 新增的 read-file-strict 直接调用上文的 readFileStrict

{
  "operation": "read-file-strict",
  "params": {
    "root": "/absolute/consumer-root",
    "path": "authority/frozen.json",
    "encoding": "utf8",
    "expectedSha256": "<lowercase-sha256>"
  }
}

params 是闭合对象。rootpath 是必填非空字符串;encoding 只能是 utf8 或省略;expectedSha256 省略时不做预期摘要比对,提供时沿用核心严格读取合同。

桥接保留核心回执的 pathsha256bytesmode。UTF-8 内容仍是字符串;二进制内容投影成 Node 标准的 Buffer JSON 形态 { "type": "Buffer", "data": [...] },以便通过 JSON 传输后无损还原字节。

直接调用失败时沿用核心异常,包括 SFC2004details.kind。候选 mechanisms-cli.mjs 继续使用一请求一响应 JSON:成功退出 0,拒绝或用法错误退出 2;CLI 错误 JSON 只承诺 namemessage,不承诺跨语言保留 details

该入口不选择 method,不解释 domainResult,也不拥有重试、调度或生命周期。消费者必须把 Contracts、Harness 与 Engineering Kit 精确锁定到同一版本;不能从 Foundation 工作树导入源码。0.3.0 的 v2 与 0.2.1 的 v1 不兼容。 迁移到规范入口和 Schema 身份后,后续仅晋升 stable 不再要求改合同身份;消费者仍需更新精确 pin 才能取得新发布的 stable 承诺,Bundle 是否重建由既有包字节与 provenance 绑定输入决定。

rename-directory-no-replace 的规范入口是 skill-family-harness-node/rename-directory-no-replace;历史 /candidate/rename-directory-no-replace 入口解析同一原生原语。 该原语仍不等同于稳定的高层 fixed-set-publication,消费者应根据所需合同选择,不得用别名混淆两个能力层次。


与机器事实层的互链

  • 能力稳定 ID 见 docs/agents/capability-catalog.jsonfoundation.harness.*)。
  • 机械校验:scripts/docs/capability-catalog-check.mjs 解析 src/index.mjs,拒绝引用不存在的入口。