skill-family-harness-node 公共 API 参考¶
本页从真实导出(src/index.mjs 与各源模块)核对,不手写无法证明新鲜度的全集。每个公共入口按 hand-off §4.3 说明:签名、输入与输出、是否纯函数、文件/进程/Git/网络副作用、稳定错误码与 details.kind、前置条件与信任锚、since 与 stability、源文件与正例/负例测试、调用方仍拥有的业务语义。
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 对应):
- 契约校验 →
validateContractDocument/getValidator - 路径收容 →
classifyPathInput/resolveContained/readFileContained - 严格读取 →
readFileStrict - 身份绑定读取 →
createFilesystemRootBinding/readFileBound - 固定集合发布 →
createFixedSetPublicationManifest/publishFixedSet - 原子写 →
writeFileAtomic - 临时工作区 →
TemporaryWorkspace/withTemporaryWorkspace - 资源闭包 →
computeResourceClosure/digestBytes/closureContains - 进程监督 →
superviseProcess/validateTimeoutPolicy - 请求管线 →
parseRequest/processRequest - 报告 →
validateReportModel/renderReportMarkdown/buildBinding/verifyBinding/checkReport - 宿主适配机制 →
normalizeAdapterSource/buildAdapterClosure/materializeAdapterBuild/probeVersionVector - 持久状态底座 →
openStateStore/appendEvent/readSnapshot/verifyStateStore… - 基线物化 →
computeDirectoryDigest/materializeBaseline(FND-ADR-009) - 只读 chokepoint →
createReadChokepoint(FND-ADR-009) - 策略化表面扫描 →
scanSurface(FND-ADR-009) - token 上界估算 →
estimateTokenUpperBound/estimateTokens(FND-ADR-009) - 通用上限守卫 →
openUsageGuard/appendUsageEvent/readUsage/closeUsageGuard(FND-ADR-009) - 机制错误 →
HarnessError/mechanismError/HARNESS_ERROR_KINDS
契约校验 (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:沿用 ContractsSFC1001/SFC1002/SFC1006;底层机制失败统一SFC2004+HARNESS_ERROR_KINDS的kind(如INVALID_PATH)。 - 前置条件与信任锚:已安装
skill-family-contracts;Ajv 8.20.0。 since/stability:0.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/readFileContained为async,含只读文件系统访问。 - 副作用:只读文件系统访问(读取/解析);不写。
- 稳定错误码与
details.kind:机制失败抛HarnessError(SFC2004)+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/stability:0.2.0/stable。- 源文件:
packages/skill-family-harness-node/src/paths.mjs。 - 正例/负例测试:
packages/skill-family-harness-node/test/containment.test.mjs、boundaries.test.mjs。 - 调用方仍拥有的业务语义:哪些路径是业务允许的选择规则(业务选择语义留在调用方)。
严格读取 (foundation.harness.strict-read)¶
readFileStrict¶
- 签名:
readFileStrict(root, relPath, { encoding?, expectedSha256? } = {})(async)。 - 输入:收容根目录、相对文件路径,可选的
utf8编码与小写 sha256 预期摘要。 - 输出:冻结回执
{ path, content, sha256, bytes, mode }。指定utf8时,content是字符串;省略编码时,content是Buffer。 - 纯函数:否,函数只读一个受收容的普通文件。
- 副作用:执行
lstat、open、read与文件身份复核;不写文件,不访问 Git 或网络。 - 稳定错误码与
details.kind:失败使用SFC2004。缺失文件返回missing-resource,摘要不符返回content-guard-rejected,目录返回read-failed,越界路径沿用路径收容的失败种类。 - 符号链接边界:叶节点符号链接始终拒绝。祖先目录可以是指向根内目录的符号链接;其规范路径仍须受
root收容。 - 前置条件与信任锚:
expectedSha256的来源与信任由调用方负责;摘要只覆盖实际读到的字节。 since/stability:0.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得到的完整 POSIXst_mode,包括文件类型与特殊权限位。 - 语义边界:根与中间目录由固定四平台 N-API 闭包以不跟随符号链接的句柄相对方式获取;叶子必须是单链接普通文件。句柄不会逃逸,调用结束前关闭。绑定读取不提供删除或恢复状态机。
- 副作用:只读文件系统访问;不写文件、不触 Git、网络或进程。
- 错误:根身份不符、符号链接组件、缺失资源和摘要不符均失败关闭;不支持的 Darwin/Linux 架构不提供 JavaScript 回退。
since/stability:0.9.0/stable。- 源文件:
packages/skill-family-harness-node/src/bound-read.mjs与src/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。文件成员包含同次读取的contentBase64、sha256、bytes与完整 POSIXstatMode;目录成员只含路径、类型和模式,不伪造文件摘要。 - 副作用:只读文件系统,不安装、不启动进程、不访问网络。结果含原始文件内容,调用方必须保护敏感数据。
- 失败语义:参数不合法抛
TypeError,机制失败沿SFC2004关闭,不把部分观察报告为成功。 - 保证边界:每次检查同一根绑定,不使用旧缓存;不承诺整个操作期间的连续路径身份或事务快照。
since/stability:0.13.0/candidate。观察完成不等于消费者接受载荷。- 源文件:
packages/skill-family-harness-node/src/filesystem-observation.mjs与src/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 终态为
succeeded、refused、failed或indeterminate。 - 语义边界:发布使用 Darwin
renameatx_np(RENAME_EXCL)或 Linuxrenameat2(RENAME_NOREPLACE)的固定原生闭包;不使用检查后rename的 JavaScript 替代,不提供身份保护删除,不自动重试、回滚或恢复indeterminate。 - 副作用:仅在成功时对目标目录执行一次不替换发布;失败关闭。
since/stability:0.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) - 输入:已收容目标路径、文件内容(
string或Buffer)。 - 输出:写入完成的文件,字节与输入一致。
- 纯函数:否(落盘)。
- 副作用:在根目录内创建临时文件,先
fsync再rename覆盖目标;失败时回滚临时文件、不留残影。 - 稳定错误码与
details.kind:越界路径抛SFC2004+PATH_TRAVERSAL/越界类kind;非法数据类型 / 写失败+ ATOMIC_WRITE_FAILED。 - 前置条件与信任锚:目标路径经
path-containment验证在根目录内。 since/stability:0.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/stability:0.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/stability:0.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-envelope。rawSink.onClosed只接收冻结的 stdout/stderr{ sha256, bytes }摘要; 它不创建第二种公开 envelope 或 receipt。 - 副作用:启动一个受监督子进程。raw sink 在 spawn 前以 exclusive/no-follow、0600 打开两个文件,直到 child
close、两个 streamclose、全部排队写入、fsync和 handleclose都完成才结束;exit 后到达的字节仍计入摘要。 - 限额结果:仅配置上限时,
evidence增加outputByteLimits和outputLimitExceeded;超限采用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.mjs、packages/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_FAILEDkind。 - 前置条件与信任锚:请求符合 kernel 协议结构;业务语义由消费者拥有。
since/stability:0.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.kind:SFC3001(REPORT_DIGEST_MISMATCH,绑定摘要不符或报告非模型规范渲染)、SFC3002(REPORT_ELEMENT_MISSING,强制元素缺失)、SFC3003(REPORT_FACT_DRIFT,报告改写绑定结果事实或字节与确定性再渲染不一致)。风格告警由collectStyleWarnings产出,仅建议、不编码、不阻断。 - 前置条件与信任锚:
REPORT_RENDERER_NAME/VERSION取自各自 package(当前0.3.0);双输出成组写入并拒绝路径别名与输入覆盖。 since/stability:0.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/stability:0.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/SFC2004 与 details.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/stability:0.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的错误对象;非法kind抛TypeError。 - 纯函数:是。
- 副作用:无。
- 稳定错误码与
details.kind:本模块不发明新码——机制失败统一SFC2004(EXECUTION_FAILED),其注册含义为「机制运行时执行合规操作时失败;details 携带机制证据」;details.kind取下列冻结枚举之一。 - 前置条件与信任锚:
HARNESS_ERROR_KINDS冻结,新增 SFC 码属 Contracts 变更(不在本包写集)。 since/stability:0.2.0/stable。- 源文件:
packages/skill-family-harness-node/src/errors.mjs。 - 正例/负例测试:
packages/skill-family-harness-node/test/boundary.test.mjs、boundaries.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 含phase:pre-materialization/post-materialization);目录不可用抛invalid-root;建目录失败抛workspace-create-failed。 - 前置条件与信任锚:调用方持有冻结摘要;同一权限级进程可在物化窗口内改动源,机制以双端摘要捕获并失败关闭,不承诺抵御同权限恶意进程。
since/stability:0.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/stability:0.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 含kindOfHit:path/content);策略非法或模式不可编译抛scan-policy-invalid;缺失文件抛missing-resource;参数非法抛TypeError。 - 前置条件与信任锚:策略文档通过契约校验;
allowedUses只携带不解释,命中不被豁免(豁免由消费者层实现)。 since/stability:0.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/stability:0.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_ID(skill-family.token-estimator)、TOKEN_ESTIMATOR_VERSION(1.0.0)、TOKEN_ESTIMATION_ALGORITHM(cjk-char-whitespace-split)、CJK_CODE_POINT_RANGES(冻结码位区间表) - 输入:文本字符串;
isCjkCodePoint接收整数码位。 - 输出:冻结的词元估算记录(
kind: skill-family.token-estimate-record,schemaVersion: 1),携带estimator.id/estimator.version/algorithm、输入统计(codePoints/inputBytes)、切分统计(cjkCharacters/whitespaceSeparators/otherRuns)与tokens;unit为tokens,precision为deterministic-heuristic,scope为content-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 相等;比较阈值时同一批次必须使用同一估算器(记录内的
estimator与algorithm即裁决依据)。 since/stability:0.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-estimate(src/token-estimate-cli.mjs);与工程 Kit 的四命令互不混用。 - 用法:
skill-family-token-estimate (--text <s> | --file <p> | --stdin) [--estimator tokens|upper-bound|both];默认--estimator tokens。both输出{ tokens, upperBound }两个键,明示两个估算器并存而非混合。 - 输出:stdout 打印 JSON 估算记录(
tokens为估算记录,upper-bound为token-estimate-result),换行结尾。 - 副作用:只读取命令行参数、
--file指定文件或 stdin;只写 stdout。 - 稳定退出码:
0成功;2用法错误(输入源缺失或互斥、未知参数、--file目标不是普通文件等,stderr 给出原因);--help打印用法后退出 0。 - 前置条件与信任锚:
--file按调用方给定的路径原样读取,CLI 不做路径收容;需要收容时在库内用readFileContained。 since/stability:0.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/stability:0.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 是闭合对象。root 与 path 是必填非空字符串;encoding 只能是 utf8 或省略;expectedSha256 省略时不做预期摘要比对,提供时沿用核心严格读取合同。
桥接保留核心回执的 path、sha256、bytes 与 mode。UTF-8 内容仍是字符串;二进制内容投影成 Node 标准的 Buffer JSON 形态 { "type": "Buffer", "data": [...] },以便通过 JSON 传输后无损还原字节。
直接调用失败时沿用核心异常,包括 SFC2004 与 details.kind。候选 mechanisms-cli.mjs 继续使用一请求一响应 JSON:成功退出 0,拒绝或用法错误退出 2;CLI 错误 JSON 只承诺 name 与 message,不承诺跨语言保留 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.json(foundation.harness.*)。 - 机械校验:
scripts/docs/capability-catalog-check.mjs解析src/index.mjs,拒绝引用不存在的入口。