|
5
|
2
|
5
|
0.16.0
|
0.16.0
|
1789048757
|
0
|
{"scope":"@juhai","name":& {"scope":"@juhai","name":"kernel","description":"基础框架内核契约(租户/信封/状态机/重放/请求上下文/平台端口/RLS/告警/作业)——源码留在 base-framework 仓,上层按框架版本 pin","license":"UNLICENSED","dependencies":{"zod":"^3.24.1"},"development_dependencies":{"typescript":"^5.7.2","vitest":"^2.1.8"},"readme":"ERROR: No README data found!","repository":{"type":"git","url":"git@gitea.g-hi.com:luoanwu/base-framework.git"}}...
|
1
|
Edit
Delete
|
|
6
|
2
|
5
|
0.16.1
|
0.16.1
|
1789049321
|
0
|
{"scope":"@juhai","name":& {"scope":"@juhai","name":"kernel","description":"基础框架内核契约(租户/信封/状态机/重放/请求上下文/平台端口/RLS/告警/作业)——源码留在 base-framework 仓,上层按框架版本 pin","license":"UNLICENSED","dependencies":{"zod":"^3.24.1"},"development_dependencies":{"typescript":"^5.7.2","vitest":"^2.1.8"},"readme":"ERROR: No README data found!","repository":{"type":"git","url":"git@gitea.g-hi.com:luoanwu/base-framework.git"}}...
|
78
|
Edit
Delete
|
|
7
|
3
|
5
|
1.0.0-rc.0
|
1.0.0-rc.0
|
1789202442
|
0
|
{"scope":"@juhai","name":& {"scope":"@juhai","name":"contracts","description":"企业应用群机器契约:Catalog、JSON Schema、OpenAPI、兼容基线与治理 Linter(基础设施仓 contracts/,DEC-010 / DEC-031)","license":"UNLICENSED","dependencies":{"ajv":"8.20.0","ajv-formats":"3.0.1"},"development_dependencies":{"@types/node":"20.19.43","json-schema-to-typescript":"16.0.0","typescript":"5.9.3"},"readme":"# @juhai/contracts(原 platform-contracts 候选控制面)\n\n## 在 enterprise-platform 内的状态(PF-04 阶段 1,2026-09-10)\n\n- **身份**:本目录是 `企业应用/platform-contracts/` 的带来源登记导入(见 [SOURCE.md](SOURCE.md));包名按 DEC-031 命名修订改为 `@juhai/contracts`,版本 `1.0.0-rc.0`(rc 系列;非 rc `1.0.0` 受 DEC-010 附条件:远端 + Required Check)。`catalogs/`、`contracts/`、`examples/`、`apps/`、`compatibility/` 与来源逐字节一致;`schemas/` 仅含下述 PF-04 的 `causation_id` / `correlation_id` 变更。\n- **工作区根**:Linter、影响图与测试以「工作区根」(`企业应用/`,同时含 `基础/` 与 `doc/`)为基准解析 Catalog `directory` / `evidence`、DEC `source` 与各应用仓路径,不再假定包位于工作区根的直接子目录。解析顺序:`--workspace-root \u003cabs\u003e`(`node scripts/check.mjs --workspace-root …`)→ 环境变量 `PLATFORM_CONTRACTS_WORKSPACE_ROOT` → 自动探测(从本目录向上找到首个同时含 `基础/` 与 `doc/` 的祖先)。经 `pnpm` 复合脚本运行时请用环境变量(pnpm 只把额外参数附加到最后一条命令)。\n- **独立克隆**(无 `基础/` 与 `doc/` 祖先,例如云端 CI 只 checkout 本仓;2026-09-12):`check:local` 的影响图以 `--workspace-optional` 退化为\"仅包内\"计算并在 stderr 打印 `[WORKSPACE_ROOT_UNRESOLVED]` 提示,不核验 Catalog / AppManifest / 裁决的路径引用;依赖应用仓文件、工作区路径或真实探测结果的 16 个测试显式 `skip`(91 例中 75 例照跑)。`check` 与 `check:impact` 在独立克隆下仍失败关闭(退出码 2),显式 `--workspace-root` / 环境变量不可用时任何模式都失败关闭。\n- **TS 层(CT-1)**:`scripts/schema-registry.mjs` 是 key → Schema 文件 → 类型名的唯一来源;改 Schema 后运行 `pnpm generate` 重生成 `generated/`,`pnpm check:generated`(在 `check:local` 内)在缺失 / 差异 / 多余文件时失败;`pnpm build`(tsc → `dist/`)在 `test` 与 `check:local` 之前自动执行;首次使用需 `pnpm --dir contracts install`(依赖只来自公共 npm,全部 exact pin)。\n- **`pnpm check` 现状**:`check` 报告且仅报告 6 项 `PLATFORM_PROJECT_UNREGISTERED`(`基础/reports`、`基础/tests`、`基础/企业搜索与统一检索平台`、`基础/外部连接器与集成平台`、`基础/开发者自助与应用工程平台`、`基础/数据治理与隐私平台`),全部随 CHG-001(新增基础应用 MachineCatalog 变更)合并后消失;Linter 未被放宽。合并前以 `pnpm check:local`(schema 兼容 + 影响图 + 测试)作为绿色门禁;CHG-001 合并后 `check` 转绿,根 `pnpm check` 再切回完整 `check`。\n- **`causation_id` 可选、`correlation_id` 映射**(设计 §7 / §25 张力 4):`schemas/fact-envelope.v1.schema.json` 的 `required` 去掉 `causation_id`(旅程首条事实没有因果父,省略而非填占位值);`trace_id` = 旅程锚点、`correlation_id` = 业务关联写入 `fact-envelope.v1` 与 `request-context.v1` 的 `description`(后者只加说明)。Linter 新增规则 `FACT_ENVELOPE_FIELD_NOT_OPTIONAL` 防止回退为必填;`test/fact-envelope.test.mjs` 用兼容检查器自身的规则证明该放宽向后兼容(反向则报 `REQUIRED_PROPERTY_ADDED`)。`compatibility/` 冻结基线未动(信封不在基线内)。\n- **消费**:`pnpm add @juhai/contracts@1.0.0-rc.N`(exact pin,`check:pins` 强制);子路径导出 `@juhai/contracts/catalogs/*`、`/schemas/*`、`/contracts/*`、`/examples/*`、`/apps/*`、`/compatibility/*`、`/scripts/*`、`/package.json`;**裸入口(CT-1,2026-09-12)**:`import { validate, validateFact, assertValid, isValid, schemaOf, SCHEMA_KEYS, type FactEnvelopeV1 } from '@juhai/contracts'`——12 个 JSON Schema 的 TypeScript 类型(`generated/`,由 `schemas/` 生成并入库)与 Ajv 2020 校验器(按 key 懒编译;未知 key 抛 `RangeError`;`validateFact` 先验信封再按 `facts/\u003cfact_type\u003e.v\u003cmajor\u003e` 验载荷,未登记载荷 Schema 以 `payloadSchema` 失败关闭);`dist/` 随包发布,运行依赖仅 `ajv` / `ajv-formats`;`test/`、`src/`、`generated/` 不随包发布。\n\n本目录是企业应用群 Git-first 机器契约的 **W1 候选实现**,用于先建立可校验的语义基线。`DEC-010` 尚未裁决 Catalog 的最终物理位置,因此这里的 Registry、AppManifest 和 Schema 均为 `proposed` 或 `draft`,不能作为“能力已上线”的证据。\n\n## 已覆盖\n\n- `Employment` 的唯一 Owner、Canonical ID 目标格式与数据分级,以及企业 IdP 已实现权威模型的目录对账;\n- `FactEnvelope v1` JSON Schema;\n- `EmploymentTransferred v1` Payload JSON Schema;\n- HR、Digital Employee OS、Permission Platform、企业 IdP、执行监管、基础框架、嗨设、巨嗨智服、知识云、设备云、巨嗨报价系统与尤克特拉十二个草案 AppManifest;\n- Fact Producer/Consumer、Projection/Replay 和待裁决 Owner 的静态治理检查;Fact Projection 进一步绑定 Consumer、只读 Authority、状态 Schema、`consumer_name + fact_id` 幂等、Projection + `processed_fact` 原子提交、单调但不连续的聚合版本语义,以及受 Backbone ADR 阻断的消息 Gap 检测;\n- Resource/Action Catalog v1、Actor/Request Context v1 和 Permission Decision API v1 候选契约;\n- DEC-001—030 全量 Decision Catalog 登记(5 approved / 27 pending,2026-09-10 批准 DEC-010 / 031 / 032),并校验所有 Catalog 引用的裁决可解析;\n- 权限请求/拒绝样例,强制租户一致、未知资源/动作拒绝、故障关闭和拒绝不正缓存;\n- DEC-012 完整候选 ADR、首条 Fact Schema 的不可变 proposed Snapshot 与保守向后兼容检查器;\n- 从 Catalog + AppManifest 构建的 proposed Producer/Consumer Impact Graph 与变更查询 CLI;\n- `基础/` 21 个平台目录的机器项目清单:19 个属于本轮目标,明确排除基础框架与 AI 数字员工;实现状态、代码真源、证据等级和阻塞 DEC 可查询;\n- 可执行的正向检查和 Owner、ADR、Canonical ID、PII、Replay、Consumer、Application Dependency、Permission、Schema Compatibility 负向边界测试。\n\n## 尚未裁决,禁止越权实现\n\n- `Person`、`Organization`、`Store`、`Position`、`Actor` Owner(`DEC-001`—`DEC-005`);\n- AppManifest/ProductManifest 边界、Catalog 物理真源和双 Envelope 边界(`DEC-009`—`DEC-011`,评审材料已形成但尚未批准);\n- Schema 最终组合与兼容策略批准(`DEC-012`);候选检查器只证明当前规则可机械执行,不是正式发布策略;\n- Broker、Topic、Fact Store 与 Ordering(`DEC-013`—`DEC-016`);\n- Scope 执行和权限分工(`DEC-017`—`DEC-019`);\n- 权限平台的引擎、策略存储和运行时技术路线(`DEC-029`)。\n- 尤克特拉身份、设备、客户、订单、执行与通知重名实体的 Owner、映射和迁移方案(`DEC-030`,其中 Store 仍受 `DEC-003` 阻塞)。\n- 平台契约与 SDK 的分发通道、发布包名登记与发布门禁(`DEC-031`);裁决前派生仓 Planner 只能以夹具或标注来源 SHA 的过渡复制形式被业务仓引用,不得冒充平台接入。\n\n因此 Permission Decision API 是可评审、可机械验证的候选边界,不是权限引擎已实现或已上线的声明。Actor Context 仅携带 IdP 已认证的不透明主体标识,不越权裁决 `Actor` 企业 Owner。\n\n`DEC-027/028` 已批准并进入 HR 实现;Linter 仍会阻止草案 Manifest 标记为 `active`,也不允许 `EmploymentTransferred` 越过 `DEC-010/012` 直接激活。\n\n企业 IdP 草案清单已对账其当前 E2 代码中的 Tenant/User、Application/OIDC Client、Credential/Authenticator、Consent、Session、Authorization Code/Grant、Refresh Token Family/Token、Backchannel Delivery 与 Security Event 等权威模型;这仍不代表生产 KMS/HSM、远程 CI 或生产部署已签收。`User` 是 IdP 账户主体,不等同于 DEC-001 尚未裁决的企业 `Person`。嗨设现已真实消费 IdP RS256 access token/JWKS,并登记 `material.production` 候选权限面;它只保存 actor 引用,不拥有 Tenant/User/Session/Grant。执行监管的 Project/Ticket/SLA 仍未进入企业 Entity Catalog。知识云则登记 `KnowledgeCandidate`、`KnowledgeAtom`、`KnowledgeAtomVersion`、`KnowledgeSource` 与 `KnowledgeFeedback` 五个权威对象;`KnowledgeEmbedding`、检索 Evidence 与 AI 推理结果都是可重建派生物,不得冒充企业权威实体。巨嗨报价系统已将当前 Prisma 的 68 个业务模型登记为权威对象,并由测试持续与真实 schema 对账;本地 `User/UserEvent` 及 `Outbox/OutboxReplayEvent` 明确排除,避免抢占 IdP 身份 Owner 或把技术投递记录冒充企业业务实体。尤克特拉只登记已验证的 Express/PostgreSQL 运行时,其 71 个 Prisma 模型中与全局 Catalog 重名的七个对象由 DEC-030 阻断,Fact、统一 Permission、Projection 和权威 Entity 保持空集;这不把本地数据误报成共享真源,也不把单后端误报成双后端。基础框架只作为工程模板登记,不拥有企业业务事实。\n\nPlatform Project Catalog 当前只允许企业 IdP 声明独立服务 `implemented_e2`;通知与 Webhook 中心、公共文件平台及配置与功能开关平台声明 `module_e2`。公共文件已由执行监管、巨嗨报价与嗨设三个真实消费者完成 E2 运行验证;通知投递已由执行监管、巨嗨智服与巨嗨报价三个真实消费者完成 E2 运行验证;配置平台当前只有执行监管一个真实业务消费者,生产无有效批准快照时关闭、坏刷新保留最后良好版本,并把版本/摘要/来源/原因写入 AutomationRun。前三者都不表示 G4 已裁决或独立服务已启动;配置平台尤其仍缺第二、第三消费者。报价本地 `QuotationNotificationIntent` 是技术投递记录,不登记为企业权威实体。应用与契约注册中心、企业事实干线和统一权限平台仅为 `candidate_e0`;其余目标平台仍是 `not_started`。各平台目录内复制的 `base-framework/` 一律不计为平台实现,任何 E2 证据文件都必须真实存在并报告 `passed`。\n\n## 使用\n\n无需安装第三方依赖,Node.js 20+ 即可运行:\n\n```bash\nnpm run check\nnpm test\n```\n\n`check` 校验平台项目目录、目标范围、证据、Schema 引用、Owner、Producer/Consumer、Projection/Replay、幂等/原子提交/版本顺序、权限与 Scope 对账,并对每个已登记 Fact 执行 proposed Snapshot 不可变/版本兼容检查;`test` 证明目录漏登、模板冒充实现、E2 证据未通过、Owner 冲突、Consumer 绑定漂移、Owner 越权、非原子 Projection、错误连续版本假设、Projection PII/来源漂移与不兼容 Schema 会失败。\n\n查询一个 Fact Schema 变更的直接与二跳影响:\n\n```bash\nnpm run impact -- schema schemas/facts/EmploymentTransferred.v1.json 2\n```\n\n输出明确区分节点深度,并列出 Producer、Consumers、Projections、Entity、阻塞 Decision 与相关边;未知目标返回非零退出码,不生成空的“无影响”结果。\n\n## 状态升级规则\n\n只有同时满足以下条件,才能把本目录从候选实现升级为正式真源:\n\n1. `DEC-010` ADR 已批准;\n2. `DEC-012` Schema 表达和兼容策略已批准;\n3. App Owner 对 AppManifest 与真实代码、部署资产完成核验;\n4. CI 使用本 Linter 或其正式替代品阻断冲突;\n5. 运行时证据证明事实生产、消费、幂等与 Replay,而不只是静态文件通过。\n","repository":{"type":"","url":""}}...
|
8
|
Edit
Delete
|
|
8
|
4
|
5
|
1.0.0-rc.0
|
1.0.0-rc.0
|
1789202446
|
0
|
{"scope":"@juhai","name":& {"scope":"@juhai","name":"governance","description":"基础设施层跨仓门禁(设计方案 §9):check:pins(exact pin 消费规则)、check:fixtures(契约正反例夹具)、verify:candidate(候选可晋级核验)、release:manifest(已知事实清单)、CI 模板;零依赖 CLI,供上层仓 exact pin 后在 CI 运行。","license":"UNLICENSED","bin":{"juhai-governance":"bin/cli.mjs"},"readme":"# @juhai/governance — 基础设施跨仓门禁\n\n设计方案 §4.2 / §9 定义的 `governance/` 交付:一组**零依赖**的构建期检查,随基础设施仓同一 Release 版本号发布到 Gitea npm registry(DEC-031),供上层仓 **exact pin** 后在 CI 运行(`check:pins` 为必需检查,DEC-031 附带条款 4)。\n\n## 命令(`juhai-governance \u003ccommand\u003e [--root \u003cdir\u003e]`)\n\n| 命令 | 用途 | 报告 | 退出码 |\n|---|---|---|---|\n| `check:pins [--require \u003cpkg\u003e]…` | `@juhai/*` 依赖只允许 `x.y.z` 或 `workspace:*`;`--require` 要求该包至少一处 exact pin(证明消费者已接入) | 无(stdout) | 1 = 有违规 |\n| `check:fixtures --suite \u003csuite.json\u003e…` | 契约正反例夹具套件:ACCEPT 须零原因、REJECT 须有原因且含声明前缀;`format: dec-039` 复用既有检查器;`workspaceRelative` 套件在独立克隆里报告 unavailable | `reports/fixtures.latest.json` | 1 = 任一用例不符 |\n| `verify:candidate --candidate \u003cdir\u003e --sha \u003csha\u003e …` | 候选可晋级核验(Q12-C / X12):逐份 required 报告核 sourceSha / dirty / 状态 / 地板 / digest,缺失即不合格 | `\u003cdir\u003e/release-candidate.json` 或 `--out` | 1 = 不合格 |\n| `release:manifest` | 已知事实清单,**逐项按磁盘判定**:`governance/package.json`、`runtime/clients/\u003cm\u003e/package.json`(name 须为 `@juhai/client-\u003cm\u003e`)、`reports/image-digest.json`(`sha256:` 且 `sourceSha` = HEAD)、compose 镜像是否 `@sha256:` 锁定、`reports/sbom.spdx.json`、`reports/signature.json`;任一缺失即 `status=partial` 并写明缺什么,不判定晋级 | `reports/release-manifest.latest.json` | 0 |\n| `ci:template [--out \u003cfile\u003e]` | 输出消费者最小 CI 模板(私包认证 + check:pins + 可选夹具) | — | 0 |\n| `check:modules` / `check:module-imports` / `check:catalog` / `catalog:drift` | 基础设施仓内部门禁(依赖 `runtime/modules.json` 与 `contracts/catalogs`) | `reports/*.latest.json` | 1 = 违规(drift 默认 0) |\n| `check:migration-decs` | 仓纪律 3:`runtime/modules/*/prisma/migrations` 与 `identity/apps/*/prisma/migrations` 的 `migration.sql` 前 10 行须有 `-- decision: DEC-NNN` 且该 DEC 已批准;`state=shape` 模块不得有迁移;例外只能逐个迁移登记在 `migration-decs.exceptions.json`(条件失效判 `EXCEPTION_STALE`) | `reports/migration-decs.latest.json` | 1 = 违规 |\n| `check:facts [--candidates \u003cdir\u003e] [--report-only]` | §6.4:`modules.json` 声明的 Fact ⊆ `contracts/catalogs/facts.json` ∪ CHG-004 候选(候选须 `status: pending-dec` + `blocked_by`);候选目录不可用时报 `UNRESOLVED`(fail-closed)。**接入根 `pnpm check` 前置 CT-2 材料落地** | `reports/facts.latest.json` | 1 = 违规 / unresolved |\n| `check:caddy` | §5 / §7:`modules.json` 的 HTTP 契约经 `caddy-routes.json` 映射前缀后必须被 `stack/caddy/Caddyfile` 的 path 匹配器覆盖;`/healthz`、`X-Request-Id` 注入、`{$PLATFORM_API_UPSTREAM}` 必备;本机有 `caddy` 则 `caddy validate`,否则报告 `validate: skipped`(`CHECK_CADDY_DOCKER=1` 走 docker) | `reports/caddy.latest.json` | 1 = 违规 / 语法失败 |\n\n所有报告带 `provenance`(`gitSha` / `worktreeDirty` / `runner` 原值 / `runnerNormalized` / `runId`);`worktreeDirty` 忽略 latest 报告本身。\n\n`verify:candidate` 在候选源码工作树的根目录运行:从 `runtime/reports/baseline.json` 与 `identity/reports/baseline.json` 读取最低测试数量,不能用 artifact 自报的较低地板代替。报告须为对象,验收计数与地板须为正整数,治理报告须含固定必需指标且为零;缺失、`null`、数组、标量和显式 `PARTIAL` 状态均不合格。旧治理报告没有 `status` 字段时仍按必需指标核验。指定 `--run-id` 或运行于 GitHub Actions 时要求每份报告为 CI runner;本地诊断保留 local 来源,不代表远端验收。独立调用纯函数 `evaluateCandidate` 时须显式传入 `{ baselines, requireCi }`;CLI 自动读取源码基线。\n\n## 消费方接入\n\n```bash\npnpm add -D @juhai/governance@1.0.0-rc.0 # exact pin;.npmrc 配 @juhai 作用域到 Gitea registry\npnpm exec juhai-governance ci:template --out .github/workflows/platform-governance.yml\npnpm exec juhai-governance check:pins --require @juhai/contracts\n```\n\n夹具套件格式见 `check-fixtures.mjs` 头注;示例 `fixtures/contracts.suite.json`(正例取 `@juhai/contracts` 的 examples,反例故意破坏必填 / 类型 / 血缘字段)。\n\n## 本仓内\n\n`pnpm check`(仓根)已串联:`check:pins` → `check:modules` → `check:module-imports` → `check:catalog` → `catalog:drift` → `check:fixtures` → `check:migration-decs` → `check:caddy` → governance 测试 → contracts → runtime 静态门禁(`check:facts` 有脚本与测试,待 CHG-004 候选材料落地后入链)。`.github/CODEOWNERS` 按设计 §23 登记路径 → 角色占位,`test/codeowners.test.mjs` 断言覆盖面。`pnpm --dir governance test` 跑本包测试;`pnpm --dir governance pack` 产出可安装的 tgz(发布走 DEC-031 通道,需平台负责人确认)。\n","repository":{"type":"","url":""}}...
|
8
|
Edit
Delete
|
|
9
|
3
|
5
|
1.0.0-rc.1
|
1.0.0-rc.1
|
1789220676
|
0
|
{"scope":"@juhai","name":& {"scope":"@juhai","name":"contracts","description":"企业应用群机器契约:Catalog、JSON Schema、OpenAPI、兼容基线与治理 Linter(基础设施仓 contracts/,DEC-010 / DEC-031)","license":"UNLICENSED","dependencies":{"ajv":"8.20.0","ajv-formats":"3.0.1"},"development_dependencies":{"@types/node":"20.19.43","json-schema-to-typescript":"16.0.0","typescript":"5.9.3"},"readme":"# @juhai/contracts(原 platform-contracts 候选控制面)\n\n## 在 enterprise-platform 内的状态(PF-04 阶段 1,2026-09-10)\n\n- **身份**:本目录是 `企业应用/platform-contracts/` 的带来源登记导入(见 [SOURCE.md](SOURCE.md));包名按 DEC-031 命名修订改为 `@juhai/contracts`,版本 `1.0.0-rc.0`(rc 系列;非 rc `1.0.0` 受 DEC-010 附条件:远端 + Required Check)。`catalogs/`、`contracts/`、`examples/`、`apps/`、`compatibility/` 与来源逐字节一致;`schemas/` 仅含下述 PF-04 的 `causation_id` / `correlation_id` 变更。\n- **工作区根**:Linter、影响图与测试以「工作区根」(`企业应用/`,同时含 `基础/` 与 `doc/`)为基准解析 Catalog `directory` / `evidence`、DEC `source` 与各应用仓路径,不再假定包位于工作区根的直接子目录。解析顺序:`--workspace-root \u003cabs\u003e`(`node scripts/check.mjs --workspace-root …`)→ 环境变量 `PLATFORM_CONTRACTS_WORKSPACE_ROOT` → 自动探测(从本目录向上找到首个同时含 `基础/` 与 `doc/` 的祖先)。经 `pnpm` 复合脚本运行时请用环境变量(pnpm 只把额外参数附加到最后一条命令)。\n- **独立克隆**(无 `基础/` 与 `doc/` 祖先,例如云端 CI 只 checkout 本仓;2026-09-12):`check:local` 的影响图以 `--workspace-optional` 退化为\"仅包内\"计算并在 stderr 打印 `[WORKSPACE_ROOT_UNRESOLVED]` 提示,不核验 Catalog / AppManifest / 裁决的路径引用;依赖应用仓文件、工作区路径或真实探测结果的 16 个测试显式 `skip`(91 例中 75 例照跑)。`check` 与 `check:impact` 在独立克隆下仍失败关闭(退出码 2),显式 `--workspace-root` / 环境变量不可用时任何模式都失败关闭。\n- **TS 层(CT-1)**:`scripts/schema-registry.mjs` 是 key → Schema 文件 → 类型名的唯一来源;改 Schema 后运行 `pnpm generate` 重生成 `generated/`,`pnpm check:generated`(在 `check:local` 内)在缺失 / 差异 / 多余文件时失败;`pnpm build`(tsc → `dist/`)在 `test` 与 `check:local` 之前自动执行;首次使用需 `pnpm --dir contracts install`(依赖只来自公共 npm,全部 exact pin)。\n- **`pnpm check` 现状**:`check` 报告且仅报告 6 项 `PLATFORM_PROJECT_UNREGISTERED`(`基础/reports`、`基础/tests`、`基础/企业搜索与统一检索平台`、`基础/外部连接器与集成平台`、`基础/开发者自助与应用工程平台`、`基础/数据治理与隐私平台`),全部随 CHG-001(新增基础应用 MachineCatalog 变更)合并后消失;Linter 未被放宽。合并前以 `pnpm check:local`(schema 兼容 + 影响图 + 测试)作为绿色门禁;CHG-001 合并后 `check` 转绿,根 `pnpm check` 再切回完整 `check`。\n- **`causation_id` 可选、`correlation_id` 映射**(设计 §7 / §25 张力 4):`schemas/fact-envelope.v1.schema.json` 的 `required` 去掉 `causation_id`(旅程首条事实没有因果父,省略而非填占位值);`trace_id` = 旅程锚点、`correlation_id` = 业务关联写入 `fact-envelope.v1` 与 `request-context.v1` 的 `description`(后者只加说明)。Linter 新增规则 `FACT_ENVELOPE_FIELD_NOT_OPTIONAL` 防止回退为必填;`test/fact-envelope.test.mjs` 用兼容检查器自身的规则证明该放宽向后兼容(反向则报 `REQUIRED_PROPERTY_ADDED`)。`compatibility/` 冻结基线未动(信封不在基线内)。\n- **消费**:`pnpm add @juhai/contracts@1.0.0-rc.N`(exact pin,`check:pins` 强制);子路径导出 `@juhai/contracts/catalogs/*`、`/schemas/*`、`/contracts/*`、`/examples/*`、`/apps/*`、`/compatibility/*`、`/scripts/*`、`/package.json`;**裸入口(CT-1,2026-09-12)**:`import { validate, validateFact, assertValid, isValid, schemaOf, SCHEMA_KEYS, type FactEnvelopeV1 } from '@juhai/contracts'`——12 个 JSON Schema 的 TypeScript 类型(`generated/`,由 `schemas/` 生成并入库)与 Ajv 2020 校验器(按 key 懒编译;未知 key 抛 `RangeError`;`validateFact` 先验信封再按 `facts/\u003cfact_type\u003e.v\u003cmajor\u003e` 验载荷,未登记载荷 Schema 以 `payloadSchema` 失败关闭);`dist/` 随包发布,运行依赖仅 `ajv` / `ajv-formats`;`test/`、`src/`、`generated/` 不随包发布。\n\n本目录是企业应用群 Git-first 机器契约的 **W1 候选实现**,用于先建立可校验的语义基线。`DEC-010` 尚未裁决 Catalog 的最终物理位置,因此这里的 Registry、AppManifest 和 Schema 均为 `proposed` 或 `draft`,不能作为“能力已上线”的证据。\n\n## 已覆盖\n\n- `Employment` 的唯一 Owner、Canonical ID 目标格式与数据分级,以及企业 IdP 已实现权威模型的目录对账;\n- `FactEnvelope v1` JSON Schema;\n- `EmploymentTransferred v1` Payload JSON Schema;\n- HR、Digital Employee OS、Permission Platform、企业 IdP、执行监管、基础框架、嗨设、巨嗨智服、知识云、设备云、巨嗨报价系统与尤克特拉十二个草案 AppManifest;\n- Fact Producer/Consumer、Projection/Replay 和待裁决 Owner 的静态治理检查;Fact Projection 进一步绑定 Consumer、只读 Authority、状态 Schema、`consumer_name + fact_id` 幂等、Projection + `processed_fact` 原子提交、单调但不连续的聚合版本语义,以及受 Backbone ADR 阻断的消息 Gap 检测;\n- Resource/Action Catalog v1、Actor/Request Context v1 和 Permission Decision API v1 候选契约;\n- DEC-001—032 全量 Decision Catalog 登记(32 approved / 0 pending:2026-09-10 批准 010 / 031 / 032,2026-09-12 决策会批准其余 27 项,013 Broker = Redpanda、008 部分生效、030 分阶段;037—039 待 CHG-002),并校验所有 Catalog 引用的裁决可解析;\n- 权限请求/拒绝样例,强制租户一致、未知资源/动作拒绝、故障关闭和拒绝不正缓存;\n- DEC-012 完整候选 ADR、首条 Fact Schema 的不可变 proposed Snapshot 与保守向后兼容检查器;\n- 从 Catalog + AppManifest 构建的 proposed Producer/Consumer Impact Graph 与变更查询 CLI;\n- `基础/` 21 个平台目录的机器项目清单:19 个属于本轮目标,明确排除基础框架与 AI 数字员工;实现状态、代码真源、证据等级和阻塞 DEC 可查询;\n- 可执行的正向检查和 Owner、ADR、Canonical ID、PII、Replay、Consumer、Application Dependency、Permission、Schema Compatibility 负向边界测试。\n\n## 尚未裁决,禁止越权实现\n\n- `Person`、`Organization`、`Store`、`Position`、`Actor` Owner(`DEC-001`—`DEC-005`);\n- AppManifest/ProductManifest 边界、Catalog 物理真源和双 Envelope 边界(`DEC-009`—`DEC-011`,评审材料已形成但尚未批准);\n- Schema 最终组合与兼容策略批准(`DEC-012`);候选检查器只证明当前规则可机械执行,不是正式发布策略;\n- Broker、Topic、Fact Store 与 Ordering(`DEC-013`—`DEC-016`);\n- Scope 执行和权限分工(`DEC-017`—`DEC-019`);\n- 权限平台的引擎、策略存储和运行时技术路线(`DEC-029`)。\n- 尤克特拉身份、设备、客户、订单、执行与通知重名实体的 Owner、映射和迁移方案(`DEC-030`,其中 Store 仍受 `DEC-003` 阻塞)。\n- 平台契约与 SDK 的分发通道、发布包名登记与发布门禁(`DEC-031`);裁决前派生仓 Planner 只能以夹具或标注来源 SHA 的过渡复制形式被业务仓引用,不得冒充平台接入。\n\n因此 Permission Decision API 是可评审、可机械验证的候选边界,不是权限引擎已实现或已上线的声明。Actor Context 仅携带 IdP 已认证的不透明主体标识,不越权裁决 `Actor` 企业 Owner。\n\n`DEC-027/028` 已批准并进入 HR 实现;Linter 仍会阻止草案 Manifest 标记为 `active`,也不允许 `EmploymentTransferred` 越过 `DEC-010/012` 直接激活。\n\n企业 IdP 草案清单已对账其当前 E2 代码中的 Tenant/User、Application/OIDC Client、Credential/Authenticator、Consent、Session、Authorization Code/Grant、Refresh Token Family/Token、Backchannel Delivery 与 Security Event 等权威模型;这仍不代表生产 KMS/HSM、远程 CI 或生产部署已签收。`User` 是 IdP 账户主体,不等同于 DEC-001 尚未裁决的企业 `Person`。嗨设现已真实消费 IdP RS256 access token/JWKS,并登记 `material.production` 候选权限面;它只保存 actor 引用,不拥有 Tenant/User/Session/Grant。执行监管的 Project/Ticket/SLA 仍未进入企业 Entity Catalog。知识云则登记 `KnowledgeCandidate`、`KnowledgeAtom`、`KnowledgeAtomVersion`、`KnowledgeSource` 与 `KnowledgeFeedback` 五个权威对象;`KnowledgeEmbedding`、检索 Evidence 与 AI 推理结果都是可重建派生物,不得冒充企业权威实体。巨嗨报价系统已将当前 Prisma 的 68 个业务模型登记为权威对象,并由测试持续与真实 schema 对账;本地 `User/UserEvent` 及 `Outbox/OutboxReplayEvent` 明确排除,避免抢占 IdP 身份 Owner 或把技术投递记录冒充企业业务实体。尤克特拉只登记已验证的 Express/PostgreSQL 运行时,其 71 个 Prisma 模型中与全局 Catalog 重名的七个对象由 DEC-030 阻断,Fact、统一 Permission、Projection 和权威 Entity 保持空集;这不把本地数据误报成共享真源,也不把单后端误报成双后端。基础框架只作为工程模板登记,不拥有企业业务事实。\n\nPlatform Project Catalog 当前只允许企业 IdP 声明独立服务 `implemented_e2`;通知与 Webhook 中心、公共文件平台及配置与功能开关平台声明 `module_e2`。公共文件已由执行监管、巨嗨报价与嗨设三个真实消费者完成 E2 运行验证;通知投递已由执行监管、巨嗨智服与巨嗨报价三个真实消费者完成 E2 运行验证;配置平台当前只有执行监管一个真实业务消费者,生产无有效批准快照时关闭、坏刷新保留最后良好版本,并把版本/摘要/来源/原因写入 AutomationRun。前三者都不表示 G4 已裁决或独立服务已启动;配置平台尤其仍缺第二、第三消费者。报价本地 `QuotationNotificationIntent` 是技术投递记录,不登记为企业权威实体。应用与契约注册中心、企业事实干线和统一权限平台仅为 `candidate_e0`;其余目标平台仍是 `not_started`。各平台目录内复制的 `base-framework/` 一律不计为平台实现,任何 E2 证据文件都必须真实存在并报告 `passed`。\n\n## 使用\n\n无需安装第三方依赖,Node.js 20+ 即可运行:\n\n```bash\nnpm run check\nnpm test\n```\n\n`check` 校验平台项目目录、目标范围、证据、Schema 引用、Owner、Producer/Consumer、Projection/Replay、幂等/原子提交/版本顺序、权限与 Scope 对账,并对每个已登记 Fact 执行 proposed Snapshot 不可变/版本兼容检查;`test` 证明目录漏登、模板冒充实现、E2 证据未通过、Owner 冲突、Consumer 绑定漂移、Owner 越权、非原子 Projection、错误连续版本假设、Projection PII/来源漂移与不兼容 Schema 会失败。\n\n查询一个 Fact Schema 变更的直接与二跳影响:\n\n```bash\nnpm run impact -- schema schemas/facts/EmploymentTransferred.v1.json 2\n```\n\n输出明确区分节点深度,并列出 Producer、Consumers、Projections、Entity、阻塞 Decision 与相关边;未知目标返回非零退出码,不生成空的“无影响”结果。\n\n## 状态升级规则\n\n只有同时满足以下条件,才能把本目录从候选实现升级为正式真源:\n\n1. `DEC-010` ADR 已批准;\n2. `DEC-012` Schema 表达和兼容策略已批准;\n3. App Owner 对 AppManifest 与真实代码、部署资产完成核验;\n4. CI 使用本 Linter 或其正式替代品阻断冲突;\n5. 运行时证据证明事实生产、消费、幂等与 Replay,而不只是静态文件通过。\n","repository":{"type":"","url":""}}...
|
72
|
Edit
Delete
|
|
10
|
4
|
5
|
1.0.0-rc.1
|
1.0.0-rc.1
|
1789220680
|
0
|
{"scope":"@juhai","name":& {"scope":"@juhai","name":"governance","description":"基础设施层跨仓门禁(设计方案 §9):check:pins(exact pin 消费规则)、check:fixtures(契约正反例夹具)、verify:candidate(候选可晋级核验)、release:manifest(已知事实清单)、CI 模板;零依赖 CLI,供上层仓 exact pin 后在 CI 运行。","license":"UNLICENSED","bin":{"juhai-governance":"bin/cli.mjs"},"readme":"# @juhai/governance — 基础设施跨仓门禁\n\n设计方案 §4.2 / §9 定义的 `governance/` 交付:一组**零依赖**的构建期检查,随基础设施仓同一 Release 版本号发布到 Gitea npm registry(DEC-031),供上层仓 **exact pin** 后在 CI 运行(`check:pins` 为必需检查,DEC-031 附带条款 4)。\n\n## 命令(`juhai-governance \u003ccommand\u003e [--root \u003cdir\u003e]`)\n\n| 命令 | 用途 | 报告 | 退出码 |\n|---|---|---|---|\n| `check:pins [--require \u003cpkg\u003e]…` | `@juhai/*` 依赖只允许 `x.y.z` 或 `workspace:*`;`--require` 要求该包至少一处 exact pin(证明消费者已接入) | 无(stdout) | 1 = 有违规 |\n| `check:port-conformance` | 基础设施仓内独立端口测试:先构建 contracts/modules/clients,再跑 `runtime/test/port`;必须完整通过内核 14、模块 6、客户端 21 例,拒绝跳过与空跑 | `reports/port-conformance.latest.json` | 1 = 构建/测试/覆盖核验失败 |\n| `check:fixtures --suite \u003csuite.json\u003e… [--allow-unavailable-suite \u003cid\u003e]…` | 契约正反例夹具:校验套件配置后,ACCEPT 须零原因、REJECT 须有原因且含声明前缀;缺工作区默认失败,显式允许且有其他用例执行才可 partial | `reports/fixtures.latest.json` | 1 = 配置错误、空跑、不可用或用例不符 |\n| `verify:candidate --candidate \u003cdir\u003e --sha \u003csha\u003e …` | 候选可晋级核验(Q12-C / X12):逐份 required 报告核 sourceSha / dirty / 状态 / 地板 / digest,缺失即不合格 | `\u003cdir\u003e/release-candidate.json` 或 `--out` | 1 = 不合格 |\n| `release:manifest` | 已知事实清单,**逐项按磁盘判定**:`governance/package.json`、`runtime/clients/\u003cm\u003e/package.json`(name 须为 `@juhai/client-\u003cm\u003e`)、`reports/image-digest.json`(`sha256:` 且 `sourceSha` = HEAD)、compose 镜像是否 `@sha256:` 锁定、`reports/sbom.spdx.json`、`reports/signature.json`;任一缺失即 `status=partial` 并写明缺什么,不判定晋级 | `reports/release-manifest.latest.json` | 0 |\n| `ci:template [--out \u003cfile\u003e]` | 输出消费者最小 CI 模板(私包认证 + contracts/governance 必需 exact pin + 必需夹具) | — | 0 |\n| `check:modules` / `check:module-imports` / `check:catalog` / `catalog:drift` | 基础设施仓内部门禁(依赖 `runtime/modules.json` 与 `contracts/catalogs`) | `reports/*.latest.json` | 1 = 违规(drift 默认 0) |\n| `check:migration-decs` | 仓纪律 3:`runtime/modules/*/prisma/migrations` 与 `identity/apps/*/prisma/migrations` 的 `migration.sql` 前 10 行须有 `-- decision: DEC-NNN` 且该 DEC 已批准;`state=shape` 模块不得有迁移;例外只能逐个迁移登记在 `migration-decs.exceptions.json`(条件失效判 `EXCEPTION_STALE`) | `reports/migration-decs.latest.json` | 1 = 违规 |\n| `check:facts [--candidates \u003cdir\u003e] [--report-only]` | §6.4:`modules.json` 声明的 Fact ⊆ `contracts/catalogs/facts.json` ∪ CHG-004 候选(候选须 `status: pending-dec` + `blocked_by`);候选目录不可用时报 `UNRESOLVED`(fail-closed)。**接入根 `pnpm check` 前置 CT-2 材料落地** | `reports/facts.latest.json` | 1 = 违规 / unresolved |\n| `check:caddy` | §5 / §7:`modules.json` 的 HTTP 契约经 `caddy-routes.json` 映射前缀后必须被 `stack/caddy/Caddyfile` 的 path 匹配器覆盖;`/healthz`、`X-Request-Id` 注入、`{$PLATFORM_API_UPSTREAM}` 必备;本机有 `caddy` 则 `caddy validate`,否则报告 `validate: skipped`(`CHECK_CADDY_DOCKER=1` 走 docker) | `reports/caddy.latest.json` | 1 = 违规 / 语法失败 |\n\n所有报告带 `provenance`(`gitSha` / `worktreeDirty` / `runner` 原值 / `runnerNormalized` / `runId`);`worktreeDirty` 忽略 latest 报告本身。\n\nG-7 的 `port-conformance` job 保留同仓 PR 的私包认证约束,不访问数据库。每次执行使用新的临时 Vitest JSON;构建失败、测试失败或没有新报告时覆盖旧成功状态为 failed。三组逐文件地板在 `lib/port-conformance.mjs`,新增套件须同步更新覆盖清单。candidate 依赖该 job 成功,且十一份 required 报告中必须含同源码、干净工作树的端口报告;旧十份报告不能用于新版本候选。发布门禁沿用同一 REQUIRED_REPORTS 集合。此门禁证明端口一致性,不提升模块 shape 状态。\n\n`verify:candidate` 在候选源码工作树的根目录运行:从 `runtime/reports/baseline.json` 与 `identity/reports/baseline.json` 读取最低测试数量,不能用 artifact 自报的较低地板代替。报告须为对象,验收计数与地板须为正整数,治理报告须含固定必需指标且为零;缺失、`null`、数组、标量和显式 `PARTIAL` 状态均不合格。旧治理报告没有 `status` 字段时仍按必需指标核验。指定 `--run-id` 或运行于 GitHub Actions 时要求每份报告为 CI runner;本地诊断保留 local 来源,不代表远端验收。独立调用纯函数 `evaluateCandidate` 时须显式传入 `{ baselines, requireCi }`;CLI 自动读取源码基线。\n\n## 镜像、SBOM 与签名(开发计划 §3A D-1 / D-2;仓根脚本)\n\n| 脚本 | 作用 | 产物 |\n|---|---|---|\n| `pnpm image:build`(`governance/build-image.mjs`) | 用 `runtime/Dockerfile` 构建运行时镜像;默认 `--context head`(`git archive HEAD:runtime`,本机 WIP 不进镜像);私有 registry token 只经 `--secret id=npmrc,src=\u003cnpmrc\u003e`(默认 `~/.npmrc`,`--npmrc` 可指定)进入安装层,不进镜像、不打��� | `reports/image-digest.json`:`digest` = 本机 `--load` 的 image id(`digestKind` 说明;推送后换 registry manifest digest)、`sourceSha` / `worktreeDirty` / `dockerfileTracked` / 平台 / 大小 / 基础镜像 |\n| `pnpm image:sbom`(`governance/sbom.mjs`) | `syft` 或 `docker sbom` 生成完整 SPDX(OS + Node);两者都缺时退到 **lockfile 模式**:从镜像里 deploy 树的 pnpm lock 与工作区包生成只含 Node 依赖的 SPDX 2.3(`sbom.latest.json.scope` 标 partial,Debian 包不在内;完整 SBOM 由 CI image job 的 syft 产出);镜像不可用则退出 3 不写空文件 | `reports/sbom.spdx.json` + 元数据 `reports/sbom.latest.json`(tool / scope / sha256 / 包数) |\n| `pnpm image:sign`(`governance/sign-image.mjs`) | `cosign sign --key $COSIGN_KEY \u003cregistry ref@digest\u003e`;未推送 / 无密钥 / 无 cosign 时明确跳过、退出 0 | `reports/signature.json`(缺失即 Manifest `missing: signature`) |\n\n`release:manifest` 逐项按磁盘判定这三份产物;CI 的 `image` job 在 Secret 配置后产出同名 artifact(不推 registry)。\n\n## 消费方接入\n\n```bash\npnpm add -D @juhai/governance@1.0.0-rc.1 # exact pin;.npmrc 配 @juhai 作用域到 Gitea registry\npnpm exec juhai-governance ci:template --out .github/workflows/platform-governance.yml\npnpm exec juhai-governance check:pins --require @juhai/contracts --require @juhai/governance\npnpm exec juhai-governance check:fixtures --suite governance/fixtures/contracts.suite.json\n```\n\n夹具套件格式见 `check-fixtures.mjs` 头注;示例 `fixtures/contracts.suite.json`(正例取 `@juhai/contracts` 的 examples,反例故意破坏必填 / 类型 / 血缘字段)。消费者须在自己仓内建立 `governance/fixtures/contracts.suite.json`,按实际安装位置调整 schema / inputFile 路径;模板不再跳过缺失文件。\n\n套件必须有非空且不重复的 id / case id、合法 expect、已声明 schema,以及 input / inputFile 二选一。空套件、缺失 schema、损坏的本地引用、文件读取/解析/模块加载错误会生成 failed 报告并退出 1,覆盖旧的成功报告;规则必须显式返回原因数组,DEC-039 适配器的失败结论不能被重新判为成功。JSON Schema 校验仍是头注声明的子集,不代表完整元 Schema 校验或支持所有关键字。\n\n根 `pnpm check:fixtures` 先构建运行时模块,再显式带 `--allow-unavailable-suite dec-039-party-model`,仅容许独立克隆缺少企业应用工作区时跳过 DEC-039 外部套件,报告 status=partial、保留 unavailable 计数;contracts 与六个模块套件仍必须执行,缺失模块构建产物不会被该豁免放过。全部套件不可用、配置错误和真实用例失败仍阻断。消费者模板使用默认严格模式。`--allow-unavailable` 保留为显式允许所有不可用套件的诊断开关,不用于本仓根门禁。以上增强为仓内新源码,已发布的 `1.0.0-rc.0` 保持不变,本仓已准备 `1.0.0-rc.1`,实际发布及 Registry 安装状态见发布记录。\n\n## 本仓内\n\n`pnpm check`(仓根)已串联:`check:pins` → `check:modules` → `check:module-imports` → `check:catalog` → `catalog:drift` → `check:fixtures` → `check:facts` → `check:migration-decs` → `check:caddy` → governance 测试 → contracts → runtime 静态门禁。`pnpm check:port-conformance` 独立运行真实端口测试,CI 单独生产证据。`.github/CODEOWNERS` 仍为角色占位,不能把覆盖测试通过解释为真实团队审批已生效。发布走 DEC-031 的固定源码 RC 通道;已发布版本不覆盖,新包代码须使用后续新 RC 版本。\n","repository":{"type":"","url":""}}...
|
72
|
Edit
Delete
|
|
11
|
3
|
5
|
1.0.0-rc.2
|
1.0.0-rc.2
|
1789361194
|
0
|
{"scope":"@juhai","name":& {"scope":"@juhai","name":"contracts","description":"企业应用群机器契约:Catalog、JSON Schema、OpenAPI、兼容基线与治理 Linter(基础设施仓 contracts/,DEC-010 / DEC-031)","license":"UNLICENSED","dependencies":{"ajv":"8.20.0","ajv-formats":"3.0.1"},"development_dependencies":{"@types/node":"20.19.43","json-schema-to-typescript":"16.0.0","typescript":"5.9.3"},"readme":"# @juhai/contracts(原 platform-contracts 候选控制面)\n\n## 在 enterprise-platform 内的状态(PF-04 阶段 1,2026-09-10)\n\n- **身份**:本目录是 `企业应用/platform-contracts/` 的带来源登记导入(见 [SOURCE.md](SOURCE.md));包名按 DEC-031 命名修订改为 `@juhai/contracts`,版本 `1.0.0-rc.0`(rc 系列;非 rc `1.0.0` 受 DEC-010 附条件:远端 + Required Check)。`catalogs/`、`contracts/`、`examples/`、`apps/`、`compatibility/` 与来源逐字节一致;`schemas/` 仅含下述 PF-04 的 `causation_id` / `correlation_id` 变更。\n- **工作区根**:Linter、影响图与测试以「工作区根」(`企业应用/`,同时含 `基础/` 与 `doc/`)为基准解析 Catalog `directory` / `evidence`、DEC `source` 与各应用仓路径,不再假定包位于工作区根的直接子目录。解析顺序:`--workspace-root \u003cabs\u003e`(`node scripts/check.mjs --workspace-root …`)→ 环境变量 `PLATFORM_CONTRACTS_WORKSPACE_ROOT` → 自动探测(从本目录向上找到首个同时含 `基础/` 与 `doc/` 的祖先)。经 `pnpm` 复合脚本运行时请用环境变量(pnpm 只把额外参数附加到最后一条命令)。\n- **独立克隆**(无 `基础/` 与 `doc/` 祖先,例如云端 CI 只 checkout 本仓;2026-09-12):`check:local` 的影响图以 `--workspace-optional` 退化为\"仅包内\"计算并在 stderr 打印 `[WORKSPACE_ROOT_UNRESOLVED]` 提示,不核验 Catalog / AppManifest / 裁决的路径引用;依赖应用仓文件、工作区路径或真实探测结果的 16 个测试显式 `skip`(91 例中 75 例照跑)。`check` 与 `check:impact` 在独立克隆下仍失败关闭(退出码 2),显式 `--workspace-root` / 环境变量不可用时任何模式都失败关闭。\n- **TS 层(CT-1)**:`scripts/schema-registry.mjs` 是 key → Schema 文件 → 类型名的唯一来源;改 Schema 后运行 `pnpm generate` 重生成 `generated/`,`pnpm check:generated`(在 `check:local` 内)在缺失 / 差异 / 多余文件时失败;`pnpm build`(tsc → `dist/`)在 `test` 与 `check:local` 之前自动执行;首次使用需 `pnpm --dir contracts install`(依赖只来自公共 npm,全部 exact pin)。\n- **`pnpm check` 现状**:`check` 报告且仅报告 6 项 `PLATFORM_PROJECT_UNREGISTERED`(`基础/reports`、`基础/tests`、`基础/企业搜索与统一检索平台`、`基础/外部连接器与集成平台`、`基础/开发者自助与应用工程平台`、`基础/数据治理与隐私平台`),全部随 CHG-001(新增基础应用 MachineCatalog 变更)合并后消失;Linter 未被放宽。合并前以 `pnpm check:local`(schema 兼容 + 影响图 + 测试)作为绿色门禁;CHG-001 合并后 `check` 转绿,根 `pnpm check` 再切回完整 `check`。\n- **`causation_id` 可选、`correlation_id` 映射**(设计 §7 / §25 张力 4):`schemas/fact-envelope.v1.schema.json` 的 `required` 去掉 `causation_id`(旅程首条事实没有因果父,省略而非填占位值);`trace_id` = 旅程锚点、`correlation_id` = 业务关联写入 `fact-envelope.v1` 与 `request-context.v1` 的 `description`(后者只加说明)。Linter 新增规则 `FACT_ENVELOPE_FIELD_NOT_OPTIONAL` 防止回退为必填;`test/fact-envelope.test.mjs` 用兼容检查器自身的规则证明该放宽向后兼容(反向则报 `REQUIRED_PROPERTY_ADDED`)。`compatibility/` 冻结基线未动(信封不在基线内)。\n- **消费**:`pnpm add @juhai/contracts@1.0.0-rc.N`(exact pin,`check:pins` 强制);子路径导出 `@juhai/contracts/catalogs/*`、`/schemas/*`、`/contracts/*`、`/examples/*`、`/apps/*`、`/compatibility/*`、`/scripts/*`、`/package.json`;**裸入口(CT-1,2026-09-12)**:`import { validate, validateFact, assertValid, isValid, schemaOf, SCHEMA_KEYS, type FactEnvelopeV1 } from '@juhai/contracts'`——12 个 JSON Schema 的 TypeScript 类型(`generated/`,由 `schemas/` 生成并入库)与 Ajv 2020 校验器(按 key 懒编译;未知 key 抛 `RangeError`;`validateFact` 先验信封再按 `facts/\u003cfact_type\u003e.v\u003cmajor\u003e` 验载荷,未登记载荷 Schema 以 `payloadSchema` 失败关闭);`dist/` 随包发布,运行依赖仅 `ajv` / `ajv-formats`;`test/`、`src/`、`generated/` 不随包发布。\n\n本目录是企业应用群 Git-first 机器契约的 **W1 候选实现**,用于先建立可校验的语义基线。`DEC-010` 尚未裁决 Catalog 的最终物理位置,因此这里的 Registry、AppManifest 和 Schema 均为 `proposed` 或 `draft`,不能作为“能力已上线”的证据。\n\n## 已覆盖\n\n- `Employment` 的唯一 Owner、Canonical ID 目标格式与数据分级,以及企业 IdP 已实现权威模型的目录对账;\n- `FactEnvelope v1` JSON Schema;\n- `EmploymentTransferred v1` Payload JSON Schema;\n- HR、Digital Employee OS、Permission Platform、企业 IdP、执行监管、基础框架、嗨设、巨嗨智服、知识云、设备云、巨嗨报价系统与尤克特拉十二个草案 AppManifest;\n- Fact Producer/Consumer、Projection/Replay 和待裁决 Owner 的静态治理检查;Fact Projection 进一步绑定 Consumer、只读 Authority、状态 Schema、`consumer_name + fact_id` 幂等、Projection + `processed_fact` 原子提交、单调但不连续的聚合版本语义,以及受 Backbone ADR 阻断的消息 Gap 检测;\n- Resource/Action Catalog v1、Actor/Request Context v1 和 Permission Decision API v1 候选契约;\n- DEC-001—032 全量 Decision Catalog 登记(32 approved / 0 pending:2026-09-10 批准 010 / 031 / 032,2026-09-12 决策会批准其余 27 项,013 Broker = Redpanda、008 部分生效、030 分阶段;037—039 待 CHG-002),并校验所有 Catalog 引用的裁决可解析;\n- 权限请求/拒绝样例,强制租户一致、未知资源/动作拒绝、故障关闭和拒绝不正缓存;\n- DEC-012 完整候选 ADR、首条 Fact Schema 的不可变 proposed Snapshot 与保守向后兼容检查器;\n- 从 Catalog + AppManifest 构建的 proposed Producer/Consumer Impact Graph 与变更查询 CLI;\n- `基础/` 21 个平台目录的机器项目清单:19 个属于本轮目标,明确排除基础框架与 AI 数字员工;实现状态、代码真源、证据等级和阻塞 DEC 可查询;\n- 可执行的正向检查和 Owner、ADR、Canonical ID、PII、Replay、Consumer、Application Dependency、Permission、Schema Compatibility 负向边界测试。\n\n## 尚未裁决,禁止越权实现\n\n- `Person`、`Organization`、`Store`、`Position`、`Actor` Owner(`DEC-001`—`DEC-005`);\n- AppManifest/ProductManifest 边界、Catalog 物理真源和双 Envelope 边界(`DEC-009`—`DEC-011`,评审材料已形成但尚未批准);\n- Schema 最终组合与兼容策略批准(`DEC-012`);候选检查器只证明当前规则可机械执行,不是正式发布策略;\n- Broker、Topic、Fact Store 与 Ordering(`DEC-013`—`DEC-016`);\n- Scope 执行和权限分工(`DEC-017`—`DEC-019`);\n- 权限平台的引擎、策略存储和运行时技术路线(`DEC-029`)。\n- 尤克特拉身份、设备、客户、订单、执行与通知重名实体的 Owner、映射和迁移方案(`DEC-030`,其中 Store 仍受 `DEC-003` 阻塞)。\n- 平台契约与 SDK 的分发通道、发布包名登记与发布门禁(`DEC-031`);裁决前派生仓 Planner 只能以夹具或标注来源 SHA 的过渡复制形式被业务仓引用,不得冒充平台接入。\n\n因此 Permission Decision API 是可评审、可机械验证的候选边界,不是权限引擎已实现或已上线的声明。Actor Context 仅携带 IdP 已认证的不透明主体标识,不越权裁决 `Actor` 企业 Owner。\n\n`DEC-027/028` 已批准并进入 HR 实现;Linter 仍会阻止草案 Manifest 标记为 `active`,也不允许 `EmploymentTransferred` 越过 `DEC-010/012` 直接激活。\n\n企业 IdP 草案清单已对账其当前 E2 代码中的 Tenant/User、Application/OIDC Client、Credential/Authenticator、Consent、Session、Authorization Code/Grant、Refresh Token Family/Token、Backchannel Delivery 与 Security Event 等权威模型;这仍不代表生产 KMS/HSM、远程 CI 或生产部署已签收。`User` 是 IdP 账户主体,不等同于 DEC-001 尚未裁决的企业 `Person`。嗨设现已真实消费 IdP RS256 access token/JWKS,并登记 `material.production` 候选权限面;它只保存 actor 引用,不拥有 Tenant/User/Session/Grant。执行监管的 Project/Ticket/SLA 仍未进入企业 Entity Catalog。知识云则登记 `KnowledgeCandidate`、`KnowledgeAtom`、`KnowledgeAtomVersion`、`KnowledgeSource` 与 `KnowledgeFeedback` 五个权威对象;`KnowledgeEmbedding`、检索 Evidence 与 AI 推理结果都是可重建派生物,不得冒充企业权威实体。巨嗨报价系统已将当前 Prisma 的 68 个业务模型登记为权威对象,并由测试持续与真实 schema 对账;本地 `User/UserEvent` 及 `Outbox/OutboxReplayEvent` 明确排除,避免抢占 IdP 身份 Owner 或把技术投递记录冒充企业业务实体。尤克特拉只登记已验证的 Express/PostgreSQL 运行时,其 71 个 Prisma 模型中与全局 Catalog 重名的七个对象由 DEC-030 阻断,Fact、统一 Permission、Projection 和权威 Entity 保持空集;这不把本地数据误报成共享真源,也不把单后端误报成双后端。基础框架只作为工程模板登记,不拥有企业业务事实。\n\nPlatform Project Catalog 当前只允许���业 IdP 声明独立服务 `implemented_e2`;通知与 Webhook 中心、公共文件平台及配置与功能开关平台声明 `module_e2`。公共文件已由执行监管、巨嗨报价与嗨设三个真实消费者完成 E2 运行验证;通知投递已由执行监管、巨嗨智服与巨嗨报价三个真实消费者完成 E2 运行验证;配置平台当前只有执行监管一个真实业务消费者,生产无有效批准快照时关闭、坏刷新保留最后良好版本,并把版本/摘要/来源/原因写入 AutomationRun。前三者都不表示 G4 已裁决或独立服务已启动;配置平台尤其仍缺第二、第三消费者。报价本地 `QuotationNotificationIntent` 是技术投递记录,不登记为企业权威实体。应用与契约注册中心、企业事实干线和统一权限平台仅为 `candidate_e0`;其余目标平台仍是 `not_started`。各平台目录内复制的 `base-framework/` 一律不计为平台实现,任何 E2 证据文件都必须真实存在并报告 `passed`。\n\n## 使用\n\n无需安装第三方依赖,Node.js 20+ 即可运行:\n\n```bash\nnpm run check\nnpm test\n```\n\n`check` 校验平台项目目录、目标范围、证据、Schema 引用、Owner、Producer/Consumer、Projection/Replay、幂等/原子提交/版本顺序、权限与 Scope 对账,并对每个已登记 Fact 执行 proposed Snapshot 不可变/版本兼容检查;`test` 证明目录漏登、模板冒充实现、E2 证据未通过、Owner 冲突、Consumer 绑定漂移、Owner 越权、非原子 Projection、错误连续版本假设、Projection PII/来源漂移与不兼容 Schema 会失败。\n\n查询一个 Fact Schema 变更的直接与二跳影响:\n\n```bash\nnpm run impact -- schema schemas/facts/EmploymentTransferred.v1.json 2\n```\n\n输出明确区分节点深度,并列出 Producer、Consumers、Projections、Entity、阻塞 Decision 与相关边;未知目标返回非零退出码,不生成空的“无影响”结果。\n\n## 状态升级规则\n\n只有同时满足以下条件,才能把本目录从候选实现升级为正式真源:\n\n1. `DEC-010` ADR 已批准;\n2. `DEC-012` Schema 表达和兼容策略已批准;\n3. App Owner 对 AppManifest 与真实代码、部署资产完成核验;\n4. CI 使用本 Linter 或其正式替代品阻断冲突;\n5. 运行时证据证明事实生产、消费、幂等与 Replay,而不只是静态文件通过。\n","repository":{"type":"","url":""}}...
|
2
|
Edit
Delete
|
|
12
|
4
|
5
|
1.0.0-rc.2
|
1.0.0-rc.2
|
1789361196
|
0
|
{"scope":"@juhai","name":& {"scope":"@juhai","name":"governance","description":"基础设施层跨仓门禁(设计方案 §9):check:pins(exact pin 消费规则)、check:fixtures(契约正反例夹具)、verify:candidate(候选可晋级核验)、release:manifest(已知事实清单)、CI 模板;零依赖 CLI,供上层仓 exact pin 后在 CI 运行。","license":"UNLICENSED","bin":{"juhai-governance":"bin/cli.mjs"},"readme":"# @juhai/governance — 基础设施跨仓门禁\n\n设计方案 §4.2 / §9 定义的 `governance/` 交付:一组**零依赖**的构建期检查,随基础设施仓同一 Release 版本号发布到 Gitea npm registry(DEC-031),供上层仓 **exact pin** 后在 CI 运行(`check:pins` 为必需检查,DEC-031 附带条款 4)。\n\n## 命令(`juhai-governance \u003ccommand\u003e [--root \u003cdir\u003e]`)\n\n| 命令 | 用途 | 报告 | 退出码 |\n|---|---|---|---|\n| `check:pins [--require \u003cpkg\u003e]…` | `@juhai/*` 依赖只允许 `x.y.z` 或 `workspace:*`;`--require` 要求该包至少一处 exact pin(证明消费者已接入) | 无(stdout) | 1 = 有违规 |\n| `check:port-conformance` | 基础设施仓内独立端口测试:先构建 contracts/modules/clients,再跑 `runtime/test/port`;必须完整通过内核 14、模块 6、客户端 21 例,拒绝跳过与空跑 | `reports/port-conformance.latest.json` | 1 = 构建/测试/覆盖核验失败 |\n| `check:fixtures --suite \u003csuite.json\u003e… [--allow-unavailable-suite \u003cid\u003e]…` | 契约正反例夹具:校验套件配置后,ACCEPT 须零原因、REJECT 须有原因且含声明前缀;缺工作区默认失败,显式允许且有其他用例执行才可 partial | `reports/fixtures.latest.json` | 1 = 配置错误、空跑、不可用或用例不符 |\n| `verify:candidate --candidate \u003cdir\u003e --sha \u003csha\u003e …` | 候选可晋级核验(Q12-C / X12):逐份 required 报告核 sourceSha / dirty / 状态 / 地板 / digest,缺失即不合格 | `\u003cdir\u003e/release-candidate.json` 或 `--out` | 1 = 不合格 |\n| `release:manifest` | 已知事实清单,**逐项按磁盘判定**:`governance/package.json`、`runtime/clients/\u003cm\u003e/package.json`(name 须为 `@juhai/client-\u003cm\u003e`)、`reports/image-digest.json`(`sha256:` 且 `sourceSha` = HEAD)、compose 镜像是否 `@sha256:` 锁定、`reports/sbom.spdx.json`、`reports/signature.json`;任一缺失即 `status=partial` 并写明缺什么,不判定晋级 | `reports/release-manifest.latest.json` | 0 |\n| `ci:template [--out \u003cfile\u003e]` | 输出消费者最小 CI 模板(私包认证 + contracts/governance 必需 exact pin + 必需夹具) | — | 0 |\n| `check:modules` / `check:module-imports` / `check:catalog` / `catalog:drift` | 基础设施仓内部门禁(依赖 `runtime/modules.json` 与 `contracts/catalogs`) | `reports/*.latest.json` | 1 = 违规(drift 默认 0) |\n| `check:migration-decs` | 仓纪律 3:`runtime/modules/*/prisma/migrations` 与 `identity/apps/*/prisma/migrations` 的 `migration.sql` 前 10 行须有 `-- decision: DEC-NNN` 且该 DEC 已批准;`state=shape` 模块不得有迁移;例外只能逐个迁移登记在 `migration-decs.exceptions.json`(条件失效判 `EXCEPTION_STALE`) | `reports/migration-decs.latest.json` | 1 = 违规 |\n| `check:facts [--candidates \u003cdir\u003e] [--report-only]` | §6.4:`modules.json` 声明的 Fact ⊆ `contracts/catalogs/facts.json` ∪ CHG-004 候选(候选须 `status: pending-dec` + `blocked_by`);候选目录不可用时报 `UNRESOLVED`(fail-closed)。**接入根 `pnpm check` 前置 CT-2 材料落地** | `reports/facts.latest.json` | 1 = 违规 / unresolved |\n| `check:caddy` | §5 / §7:`modules.json` 的 HTTP 契约经 `caddy-routes.json` 映射前缀后必须被 `stack/caddy/Caddyfile` 的 path 匹配器覆盖;`/healthz`、`X-Request-Id` 注入、`{$PLATFORM_API_UPSTREAM}` 必备;本机有 `caddy` 则 `caddy validate`,否则报告 `validate: skipped`(`CHECK_CADDY_DOCKER=1` 走 docker) | `reports/caddy.latest.json` | 1 = 违规 / 语法失败 |\n\n所有报告带 `provenance`(`gitSha` / `worktreeDirty` / `runner` 原值 / `runnerNormalized` / `runId`);`worktreeDirty` 忽略 latest 报告本身。\n\nG-7 的 `port-conformance` job 保留同仓 PR 的私包认证约束,不访问数据库。每次执行使用新的临时 Vitest JSON;构建失败、测试失败或没有新报告时覆盖旧成功状态为 failed。三组逐文件地板在 `lib/port-conformance.mjs`,新增套件须同步更新覆盖清单。candidate 依赖该 job 成功,且十一份 required 报告中必须含同源码、干净工作树的端口报告;旧十份报告不能用于新版本候选。发布门禁沿用相同的源码必需报告策略。此门禁证明端口一致性,不提升模块 shape 状态。\n\n`verify:candidate` 在候选源码工作树的根目录运行:从 `runtime/reports/baseline.json` 与 `identity/reports/baseline.json` 读取最低测试数量,不能用 artifact 自报的较低地板代替。报告须为对象,验收计数与地板须为正整数,治理报告须含固定必需指标且为零;缺失、`null`、数组、标量和显式 `PARTIAL` 状态均不合格。旧治理报告没有 `status` 字段时仍按必需指标核验。指定 `--run-id` 或运行于 GitHub Actions 时要求每份报告为 CI runner;本地诊断保留 local 来源,不代表远端验收。独立调用纯函数 `evaluateCandidate` 时须显式传入 `{ baselines, requireCi, mainlineRequired }`;CLI 自动读取源码基线和 `runtime/modules.json`。\n\n### 持久化主线候选证据\n\n候选源码中的 fact / permission / audit 任一模块进入 `authority` 或 `e2` 后,必需报告从 11 份增加为 13 份,增加 `mainline-acceptance` 和 `revocation-sla`。模块登记缺失、损坏或状态非法时拒绝候选;不能由 artifact 自报关闭此要求。RC 发布入口读取相同源码策略,不接受只含旧 11 份报告的候选。\n\n主线报告须完整包含事实持久化 11、审计篡改 5、主线/撤权/混沌 11 项;各套件唯一,退出成功,无失败、pending 或 todo。撤权报告至少 20 个正数样本,按样本重算 p95/max 并比对摘要,要求 p95 \u003c 30 秒、max \u003c 60 秒。Grant 撤销通过而就业 Scope 仍待实现时,报告必须显式保持 `partial` 和未验证说明,候选结果保留这项覆盖边界;这不表示 MS-3、真实 HR/OS 接入或生产签收完成。\n\nruntime artifact 兼容旧单目录扁平上传,以及新增仓根报告后的目录结构。只在本次下载目录内读取固定的两种路径,不回退到仓内历史报告;同时发现两份时拒绝。源登记或目录读取失败也覆盖写入不合格候选,防止遗留成功报告。\n\n## 镜像、SBOM 与签名(开发计划 §3A D-1 / D-2;仓根脚本)\n\n| 脚本 | 作用 | 产物 |\n|---|---|---|\n| `pnpm image:build`(`governance/build-image.mjs`) | 用 `runtime/Dockerfile` 构建运行时镜像;默认 `--context head`(`git archive HEAD:runtime`,本机 WIP 不进镜像);私有 registry token 只经 `--secret id=npmrc,src=\u003cnpmrc\u003e`(默认 `~/.npmrc`,`--npmrc` 可指定)进入安装层,不进镜像、不打印 | `reports/image-digest.json`:`digest` = 本机 `--load` 的 image id(`digestKind` 说明;推送后换 registry manifest digest)、`sourceSha` / `worktreeDirty` / `dockerfileTracked` / 平台 / 大小 / 基础镜像 |\n| `pnpm image:sbom`(`governance/sbom.mjs`) | `syft` 或 `docker sbom` 生成完整 SPDX(OS + Node);两者都缺时退到 **lockfile 模式**:从镜像里 deploy 树的 pnpm lock 与工作区包生成只含 Node 依赖的 SPDX 2.3(`sbom.latest.json.scope` 标 partial,Debian 包不在内;完整 SBOM 由 CI image job 的 syft 产出);镜像不可用则退出 3 不写空文件 | `reports/sbom.spdx.json` + 元数据 `reports/sbom.latest.json`(tool / scope / sha256 / 包数) |\n| `pnpm image:sign`(`governance/sign-image.mjs`) | `cosign sign --key $COSIGN_KEY \u003cregistry ref@digest\u003e`;未推送 / 无密钥 / 无 cosign 时明确跳过、退出 0 | `reports/signature.json`(缺失即 Manifest `missing: signature`) |\n\n`release:manifest` 逐项按磁盘判定这三份产物;CI 的 `image` job 在 Secret 配置后产出同名 artifact(不推 registry)。\n\n## 环境晋级记录(开发计划 PF-23;DEC-024 A / DEC-026;仓根脚本)\n\n| 脚本 | 作用 | 产物 |\n|---|---|---|\n| `pnpm promotion:check -- --record \u003crecord.json\u003e [--manifest …] [--template …]`(`governance/check-promotion.mjs`) | 核验一份晋级记录:R1 形状(`stack/promotion/promotion-record.schema.json`)、R2 级序 dev→test→staging→prod(preview←candidate)、R3 同 digest(记录 = 候选 = Manifest 文件 `images.runtime.digest`,prod 禁止 rebuild 由此机器化)、R4 级别门槛(staging:eligible + SBOM + 签名或未过期 waiver;prod:Manifest complete + 签名 + 签收全闭)、R5 必需检查项、R6 审批角色、R7 回滚演练 ≤ 600 s、R8 preview 上限、R9 签收项在模板内 | `reports/promotion.latest.json`(`verdict` APPROVED / APPROVED_WITH_PENDING_SIGNOFFS / REJECTED;REJECTED 退出 1) |\n\n记录模板 `stack/promotion/promotion-record.template.json`,签收模板 `stack/promotion/target-env-signoff.template.json`(P1—P9,取自 OS `target-env-signoff.json`);步骤见 [staging 晋级操作说明](../docs/staging晋级操作说明.md)。纯函数 `evaluatePromotion(record, { schema, manifest, template, today })` 可独立调用(`governance/test/promotion.test.mjs` 18 例)。\n\n## 消费方接入\n\n```bash\npnpm add -D @juhai/governance@1.0.0-rc.1 # exact pin;.npmrc 配 @juhai 作用域到 Gitea registry\npnpm exec juhai-governance ci:template --out .github/workflows/platform-governance.yml\npnpm exec juhai-governance check:pins --require @juhai/contracts --require @juhai/governance\npnpm exec juhai-governance check:fixtures --suite governance/fixtures/contracts.suite.json\n```\n\n夹���套件格式见 `check-fixtures.mjs` 头注;示例 `fixtures/contracts.suite.json`(正例取 `@juhai/contracts` 的 examples,反例故意破坏必填 / 类型 / 血缘字段)。消费者须在自己仓内建立 `governance/fixtures/contracts.suite.json`,按实际安装位置调整 schema / inputFile 路径;模板不再跳过缺失文件。\n\n套件必须有非空且不重复的 id / case id、合法 expect、已声明 schema,以及 input / inputFile 二选一。空套件、缺失 schema、损坏的本地引用、文件读取/解析/模块加载错误会生成 failed 报告并退出 1,覆盖旧的成功报告;规则必须显式返回原因数组,DEC-039 适配器的失败结论不能被重新判为成功。JSON Schema 校验仍是头注声明的子集,不代表完整元 Schema 校验或支持所有关键字。\n\n根 `pnpm check:fixtures` 先构建运行时模块,再显式带 `--allow-unavailable-suite dec-039-party-model`,仅容许独立克隆缺少企业应用工作区时跳过 DEC-039 外部套件,报告 status=partial、保留 unavailable 计数;contracts 与六个模块套件仍必须执行,缺失模块构建产物不会被该豁免放过。全部套件不可用、配置错误和真实用例失败仍阻断。消费者模板使用默认严格模式。`--allow-unavailable` 保留为显式允许所有不可用套件的诊断开关,不用于本仓根门禁。以上增强为仓内新源码,已发布的 `1.0.0-rc.0` 保持不变,本仓已准备 `1.0.0-rc.1`,实际发布及 Registry 安装状态见发布记录。\n\n## 本仓内\n\n`pnpm check`(仓根)已串联:`check:pins` → `check:modules` → `check:module-imports` → `check:catalog` → `catalog:drift` → `check:fixtures` → `check:facts` → `check:migration-decs` → `check:caddy` → governance 测试 → contracts → runtime 静态门禁。`pnpm check:port-conformance` 独立运行真实端口测试,CI 单独生产证据。`.github/CODEOWNERS` 仍为角色占位,不能把覆盖测试通过解释为真实团队审批已生效。发布走 DEC-031 的固定源码 RC 通道;已发布版本不覆盖,新包代码须使用后续新 RC 版本。\n","repository":{"type":"","url":""}}...
|
1
|
Edit
Delete
|
|
13
|
5
|
5
|
1.0.0-rc.2
|
1.0.0-rc.2
|
1789361198
|
0
|
{"scope":"@juhai","name":& {"scope":"@juhai","name":"client-fact","description":"可信事实受理客户端、事务 Outbox 与幂等 Inbox;Kafka 运输不影响领域契约","license":"UNLICENSED","dependencies":{"@prisma/client":"6.19.3"},"development_dependencies":{"@types/node":"^22.10.2","typescript":"^5.7.2","vitest":"^2.1.8"},"peer_dependencies":{"@juhai/kernel":"0.16.1"},"readme":"ERROR: No README data found!","repository":{"type":"","url":""}}...
|
2
|
Edit
Delete
|
|
14
|
3
|
5
|
1.0.0-rc.3
|
1.0.0-rc.3
|
1789365043
|
0
|
{"scope":"@juhai","name":& {"scope":"@juhai","name":"contracts","description":"企业应用群机器契约:Catalog、JSON Schema、OpenAPI、兼容基线与治理 Linter(基础设施仓 contracts/,DEC-010 / DEC-031)","license":"UNLICENSED","dependencies":{"ajv":"8.20.0","ajv-formats":"3.0.1"},"development_dependencies":{"@types/node":"20.19.43","json-schema-to-typescript":"16.0.0","typescript":"5.9.3"},"readme":"# @juhai/contracts(原 platform-contracts 候选控制面)\n\n## 在 enterprise-platform 内的状态(PF-04 阶段 1,2026-09-10)\n\n- **身份**:本目录是 `企业应用/platform-contracts/` 的带来源登记导入(见 [SOURCE.md](SOURCE.md));包名按 DEC-031 命名修订改为 `@juhai/contracts`,版本 `1.0.0-rc.0`(rc 系列;非 rc `1.0.0` 受 DEC-010 附条件:远端 + Required Check)。`catalogs/`、`contracts/`、`examples/`、`apps/`、`compatibility/` 与来源逐字节一致;`schemas/` 仅含下述 PF-04 的 `causation_id` / `correlation_id` 变更。\n- **工作区根**:Linter、影响图与测试以「工作区根」(`企业应用/`,同时含 `基础/` 与 `doc/`)为基准解析 Catalog `directory` / `evidence`、DEC `source` 与各应用仓路径,不再假定包位于工作区根的直接子目录。解析顺序:`--workspace-root \u003cabs\u003e`(`node scripts/check.mjs --workspace-root …`)→ 环境变量 `PLATFORM_CONTRACTS_WORKSPACE_ROOT` → 自动探测(从本目录向上找到首个同时含 `基础/` 与 `doc/` 的祖先)。经 `pnpm` 复合脚本运行时请用环境变量(pnpm 只把额外参数附加到最后一条命令)。\n- **独立克隆**(无 `基础/` 与 `doc/` 祖先,例如云端 CI 只 checkout 本仓;2026-09-12):`check:local` 的影响图以 `--workspace-optional` 退化为\"仅包内\"计算并在 stderr 打印 `[WORKSPACE_ROOT_UNRESOLVED]` 提示,不核验 Catalog / AppManifest / 裁决的路径引用;依赖应用仓文件、工作区路径或真实探测结果的 16 个测试显式 `skip`(91 例中 75 例照跑)。`check` 与 `check:impact` 在独立克隆下仍失败关闭(退出码 2),显式 `--workspace-root` / 环境变量不可用时任何模式都失败关闭。\n- **TS 层(CT-1)**:`scripts/schema-registry.mjs` 是 key → Schema 文件 → 类型名的唯一来源;改 Schema 后运行 `pnpm generate` 重生成 `generated/`,`pnpm check:generated`(在 `check:local` 内)在缺失 / 差异 / 多余文件时失败;`pnpm build`(tsc → `dist/`)在 `test` 与 `check:local` 之前自动执行;首次使用需 `pnpm --dir contracts install`(依赖只来自公共 npm,全部 exact pin)。\n- **`pnpm check` 现状**:`check` 报告且仅报告 6 项 `PLATFORM_PROJECT_UNREGISTERED`(`基础/reports`、`基础/tests`、`基础/企业搜索与统一检索平台`、`基础/外部连接器与集成平台`、`基础/开发者自助与应用工程平台`、`基础/数据治理与隐私平台`),全部随 CHG-001(新增基础应用 MachineCatalog 变更)合并后消失;Linter 未被放宽。合并前以 `pnpm check:local`(schema 兼容 + 影响图 + 测试)作为绿色门禁;CHG-001 合并后 `check` 转绿,根 `pnpm check` 再切回完整 `check`。\n- **`causation_id` 可选、`correlation_id` 映射**(设计 §7 / §25 张力 4):`schemas/fact-envelope.v1.schema.json` 的 `required` 去掉 `causation_id`(旅程首条事实没有因果父,省略而非填占位值);`trace_id` = 旅程锚点、`correlation_id` = 业务关联写入 `fact-envelope.v1` 与 `request-context.v1` 的 `description`(后者只加说明)。Linter 新增规则 `FACT_ENVELOPE_FIELD_NOT_OPTIONAL` 防止回退为必填;`test/fact-envelope.test.mjs` 用兼容检查器自身的规则证明该放宽向后兼容(反向则报 `REQUIRED_PROPERTY_ADDED`)。`compatibility/` 冻结基线未动(信封不在基线内)。\n- **消费**:`pnpm add @juhai/contracts@1.0.0-rc.N`(exact pin,`check:pins` 强制);子路径导出 `@juhai/contracts/catalogs/*`、`/schemas/*`、`/contracts/*`、`/examples/*`、`/apps/*`、`/compatibility/*`、`/scripts/*`、`/package.json`;**裸入口(CT-1,2026-09-12)**:`import { validate, validateFact, assertValid, isValid, schemaOf, SCHEMA_KEYS, type FactEnvelopeV1 } from '@juhai/contracts'`——12 个 JSON Schema 的 TypeScript 类型(`generated/`,由 `schemas/` 生成并入库)与 Ajv 2020 校验器(按 key 懒编译;未知 key 抛 `RangeError`;`validateFact` 先验信封再按 `facts/\u003cfact_type\u003e.v\u003cmajor\u003e` 验载荷,未登记载荷 Schema 以 `payloadSchema` 失败关闭);`dist/` 随包发布,运行依赖仅 `ajv` / `ajv-formats`;`test/`、`src/`、`generated/` 不随包发布。\n\n本目录是企业应用群 Git-first 机器契约的 **W1 候选实现**,用于先建立可校验的语义基线。`DEC-010` 尚未裁决 Catalog 的最终物理位置,因此这里的 Registry、AppManifest 和 Schema 均为 `proposed` 或 `draft`,不能作为“能力已上线”的证据。\n\n## 已覆盖\n\n- `Employment` 的唯一 Owner、Canonical ID 目标格式与数据分级,以及企业 IdP 已实现权威模型的目录对账;\n- `FactEnvelope v1` JSON Schema;\n- `EmploymentTransferred v1` Payload JSON Schema;\n- HR、Digital Employee OS、Permission Platform、企业 IdP、执行监管、基础框架、嗨设、巨嗨智服、知识云、设备云、巨嗨报价系统与尤克特拉十二个草案 AppManifest;\n- Fact Producer/Consumer、Projection/Replay 和待裁决 Owner 的静态治理检查;Fact Projection 进一步绑定 Consumer、只读 Authority、状态 Schema、`consumer_name + fact_id` 幂等、Projection + `processed_fact` 原子提交、单调但不连续的聚合版本语义,以及受 Backbone ADR 阻断的消息 Gap 检测;\n- Resource/Action Catalog v1、Actor/Request Context v1 和 Permission Decision API v1 候选契约;\n- DEC-001—032 全量 Decision Catalog 登记(32 approved / 0 pending:2026-09-10 批准 010 / 031 / 032,2026-09-12 决策会批准其余 27 项,013 Broker = Redpanda、008 部分生效、030 分阶段;037—039 待 CHG-002),并校验所有 Catalog 引用的裁决可解析;\n- 权限请求/拒绝样例,强制租户一致、未知资源/动作拒绝、故障关闭和拒绝不正缓存;\n- DEC-012 完整候选 ADR、首条 Fact Schema 的不可变 proposed Snapshot 与保守向后兼容检查器;\n- 从 Catalog + AppManifest 构建的 proposed Producer/Consumer Impact Graph 与变更查询 CLI;\n- `基础/` 21 个平台目录的机器项目清单:19 个属于本轮目标,明确排除基础框架与 AI 数字员工;实现状态、代码真源、证据等级和阻塞 DEC 可查询;\n- 可执行的正向检查和 Owner、ADR、Canonical ID、PII、Replay、Consumer、Application Dependency、Permission、Schema Compatibility 负向边界测试。\n\n## 尚未裁决,禁止越权实现\n\n- `Person`、`Organization`、`Store`、`Position`、`Actor` Owner(`DEC-001`—`DEC-005`);\n- AppManifest/ProductManifest 边界、Catalog 物理真源和双 Envelope 边界(`DEC-009`—`DEC-011`,评审材料已形成但尚未批准);\n- Schema 最终组合与兼容策略批准(`DEC-012`);候选检查器只证明当前规则可机械执行,不是正式发布策略;\n- Broker、Topic、Fact Store 与 Ordering(`DEC-013`—`DEC-016`);\n- Scope 执行和权限分工(`DEC-017`—`DEC-019`);\n- 权限平台的引擎、策略存储和运行时技术路线(`DEC-029`)。\n- 尤克特拉身份、设备、客户、订单、执行与通知重名实体的 Owner、映射和迁移方案(`DEC-030`,其中 Store 仍受 `DEC-003` 阻塞)。\n- 平台契约与 SDK 的分发通道、发布包名登记与发布门禁(`DEC-031`);裁决前派生仓 Planner 只能以夹具或标注来源 SHA 的过渡复制形式被业务仓引用,不得冒充平台接入。\n\n因此 Permission Decision API 是可评审、可机械验证的候选边界,不是权限引擎已实现或已上线的声明。Actor Context 仅携带 IdP 已认证的不透明主体标识,不越权裁决 `Actor` 企业 Owner。\n\n`DEC-027/028` 已批准并进入 HR 实现;Linter 仍会阻止草案 Manifest 标记为 `active`,也不允许 `EmploymentTransferred` 越过 `DEC-010/012` 直接激活。\n\n企业 IdP 草案清单已对账其当前 E2 代码中的 Tenant/User、Application/OIDC Client、Credential/Authenticator、Consent、Session、Authorization Code/Grant、Refresh Token Family/Token、Backchannel Delivery 与 Security Event 等权威模型;这仍不代表生产 KMS/HSM、远程 CI 或生产部署已签收。`User` 是 IdP 账户主体,不等同于 DEC-001 尚未裁决的企业 `Person`。嗨设现已真实消费 IdP RS256 access token/JWKS,并登记 `material.production` 候选权限面;它只保存 actor 引用,不拥有 Tenant/User/Session/Grant。执行监管的 Project/Ticket/SLA 仍未进入企业 Entity Catalog。知识云则登记 `KnowledgeCandidate`、`KnowledgeAtom`、`KnowledgeAtomVersion`、`KnowledgeSource` 与 `KnowledgeFeedback` 五个权威对象;`KnowledgeEmbedding`、检索 Evidence 与 AI 推理结果都是可重建派生物,不得冒充企业权威实体。巨嗨报价系统已将当前 Prisma 的 68 个业务模型登记为权威对象,并由测试持续与真实 schema 对账;本地 `User/UserEvent` 及 `Outbox/OutboxReplayEvent` 明确排除,避免抢占 IdP 身份 Owner 或把技术投递记录冒充企业业务实体。尤克特拉只登记已验证的 Express/PostgreSQL 运行时,其 71 个 Prisma 模型中与全局 Catalog 重名的七个对象由 DEC-030 阻断,Fact、统一 Permission、Projection 和权威 Entity 保持空集;这不把本地数据误报成共享真源,也不把单后端误报成双后端。基础框架只作为工程模板登记,不拥有企业业务事实。\n\nPlatform Project Catalog 当前只允许���业 IdP 声明独立服务 `implemented_e2`;通知与 Webhook 中心、公共文件平台及配置与功能开关平台声明 `module_e2`。公共文件已由执行监管、巨嗨报价与嗨设三个真实消费者完成 E2 运行验证;通知投递已由执行监管、巨嗨智服与巨嗨报价三个真实消费者完成 E2 运行验证;配置平台当前只有执行监管一个真实业务消费者,生产无有效批准快照时关闭、坏刷新保留最后良好版本,并把版本/摘要/来源/原因写入 AutomationRun。前三者都不表示 G4 已裁决或独立服务已启动;配置平台尤其仍缺第二、第三消费者。报价本地 `QuotationNotificationIntent` 是技术投递记录,不登记为企业权威实体。应用与契约注册中心、企业事实干线和统一权限平台仅为 `candidate_e0`;其余目标平台仍是 `not_started`。各平台目录内复制的 `base-framework/` 一律不计为平台实现,任何 E2 证据文件都必须真实存在并报告 `passed`。\n\n## 使用\n\n无需安装第三方依赖,Node.js 20+ 即可运行:\n\n```bash\nnpm run check\nnpm test\n```\n\n`check` 校验平台项目目录、目标范围、证据、Schema 引用、Owner、Producer/Consumer、Projection/Replay、幂等/原子提交/版本顺序、权限与 Scope 对账,并对每个已登记 Fact 执行 proposed Snapshot 不可变/版本兼容检查;`test` 证明目录漏登、模板冒充实现、E2 证据未通过、Owner 冲突、Consumer 绑定漂移、Owner 越权、非原子 Projection、错误连续版本假设、Projection PII/来源漂移与不兼容 Schema 会失败。\n\n查询一个 Fact Schema 变更的直接与二跳影响:\n\n```bash\nnpm run impact -- schema schemas/facts/EmploymentTransferred.v1.json 2\n```\n\n输出明确区分节点深度,并列出 Producer、Consumers、Projections、Entity、阻塞 Decision 与相关边;未知目标返回非零退出码,不生成空的“无影响”结果。\n\n## 状态升级规则\n\n只有同时满足以下条件,才能把本目录从候选实现升级为正式真源:\n\n1. `DEC-010` ADR 已批准;\n2. `DEC-012` Schema 表达和兼容策略已批准;\n3. App Owner 对 AppManifest 与真实代码、部署资产完成核验;\n4. CI 使用本 Linter 或其正式替代品阻断冲突;\n5. 运行时证据证明事实生产、消费、幂等与 Replay,而不只是静态文件通过。\n","repository":{"type":"","url":""}}...
|
1
|
Edit
Delete
|
|
15
|
4
|
5
|
1.0.0-rc.3
|
1.0.0-rc.3
|
1789365045
|
0
|
{"scope":"@juhai","name":& {"scope":"@juhai","name":"governance","description":"基础设施层跨仓门禁(设计方案 §9):check:pins(exact pin 消费规则)、check:fixtures(契约正反例夹具)、verify:candidate(候选可晋级核验)、release:manifest(已知事实清单)、CI 模板;零依赖 CLI,供上层仓 exact pin 后在 CI 运行。","license":"UNLICENSED","bin":{"juhai-governance":"bin/cli.mjs"},"readme":"# @juhai/governance — 基础设施跨仓门禁\n\n设计方案 §4.2 / §9 定义的 `governance/` 交付:一组**零依赖**的构建期检查,随基础设施仓同一 Release 版本号发布到 Gitea npm registry(DEC-031),供上层仓 **exact pin** 后在 CI 运行(`check:pins` 为必需检查,DEC-031 附带条款 4)。\n\n## 命令(`juhai-governance \u003ccommand\u003e [--root \u003cdir\u003e]`)\n\n| 命令 | 用途 | 报告 | 退出码 |\n|---|---|---|---|\n| `check:pins [--require \u003cpkg\u003e]…` | `@juhai/*` 依赖只允许 `x.y.z` 或 `workspace:*`;`--require` 要求该包至少一处 exact pin(证明消费者已接入) | 无(stdout) | 1 = 有违规 |\n| `check:port-conformance` | 基础设施仓内独立端口测试:先构建 contracts/modules/clients,再跑 `runtime/test/port`;必须完整通过内核 14、模块 6、客户端 21 例,拒绝跳过与空跑 | `reports/port-conformance.latest.json` | 1 = 构建/测试/覆盖核验失败 |\n| `check:fixtures --suite \u003csuite.json\u003e… [--allow-unavailable-suite \u003cid\u003e]…` | 契约正反例夹具:校验套件配置后,ACCEPT 须零原因、REJECT 须有原因且含声明前缀;缺工作区默认失败,显式允许且有其他用例执行才可 partial | `reports/fixtures.latest.json` | 1 = 配置错误、空跑、不可用或用例不符 |\n| `verify:candidate --candidate \u003cdir\u003e --sha \u003csha\u003e …` | 候选可晋级核验(Q12-C / X12):逐份 required 报告核 sourceSha / dirty / 状态 / 地板 / digest,缺失即不合格 | `\u003cdir\u003e/release-candidate.json` 或 `--out` | 1 = 不合格 |\n| `release:manifest` | 已知事实清单,**逐项按磁盘判定**:`governance/package.json`、`runtime/clients/\u003cm\u003e/package.json`(name 须为 `@juhai/client-\u003cm\u003e`)、`reports/image-digest.json`(`sha256:` 且 `sourceSha` = HEAD)、compose 镜像是否 `@sha256:` 锁定、`reports/sbom.spdx.json`、`reports/signature.json`;任一缺失即 `status=partial` 并写明缺什么,不判定晋级 | `reports/release-manifest.latest.json` | 0 |\n| `ci:template [--out \u003cfile\u003e]` | 输出消费者最小 CI 模板(私包认证 + contracts/governance 必需 exact pin + 必需夹具) | — | 0 |\n| `check:modules` / `check:module-imports` / `check:catalog` / `catalog:drift` | 基础设施仓内部门禁(依赖 `runtime/modules.json` 与 `contracts/catalogs`) | `reports/*.latest.json` | 1 = 违规(drift 默认 0) |\n| `check:migration-decs` | 仓纪律 3:`runtime/modules/*/prisma/migrations` 与 `identity/apps/*/prisma/migrations` 的 `migration.sql` 前 10 行须有 `-- decision: DEC-NNN` 且该 DEC 已批准;`state=shape` 模块不得有迁移;例外只能逐个迁移登记在 `migration-decs.exceptions.json`(条件失效判 `EXCEPTION_STALE`) | `reports/migration-decs.latest.json` | 1 = 违规 |\n| `check:facts [--candidates \u003cdir\u003e] [--report-only]` | §6.4:`modules.json` 声明的 Fact ⊆ `contracts/catalogs/facts.json` ∪ CHG-004 候选(候选须 `status: pending-dec` + `blocked_by`);候选目录不可用时报 `UNRESOLVED`(fail-closed)。**接入根 `pnpm check` 前置 CT-2 材料落地** | `reports/facts.latest.json` | 1 = 违规 / unresolved |\n| `check:caddy` | §5 / §7:`modules.json` 的 HTTP 契约经 `caddy-routes.json` 映射前缀后必须被 `stack/caddy/Caddyfile` 的 path 匹配器覆盖;`/healthz`、`X-Request-Id` 注入、`{$PLATFORM_API_UPSTREAM}` 必备;本机有 `caddy` 则 `caddy validate`,否则报告 `validate: skipped`(`CHECK_CADDY_DOCKER=1` 走 docker) | `reports/caddy.latest.json` | 1 = 违规 / 语法失败 |\n\n所有报告带 `provenance`(`gitSha` / `worktreeDirty` / `runner` 原值 / `runnerNormalized` / `runId`);`worktreeDirty` 忽略 latest 报告本身。\n\nG-7 的 `port-conformance` job 保留同仓 PR 的私包认证约束,不访问数据库。每次执行使用新的临时 Vitest JSON;构建失败、测试失败或没有新报告时覆盖旧成功状态为 failed。三组逐文件地板在 `lib/port-conformance.mjs`,新增套件须同步更新覆盖清单。candidate 依赖该 job 成功,且十一份 required 报告中必须含同源码、干净工作树的端口报告;旧十份报告不能用于新版本候选。发布门禁沿用相同的源码必需报告策略。此门禁证明端口一致性,不提升模块 shape 状态。\n\n`verify:candidate` 在候选源码工作树的根目录运行:从 `runtime/reports/baseline.json` 与 `identity/reports/baseline.json` 读取最低测试数量,不能用 artifact 自报的较低地板代替。报告须为对象,验收计数与地板须为正整数,治理报告须含固定必需指标且为零;缺失、`null`、数组、标量和显式 `PARTIAL` 状态均不合格。旧治理报告没有 `status` 字段时仍按必需指标核验。指定 `--run-id` 或运行于 GitHub Actions 时要求每份报告为 CI runner;本地诊断保留 local 来源,不代表远端验收。独立调用纯函数 `evaluateCandidate` 时须显式传入 `{ baselines, requireCi, mainlineRequired }`;CLI 自动读取源码基线和 `runtime/modules.json`。\n\n### 持久化主线候选证据\n\n候选源码中的 fact / permission / audit 任一模块进入 `authority` 或 `e2` 后,必需报告从 11 份增加为 13 份,增加 `mainline-acceptance` 和 `revocation-sla`。模块登记缺失、损坏或状态非法时拒绝候选;不能由 artifact 自报关闭此要求。RC 发布入口读取相同源码策略,不接受只含旧 11 份报告的候选。\n\n主线报告须完整包含事实持久化 11、审计篡改 5、主线/撤权/混沌 11 项;各套件唯一,退出成功,无失败、pending 或 todo。撤权报告至少 20 个正数样本,按样本重算 p95/max 并比对摘要,要求 p95 \u003c 30 秒、max \u003c 60 秒。Grant 撤销通过而就业 Scope 仍待实现时,报告必须显式保持 `partial` 和未验证说明,候选结果保留这项覆盖边界;这不表示 MS-3、真实 HR/OS 接入或生产签收完成。\n\nruntime artifact 兼容旧单目录扁平上传,以及新增仓根报告后的目录结构。只在本次下载目录内读取固定的两种路径,不回退到仓内历史报告;同时发现两份时拒绝。源登记或目录读取失败也覆盖写入不合格候选,防止遗留成功报告。\n\n## 镜像、SBOM 与签名(开发计划 §3A D-1 / D-2;仓根脚本)\n\n| 脚本 | 作用 | 产物 |\n|---|---|---|\n| `pnpm image:build`(`governance/build-image.mjs`) | 用 `runtime/Dockerfile` 构建运行时镜像;默认 `--context head`(`git archive HEAD:runtime`,本机 WIP 不进镜像);私有 registry token 只经 `--secret id=npmrc,src=\u003cnpmrc\u003e`(默认 `~/.npmrc`,`--npmrc` 可指定)进入安装层,不进镜像、不打印 | `reports/image-digest.json`:`digest` = 本机 `--load` 的 image id(`digestKind` 说明;推送后换 registry manifest digest)、`sourceSha` / `worktreeDirty` / `dockerfileTracked` / 平台 / 大小 / 基础镜像 |\n| `pnpm image:sbom`(`governance/sbom.mjs`) | `syft` 或 `docker sbom` 生成完整 SPDX(OS + Node);两者都缺时退到 **lockfile 模式**:从镜像里 deploy 树的 pnpm lock 与工作区包生成只含 Node 依赖的 SPDX 2.3(`sbom.latest.json.scope` 标 partial,Debian 包不在内;完整 SBOM 由 CI image job 的 syft 产出);镜像不可用则退出 3 不写空文件 | `reports/sbom.spdx.json` + 元数据 `reports/sbom.latest.json`(tool / scope / sha256 / 包数) |\n| `pnpm image:sign`(`governance/sign-image.mjs`) | `cosign sign --key $COSIGN_KEY \u003cregistry ref@digest\u003e`;未推送 / 无密钥 / 无 cosign 时明确跳过、退出 0 | `reports/signature.json`(缺失即 Manifest `missing: signature`) |\n\n`release:manifest` 逐项按磁盘判定这三份产物;CI 的 `image` job 在 Secret 配置后产出同名 artifact(不推 registry)。\n\n## 环境晋级记录(开发计划 PF-23;DEC-024 A / DEC-026;仓根脚本)\n\n| 脚本 | 作用 | 产物 |\n|---|---|---|\n| `pnpm promotion:check -- --record \u003crecord.json\u003e [--manifest …] [--template …]`(`governance/check-promotion.mjs`) | 核验一份晋级记录:R1 形状(`stack/promotion/promotion-record.schema.json`)、R2 级序 dev→test→staging→prod(preview←candidate)、R3 同 digest(记录 = 候选 = Manifest 文件 `images.runtime.digest`,prod 禁止 rebuild 由此机器化)、R4 级别门槛(staging:eligible + SBOM + 签名或未过期 waiver;prod:Manifest complete + 签名 + 签收全闭)、R5 必需检查项、R6 审批角色、R7 回滚演练 ≤ 600 s、R8 preview 上限、R9 签收项在模板内 | `reports/promotion.latest.json`(`verdict` APPROVED / APPROVED_WITH_PENDING_SIGNOFFS / REJECTED;REJECTED 退出 1) |\n\n记录模板 `stack/promotion/promotion-record.template.json`,签收模板 `stack/promotion/target-env-signoff.template.json`(P1—P9,取自 OS `target-env-signoff.json`);步骤见 [staging 晋级操作说明](../docs/staging晋级操作说明.md)。纯函数 `evaluatePromotion(record, { schema, manifest, template, today })` 可独立调用(`governance/test/promotion.test.mjs` 18 例)。\n\n## 消费方接入\n\n```bash\npnpm add -D @juhai/governance@1.0.0-rc.1 # exact pin;.npmrc 配 @juhai 作用域到 Gitea registry\npnpm exec juhai-governance ci:template --out .github/workflows/platform-governance.yml\npnpm exec juhai-governance check:pins --require @juhai/contracts --require @juhai/governance\npnpm exec juhai-governance check:fixtures --suite governance/fixtures/contracts.suite.json\n```\n\n夹���套件格式见 `check-fixtures.mjs` 头注;示例 `fixtures/contracts.suite.json`(正例取 `@juhai/contracts` 的 examples,反例故意破坏必填 / 类型 / 血缘字段)。消费者须在自己仓内建立 `governance/fixtures/contracts.suite.json`,按实际安装位置调整 schema / inputFile 路径;模板不再跳过缺失文件。\n\n套件必须有非空且不重复的 id / case id、合法 expect、已声明 schema,以及 input / inputFile 二选一。空套件、缺失 schema、损坏的本地引用、文件读取/解析/模块加载错误会生成 failed 报告并退出 1,覆盖旧的成功报告;规则必须显式返回原因数组,DEC-039 适配器的失败结论不能被重新判为成功。JSON Schema 校验仍是头注声明的子集,不代表完整元 Schema 校验或支持所有关键字。\n\n根 `pnpm check:fixtures` 先构建运行时模块,再显式带 `--allow-unavailable-suite dec-039-party-model`,仅容许独立克隆缺少企业应用工作区时跳过 DEC-039 外部套件,报告 status=partial、保留 unavailable 计数;contracts 与六个模块套件仍必须执行,缺失模块构建产物不会被该豁免放过。全部套件不可用、配置错误和真实用例失败仍阻断。消费者模板使用默认严格模式。`--allow-unavailable` 保留为显式允许所有不可用套件的诊断开关,不用于本仓根门禁。以上增强为仓内新源码,已发布的 `1.0.0-rc.0` 保持不变,本仓已准备 `1.0.0-rc.1`,实际发布及 Registry 安装状态见发布记录。\n\n## 本仓内\n\n`pnpm check`(仓根)已串联:`check:pins` → `check:modules` → `check:module-imports` → `check:catalog` → `catalog:drift` → `check:fixtures` → `check:facts` → `check:migration-decs` → `check:caddy` → governance 测试 → contracts → runtime 静态门禁。`pnpm check:port-conformance` 独立运行真实端口测试,CI 单独生产证据。`.github/CODEOWNERS` 仍为角色占位,不能把覆盖测试通过解释为真实团队审批已生效。发布走 DEC-031 的固定源码 RC 通道;已发布版本不覆盖,新包代码须使用后续新 RC 版本。\n","repository":{"type":"","url":""}}...
|
1
|
Edit
Delete
|
|
16
|
5
|
5
|
1.0.0-rc.3
|
1.0.0-rc.3
|
1789365048
|
0
|
{"scope":"@juhai","name":& {"scope":"@juhai","name":"client-fact","description":"可信事实受理客户端、事务 Outbox 与幂等 Inbox;Kafka 运输不影响领域契约","license":"UNLICENSED","dependencies":{"@prisma/client":"6.19.3"},"development_dependencies":{"@types/node":"^22.10.2","typescript":"^5.7.2","vitest":"^2.1.8"},"peer_dependencies":{"@juhai/kernel":"0.16.1"},"readme":"ERROR: No README data found!","repository":{"type":"","url":""}}...
|
71
|
Edit
Delete
|
|
17
|
2
|
5
|
0.22.0
|
0.22.0
|
1789471733
|
0
|
{"scope":"@juhai","name":& {"scope":"@juhai","name":"kernel","description":"基础框架内核契约(租户/信封/状态机/重放/请求上下文/平台端口/RLS/告警/作业)——源码留在 base-framework 仓,上层按框架版本 pin","license":"UNLICENSED","dependencies":{"zod":"^3.24.1"},"development_dependencies":{"typescript":"^5.7.2","vitest":"^2.1.8"},"readme":"ERROR: No README data found!","repository":{"type":"git","url":"git@gitea.g-hi.com:luoanwu/base-framework.git"}}...
|
18
|
Edit
Delete
|
|
18
|
3
|
5
|
1.0.0-rc.4
|
1.0.0-rc.4
|
1789773216
|
0
|
{"scope":"@juhai","name":& {"scope":"@juhai","name":"contracts","description":"企业应用群机器契约:Catalog、JSON Schema、OpenAPI、兼容基线与治理 Linter(基础设施仓 contracts/,DEC-010 / DEC-031)","license":"UNLICENSED","dependencies":{"ajv":"8.20.0","ajv-formats":"3.0.1"},"development_dependencies":{"@types/node":"20.19.43","json-schema-to-typescript":"16.0.0","typescript":"5.9.3"},"readme":"# @juhai/contracts(原 platform-contracts 候选控制面)\n\n## 在 enterprise-platform 内的状态(PF-04 阶段 1,2026-09-10)\n\n- **身份**:本目录是原 `platform-contracts/` 候选控制面的带来源登记导入(见 [SOURCE.md](SOURCE.md);来源目录已于 2026-09-16 按 PF-04 阶段 2 物理移除,SOURCE.md 记录的指纹是它最后的状态);包名按 DEC-031 命名修订改为 `@juhai/contracts`,版本 `1.0.0-rc.0`(rc 系列;非 rc `1.0.0` 受 DEC-010 附条件:远端 + Required Check)。`catalogs/`、`contracts/`、`examples/`、`apps/`、`compatibility/` 与来源逐字节一致;`schemas/` 仅含下述 PF-04 的 `causation_id` / `correlation_id` 变更。\n- **工作区根**:Linter、影响图与测试以「工作区根」(`企业应用/`,同时含 `平台治理/基础/` 与 `doc/`)为基准解析 Catalog `directory` / `evidence`、DEC `source` 与各应用仓路径,不再假定包位于工作区根的直接子目录。解析顺序:`--workspace-root \u003cabs\u003e`(`node scripts/check.mjs --workspace-root …`)→ 环境变量 `PLATFORM_CONTRACTS_WORKSPACE_ROOT` → 自动探测(从本目录向上找到首个同时含 `平台治理/基础/` 与 `doc/` 的祖先)。经 `pnpm` 复合脚本运行时请用环境变量(pnpm 只把额外参数附加���最后一条命令)。\n- **独立克隆**(向上没有含 `workspace.json` 的工作区根,例如云端 CI 只 checkout 本仓;2026-09-12):`check:local` 的影响图以 `--workspace-optional` 退化为\"仅包内\"计算并在 stderr 打印 `[WORKSPACE_ROOT_UNRESOLVED]` 提示,不核验 Catalog / AppManifest / 裁决的路径引用;依赖应用仓文件、工作区路径或真实探测结果的 16 个测试显式 `skip`(91 例中 75 例照跑)。`check` 与 `check:impact` 在独立克隆下仍失败关闭(退出码 2),显式 `--workspace-root` / 环境变量不可用时任何模式都失败关闭。\n- **TS 层(CT-1)**:`scripts/schema-registry.mjs` 是 key → Schema 文件 → 类型名的唯一来源;改 Schema 后运行 `pnpm generate` 重生成 `generated/`,`pnpm check:generated`(在 `check:local` 内)在缺失 / 差异 / 多余文件时失败;`pnpm build`(tsc → `dist/`)在 `test` 与 `check:local` 之前自动执行;首次使用需 `pnpm --dir contracts install`(依赖只来自公共 npm,全部 exact pin)。\n- **`pnpm check` 现状**:`check` 报告且仅报告 4 项 `PLATFORM_PROJECT_UNREGISTERED`(`企业控制面/企业搜索与统一检索平台`、`企业控制面/外部连接器与集成平台`、`企业控制面/开发者自助与应用工程平台`、`企业控制面/数据治理与隐私平台`;2026-09-14 迁移后扫描面已换成 `企业控制面/`,G-12 提到的 `平台治理/基础/reports`、`平台治理/基础/tests` 两项假阳性随之消失),全部随 CHG-001(新增基础应用 MachineCatalog 变更)合并后消失;Linter 未被放宽。合并前以 `pnpm check:local`(schema 兼容 + 影响图 + 测试)作为绿色门禁;CHG-001 合并后 `check` 转绿,根 `pnpm check` 再切回完整 `check`。\n- **`causation_id` 可选、`correlation_id` 映射**(设计 §7 / §25 张力 4):`schemas/fact-envelope.v1.schema.json` 的 `required` 去掉 `causation_id`(旅程首条事实没有因果父,省略而非填占位值);`trace_id` = 旅程锚点、`correlation_id` = 业务关联写入 `fact-envelope.v1` 与 `request-context.v1` 的 `description`(后者只加说明)。Linter 新增规则 `FACT_ENVELOPE_FIELD_NOT_OPTIONAL` 防止回退为必填;`test/fact-envelope.test.mjs` 用兼容检查器自身的规则证明该放宽向后兼容(反向则报 `REQUIRED_PROPERTY_ADDED`)。`compatibility/` 冻结基线未动(信封不在基线内)。\n- **消费**:`pnpm add @juhai/contracts@1.0.0-rc.N`(exact pin,`check:pins` 强制);子路径导出 `@juhai/contracts/catalogs/*`、`/schemas/*`、`/contracts/*`、`/examples/*`、`/apps/*`、`/compatibility/*`、`/scripts/*`、`/package.json`;**裸入口(CT-1,2026-09-12)**:`import { validate, validateFact, assertValid, isValid, schemaOf, SCHEMA_KEYS, type FactEnvelopeV1 } from '@juhai/contracts'`——12 个 JSON Schema 的 TypeScript 类型(`generated/`,由 `schemas/` 生成并入库)与 Ajv 2020 校验器(按 key 懒编译;未知 key 抛 `RangeError`;`validateFact` 先验信封再按 `facts/\u003cfact_type\u003e.v\u003cmajor\u003e` 验载荷,未登记载荷 Schema 以 `payloadSchema` 失败关闭);`dist/` 随包发布,运行依赖仅 `ajv` / `ajv-formats`;`test/`、`src/`、`generated/` 不随包发布。\n\n本目录是企业应用群 Git-first 机器契约的 **W1 候选实现**,用于先建立可校验的语义基线。`DEC-010` 尚未裁决 Catalog 的最终物理位置,因此这里的 Registry、AppManifest 和 Schema 均为 `proposed` 或 `draft`,不能作为“能力已上线”的证据。\n\n## 已覆盖\n\n- `Employment` 的唯一 Owner、Canonical ID 目标格式与数据分级,以及企业 IdP 已实现权威模型的目录对账;\n- `FactEnvelope v1` JSON Schema;\n- `EmploymentTransferred v1` Payload JSON Schema;\n- HR、Digital Employee OS、Permission Platform、企业 IdP、执行监管、基础框架、嗨设、巨嗨智服、知识云、设备云、巨嗨报价系统与尤克特拉十二个草案 AppManifest���\n- Fact Producer/Consumer、Projection/Replay 和待裁决 Owner 的静态治理检查;Fact Projection 进一步绑定 Consumer、只读 Authority、状态 Schema、`consumer_name + fact_id` 幂等、Projection + `processed_fact` 原子提交、单调但不连续的聚合版本语义,以及受 Backbone ADR 阻断的消息 Gap 检测;\n- Resource/Action Catalog v1、Actor/Request Context v1 和 Permission Decision API v1 候选契约;\n- DEC-001—032 全量 Decision Catalog 登记(32 approved / 0 pending:2026-09-10 批准 010 / 031 / 032,2026-09-12 决策会批准其余 27 项,013 Broker = Redpanda、008 部分生效、030 分阶段;037—039 待 CHG-002),并校验所有 Catalog 引用的裁决可解析;\n- 权限请求/拒绝样例,强制租户一致、未知资源/动作拒绝、故障关闭和拒绝不正缓存;\n- DEC-012 完整候选 ADR、首条 Fact Schema 的不可变 proposed Snapshot 与保守向后兼容检查器;\n- 从 Catalog + AppManifest 构建的 proposed Producer/Consumer Impact Graph 与变更查询 CLI;\n- `平台治理/基础/` 21 个平台目录的机器项目清单:19 个属于本轮目标,明确排除基础框架与 AI 数字员工;实现状态、代码真源、证据等级和阻塞 DEC 可查询;\n- 可执行的正向检查和 Owner、ADR、Canonical ID、PII、Replay、Consumer、Application Dependency、Permission、Schema Compatibility 负向边界测试。\n\n## 尚未裁决,禁止越权实现\n\n- `Person`、`Organization`、`Store`、`Position`、`Actor` Owner(`DEC-001`—`DEC-005`);\n- AppManifest/ProductManifest 边界、Catalog 物理真源和双 Envelope 边界(`DEC-009`—`DEC-011`,评审材料已形成但尚未批准);\n- Schema 最终组合与兼容策略批准(`DEC-012`);候选检查器只证明当前规则可机械执行,不是正式发布策略;\n- Broker、Topic、Fact Store 与 Ordering(`DEC-013`—`DEC-016`);\n- Scope 执行和权限分工(`DEC-017`—`DEC-019`);\n- 权限平台的引擎、策略存储和运行时技术路线(`DEC-029`)。\n- 尤克特拉身份、设备、客户、订单、执行与通知重名实体的 Owner、映射和迁移方案(`DEC-030`,其中 Store 仍受 `DEC-003` 阻塞)。\n- 平台契约与 SDK 的分发通道、发布包名登记与发布门禁(`DEC-031`);裁决前派生仓 Planner 只能以夹具或标注来源 SHA 的过渡复制形式被业务仓引用,不得冒充平台接入。\n\n因此 Permission Decision API 是可评审、可机械验证的候选边界,不是权限引擎已实现或已上线的声明。Actor Context 仅携带 IdP 已认证的不透明主体标识,不越权裁决 `Actor` 企业 Owner。\n\n`DEC-027/028` 已批准并进入 HR 实现;Linter 仍会阻止草案 Manifest 标记为 `active`,也不允许 `EmploymentTransferred` 越过 `DEC-010/012` 直接激活。\n\n企业 IdP 草案清单已对账其当前 E2 代码中的 Tenant/User、Application/OIDC Client、Credential/Authenticator、Consent、Session、Authorization Code/Grant、Refresh Token Family/Token、Backchannel Delivery 与 Security Event 等权威模型;这仍不代表生产 KMS/HSM、远程 CI 或生产部署已签收。`User` 是 IdP 账户主体,不等同于企业 `Person`(其 Owner 归属由 DEC-001 裁定,2026-09-12 已批准)。嗨设现已真实消费 IdP RS256 access token/JWKS,并登记 `material.production` 候选权限面;它只保存 actor 引用,不拥有 Tenant/User/Session/Grant。执行监管的 Project/Ticket/SLA 仍未进入企业 Entity Catalog。知识云则登记 `KnowledgeCandidate`、`KnowledgeAtom`、`KnowledgeAtomVersion`、`KnowledgeSource` 与 `KnowledgeFeedback` 五个权威对象;`KnowledgeEmbedding`、检索 Evidence 与 AI 推理结果都是可重建派生物,不得冒充企业权威实体。巨嗨报价系统已将当前 Prisma 的 68 个业务模型登记为权威对象,并由测试持续与真实 schema 对账;本地 `User/UserEvent` 及 `Outbox/OutboxReplayEvent` 明确排除,避免抢占 IdP 身份 Owner 或把技术投递记录冒充企业业务实体。尤克特拉只登记已验证的 Express/PostgreSQL 运行时,其 71 个 Prisma 模型中与全局 Catalog 重名的七个对象由 DEC-030 阻断,Fact、统一 Permission、Projection 和权威 Entity 保持空集;这不把本地数据误报成共享真源,也不把单后端误报成双后端。基础框架只作为工程模板登记,不拥有企业业务事实。\n\nPlatform Project Catalog 当前只允许企业 IdP 声明独立服务 `implemented_e2`;通知与 Webhook 中心、公共文件平台及配置与功能开关平台声明 `module_e2`。公共文件已由执行监管、巨嗨报价与嗨设三个真实消费者完成 E2 运行验证;通知投递已由执行监管、巨嗨智服与巨嗨报价三个真实消费者完成 E2 运行验证;配置平台当前只有执行监管一个真实业务消费者,生产无有效批准快照时关闭、坏刷新保留最后良好版本,并把版本/摘要/来源/原因写入 AutomationRun。前三者都不表示 G4 已裁决或独立服务已启动;配置平台尤其仍缺第二、第三消费者。报价本地 `QuotationNotificationIntent` 是技术投递记录,不登记为企业权威实体。应用与契约注册中心、企业事实干线和统一权限平台仅为 `candidate_e0`;其余目标平台仍是 `not_started`。各平台目录内复制的 `base-framework/` 一律不计为平台实现,任何 E2 证据文件都必须真实存在并报告 `passed`。\n\n## 使用\n\n无需安装第三方依赖,Node.js 20+ 即可运行:\n\n```bash\nnpm run check\nnpm test\n```\n\n`check` 校验平台项目目录、目标范围、证据、Schema 引用、Owner、Producer/Consumer、Projection/Replay、幂等/原子提交/版本顺序、权限与 Scope 对账,并对每个已登记 Fact 执行 proposed Snapshot 不可变/版本兼容检查;`test` 证明目录漏登、模板冒充实现、E2 证据未通过、Owner 冲突、Consumer 绑定漂移、Owner 越权、非原子 Projection、错误连续版本假设、Projection PII/来源漂移与不兼容 Schema 会失败。\n\n查询一个 Fact Schema 变更的直接与二跳影响:\n\n```bash\nnpm run impact -- schema schemas/facts/EmploymentTransferred.v1.json 2\n```\n\n输出明确区分节点深度,并列出 Producer、Consumers、Projections、Entity、阻塞 Decision 与相关边;未知目标返回非零退出码,不生成空的“无影响”结果。\n\n## 状态升级规则\n\n只有同时满足以下条件,才能把本目录从候选实现升级为正式真源:\n\n1. `DEC-010` ADR 已批准;\n2. `DEC-012` Schema 表达和兼容策略已批准;\n3. App Owner 对 AppManifest 与真实代码、部署资产完成核验;\n4. CI 使用本 Linter 或其正式替代品阻断冲突;\n5. 运行时证据证明事实生产、消费、幂等与 Replay,而不只是静态文件通过。\n","repository":{"type":"","url":""}}...
|
0
|
Edit
Delete
|
|
19
|
4
|
5
|
1.0.0-rc.4
|
1.0.0-rc.4
|
1789773218
|
0
|
{"scope":"@juhai","name":& {"scope":"@juhai","name":"governance","description":"基础设施层跨仓门禁(设计方案 §9):check:pins(exact pin 消费规则)、check:fixtures(契约正反例夹具)、verify:candidate(候选可晋级核验)、release:manifest(已知事实清单)、CI 模板;零依赖 CLI,供上层仓 exact pin 后在 CI 运行。","license":"UNLICENSED","bin":{"juhai-governance":"bin/cli.mjs"},"readme":"# @juhai/governance — 基础设施跨仓门禁\n\n设计方案 §4.2 / §9 定义的 `governance/` 交付:一组**零依赖**的构建期检查,随基础设施仓同一 Release 版本号发布到 Gitea npm registry(DEC-031),供上层仓 **exact pin** 后在 CI 运行(`check:pins` 为必需检查,DEC-031 附带条款 4)。\n\n## 命令(`juhai-governance \u003ccommand\u003e [--root \u003cdir\u003e]`)\n\n| 命令 | 用途 | 报告 | 退出码 |\n|---|---|---|---|\n| `check:pins [--require \u003cpkg\u003e]…` | `@juhai/*` 依赖只允许 `x.y.z` 或 `workspace:*`;`--require` 要求该包至少一处 exact pin(证明消费者已接入) | 无(stdout) | 1 = 有违规 |\n| `check:port-conformance` | 基础设施仓内独立端口测试:先构建 contracts/modules/clients,再跑 `runtime/test/port`;必须完整通过内核 14、模块 6、客户端 21 例,拒绝跳过与空跑 | `reports/port-conformance.latest.json` | 1 = 构建/测试/覆盖核验失败 |\n| `check:fixtures --suite \u003csuite.json\u003e… [--allow-unavailable-suite \u003cid\u003e]…` | 契约正反例夹具:校验套件配置后,ACCEPT 须零原因、REJECT 须有原因且含声明前缀;缺工作区默认失败,显式允许且有其他用例执行才可 partial | `reports/fixtures.latest.json` | 1 = 配置错误、空跑、不可用或用例不符 |\n| `verify:candidate --candidate \u003cdir\u003e --sha \u003csha\u003e …` | 候选可晋级核验(Q12-C / X12):逐份 required 报告核 sourceSha / dirty / 状态 / 地板 / digest,缺失即不合格 | `\u003cdir\u003e/release-candidate.json` 或 `--out` | 1 = 不合格 |\n| `release:manifest` | 已知事实清单,**逐项按磁盘判定**:`governance/package.json`、`runtime/clients/\u003cm\u003e/package.json`(name 须为 `@juhai/client-\u003cm\u003e`)、`reports/image-digest.json`(`sha256:` 且 `sourceSha` = HEAD)、compose 镜像是否 `@sha256:` 锁定、`reports/sbom.spdx.json`、`reports/signature.json`;任一缺失即 `status=partial` 并写明缺什么,不判定晋级 | `reports/release-manifest.latest.json` | 0 |\n| `ci:template [--out \u003cfile\u003e]` | 输出消费者最小 CI 模板(私包认证 + contracts/governance 必需 exact pin + 必需夹具) | — | 0 |\n| `check:modules` / `check:module-imports` / `check:catalog` / `catalog:drift` | 基础设施仓内部门禁(依赖 `runtime/modules.json` 与 `contracts/catalogs`) | `reports/*.latest.json` | 1 = 违规(drift 默认 0) |\n| `reports:rebind [--gates a,b] [--list] [--dry-run]` | **在 HEAD 的干净检出里重跑零依赖门禁并把报告带回**(偏差 #34-A 裁决实现)。`provenance.worktreeDirty` 由全仓 `git status` 算,而 `check:evidence` 按作用域判过期——口径不一致使得只要任何无关文件脏着就没法回绑任何报告;本工具不改判据,改为换个干净的地方生成。可行前提是 `governance/` 零依赖,临时检出**不需要 pnpm install**。作用域内有未提交输入的门禁会被跳过(否则等于用 HEAD 的结论覆盖当前工作区);目标报告自己在工作区未提交时也跳过(可能是并行会话的在途产物,覆盖即销毁,`--force` 才override);产出若不是「绑 HEAD 且 dirty=false」则拒绝带回。一个门禁可写多份报告(`workbench-snapshots` 两份快照),要么全带回要么一份不带,避免同源报告绑到不同提交。需要构建产物的 `check:fixtures` / `check:port-conformance` 与 runtime / contracts 的检查不在范围,须在装好依赖的检出里跑。 |\n| `check:migration-decs` | 仓纪律 3:`runtime/modules/*/prisma/migrations` 与 `identity/apps/*/prisma/migrations` 的 `migration.sql` 前 10 行须有 `-- decision: DEC-NNN` 且该 DEC 已批准;`state=shape` 模块不得有迁移;例外只能逐个迁移登记在 `migration-decs.exceptions.json`(条件失效判 `EXCEPTION_STALE`) | `reports/migration-decs.latest.json` | 1 = 违规 |\n| `check:facts [--candidates \u003cdir\u003e] [--report-only]` | §6.4:`modules.json` 声明的 Fact ⊆ `contracts/catalogs/facts.json` ∪ CHG-004 候选(候选须 `status: pending-dec` + `blocked_by`);候选目录不可用时报 `UNRESOLVED`(fail-closed)。**接入根 `pnpm check` 前置 CT-2 材料落地** | `reports/facts.latest.json` | 1 = 违规 / unresolved |\n| `check:caddy` | §5 / §7:`modules.json` 的 HTTP 契约经 `caddy-routes.json` 映射前缀后必须被 profiles 段登记的每份 Caddyfile(dev 基线 `stack/caddy/Caddyfile` + staging `Caddyfile.staging`)的 path 匹配器覆盖;tls=required 的 profile 另守 `TLS_DISABLED` / `TLS_HOST_MISSING` / `TLS_ISSUER_MISSING` / `HSTS_MISSING` / `PLAINTEXT_SITE_FORBIDDEN`(2026-09-16);`/healthz`、`X-Request-Id` 注入、`{$PLATFORM_API_UPSTREAM}` 必备;本机有 `caddy` 则 `caddy validate`,否则报告 `validate: skipped`(`CHECK_CADDY_DOCKER=1` 走 docker) | `reports/caddy.latest.json` | 1 = 违规 / 语法失败 |\n| `check:otel` | §5 / §15 采纳形态:`stack/otel/collector.yaml` 与登记真源 `otel-attributes.json` 逐项一致(三条 pipeline 的 processor、keep_keys allowlist、属性上限 / 时间有效性 / 产生端名单);2026-09-16 起另守告警规则——`stack/otel/prometheus.yaml` 的 `rule_files` 含登记 glob,`stack/otel/rules/*.yaml` 每条规则有 for / labels.severity / annotations.summary / annotations.runbook,expr 指标带选择器且在 alerts.metrics 登记(登记 = 有实测产生端;没有产生端的写 alerts.pending);本机有 `promtool` 则校验语法,`CHECK_OTEL_DOCKER=1` 用 compose 锁定的 prometheus 镜像跑,否则报告 `skipped` | `reports/otel.latest.json` | 1 = 违规 / promtool 失败 |\n| `check:evidence [--read-only] [--json]` | 检查报告绑定提交到 HEAD 的作用域差异,以及暂存、未暂存、删除、未跟踪输入。静态报告按 error 阻断,运行验收沿用登记的 warn;无关改动不影响。分别统计 fresh / stale / worktreeChanged / invalid / exempted,例外不计新鲜;存在 warn 或豁免时为 partial,退出 0 不代表完整验收。**未登记的报告也要逐条记账**(2026-09-18):`SCOPE_UNDECLARED` 是 info、不拦任何东西,于是「未登记」这一类可以无声增长,而它恰恰是本门禁完全看不见的那部分(当时 48 份报告里 13 份在此)。现由 `evidence-scopes.json` 的 `undeclared` 逐条写明 class / reason / recordedAt / resolveBy,五类取值 self / aggregate / provenance-missing / one-off-snapshot / no-generator;报告存在却既无作用域又无账 = `UNDECLARED_UNACCOUNTED` 判红,账指向的报告已登记或已消失 = `UNDECLARED_STALE` 判红,字段残缺或 class 非法 = `UNDECLARED_INCOMPLETE` 判红。记账**不是豁免**:no-generator 与 one-off-snapshot 的出口只有「补生成脚本后转正式登记」或「退役该报告」二选一。`--read-only` 不改报告,`--json` 只输出 JSON | `reports/evidence-freshness.latest.json`(只读模式不写) | 1 = error;0 = passed 或 partial,须读取 status / counts |\n| `check:gate-flow [--read-only] [--json]` | **每个门禁的失败信号有谁在看?**(2026-09-18 新增)治理层 2026-09-14 为自己建了 `门禁消费登记.json` 逐条回答这个问题,本仓一直没问过。实测根 `package.json` 44 个脚本里 12 个既不在 `pnpm check` 链、CI 也不调用,其中三个是真门禁——`image:smoke`(**CI 的 image job 构建镜像、生成 SBOM、签名,却从不启动它一次**,而开发计划把这六项冒烟写成 D-1 的退出条件)、`promotion:check`(事件驱动)、`check:deployed`(要 docker 与在跑的底座)。三个各有理由,但理由只散在 CLAUDE.md / README 的散文里、没有复核期。**消费关系一律自动推导,不接受声明**:从 `check` 链递归展开,再对两份 CI 工作流按脚本名与脚本里的 `.mjs` 路径现取(CI 有几处绕开 pnpm 直接 `node governance/…`)。`governance/gate-flow.json` 因此只装推不出来的那些,随接线逐条变少,也不能无声变多。F1 无人消费且未登记;F2 登记已腐烂(脚本没了 / 已被消费 / 重名);F3 流外门禁缺 reason 或 wireInWhen;F4 缺 `conditionReviewBy` 或已过期;F5 role 非法。F4 守日期不守条件——接入条件多半含人的判断,能机器化的只有「必须有人按期回来看一眼」。 | `reports/gate-flow.latest.json`(只读模式不写) | 1 = 有违规;0 = 通过 |\n| `check:ci-mirror [--read-only] [--json]` | **两条 CI 通道是不是真的同步**(2026-09-18 新增)。`CLAUDE.md` 与镜像文件自己的头注释都写着「`.gitea/workflows/platform.yml` 是 `.github` 版的镜像副本,只差四处,两份必须同步改」,而实测**没有任何东西在比对它们**。剥掉整行注释与空行、按 `governance/ci-mirror.json` 把镜像还原成主干形态之后,两份 461 行逐行相同——文件层面的差异恰好三类(镜像头注释块、artifact v3↔v4、一行 `GOV_REPORT_RUNNER`)。M1 声明之外的差异;M2 声明了却已不存在(声明不许腐烂);M3 声明缺 id 或 reason。只剥**整行**注释:行尾注释可能跟在真命令后面,剥掉会让门禁漏判。**值得有执行者的理由不是洁癖**:那行 `GOV_REPORT_RUNNER: gitea-actions` 是证据来源标注的唯一保证——act_runner 为兼容会设 `GITHUB_ACTIONS=true`,不显式覆盖,本通道产出的报告���把自己标成 github-actions 并被 `verify-candidate` 当作 CI 证据接受,一次漏同步就是一次冒充。**未决口径**见声明里的 `openDiscrepancy`:头注释宣称的差异③『fork 判定改用 `gitea.*` 上下文』**在文件里根本不存在**,两份的 fork 守卫逐字相同、全是 `github.*`;是声称做了没做还是当初判断错了,归 SRE / 框架 Owner,本门禁不替人裁决。 | `reports/ci-mirror.latest.json`(只读模式不写) | 1 = 有违规;0 = 通过 |\n| `check:deployed`(仓根脚本,不在发布 CLI 命令集) | 核对固定镜像源提交、当前 HEAD 的运行时输入、目标容器镜像及环境键。运行时有变更但镜像未构建、容器未换、无目标容器、缺源提交或脏镜像均阻断;仅治理/文档/报告变化无需重建。未提交运行时输入与缺环境键单列为 partial。默认只读,`--write-report` 才写报告;不接触业务数据 | 可选 `reports/deployed-runtime.latest.json` | 1 = 部署未满足;2 = Docker 不可用;0 = passed / partial |\n\n`catalog:drift --workspace-root \u003c工作区根\u003e` 支持独立检出指向真实工作区,也支持 `PLATFORM_CONTRACTS_WORKSPACE_ROOT`;显式路径无效时拒绝执行,自动探测不到时才保留 unknown。\n\nCatalog 对账分别处理实现状态与证据等级:`authority` 表示权威持久化实现,不自动要求或授予 E2;`candidate_e0` 可保留并记录待签收信息。只有模块明确声明 `e2` 时,才要求与 Catalog 的 `implemented_e2` 对账。不得为了消除差异自动升级 Catalog。\n\n所有报告带 `provenance`(`gitSha` / `worktreeDirty` / `runner` 原值 / `runnerNormalized` / `runId`);`worktreeDirty` 忽略 latest 报告本身。\n\nG-7 的 `port-conformance` job 保留同仓 PR 的私包认证约束,不访问数据库。每次执行使用新的临时 Vitest JSON;构建失败、测试失败或没有新报告时覆盖旧成功状态为 failed。三组逐文件地板在 `lib/port-conformance.mjs`,新增套件须同步更新覆盖清单。candidate 依赖该 job 成功,且十一份 required 报告中必须含同源码、干净工作树的端口报告;旧十份报告不能用于新版本候选。发布门禁沿用相同的源码必需报告策略。此门禁证明端口一致性,不提升模块 shape 状态。\n\n`verify:candidate` 在候选源码工作树的根目录运行:从 `runtime/reports/baseline.json` 与 `identity/reports/baseline.json` 读取最低测试数量,不能用 artifact 自报的较低地板代替。报告须为对象,验收计数与地板须为正整数,治理报告须含固定必需指标且为零;缺失、`null`、数组、标量和显式 `PARTIAL` 状态均不合格。旧治理报告没有 `status` 字段时仍按必需指标核验。指定 `--run-id` 或运行于 GitHub Actions 时要求每份报告为 CI runner;本地诊断保留 local 来源,不代表远端验收。独立调用纯函数 `evaluateCandidate` 时须显式传入 `{ baselines, requireCi, mainlineRequired }`;CLI 自动读取源码基线和 `runtime/modules.json`。\n\n### 持久化主线候选证据\n\n候选源码中的 fact / permission / audit 任一模块进入 `authority` 或 `e2` 后,必需报告从 11 份增加为 13 份,增加 `mainline-acceptance` 和 `revocation-sla`。模块登记缺失、损坏或状态非法时拒绝候选;不能由 artifact 自报关闭此要求。RC 发布入口读取相同源码策略,不接受只含旧 11 份报告的候选。\n\n主线报告须完整包含事实持久化 11、审计篡改 5、主线/撤权/混沌 11 项;各套件唯一,退出成功,无失败、pending 或 todo。撤权报告至少 20 个正数样本,按样本重算 p95/max 并比对摘要,要求 p95 \u003c 30 秒、max \u003c 60 秒。Grant 撤销通过而就业 Scope 仍待实现时,报告必须显式保持 `partial` 和未验证说明,候选结果保留这项覆盖边界;这不表示 MS-3、真实 HR/OS 接入或生产签收完成。\n\nruntime artifact 兼容旧单目录扁平上传,以及新增仓根报告后的目录结构。只在本次下载目录内读取固定的两种路径,不回退到仓内历史报告;同时发现两份时拒绝。源登记或目录读取失败也覆盖写入不合格候选,防止遗留成功报告。\n\n## 镜像、SBOM 与签名(开发计划 §3A D-1 / D-2;仓根脚本)\n\n| 脚本 | 作用 | 产物 |\n|---|---|---|\n| `pnpm image:build`(`governance/build-image.mjs`) | 用 `runtime/Dockerfile` 构建运行时镜像;默认 `--context head`(`git archive HEAD:runtime`,本机 WIP 不进镜像);私有 registry token 只经 `--secret id=npmrc,src=\u003cnpmrc\u003e`(默认 `~/.npmrc`,`--npmrc` 可指定)进入安装层,不进镜像、不打印 | `reports/image-digest.json`:`digest` = 本机 `--load` 的 image id(`digestKind` 说明;推送后换 registry manifest digest)、`sourceSha` / `worktreeDirty` / `dockerfileTracked` / 平台 / 大小 / 基础镜像 |\n| `pnpm image:sbom`(`governance/sbom.mjs`) | `syft` 或 `docker sbom` 生成完整 SPDX(OS + Node);两者都缺时退到 **lockfile 模式**:从镜像里 deploy 树的 pnpm lock 与工作区包生成只含 Node 依赖的 SPDX 2.3(`sbom.latest.json.scope` 标 partial,Debian 包不在内;完整 SBOM 由 CI image job 的 syft 产出);镜像不可用则退出 3 不写空文件 | `reports/sbom.spdx.json` + 元数据 `reports/sbom.latest.json`(tool / scope / sha256 / 包数) |\n| `pnpm image:sign`(`governance/sign-image.mjs`) | `cosign sign --key $COSIGN_KEY \u003cregistry ref@digest\u003e`;未推送 / 无密钥 / 无 cosign 时明确跳过、退出 0 | `reports/signature.json`(缺失即 Manifest `missing: signature`) |\n\n`release:manifest` 逐项按磁盘判定这三份产物;CI 的 `image` job 在 Secret 配置后产出同名 artifact(不推 registry)。\n\n## 环境晋级记录(开发计划 PF-23;DEC-024 A / DEC-026;仓根脚本)\n\n| 脚本 | 作用 | 产物 |\n|---|---|---|\n| `pnpm promotion:check -- --record \u003crecord.json\u003e [--manifest …] [--template …]`(`governance/check-promotion.mjs`) | 核验一份晋级记录:R1 形状(`stack/promotion/promotion-record.schema.json`)、R2 级序 dev→test→staging→prod(preview←candidate)、R3 同 digest(记录 = 候选 = Manifest 文件 `images.runtime.digest`,prod 禁止 rebuild 由此机器化)、R4 级别门槛(staging:eligible + SBOM + 签名或未过期 waiver;prod:Manifest complete + 签名 + 签收全闭)、R5 必需检查项、R6 审批角色 + 委派(initiator / approvals 的 `actorType`;数字员工须带未过期、TTL ≤ 24h、非自我委托的 delegation 引用——DEC-007 A,缺口 G-8)、R7 回滚演练 ≤ 600 s、R8 preview 上限、R9 签收项在模板内、R10 脏树 Manifest 禁晋级、R11 源提交交叉断言(记录 = Manifest = 制品 `images.runtime.sourceSha`,均 40 位;迁自统一交付平台 FULL_SOURCE_COMMIT_REQUIRED / ARTIFACT_SOURCE_MISMATCH,2026-09-16)、R12 迁移就绪(Manifest 有迁移目录时记录须带 `migrations` 段:expand_migrate_contract / ready / backwardCompatible / rollbackEvidence;迁自 MIGRATION_* 判定) | `reports/promotion.latest.json`(`verdict` APPROVED / APPROVED_WITH_PENDING_SIGNOFFS / REJECTED;REJECTED 退出 1) |\n\n记录模板 `stack/promotion/promotion-record.template.json`,签收模板 `stack/promotion/target-env-signoff.template.json`(P1—P9,取自 OS `target-env-signoff.json`);步骤见 [staging 晋级操作说明](../docs/staging晋级操作说明.md)。纯函数 `evaluatePromotion(record, { schema, manifest, template, today })` 可独立调用(`governance/test/promotion.test.mjs` 32 例)。\n\n## 消费方接入\n\n```bash\npnpm add -D @juhai/governance@1.0.0-rc.1 # exact pin;.npmrc 配 @juhai 作用域到 Gitea registry\npnpm exec juhai-governance ci:template --out .github/workflows/platform-governance.yml\npnpm exec juhai-governance check:pins --require @juhai/contracts --require @juhai/governance\npnpm exec juhai-governance check:fixtures --suite governance/fixtures/contracts.suite.json\n```\n\n夹具套件格式见 `check-fixtures.mjs` 头注;示例 `fixtures/contracts.suite.json`(正例取 `@juhai/contracts` 的 examples,反例故意破坏必填 / 类型 / 血缘字段)。消费者须在自己仓内建立 `governance/fixtures/contracts.suite.json`,按实际安装位置调整 schema / inputFile 路径;模板不再跳过缺失文件。\n\n套件必须有非空且不重复的 id / case id、合法 expect、已声明 schema,以及 input / inputFile 二选一。空套件、缺失 schema、损坏的本地引用、文件读取/解析/模块加载错误会生成 failed 报告并退出 1,覆盖旧的成功报告;规则必须显式返回原因数组,DEC-039 适配器的失败结论不能被重新判为成功。JSON Schema 校验仍是头注声明的子集,不代表完整元 Schema 校验或支持所有关键字。\n\n根 `pnpm check:fixtures` 先构建运行时模块,再显式带 `--allow-unavailable-suite dec-039-party-model`,仅容许独立克隆缺少企业应用工作区时跳过 DEC-039 外部套件,报告 status=partial、保留 unavailable 计数;contracts 与六个模块套件仍必须执行,缺失模块构建产物不会被该豁免放过。全部套件不可用、配置错误和真实用例失败仍阻断。消费者模板使用默认严格模式。`--allow-unavailable` 保留为显式允许所有不可用套件的诊断开关,不用于本仓根门禁。以上增强为仓内新源码,已发布的 `1.0.0-rc.0` 保持不变,本仓已准备 `1.0.0-rc.1`,实际发布及 Registry 安装状态见发布记录。\n\n## 本仓内\n\n`pnpm check`(仓根)已串联:`check:pins` → `check:modules` → `check:module-imports` → `check:catalog` → `catalog:drift` → `check:fixtures` → `check:facts` → `check:migration-decs` → `check:caddy` → governance 测试 → contracts → runtime 静态门禁 → `check:evidence`(放链尾:前面各检查已把自己的报告重绑到当前 HEAD,此时剩下的过期项才是真的没人重跑)。`pnpm check:port-conformance` 独立运行真实端口测试,CI 单独生产证据。`.github/CODEOWNERS` 仍为角色占位,不能把覆盖测试通过解释为真实团队审批已生效。发布走 DEC-031 的固定源码 RC 通道;已发布版本不覆盖,新包代码须使用后续新 RC 版本。\n","repository":{"type":"","url":""}}...
|
0
|
Edit
Delete
|
|
20
|
5
|
5
|
1.0.0-rc.4
|
1.0.0-rc.4
|
1789773219
|
0
|
{"scope":"@juhai","name":& {"scope":"@juhai","name":"client-fact","description":"可信事实受理客户端、事务 Outbox 与幂等 Inbox;Kafka 运输不影响领域契约","license":"UNLICENSED","dependencies":{"@prisma/client":"6.19.3"},"development_dependencies":{"@types/node":"^22.10.2","typescript":"^5.7.2","vitest":"^2.1.8"},"peer_dependencies":{"@juhai/kernel":"0.22.0"},"readme":"# @juhai/client-fact\n\n事实干线(M5)的消费者 SDK:Outbox 投递 + Inbox 幂等/版本/Gap/DLQ 判定 + 可信回查。\n上层只允许 exact pin(`check:pins`),判定语义只在本包,**消费者不得复刻第二份**。\n\n本文记录的是**真实上层接入时踩过的坑**(数字员工基座 `os-employment-projection`,回灌台账 U-29 / U-31 / U-34)。\n平台自己的主线 e2e 用合成宿主表,这些坑在平台侧照不出来。\n\n---\n\n## 1. `baseUrl` 必须包含 `/api` 前缀(U-34)\n\n平台 NestJS 应用 `setGlobalPrefix(\"api\")`,而本包用**相对 URL** 解析端点:\n\n```ts\nnew URL(\"./v1/facts/intents\", baseUrl) // createFactPublisher 内部\n```\n\n因此:\n\n| baseUrl | 实际请求 | 结果 |\n| --- | --- | --- |\n| `https://host/api` | `https://host/api/v1/facts/intents` | ✅ 正确 |\n| `https://host` | `https://host/v1/facts/intents` | ❌ 404 |\n| `https://host/api/` | `https://host/api/v1/facts/intents` | ✅(结尾斜杠会被补齐) |\n\n**为什么这条必须写在契约里**:少写 `/api` 不会显式报错,而是让**所有**回查返回 404。消费者若把 404\n当成\"事实不存在\"交给 `FactInbox`,SDK 会判 `UNTRUSTED_FACT` → 计入毒消息 → 三次进死信。\n一个配置漏字母会把整条摄入变成全量死信,而日志读起来像是\"平台在篡改事实\"。\n\n**消费者必须区分三种情况,不要混进毒消息计数**:\n\n| 情况 | 应有处置 |\n| --- | --- |\n| 回查端点返回 404 | 该 fact 确实不存在 → 交 SDK 判 `UNTRUSTED_FACT`(正当的毒消息) |\n| 回查不可达 / 5xx / 超时 | **抛错**,保留 broker offset 等待恢复;不要返回 null |\n| 未配置回查地址 | **失败关闭**:每次调用都拒绝,绝不\"跳过校验\" |\n\n平台 e2e 里 `baseUrl = http://127.0.0.1:${port}/api` 曾是这条约定唯一的载体(一行测试赋值)。\n\n## 2. 迁移模板只给表,授权与策略绑定由消费者补齐(U-31)\n\n`migrations/001_outbox_inbox.sql` 建五张表并对每张表 `ENABLE + FORCE ROW LEVEL SECURITY`,\n策略为:\n\n```sql\nCREATE POLICY tenant_isolation ON %I\n USING (tenant_id = current_setting('app.current_tenant_id', true))\n WITH CHECK (tenant_id = current_setting('app.current_tenant_id', true));\n```\n\n**模板的两个边界,照抄前必须知道**:\n\n1. **策略没有 `TO \u003crole\u003e` 子句** ⇒ 对 PUBLIC 生效。消费者若有 system / 后台角色需要跨租户扫描\n (补 gap、重放、运维对账),它同样会被这���策略挡住——除非该角色 `BYPASSRLS`,\n 而 `FORCE ROW LEVEL SECURITY` 下表属主也不豁免。\n2. **模板不含任何 `GRANT`**。消费者库若用独立的低权限运行角色(而不是表属主连接),\n 照抄模板后该角色对这五张表**没有任何权限**,摄入会直接失败。\n\n**契约**:表 DDL 逐字照用(列名与主键是 SDK 的 SQL 依赖,改了就对不上);\n`GRANT` 与策略的角色绑定**由消费者按自身角色模型补齐**,作为自己的增量迁移。\n参考实现见数字员工基座的 `20260928010000_platform_client_fact_inbox`(tenant / system 两角色 + 逐表显式 GRANT)。\n\n## 3. 处理结果与 rc.3 的行为变更(U-29)\n\n`FactInbox.handle()` 的返回值:\n\n| 返回 | 含义 |\n| --- | --- |\n| `APPLIED` | 首次应用,投影已写 |\n| `DUPLICATE` | 同 `fact_id` 重投,单次效果(digest 不一致则抛 `PROCESSED_FACT_CONFLICT`) |\n| `STALE` | 版本 ≤ 水位,不写投影 |\n| `GAP` | `previous_version ≠ 水位`,落 gap 缓冲等补齐 |\n\n\u003e **`1.0.0-rc.3` 起的行为变更**:`STALE` 之前**不可达**——版本落后时本包抛\n\u003e `FactRejected(\"UNPROCESSED_VERSION_BEHIND_WATERMARK\")`,而 `handle` 把任何 `FactRejected`\n\u003e 计入 attempts,于是至少一次投递下的**正常迟到重投**三次即被打进死信,与\"内容有毒\"共用一套判据。\n\u003e rc.3 改为返回 `\"STALE\"`,并顺手删掉该 fact 可能留在 gap 缓冲里的副本(落后事实永远等不到\n\u003e `previous_version = 水位`,留着只会把缓冲占满到 `GAP_BUFFER_FULL`,drain 循环也会空转)。\n\u003e\n\u003e 消费 rc.2 及更早版本的上层需要在边界做\"错误码 → 结果词\"的翻译;**升到 rc.3 后应删除该翻译**,\n\u003e 判定回到 SDK 单源。\n\n## 4. 写链边界\n\n`appendFactIntent` 必须在**属主自己的业务事务内**调用——它与业务写同 tx,事务回滚则事实意图一并回滚。\n`FactInbox.handle` 同理在消费者事务内完成 `processed_fact` + 投影 + 水位的原子写入。\n本包不提供事务,也不管理连接:宿主传入符合 `FactTransaction` 结构的 tx 即可(不要求宿主生成 Prisma schema)。\n\n## 5. 可信回查读取器 `createFactReader`(候选)\n\n\u003e 本节为 `3074b75` 引入的读取面文档,原文保留(英文),与上面三节的接入契约互补:\n\u003e 上面讲「接进来会踩什么」,本节讲「读取器本身怎么用、边界在哪」。\n\n```ts\nconst reader = createFactReader({\n baseUrl: \"https://platform.example/api\",\n tenantId,\n token: getConsumerBearer,\n});\nconst inbox = new FactInbox({\n tenantId, consumerId, tenant: consumerTenantTransaction,\n trustedLookup: reader.lookup,\n apply: applyOwnerFact,\n});\n// On shutdown: stop consumer delivery, then reader.close().\n```\n\nThe server binds the verified JWT tenant/application/subject to one enrolled consumer. It checks the persisted consumer's activation and source-domain/fact-type scope on every lookup. `replayAllowed` is not required for point lookups; replay remains a separate operation. The candidate server is enabled only with `PLATFORM_FACT_READ_ENABLED=1` in development/test with JWT, `DATABASE_URL_FACT`, and an exact `FACT_READERS_JSON` list of `{tenantId,appId,subject,consumerId}`. It can run independently of intake and relay. Production/default assembly remains unavailable pending CHG-004 and live service identity integration.\n\nThe reader uses HTTPS (HTTP only on literal loopback/localhost), denies redirects and URL credentials, and bounds token/fetch/body processing to 5 seconds and 128 KiB by default. It verifies tenant/id/ordering/receipt and the canonical submission digest. It does not cache authorization or facts. A typed M5 `FACT_NOT_FOUND` returns null; all other transport/authentication/integrity errors throw `FactReadUnavailable`, which is deliberately distinct from `FactRejected`. Dependency failures must retain the Kafka offset and must not increment poison counters. `close()` aborts active lookups and rejects future ones; callbacks that ignore cancellation may continue internally but cannot produce an accepted lookup.\n\nA deactivated or deleted consumer registration answers 403, which the reader turns into a retryable `FactReadUnavailable`: the Kafka offset is kept and nothing is counted as poison. A registration that is still active but no longer covers the fact's source domain or type answers the same 404 as an unknown id, which is a null lookup and therefore `UNTRUSTED_FACT` — a dead letter. Narrowing `sourceDomain`/`factTypes` on a live consumer will dead-letter facts that are already in flight, while deactivating the same consumer only pauses it. Deactivate first, change scope, then reactivate; treat a scope edit as a migration, not as a switch.\n\nThe server refuses a bearer carried in the query string (`FACT_READ_URL_CREDENTIAL_REFUSED`, 401) even when a valid `Authorization` header is also present, because the token has already reached the proxy access log by then. The reader never produces such a URL; the refusal exists for anything else that calls the surface.\n\nAn authenticated M5 response plus the receipt digest is the trust boundary here, not a cryptographic signature proving the Owner. A compromised M5 authority or whole-row rewrite with a recomputed digest is outside this reader's detection. Kafka self-asserted hashes are never sufficient. Consumers still need the Owner's domain validation, bootstrap watermark reconciliation and appropriate action enforcement.\n","repository":{"type":"","url":""}}...
|
0
|
Edit
Delete
|
|
21
|
3
|
5
|
1.0.0-rc.5
|
1.0.0-rc.5
|
1789775317
|
0
|
{"scope":"@juhai","name":& {"scope":"@juhai","name":"contracts","description":"企业应用群机器契约:Catalog、JSON Schema、OpenAPI、兼容基线与治理 Linter(基础设施仓 contracts/,DEC-010 / DEC-031)","license":"UNLICENSED","dependencies":{"ajv":"8.20.0","ajv-formats":"3.0.1"},"development_dependencies":{"@types/node":"20.19.43","json-schema-to-typescript":"16.0.0","typescript":"5.9.3"},"readme":"# @juhai/contracts(原 platform-contracts 候选控制面)\n\n## 在 enterprise-platform 内的状态(PF-04 阶段 1,2026-09-10)\n\n- **身份**:本目录是原 `platform-contracts/` 候选控制面的带来源登记导入(见 [SOURCE.md](SOURCE.md);来源目录已于 2026-09-16 按 PF-04 阶段 2 物理移除,SOURCE.md 记录的指纹是它最后的状态);包名按 DEC-031 命名修订改为 `@juhai/contracts`,版本 `1.0.0-rc.0`(rc 系列;非 rc `1.0.0` 受 DEC-010 附条件:远端 + Required Check)。`catalogs/`、`contracts/`、`examples/`、`apps/`、`compatibility/` 与来源逐字节一致;`schemas/` 仅含下述 PF-04 的 `causation_id` / `correlation_id` 变更。\n- **工作区根**:Linter、影响图与测试以「工作区根」(`企业应用/`,同时含 `平台治理/基础/` 与 `doc/`)为基准解析 Catalog `directory` / `evidence`、DEC `source` 与各应用仓路径,不再假定包位于工作区根的直接子目录。解析顺序:`--workspace-root \u003cabs\u003e`(`node scripts/check.mjs --workspace-root …`)→ 环境变量 `PLATFORM_CONTRACTS_WORKSPACE_ROOT` → 自动探测(从本目录向上找到首个同时含 `平台治理/基础/` 与 `doc/` 的祖先)。经 `pnpm` 复合脚本运行时请用环境变量(pnpm 只把额外参数附加���最后一条命令)。\n- **独立克隆**(向上没有含 `workspace.json` 的工作区根,例如云端 CI 只 checkout 本仓;2026-09-12):`check:local` 的影响图以 `--workspace-optional` 退化为\"仅包内\"计算并在 stderr 打印 `[WORKSPACE_ROOT_UNRESOLVED]` 提示,不核验 Catalog / AppManifest / 裁决的路径引用;依赖应用仓文件、工作区路径或真实探测结果的 16 个测试显式 `skip`(91 例中 75 例照跑)。`check` 与 `check:impact` 在独立克隆下仍失败关闭(退出码 2),显式 `--workspace-root` / 环境变量不可用时任何模式都失败关闭。\n- **TS 层(CT-1)**:`scripts/schema-registry.mjs` 是 key → Schema 文件 → 类型名的唯一来源;改 Schema 后运行 `pnpm generate` 重生成 `generated/`,`pnpm check:generated`(在 `check:local` 内)在缺失 / 差异 / 多余文件时失败;`pnpm build`(tsc → `dist/`)在 `test` 与 `check:local` 之前自动执行;首次使用需 `pnpm --dir contracts install`(依赖只来自公共 npm,全部 exact pin)。\n- **`pnpm check` 现状**:`check` 报告且仅报告 4 项 `PLATFORM_PROJECT_UNREGISTERED`(`企业控制面/企业搜索与统一检索平台`、`企业控制面/外部连接器与集成平台`、`企业控制面/开发者自助与应用工程平台`、`企业控制面/数据治理与隐私平台`;2026-09-14 迁移后扫描面已换成 `企业控制面/`,G-12 提到的 `平台治理/基础/reports`、`平台治理/基础/tests` 两项假阳性随之消失),全部随 CHG-001(新增基础应用 MachineCatalog 变更)合并后消失;Linter 未被放宽。合并前以 `pnpm check:local`(schema 兼容 + 影响图 + 测试)作为绿色门禁;CHG-001 合并后 `check` 转绿,根 `pnpm check` 再切回完整 `check`。\n- **`causation_id` 可选、`correlation_id` 映射**(设计 §7 / §25 张力 4):`schemas/fact-envelope.v1.schema.json` 的 `required` 去掉 `causation_id`(旅程首条事实没有因果父,省略而非填占位值);`trace_id` = 旅程锚点、`correlation_id` = 业务关联写入 `fact-envelope.v1` 与 `request-context.v1` 的 `description`(后者只加说明)。Linter 新增规则 `FACT_ENVELOPE_FIELD_NOT_OPTIONAL` 防止回退为必填;`test/fact-envelope.test.mjs` 用兼容检查器自身的规则证明该放宽向后兼容(反向则报 `REQUIRED_PROPERTY_ADDED`)。`compatibility/` 冻结基线未动(信封不在基线内)。\n- **消费**:`pnpm add @juhai/contracts@1.0.0-rc.N`(exact pin,`check:pins` 强制);子路径导出 `@juhai/contracts/catalogs/*`、`/schemas/*`、`/contracts/*`、`/examples/*`、`/apps/*`、`/compatibility/*`、`/scripts/*`、`/package.json`;**裸入口(CT-1,2026-09-12)**:`import { validate, validateFact, assertValid, isValid, schemaOf, SCHEMA_KEYS, type FactEnvelopeV1 } from '@juhai/contracts'`——12 个 JSON Schema 的 TypeScript 类型(`generated/`,由 `schemas/` 生成并入库)与 Ajv 2020 校验器(按 key 懒编译;未知 key 抛 `RangeError`;`validateFact` 先验信封再按 `facts/\u003cfact_type\u003e.v\u003cmajor\u003e` 验载荷,未登记载荷 Schema 以 `payloadSchema` 失败关闭);`dist/` 随包发布,运行依赖仅 `ajv` / `ajv-formats`;`test/`、`src/`、`generated/` 不随包发布。\n\n本目录是企业应用群 Git-first 机器契约的 **W1 候选实现**,用于先建立可校验的语义基线。`DEC-010` 尚未裁决 Catalog 的最终物理位置,因此这里的 Registry、AppManifest 和 Schema 均为 `proposed` 或 `draft`,不能作为“能力已上线”的证据。\n\n## 已覆盖\n\n- `Employment` 的唯一 Owner、Canonical ID 目标格式与数据分级,以及企业 IdP 已实现权威模型的目录对账;\n- `FactEnvelope v1` JSON Schema;\n- `EmploymentTransferred v1` Payload JSON Schema;\n- HR、Digital Employee OS、Permission Platform、企业 IdP、执行监管、基础框架、嗨设、巨嗨智服、知识云、设备云、巨嗨报价系统与尤克特拉十二个草案 AppManifest���\n- Fact Producer/Consumer、Projection/Replay 和待裁决 Owner 的静态治理检查;Fact Projection 进一步绑定 Consumer、只读 Authority、状态 Schema、`consumer_name + fact_id` 幂等、Projection + `processed_fact` 原子提交、单调但不连续的聚合版本语义,以及受 Backbone ADR 阻断的消息 Gap 检测;\n- Resource/Action Catalog v1、Actor/Request Context v1 和 Permission Decision API v1 候选契约;\n- DEC-001—032 全量 Decision Catalog 登记(32 approved / 0 pending:2026-09-10 批准 010 / 031 / 032,2026-09-12 决策会批准其余 27 项,013 Broker = Redpanda、008 部分生效、030 分阶段;037—039 待 CHG-002),并校验所有 Catalog 引用的裁决可解析;\n- 权限请求/拒绝样例,强制租户一致、未知资源/动作拒绝、故障关闭和拒绝不正缓存;\n- DEC-012 完整候选 ADR、首条 Fact Schema 的不可变 proposed Snapshot 与保守向后兼容检查器;\n- 从 Catalog + AppManifest 构建的 proposed Producer/Consumer Impact Graph 与变更查询 CLI;\n- `平台治理/基础/` 21 个平台目录的机器项目清单:19 个属于本轮目标,明确排除基础框架与 AI 数字员工;实现状态、代码真源、证据等级和阻塞 DEC 可查询;\n- 可执行的正向检查和 Owner、ADR、Canonical ID、PII、Replay、Consumer、Application Dependency、Permission、Schema Compatibility 负向边界测试。\n\n## 尚未裁决,禁止越权实现\n\n- `Person`、`Organization`、`Store`、`Position`、`Actor` Owner(`DEC-001`—`DEC-005`);\n- AppManifest/ProductManifest 边界、Catalog 物理真源和双 Envelope 边界(`DEC-009`—`DEC-011`,评审材料已形成但尚未批准);\n- Schema 最终组合与兼容策略批准(`DEC-012`);候选检查器只证明当前规则可机械执行,不是正式发布策略;\n- Broker、Topic、Fact Store 与 Ordering(`DEC-013`—`DEC-016`);\n- Scope 执行和权限分工(`DEC-017`—`DEC-019`);\n- 权限平台的引擎、策略存储和运行时技术路线(`DEC-029`)。\n- 尤克特拉身份、设备、客户、订单、执行与通知重名实体的 Owner、映射和迁移方案(`DEC-030`,其中 Store 仍受 `DEC-003` 阻塞)。\n- 平台契约与 SDK 的分发通道、发布包名登记与发布门禁(`DEC-031`);裁决前派生仓 Planner 只能以夹具或标注来源 SHA 的过渡复制形式被业务仓引用,不得冒充平台接入。\n\n因此 Permission Decision API 是可评审、可机械验证的候选边界,不是权限引擎已实现或已上线的声明。Actor Context 仅携带 IdP 已认证的不透明主体标识,不越权裁决 `Actor` 企业 Owner。\n\n`DEC-027/028` 已批准并进入 HR 实现;Linter 仍会阻止草案 Manifest 标记为 `active`,也不允许 `EmploymentTransferred` 越过 `DEC-010/012` 直接激活。\n\n企业 IdP 草案清单已对账其当前 E2 代码中的 Tenant/User、Application/OIDC Client、Credential/Authenticator、Consent、Session、Authorization Code/Grant、Refresh Token Family/Token、Backchannel Delivery 与 Security Event 等权威模型;这仍不代表生产 KMS/HSM、远程 CI 或生产部署已签收。`User` 是 IdP 账户主体,不等同于企业 `Person`(其 Owner 归属由 DEC-001 裁定,2026-09-12 已批准)。嗨设现已真实消费 IdP RS256 access token/JWKS,并登记 `material.production` 候选权限面;它只保存 actor 引用,不拥有 Tenant/User/Session/Grant。执行监管的 Project/Ticket/SLA 仍未进入企业 Entity Catalog。知识云则登记 `KnowledgeCandidate`、`KnowledgeAtom`、`KnowledgeAtomVersion`、`KnowledgeSource` 与 `KnowledgeFeedback` 五个权威对象;`KnowledgeEmbedding`、检索 Evidence 与 AI 推理结果都是可重建派生物,不得冒充企业权威实体。巨嗨报价系统已将当前 Prisma 的 68 个业务模型登记为权威对象,并由测试持续与真实 schema 对账;本地 `User/UserEvent` 及 `Outbox/OutboxReplayEvent` 明确排除,避免抢占 IdP 身份 Owner 或把技术投递记录冒充企业业务实体。尤克特拉只登记已验证的 Express/PostgreSQL 运行时,其 71 个 Prisma 模型中与全局 Catalog 重名的七个对象由 DEC-030 阻断,Fact、统一 Permission、Projection 和权威 Entity 保持空集;这不把本地数据误报成共享真源,也不把单后端误报成双后端。基础框架只作为工程模板登记,不拥有企业业务事实。\n\nPlatform Project Catalog 当前只允许企业 IdP 声明独立服务 `implemented_e2`;通知与 Webhook 中心、公共文件平台及配置与功能开关平台声明 `module_e2`。公共文件已由执行监管、巨嗨报价与嗨设三个真实消费者完成 E2 运行验证;通知投递已由执行监管、巨嗨智服与巨嗨报价三个真实消费者完成 E2 运行验证;配置平台当前只有执行监管一个真实业务消费者,生产无有效批准快照时关闭、坏刷新保留最后良好版本,并把版本/摘要/来源/原因写入 AutomationRun。前三者都不表示 G4 已裁决或独立服务已启动;配置平台尤其仍缺第二、第三消费者。报价本地 `QuotationNotificationIntent` 是技术投递记录,不登记为企业权威实体。应用与契约注册中心、企业事实干线和统一权限平台仅为 `candidate_e0`;其余目标平台仍是 `not_started`。各平台目录内复制的 `base-framework/` 一律不计为平台实现,任何 E2 证据文件都必须真实存在并报告 `passed`。\n\n## 使用\n\n无需安装第三方依赖,Node.js 20+ 即可运行:\n\n```bash\nnpm run check\nnpm test\n```\n\n`check` 校验平台项目目录、目标范围、证据、Schema 引用、Owner、Producer/Consumer、Projection/Replay、幂等/原子提交/版本顺序、权限与 Scope 对账,并对每个已登记 Fact 执行 proposed Snapshot 不可变/版本兼容检查;`test` 证明目录漏登、模板冒充实现、E2 证据未通过、Owner 冲突、Consumer 绑定漂移、Owner 越权、非原子 Projection、错误连续版本假设、Projection PII/来源漂移与不兼容 Schema 会失败。\n\n查询一个 Fact Schema 变更的直接与二跳影响:\n\n```bash\nnpm run impact -- schema schemas/facts/EmploymentTransferred.v1.json 2\n```\n\n输出明确区分节点深度,并列出 Producer、Consumers、Projections、Entity、阻塞 Decision 与相关边;未知目标返回非零退出码,不生成空的“无影响”结果。\n\n## 状态升级规则\n\n只有同时满足以下条件,才能把本目录从候选实现升级为正式真源:\n\n1. `DEC-010` ADR 已批准;\n2. `DEC-012` Schema 表达和兼容策略已批准;\n3. App Owner 对 AppManifest 与真实代码、部署资产完成核验;\n4. CI 使用本 Linter 或其正式替代品阻断冲突;\n5. 运行时证据证明事实生产、消费、幂等与 Replay,而不只是静态文件通过。\n","repository":{"type":"","url":""}}...
|
0
|
Edit
Delete
|
|
22
|
4
|
5
|
1.0.0-rc.5
|
1.0.0-rc.5
|
1789775319
|
0
|
{"scope":"@juhai","name":& {"scope":"@juhai","name":"governance","description":"基础设施层跨仓门禁(设计方案 §9):check:pins(exact pin 消费规则)、check:fixtures(契约正反例夹具)、verify:candidate(候选可晋级核验)、release:manifest(已知事实清单)、CI 模板;零依赖 CLI,供上层仓 exact pin 后在 CI 运行。","license":"UNLICENSED","bin":{"juhai-governance":"bin/cli.mjs"},"readme":"# @juhai/governance — 基础设施跨仓门禁\n\n设计方案 §4.2 / §9 定义的 `governance/` 交付:一组**零依赖**的构建期检查,随基础设施仓同一 Release 版本号发布到 Gitea npm registry(DEC-031),供上层仓 **exact pin** 后在 CI 运行(`check:pins` 为必需检查,DEC-031 附带条款 4)。\n\n## 命令(`juhai-governance \u003ccommand\u003e [--root \u003cdir\u003e]`)\n\n| 命令 | 用途 | 报告 | 退出码 |\n|---|---|---|---|\n| `check:pins [--require \u003cpkg\u003e]…` | 三层:`@juhai/*` 只允许 `x.y.z` / `workspace:*`;**对外发布包**(有 `publishConfig`)的第三方依赖同样只允许 `x.y.z`;其余第三方按 `pins-baseline.json` 的存量登记放行,登记外的新增必须 exact,登记项对应依赖消失则判红。`--require` 要求该包至少一处 exact pin(证明消费者已接入) | 无(stdout) | 1 = 有违规 |\n| `check:port-conformance` | 基础设施仓内独立端口测试:先构建 contracts/modules/clients,再跑 `runtime/test/port`;必须完整通过内核 14、模块 6、客户端 21 例,拒绝跳过与空跑 | `reports/port-conformance.latest.json` | 1 = 构建/测试/覆盖核验失败 |\n| `check:fixtures --suite \u003csuite.json\u003e… [--allow-unavailable-suite \u003cid\u003e]…` | 契约正反例夹具:校验套件配置后,ACCEPT 须零原因、REJECT 须有原因且含声明前缀;缺工作区默认失败,显式允许且有其他用例执行才可 partial | `reports/fixtures.latest.json` | 1 = 配置错误、空跑、不可用或用例不符 |\n| `verify:candidate --candidate \u003cdir\u003e --sha \u003csha\u003e …` | 候选可晋级核验(Q12-C / X12):逐份 required 报告核 sourceSha / dirty / 状态 / 地板 / digest,缺失即不合格 | `\u003cdir\u003e/release-candidate.json` 或 `--out` | 1 = 不合格 |\n| `release:manifest` | 已知事实清单,**逐项按磁盘判定**:`governance/package.json`、`runtime/clients/\u003cm\u003e/package.json`(name 须为 `@juhai/client-\u003cm\u003e`)、`reports/image-digest.json`(`sha256:` 且 `sourceSha` = HEAD)、compose 镜像是否 `@sha256:` 锁定、`reports/sbom.spdx.json`、`reports/signature.json`;任一缺失即 `status=partial` 并写明缺什么,不判定晋级 | `reports/release-manifest.latest.json` | 0 |\n| `ci:template [--out \u003cfile\u003e]` | 输出消费者最小 CI 模板(私包认证 + contracts/governance 必需 exact pin + 必需夹具) | — | 0 |\n| `check:modules` / `check:module-imports` / `check:catalog` / `catalog:drift` | 基础设施仓内部门禁(依赖 `runtime/modules.json` 与 `contracts/catalogs`) | `reports/*.latest.json` | 1 = 违规(drift 默认 0) |\n| `reports:rebind [--gates a,b] [--list] [--dry-run]` | **在 HEAD 的干净检出里重跑零依赖门禁并把报告带回**(偏差 #34-A 裁决实现)。`provenance.worktreeDirty` 由全仓 `git status` 算,而 `check:evidence` 按作用域判过期——口径不一致使得只要任何无关文件脏着就没法回绑任何报告;本工具不改判据,改为换个干净的地方生成。可行前提是 `governance/` 零依赖,临时检出**不需要 pnpm install**。作用域内有未提交输入的门禁会被跳过(否则等于用 HEAD 的结论覆盖当前工作区);目标报告自己在工作区未提交时也跳过(可能是并行会话的在途产物,覆盖即销毁,`--force` 才override);产出若不是「绑 HEAD 且 dirty=false」则拒绝带回。一个门禁可写多份报告(`workbench-snapshots` 两份快照),要么全带回要么一份不带,避免同源报告绑到不同提交。需要构建产物的 `check:fixtures` / `check:port-conformance` 与 runtime / contracts 的检查不在范围,须在装好依赖的检出里跑。 |\n| `check:migration-decs` | 仓纪律 3:`runtime/modules/*/prisma/migrations` 与 `identity/apps/*/prisma/migrations` 的 `migration.sql` 前 10 行须有 `-- decision: DEC-NNN` 且该 DEC 已批准;`state=shape` 模块不得有迁移;例外只能逐个迁移登记在 `migration-decs.exceptions.json`(条件失效判 `EXCEPTION_STALE`) | `reports/migration-decs.latest.json` | 1 = 违规 |\n| `check:facts [--candidates \u003cdir\u003e] [--report-only]` | §6.4:`modules.json` 声明的 Fact ⊆ `contracts/catalogs/facts.json` ∪ CHG-004 候选(候选须 `status: pending-dec` + `blocked_by`);候选目录不可用时报 `UNRESOLVED`(fail-closed)。**接入根 `pnpm check` 前置 CT-2 材料落地** | `reports/facts.latest.json` | 1 = 违规 / unresolved |\n| `check:caddy` | §5 / §7:`modules.json` 的 HTTP 契约经 `caddy-routes.json` 映射前缀后必须被 profiles 段登记的每份 Caddyfile(dev 基线 `stack/caddy/Caddyfile` + staging `Caddyfile.staging`)的 path 匹配器覆盖;tls=required 的 profile 另守 `TLS_DISABLED` / `TLS_HOST_MISSING` / `TLS_ISSUER_MISSING` / `HSTS_MISSING` / `PLAINTEXT_SITE_FORBIDDEN`(2026-09-16);`/healthz`、`X-Request-Id` 注入、`{$PLATFORM_API_UPSTREAM}` 必备;本机有 `caddy` 则 `caddy validate`,否则报告 `validate: skipped`(`CHECK_CADDY_DOCKER=1` 走 docker) | `reports/caddy.latest.json` | 1 = 违规 / 语法失败 |\n| `check:otel` | §5 / §15 采纳形态:`stack/otel/collector.yaml` 与登记真源 `otel-attributes.json` 逐项一致(三条 pipeline 的 processor、keep_keys allowlist、属性上限 / 时间有效性 / 产生端名单);2026-09-16 起另守告警规则——`stack/otel/prometheus.yaml` 的 `rule_files` 含登记 glob,`stack/otel/rules/*.yaml` 每条规则有 for / labels.severity / annotations.summary / annotations.runbook,expr 指标带选择器且在 alerts.metrics 登记(登记 = 有实测产生端;没有产生端的写 alerts.pending);本机有 `promtool` 则校验语法,`CHECK_OTEL_DOCKER=1` 用 compose 锁定的 prometheus 镜像跑,否则报告 `skipped` | `reports/otel.latest.json` | 1 = 违规 / promtool 失败 |\n| `check:evidence [--read-only] [--json]` | 检查报告绑定提交到 HEAD 的作用域差异,以及暂存、未暂存、删除、未跟踪输入。静态报告按 error 阻断,运行验收沿用登记的 warn;无关改动不影响。分别统计 fresh / stale / worktreeChanged / invalid / exempted,例外不计新鲜;存在 warn 或豁免时为 partial,退出 0 不代表完整验收。**未登记的报告也要逐条记账**(2026-09-18):`SCOPE_UNDECLARED` 是 info、不拦任何东西,于是「未登记」这一类可以无声增长,而它恰恰是本门禁完全看不见的那部分(当时 48 份报告里 13 份在此)。现由 `evidence-scopes.json` 的 `undeclared` 逐条写明 class / reason / recordedAt / resolveBy,五类取值 self / aggregate / provenance-missing / one-off-snapshot / no-generator;报告存在却既无作用域又无账 = `UNDECLARED_UNACCOUNTED` 判红,账指向的报告已登记或已消失 = `UNDECLARED_STALE` 判红,字段残缺或 class 非法 = `UNDECLARED_INCOMPLETE` 判红。记账**不是豁免**:no-generator 与 one-off-snapshot 的出口只有「补生成脚本后转正式登记」或「退役该报告」二选一。`--read-only` 不改报告,`--json` 只输出 JSON | `reports/evidence-freshness.latest.json`(只读模式不写) | 1 = error;0 = passed 或 partial,须读取 status / counts |\n| `check:gate-flow [--read-only] [--json]` | **每个门禁的失败信号有谁在看?**(2026-09-18 新增)治理层 2026-09-14 为自己建了 `门禁消费登记.json` 逐条回答这个问题,本仓一直没问过。实测根 `package.json` 44 个脚本里 12 个既不在 `pnpm check` 链、CI 也不调用,其中三个是真门禁——`image:smoke`(**CI 的 image job 构建镜像、生成 SBOM、签名,却从不启动它一次**,而开发计划把这六项冒烟写成 D-1 的退出条件)、`promotion:check`(事件驱动)、`check:deployed`(要 docker 与在跑的底座)。三个各有理由,但理由只散在 CLAUDE.md / README 的散文里、没有复核期。**消费关系一律自动推导,不接受声明**:从 `check` 链递归展开,再对两份 CI 工作流按脚本名与脚本里的 `.mjs` 路径现取(CI 有几处绕开 pnpm 直接 `node governance/…`)。`governance/gate-flow.json` 因此只装推不出来的那些,随接线逐条变少,也不能无声变多。F1 无人消费且未登记;F2 登记已腐烂(脚本没了 / 已被消费 / 重名);F3 流外门禁缺 reason 或 wireInWhen;F4 缺 `conditionReviewBy` 或已过期;F5 role 非法。F4 守日期不守条件——接入条件多半含人的判断,能机器化的只有「必须有人按期回来看一眼」。 | `reports/gate-flow.latest.json`(只读模式不写) | 1 = 有违规;0 = 通过 |\n| `check:ci-mirror [--read-only] [--json]` | **两条 CI 通道是不是真的同步**(2026-09-18 新增)。`CLAUDE.md` 与镜像文件自己的头注释都写着「`.gitea/workflows/platform.yml` 是 `.github` 版的镜像副本,只差四处,两份必须同步改」,而实测**没有任何东西在比对它们**。剥掉整行注释与空行、按 `governance/ci-mirror.json` 把镜像还原成主干形态之后,两份 461 行逐行相同——文件层面的差异恰好三类(镜像头注释块、artifact v3↔v4、一行 `GOV_REPORT_RUNNER`)。M1 声明之外的差异;M2 声明了却已不存在(声明不许腐烂);M3 声明缺 id 或 reason。只剥**整行**注释:行尾注释可能跟在真命令后面,剥掉会让门禁漏判。**值得有执行者的理由不是洁癖**:那行 `GOV_REPORT_RUNNER: gitea-actions` 是证据来源标注的唯一保证——act_runner 为兼容会设 `GITHUB_ACTIONS=true`,不显式覆盖,本通道产出的报告会把自己标成 github-actions 并被 `verify-candidate` 当作 CI 证据接受,一次漏同步就是一次冒充。**未决口径**见声明里的 `openDiscrepancy`:头注释宣称的差异③『fork 判定改用 `gitea.*` 上下文』**在文件里根本不存在**,两份的 fork 守卫逐字相同、全是 `github.*`;是声称做了没做还是当初判断错了,归 SRE / 框架 Owner,本门禁不替人裁决。 | `reports/ci-mirror.latest.json`(只读模式不写) | 1 = 有违规;0 = 通过 |\n| `check:deployed`(仓根脚本,不在发布 CLI 命令集) | 核对固定镜像源提交、当前 HEAD 的运行时输入、目标容器镜像及环境键。运行时有变更但镜像未构建、容器未换、无目标容器、缺源提交或脏镜像均阻断;仅治理/文档/报告变化无需重建。未提交运行时输入与缺环境键单列为 partial。默认只读,`--write-report` 才写报告;不接触业务数据 | 可选 `reports/deployed-runtime.latest.json` | 1 = 部署未满足;2 = Docker 不可用;0 = passed / partial |\n\n`catalog:drift --workspace-root \u003c工作区根\u003e` 支持独立检出指向真实工作区,也支持 `PLATFORM_CONTRACTS_WORKSPACE_ROOT`;显式路径无效时拒绝执行,自动探测不到时才保留 unknown。\n\nCatalog 对账分别处理实现状态与证据等级:`authority` 表示权威持久化实现,不自动要求或授予 E2;`candidate_e0` 可保留并记录待签收信息。只有模块明确声明 `e2` 时,才要求与 Catalog 的 `implemented_e2` 对账。不得为了消除差异自动升级 Catalog。\n\n所有报告带 `provenance`(`gitSha` / `worktreeDirty` / `runner` 原值 / `runnerNormalized` / `runId`);`worktreeDirty` 忽略 latest 报告本身。\n\nG-7 的 `port-conformance` job 保留同仓 PR 的私包认证约束,不访问数据库。每次执行使用新的临时 Vitest JSON;构建失败、测试失败或没有新报告时覆盖旧成功状态为 failed。三组逐文件地板在 `lib/port-conformance.mjs`,新增套件须同步更新覆盖清单。candidate 依赖该 job 成功,且十一份 required 报告中必须含同源码、干净工作树的端口报告;旧十份报告不能用于新版本候选。发布门禁沿用相同的源码必需报告策略。此门禁证明端口一致性,不提升模块 shape 状态。\n\n`verify:candidate` 在候选源码工作树的根目录运行:从 `runtime/reports/baseline.json` 与 `identity/reports/baseline.json` 读取最低测试数量,不能用 artifact 自报的较低地板代替。报告须为对象,验收计数与地板须为正整数,治理报告须含固定必需指标且为零;缺失、`null`、数组、标量和显式 `PARTIAL` 状态均不合格。旧治理报告没有 `status` 字段时仍按必需指标核验。指定 `--run-id` 或运行于 GitHub Actions 时要求每份报告为 CI runner;本地诊断保留 local 来源,不代表远端验收。独立调用纯函数 `evaluateCandidate` 时须显式传入 `{ baselines, requireCi, mainlineRequired }`;CLI 自动读取源码基线和 `runtime/modules.json`。\n\n### 持久化主线候选证据\n\n候选源码中的 fact / permission / audit 任一模块进入 `authority` 或 `e2` 后,必需报告从 11 份增加为 13 份,增加 `mainline-acceptance` 和 `revocation-sla`。模块登记缺失、损坏或状态非法时拒绝候选;不能由 artifact 自报关闭此要求。RC 发布入口读取相同源码策略,不接受只含旧 11 份报告的候选。\n\n主线报告须完整包含事实持久化 11、审计篡改 5、主线/撤权/混沌 11 项;各套件唯一,退出成功,无失败、pending 或 todo。撤权报告至少 20 个正数样本,按样本重算 p95/max 并比对摘要,要求 p95 \u003c 30 秒、max \u003c 60 秒。Grant 撤销通过而就业 Scope 仍待实现时,报告必须显式保持 `partial` 和未验证说明,候选结果保留这项覆盖边界;这不表示 MS-3、真实 HR/OS 接入或生产签收完成。\n\nruntime artifact 兼容旧单目录扁平上传,以及新增仓根报告后的目录结构。只在本次下载目录内读取固定的两种路径,不回退到仓内历史报告;同时发现两份时拒绝。源登记或目录读取失败也覆盖写入不合格候选,防止遗留成功报告。\n\n## 镜像、SBOM 与签名(开发计划 §3A D-1 / D-2;仓根脚本)\n\n| 脚本 | 作用 | 产物 |\n|---|---|---|\n| `pnpm image:build`(`governance/build-image.mjs`) | 用 `runtime/Dockerfile` 构建运行时镜像;默认 `--context head`(`git archive HEAD:runtime`,本机 WIP 不进镜像);私有 registry token 只经 `--secret id=npmrc,src=\u003cnpmrc\u003e`(默认 `~/.npmrc`,`--npmrc` 可指定)进入安装层,不进镜像、不打印 | `reports/image-digest.json`:`digest` = 本机 `--load` 的 image id(`digestKind` 说明;推送后换 registry manifest digest)、`sourceSha` / `worktreeDirty` / `dockerfileTracked` / 平台 / 大小 / 基础镜像 |\n| `pnpm image:sbom`(`governance/sbom.mjs`) | `syft` 或 `docker sbom` 生成完整 SPDX(OS + Node);两者都缺时退到 **lockfile 模式**:从镜像里 deploy 树的 pnpm lock 与工作区包生成只含 Node 依赖的 SPDX 2.3(`sbom.latest.json.scope` 标 partial,Debian 包不在内;完整 SBOM 由 CI image job 的 syft 产出);镜像不可用则退出 3 不写空文件 | `reports/sbom.spdx.json` + 元数据 `reports/sbom.latest.json`(tool / scope / sha256 / 包数) |\n| `pnpm image:sign`(`governance/sign-image.mjs`) | `cosign sign --key $COSIGN_KEY \u003cregistry ref@digest\u003e`;未推送 / 无密钥 / 无 cosign 时明确跳过、退出 0 | `reports/signature.json`(缺失即 Manifest `missing: signature`) |\n\n`release:manifest` 逐项按磁盘判定这三份产物;CI 的 `image` job 在 Secret 配置后产出同名 artifact(不推 registry)。\n\n## 环境晋级记录(开发计划 PF-23;DEC-024 A / DEC-026;仓根脚本)\n\n| 脚本 | 作用 | 产物 |\n|---|---|---|\n| `pnpm promotion:check -- --record \u003crecord.json\u003e [--manifest …] [--template …]`(`governance/check-promotion.mjs`) | 核验一份晋级记录:R1 形状(`stack/promotion/promotion-record.schema.json`)、R2 级序 dev→test→staging→prod(preview←candidate)、R3 同 digest(记录 = 候选 = Manifest 文件 `images.runtime.digest`,prod 禁止 rebuild 由此机器化)、R4 级别门槛(staging:eligible + SBOM + 签名或未过期 waiver;prod:Manifest complete + 签名 + 签收全闭)、R5 必需检查项、R6 审批角色 + 委派(initiator / approvals 的 `actorType`;数字员工须带未过期、TTL ≤ 24h、非自我委托的 delegation 引用——DEC-007 A,缺口 G-8)、R7 回滚演练 ≤ 600 s、R8 preview 上限、R9 签收项在模板内、R10 脏树 Manifest 禁晋级、R11 源提交交叉断言(记录 = Manifest = 制品 `images.runtime.sourceSha`,均 40 位;迁自统一交付平台 FULL_SOURCE_COMMIT_REQUIRED / ARTIFACT_SOURCE_MISMATCH,2026-09-16)、R12 迁移就绪(Manifest 有迁移目录时记录须带 `migrations` 段:expand_migrate_contract / ready / backwardCompatible / rollbackEvidence;迁自 MIGRATION_* 判定) | `reports/promotion.latest.json`(`verdict` APPROVED / APPROVED_WITH_PENDING_SIGNOFFS / REJECTED;REJECTED 退出 1) |\n\n记录模板 `stack/promotion/promotion-record.template.json`,签收模板 `stack/promotion/target-env-signoff.template.json`(P1—P9,取自 OS `target-env-signoff.json`);步骤见 [staging 晋级操作说明](../docs/staging晋级操作说明.md)。纯函数 `evaluatePromotion(record, { schema, manifest, template, today })` 可独立调用(`governance/test/promotion.test.mjs` 32 例)。\n\n## 消费方接入\n\n```bash\npnpm add -D @juhai/governance@1.0.0-rc.1 # exact pin;.npmrc 配 @juhai 作用域到 Gitea registry\npnpm exec juhai-governance ci:template --out .github/workflows/platform-governance.yml\npnpm exec juhai-governance check:pins --require @juhai/contracts --require @juhai/governance\npnpm exec juhai-governance check:fixtures --suite governance/fixtures/contracts.suite.json\n```\n\n夹具套件格式见 `check-fixtures.mjs` 头注;示例 `fixtures/contracts.suite.json`(正例取 `@juhai/contracts` 的 examples,反例故意破坏必填 / 类型 / 血缘字段)。消费者须在自己仓内建立 `governance/fixtures/contracts.suite.json`,按实际安装位置调整 schema / inputFile 路径;模板不再跳过缺失文件。\n\n套件必须有非空且不重复的 id / case id、合法 expect、已声明 schema,以及 input / inputFile 二选一。空套件、缺失 schema、损坏的本地引用、文件读取/解析/模块加载错误会生成 failed 报告并退出 1,覆盖旧的成功报告;规则必须显式返回原因数组,DEC-039 适配器的失败结论不能被重新判为成功。JSON Schema 校验仍是头注声明的子集,不代表完整元 Schema 校验或支持所有关键字。\n\n根 `pnpm check:fixtures` 先构建运行时模块,再显式带 `--allow-unavailable-suite dec-039-party-model`,仅容许独立克隆缺少企业应用工作区时跳过 DEC-039 外部套件,报告 status=partial、保留 unavailable 计数;contracts 与六个模块套件仍必须执行,缺失模块构建产物不会被该豁免放过。全部套件不可用、配置错误和真实用例失败仍阻断。消费者模板使用默认严格模式。`--allow-unavailable` 保留为显式允许所有不可用套件的诊断开关,不用于本仓根门禁。以上增强为仓内新源码,已发布的 `1.0.0-rc.0` 保持不变,本仓已准备 `1.0.0-rc.1`,实际发布及 Registry 安装状态见发布记录。\n\n## 本仓内\n\n`pnpm check`(仓根)已串联:`check:pins` → `check:modules` → `check:module-imports` → `check:catalog` → `catalog:drift` → `check:fixtures` → `check:facts` → `check:migration-decs` → `check:caddy` → governance 测试 → contracts → runtime 静态门禁 → `check:evidence`(放链尾:前面各检查已把自己的报告重绑到当前 HEAD,此时剩下的过期项才是真的没人重跑)。`pnpm check:port-conformance` 独立运行真实端口测试,CI 单独生产证据。`.github/CODEOWNERS` 仍为角色占位,不能把覆盖测试通过解释为真实团队审批已生效。发布走 DEC-031 的固定源码 RC 通道;已发布版本不覆盖,新包代码须使用后续新 RC 版本。\n","repository":{"type":"","url":""}}...
|
0
|
Edit
Delete
|
|
23
|
5
|
5
|
1.0.0-rc.5
|
1.0.0-rc.5
|
1789775329
|
0
|
{"scope":"@juhai","name":& {"scope":"@juhai","name":"client-fact","description":"可信事实受理客户端、事务 Outbox 与幂等 Inbox;Kafka 运输不影响领域契约","license":"UNLICENSED","dependencies":{"@prisma/client":"6.19.3"},"development_dependencies":{"@types/node":"22.19.20","typescript":"5.9.3","vitest":"2.1.9"},"peer_dependencies":{"@juhai/kernel":"0.22.0"},"readme":"# @juhai/client-fact\n\n事实干线(M5)的消费者 SDK:Outbox 投递 + Inbox 幂等/版本/Gap/DLQ 判定 + 可信回查。\n上层只允许 exact pin(`check:pins`),判定语义只在本包,**消费者不得复刻第二份**。\n\n本文记录的是**真实上层接入时踩过的坑**(数字员工基座 `os-employment-projection`,回灌台账 U-29 / U-31 / U-34)。\n平台自己的主线 e2e 用合成宿主表,这些坑在平台侧照不出来。\n\n---\n\n## 1. `baseUrl` 必须包含 `/api` 前缀(U-34)\n\n平台 NestJS 应用 `setGlobalPrefix(\"api\")`,而本包用**相对 URL** 解析端点:\n\n```ts\nnew URL(\"./v1/facts/intents\", baseUrl) // createFactPublisher 内部\n```\n\n因此:\n\n| baseUrl | 实际请求 | 结果 |\n| --- | --- | --- |\n| `https://host/api` | `https://host/api/v1/facts/intents` | ✅ 正确 |\n| `https://host` | `https://host/v1/facts/intents` | ❌ 404 |\n| `https://host/api/` | `https://host/api/v1/facts/intents` | ✅(结尾斜杠会被补齐) |\n\n**为什么这条必须写在契约里**:少写 `/api` 不会显式报错,而是让**所有**回查返回 404。消费者若把 404\n当成\"事实不存在\"交给 `FactInbox`,SDK 会判 `UNTRUSTED_FACT` → 计入毒消息 → 三次进死信。\n一个配置漏字母会把整条摄入变成全量死信,而日志读起来像是\"平台在篡改事实\"。\n\n**消费者必须区分三种情况,不要混进毒消息计数**:\n\n| 情况 | 应有处置 |\n| --- | --- |\n| 回查端点返回 404 | 该 fact 确实不存在 → 交 SDK 判 `UNTRUSTED_FACT`(正当的毒消息) |\n| 回查不可达 / 5xx / 超时 | **抛错**,保留 broker offset 等待恢复;不要返回 null |\n| 未配置回查地址 | **失败关闭**:每次调用都拒绝,绝不\"跳过校验\" |\n\n平台 e2e 里 `baseUrl = http://127.0.0.1:${port}/api` 曾是这条约定唯一的载体(一行测试赋值)。\n\n## 2. 迁移模板只给表,授权与策略绑定由消费者补齐(U-31)\n\n`migrations/001_outbox_inbox.sql` 建五张表并对每张表 `ENABLE + FORCE ROW LEVEL SECURITY`,\n策略为:\n\n```sql\nCREATE POLICY tenant_isolation ON %I\n USING (tenant_id = current_setting('app.current_tenant_id', true))\n WITH CHECK (tenant_id = current_setting('app.current_tenant_id', true));\n```\n\n**模板的两个边界,照抄前必须知道**:\n\n1. **策略没有 `TO \u003crole\u003e` 子句** ⇒ 对 PUBLIC 生效。消费者若有 system / 后台角色需要跨租户扫描\n (补 gap、重放、运维对账),它同样会被这条���略挡住——除非该角色 `BYPASSRLS`,\n 而 `FORCE ROW LEVEL SECURITY` 下表属主也不豁免。\n2. **模板不含任何 `GRANT`**。消费者库若用独立的低权限运行角色(而不是表属主连接),\n 照抄模板后该角色对这五张表**没有任何权限**,摄入会直接失败。\n\n**契约**:表 DDL 逐字照用(列名与主键是 SDK 的 SQL 依赖,改了就对不上);\n`GRANT` 与策略的角色绑定**由消费者按自身角色模型补齐**,作为自己的增量迁移。\n参考实现见数字员工基座的 `20260928010000_platform_client_fact_inbox`(tenant / system 两角色 + 逐表显式 GRANT)。\n\n## 3. 处理结果与 rc.3 的行为变更(U-29)\n\n`FactInbox.handle()` 的返回值:\n\n| 返回 | 含义 |\n| --- | --- |\n| `APPLIED` | 首次应用,投影已写 |\n| `DUPLICATE` | 同 `fact_id` 重投,单次效果(digest 不一致则抛 `PROCESSED_FACT_CONFLICT`) |\n| `STALE` | 版本 ≤ 水位,不写投影 |\n| `GAP` | `previous_version ≠ 水位`,落 gap 缓冲等补齐 |\n\n\u003e **`1.0.0-rc.3` 起的行为变更**:`STALE` 之前**不可达**——版本落后时本包抛\n\u003e `FactRejected(\"UNPROCESSED_VERSION_BEHIND_WATERMARK\")`,而 `handle` 把任何 `FactRejected`\n\u003e 计入 attempts,于是至少一次投递下的**正常迟到重投**三次即被打进死信,与\"内容有毒\"共用一套判据。\n\u003e rc.3 改为返回 `\"STALE\"`,并顺手删掉该 fact 可能留在 gap 缓冲里的副本(落后事实永远等不到\n\u003e `previous_version = 水位`,留着只会把缓冲占满到 `GAP_BUFFER_FULL`,drain 循环也会空转)。\n\u003e\n\u003e 消费 rc.2 及更早版本的上层需要在边界做\"错误码 → 结果词\"的翻译;**升到 rc.3 后应删除该翻译**,\n\u003e 判定回到 SDK 单源。\n\n## 4. 写链边界\n\n`appendFactIntent` 必须在**属主自己的业务事务内**调用——它与业务写同 tx,事务回滚则事实意图一并回滚。\n`FactInbox.handle` 同理在消费者事务内完成 `processed_fact` + 投影 + 水位的原子写入。\n本包不提供事务,也不管理连接:宿主传入符合 `FactTransaction` 结构的 tx 即可(不要求宿主生成 Prisma schema)。\n\n## 5. 可信回查读取器 `createFactReader`(候选)\n\n\u003e 本节为 `3074b75` 引入的读取面文档,原文保留(英文),与上面三节的接入契约互补:\n\u003e 上面讲「接进来会踩什么」,本节讲「读取器本身怎么用、边界在哪」。\n\n```ts\nconst reader = createFactReader({\n baseUrl: \"https://platform.example/api\",\n tenantId,\n token: getConsumerBearer,\n});\nconst inbox = new FactInbox({\n tenantId, consumerId, tenant: consumerTenantTransaction,\n trustedLookup: reader.lookup,\n apply: applyOwnerFact,\n});\n// On shutdown: stop consumer delivery, then reader.close().\n```\n\nThe server binds the verified JWT tenant/application/subject to one enrolled consumer. It checks the persisted consumer's activation and source-domain/fact-type scope on every lookup. `replayAllowed` is not required for point lookups; replay remains a separate operation. The candidate server is enabled only with `PLATFORM_FACT_READ_ENABLED=1` in development/test with JWT, `DATABASE_URL_FACT`, and an exact `FACT_READERS_JSON` list of `{tenantId,appId,subject,consumerId}`. It can run independently of intake and relay. Production/default assembly remains unavailable pending CHG-004 and live service identity integration.\n\nThe reader uses HTTPS (HTTP only on literal loopback/localhost), denies redirects and URL credentials, and bounds token/fetch/body processing to 5 seconds and 128 KiB by default. It verifies tenant/id/ordering/receipt and the canonical submission digest. It does not cache authorization or facts. A typed M5 `FACT_NOT_FOUND` returns null; all other transport/authentication/integrity errors throw `FactReadUnavailable`, which is deliberately distinct from `FactRejected`. Dependency failures must retain the Kafka offset and must not increment poison counters. `close()` aborts active lookups and rejects future ones; callbacks that ignore cancellation may continue internally but cannot produce an accepted lookup.\n\nA deactivated or deleted consumer registration answers 403, which the reader turns into a retryable `FactReadUnavailable`: the Kafka offset is kept and nothing is counted as poison. A registration that is still active but no longer covers the fact's source domain or type answers the same 404 as an unknown id, which is a null lookup and therefore `UNTRUSTED_FACT` — a dead letter. Narrowing `sourceDomain`/`factTypes` on a live consumer will dead-letter facts that are already in flight, while deactivating the same consumer only pauses it. Deactivate first, change scope, then reactivate; treat a scope edit as a migration, not as a switch.\n\nThe server refuses a bearer carried in the query string (`FACT_READ_URL_CREDENTIAL_REFUSED`, 401) even when a valid `Authorization` header is also present, because the token has already reached the proxy access log by then. The reader never produces such a URL; the refusal exists for anything else that calls the surface.\n\nAn authenticated M5 response plus the receipt digest is the trust boundary here, not a cryptographic signature proving the Owner. A compromised M5 authority or whole-row rewrite with a recomputed digest is outside this reader's detection. Kafka self-asserted hashes are never sufficient. Consumers still need the Owner's domain validation, bootstrap watermark reconciliation and appropriate action enforcement.\n","repository":{"type":"","url":""}}...
|
0
|
Edit
Delete
|
|
24
|
3
|
5
|
1.0.0-rc.6
|
1.0.0-rc.6
|
1789775910
|
0
|
{"scope":"@juhai","name":& {"scope":"@juhai","name":"contracts","description":"企业应用群机器契约:Catalog、JSON Schema、OpenAPI、兼容基线与治理 Linter(基础设施仓 contracts/,DEC-010 / DEC-031)","license":"UNLICENSED","dependencies":{"ajv":"8.20.0","ajv-formats":"3.0.1"},"development_dependencies":{"@types/node":"20.19.43","json-schema-to-typescript":"16.0.0","typescript":"5.9.3"},"readme":"# @juhai/contracts(原 platform-contracts 候选控制面)\n\n## 在 enterprise-platform 内的状态(PF-04 阶段 1,2026-09-10)\n\n- **身份**:本目录是原 `platform-contracts/` 候选控制面的带来源登记导入(见 [SOURCE.md](SOURCE.md);来源目录已于 2026-09-16 按 PF-04 阶段 2 物理移除,SOURCE.md 记录的指纹是它最后的状态);包名按 DEC-031 命名修订改为 `@juhai/contracts`,版本 `1.0.0-rc.0`(rc 系列;非 rc `1.0.0` 受 DEC-010 附条件:远端 + Required Check)。`catalogs/`、`contracts/`、`examples/`、`apps/`、`compatibility/` 与来源逐字节一致;`schemas/` 仅含下述 PF-04 的 `causation_id` / `correlation_id` 变更。\n- **工作区根**:Linter、影响图与测试以「工作区根」(`企业应用/`,同时含 `平台治理/基础/` 与 `doc/`)为基准解析 Catalog `directory` / `evidence`、DEC `source` 与各应用仓路径,不再假定包位于工作区根的直接子目录。解析顺序:`--workspace-root \u003cabs\u003e`(`node scripts/check.mjs --workspace-root …`)→ 环境变量 `PLATFORM_CONTRACTS_WORKSPACE_ROOT` → 自动探测(从本目录向上找到首个同时含 `平台治理/基础/` 与 `doc/` 的祖先)。经 `pnpm` 复合脚本运行时请用环境变量(pnpm 只把额外参数附加���最后一条命令)。\n- **独立克隆**(向上没有含 `workspace.json` 的工作区根,例如云端 CI 只 checkout 本仓;2026-09-12):`check:local` 的影响图以 `--workspace-optional` 退化为\"仅包内\"计算并在 stderr 打印 `[WORKSPACE_ROOT_UNRESOLVED]` 提示,不核验 Catalog / AppManifest / 裁决的路径引用;依赖应用仓文件、工作区路径或真实探测结果的 16 个测试显式 `skip`(91 例中 75 例照跑)。`check` 与 `check:impact` 在独立克隆下仍失败关闭(退出码 2),显式 `--workspace-root` / 环境变量不可用时任何模式都失败关闭。\n- **TS 层(CT-1)**:`scripts/schema-registry.mjs` 是 key → Schema 文件 → 类型名的唯一来源;改 Schema 后运行 `pnpm generate` 重生成 `generated/`,`pnpm check:generated`(在 `check:local` 内)在缺失 / 差异 / 多余文件时失败;`pnpm build`(tsc → `dist/`)在 `test` 与 `check:local` 之前自动执行;首次使用需 `pnpm --dir contracts install`(依赖只来自公共 npm,全部 exact pin)。\n- **`pnpm check` 现状**:`check` 报告且仅报告 4 项 `PLATFORM_PROJECT_UNREGISTERED`(`企业控制面/企业搜索与统一检索平台`、`企业控制面/外部连接器与集成平台`、`企业控制面/开发者自助与应用工程平台`、`企业控制面/数据治理与隐私平台`;2026-09-14 迁移后扫描面已换成 `企业控制面/`,G-12 提到的 `平台治理/基础/reports`、`平台治理/基础/tests` 两项假阳性随之消失),全部随 CHG-001(新增基础应用 MachineCatalog 变更)合并后消失;Linter 未被放宽。合并前以 `pnpm check:local`(schema 兼容 + 影响图 + 测试)作为绿色门禁;CHG-001 合并后 `check` 转绿,根 `pnpm check` 再切回完整 `check`。\n- **`causation_id` 可选、`correlation_id` 映射**(设计 §7 / §25 张力 4):`schemas/fact-envelope.v1.schema.json` 的 `required` 去掉 `causation_id`(旅程首条事实没有因果父,省略而非填占位值);`trace_id` = 旅程锚点、`correlation_id` = 业务关联写入 `fact-envelope.v1` 与 `request-context.v1` 的 `description`(后者只加说明)。Linter 新增规则 `FACT_ENVELOPE_FIELD_NOT_OPTIONAL` 防止回退为必填;`test/fact-envelope.test.mjs` 用兼容检查器自身的规则证明该放宽向后兼容(反向则报 `REQUIRED_PROPERTY_ADDED`)。`compatibility/` 冻结基线未动(信封不在基线内)。\n- **消费**:`pnpm add @juhai/contracts@1.0.0-rc.N`(exact pin,`check:pins` 强制);子路径导出 `@juhai/contracts/catalogs/*`、`/schemas/*`、`/contracts/*`、`/examples/*`、`/apps/*`、`/compatibility/*`、`/scripts/*`、`/package.json`;**裸入口(CT-1,2026-09-12)**:`import { validate, validateFact, assertValid, isValid, schemaOf, SCHEMA_KEYS, type FactEnvelopeV1 } from '@juhai/contracts'`——12 个 JSON Schema 的 TypeScript 类型(`generated/`,由 `schemas/` 生成并入库)与 Ajv 2020 校验器(按 key 懒编译;未知 key 抛 `RangeError`;`validateFact` 先验信封再按 `facts/\u003cfact_type\u003e.v\u003cmajor\u003e` 验载荷,未登记载荷 Schema 以 `payloadSchema` 失败关闭);`dist/` 随包发布,运行依赖仅 `ajv` / `ajv-formats`;`test/`、`src/`、`generated/` 不随包发布。\n\n本目录是企业应用群 Git-first 机器契约的 **W1 候选实现**,用于先建立可校验的语义基线。`DEC-010` 尚未裁决 Catalog 的最终物理位置,因此这里的 Registry、AppManifest 和 Schema 均为 `proposed` 或 `draft`,不能作为“能力已上线”的证据。\n\n## 已覆盖\n\n- `Employment` 的唯一 Owner、Canonical ID 目标格式与数据分级,以及企业 IdP 已实现权威模型的目录对账;\n- `FactEnvelope v1` JSON Schema;\n- `EmploymentTransferred v1` Payload JSON Schema;\n- HR、Digital Employee OS、Permission Platform、企业 IdP、执行监管、基础框架、嗨设、巨嗨智服、知识云、设备云、巨嗨报价系统与尤克特拉十二个草案 AppManifest���\n- Fact Producer/Consumer、Projection/Replay 和待裁决 Owner 的静态治理检查;Fact Projection 进一步绑定 Consumer、只读 Authority、状态 Schema、`consumer_name + fact_id` 幂等、Projection + `processed_fact` 原子提交、单调但不连续的聚合版本语义,以及受 Backbone ADR 阻断的消息 Gap 检测;\n- Resource/Action Catalog v1、Actor/Request Context v1 和 Permission Decision API v1 候选契约;\n- DEC-001—032 全量 Decision Catalog 登记(32 approved / 0 pending:2026-09-10 批准 010 / 031 / 032,2026-09-12 决策会批准其余 27 项,013 Broker = Redpanda、008 部分生效、030 分阶段;037—039 待 CHG-002),并校验所有 Catalog 引用的裁决可解析;\n- 权限请求/拒绝样例,强制租户一致、未知资源/动作拒绝、故障关闭和拒绝不正缓存;\n- DEC-012 完整候选 ADR、首条 Fact Schema 的不可变 proposed Snapshot 与保守向后兼容检查器;\n- 从 Catalog + AppManifest 构建的 proposed Producer/Consumer Impact Graph 与变更查询 CLI;\n- `平台治理/基础/` 21 个平台目录的机器项目清单:19 个属于本轮目标,明确排除基础框架与 AI 数字员工;实现状态、代码真源、证据等级和阻塞 DEC 可查询;\n- 可执行的正向检查和 Owner、ADR、Canonical ID、PII、Replay、Consumer、Application Dependency、Permission、Schema Compatibility 负向边界测试。\n\n## 尚未裁决,禁止越权实现\n\n- `Person`、`Organization`、`Store`、`Position`、`Actor` Owner(`DEC-001`—`DEC-005`);\n- AppManifest/ProductManifest 边界、Catalog 物理真源和双 Envelope 边界(`DEC-009`—`DEC-011`,评审材料已形成但尚未批准);\n- Schema 最终组合与兼容策略批准(`DEC-012`);候选检查器只证明当前规则可机械执行,不是正式发布策略;\n- Broker、Topic、Fact Store 与 Ordering(`DEC-013`—`DEC-016`);\n- Scope 执行和权限分工(`DEC-017`—`DEC-019`);\n- 权限平台的引擎、策略存储和运行时技术路线(`DEC-029`)。\n- 尤克特拉身份、设备、客户、订单、执行与通知重名实体的 Owner、映射和迁移方案(`DEC-030`,其中 Store 仍受 `DEC-003` 阻塞)。\n- 平台契约与 SDK 的分发通道、发布包名登记与发布门禁(`DEC-031`);裁决前派生仓 Planner 只能以夹具或标注来源 SHA 的过渡复制形式被业务仓引用,不得冒充平台接入。\n\n因此 Permission Decision API 是可评审、可机械验证的候选边界,不是权限引擎已实现或已上线的声明。Actor Context 仅携带 IdP 已认证的不透明主体标识,不越权裁决 `Actor` 企业 Owner。\n\n`DEC-027/028` 已批准并进入 HR 实现;Linter 仍会阻止草案 Manifest 标记为 `active`,也不允许 `EmploymentTransferred` 越过 `DEC-010/012` 直接激活。\n\n企业 IdP 草案清单已对账其当前 E2 代码中的 Tenant/User、Application/OIDC Client、Credential/Authenticator、Consent、Session、Authorization Code/Grant、Refresh Token Family/Token、Backchannel Delivery 与 Security Event 等权威模型;这仍不代表生产 KMS/HSM、远程 CI 或生产部署已签收。`User` 是 IdP 账户主体,不等同于企业 `Person`(其 Owner 归属由 DEC-001 裁定,2026-09-12 已批准)。嗨设现已真实消费 IdP RS256 access token/JWKS,并登记 `material.production` 候选权限面;它只保存 actor 引用,不拥有 Tenant/User/Session/Grant。执行监管的 Project/Ticket/SLA 仍未进入企业 Entity Catalog。知识云则登记 `KnowledgeCandidate`、`KnowledgeAtom`、`KnowledgeAtomVersion`、`KnowledgeSource` 与 `KnowledgeFeedback` 五个权威对象;`KnowledgeEmbedding`、检索 Evidence 与 AI 推理结果都是可重建派生物,不得冒充企业权威实体。巨嗨报价系统已将当前 Prisma 的 68 个业务模型登记为权威对象,并由测试持续与真实 schema 对账;本地 `User/UserEvent` 及 `Outbox/OutboxReplayEvent` 明确排除,避免抢占 IdP 身份 Owner 或把技术投递记录冒充企业业务实体。尤克特拉只登记已验证的 Express/PostgreSQL 运行时,其 71 个 Prisma 模型中与全局 Catalog 重名的七个对象由 DEC-030 阻断,Fact、统一 Permission、Projection 和权威 Entity 保持空集;这不把本地数据误报成共享真源,也不把单后端误报成双后端。基础框架只作为工程模板登记,不拥有企业业务事实。\n\nPlatform Project Catalog 当前只允许企业 IdP 声明独立服务 `implemented_e2`;通知与 Webhook 中心、公共文件平台及配置与功能开关平台声明 `module_e2`。公共文件已由执行监管、巨嗨报价与嗨设三个真实消费者完成 E2 运行验证;通知投递已由执行监管、巨嗨智服与巨嗨报价三个真实消费者完成 E2 运行验证;配置平台当前只有执行监管一个真实业务消费者,生产无有效批准快照时关闭、坏刷新保留最后良好版本,并把版本/摘要/来源/原因写入 AutomationRun。前三者都不表示 G4 已裁决或独立服务已启动;配置平台尤其仍缺第二、第三消费者。报价本地 `QuotationNotificationIntent` 是技术投递记录,不登记为企业权威实体。应用与契约注册中心、企业事实干线和统一权限平台仅为 `candidate_e0`;其余目标平台仍是 `not_started`。各平台目录内复制的 `base-framework/` 一律不计为平台实现,任何 E2 证据文件都必须真实存在并报告 `passed`。\n\n## 使用\n\n无需安装第三方依赖,Node.js 20+ 即可运行:\n\n```bash\nnpm run check\nnpm test\n```\n\n`check` 校验平台项目目录、目标范围、证据、Schema 引用、Owner、Producer/Consumer、Projection/Replay、幂等/原子提交/版本顺序、权限与 Scope 对账,并对每个已登记 Fact 执行 proposed Snapshot 不可变/版本兼容检查;`test` 证明目录漏登、模板冒充实现、E2 证据未通过、Owner 冲突、Consumer 绑定漂移、Owner 越权、非原子 Projection、错误连续版本假设、Projection PII/来源漂移与不兼容 Schema 会失败。\n\n查询一个 Fact Schema 变更的直接与二跳影响:\n\n```bash\nnpm run impact -- schema schemas/facts/EmploymentTransferred.v1.json 2\n```\n\n输出明确区分节点深度,并列出 Producer、Consumers、Projections、Entity、阻塞 Decision 与相关边;未知目标返回非零退出码,不生成空的“无影响”结果。\n\n## 状态升级规则\n\n只有同时满足以下条件,才能把本目录从候选实现升级为正式真源:\n\n1. `DEC-010` ADR 已批准;\n2. `DEC-012` Schema 表达和兼容策略已批准;\n3. App Owner 对 AppManifest 与真实代码、部署资产完成核验;\n4. CI 使用本 Linter 或其正式替代品阻断冲突;\n5. 运行时证据证明事实生产、消费、幂等与 Replay,而不只是静态文件通过。\n","repository":{"type":"","url":""}}...
|
136
|
Edit
Delete
|
|
25
|
4
|
5
|
1.0.0-rc.6
|
1.0.0-rc.6
|
1789775912
|
0
|
{"scope":"@juhai","name":& {"scope":"@juhai","name":"governance","description":"基础设施层跨仓门禁(设计方案 §9):check:pins(exact pin 消费规则)、check:fixtures(契约正反例夹具)、verify:candidate(候选可晋级核验)、release:manifest(已知事实清单)、CI 模板;零依赖 CLI,供上层仓 exact pin 后在 CI 运行。","license":"UNLICENSED","bin":{"juhai-governance":"bin/cli.mjs"},"readme":"# @juhai/governance — 基础设施跨仓门禁\n\n设计方案 §4.2 / §9 定义的 `governance/` 交付:一组**零依赖**的构建期检查,随基础设施仓同一 Release 版本号发布到 Gitea npm registry(DEC-031),供上层仓 **exact pin** 后在 CI 运行(`check:pins` 为必需检查,DEC-031 附带条款 4)。\n\n## 命令(`juhai-governance \u003ccommand\u003e [--root \u003cdir\u003e]`)\n\n| 命令 | 用途 | 报告 | 退出码 |\n|---|---|---|---|\n| `check:pins [--require \u003cpkg\u003e]…` | 三层:`@juhai/*` 只允许 `x.y.z` / `workspace:*`;**对外发布包**(有 `publishConfig`)的第三方依赖同样只允许 `x.y.z`;其余第三方按 `pins-baseline.json` 的存量登记放行,登记外的新增必须 exact,登记项对应依赖消失则判红。`--require` 要求该包至少一处 exact pin(证明消费者已接入) | 无(stdout) | 1 = 有违规 |\n| `check:port-conformance` | 基础设施仓内独立端口测试:先构建 contracts/modules/clients,再跑 `runtime/test/port`;必须完整通过内核 14、模块 6、客户端 21 例,拒绝跳过与空跑 | `reports/port-conformance.latest.json` | 1 = 构建/测试/覆盖核验失败 |\n| `check:fixtures --suite \u003csuite.json\u003e… [--allow-unavailable-suite \u003cid\u003e]…` | 契约正反例夹具:校验���件配置后,ACCEPT 须零原因、REJECT 须有原因且含声明前缀;缺工作区默认失败,显式允许且有其他用例执行才可 partial | `reports/fixtures.latest.json` | 1 = 配置错误、空跑、不可用或用例不符 |\n| `verify:candidate --candidate \u003cdir\u003e --sha \u003csha\u003e …` | 候选可晋级核验(Q12-C / X12):逐份 required 报告核 sourceSha / dirty / 状态 / 地板 / digest,缺失即不合格 | `\u003cdir\u003e/release-candidate.json` 或 `--out` | 1 = 不合格 |\n| `release:manifest` | 已知事实清单,**逐项按磁盘判定**:`governance/package.json`、`runtime/clients/\u003cm\u003e/package.json`(name 须为 `@juhai/client-\u003cm\u003e`)、`reports/image-digest.json`(`sha256:` 且 `sourceSha` = HEAD)、compose 镜像是否 `@sha256:` 锁定、`reports/sbom.spdx.json`、`reports/signature.json`;任一缺失即 `status=partial` 并写明缺什么,不判定晋级 | `reports/release-manifest.latest.json` | 0 |\n| `ci:template [--out \u003cfile\u003e]` | 输出消费者最小 CI 模板(私包认证 + contracts/governance 必需 exact pin + 必需夹具) | — | 0 |\n| `check:modules` / `check:module-imports` / `check:catalog` / `catalog:drift` | 基础设施仓内部门禁(依赖 `runtime/modules.json` 与 `contracts/catalogs`) | `reports/*.latest.json` | 1 = 违规(drift 默认 0) |\n| `reports:rebind [--gates a,b] [--list] [--dry-run]` | **在 HEAD 的干净检出里重跑零依赖门禁并把报告带回**(偏差 #34-A 裁决实现)。`provenance.worktreeDirty` 由全仓 `git status` 算,而 `check:evidence` 按作用域判过期——口径不一致使得只要任何无关文件脏着就没法回绑任何报告;本工具不改判据,改为换个干净的地方生成。可行前提是 `governance/` 零依赖,临时检出**不需要 pnpm install**。作用域内有未提交输入的门禁会被跳过(否则等于用 HEAD 的结论覆盖当前工作区);目标报告自己在工作区未提交时也跳过(可能是并行会话的在途产物,覆盖即销毁,`--force` 才override);产出若不是「绑 HEAD 且 dirty=false」则拒绝带回。一个门禁可写多份报告(`workbench-snapshots` 两份快照),要么全带回要么一份不带,避免同源报告绑到不同提交。需要构建产物的 `check:fixtures` / `check:port-conformance` 与 runtime / contracts 的检查不在范围,须在装好依赖的检出里跑。 |\n| `check:migration-decs` | 仓纪律 3:`runtime/modules/*/prisma/migrations` 与 `identity/apps/*/prisma/migrations` 的 `migration.sql` 前 10 行须有 `-- decision: DEC-NNN` 且该 DEC 已批准;`state=shape` 模块不得有迁移;例外只能逐个迁移登记在 `migration-decs.exceptions.json`(条件失效判 `EXCEPTION_STALE`) | `reports/migration-decs.latest.json` | 1 = 违规 |\n| `check:facts [--candidates \u003cdir\u003e] [--report-only]` | §6.4:`modules.json` 声明的 Fact ⊆ `contracts/catalogs/facts.json` ∪ CHG-004 候选(候选须 `status: pending-dec` + `blocked_by`);候选目录不可用时报 `UNRESOLVED`(fail-closed)。**接入根 `pnpm check` 前置 CT-2 材料落地** | `reports/facts.latest.json` | 1 = 违规 / unresolved |\n| `check:fact-pii [--dir \u003c目录\u003e]…` | Fact payload 禁止复制 PII:字段名命中 PII 模式、或存在开放结构(缺 `properties` / 未禁 `additionalProperties`)即判红;自由文本字段只登账不判红。判据来自 `fact-pii-rules.json`(仓内同名文件优先,否则用包自带的);`--dir` 指定 Fact schema 目录,缺省是 `contracts/schemas/facts` 与 `contracts/candidates/facts` | `reports/fact-pii.latest.json` | 1 = 有违规 |\n| `check:caddy` | §5 / §7:`modules.json` 的 HTTP 契约经 `caddy-routes.json` 映射前缀后必须被 profiles 段登记的每份 Caddyfile(dev 基线 `stack/caddy/Caddyfile` + staging `Caddyfile.staging`)的 path 匹配器覆盖;tls=required 的 profile 另守 `TLS_DISABLED` / `TLS_HOST_MISSING` / `TLS_ISSUER_MISSING` / `HSTS_MISSING` / `PLAINTEXT_SITE_FORBIDDEN`(2026-09-16);`/healthz`、`X-Request-Id` 注入、`{$PLATFORM_API_UPSTREAM}` 必备;本机有 `caddy` 则 `caddy validate`,否则报告 `validate: skipped`(`CHECK_CADDY_DOCKER=1` 走 docker) | `reports/caddy.latest.json` | 1 = 违规 / 语法失败 |\n| `check:otel` | §5 / §15 采纳形态:`stack/otel/collector.yaml` 与登记真源 `otel-attributes.json` 逐项一致(三条 pipeline 的 processor、keep_keys allowlist、属性上限 / 时间有效性 / 产生端名单);2026-09-16 起另守告警规则——`stack/otel/prometheus.yaml` 的 `rule_files` 含登记 glob,`stack/otel/rules/*.yaml` 每条规则有 for / labels.severity / annotations.summary / annotations.runbook,expr 指标带选择器且在 alerts.metrics 登记(登记 = 有实测产生端;没有产生端的写 alerts.pending);本机有 `promtool` 则校验语法,`CHECK_OTEL_DOCKER=1` 用 compose 锁定的 prometheus 镜像跑,否则报告 `skipped` | `reports/otel.latest.json` | 1 = 违规 / promtool 失败 |\n| `check:evidence [--read-only] [--json]` | 检查报告绑定提交到 HEAD 的作用域差异,以及暂存、未暂存、删除、未跟踪输入。静态报告按 error 阻断,运行验收沿用登记的 warn;无关改动不影响。分别统计 fresh / stale / worktreeChanged / invalid / exempted,例外不计新鲜;存在 warn 或豁免时为 partial,退出 0 不代表完整验收。**未登记的报告也要逐条记账**(2026-09-18):`SCOPE_UNDECLARED` 是 info、不拦任何东西,于是「未登记」这一类可以无声增长,而它恰恰是本门禁完全看不见的那部分(当时 48 份报告里 13 份在此)。现由 `evidence-scopes.json` 的 `undeclared` 逐条写明 class / reason / recordedAt / resolveBy,五类取值 self / aggregate / provenance-missing / one-off-snapshot / no-generator;报告存在却既无作用域又无账 = `UNDECLARED_UNACCOUNTED` 判红,账指向的报告已登记或已消失 = `UNDECLARED_STALE` 判红,字段残缺或 class 非法 = `UNDECLARED_INCOMPLETE` 判红。记账**不是豁免**:no-generator 与 one-off-snapshot 的出口只有「补生成脚本后转正式登记」或「退役该报告」二选一。`--read-only` 不改报告,`--json` 只输出 JSON | `reports/evidence-freshness.latest.json`(只读模式不写) | 1 = error;0 = passed 或 partial,须读取 status / counts |\n| `check:gate-flow [--read-only] [--json]` | **每个门禁的失败信号有谁在看?**(2026-09-18 新增)治理层 2026-09-14 为自己建了 `门禁消费登记.json` 逐条回答这个问题,本仓一直没问过。实测根 `package.json` 44 个脚本里 12 个既不在 `pnpm check` 链、CI 也不调用,其中三个是真门禁——`image:smoke`(**CI 的 image job 构建镜像、生成 SBOM、签名,却从不启动它一次**,而开发计划把这六项冒烟写成 D-1 的退出条件)、`promotion:check`(事件驱动)、`check:deployed`(要 docker 与在跑的底座)。三个各有理由,但理由只散在 CLAUDE.md / README 的散文里、没有复核期。**消费关系一律自动推导,不接受声明**:从 `check` 链递归展开,再对两份 CI 工作流按脚本名与脚本里的 `.mjs` 路径现取(CI 有几处绕开 pnpm 直接 `node governance/…`)。`governance/gate-flow.json` 因此只装推不出来的那些,随接线逐条变少,也不能无声变多。F1 无人消费且未登记;F2 登记已腐烂(脚本没了 / 已被消费 / 重名);F3 流外门禁缺 reason 或 wireInWhen;F4 缺 `conditionReviewBy` 或已过期;F5 role 非法。F4 守日期不守条件——接入条件多半含人的判断,能机器化的只有「必须有人按期回来看一眼」。 | `reports/gate-flow.latest.json`(只读模式不写) | 1 = 有违规;0 = 通过 |\n| `check:ci-mirror [--read-only] [--json]` | **两条 CI 通道是不是真的同步**(2026-09-18 新增)。`CLAUDE.md` 与镜像文件自己的头注释都写着「`.gitea/workflows/platform.yml` 是 `.github` 版的镜像副本,只差四处,���份必须同步改」,而实测**没有任何东西在比对它们**。剥掉整行注释与空行、按 `governance/ci-mirror.json` 把镜像还原成主干形态之后,两份 461 行逐行相同——文件层面的差异恰好三类(镜像头注释块、artifact v3↔v4、一行 `GOV_REPORT_RUNNER`)。M1 声明之外的差异;M2 声明了却已不存在(声明不许腐烂);M3 声明缺 id 或 reason。只剥**整行**注释:行尾注释可能跟在真命令后面,剥掉会让门禁漏判。**值得有执行者的理由不是洁癖**:那行 `GOV_REPORT_RUNNER: gitea-actions` 是证据来源标注的唯一保证——act_runner 为兼容会设 `GITHUB_ACTIONS=true`,不显式覆盖,本通道产出的报告会把自己标成 github-actions 并被 `verify-candidate` 当作 CI 证据接受,一次漏同步就是一次冒充。**未决口径**见声明里的 `openDiscrepancy`:头注释宣称的差异③『fork 判定改用 `gitea.*` 上下文』**在文件里根本不存在**,两份的 fork 守卫逐字相同、全是 `github.*`;是声称做了没做还是当初判断错了,归 SRE / 框架 Owner,本门禁不替人裁决。 | `reports/ci-mirror.latest.json`(只读模式不写) | 1 = 有违规;0 = 通过 |\n| `check:deployed`(仓根脚本,不在发布 CLI 命令集) | 核对固定镜像源提交、当前 HEAD 的运行时输入、目标容器镜像及环境键。运行时有变更但镜像未构建、容器未换、无目标容器、缺源提交或脏镜像均阻断;仅治理/文档/报告变化无需重建。未提交运行时输入与缺环境键单列为 partial。默认只读,`--write-report` 才写报告;不接触业务数据 | 可选 `reports/deployed-runtime.latest.json` | 1 = 部署未满足;2 = Docker 不可用;0 = passed / partial |\n\n`catalog:drift --workspace-root \u003c工作区根\u003e` 支持独立检出指向真实工作区,也支持 `PLATFORM_CONTRACTS_WORKSPACE_ROOT`;显式路径无效时拒绝执行,自动探测不到时才保留 unknown。\n\nCatalog 对账分别处理实现状态与证据等级:`authority` 表示权威持久化实现,不自动要求或授予 E2;`candidate_e0` 可保留并记录待签收信息。只有模块明确声明 `e2` 时,才要求与 Catalog 的 `implemented_e2` 对账。不得为了消除差异自动升级 Catalog。\n\n所有报告带 `provenance`(`gitSha` / `worktreeDirty` / `runner` 原值 / `runnerNormalized` / `runId`);`worktreeDirty` 忽略 latest 报告本身。\n\nG-7 的 `port-conformance` job 保留同仓 PR 的私包认证约束,不访问数据库。每次执行使用新的临时 Vitest JSON;构建失败、测试失败或没有新报告时覆盖旧成功状态为 failed。三组逐文件地板在 `lib/port-conformance.mjs`,新增套件须同步更新覆盖清单。candidate 依赖该 job 成功,且十一份 required 报告中必须含同源码、干净工作树的端口报告;旧十份报告不能用于新版本候选。发布门禁沿用相同的源码必需报告策略。此门禁证明端口一致性,不提升模块 shape 状态。\n\n`verify:candidate` 在候选源码工作树的根目录运行:从 `runtime/reports/baseline.json` 与 `identity/reports/baseline.json` 读取最低测试数量,不能用 artifact 自报的较低地板代替。报告须为对象,验收计数与地板须为正整数,治理报告须含固定必需指标且为零;缺失、`null`、数组、标量和显式 `PARTIAL` 状态均不合格。旧治理报告没有 `status` 字段时仍按必需指标核验。指定 `--run-id` 或运行于 GitHub Actions 时要求每份报告为 CI runner;本地诊断保留 local 来源,不代表远端验收。独立调用纯函数 `evaluateCandidate` 时须显式传入 `{ baselines, requireCi, mainlineRequired }`;CLI 自动读取源码基线和 `runtime/modules.json`。\n\n### 持久化主线候选证据\n\n候选源码中的 fact / permission / audit 任一模块进入 `authority` 或 `e2` 后,必需报告从 11 份增加为 13 份,增加 `mainline-acceptance` 和 `revocation-sla`。模块登记缺失、损坏或状态非法时拒绝候选;不能由 artifact 自报关闭此要求。RC 发布入口读取相同源码策略,不接受只含旧 11 份报告的候选。\n\n主线报告须完整包含事实持久化 11、审计篡改 5、主线/撤权/混沌 11 项;各套件唯一,退出成功,无失败、pending 或 todo。撤权报告至少 20 个正数样本,按样本重算 p95/max 并比对摘要,要求 p95 \u003c 30 秒、max \u003c 60 秒。Grant 撤销通过而就业 Scope 仍待实现时,报告必须显式保持 `partial` 和未验证说明,候选结果保留这项覆盖边界;这不表示 MS-3、真实 HR/OS 接入或生产签收完成。\n\nruntime artifact 兼容旧单目录扁平上传,以及新增仓根报告后的目录结构。只在本次下载目录内读取固定的两种路径,不回退到仓内历史报告;同时发现两份时拒绝。源登记或目录读取失败也覆盖写入不合格候选,防止遗留成功报告。\n\n## 镜像、SBOM 与签名(开发计划 §3A D-1 / D-2;仓根脚本)\n\n| 脚本 | 作用 | 产物 |\n|---|---|---|\n| `pnpm image:build`(`governance/build-image.mjs`) | 用 `runtime/Dockerfile` 构建运行时镜像;默认 `--context head`(`git archive HEAD:runtime`,本机 WIP 不进镜像);私有 registry token 只经 `--secret id=npmrc,src=\u003cnpmrc\u003e`(默认 `~/.npmrc`,`--npmrc` 可指定)进入安装层,不进镜像、不打印 | `reports/image-digest.json`:`digest` = 本机 `--load` 的 image id(`digestKind` 说明;推送后换 registry manifest digest)、`sourceSha` / `worktreeDirty` / `dockerfileTracked` / 平台 / 大小 / 基础镜像 |\n| `pnpm image:sbom`(`governance/sbom.mjs`) | `syft` 或 `docker sbom` 生成完整 SPDX(OS + Node);两者都缺时退到 **lockfile 模式**:从镜像里 deploy 树的 pnpm lock 与工作区包生成只含 Node 依赖的 SPDX 2.3(`sbom.latest.json.scope` 标 partial,Debian 包不在内;完整 SBOM 由 CI image job 的 syft 产出);镜像不可用则退出 3 不写空文件 | `reports/sbom.spdx.json` + 元数据 `reports/sbom.latest.json`(tool / scope / sha256 / 包数) |\n| `pnpm image:sign`(`governance/sign-image.mjs`) | `cosign sign --key $COSIGN_KEY \u003cregistry ref@digest\u003e`;未推送 / 无密钥 / 无 cosign 时明确跳过、退出 0 | `reports/signature.json`(缺失即 Manifest `missing: signature`) |\n\n`release:manifest` 逐项按磁盘判定这三份产物;CI 的 `image` job 在 Secret 配置后产出同名 artifact(不推 registry)。\n\n## 环境晋级记录(开发计划 PF-23;DEC-024 A / DEC-026;仓根脚本)\n\n| 脚本 | 作用 | 产物 |\n|---|---|---|\n| `pnpm promotion:check -- --record \u003crecord.json\u003e [--manifest …] [--template …]`(`governance/check-promotion.mjs`) | 核验一份晋级记录:R1 形状(`stack/promotion/promotion-record.schema.json`)、R2 级序 dev→test→staging→prod(preview←candidate)、R3 同 digest(记录 = 候选 = Manifest 文件 `images.runtime.digest`,prod 禁止 rebuild 由此机器化)、R4 级别门槛(staging:eligible + SBOM + 签名或未过期 waiver;prod:Manifest complete + 签名 + 签收全闭)、R5 必需检查项、R6 审批角色 + 委派(initiator / approvals 的 `actorType`;数字员工须带未过期、TTL ≤ 24h、非自我委托的 delegation 引用——DEC-007 A,缺口 G-8)、R7 回滚演练 ≤ 600 s、R8 preview 上限、R9 签收项在模板内、R10 脏树 Manifest 禁晋级、R11 源提交交叉断言(记录 = Manifest = 制品 `images.runtime.sourceSha`,均 40 位;迁自统一交付平台 FULL_SOURCE_COMMIT_REQUIRED / ARTIFACT_SOURCE_MISMATCH,2026-09-16)、R12 迁移就绪(Manifest 有迁移目录时记录须带 `migrations` 段:expand_migrate_contract / ready / backwardCompatible / rollbackEvidence;迁自 MIGRATION_* 判定) | `reports/promotion.latest.json`(`verdict` APPROVED / APPROVED_WITH_PENDING_SIGNOFFS / REJECTED;REJECTED 退出 1) |\n\n记录模板 `stack/promotion/promotion-record.template.json`,签收模板 `stack/promotion/target-env-signoff.template.json`(P1—P9,取自 OS `target-env-signoff.json`);步骤见 [staging 晋级操作说明](../docs/staging晋级操作说明.md)。纯函数 `evaluatePromotion(record, { schema, manifest, template, today })` 可独立调用(`governance/test/promotion.test.mjs` 32 例)。\n\n## 消费方接入\n\n```bash\npnpm add -D @juhai/governance@1.0.0-rc.1 # exact pin;.npmrc 配 @juhai 作用域到 Gitea registry\npnpm exec juhai-governance ci:template --out .github/workflows/platform-governance.yml\npnpm exec juhai-governance check:pins --require @juhai/contracts --require @juhai/governance\npnpm exec juhai-governance check:fixtures --suite governance/fixtures/contracts.suite.json\n```\n\n夹具套件格式见 `check-fixtures.mjs` 头注;示例 `fixtures/contracts.suite.json`(正例取 `@juhai/contracts` 的 examples,反例故意破坏必填 / 类型 / 血缘字段)。消费者须在自己仓内建立 `governance/fixtures/contracts.suite.json`,按实际安装位置调整 schema / inputFile 路径;模板不再跳过缺失文件。\n\n套件必须有非空且不重复的 id / case id、合法 expect、已声明 schema,以及 input / inputFile 二选一。空套件、缺失 schema、损坏的本地引用、文件读取/解析/模块加载错误会生成 failed 报告并退出 1,覆盖旧的成功报告;规则必须显式返回原因数组,DEC-039 适配器的失败结论不能被重新判为成功。JSON Schema 校验仍是头注声明的子集,不代表完整元 Schema 校验或支持所有关键字。\n\n根 `pnpm check:fixtures` 先构建运行时模块,再显式带 `--allow-unavailable-suite dec-039-party-model`,仅容许独立克隆缺少企业应用工作区时跳过 DEC-039 外部套件,报告 status=partial、保留 unavailable 计数;contracts 与六个模块套件仍必须执行,缺失模块构建产物不会被该豁免放过。全部套件不可用、配置错误和真实用例失败仍阻断。消费者模板使用默认严格模式。`--allow-unavailable` 保留为显式允许所有不可用套件的诊断开关,不用于本仓根门禁。以上增强为仓内新源码,已发布的 `1.0.0-rc.0` 保持不变,本仓已准备 `1.0.0-rc.1`,实际发布及 Registry 安装状态见发布记录。\n\n## 本仓内\n\n`pnpm check`(仓根)已串联:`check:pins` → `check:modules` → `check:module-imports` → `check:catalog` → `catalog:drift` → `check:fixtures` → `check:facts` → `check:fact-pii` → `check:migration-decs` → `check:caddy` → governance 测试 → contracts → runtime 静态门禁 → `check:evidence`(放链尾:前面各检查已把自己的报告重绑到当前 HEAD,此时剩下的过期项才是真的没人重跑)。`pnpm check:port-conformance` 独立运行真实端口测试,CI 单独生产证据。`.github/CODEOWNERS` 仍为角色占位,不能把覆盖测试通过解释为真实团队审批已生效。发布走 DEC-031 的固定源码 RC 通道;已发布版本不覆盖,新包代码须使用后续新 RC 版本。\n","repository":{"type":"","url":""}}...
|
0
|
Edit
Delete
|
|
26
|
5
|
5
|
1.0.0-rc.6
|
1.0.0-rc.6
|
1789775914
|
0
|
{"scope":"@juhai","name":& {"scope":"@juhai","name":"client-fact","description":"可信事实受理客户端、事务 Outbox 与幂等 Inbox;Kafka 运输不影响领域契约","license":"UNLICENSED","dependencies":{"@prisma/client":"6.19.3"},"development_dependencies":{"@types/node":"22.19.20","typescript":"5.9.3","vitest":"2.1.9"},"peer_dependencies":{"@juhai/kernel":"0.22.0"},"readme":"# @juhai/client-fact\n\n事实干线(M5)的消费者 SDK:Outbox 投递 + Inbox 幂等/版本/Gap/DLQ 判定 + 可信回查。\n上层只允许 exact pin(`check:pins`),判定语义只在本包,**消费者不得复刻第二份**。\n\n本文记录的是**真实上层接入时踩过的坑**(数字员工基座 `os-employment-projection`,回灌台账 U-29 / U-31 / U-34)。\n平台自己的主线 e2e 用合成宿主表,这些坑在平台侧照不出来。\n\n---\n\n## 1. `baseUrl` 必须包含 `/api` 前缀(U-34)\n\n平台 NestJS 应用 `setGlobalPrefix(\"api\")`,而本包用**相对 URL** 解析端点:\n\n```ts\nnew URL(\"./v1/facts/intents\", baseUrl) // createFactPublisher 内部\n```\n\n因此:\n\n| baseUrl | 实际请求 | 结果 |\n| --- | --- | --- |\n| `https://host/api` | `https://host/api/v1/facts/intents` | ✅ 正确 |\n| `https://host` | `https://host/v1/facts/intents` | ❌ 404 |\n| `https://host/api/` | `https://host/api/v1/facts/intents` | ✅(结尾斜杠会被补齐) |\n\n**为什么这条必须写在契约里**:少写 `/api` 不会显式报错,而是让**所有**回查返回 404。消费者若把 404\n当成\"事实不存在\"交给 `FactInbox`,SDK 会判 `UNTRUSTED_FACT` → 计入毒消息 → 三次进死信。\n一个配置漏字母会把整条摄入变成全量死信,而日志读起来像是\"平台在篡改事实\"。\n\n**消费者必须区分三种情况,不要混进毒消息计数**:\n\n| 情况 | 应有处置 |\n| --- | --- |\n| 回查端点返回 404 | 该 fact 确实不存在 → 交 SDK 判 `UNTRUSTED_FACT`(正当的毒消息) |\n| 回查不可达 / 5xx / 超时 | **抛错**,保留 broker offset 等待恢复;不要返回 null |\n| 未配置回查地址 | **失败关闭**:每次调用都拒绝,绝不\"跳过校验\" |\n\n平台 e2e 里 `baseUrl = http://127.0.0.1:${port}/api` 曾是这条约定唯一的载体(一行测试赋值)。\n\n## 2. 迁移模板只给表,授权与策略绑定由消费者补齐(U-31)\n\n`migrations/001_outbox_inbox.sql` 建五张表并对每张表 `ENABLE + FORCE ROW LEVEL SECURITY`,\n策略为:\n\n```sql\nCREATE POLICY tenant_isolation ON %I\n USING (tenant_id = current_setting('app.current_tenant_id', true))\n WITH CHECK (tenant_id = current_setting('app.current_tenant_id', true));\n```\n\n**模板的两个边界,照抄前必须知道**:\n\n1. **策略没有 `TO \u003crole\u003e` 子句** ⇒ 对 PUBLIC 生效。消费者若有 system / 后台角色需要跨租户扫描\n (补 gap、重放、运维对账),它同样会被这条���略挡住——除非该角色 `BYPASSRLS`,\n 而 `FORCE ROW LEVEL SECURITY` 下表属主也不豁免。\n2. **模板不含任何 `GRANT`**。消费者库若用独立的低权限运行角色(而不是表属主连接),\n 照抄模板后该角色对这五张表**没有任何权限**,摄入会直接失败。\n\n**契约**:表 DDL 逐字照用(列名与主键是 SDK 的 SQL 依赖,改了就对不上);\n`GRANT` 与策略的角色绑定**由消费者按自身角色模型补齐**,作为自己的增量迁移。\n参考实现见数字员工基座的 `20260928010000_platform_client_fact_inbox`(tenant / system 两角色 + 逐表显式 GRANT)。\n\n## 3. 处理结果与 rc.3 的行为变更(U-29)\n\n`FactInbox.handle()` 的返回值:\n\n| 返回 | 含义 |\n| --- | --- |\n| `APPLIED` | 首次应用,投影已写 |\n| `DUPLICATE` | 同 `fact_id` 重投,单次效果(digest 不一致则抛 `PROCESSED_FACT_CONFLICT`) |\n| `STALE` | 版本 ≤ 水位,不写投影 |\n| `GAP` | `previous_version ≠ 水位`,落 gap 缓冲等补齐 |\n\n\u003e **`1.0.0-rc.3` 起的行为变更**:`STALE` 之前**不可达**——版本落后时本包抛\n\u003e `FactRejected(\"UNPROCESSED_VERSION_BEHIND_WATERMARK\")`,而 `handle` 把任何 `FactRejected`\n\u003e 计入 attempts,于是至少一次投递下的**正常迟到重投**三次即被打进死信,与\"内容有毒\"共用一套判据。\n\u003e rc.3 改为返回 `\"STALE\"`,并顺手删掉该 fact 可能留在 gap 缓冲里的副本(落后事实永远等不到\n\u003e `previous_version = 水位`,留着只会把缓冲占满到 `GAP_BUFFER_FULL`,drain 循环也会空转)。\n\u003e\n\u003e 消费 rc.2 及更早版本的上层需要在边界做\"错误码 → 结果词\"的翻译;**升到 rc.3 后应删除该翻译**,\n\u003e 判定回到 SDK 单源。\n\n## 4. 写链边界\n\n`appendFactIntent` 必须在**属主自己的业务事务内**调用——它与业务写同 tx,事务回滚则事实意图一并回滚。\n`FactInbox.handle` 同理在消费者事务内完成 `processed_fact` + 投影 + 水位的原子写入。\n本包不提供事务,也不管理连接:宿主传入符合 `FactTransaction` 结构的 tx 即可(不要求宿主生成 Prisma schema)。\n\n## 5. 可信回查读取器 `createFactReader`(候选)\n\n\u003e 本节为 `3074b75` 引入的读取面文档,原文保留(英文),与上面三节的接入契约互补:\n\u003e 上面讲「接进来会踩什么」,本节讲「读取器本身怎么用、边界在哪」。\n\n```ts\nconst reader = createFactReader({\n baseUrl: \"https://platform.example/api\",\n tenantId,\n token: getConsumerBearer,\n});\nconst inbox = new FactInbox({\n tenantId, consumerId, tenant: consumerTenantTransaction,\n trustedLookup: reader.lookup,\n apply: applyOwnerFact,\n});\n// On shutdown: stop consumer delivery, then reader.close().\n```\n\nThe server binds the verified JWT tenant/application/subject to one enrolled consumer. It checks the persisted consumer's activation and source-domain/fact-type scope on every lookup. `replayAllowed` is not required for point lookups; replay remains a separate operation. The candidate server is enabled only with `PLATFORM_FACT_READ_ENABLED=1` in development/test with JWT, `DATABASE_URL_FACT`, and an exact `FACT_READERS_JSON` list of `{tenantId,appId,subject,consumerId}`. It can run independently of intake and relay. Production/default assembly remains unavailable pending CHG-004 and live service identity integration.\n\nThe reader uses HTTPS (HTTP only on literal loopback/localhost), denies redirects and URL credentials, and bounds token/fetch/body processing to 5 seconds and 128 KiB by default. It verifies tenant/id/ordering/receipt and the canonical submission digest. It does not cache authorization or facts. A typed M5 `FACT_NOT_FOUND` returns null; all other transport/authentication/integrity errors throw `FactReadUnavailable`, which is deliberately distinct from `FactRejected`. Dependency failures must retain the Kafka offset and must not increment poison counters. `close()` aborts active lookups and rejects future ones; callbacks that ignore cancellation may continue internally but cannot produce an accepted lookup.\n\nA deactivated or deleted consumer registration answers 403, which the reader turns into a retryable `FactReadUnavailable`: the Kafka offset is kept and nothing is counted as poison. A registration that is still active but no longer covers the fact's source domain or type answers the same 404 as an unknown id, which is a null lookup and therefore `UNTRUSTED_FACT` — a dead letter. Narrowing `sourceDomain`/`factTypes` on a live consumer will dead-letter facts that are already in flight, while deactivating the same consumer only pauses it. Deactivate first, change scope, then reactivate; treat a scope edit as a migration, not as a switch.\n\nThe server refuses a bearer carried in the query string (`FACT_READ_URL_CREDENTIAL_REFUSED`, 401) even when a valid `Authorization` header is also present, because the token has already reached the proxy access log by then. The reader never produces such a URL; the refusal exists for anything else that calls the surface.\n\nAn authenticated M5 response plus the receipt digest is the trust boundary here, not a cryptographic signature proving the Owner. A compromised M5 authority or whole-row rewrite with a recomputed digest is outside this reader's detection. Kafka self-asserted hashes are never sufficient. Consumers still need the Owner's domain validation, bootstrap watermark reconciliation and appropriate action enforcement.\n","repository":{"type":"","url":""}}...
|
0
|
Edit
Delete
|
|
27
|
2
|
5
|
0.23.0
|
0.23.0
|
1790403659
|
0
|
{"scope":"@juhai","name":& {"scope":"@juhai","name":"kernel","description":"基础框架内核契约(租户/信封/状态机/重放/请求上下文/平台端口/RLS/告警/作业)——源码留在 base-framework 仓,上层按框架版本 pin","license":"UNLICENSED","dependencies":{"zod":"^3.24.1"},"development_dependencies":{"typescript":"^5.7.2","vitest":"^2.1.8"},"readme":"ERROR: No README data found!","repository":{"type":"git","url":"git@gitea.g-hi.com:luoanwu/base-framework.git"}}...
|
2
|
Edit
Delete
|
|
28
|
2
|
5
|
0.24.0
|
0.24.0
|
1790419994
|
0
|
{"scope":"@juhai","name":& {"scope":"@juhai","name":"kernel","description":"基础框架内核契约(租户/信封/状态机/重放/请求上下文/平台端口/RLS/告警/作业)——源码留在 base-framework 仓,上层按框架版本 pin","license":"UNLICENSED","dependencies":{"zod":"^3.24.1"},"development_dependencies":{"typescript":"^5.7.2","vitest":"^2.1.8"},"readme":"ERROR: No README data found!","repository":{"type":"git","url":"git@gitea.g-hi.com:luoanwu/base-framework.git"}}...
|
149
|
Edit
Delete
|
|
29
|
3
|
5
|
1.0.0-rc.7
|
1.0.0-rc.7
|
1791622728
|
0
|
{"scope":"@juhai","name":& {"scope":"@juhai","name":"contracts","description":"企业应用群机器契约:Catalog、JSON Schema、OpenAPI、兼容基线与治理 Linter(基础设施仓 contracts/,DEC-010 / DEC-031)","license":"UNLICENSED","dependencies":{"ajv":"8.20.0","ajv-formats":"3.0.1"},"development_dependencies":{"@types/node":"20.19.43","json-schema-to-typescript":"16.0.0","typescript":"5.9.3"},"readme":"# @juhai/contracts(原 platform-contracts 候选控制面)\n\n## 当前发布列车\n\n本列车版本为 `1.0.0-rc.7`,与 16 个客户端及 `@juhai/governance` 统一版本。消费者应 exact pin;实际可安装版本以配置的 npm Registry 为准,源码提交、验证运行与候选摘要见包内 `provenance.json`。预发行包不代表候选协议获准激活或生产环境已经验收。以下迁移记录保留其历史版本和裁决状态,当前机器登记以本包 Catalog、Schema 与 `package.json` 为准。\n\n## 在 enterprise-platform 内的状态(PF-04 阶段 1,2026-09-10)\n\n- **身份**:本目录是原 `platform-contracts/` 候选控制面的带来源登记导入(见 [SOURCE.md](SOURCE.md);来源目录已于 2026-09-16 按 PF-04 阶段 2 物理移除,SOURCE.md 记录的指纹是它最后的状态);包名按 DEC-031 命名修订改为 `@juhai/contracts`,版本 **`1.0.0-rc.6`**(仓内 `package.json`,2026-09-18 实测;本行此前写 `1.0.0-rc.0`。**注册表上最后一个已发布版本仍是 `rc.3`**,且那是[本地旁路发布](../docs/G-12本地旁路发布记录-2026-09-13.md),rc.4—rc.6 未发出去——GitHub Actions 计费未恢复。非 rc `1.0.0` 受 DEC-010 附条件:远端 + Required Check)。`catalogs/`、`contracts/`、`examples/`、`apps/`、`compatibility/` 与来源逐字节一致;`schemas/` 仅含下述 PF-04 的 `causation_id` / `correlation_id` 变更。\n- **工作区根**:Linter、影响图与测试以「工作区根」(`企业应用/`,同时含 `平台治理/基础/` 与 `doc/`)为基准解析 Catalog `directory` / `evidence`、DEC `source` 与各应用仓路径,不再假定包位于工作区根的直接子目录。解析顺序:`--workspace-root \u003cabs\u003e`(`node scripts/check.mjs --workspace-root …`)→ 环境变量 `PLATFORM_CONTRACTS_WORKSPACE_ROOT` → 自动探测(从本目录向上找到首个同时含 `平台治理/基础/` 与 `doc/` 的祖先)。经 `pnpm` 复合脚本运行时请用环境变量(pnpm 只把额外参数附加到最后一条命令)。\n- **独立克隆**(向上没有含 `workspace.json` 的工作区根,例如云端 CI 只 checkout 本仓;2026-09-12):`check:local` 的影响图以 `--workspace-optional` 退化为\"仅包内\"计算并在 stderr 打印 `[WORKSPACE_ROOT_UNRESOLVED]` 提示,不核验 Catalog / AppManifest / 裁决的路径引用;依赖应用仓文件、工作区路径或真实探测结果的 16 个测试显式 `skip`(91 例中 75 例照跑)。`check` 与 `check:impact` 在独立克隆下仍失败关闭(退出码 2),显式 `--workspace-root` / 环境变量不可用时任何模式都失败关闭。\n- **TS 层(CT-1)**:`scripts/schema-registry.mjs` 是 key → Schema 文件 → 类型名的唯一来源;改 Schema 后运行 `pnpm generate` 重生成 `generated/`,`pnpm check:generated`(在 `check:local` 内)在缺失 / 差异 / 多余文件时失败;`pnpm build`(tsc → `dist/`)在 `test` 与 `check:local` 之前自动执行;首次使用需 `pnpm --dir contracts install`(依赖只来自公共 npm,全部 exact pin)。\n- **`pnpm check` 现状**:`check` 报告且仅报告 4 项 `PLATFORM_PROJECT_UNREGISTERED`(`企业控制面/企业搜索与统一检索平台`、`企业控制面/外部连接器与集成平台`、`企业控制面/开发者自助与应用工程平台`、`企业控制面/数据治理与隐私平台`;2026-09-14 迁移后扫描面已换成 `企业控制面/`,G-12 提到的 `平台治理/基础/reports`、`平台治理/基础/tests` 两项假阳性随之消失),全部随 CHG-001(新增基础应用 MachineCatalog 变更)合并后消失;Linter 未被放宽。合并前以 `pnpm check:local`(schema 兼容 + 影响图 + 测试)作为绿色门禁;CHG-001 合并后 `check` 转绿,根 `pnpm check` 再切回完整 `check`。\n- **`causation_id` 可选、`correlation_id` 映射**(设计 §7 / §25 张力 4):`schemas/fact-envelope.v1.schema.json` 的 `required` 去掉 `causation_id`(旅程首条事实没有因果父,省略而非填占位值);`trace_id` = 旅程锚点、`correlation_id` = 业务关联写入 `fact-envelope.v1` 与 `request-context.v1` 的 `description`(后者只加说明)。Linter 新增规则 `FACT_ENVELOPE_FIELD_NOT_OPTIONAL` 防止回退为必填;`test/fact-envelope.test.mjs` 用兼容检查器自身的规则证明该放宽向后兼容(反向则报 `REQUIRED_PROPERTY_ADDED`)。`compatibility/` 冻结基线未动(信封不在基线内)。\n- **消费**:`pnpm add @juhai/contracts@1.0.0-rc.N`(exact pin,`check:pins` 强制);子路径导出 `@juhai/contracts/catalogs/*`、`/schemas/*`、`/contracts/*`、`/examples/*`、`/apps/*`、`/compatibility/*`、`/scripts/*`、`/package.json`;**裸入口(CT-1,2026-09-12)**:`import { validate, validateFact, assertValid, isValid, schemaOf, SCHEMA_KEYS, type FactEnvelopeV1 } from '@juhai/contracts'`——12 个 JSON Schema 的 TypeScript 类型(`generated/`,由 `schemas/` 生成并入库)与 Ajv 2020 校验器(按 key 懒编译;未知 key 抛 `RangeError`;`validateFact` 先验信封再按 `facts/\u003cfact_type\u003e.v\u003cmajor\u003e` 验载荷,未登记载荷 Schema 以 `payloadSchema` 失败关闭);`dist/` 随包���布,运行依赖仅 `ajv` / `ajv-formats`;`test/`、`src/`、`generated/` 不随包发布。\n\n本目录是企业应用群 Git-first 机器契约的 **W1 候选实现**,用于先建立可校验的语义基线。`DEC-010` 尚未裁决 Catalog 的最终物理位置,因此这里的 Registry、AppManifest 和 Schema 均为 `proposed` 或 `draft`,不能作为“能力已上线”的证据。\n\n## 已覆盖\n\n- `Employment` 的唯一 Owner、Canonical ID 目标格式与数据分级,以及企业 IdP 已实现权威模型的目录对账;\n- `FactEnvelope v1` JSON Schema;\n- `EmploymentTransferred v1` Payload JSON Schema;\n- HR、Digital Employee OS、Permission Platform、企业 IdP、执行监管、基础框架、嗨设、巨嗨智服、知识云、设备云、巨嗨报价系统与尤克特拉十二个草案 AppManifest;\n- Fact Producer/Consumer、Projection/Replay 和待裁决 Owner 的静态治理检查;Fact Projection 进一步绑定 Consumer、只读 Authority、状态 Schema、`consumer_name + fact_id` 幂等、Projection + `processed_fact` 原子提交、单调但不连续的聚合版本语义,以及受 Backbone ADR 阻断的消息 Gap 检测;\n- 五份待裁决 Fact 的 payload Schema 与共享 canonical-id 定义随候选登记镜像在 `candidates/schemas/`;候选登记只指向仓内镜像,使独立 CI 能实际执行 PII、开放结构与 `$ref` 检查;\n- Resource/Action Catalog v1、Actor/Request Context v1 和 Permission Decision API v1 候选契约;\n- 全量 Decision Catalog 登记:**39 条裁决(32 approved / 4 rejected / 3 pending)**(2026-09-18 实测订正——本行此前写「DEC-001—032,32 approved / 0 pending,037—039 待 CHG-002」:037—039 已登记为 `pending`,另有 DEC-033—036 随 CHG-015 撤销为 `rejected`),并校验所有 Catalog 引用的裁决可解析;\n- 权限请求/拒绝样例,强制租户一致、未知资源/动作拒绝、故障关闭和拒绝不正缓存;\n- DEC-012 完整候选 ADR、首条 Fact Schema 的不可变 proposed Snapshot 与保守向后兼容检查器;\n- 从 Catalog + AppManifest 构建的 proposed Producer/Consumer Impact Graph 与变更查询 CLI;\n- `平台治理/基础/` 21 个平台目录的机器项目清单:19 个属于本轮目标,明确排除基础框架与 AI 数字员工;实现状态、代码真源、证据等级和阻塞 DEC 可查询;\n- 可执行的正向检查和 Owner、ADR、Canonical ID、PII、Replay、Consumer、Application Dependency、Permission、Schema Compatibility 负向边界测试。\n\n## 尚未裁决,禁止越权实现\n\n- `Person`、`Organization`、`Store`、`Position`、`Actor` Owner(`DEC-001`—`DEC-005`);\n- AppManifest/ProductManifest 边界、Catalog 物理真源和双 Envelope 边界(`DEC-009`—`DEC-011`,评审材料已形成但尚未批准);\n- Schema 最终组合与兼容策略批准(`DEC-012`);候选检查器只证明当前规则可机械执行,不是正式发布策略;\n- Broker、Topic、Fact Store 与 Ordering(`DEC-013`—`DEC-016`);\n- Scope 执行和权限分工(`DEC-017`—`DEC-019`);\n- 权限平台的引擎、策略存储和运行时技术路线(`DEC-029`)。\n- 尤克特拉身份、设备、客户、订单、执行与通知重名实体的 Owner、映射和迁移方案(`DEC-030`,其中 Store 仍受 `DEC-003` 阻塞)。\n- 平台契约与 SDK 的分发通道、发布包名登记与发布门禁(`DEC-031`);裁决前派生仓 Planner 只能以夹具或标注来源 SHA 的过渡复制形式被业务仓引用,不得冒充平台接入。\n\n因此 Permission Decision API 是可评审、可机械验证的候选边界,不是权限引擎已实现或已上线的声明。Actor Context 仅携带 IdP 已认证的不透明主体标识,不越权裁决 `Actor` 企业 Owner。\n\n`DEC-027/028` 已批准并进入 HR 实现;Linter 仍会阻止草案 Manifest 标记为 `active`,也不允许 `EmploymentTransferred` 越过 `DEC-010/012` 直接激活。\n\n企业 IdP 草案清单已对账其当前 E2 代码中的 Tenant/User、Application/OIDC Client、Credential/Authenticator、Consent、Session、Authorization Code/Grant、Refresh Token Family/Token、Backchannel Delivery 与 Security Event 等权威模型;这仍不代表生产 KMS/HSM、远程 CI 或生产部署已签收。`User` 是 IdP 账户主体,不等同于企业 `Person`(其 Owner 归属由 DEC-001 裁定,2026-09-12 已批准)。嗨设现已真实消费 IdP RS256 access token/JWKS,并登记 `material.production` 候选权限面;它只保存 actor 引用,不拥有 Tenant/User/Session/Grant。执行监管的 Project/Ticket/SLA 仍未进入企业 Entity Catalog。知识云则登记 `KnowledgeCandidate`、`KnowledgeAtom`、`KnowledgeAtomVersion`、`KnowledgeSource` 与 `KnowledgeFeedback` 五个权威对象;`KnowledgeEmbedding`、检索 Evidence 与 AI 推理结果都是可重建派生物,不得冒充企业权威实体。巨嗨报价系统已将当前 Prisma 的 68 个业务模型登记为权威对象,并由测试持续与真实 schema 对账;本地 `User/UserEvent` 及 `Outbox/OutboxReplayEvent` 明确排除,避免抢占 IdP 身份 Owner 或把技术投递记录冒充企业业务实体。尤克特拉只登记已验证的 Express/PostgreSQL 运行时,其 Prisma 模型中与全局 Catalog 精确重名的七个对象由 DEC-030 阻断;模型总数随应用演进,测试守重名集合与裁决登记的一致性,Fact、统一 Permission、Projection 和权威 Entity 保持空集;这不把本地数据误报成共享真源,也不把单后端误报成双后端。基础框架只作为工程模板登记,不拥有企业业务事实。\n\nPlatform Project Catalog 当前只允许企业 IdP 声明独立服务 `implemented_e2`;通知与 Webhook 中心、公共文件平台及配置与功能开关平台声明 `module_e2`。公共文件已由执行监管、巨嗨报价与嗨设三个真实消费者完成 E2 运行验证;通知投递已由执行监管、巨嗨智服与巨嗨报价三个真实消费者完成 E2 运行验证;配置平台当前只有执行监管一个真实业务消费者,生产无有效批准快照时关闭、坏刷新保留最后良好版本,并把版本/摘要/来源/原因写入 AutomationRun。前三者都不表示 G4 已裁决或独立服务已启动;配置平台尤其仍缺第二、第三消费者。报价本地 `QuotationNotificationIntent` 是技术投递记录,不登记为企业权威实体。应用与契约注册中心、企业事实干线和统一权限平台仅为 `candidate_e0`;其余目标平台仍是 `not_started`。各平台目录内复制的 `base-framework/` 一律不计为平台实现,任何 E2 证据文件都必须真实存在并报告 `passed`。\n\n## 使用\n\n无需安装第三方依赖,Node.js 20+ 即可运行:\n\n```bash\nnpm run check\nnpm test\n```\n\n`check` 校验平台项目目录、目标范围、证据、Schema 引用、Owner、Producer/Consumer、Projection/Replay、幂等/原子提交/版本顺序、权限与 Scope 对账,并对每个已登记 Fact 执行 proposed Snapshot 不可变/版本兼容检查;`test` 证明目录漏登、模板冒充实现、E2 证据未通过、Owner 冲突、Consumer 绑定漂移、Owner 越权、非原子 Projection、错误连续版本假设、Projection PII/来源漂移与不兼容 Schema 会失败。\n\n查询一个 Fact Schema 变更的直接与二跳影响:\n\n```bash\nnpm run impact -- schema schemas/facts/EmploymentTransferred.v1.json 2\n```\n\n输出明确区分节点深度,并列出 Producer、Consumers、Projections、Entity、阻塞 Decision 与相关边;未知目标返回非零退出码,不生成空的“无影响”结果。\n\n## 状态升级规则\n\n只有同时满足以下条件,才能把本目录从候选实现升级为正式真源:\n\n1. `DEC-010` ADR 已批准;\n2. `DEC-012` Schema 表达和兼容策略已批准;\n3. App Owner 对 AppManifest 与真实代码、部署资产完成核验;\n4. CI 使用本 Linter 或其正式替代品阻断冲突;\n5. 运行时证据证明事实生产、消费、幂等与 Replay,而不只是静态文件通过。\n","repository":{"type":"","url":""}}...
|
14
|
Edit
Delete
|
|
30
|
4
|
5
|
1.0.0-rc.7
|
1.0.0-rc.7
|
1791622735
|
0
|
{"scope":"@juhai","name":& {"scope":"@juhai","name":"governance","description":"基础设施层跨仓门禁(设计方案 §9):check:pins(exact pin 消费规则)、check:fixtures(契约正反例夹具)、verify:candidate(候选可晋级核验)、release:manifest(已知事实清单)、CI 模板;零依赖 CLI,供上层仓 exact pin 后在 CI 运行。","license":"UNLICENSED","bin":{"juhai-governance":"bin/cli.mjs"},"readme":"# @juhai/governance — 基础设施跨仓门禁\n\n设计方案 §4.2 / §9 定义的 `governance/` 交付:一组**零依赖**的构建期检查,随基础设施仓同一 Release 版本号发布到 Gitea npm registry(DEC-031),供上层仓 **exact pin** 后在 CI 运行(`check:pins` 为必需检查,DEC-031 附带条款 4)。\n\n横切底座范围以 `cross-cutting-capabilities.json` 为机器真源:X01—X15 必须恰好各出现一次,并逐项提供合法分类、成熟度、Owner、存在的仓内控制路径、开放缺口、退出证据与未过期复核期。[逐项治理收口清单](../docs/能力设计/横切能力治理收口-2026-09-24.md)列出下一刀和首个故障证据。每项的 `leadRole` 必须是 `ownerRoles` 中一个明确的**协调牵头岗位**,负责推进、依赖协调与证据汇集;其余角色的实现、审批及签收责任不转移,岗位登记也不代表具体人员已签收。两类底座共担的条目仍只指定一个协调牵头���位。升为 `verified` 还须登记 `evidenceRefs: [{scenario: \"normal|denial|recovery\", report: \"reports/…latest.json\", caseId: \"Xxx-A-用例\"}]`,三类场景各至少一份;报告须在 `evidence-scopes.json` 登记作用域、状态为 `passed`、无未验证项、绑定干净的当前有效源码,并在 `crossCuttingCases` 中逐条列出与引用一致的 `{capabilityId, scenario, caseId, status: \"passed\", environment, subjectRef}`。机器据此拒绝挪用无关的绿色报告;这些字段仍是报告生成器的声明,`verificationReview: {reviewer, scope, reviewedAt}` 必须记录人工对用例内容及环境、消费者或资产范围的实质复核。`test/cross-cutting-capabilities.test.mjs` 随治理测试链执行;工作台快照只展示该登记,不会把 `designed` / `partial` 提升为 `verified`。\n\n## 命令(`juhai-governance \u003ccommand\u003e [--root \u003cdir\u003e]`)\n\n| 命令 | 用途 | 报告 | 退出码 |\n|---|---|---|---|\n| `check:pins [--require \u003cpkg\u003e]…` | 三层:`@juhai/*` 只允许 `x.y.z` / `workspace:*`;对外发布包的第三方依赖必须 exact;其余第三方按只减不增的 `pins-baseline.json` 放行存量。解析来源从仓根及第一层独立 pnpm 根的锁文件核验,并与 manifest 的外部 exact pin 对应;本仓有基线而来源零覆盖、基线损坏或锁文件不可读均判红。无基线的消费者仓在无锁文件时仍只核 manifest。`--require` 要求该包至少一处 exact pin | 无(stdout) | 1 = 有违规 |\n| `check:port-conformance` | 基础设施仓内独立端口测试:先构建 contracts/modules/clients,再跑 `runtime/test/port`;必须完整通过内核 14、模块 6、客户端 21 例,拒绝跳过与空跑 | `reports/port-conformance.latest.json` | 1 = 构建/测试/覆盖核验失败 |\n| `check:fixtures --suite \u003csuite.json\u003e… [--allow-unavailable-suite \u003cid\u003e]…` | 契约正反例夹具:校验套件配置后,ACCEPT 须零原因、REJECT 须有原因且含声明前缀;缺工作区默认失败,显式允许且有其他用例执行才可 partial | `reports/fixtures.latest.json` | 1 = 配置错误、空跑、不可用或用例不符 |\n| `verify:candidate --candidate \u003cdir\u003e --sha \u003csha\u003e …` | 候选可晋级核验(Q12-C / X12):逐份 required 报告核 sourceSha / dirty / 状态 / 地板 / digest,缺失即不合格 | `\u003cdir\u003e/release-candidate.json` 或 `--out` | 1 = 不合格 |\n| `release:manifest` | 已知事实清单,**逐项按磁盘判定**:`governance/package.json`、`runtime/clients/\u003cm\u003e/package.json`(name 须为 `@juhai/client-\u003cm\u003e`)、`reports/image-digest.json`(`sha256:` 且 `sourceSha` = HEAD)、compose 镜像是否 `@sha256:` 锁定、`reports/sbom.spdx.json`、`reports/signature.json`;任一缺失即 `status=partial` 并写明缺什么,不判定晋级 | `reports/release-manifest.latest.json` | 0 |\n| `ci:template [--out \u003cfile\u003e]` | 输出消费者最小 CI 模板(私包认证 + contracts/governance 必需 exact pin + 必需夹具) | — | 0 |\n| `check:modules` / `check:module-imports` / `check:catalog` / `catalog:drift` | 基础设施仓内部门禁(依赖 `runtime/modules.json` 与 `contracts/catalogs`) | `reports/*.latest.json` | 1 = 违规(drift 默认 0) |\n| `reports:rebind [--gates a,b] [--list] [--dry-run]` | **在 HEAD 的干净检出里重跑零依赖门禁并把报告带回**(偏差 #34-A 裁决实现)。`provenance.worktreeDirty` 由全仓 `git status` 算,而 `check:evidence` 按作用域判过期——口径不一致使得只要任何无关文件脏着就没法回绑任何报告;本工具不改判据,改为换个干净的地方生成。可行前提是 `governance/` 零依赖,临时检出**不需要 pnpm install**。作用域内有未提交输入的门禁会被跳过(否则等于用 HEAD 的结论覆盖当前工作区);目标报告自己在工作区未提交时也跳过(可能是并行会话的在途产物,覆盖即销毁,`--force` 才override);产出若不是「绑 HEAD 且 dirty=false」则拒绝带回。一个���禁可写多份报告(`workbench-snapshots` 两份快照),要么全带回要么一份不带,避免同源报告绑到不同提交。需要构建产物的 `check:fixtures` / `check:port-conformance` 与 runtime / contracts 的检查不在范围,须在装好依赖的检出里跑。 |\n| `check:migration-decs` | 仓纪律 3:`runtime/modules/*/prisma/migrations` 与 `identity/apps/*/prisma/migrations` 的 `migration.sql` 前 10 行须有 `-- decision: DEC-NNN` 且该 DEC 已批准;`state=shape` 模块不得有迁移;例外只能逐个迁移登记在 `migration-decs.exceptions.json`(条件失效判 `EXCEPTION_STALE`) | `reports/migration-decs.latest.json` | 1 = 违规 |\n| `check:facts [--candidates \u003cdir\u003e] [--report-only] [--workspace-root \u003c路径\u003e]` | §6.4:`modules.json` 声明的 Fact ⊆ `contracts/catalogs/facts.json` ∪ CHG-004 候选;每个候选须 `status: pending-dec`,且 `blocked_by` 必须是可解析、可落地的 DEC / CHG / 决策批次引用。独立克隆无法核验的工作区引用单独登账,候选目录不可用时报 `UNRESOLVED`(fail-closed) | `reports/facts.latest.json` | 1 = 违规 / unresolved |\n| `check:fact-pii [--dir \u003c目录\u003e]… [--workspace-root \u003c路径\u003e]` | Fact payload 禁止复制 PII:字段名命中 PII 模式、存在开放结构、候选 schema 指针不可达,或 `allowedKeys` 缺精确范围、理由、真实日期即判红;自由文本字段只登账不判红。候选 schema 随仓镜像到 `contracts/candidates/schemas`,独立 CI 也会实际扫描。判据来自 `fact-pii-rules.json`(仓内同名文件优先,否则用包自带的) | `reports/fact-pii.latest.json` | 1 = 有违规 |\n| `check:cross-cutting` | X01—X15 横切治理与运行底座登记:编号闭集、固定分类、牵头岗位、控制落点、开放缺口、退出证据和复核期必须完整;使用执行当天日期,过期即判红;`verified` 须有三类场景、逐项匹配用例的已登记且新鲜的通过报告和覆盖范围复核 | `reports/cross-cutting-capabilities.latest.json` | 1 = 登记缺失、分类漂移、复核过期或验证证据不足 |\n| `check:caddy` | §5 / §7:`modules.json` 的 HTTP 契约经 `caddy-routes.json` 映射前缀后必须被 profiles 段登记的每份 Caddyfile(dev 基线 `stack/caddy/Caddyfile` + staging `Caddyfile.staging`)的 path 匹配器覆盖;tls=required 的 profile 另守 `TLS_DISABLED` / `TLS_HOST_MISSING` / `TLS_ISSUER_MISSING` / `HSTS_MISSING` / `PLAINTEXT_SITE_FORBIDDEN`(2026-09-16);`/healthz`、`X-Request-Id` 注入、`{$PLATFORM_API_UPSTREAM}` 必备;**2026-09-19(G-10)另守入口自身的可观测性**:登记 `observability` 段后逐 profile 判 `TRACING_MISSING` / `TRACING_SPAN_MISMATCH` / `METRICS_GLOBAL_OPTION_MISSING`(Caddy 2.9 起 HTTP 请求指标 opt-in,不开时端点活着但只有四条)/ `METRICS_SITE_MISSING` / `METRICS_PATH_MISMATCH`,全仓一次判 `OTEL_ENV_MISSING` / `OTEL_SERVICE_NAME_UNREGISTERED`(交叉 `otel-attributes.json` 的 producers.registered);访问日志出口另守 `ACCESS_LOG_FILE_MISSING` / `ACCESS_LOG_MODE_MISSING`(默认 0600 时 Collector 读不到,管道静默为空)与 `ACCESS_LOG_VOLUME_UNSHARED`(共享卷须写入侧可写、读取侧只读);本机有 `caddy` 则 `caddy validate`,否则报告 `validate: skipped`(`CHECK_CADDY_DOCKER=1` 走 docker) | `reports/caddy.latest.json` | 1 = 违规 / 语法失败 |\n| `check:otel` | §5 / §15 采纳形态:`stack/otel/collector.yaml` 与登记真源 `otel-attributes.json` 逐项一致(三条 pipeline 的 processor、keep_keys allowlist、属性上限 / 时间有效性 / 产生端名单);2026-09-16 起另守告警规则——`stack/otel/prometheus.yaml` 的 `rule_files` 含登记 glob,`stack/otel/rules/*.yaml` 每条规则有 for / labels.severity / annotations.summary / annotations.runbook,expr 指标带选择器且在 alerts.metrics 登记(登记 = 有实测产生端;没有产生端的写 alerts.pending);**2026-09-19(G-10)另守两段**:`scrape` 段 ↔ `prometheus.yaml` 的 scrape_configs(`SCRAPE_JOB_MISSING` / `SCRAPE_TARGET_MISMATCH` / `SCRAPE_JOB_UNREGISTERED` / `SCRAPE_JOB_UNALERTED`——抓了却不在掉线告警的 `up{job=~…}` 里等于没抓),`logSources` 段守 OTLP 之外的日志来源(`LOG_SOURCE_MISSING` / `LOG_SOURCE_PATH_MISMATCH` / `LOG_SOURCE_SERVICE_NAME_MISSING` / `LOG_SOURCE_BODY_UNREPLACED` / `LOG_SOURCE_PRODUCER_UNREGISTERED`——filelog 不带 resource、body 不被 allowlist 管,这两条是它与 OTLP 的关键差别),`producers.wiring` 段把「登记」与「接线」分开(`PRODUCER_WIRING_UNDECLARED` / `PRODUCER_WIRING_PENDING_UNDATED` / `PRODUCER_WIRING_ORPHANED`,pending 必须带 wireInWhen 与 conditionReviewBy);本机有 `promtool` 则校验语法,`CHECK_OTEL_DOCKER=1` 用 compose 锁定的 prometheus 镜像跑,否则报告 `skipped` | `reports/otel.latest.json` | 1 = 违规 / promtool 失败 |\n| `check:evidence [--read-only] [--json]` | 检查报告绑定提交到 HEAD 的作用域差异,以及暂存、未暂存、删除、未跟踪输入。静态报告按 error 阻断;运行验收可登记为 warn,但已经 stale 后最多落后 **2000 提交 / 30 天**,任一超限自动转 error,年龄无法读取也失败关闭;作用域没变化时不按提交年龄误杀。分别统计 fresh / stale / worktreeChanged / invalid / exempted,例外不计新鲜;存在 warn 或豁免时为 partial,退出 0 不代表完整验收。**未登记的报告也要逐条记账**(2026-09-18):`SCOPE_UNDECLARED` 是 info、不拦任何东西,于是「未登记」这一类可以无声增长,而它恰恰是本门禁完全看不见的那部分(当时 48 份报告里 13 份在此)。现由 `evidence-scopes.json` 的 `undeclared` 逐条写明 class / reason / recordedAt / resolveBy,五类取值 self / aggregate / provenance-missing / one-off-snapshot / no-generator;报告存在却既无作用域又无账 = `UNDECLARED_UNACCOUNTED` 判红,账指向的报告已登记或已消失 = `UNDECLARED_STALE` 判红,字段残缺或 class 非法 = `UNDECLARED_INCOMPLETE` 判红。记账**不是豁免**:no-generator 与 one-off-snapshot 的出口只有「补生成脚本后转正式登记」或「退役该报告」二选一。企业底座另以 `evidence-scope-floor.json` 固定 56 份作用域下限,收缩、撤登记、error 降级判红;例外 resolveBy 须是未过期的真实 ISO 日期。`--read-only` 不改报告,`--json` 只输出 JSON | `reports/evidence-freshness.latest.json`(只读模式不写) | 1 = error;0 = passed 或 partial,须读取 status / counts |\n| `check:gate-flow [--read-only] [--json]` | 从根 check 链与两份 CI 工作流推导脚本消费;流外门禁须具名说明并按期复核。`gate-flow.json.requiredCheckScripts` 固定根链必需集合,F6 要求脚本表、实际链和登记逐项一致,防止必需环静默消失 | `reports/gate-flow.latest.json`(只读模式不写) | 1 = 有违规;0 = 通过 |\n| `check:ci-mirror [--read-only] [--json]` | **两条 CI 通道是不是真的同步**(2026-09-18 新增)。`CLAUDE.md` 与镜像文件自己的头注释都写着「`.gitea/workflows/platform.yml` 是 `.github` 版的镜像副本,只差四处,两份必须同步改」,而实测**没有任何东西在比对它们**。剥掉整行注释与空行、按 `governance/ci-mirror.json` 把镜像还原成主干形态之后,两份 461 行逐行相同——文件层面的差异恰好三类(镜像头注释块、artifact v3↔v4、一行 `GOV_REPORT_RUNNER`)。M1 声明之外的差异;M2 声明了却已不存在(声明不许腐烂);M3 声明缺 id 或 reason。只剥**整行**注释:行尾注释可能跟在真命令后面,剥掉会让门禁漏判。**值得有执行者的理由不是洁癖**:那行 `GOV_REPORT_RUNNER: gitea-actions` 是证据来源标注的唯一保证——act_runner 为兼容会设 `GITHUB_ACTIONS=true`,不显式覆盖,本通道产出的报告会把自己标成 github-actions 并被 `verify-candidate` 当作 CI 证据接受,一次漏同步就是一次冒充。**未决口径**见声明里的 `openDiscrepancy`:头注释宣称的差异③『fork 判定改用 `gitea.*` 上下文』**在文件里根本不存在**,两份的 fork 守卫逐字相同、全是 `github.*`;是声称做了没做还是当初判断错了,归 SRE / 框架 Owner,本门禁不替人裁决。 | `reports/ci-mirror.latest.json`(只读模式不写) | 1 = 有违规;0 = 通过 |\n| `check:deployed`(仓根脚本,不在发布 CLI 命令集) | 核对固定镜像源提交、当前 HEAD 的运行时输入、目标容器镜像及环境键。运行时有变更但镜像未构建、容器未换、无目标容器、缺源提交或脏镜像均阻断;仅治理/文档/报告变化无需重建。未提交运行时输入与缺环境键单列为 partial。默认只读,`--write-report` 才写报告;不接触业务数据 | 可选 `reports/deployed-runtime.latest.json` | 1 = 部署未满足;2 = Docker 不可用;0 = passed / partial |\n\n`catalog:drift --workspace-root \u003c工作区根\u003e` 支持独立检出指向真实工作区,也支持 `PLATFORM_CONTRACTS_WORKSPACE_ROOT`;显式路径无效时拒绝执行,自动探测不到时才保留 unknown。\n\nCatalog 对账分别处理实现状态与证据等级:`authority` 表示权威持久化实现,不自动要求或授予 E2;`candidate_e0` 可保留并记录待签收信息。Catalog 的 `code_truth` 指向本仓模块时,`module_e2` / `implemented_e2` 必须由模块自身的 `state=e2` 支撑;反向仍要求模块 `state=e2` 与 Catalog `implemented_e2` 对账。不得为了消除差异自动升级 Catalog。\n\n所有报告带 `provenance`(`gitSha` / `worktreeDirty` / `runner` 原值 / `runnerNormalized` / `runId`);`worktreeDirty` 忽略 latest 报告本身。\n\nG-7 的 `port-conformance` job 保留同仓 PR 的私包认证约束,不访问数据库。每次执行使用新的临时 Vitest JSON;构建失败、测试失败或没有新报告时覆盖旧成功状态为 failed。四组逐文件地板在 `lib/port-conformance.mjs`,新增套件须同步更新覆盖清单。candidate 依赖该 job 成功,且十一份 required 报告中必须含同源码、干净工作树的端口报告;旧十份报告不能用于新版本候选。发布门禁沿用相同的源码必需报告策略。此门禁证明端口一致性,不提升模块 shape 状态。\n\n`verify:candidate` 在候选源码工作树的根目录运行:从 `runtime/reports/baseline.json` 与 `identity/reports/baseline.json` 读取最低测试数量,不能用 artifact 自报的较低地板代替。报告须为对象,验收计数与地板须为正整数,治理报告须含固定必需指标且为零;缺失、`null`、数组、标量和显式 `PARTIAL` 状态均不合格。旧治理报告没有 `status` 字段时仍按必需指标核验。指定 `--run-id` 或运行于 GitHub Actions 时要求每份报告为 CI runner;本地诊断保留 local 来源,不代表远端验收。独立调用纯函数 `evaluateCandidate` 时须显式传入 `{ baselines, requireCi, mainlineRequired }`;CLI 自动读取源码基线和 `runtime/modules.json`。\n\n### 持久化主线候选证据\n\n候选源码中的 fact / permission / audit 任一模块进入 `authority` 或 `e2` 后,必需报告从 11 份增加为 14 份,增加 `mainline-acceptance`、`revocation-sla` 和 `credential-m1-sla`。模块登记缺失、损坏或状态非法时拒绝候选;不能由 artifact 自报关闭此要求。RC 发布入口读取相同源码策略,不接受只含旧 11 或 13 份报告的候选。M1/M2 报告另要求 20 次实际撤权到 HTTP 与材料读取同时拒绝的正数样本,重算摘要并检查同一 SLA 上界。\n\n主线报告须完整包含 `lib/mainline-evidence.mjs` 登记的全部套件及逐套件地板,包括实时 M1/M2 HTTP/SDK 联动 16 项;各套件唯一,退出成功,无失败、pending 或 todo。撤权报告至少 20 个正数样本,按样本重算 p95/max 并比对摘要,要求 p95 \u003c 30 秒、max \u003c 60 秒。Grant 撤销通过而就业 Scope 仍待实现时,报告必须显式保持 `partial` 和未验证说明,候选结果保留这项覆盖边界;这不表示 MS-3、真实 HR/OS 接入或生产签收完成。\n\nruntime artifact 兼容旧单目录扁平上传,以及新增仓根报告后的目录结构。只在本次下载目录内读取固定的两种路径,不回退到仓内历史报告;同时发现两份时拒绝。源登记或目录读取失败也覆盖写入不合格候选,防止遗留成功报告。\n\n## 镜像、SBOM 与签名(开发计划 §3A D-1 / D-2;仓根脚本)\n\n| 脚本 | 作用 | 产物 |\n|---|---|---|\n| `pnpm image:build`(`governance/build-image.mjs`) | 用 `runtime/Dockerfile` 构建运行时镜像;默认 `--context head`(`git archive HEAD:runtime`,本机 WIP 不进镜像);私有 registry token 只经 `--secret id=npmrc,src=\u003cnpmrc\u003e`(默认 `~/.npmrc`,`--npmrc` 可指定)进入安装层,不进镜像、不打印 | `reports/image-digest.json`:`digest` = 本机 `--load` 的 image id(`digestKind` 说明;推送后换 registry manifest digest)、`sourceSha` / `worktreeDirty` / `dockerfileTracked` / 平台 / 大小 / 基础镜像 |\n| `pnpm image:sbom`(`governance/sbom.mjs`) | `syft` 或 `docker sbom` 生成完整 SPDX(OS + Node);两者都缺时退到 **lockfile 模式**:从镜像里 deploy 树的 pnpm lock 与工作区包生成只含 Node 依赖的 SPDX 2.3(`sbom.latest.json.scope` 标 partial,Debian 包不在内;完整 SBOM 由 CI image job 的 syft 产出);镜像不可用则退出 3 不写空文件 | `reports/sbom.spdx.json` + 元数据 `reports/sbom.latest.json`(tool / scope / sha256 / 包数) |\n| `pnpm image:publish -- --repository \u003cregistry/ns/name\u003e [--tag \u003ctag\u003e] [--dry-run]`(`governance/publish-image.mjs`) | 前置:`image-digest.json` 绑定 clean HEAD(`contextMode=head`、`worktreeDirty=false`、Dockerfile 未改、`sourceSha` = 当前 HEAD、未 published);`docker tag` + `docker push`,registry manifest digest 取自 push 输出并与 `RepoDigests` 互证,不一致 / 取不到即失败不改报告;`docker login` 由调用方完成,脚本不读凭据 | `reports/image-digest.json` 追加 `published` / `registry` / `repository` / `registryTag` / `registryRef`(`\u003crepository\u003e@sha256:…`)/ `registryDigest` / `pushedAt` / `pusher`;`sign-image` 与 `release-manifest` 只认此引用 |\n| `governance/prepare-image-release.mjs \u003ctag\u003e \u003crun.json\u003e \u003ccandidate.json\u003e \u003cprotection.json\u003e` | 镜像发布门(`Publish runtime image` workflow 用):clean tag `runtime-v\u003csemver\u003e[-rc.N]` + 同源 Platform CI 在 main 成功 + 候选 eligible 且 required 报告全部 ci / clean + Required Check 覆盖管理员 | `reports/image-release-evidence.json` |\n| `pnpm image:sign`(`governance/sign-image.mjs`) | `cosign sign --key $COSIGN_KEY \u003cregistry ref@digest\u003e`;未推送 / 无密钥 / 无 cosign 时明确跳过、退出 0 | `reports/signature.json`(缺失即 Manifest `missing: signature`) |\n\n`release:manifest` 逐项按磁盘判定这三份产物;CI 的 `image` job 在 Secret 配置后产出同名 artifact(不推 registry)。\n\n## 环境晋级记录(开发计划 PF-23;DEC-024 A / DEC-026;仓根脚本)\n\n| 脚本 | 作用 | 产物 |\n|---|---|---|\n| `pnpm promotion:check -- --record \u003crecord.json\u003e [--manifest …] [--template …]`(`governance/check-promotion.mjs`) | 核验一份晋级记录:R1 形状(`stack/promotion/promotion-record.schema.json`)、R2 级序 dev→test→staging→prod(preview←candidate)、R3 同 digest(记录 = 候选 = Manifest 文件 `images.runtime.digest`,prod 禁止 rebuild 由此机器化)、R4 级别门槛(staging:eligible + SBOM + 签名或未过期 waiver;prod:Manifest complete + 签名 + 签收全闭)、R5 必需检查项恰好一次及仓内 JSON 实证(报告 `check` 对应、`status=passed`、clean `provenance.gitSha` 等于制品 `sourceSha`;拉取与冒烟报告另绑定 runtime digest)、R6 审批角色 + 委派(initiator / approvals 的 `actorType`;数字员工须带未过期、TTL ≤ 24h、非自我委托的 delegation 引用——DEC-007 A,缺口 G-8)、R7 回滚演练 ≤ 600 s、R8 preview 上限、R9 签收项在模板内、R10 脏树 Manifest 禁晋级、R11 源提交交叉断言(记录 = Manifest = 制品 `images.runtime.sourceSha`,均 40 位;迁自统一交付平台 FULL_SOURCE_COMMIT_REQUIRED / ARTIFACT_SOURCE_MISMATCH,2026-09-16)、R12 迁移就绪(Manifest 有迁移目录时记录须带 `migrations` 段:expand_migrate_contract / ready / backwardCompatible / rollbackEvidence;迁自 MIGRATION_* 判定) | `reports/promotion.latest.json`(`verdict` APPROVED / APPROVED_WITH_PENDING_SIGNOFFS / REJECTED;REJECTED 退出 1) |\n\n记录模板 `stack/promotion/promotion-record.template.json`,签收模板 `stack/promotion/target-env-signoff.template.json`(P1—P9,取自 OS `target-env-signoff.json`);步骤见 [staging 晋级操作说明](../docs/staging晋级操作说明.md)。记录字段判定与 R5 机器实证判定分别由 `evaluatePromotion`、`evaluateRequiredCheckEvidence` 覆盖(`governance/test/promotion.test.mjs` 37 例)。\n\n## 消费方接入\n\n```bash\npnpm add -D @juhai/governance@1.0.0-rc.1 # exact pin;.npmrc 配 @juhai 作用域到 Gitea registry\npnpm exec juhai-governance ci:template --out .github/workflows/platform-governance.yml\npnpm exec juhai-governance check:pins --require @juhai/contracts --require @juhai/governance\npnpm exec juhai-governance check:fixtures --suite governance/fixtures/contracts.suite.json\n```\n\n夹具套件格式见 `check-fixtures.mjs` 头注;示例 `fixtures/contracts.suite.json`(正例取 `@juhai/contracts` 的 examples,反例故意破坏必填 / 类型 / 血缘字段)。消费者须在自己仓内建立 `governance/fixtures/contracts.suite.json`,按实际安装位置调整 schema / inputFile 路径;模板不再跳过缺失文件。\n\n套件必须有非空且不重复的 id / case id、合法 expect、已声明 schema,以及 input / inputFile 二选一。空套件、缺失 schema、损坏的本地引用、文件读取/解析/模块加载错误会生成 failed 报告并退出 1,覆盖旧的成功报告;规则必须显式返回原因数组,DEC-039 适配器的失败结论不能被重新判为成功。JSON Schema 校验仍是头注声明的子集,不代表完整元 Schema 校验或支持所有关键字。\n\n根 `pnpm check:fixtures` 先构建运行时模块,再显式带 `--allow-unavailable-suite dec-039-party-model`,仅容许独立克隆缺少企业应用工作区时跳过 DEC-039 外部套件,报告 status=partial、保留 unavailable 计数;contracts 与六个模块套件仍必须执行,缺失模块构建产物不会被该豁免放过。全部套件不可用、配置错误和真实用例失败仍阻断。消费者模板使用默认严格模式。`--allow-unavailable` 保留为显式允许所有不可用套件的诊断开关,不用于本仓根门禁。以上增强为仓内新源码,已发布的 `1.0.0-rc.0` 保持不变,本仓已准备 `1.0.0-rc.1`,实际发布及 Registry 安装状态见发布记录。\n\n## 本仓内\n\n仓根 `pnpm check` 的当前链以根 `package.json` 的 `scripts.check` 为准;`check:pins` 是第一环,`check:evidence` 是末环。`pnpm check:port-conformance` 独立运行真实端口测试,CI 单独生产证据。`.github/CODEOWNERS` 仍有角色占位,不能把覆盖测试通过解释为真实团队审批已生效。发布走 DEC-031 的固定源码 RC 通道;已发布版本不覆盖,新包代码须使用后续新 RC 版本。\n","repository":{"type":"","url":""}}...
|
5
|
Edit
Delete
|
|
31
|
6
|
5
|
1.0.0-rc.7
|
1.0.0-rc.7
|
1791622739
|
0
|
{"scope":"@juhai","name":& {"scope":"@juhai","name":"client-ai","description":"AI 治理远程客户端:把 ai-route.v1 候选契约的四个操作(路由决策 / 读决策 / 用量上报 / 经 LiteLLM 代执行)实现为对平台端点的调用;未配置或传输失败一律拒绝,不静默回退(缺失清单 G-5;开发计划 §3A CL-7)","license":"UNLICENSED","development_dependencies":{"@types/node":"22.19.20","typescript":"5.9.3","vitest":"2.1.9"},"readme":"# @juhai/client-ai\n\nM7 AI 治理的调用方 SDK:把 `ai-route.v1` 候选契约(`contracts/candidates/contracts/ai-route-api.v1.openapi.json`,pending CHG-004)的四个操作实现为对平台端点的调用。缺失清单 G-5;开发计划 §3A CL-7。\n\nM7 不提供内核端口(`modules.json` `provides: []`),本包不实现 `PlatformPorts`、不声明 `@juhai/kernel` peer;与 `client-public-file` 同形。\n\n```ts\nimport { AI_ROUTE_API_VERSION, AI_USAGE_API_VERSION, AI_INVOKE_API_VERSION, createAiRouteClient } from \"@juhai/client-ai\";\n\nconst ai = createAiRouteClient({ baseUrl: \"https://platform.example.com\", token: () =\u003e serviceToken() });\nconst routed = await ai.route({ api_version: AI_ROUTE_API_VERSION, request: { request_id, capability: \"chat\", purpose, agent_id, requested_by, /* … */ estimated_units: 200 } });\nif (routed.ok \u0026\u0026 routed.value.outcome === \"routed\") {\n // A:自己执行(credential_ref 是 secret:// 引用,材料由宿主经 M2 / OpenBao 解析,本包不碰),再按 attempt 上报\n await ai.reportUsage(routed.value.decision_id, { api_version: AI_USAGE_API_VERSION, attempt: 1, status: \"settled\", input_tokens, output_tokens, cost_units });\n // B:provider=litellm 的路由交给平台经 LiteLLM 执行这一 attempt,平台按 LiteLLM 真实 usage 结算\n const out = await ai.invoke(routed.value.decision_id, { api_version: AI_INVOKE_API_VERSION, attempt: 1, messages: [{ role: \"user\", content: \"…\" }] });\n}\n```\n\n| 方法 | 端点 | 成功时校验 |\n|---|---|---|\n| `route` | `POST /api/v1/ai/route` | `request_id` 回显一致;routed 必须 `audited=true`、`expires_at` 未过、`credential_ref` 是 `secret://` 引用、`credential_lease=null`;rejected 必须 `route=null` 且有 reasons |\n| `get` | `GET /api/v1/ai/route/{decisionId}` | 同上,`decision_id` 回显一致 |\n| `reportUsage` | `POST /api/v1/ai/route/{decisionId}/usage` | `decision_id` / `attempt` / `status` 回显一致,数量是十进制串 |\n| `invoke` | `POST /api/v1/ai/route/{decisionId}/invoke` | 同上,并含 `output.content`;默认超时 90 s(`invokeTimeoutMs`) |\n\n| 情形 | 返回 |\n|---|---|\n| 未配置 `baseUrl`,或非 localhost 的 `http://`、带用户名口令 / 查询串 | `{ ok: false, code: \"AI_CLIENT_NOT_CONFIGURED\" }`,不发请求 |\n| 入参缺 `request_id` / `decisionId` 非法 / `attempt` 非整数 | `AI_CLIENT_INVALID_REQUEST`,不发请求 |\n| 网络错误 / 超时 | `AI_CLIENT_TRANSPORT_FAILED`,`retryable: true` |\n| 非 200 且响应体带稳定码 | 原样透传服务端码(`AI_AUDIT_UNAVAILABLE` / `AI_ROUTE_EXPIRED` / `AI_PROVIDER_UNAVAILABLE` / `AI_REQUEST_INVALID` + `reasons` …),`status` 同带;5xx 为 `retryable: true` |\n| 非 200 且没有稳定码 | 5xx → `AI_CLIENT_REMOTE_UNAVAILABLE`(retryable),4xx → `AI_CLIENT_REMOTE_REJECTED` |\n| 200 但不是契约形状 | `AI_CLIENT_INVALID_RESPONSE`——含「routed 却未审计」「credential_ref 不是引用而像密钥」 |\n\n四个方法永不抛错;`retryable` 只是提示,**本包不自动重试**。服务端对 `request_id`(路由)与 `attempt`(用量 / 代执行)幂等:用**同一个** id / attempt 重发即可,换 id 等于新决策、会重复预留预算。\n\n## 与旧分支的关系\n\n旧 `client-ai`(`edcb7a6d` / `061821c9`,从未进主线)没有迁入:`createAiGatewayClient` 走的是契约落地前的草稿协议(`POST /v1/ai/usage` + `usage_id`),与当前服务端不互通;`createAiRouteLedgerClient` 的 GET 守卫要求 `route` 恒为 `null`,读已路由决策必判失败。本包按当前契约重写,单测对只监听 127.0.0.1 的桩逐一覆盖上表。\n\n## 未做\n\n- 未进发布列车(`governance/release-packages.json` `notInTrain` 登记);CI 发布通道与 G-1 正式登记是前置。\n- 未接任何真实上层消费者;契约仍是候选,ai-route 面只在 development / test 显式启用。\n","repository":{"type":"","url":""}}...
|
1
|
Edit
Delete
|
|
32
|
7
|
5
|
1.0.0-rc.7
|
1.0.0-rc.7
|
1791622743
|
0
|
{"scope":"@juhai","name":& {"scope":"@juhai","name":"client-application-contract-registry","description":"application-contract-registry 已有 HTTP 接口客户端;候选边界见 README;未配置即失败关闭","license":"UNLICENSED","development_dependencies":{"@types/node":"22.19.20","typescript":"5.9.3"},"readme":"# @juhai/client-application-contract-registry\n\nNode.js 20+ 的 HTTP 客户端,RC 列车版本 `1.0.0-rc.7`。发布状态以 Registry 中该 exact 版本及包内 provenance.json 为准;加入列车不代表真实消费者已完成接入。无状态准入 review 仍为候选;正式台账仅记录评审,不激活应用、不写注册中心。\n\n传输实现内联,无运行时依赖,不导入私有 `@repo/*`、平台模块或其他客户端;没有对应内核端口,不声明虚假的 kernel peer。\n\n```ts\nimport { ApplicationContractRegistryClient } from '@juhai/client-application-contract-registry';\nconst client = new ApplicationContractRegistryClient({\n baseUrl: 'https://platform.example.com', // 入口,勿再附加 /api\n token: async () =\u003e currentAccessToken(), // 每次请求取当前令牌\n});\n```\n\n每个方法收一个 input 对象(含路径标识、查询字段,以及 POST 的 body;需要幂等键的操作还需 idempotencyKey),第二个参数可传 `{ signal }`。baseUrl 可含反向代理前缀,不能含账号口令、查询或 fragment。凭据、租户和主体只能由服务端验证;包不生成可信主体头。候选服务、权限、来源登记或生产身份链未配置时,服务端拒绝会原样返回。\n\n| 方法 | 已有接口 |\n|---|---|\n| `planManifestAdmission` | `POST /api/v1/registry/manifests:review` |\n| `submitManifestReview` | `POST /api/v1/registry/manifest-reviews` |\n| `listManifestReviews` | `GET /api/v1/registry/manifest-reviews` |\n| `getManifestReview` | `GET /api/v1/registry/manifest-reviews/{reviewId}` |\n\n返回值以 `kind` 区分:`response` 带 httpStatus 和原始 JSON 对象 body;`http-error` 带非 2xx 的 httpStatus/body;`client-error` 带 NOT_CONFIGURED / INVALID_CONFIG / INVALID_INPUT / ABORTED / TIMEOUT / TRANSPORT_FAILED / INVALID_RESPONSE。**HTTP 2xx 不代表业务放行**:调用者必须检查 body 的 decision / kind / outcome 等契约字段;REJECT 不会被改写为成功。输入体和业务响应保留 unknown,服务端仍为结构与业务校验权威,不承诺不存在的静态领域类型。\n\n可配置 timeoutMs(缺省 5000、覆盖取令牌及完整 JSON 读取)、requestId、traceparent、fetchImpl。合法 W3C traceparent 原样透传,无效时生成随机根。不自动重试写操作、不自动跟随重定向;需要的幂等键由调用方提供,不在每次重试中随机重造。未配置/非法配置及路径必填值缺失时不发请求;异常、超时和取消不会降级为放行。\n\n来源:`contracts/candidates/contracts/registry-admission-api.v1.openapi.json`, `contracts/contracts/manifest-review-ledger-api.v1.openapi.json`。包内 `test/operations.json` 用于验证方法覆盖与实线路由;C17 的登记簿三项另对应当前控制器。验收 `pnpm test` 使用真实本地 HTTP stub,证明传输行为,不代替目标环境/RLS/消费者验收。构建 `pnpm build`;打包 `pnpm pack`。正式发布只能走仓库的受保护 CI 发布列车,满足同源码成功 CI、版本与 tag、分支保护和凭据前提后才能移入列车。\n","repository":{"type":"","url":""}}...
|
68
|
Edit
Delete
|
|
33
|
8
|
5
|
1.0.0-rc.7
|
1.0.0-rc.7
|
1791622747
|
0
|
{"scope":"@juhai","name":& {"scope":"@juhai","name":"client-audit","description":"审计接收远程客户端:把内核 AuditSinkPort 实现为对基础设施 audit-append.v1(POST /v1/audit/events,批量)的调用;同步模式审计失败即写链失败,缓冲模式本地缓冲 + 稳定 event_id 至少一次投递(基础设施开发设计方案 §9 client-*;开发计划 §3A CL-6;能力表 C10.02)","license":"UNLICENSED","development_dependencies":{"@juhai/kernel":"0.24.0","@types/node":"22.19.20","typescript":"5.9.3","vitest":"2.1.9"},"peer_dependencies":{"@juhai/kernel":"0.24.0"},"readme":"# @juhai/client-audit\n\n内核 `AuditSinkPort`(`@juhai/kernel@0.24.0`,peer exact)的远程实现:调用基础设施 M6 契约\n`audit-append.v1`(`POST \u003cbaseUrl\u003e/v1/audit/events`,批量)。设计:基础设施开发设计方案 §9 / §8 M6;能力表 C10.02;工作项:开发计划 §3A CL-6。\n契约 OpenAPI 随 CHG-004 登记,本包先内联映射(开发计划 §6 偏差 #17);线上事件字段与 M6 `audit-event-preflight` 的 `AuditEventCandidate` 同名(snake_case)。\n\n```ts\nimport { createRemoteAuditSinkPort } from \"@juhai/client-audit\";\n\n// 同步(缺省):审计失败即写链失败(内核 fail-closed 语义)\nconst audit = createRemoteAuditSinkPort({ baseUrl: \"https://platform.example/api\", clientId: \"hr-api\", token: () =\u003e serviceToken() });\n\n// 缓冲:append 在记录进入宿主持久缓冲后返回;宿主把缓冲与业务事务绑定(C10.02 appendLocal),relay 至少一次投递\nconst buffered = createRemoteAuditSinkPort({ baseUrl, clientId, token, delivery: \"buffered\", buffer: outboxBackedBuffer, flushIntervalMs: 1000 });\nregistry.replace({ ...registry.current(), audit });\n```\n\n| 情形 | 行为 |\n|---|---|\n| 未配置(无 `baseUrl` / `clientId`) | 返回内核 fail-closed 端口对象本身(`isFailClosedPort` 为真) |\n| 内核 `auditRecordSchema` 不通过 | 抛 `RemoteAuditError` `INVALID_REQUEST`,不打远端 |\n| 无租户上下文 | `NO_TENANT_CONTEXT`,不打远端 |\n| `details` 含 `password` / `secret` / `token` / `authorization` / `content`(大小写不敏感) | `SENSITIVE_DETAIL_FORBIDDEN`,不打远端(敏感值永不出网;与 M6 preflight 同集合) |\n| 同步:网络错误 / 超时(缺省 3 s)/ 5xx | `REMOTE_UNAVAILABLE`(写链回滚) |\n| 同步:401 / 403 / 409 / 其它 4xx | `REMOTE_REJECTED` |\n| 同步:200 但不是响���形状,或缺本批回执 | `INVALID_RESPONSE` |\n| 同步:服务端逐条拒绝(preflight / planner reasons) | `EVENT_REJECTED`,`reasons` = `\u003cevent_id\u003e:\u003creason\u003e` |\n| 缓冲:缓冲满 / 宿主 enqueue 失败 | `BUFFER_FULL`(背压,永不丢弃) |\n| 缓冲:没有显式注入持久缓冲 | 装配时报 `AUDIT_DURABLE_BUFFER_REQUIRED`;进程内存队列不能作为业务写入的持久回执 |\n| 缓冲:`flush()` 失败 | 抛同上错误,缓冲保留;下次 flush 以同 `event_id` + `digest` 重试(M6 按 ID + digest 去重) |\n| `close()` 后 | `CLOSED` |\n\n所有错误都是 `RemoteAuditError`:`code = AUDIT_APPEND_FAILED`、`port = \"audit\"`、`operation = \"append\"`、`reasonCode` 稳定,装配点按 reasonCode 映射(本地即拒 → 400,其余 → 503)。\n\n映射约定:`event_id = audit_evt_\u003csha256 前 32 hex\u003e`,`digest = sha256`,二者只由记录内容(租户、主体、请求、动作、资源、结果、生效时间、details、causation)决定,\n重试携带同值;`trace_id` 无合法 traceId 时生成、`recorded_at = now()` 且不早于 `effective_at`(M6 `AUDIT_TIME_INVALID`),二者不参与摘要;\n`reason` 缺省取 `details.reason`,否则 `kernel:\u003coutcome\u003e`,可用 `reason` 回调覆盖;每批 `Idempotency-Key = audit-batch:\u003csha256(事件 id 集)\u003e`。\n\n端口一致性:`runtime/test/port/client-audit.test.ts` 用 S-6 共用夹具对 stub server(真实落点 / 逐条拒绝 / 不可用 / 不可达)跑本包同步与缓冲两种投递。\n","repository":{"type":"git","url":"git@gitea.g-hi.com:luoanwu/enterprise-platform.git"}}...
|
3
|
Edit
Delete
|
|
34
|
9
|
5
|
1.0.0-rc.7
|
1.0.0-rc.7
|
1791622751
|
0
|
{"scope":"@juhai","name":& {"scope":"@juhai","name":"client-collaboration-messaging","description":"collaboration-messaging 已有 HTTP 接口客户端;候选边界见 README;未配置即失败关闭","license":"UNLICENSED","development_dependencies":{"@types/node":"22.19.20","typescript":"5.9.3"},"readme":"# @juhai/client-collaboration-messaging\n\nNode.js 20+ 的 HTTP 客户端,RC 列车版本 `1.0.0-rc.7`。发布状态以 Registry 中该 exact 版本及包内 provenance.json 为准;加入列车不代表真实消费者已完成接入。SSE 仅为提示流,消息/未读权威仍由 sync / attention 返回;流断开后调用方按契约重查。生产 token exchange 条件不因 SDK 建立而解除。\n\n传输实现内联,无运行时依赖,不导入私有 `@repo/*`、平台模块或其他客户端;没有对应内核端口,不声明虚假的 kernel peer。\n\n```ts\nimport { CollaborationMessagingClient } from '@juhai/client-collaboration-messaging';\nconst client = new CollaborationMessagingClient({\n baseUrl: 'https://platform.example.com', // 入口,勿再附加 /api\n token: async () =\u003e currentAccessToken(), // 每次请求取当前令牌\n});\n```\n\n每个方法收一个 input 对象(含路径标识、查询字段,以及 POST 的 body;需要幂等键的操作还需 idempotencyKey),第二个参数可传 `{ signal }`。baseUrl 可含反向代理前缀,不能含账号口令、查询或 fragment。凭据、租户和主体只能由服务端验证;包不生成可信主体头。候选服务、权限、来源登记或生产身份链未配置时,服务端拒绝会原样返回。\n\n| 方法 | 已有接口 |\n|---|---|\n| `createConversation` | `POST /api/v1/conversations` |\n| `listConversations` | `GET /api/v1/conversations` |\n| `getConversation` | `GET /api/v1/conversations/{conversationId}` |\n| `applyConversationMembership` | `POST /api/v1/conversations/{conversationId}/members:apply` |\n| `appendConversationMessage` | `POST /api/v1/conversations/{conversationId}/messages` |\n| `retractConversationMessage` | `POST /api/v1/conversations/{conversationId}/messages/{messageId}:retract` |\n| `syncConversationMessages` | `GET /api/v1/conversations/{conversationId}/sync` |\n| `getConversationAttention` | `GET /api/v1/conversations/{conversationId}/attention` |\n| `advanceConversationRead` | `POST /api/v1/conversations/{conversationId}/read:advance` |\n| `prepareConversationFile` | `POST /api/v1/conversations/{conversationId}/files/uploads` |\n| `completeConversationFile` | `POST /api/v1/conversations/{conversationId}/files/{fileId}:complete` |\n| `downloadConversationFile` | `GET /api/v1/conversations/{conversationId}/messages/{messageId}/files/{fileId}` |\n| `streamConversationHints` | `GET /api/v1/conversations/{conversationId}/events` |\n\n返回值以 `kind` 区分:`response` 带 httpStatus 和原始 JSON 对象 body;`http-error` 带非 2xx 的 httpStatus/body;`client-error` 带 NOT_CONFIGURED / INVALID_CONFIG / INVALID_INPUT / ABORTED / TIMEOUT / TRANSPORT_FAILED / INVALID_RESPONSE。**HTTP 2xx 不代表业务放行**:调用者必须检查 body 的 decision / kind / outcome 等契约字段;REJECT 不会被改写为成功。输入体和业务响应保留 unknown,服务端仍为结构与业务校验权威,不承诺不存在的静态领域类型。\n\n可配置 timeoutMs(缺省 5000、覆盖取令牌及完整 JSON 读取)、requestId、traceparent、fetchImpl。合法 W3C traceparent 原样透传,无效时生成随机根。不自动重试写操作、不自动跟随重定向;需要的幂等键由调用方提供,不在每次重试中随机重造。未配置/非法配置及路径必填值缺失时不发请求;异常、超时和取消不会降级为放行。\n\nstreamConversationHints 返回 `stream` 时包含标准 Fetch Response 和 close();仅接受 text/event-stream,超时约束建连而非长流寿命。调用者自行消费 response.body 并在 finally 调用 close()(中止连接并清理取消监听);signal 可贯穿整个流生命周期。它不缓存事件、不自动重连、不把提示当消息权威。\n\n来源:`contracts/contracts/conversation-ledger-api.v1.openapi.json`。包内 `test/operations.json` 用于验证方法覆盖与实线路由;C17 的登记簿三项另对应当前控制器。验收 `pnpm test` 使用真实本地 HTTP stub,证明传输行为,不代替目标环境/RLS/消费者验收。构建 `pnpm build`;打包 `pnpm pack`。正式发布只能走仓库的受保护 CI 发布列车,满足同源码成功 CI、版本与 tag、分支保护和凭据前提后才能移入列车。\n\n附件准备返回服务端上传信息;对象上传由调用方按该信息执行,本客户端不会把平台 Bearer 令牌转发到对象存储。completeConversationFile 不发送请求体,扫描与可发送状态仍由服务端决定。downloadConversationFile 返回可关闭的 stream,仅接受 application/octet-stream,保留标准 Response 的下载头与原始字节;权限拒绝原样返回,不自动跟随重定向。timeoutMs 约束建连,signal/close() 约束下载寿命;调用方须在 finally 关闭,服务端另有30秒传输上限。\n","repository":{"type":"","url":""}}...
|
2
|
Edit
Delete
|
|
35
|
10
|
5
|
1.0.0-rc.7
|
1.0.0-rc.7
|
1791622755
|
0
|
{"scope":"@juhai","name":& {"scope":"@juhai","name":"client-configuration-feature-flags","description":"配置与功能开关:批准快照、规范 JSON 摘要校验、租户稳定分桶放量、最后良好回退","license":"UNLICENSED","development_dependencies":{"@types/node":"22.19.20","typescript":"5.9.3","vitest":"2.1.9"},"readme":"# `@juhai/client-configuration-feature-flags`\n\n配置与功能开关能力的**带副作用那半**:批准快照的装载与刷新、规范 JSON 摘要校验、租户稳定分桶放量、最后良好回退。\n\n**规则那半在 `contracts/src/domain/configuration-feature-flags/`**(`feature-flag.ts` 与 `configuration-client.ts` 的纯判定,2026-09-14 迁入并于 2026-09-18 硬化)。\n\n## 来源与迁入\n\n逐字迁自工单仓 `packages/configuration-client/src/`(284 行实现 + 63 行单测),2026-09-18 按目录负责人「直接搬」的 G4 裁决执行。5 例单测原样随迁,5/5 绿;判定逻辑一行未改,无外部依赖。\n\n## ⚠️ 这个包还没长成平台能力\n\n**它硬编码了一个应用和一个开关:**\n\n```ts\nexport const EXECUTION_CONTROL_APP_ID = \"juhai.execution-control\";\nexport const AUTOMATION_EXECUTION_FLAG_KEY = \"automation.execution.enabled\";\n```\n\n`AutomationConfigurationSnapshot.appId` 的类型就是 `typeof EXECUTION_CONTROL_APP_ID`,`flags` 的键类型就是那一个 flag key。也就是说:**本包目前只能为「执行控制」这一个应用的「自动化执行」这一个开关服务**,换任何第二个应用或第二个开关都要改类型。\n\n这不是疏忽,是**三消费者规则要拦的那种状态**——本能力至今只有 1 个消费者(工单仓),代码还没被第二个使用者逼着一般化。设计方案 §4.2 给配置与功能开关排的条件正是「三消费者 + G4」,而文件与通知早在 2026-09-09 就满足了 3 个,配置一直是 1 个。\n\n本轮按「直接搬」的裁决**原样迁入、不做一般化**:搬是搬,重构是重构,把两件事混在一起会让「判定逻辑一行未改」这句话不再可核验。**代价要说清楚**:基础设施仓里从此有一个知道 `juhai.execution-control` 的包,方向上违反依赖单向。解除路径二选一——出现第二、第三个消费者时由它们逼出一般化(`appId` 与 flag key 变参数),或由配置与功能开关 Owner 直接裁决先一般化再接入。\n\n## 接口\n\n| 导出 | 作用 |\n|---|---|\n| `buildAutomationConfigurationSnapshot` / `configurationSnapshotDigest` | 规范 JSON(键排序)后 SHA-256;摘要比对走 `timingSafeEqual` |\n| `LocalAutomationConfigurationClient.create` | 候选快照不合格时**回退到 bundled 真值并记下拒绝原因**,生产 bundled 默认关;拒绝原因可从 `status()` 读出,不是静默吞掉 |\n| `.evaluateAutomationExecution` | 优先级:denylist → 开关关 → allowlist → 100% → 稳定分桶 → 不在放量内;FNV-1a 分桶保证同租户结论稳定 |\n| `.refresh` | 只接受**版本前进**且全部校验通过的快照,否则保留最后良好版本并给出原因数组 |\n\n校验拒绝原因(11 条):`SNAPSHOT_FORMAT_INVALID`、`SNAPSHOT_SCHEMA_INVALID`、`FLAG_SCHEMA_INVALID`、`FLAG_VALUE_INVALID`、`SCHEMA_VERSION_UNSUPPORTED`、`APP_ID_MISMATCH`、`ENVIRONMENT_MISMATCH`、`SNAPSHOT_VERSION_STALE`、`SNAPSHOT_NOT_APPROVED`、`PLAINTEXT_SECRET_FORBIDDEN`、`SNAPSHOT_EXPIRED`、`DIGEST_FORMAT_INVALID` / `DIGEST_MISMATCH`、`SNAPSHOT_VERSION_NOT_FORWARD`。\n\n## 与其他 `@juhai/client-*` 的不同\n\n本包**不实现任何内核端口**,无 `@juhai/kernel` peer 依赖,也不进端口一致性三画像——配置与功能开关按设计**在三消费者之前根本不设运行服务**。形态判据见 `../README.md`。\n\n## 未做(不在本轮范围)\n\n- **一般化**(见上)。\n- **消费者未改接**:工单仓仍用自己的 `@repo/configuration-client`;改接前提是本包发布,而发布卡在 CI 计费。\n- **Catalog 登记未动**:仍 `module_e2 / E2`,`code_truth` 仍指工单仓 `packages/configuration-client`。\n- **OpenFeature 兼容接口未做**(设计方案 §4.2 的采纳项)。\n","repository":{"type":"","url":""}}...
|
1
|
Edit
Delete
|
|
36
|
11
|
5
|
1.0.0-rc.7
|
1.0.0-rc.7
|
1791622759
|
0
|
{"scope":"@juhai","name":& {"scope":"@juhai","name":"client-cost-capacity","description":"cost-capacity 已有 HTTP 接口客户端;候选边界见 README;未配置即失败关闭","license":"UNLICENSED","development_dependencies":{"@types/node":"22.19.20","typescript":"5.9.3"},"readme":"# @juhai/client-cost-capacity\n\nNode.js 20+ 的 HTTP 客户端,RC 列车版本 `1.0.0-rc.7`。发布状态以 Registry 中该 exact 版本及包内 provenance.json 为准;加入列车不代表真实消费者已完成接入。只覆盖已实现的 OS 用量投影接口;不暴露仍仅登记的 usage-record-api,不生成账单或修改预算。\n\n传输实现内联,无运行时依赖,不导入私有 `@repo/*`、平台模块或其他客户端;没有对应内核端口,不声明虚假的 kernel peer。\n\n```ts\nimport { CostCapacityClient } from '@juhai/client-cost-capacity';\nconst client = new CostCapacityClient({\n baseUrl: 'https://platform.example.com', // 入口,勿再附加 /api\n token: async () =\u003e currentAccessToken(), // 每次请求取当前令牌\n});\n```\n\n每个方法收一个 input 对象(含路径标识、查询字段,以及 POST 的 body;需要幂等键的操作还需 idempotencyKey),第二个参数可传 `{ signal }`。baseUrl 可含反向代理前缀,不能含账号口令、查询或 fragment。凭据、租户和主体只能由服务端验证;包不生成可信主体头。候选服务、权限、来源登记或生产身份链未配置时,服务端拒绝会原样返回。\n\n| 方法 | 已有接口 |\n|---|---|\n| `ingestOsUsageProjection` | `POST /api/v1/cost/usage-projections` |\n| `getOsUsageSummary` | `GET /api/v1/cost/usage-summary` |\n\n返回值以 `kind` 区分:`response` 带 httpStatus 和原始 JSON 对象 body;`http-error` 带非 2xx 的 httpStatus/body;`client-error` 带 NOT_CONFIGURED / INVALID_CONFIG / INVALID_INPUT / ABORTED / TIMEOUT / TRANSPORT_FAILED / INVALID_RESPONSE。**HTTP 2xx 不代表业务放行**:调用者必须检查 body 的 decision / kind / outcome 等契约字段;REJECT 不会被改写为成功。输入体和业务响应保留 unknown,服务端仍为结构与业务校验权威,不承诺不存在的静态领域类型。\n\n可配置 timeoutMs(缺省 5000、覆盖取令牌及完整 JSON 读取)、requestId、traceparent、fetchImpl。合法 W3C traceparent 原样透传,无效时生成随机根。不自动重试写操作、不自动跟随重定向;需要的幂等键由调用方提供,不在每次重试中随机重造。未配置/非法配置及路径必填值缺失时不发请求;异常、超时和取消不会降级为放行。\n\n来源:`contracts/contracts/os-usage-projection-api.v1.openapi.json`。包内 `test/operations.json` 用于验证方法覆盖与实线路由;C17 的登记簿三项另对应当前控制器。验收 `pnpm test` 使用真实本地 HTTP stub,证明传输行为,不代替目标环境/RLS/消费者验收。构建 `pnpm build`;打包 `pnpm pack`。正式发布只能走仓库的受保护 CI 发布列车,满足同源码成功 CI、版本与 tag、分支保护和凭据前提后才能移入列车。\n","repository":{"type":"","url":""}}...
|
1
|
Edit
Delete
|
|
37
|
12
|
5
|
1.0.0-rc.7
|
1.0.0-rc.7
|
1791622763
|
0
|
{"scope":"@juhai","name":& {"scope":"@juhai","name":"client-credential","description":"Reference-only remote ServiceCredentialPort for the explicit M2 lease HTTP candidate; uncached M1 bearer per call and bounded fail-closed transport","license":"UNLICENSED","development_dependencies":{"@juhai/kernel":"0.24.0","@types/node":"22.19.20","typescript":"5.9.3","vitest":"2.1.9"},"peer_dependencies":{"@juhai/kernel":"0.24.0"},"readme":"# @juhai/client-credential\n\n`1.0.0-rc.7` implements kernel `ServiceCredentialPort` against the explicit M2 HTTP candidate. Registry metadata and the packaged provenance.json identify the published version; publication does not imply deployment in real HR/OS applications. Peer `@juhai/kernel` is pinned to `0.24.0`; no module dependency or host schema generation is required.\n\n```ts\nimport { createRemoteServiceCredentialPort, type RemoteCredentialPort } from \"@juhai/client-credential\";\nconst credential = createRemoteServiceCredentialPort({\n baseUrl: \"https://platform.example/api\",\n token: async (request, signal) =\u003e machineTokenFor(request, signal),\n}) as RemoteCredentialPort;\nconst lease = await credential.lease(request);\ncredential.close();\n```\n\nThe fixed route is `POST /v1/credential-leases`. The provider must return a current M1 service/job token bound to the canonical tenant, actor, application and resource audience. Every call takes a fresh bearer; neither tokens nor references are cached. Callers control retries with the original request ID. The SDK returns only `credentialRef`, `expiresAt`, and `port`; material resolution, workload injection and renewal are separate boundaries.\n\nUnconfigured calls retain the kernel fail-closed port. Configured calls throw sanitized `CredentialClientError` values with `code`, `port: \"serviceCredential\"` and an optional HTTP `status`. Provider, transport and response reading share a timeout (default 5000 ms, maximum 30000 ms), including dependencies ignoring cancellation. `close()` aborts in-flight calls. HTTPS is required; loopback HTTP needs `allowLoopbackHttp: true`. Redirects, URL credentials, queries and fragments are forbidden. Responses with extra material fields, malformed references, expired leases or bodies larger than 16 KiB are rejected. Local expiry cannot exceed the requested TTL measured from the start of the call.\n\nM2 enables this candidate only with `PLATFORM_CREDENTIAL_HTTP_ENABLED=1`, `NODE_ENV=test|development`, `AUTH_MODE=jwt`, an ordinary `DATABASE_URL_CREDENTIAL` role and forced RLS. `CREDENTIAL_IDENTITY_TRUST_JSON` is a fixed array of canonical tenant/resource bindings:\n\n```json\n[{\"tenantId\":\"ten_01kkkkkkkkkkkkkkkkkkkkkkkk\",\"issuer\":\"https://identity.example/t/example\",\"audience\":\"RESOURCE_APPLICATION_ID\",\"clientId\":\"srv_RESOURCE_RECEIVER_ID\",\"clientSecretEnv\":\"CREDENTIAL_M1_RECEIVER_SECRET\"}]\n```\n\nThe receiver credential belongs to the audience's resource application and authenticates M1 introspection independently of the caller bearer. M2 also needs `CREDENTIAL_OPENBAO_ADDRESS`, `CREDENTIAL_OPENBAO_TOKEN_ENV`, `CREDENTIAL_OPENBAO_MOUNT`, and `CREDENTIAL_OPENBAO_PREFIX`, with a least-privileged current token in the named environment variable. Secret values never become request-body fields. Turbo forwards `CREDENTIAL_*`; use this prefix for the named receiver and OpenBao secret environment variables when launching through Turbo. Trusted operator policy installation and controlled material resolution remain separate. Production workload injection, renewal, Catalog E2 activation and target-environment signoff are pending.\n\nVerification includes 16 SDK behavior cases, the shared port fixture's three profiles, and `runtime/test/e2e/credential-m1-http.test.ts` using real M1, an ordinary-role M2 database and disposable initialized/unsealed OpenBao. `pnpm mainline:check` requires that suite and its 20-sample revocation report.\n","repository":{"type":"git","url":"git@gitea.g-hi.com:luoanwu/enterprise-platform.git"}}...
|
3
|
Edit
Delete
|
|
38
|
13
|
5
|
1.0.0-rc.7
|
1.0.0-rc.7
|
1791622767
|
0
|
{"scope":"@juhai","name":& {"scope":"@juhai","name":"client-cross-domain-workflow","description":"cross-domain-workflow 已有 HTTP 接口客户端;候选边界见 README;未配置即失败关闭","license":"UNLICENSED","development_dependencies":{"@types/node":"22.19.20","typescript":"5.9.3"},"readme":"# @juhai/client-cross-domain-workflow\n\nNode.js 20+ 的 HTTP 客户端,RC 列车版本 `1.0.0-rc.7`。发布状态以 Registry 中该 exact 版本及包内 provenance.json 为准;加入列车不代表真实消费者已完成接入。工作流台账 API 仍为候选契约;包不改变准入、发布或任务执行权限。\n\n传输实现内联,无运行时依赖,不导入私有 `@repo/*`、平台模块或其他客户端;没有对应内核端口,不声明虚假的 kernel peer。\n\n```ts\nimport { CrossDomainWorkflowClient } from '@juhai/client-cross-domain-workflow';\nconst client = new CrossDomainWorkflowClient({\n baseUrl: 'https://platform.example.com', // 入口,勿再附加 /api\n token: async () =\u003e currentAccessToken(), // 每次请求取当前令牌\n});\n```\n\n每个方法收一个 input 对象(含路径标识、查询字段,以及 POST 的 body;需要幂等键的操作还需 idempotencyKey),第二个参数可传 `{ signal }`。baseUrl 可含反向代理前缀,不能含账号口令、查询或 fragment。凭据、租户和主体只能由服务端验证;包不生成可信主体头。候选服务、权限、来源登记或生产身份链未配置时,服务端拒绝会原样返回。\n\n| 方法 | 已有接口 |\n|---|---|\n| `assessWorkflowDefinition` | `POST /api/v1/workflows/definitions:assess` |\n| `planWorkflowInstance` | `POST /api/v1/workflows/{workflowId}/instances` |\n| `getWorkflowPlannerStatus` | `GET /api/v1/workflows/{workflowId}/planner/status` |\n| `publishWorkflowDefinition` | `POST /api/v1/workflows/definitions:publish` |\n| `getWorkflowInstance` | `GET /api/v1/workflows/instances/{instanceId}` |\n| `claimWorkflowSteps` | `POST /api/v1/workflows/steps:claim` |\n| `reportWorkflowStep` | `POST /api/v1/workflows/steps:report` |\n| `applyWorkflowOperatorAction` | `POST /api/v1/workflows/operator-actions:apply` |\n\n返回值以 `kind` 区分:`response` 带 httpStatus 和原始 JSON 对象 body;`http-error` 带非 2xx 的 httpStatus/body;`client-error` 带 NOT_CONFIGURED / INVALID_CONFIG / INVALID_INPUT / ABORTED / TIMEOUT / TRANSPORT_FAILED / INVALID_RESPONSE。**HTTP 2xx 不代表业务放行**:调用者必须检查 body 的 decision / kind / outcome 等契约字段;REJECT 不会被改写为成功。输入体和业务响应保留 unknown,服务端仍为结构与业务校验权威,不承诺不存在的静态领域类型。\n\n可配置 timeoutMs(缺省 5000、覆盖取令牌及完整 JSON 读取)、requestId、traceparent、fetchImpl。合法 W3C traceparent 原样透传,无效时生成随机根。不自动重试写操作、不自动跟随重定向;需要的幂等键由调用方提供,不在每次重试中随机重造。未配置/非法配置及路径必填值缺失时不发请求;异常、超时和取消不会降级为放行。\n\n来源:`contracts/candidates/contracts/workflow-ledger-api.v1.openapi.json`。包内 `test/operations.json` 用于验证方法覆盖与实线路由;C17 的登记簿三项另对应当前控制器。验收 `pnpm test` 使用真实本地 HTTP stub,证明传输行为,不代替目标环境/RLS/消费者验收。构建 `pnpm build`;打包 `pnpm pack`。正式发布只能走仓库的受保护 CI 发布列车,满足同源码成功 CI、版本与 tag、分支保护和凭据前提后才能移入列车。\n","repository":{"type":"","url":""}}...
|
1
|
Edit
Delete
|
|
39
|
14
|
5
|
1.0.0-rc.7
|
1.0.0-rc.7
|
1791622771
|
0
|
{"scope":"@juhai","name":& {"scope":"@juhai","name":"client-data-analytics","description":"data-analytics 已有 HTTP 接口客户端;候选边界见 README;未配置即失败关闭","license":"UNLICENSED","development_dependencies":{"@types/node":"22.19.20","typescript":"5.9.3"},"readme":"# @juhai/client-data-analytics\n\nNode.js 20+ 的 HTTP 客户端,RC 列车版本 `1.0.0-rc.7`。发布状态以 Registry 中该 exact 版本及包内 provenance.json 为准;加入列车不代表真实消费者已完成接入。review / evolution 及登记簿增量按 DEC-047 的候选 HTTP 面提供;后面三项以当前控制器为依据,未宣称候选契约已转正。不读取任何指标数据行。\n\n传输实现内联,无运行时依赖,不导入私有 `@repo/*`、平台模块或其他客户端;没有对应内核端口,不声明虚假的 kernel peer。\n\n```ts\nimport { DataAnalyticsClient } from '@juhai/client-data-analytics';\nconst client = new DataAnalyticsClient({\n baseUrl: 'https://platform.example.com', // 入口,勿再附加 /api\n token: async () =\u003e currentAccessToken(), // 每次请求取当前令牌\n});\n```\n\n每个方法收一个 input 对象(含路径标识、查询字段,以及 POST 的 body;需要幂等键的操作还需 idempotencyKey),第二个参数可传 `{ signal }`。baseUrl 可含反向代理前缀,不能含账号口令、查询或 fragment。凭据、租户和主体只能由服务端验证;包不生成可信主体头。候选服务、权限、来源登记或生产身份链未配置时,服务端拒绝会原样返回。\n\n| 方法 | 已有接口 |\n|---|---|\n| `reviewMetricContract` | `POST /api/v1/metrics/contracts:review` |\n| `assessMetricEvolution` | `POST /api/v1/metrics/contracts:evolution` |\n| `registerMetricContract` | `POST /api/v1/metrics/contracts` |\n| `listMetricContracts` | `GET /api/v1/metrics/contracts` |\n| `getMetricContract` | `GET /api/v1/metrics/contracts/{metricId}` |\n\n返回值以 `kind` 区分:`response` 带 httpStatus 和原始 JSON 对象 body;`http-error` 带非 2xx 的 httpStatus/body;`client-error` 带 NOT_CONFIGURED / INVALID_CONFIG / INVALID_INPUT / ABORTED / TIMEOUT / TRANSPORT_FAILED / INVALID_RESPONSE。**HTTP 2xx 不代表业务放行**:调用者必须检查 body 的 decision / kind / outcome 等契约字段;REJECT 不会被改写为成功。输入体和业务响应保留 unknown,服务端仍为结构与业务校验权威,不承诺不存在的静态领域类型。\n\n可配置 timeoutMs(缺省 5000、覆盖取令牌及完整 JSON 读取)、requestId、traceparent、fetchImpl。合法 W3C traceparent 原样透传,无效时生成随机根。不自动重试写操作、不自动跟随重定向;需要的幂等键由调用方提供,不在每次重试中随机重造。未配置/非法配置及路径必填值缺失时不发请求;异常、超时和取消不会降级为放行。\n\n来源:`contracts/candidates/contracts/metric-contract-api.v1.openapi.json`。包内 `test/operations.json` 用于验证方法覆盖与实线路由;C17 的登记簿三项另对应当前控制器。验收 `pnpm test` 使用真实本地 HTTP stub,证明传输行为,不代替目标环境/RLS/消费者验收。构建 `pnpm build`;打包 `pnpm pack`。正式发布只能走仓库的受保护 CI 发布列车,满足同源码成功 CI、版本与 tag、分支保护和凭据前提后才能移入列车。\n","repository":{"type":"","url":""}}...
|
1
|
Edit
Delete
|
|
40
|
15
|
5
|
1.0.0-rc.7
|
1.0.0-rc.7
|
1791622775
|
0
|
{"scope":"@juhai","name":& {"scope":"@juhai","name":"client-enterprise-experience","description":"enterprise-experience 已有 HTTP 接口客户端;候选边界见 README;未配置即失败关闭","license":"UNLICENSED","development_dependencies":{"@types/node":"22.19.20","typescript":"5.9.3"},"readme":"# @juhai/client-enterprise-experience\n\nNode.js 20+ 的 HTTP 客户端,RC 列车版本 `1.0.0-rc.7`。发布状态以 Registry 中该 exact 版本及包内 provenance.json 为准;加入列车不代表真实消费者已完成接入。仅贡献登记及评审,来源签收和贡献展现结论由服务端返回;SDK 不授予操作执行权。\n\n传输实现内联,无运行时依赖,不导入私有 `@repo/*`、平台模块或其他客户端;没有对应内核端口,不声明虚假的 kernel peer。\n\n```ts\nimport { EnterpriseExperienceClient } from '@juhai/client-enterprise-experience';\nconst client = new EnterpriseExperienceClient({\n baseUrl: 'https://platform.example.com', // 入口,勿再附加 /api\n token: async () =\u003e currentAccessToken(), // 每次请求取当前令牌\n});\n```\n\n每个方法收一个 input 对象(含路径标识、查询字段,以及 POST 的 body;需要幂等键的操作还需 idempotencyKey),第二个参数可传 `{ signal }`。baseUrl 可含反向代理前缀,不能含账号口令、查询或 fragment。凭据、租户和主体只能由服务端验证;包不生成可信主体头。候选服务、权限、来源登记或生产身份链未配置时,服务端拒绝会原样返回。\n\n| 方法 | 已有接口 |\n|---|---|\n| `submitExperienceSource` | `POST /api/v2/experience/sources` |\n| `listExperienceSources` | `GET /api/v2/experience/sources` |\n| `getExperienceSource` | `GET /api/v2/experience/sources/{registrationId}` |\n| `approveExperienceSource` | `POST /api/v2/experience/sources/{registrationId}:approve` |\n| `signoffExperienceSource` | `POST /api/v2/experience/sources/{registrationId}:signoff` |\n| `retireExperienceSource` | `POST /api/v2/experience/sources/{registrationId}:retire` |\n| `reviewExperienceContribution` | `POST /api/v2/experience/contributions:review` |\n\n返回值以 `kind` 区分:`response` 带 httpStatus 和原始 JSON 对象 body;`http-error` 带非 2xx 的 httpStatus/body;`client-error` 带 NOT_CONFIGURED / INVALID_CONFIG / INVALID_INPUT / ABORTED / TIMEOUT / TRANSPORT_FAILED / INVALID_RESPONSE。**HTTP 2xx 不代表业务放行**:调用者必须检查 body 的 decision / kind / outcome 等契约字段;REJECT 不会被改写为成功。输入体和业务响应保留 unknown,服务端仍为结构与业务校验权威,不承诺不存在的静态领域类型。\n\n可配置 timeoutMs(缺省 5000、覆盖取令牌及完整 JSON 读取)、requestId、traceparent、fetchImpl。合法 W3C traceparent 原样透传,无效���生成随机根。不自动重试写操作、不自动跟随重定向;需要的幂等键由调用方提供,不在每次重试中随机重造。未配置/非法配置及路径必填值缺失时不发请求;异常、超时和取消不会降级为放行。\n\n来源:`contracts/contracts/experience-contribution-api.v2.openapi.json`。包内 `test/operations.json` 用于验证方法覆盖与实线路由;C17 的登记簿三项另对应当前控制器。验收 `pnpm test` 使用真实本地 HTTP stub,证明传输行为,不代替目标环境/RLS/消费者验收。构建 `pnpm build`;打包 `pnpm pack`。正式发布只能走仓库的受保护 CI 发布列车,满足同源码成功 CI、版本与 tag、分支保护和凭据前提后才能移入列车。\n","repository":{"type":"","url":""}}...
|
1
|
Edit
Delete
|
|
41
|
5
|
5
|
1.0.0-rc.7
|
1.0.0-rc.7
|
1791622779
|
0
|
{"scope":"@juhai","name":& {"scope":"@juhai","name":"client-fact","description":"可信事实受理客户端、事务 Outbox 与幂等 Inbox;Kafka 运输不影响领域契约","license":"UNLICENSED","dependencies":{"@prisma/client":"6.19.3"},"development_dependencies":{"@types/node":"22.19.20","typescript":"5.9.3","vitest":"2.1.9"},"peer_dependencies":{"@juhai/kernel":"0.24.0"},"readme":"# @juhai/client-fact\n\n事实干线(M5)的消费者 SDK:Outbox 投递 + Inbox 幂等/版本/Gap/DLQ 判定 + 可信回查。\n上层只允许 exact pin(`check:pins`),判定语义只在本包,**消费者不得复刻第二份**。\n\n本文记录的是**真实上层接入时踩过的坑**(数字员工基座 `os-employment-projection`,回灌台账 U-29 / U-31 / U-34)。\n平台自己的主线 e2e 用合成宿主表,这些坑在平台侧照不出来。\n\n---\n\n## 1. `baseUrl` 必须包含 `/api` 前缀(U-34)\n\n平台 NestJS 应用 `setGlobalPrefix(\"api\")`,而本包用**相对 URL** 解析端点:\n\n```ts\nnew URL(\"./v1/facts/intents\", baseUrl) // createFactPublisher 内部\n```\n\n因此:\n\n| baseUrl | 实际请求 | 结果 |\n| --- | --- | --- |\n| `https://host/api` | `https://host/api/v1/facts/intents` | ✅ 正确 |\n| `https://host` | `https://host/v1/facts/intents` | ❌ 404 |\n| `https://host/api/` | `https://host/api/v1/facts/intents` | ✅(结尾斜杠会被补齐) |\n\n**为什么这条必须写在契约里**:少写 `/api` 不会显式报错,而是让**所有**回查返回 404。消费者若把 404\n当成\"事实不存在\"交给 `FactInbox`,SDK 会判 `UNTRUSTED_FACT` → 计入毒消息 → 三次进死信。\n一个配置漏字母会把整条摄入变成全量死信,而日志读起来像是\"平台在篡改事实\"。\n\n**消费者必须区分三种情况,不要混进毒消息计数**:\n\n| 情况 | 应有处置 |\n| --- | --- |\n| 回查端点返回 404 | 该 fact 确实不存在 → 交 SDK 判 `UNTRUSTED_FACT`(正当的毒消息) |\n| 回查不可达 / 5xx / 超时 | **抛错**,保留 broker offset 等待恢复;不要返回 null |\n| 未配置回查地址 | **失败关闭**:每次调用都拒绝,绝不\"跳过校验\" |\n\n平台 e2e 里 `baseUrl = http://127.0.0.1:${port}/api` 曾是这条约定唯一的载体(一行测试赋值)。\n\n## 2. 迁移模板只给表,授权与策略绑定由消费者补齐(U-31)\n\n`migrations/001_outbox_inbox.sql` 建五张表并对每张表 `ENABLE + FORCE ROW LEVEL SECURITY`,\n策略为:\n\n```sql\nCREATE POLICY tenant_isolation ON %I\n USING (tenant_id = current_setting('app.current_tenant_id', true))\n WITH CHECK (tenant_id = current_setting('app.current_tenant_id', true));\n```\n\n**模板的两个边界,照抄前必须知道**:\n\n1. **策略没有 `TO \u003crole\u003e` 子句** ⇒ 对 PUBLIC 生效。消费者若有 system / 后台角色需要跨租户扫描\n (补 gap、重放、运维对账),它同样���被这条策略挡住——除非该角色 `BYPASSRLS`,\n 而 `FORCE ROW LEVEL SECURITY` 下表属主也不豁免。\n2. **模板不含任何 `GRANT`**。消费者库若用独立的低权限运行角色(而不是表属主连接),\n 照抄模板后该角色对这五张表**没有任何权限**,摄入会直接失败。\n\n**契约**:表 DDL 逐字照用(列名与主键是 SDK 的 SQL 依赖,改了就对不上);\n`GRANT` 与策略的角色绑定**由消费者按自身角色模型补齐**,作为自己的增量迁移。\n参考实现见数字员工基座的 `20260928010000_platform_client_fact_inbox`(tenant / system 两角色 + 逐表显式 GRANT)。\n\n## 3. 处理结果与 rc.3 的行为变更(U-29)\n\n`FactInbox.handle()` 的返回值:\n\n| 返回 | 含义 |\n| --- | --- |\n| `APPLIED` | 首次应用,投影已写 |\n| `DUPLICATE` | 同 `fact_id` 重投,单次效果(digest 不一致则抛 `PROCESSED_FACT_CONFLICT`) |\n| `STALE` | 版本 ≤ 水位,不写投影 |\n| `GAP` | `previous_version ≠ 水位`,落 gap 缓冲等补齐 |\n\n\u003e **`1.0.0-rc.3` 起的行为变更**:`STALE` 之前**不可达**——版本落后时本包抛\n\u003e `FactRejected(\"UNPROCESSED_VERSION_BEHIND_WATERMARK\")`,而 `handle` 把任何 `FactRejected`\n\u003e 计入 attempts,于是至少一次投递下的**正常迟到重投**三次即被打进死信,与\"内容有毒\"共用一套判据。\n\u003e rc.3 改为返回 `\"STALE\"`,并顺手删掉该 fact 可能留在 gap 缓冲里的副本(落后事实永远等不到\n\u003e `previous_version = 水位`,留着只会把缓冲占满到 `GAP_BUFFER_FULL`,drain 循环也会空转)。\n\u003e\n\u003e 消费 rc.2 及更早版本的上层需要在边界做\"错误码 → 结果词\"的翻译;**升到 rc.3 后应删除该翻译**,\n\u003e 判定回到 SDK 单源。\n\n## 4. 写链边界\n\n`appendFactIntent` 必须在**属主自己的业务事务内**调用——它与业务写同 tx,事务回滚则事实意图一并回滚。\n`FactInbox.handle` 同理在消费者事务内完成 `processed_fact` + 投影 + 水位的原子写入。\n本包不提供事务,也不管理连接:宿主传入符合 `FactTransaction` 结构的 tx 即可(不要求宿主生成 Prisma schema)。\n\n出站 Outbox 还需依次安装 `migrations/001_outbox_inbox.sql` 与 `002_outbox_delivery.sql`。中继只选\n`exported_at IS NULL AND dead_lettered_at IS NULL AND next_attempt_at \u003c= now()` 的行;M5 明确的永久拒绝码写入\n`dead_lettered_at` 并继续处理下一行,依赖故障写入 `attempts / next_attempt_at / last_error_code` 后退避。\n`relayFactIntents` 的 `onFailure` 回调可用来告警,但它不是持久告警队列;运维必须监测死信行。\n\n处置死信时先核对 `last_error_code`、M5 的租户 / Fact 登记和原始事实内容。修正根因后,按租户在 Owner\n库事务内重排**同一个** `fact_id`,不要改写 `submission` 或 `digest`;M5 对同 ID 同内容的重复受理是幂等的:\n\n```sql\nBEGIN;\nSET LOCAL app.current_tenant_id = '\u003ctenant_id\u003e';\nUPDATE platform_client_fact_outbox\nSET dead_lettered_at = NULL, next_attempt_at = clock_timestamp(), last_error_code = NULL\nWHERE tenant_id = '\u003ctenant_id\u003e' AND fact_id = '\u003cfact_id\u003e'\n AND dead_lettered_at IS NOT NULL AND exported_at IS NULL\nRETURNING tenant_id, fact_id, attempts;\nCOMMIT;\n```\n\n确认 `RETURNING` 恰有一行,再观察同一行 `exported_at` 和 M5 回执;若再被拒绝,保留新增的拒绝码与尝试次数。\n\n## 5. 可信回查读取器 `createFactReader`(候选)\n\n\u003e 本节为 `3074b75` 引入的读取面文档,原文保留(英文),与上面三节的接入契约互补:\n\u003e 上面讲「接进来会踩什么」,本节讲「读取器本身怎么用、边界在哪」。\n\n```ts\nconst reader = createFactReader({\n baseUrl: \"https://platform.example/api\",\n tenantId,\n token: getConsumerBearer,\n});\nconst inbox = new FactInbox({\n tenantId, consumerId, tenant: consumerTenantTransaction,\n trustedLookup: reader.lookup,\n apply: applyOwnerFact,\n});\n// On shutdown: stop consumer delivery, then reader.close().\n```\n\nThe server binds the verified JWT tenant/application/subject to one enrolled consumer. It checks the persisted consumer's activation and source-domain/fact-type scope on every lookup. `replayAllowed` is not required for point lookups; replay remains a separate operation. The candidate server is enabled only with `PLATFORM_FACT_READ_ENABLED=1` in development/test with JWT, `DATABASE_URL_FACT`, and an exact `FACT_READERS_JSON` list of `{tenantId,appId,subject,consumerId}`. It can run independently of intake and relay. Production/default assembly remains unavailable pending CHG-004 and live service identity integration.\n\nThe reader uses HTTPS (HTTP only on literal loopback/localhost), denies redirects and URL credentials, and bounds token/fetch/body processing to 5 seconds and 128 KiB by default. It verifies tenant/id/ordering/receipt and the canonical submission digest. It does not cache authorization or facts. A typed M5 `FACT_NOT_FOUND` returns null; all other transport/authentication/integrity errors throw `FactReadUnavailable`, which is deliberately distinct from `FactRejected`. Dependency failures must retain the Kafka offset and must not increment poison counters. `close()` aborts active lookups and rejects future ones; callbacks that ignore cancellation may continue internally but cannot produce an accepted lookup.\n\nA deactivated or deleted consumer registration answers 403, which the reader turns into a retryable `FactReadUnavailable`: the Kafka offset is kept and nothing is counted as poison. A registration that is still active but no longer covers the fact's source domain or type answers the same 404 as an unknown id, which is a null lookup and therefore `UNTRUSTED_FACT` — a dead letter. Narrowing `sourceDomain`/`factTypes` on a live consumer will dead-letter facts that are already in flight, while deactivating the same consumer only pauses it. Deactivate first, change scope, then reactivate; treat a scope edit as a migration, not as a switch.\n\nThe server refuses a bearer carried in the query string (`FACT_READ_URL_CREDENTIAL_REFUSED`, 401) even when a valid `Authorization` header is also present, because the token has already reached the proxy access log by then. The reader never produces such a URL; the refusal exists for anything else that calls the surface.\n\nAn authenticated M5 response plus the receipt digest is the trust boundary here, not a cryptographic signature proving the Owner. A compromised M5 authority or whole-row rewrite with a recomputed digest is outside this reader's detection. Kafka self-asserted hashes are never sufficient. Consumers still need the Owner's domain validation, bootstrap watermark reconciliation and appropriate action enforcement.\n","repository":{"type":"","url":""}}...
|
5
|
Edit
Delete
|
|
42
|
16
|
5
|
1.0.0-rc.7
|
1.0.0-rc.7
|
1791622783
|
0
|
{"scope":"@juhai","name":& {"scope":"@juhai","name":"client-identity","description":"企业 IdP human access token 消费者:固定信任、JWKS 缓存、严格 claims 与 UserInfo 撤销回查","license":"UNLICENSED","dependencies":{"ajv":"8.20.0","jose":"6.2.10"},"development_dependencies":{"@juhai/kernel":"0.24.0","@types/node":"22.19.20","typescript":"5.9.3","vitest":"2.1.9"},"peer_dependencies":{"@juhai/kernel":"0.24.0"},"readme":"# @juhai/client-identity\n\nPF-07 阶段 2 ⑥:企业 IdP **human access token** 的框架无关消费者。Node.js ≥ 20.19,ESM。\n服务身份 / AI Token、IdP 模块迁移和应用接线仍是后续工作;本包不签发 Token、不实现权限引擎。\n\n```ts\nimport { createIdentityClient } from \"@juhai/client-identity\";\n\n// 在应用装配时创建一次,issuer 和 audience 来自受控配置。\nconst identity = createIdentityClient({\n issuers: [\"https://idp.example.com/t/acme\"],\n audience: \"my-app\",\n});\nconst result = await identity.verifyHumanAccessToken(accessToken, {\n tenantId: requestTenantHeader, // 可选,只与签名值比较,绝不作为租户来源\n requiredScopes: [\"openid\", \"material.read\"], // 路由声明,非请求体输入\n});\nif (!result.ok) return reply.status(result.status).send({ code: result.code });\n// HTTP、WS、SSE 适配器共同使用这一身份结果,不能自行解码 JWT 生成 principal。\nconst principal = result.identity;\n```\n\n每次成功都经过:固定 issuer map → 真实 RS256 签名 → 原始消费者 JSON Schema → 单值 audience / 时间 /\nscope 去重 / 租户与主体绑定 → 同 issuer 的 **`/oidc/userinfo`** 权威回查。公钥地址为\n`/oauth2/jwks`;两个路径取自当前 IdP Controller 与 Discovery 实现。UserInfo 要求 Token 含 `openid`。\n不采用请求输入中的 discovery URL、`jku` 或 `x5u`,不跟随重定向,不缓存 Token 的有效结论。\n\nJWKS 默认缓存 60 秒、未知 kid 刷新冷却 30 秒,单次 HTTP 超时 2 秒;密钥过期且上游不可用时失败关闭。\n轮换须先发布新公钥,再签新 Token,旧公钥覆盖存量 Token 生命周期。上游 UserInfo 401/403 → 本地 401;\n上游不可达、5xx、畸形响应或 subject 不一致 → 503。缺信任配置 → 503;Token/租户校验失败 → 401;\n主体冒充或缺路由要求的 scope → 403。只返回稳定错误码,不返回凭据、JOSE 原始错误或 UserInfo PII。\nHTTP 仅允许显式 `allowLoopbackHttp: true` 的回环开发地址;生产 issuer 使用 HTTPS。\n\n该回查证明**本次请求时** IdP 用户、会话、授权与 client 仍有效。它不自动关闭���建立的 WS/SSE,\n也不宣称实现跨应用撤销事件、快照缓存或 p95 SLA;调用方须重新校验长连接,后续再接权威失效流。\n额外 `roles` / `permissions` claim 不被映射为权限;此 API 不能将 human Token 提升为 service/AI。\n\n## 契约来源与发布边界\n\n`src/access-token.v1.schema.json` 原样导入现有 E0 消费者契约,是本包结构校验唯一来源;\n12 条原始夹具在 `runtime/modules/identity/test/fixtures/access-token.v1.fixtures.json`,\n文件摘要与来源见 `contract-import.json`。测试读取该套夹具,用本轮真实 RSA 密钥签名并经 HTTP 执行,\n不是只运行 JSON 分类器。原材料里的 pending 描述按导入快照保留,不作为最新裁决状态。\n\n该 profile 尚未登记为 `@juhai/contracts` 可导出的正式契约,因此本批不虚加该包依赖;\nCatalog 登记及新版本发布后,应改用其导出并移除临时副本。peer `@juhai/kernel` exact 0.24.0 保持 SDK\n版本约束,但内核当前没有 IdentityPort,本包不伪造 `createRemote\u003cPort\u003ePort` 或更改内核端口签名。\n包可构建/打包不等于已发布,Release Manifest 中非 null 也不代表应用接入或 PF-07 全部完成。\n\n## 验证\n\n`pnpm --dir runtime --filter @juhai/client-identity build`;`test` 使用临时回环 HTTP server,\n覆盖原始 12 条夹具、签名不符、JWKS 轮换与冷却、撤销、配置错误、超时、重定向、过期及主体冒充。\n这些测试不替代真实 IdP 数据库/浏览器验收,模块迁移后须再走实际登录与吊销链路。\n\nPF-08 canonical 切换:消费者额外要求 tenant_id 为 DEC-032 的 ten_ ULID,旧 UUID / 旧别名即使签名有效也拒绝。原始导入夹具与摘要保留;当前实现验收使用 `runtime/modules/identity/test/fixtures/canonical-access-token.fixtures.json`,同样保留原有签名、aud、scope 和头部拒绝场景,只将合法租户样本改为 canonical。此处只收紧标识格式,实时授权仍经 UserInfo 核验;实际 HR/OS 接入与正式分发版本另行交付。\n\n\nPF-08 候选解析客户端 `createTenantMappingClient({ issuers, timeoutMs })` 从固定 HTTPS issuer 列表选择 `/identity/tenant-resolution`。调用 `resolve(machineToken, { issuer, tenantRef, expectedCanonicalId })`;两项 canonical 必须一致,`expectedCanonicalId` 由宿主已验签的身份上下文提供。服务端检查 `idp:tenant:resolve` 及其配置的租户内 Application audience,不使用请求体提供的主体、应用或期望身份。\n\n客户端拒绝旧别名、重定向、超大响应、错误身份/版本/TTL,期限覆盖响应体,映射不缓存;未配置或依赖故障失败关闭。这里返回身份映射而非权限决策,机器 Token 验签与当前授权由下述独立机器身份客户端负责。协议仍为 CHG-004 候选,Registry 发布和真实 HR/OS 接入单独推进。旧别名只由管理面/迁移工具在明确到期窗口内解析,业务客户端不开放该选项。\n\n## 机器身份消费者(候选)\n\n`createMachineIdentityClient({ issuer, audience, authenticate })` 专门接受 M1 签发的 service/job access token。\n`audience` 必须是接收服务的 M1 Application.id;`authenticate(signal)` 提供接收服务自身的\n`client_secret_basic` 凭据或新生成的 `private_key_jwt` assertion。当前 M1 assertion audience 为\n`${issuer}/oauth2/token`,包括 introspection;不能重用旧 assertion,也不能用人类 Bearer 代替服务凭据。\n\n每次调用 `verifyMachineAccessToken(token, { tenantId, subject, appId, actorType, requiredScopes })`\n均从固定 issuer 读取公钥、验证 RS256 与精确声明,再通过经过服务认证的 introspection 查询当前令牌、\n授权和主体版本。无有效结论缓存,撤销后的下一次调用拒绝。错误令牌返回 401;请求主体/租户/应用/\n作用域不匹配返回 403;M1 或接收服务凭据不可用返回 503。只返回稳定错误码。\n\n整个公钥读���、验签、取接收服务凭据和 introspection 响应体共享默认 2 秒截止时间,每个响应最多\n64 KiB,禁止重定向。`close()` 取消进行中的调用并拒绝后续调用。忽略取消的外部回调可能继续运行,\n但迟到凭据不能发起 introspection,也不能产出成功结果。机器客户端暂不缓存公钥;不据本地小样本推断容量。\n\n返回的 `tenantId` 必须是 M1 当前令牌中的 canonical 标识;旧 UUID、别名和非法 ULID 即使签名有效也拒绝,客户端不推断或改写映射。\n`authorizationVersion` 与 `serviceVersion` 分别返回,调用方不得忽略主体撤销版本或自行拼接为授权。\n本组合包含 canonical Token 与候选解析实现;完整组合验收另行取得。M2 租约适配、真实 HR/OS 接入、生产凭据注入和长连接关闭仍需独立完成。\n真实 NestJS M1 + 普通角色 PostgreSQL 的 SDK 验收在 `runtime/test/e2e/identity-machine-client.test.ts`;\n它也生成单独的 `reports/machine-revocation-sla.latest.json`,不替代 Employment/Scope 撤权报告。\n\n### 宿主机器鉴权接缝(KI-2)\n\n`parsePlatformMachineTrust` / `createPlatformMachineVerifier` 供 NestJS、Fastify 宿主统一使用。\n仅从固定 issuer map 选择既有机器 SDK,成功结果分别保留 `clientId` 与 `applicationId`,逐次实时 introspection;\n机器声明不会回退旧 JWT 验证。配置、Fact Scope 与租户内应用映射见仓根\n[IdP 与事实通道接缝参考](../../../docs/integration/IdP与事实通道接缝参考-KI-1-KI-3.md)。这些新增导出尚未发布到 Registry。\n","repository":{"type":"git","url":"git@gitea.g-hi.com:luoanwu/enterprise-platform.git"}}...
|
62
|
Edit
Delete
|
|
43
|
17
|
5
|
1.0.0-rc.7
|
1.0.0-rc.7
|
1791622787
|
0
|
{"scope":"@juhai","name":& {"scope":"@juhai","name":"client-notification-webhook","description":"通知与 Webhook 中心远程客户端:把 notification-delivery-api.v1 的六个操作实现为对平台端点的调用;未配置即失败关闭(DEC-040 升格后由副作用半边改写而来)","license":"UNLICENSED","development_dependencies":{"@types/node":"22.19.20","typescript":"5.9.3","vitest":"2.1.9"},"readme":"# `@juhai/client-notification-webhook`(远程客户端)\n\nDEC-040 将路由、签名、重放防护和投递副作用迁入 `runtime/modules/notification-webhook`。本包调用 `notification-delivery-api.v1`,消费者只提交业务意图,不持有外发端点、主机白名单或签名密钥。\n\n未配置 `baseUrl`、传输失败、远端非 2xx、响应形状不合法或平台拒绝时均失败关闭。\n\n## 六个操作\n\n| 导出 | 作用 |\n|---|---|\n| `classifyEffect` | 判定重复投递、重放授权和尝试次数上限 |\n| `classifyProviderOutcome` | 将供应商结果分类为送达、重试、死信或永久失败 |\n| `planDelivery` | 从已批准策略取得路由计划 |\n| `refreshPolicy` | 提交策略快照换版 |\n| `deliver` | 幂等受理业务投递意图并由平台立即执行一次真实外发 |\n| `deliveryStatus` | 按当前租户读取安全裁剪后的投递状态与回执 |\n\n判定规则位于 `contracts/src/domain/notification-webhook/`,真实外发与 v2 HMAC 协议位于 `runtime/modules/notification-webhook/src/delivery/`。本客户端不实现内核端口,也不包含本地外发后备路径。\n\n## 当前交付状态\n\n- Catalog 仍为 `candidate_e0 / E0`,模块等级没有因本次验收自动提升。\n- 2026-09-23 已完成工单、巨嗨智服与巨嗨报价三个消费者的真实跨仓验收:实际通知任务调用平台 HTTP,平台按权限和已批准路由取测试凭据,完成 HTTPS v2 HMAC 外发、回执和双方账本状态回写。\n- 三消费者门槛当前为 3/3;生产启用仍等待 OpenBao、服务身份和目标策略。\n- 生产 `DeliveryCredentialResolver` 仍等待 OpenBao。测试凭据只在 `NODE_ENV=test` 下显式启用,不能作为生产后备路径。\n- 客户端包已登记但尚未进入发布列车。三个消费者使用各自仓内适配器调用同一平台契约,未依赖未发布包。\n\n## Webhook 签名协议\n\n当前协议为 v2:对 `JSON.stringify([\"v2\", timestamp, nonce, tenantId, idempotencyKey, body])` 做 HMAC-SHA256,把租户、幂等键、nonce、时间和原始正文一起绑定。v1 请求失败关闭;验签成功后才原子消费 nonce。\n\n## 后续缺口\n\n- 用 OpenBao / ServiceCredential 实现生产凭据解析并激活 `delivery-retry`。\n- 将客户端加入发布列车。\n- 邮件、短信等非 Webhook Provider 仍未覆盖。\n","repository":{"type":"","url":""}}...
|
1
|
Edit
Delete
|
|
44
|
18
|
5
|
1.0.0-rc.7
|
1.0.0-rc.7
|
1791622792
|
0
|
{"scope":"@juhai","name":& {"scope":"@juhai","name":"client-permission","description":"权限决策远程客户端:把内核 PermissionDecisionPort 实现为对基础设施 permission-decision-api.v1(POST /v1/decisions)的调用;未配置退回内核 fail-closed,传输失败一律拒绝(基础设施开发设计方案 §9 client-*;开发计划 §3A CL-3)","license":"UNLICENSED","development_dependencies":{"@juhai/kernel":"0.24.0","@types/node":"22.19.20","typescript":"5.9.3","vitest":"2.1.9"},"peer_dependencies":{"@juhai/kernel":"0.24.0"},"readme":"# @juhai/client-permission\n\n内核 `PermissionDecisionPort`(`@juhai/kernel@0.24.0`,peer exact)的远程实现:调用基础设施已登记契约\n`permission-decision-api.v1`(`POST \u003cbaseUrl\u003e/v1/decisions`)。设计:基础设施开发设计方案 §9 / 横切 X01;工作项:开发计划 §3A CL-3。\n\n```ts\nimport { createRemotePermissionDecisionPort } from \"@juhai/client-permission\";\n\nconst permission = createRemotePermissionDecisionPort({\n baseUrl: \"https://platform.example/api\", // 含 /api 前缀;路径固定 /v1/decisions\n clientId: \"hr-web\", // 契约 actor.client_id\n token: () =\u003e currentAccessToken(), // Bearer\n actor: (req) =\u003e ({ actor_type: \"human\", authentication_method: \"oidc\" }),\n invalidations: revocationFeed, // DEC-019 / DEC-029 门后由 M3 提供\n});\nregistry.replace({ ...registry.current(), permission });\n```\n\n| 情形 | 决策 |\n|---|---|\n| 未配置(无 `baseUrl` / `clientId`) | 返回内核 fail-closed 端口对象本身(`isFailClosedPort` 为真) |\n| 内核请求 schema 不通过 / 资源类型或动作无法映射为契约形状 | 拒绝 `INVALID_REQUEST`,不打远端 |\n| 无租户上下文 | 拒绝 `NO_TENANT_CONTEXT`,不打远端 |\n| 网络错误 / 完整调用超时(取凭证、传输、读取响应体合计,缺省 2 s)/ 5xx | 拒绝 `REMOTE_UNAVAILABLE` |\n| 401 / 403 / 其它 4xx | 拒绝 `REMOTE_REJECTED` |\n| 200 但不是 `permission-decision-response.v1` 形状 | 拒绝 `INVALID_RESPONSE` |\n| 200 放行且未过期 | `allowed=true`,有效期取服务端截止时间与接收时间 + TTL 的较早值,防止服务端时钟超前延长缓存;只缓存 ttl \u003e 0 的放行(LRU,缺省 1000 条) |\n| 放行到达时已过期(含截止时间相等) | 拒绝 `DECISION_EXPIRED`,本次调用与缓存均不得放行 |\n| TTL = 0 | 本次可放行、`expiresAt=null`,不缓存 |\n| 200 拒绝 | `allowed=false`,`reasonCode` = 契约 `reason_code`(不缓存) |\n| 请求在途收到主体/租户/全局失效,或客户端关闭 | 延迟放行返回 `DECISION_INVALIDATED`,不写回缓存;关闭后不再发起请求 |\n| actor / Scope 映射回调失败 | 拒绝 `REMOTE_UNAVAILABLE`,不会复用旧放行 |\n\n缓存按应用、映射后的主体/会话/认证属性、Scope 版本、资源和动作隔离;显式提供的认证时间也参与缓存键。\n使用结构化键,不用标识符分隔符拼接。失效按准确的租户和主体匹配,同时覆盖已完成和在途请求。\n`authenticated_at` 未提供时生成的请求时间不参与缓存键,避免默认请求时间使缓存失效。\n取凭证回调可接收 `AbortSignal`;忽略信号的依赖也不会阻止客户端在截止时间内返回。\n失效和 `close()` 会取消匹配的在途请求;关闭幂等,超时后迟到的凭证不会再发起远端调用。\n\n映射约定:内核 `resourceType` 须是点号命名空间(如 `hr.employment`),无点号类型可用 `resourceTypePrefix` 补;内核 `action`\n去掉 `\u003cresourceType\u003e.` 前缀后取单段(装配点按 `\u003cresource.type\u003e.\u003caction\u003e` 还原);`trace_id` 无合法 traceId 时生成;\n`request_id` / `correlation_id` 用内核 `requestId`;`causation_id` 用 `factId`。\n\n端口一致性:`runtime/test/port/clients.test.ts` 用 S-6 共用夹具对 stub server(拒绝一切 / 目录式放行 / 不可达)跑本包;\n真实链路:`runtime/apps/api-nestjs/test/platform.http.acceptance.test.ts` 用本包打装载 permission 模块的应用。\n# Authenticated invalidation cursor feed (candidate)\n\n`createRemotePermissionInvalidationSource({ baseUrl, tenantId, actorId, token })` reads the M3 cursor feed over HTTP. Pass it as `invalidations` to `createRemotePermissionDecisionPort`, call `await source.start()`, and close both the decision client and source during shutdown. The token must authenticate the same tenant/actor; it is fetched on every request and never put in the URL.\n\nThe default interval is 1000 ms. The source invalidates tenant caches on initial subscription, disconnect, reconnect, reset and close, preserving its cursor on failures. `stats()` exposes cursor, health and request/failure counts without credentials. `start()` waits for the first response, not all historical pages; pending historical invalidations may reject an in-flight allow. No cached allow should be treated as immune to invalidation.\n\nThe new `/v1/decisions/invalidations` extension is pending contract review. Server activation currently requires explicit development/test configuration; it is not enabled in production. The HTTP source is a reusable implementation, but production rollout, load and employment Scope enforcement remain unverified.\n\n## 稳定应用身份与 Owner 联合接入\n\n机器调用的 `clientId` 是 OAuth 凭证标识(例如 `srv_…`);请求上下文的 `appId` 使用 IdP 登记的稳定 Application ID。服务端从已经验签并经过内省的 `applicationId` 匹配 Grant,不接受请求体声明应用身份。普通 OIDC 的旧 `clientId` 授权匹配保持兼容。机器令牌主体、凭证 ID、主体类型仍须匹配。\n\nledger 的放行响应 `policy_version=permission-ledger:\u003csha256\u003e`,摘要来自本次读取的动作、有效 Grant 和 tenant/actor 失效版本;未完成策略读取的拒绝仍返回提供方名。它是决策输入证据,不是新业务授权。`scope_version=tenant-only` 明确表示这里只核验 tenant 动作授权,调用方的 Scope 版本不作为服务端已验证证据。\n\n对象访问使用 `createScopedPermissionDecisionPort`,把远程动作授权与已经签名验证的 Scope evaluator 接到同一个执行入口:\n\n```ts\nimport { createRemotePermissionDecisionPort, createScopedPermissionDecisionPort } from \"@juhai/client-permission\";\n\nconst permission = createScopedPermissionDecisionPort({\n permission: createRemotePermissionDecisionPort({\n baseUrl, clientId: serviceClientId, token: currentAccessToken,\n }),\n scope: verifiedScopeClient, // client-scope 的本地 evaluator 或远程 snapshot client\n resolveBinding: async (request, signal) =\u003e owner.loadCurrentBinding(request, signal),\n});\n```\n\nOwner 解析器必须从已认证上下文和权威记录返回绑定,包含 `tenantId/resourceTenantId/actorId/appId/resourceType/resourceId/action`、组织范围、`operation/highRisk/requiredVersion` 及覆盖岗位和资源映射的 `bindingVersion`。禁止直接照搬 HTTP body 的组织 ID、风险标志或绑定版本。实际读写必须使用同一资源 ID;业务写事务还须按 Owner 的锁或版本检查维持这份绑定,否则决策与执行之间仍可能发生变更。\n\n入口先检查绑定与范围,再获取动作决策,然后重读绑定并重新检查 Scope。租户、主体、应用、资源或动作错位、版本变化、过期、需要 live review、依赖超时或异常均拒绝。默认总时限 2 秒,忽略取消信号的依赖也受限。返回的放行 `expiresAt=null` 仅用于本次操作;不要另行缓存联合结果。持久化模块中的非 tenant 动作仍拒绝,联合入口不会把其扩大为 tenant Grant。高风险范围仍需已获批准的在线核验实现。\n\n真实链路回归位于 `runtime/test/e2e/identity-permission-http.test.ts`,使用隔离 SQL、真实 IdP 签名与内省,以及 Ed25519 签名 Scope;测试数据不进入企业授权。\n","repository":{"type":"git","url":"git@gitea.g-hi.com:luoanwu/enterprise-platform.git"}}...
|
6
|
Edit
Delete
|
|
45
|
19
|
5
|
1.0.0-rc.7
|
1.0.0-rc.7
|
1791622796
|
0
|
{"scope":"@juhai","name":& {"scope":"@juhai","name":"client-public-file","description":"公共文件平台远程客户端:把 public-file-object-api.v1 的四个操作实现为对平台端点的调用;未配置即失败关闭(DEC-040 升格后由副作用半边改写而来)","license":"UNLICENSED","development_dependencies":{"@types/node":"22.19.20","typescript":"5.9.3","vitest":"2.1.9"},"readme":"# `@juhai/client-public-file`\n\n公共文件能力的**带副作用那半**:`PublicFileRef v1` 构造与路径安全判定、S3 兼容对象存储适配、clamd `INSTREAM` 扫描、按环境装配基础设施。\n\n**纯规则那半不在本包**,在 `contracts/src/domain/public-file/`(`public-file-access-planner.ts` 的授权版本回退与签名 URL 过期判定等,2026-09-14 迁入)。两半的分工就是设计方案 §5 的形态划分:契约包只放 Schema 与校验器,副作用留给适配器。\n\n## 来源与迁入\n\n逐字迁自工单仓 `packages/attachments/src/`(453 行实现 + 69 行单测 + 35 行真实基础设施验收),2026-09-18 按目录负责人「直接搬」的 G4 裁决执行。迁入**不改一行判定逻辑**:8 例单测与 1 例真实验收原样随迁,在本仓更严的 `tsconfig.base.json`(含 `noUncheckedIndexedAccess`)下一次编译通过,8/8 绿、1 例按 `ATTACHMENT_REAL_ACCEPTANCE` 跳过(与原仓同一门槛)。\n\n迁入前这份实现在工作区里有**三份复制**:工单仓(本包来源,453 行,含存储与扫描)、巨嗨报价 `packages/public-file/src/ref.ts`(91 行)、嗨赞造意 `packages/public-file/src/ref.ts`(82 行)。后两份只抄了 ref 那一段,且**已经语义分叉**——嗨赞造意那份长出了 `assertPublicFileRef`(把收到的 ref 按 owner 字段重建再比对 `storageRef`),报价那份没有;入参防御也不同(嗨赞造意先判 `typeof value !== \"string\"`,报价直接 `.trim()`,非串抛 TypeError 而不是稳定错误)。**同一个 PublicFileRef v1,两个应用对「外来 ref 可不可信」给的答案不一样**——这正是本次搬迁要终结的东西。\n\n## 接口\n\n| 导出 | 作用 |\n|---|---|\n| `createPublicFileRef` / `assertSafeStorageRef` | 构造版本化、按 app + tenant 隔离的 `storageRef`;拒绝 `.` / `..` / 控制字符 / 绝对路径 / 反斜杠 |\n| `S3AttachmentStorage` | 预签名上传(15 min)/ 下载(5 min)、`HeadObject` 事实回读、幂等删除;每个入口先过 `assertSafeStorageRef` |\n| `ClamAvScanner` | clamd `zINSTREAM` 分块投喂;响应超 4 KiB、超时、连接错误一律判 `FAILED` 而不是放行 |\n| `MemoryAttachmentStorage` / `DeterministicAcceptanceScanner` | 验收替身;`createAttachmentInfrastructure` 在 `NODE_ENV=production` 下拒绝 memory 模式 |\n| `assertAttachmentInfrastructureConfig` | 生产必须 HTTPS + 显式 host allowlist + 成对凭证;本机有显式默认值 |\n| `inspectAttachmentContent` / `contentTypeMatches` | 魔数嗅探与 OOXML↔zip 容器匹配,防止声明类型顶替真实类型 |\n\n## 与其他 `@juhai/client-*` 的不同\n\n本包**不实现任何内核端口**,因此没有 `@juhai/kernel` 的 peer 依赖,也不在 `runtime/test/port/platform-ports.conformance.ts` 的三画像范围内——那套夹具是给「端口的远程实现」用的,本包没有远端可调(公共文件的运行服务 `file-service` 按设计要 G4 之后才从 SDK 升格)。它落在 `clients/` 是因为这里是本仓对外发布、供上层 exact pin 的那一面,形态判据见 `../README.md`。\n\n## 未做(不在本轮范围)\n\n- **四个消费者尚未改接本包**:工单仓仍用自己的 `@repo/attachments`,巨嗨报价与嗨赞造意仍各用自己的复制。改接的前提是本包发布到 Gitea Registry,而发布通道自 2026-09-18 起只剩 CI 一条路、卡在 GitHub 计费。\n- **Catalog 登记未动**:`public-file` 仍 `module_e2 / E2`,`code_truth` 仍指工单仓 `packages/attachments`。代码搬过来不等于登记跟着翻——那是受控字段变更,须走 CHG。\n- **`assertPublicFileRef` 未补**:嗨赞造意那份长出来的校验函数本包没有。它是三份里唯一的语义增量,合并与否应由公共文件 Owner 裁,不在「搬」的范围内。\n","repository":{"type":"","url":""}}...
|
1
|
Edit
Delete
|
|
46
|
20
|
5
|
1.0.0-rc.7
|
1.0.0-rc.7
|
1791622799
|
0
|
{"scope":"@juhai","name":& {"scope":"@juhai","name":"client-scope","description":"Versioned signed Scope snapshots and shared local membership evaluation; no organization authority or grants","license":"UNLICENSED","development_dependencies":{"@juhai/kernel":"0.24.0","@types/node":"22.19.20","typescript":"5.9.3","vitest":"2.1.9"},"peer_dependencies":{"@juhai/kernel":"0.24.0"},"readme":"# @juhai/client-scope\n\nNode.js SDK for signed organization / department / team closure snapshots. Snapshot and bootstrap wire formats remain `pending-dec` candidates until CHG-004 approval. The snapshot HTTP reader/poller is available only through explicit development/test candidate assembly. Owner enrollment, action grants and production activation are separate prerequisites.\n\n`createLocalScopeEvaluator` pins M4 Ed25519 public keys to a tenant and catalog version. Install an authenticated signed snapshot, then evaluate membership with trusted Owner actor/resource bindings. The caller must also obtain an M3 action decision. Never accept `actorOrganizationId` or `resourceOrganizationId` directly from request claims without the Owner binding check.\n\nInstallation validates the signature, digest, canonical IDs, interval bounds and monotonically increasing publication versions. `invalidate(dimension, minimumVersion)` fails closed until a sufficiently new publication is installed. Local reads use the last verified snapshot until TTL expiry; stale self/tenant policies intersect the original range and never expand it. Expired writes deny. High-risk and integrity-rollback evaluations require live review. Known future relation changes bound old rows' lifetime even for stale reads.\n\nThe shared conformance fixture is `runtime/test/fixtures/scope-conformance.json`; M4 and SDK test the same expected memberships. M4 stores verified Owner input and separate staged/published snapshots, without owning the Organization tree. The M4 HTTP reader is bound to an explicitly enrolled tenant/application/subject. A reachable server freeze/erasure denies snapshot reads and clears the remote SDK cache; disconnected SDK instances retain only their existing local policy and original expiry. Owner Fact ingestion and the high-risk live resolver remain pending.\n\n\n`createRemoteScopeClient` fetches `/api/v1/scope/snapshots/:dimension` with Bearer authentication, pinned M4 public keys, a 2 s end-to-end deadline and a 32 MiB body bound. HTTPS is required outside loopback. `start()` polls every 1000 ms by default; `refresh()` is a single coalesced attempt. Identity/key configuration is copied at construction. No token or arbitrary provider error is retained in stats.\n\nAn identical signed publication may be fetched again without renewing its expiry. A lower publication version or a changed payload at the same version clears membership. `invalidate(minimumVersion)` also rejects an older in-flight response. The monotonic high-water mark survives a cache discard within the client instance; process restarts still need trusted current server state/external checkpoints.\n\n`subscribe()` is structurally compatible with the permission SDK invalidation source: new Scope versions and unavailable/invalid responses drop the tenant's cached action decisions. Transport/5xx failures preserve the Scope last-known-good data only under its original local policy. Explicit 4xx denial/missing/integrity responses and invalid signed content discard it. High-risk membership always requires the still-pending live Owner-bound resolver. A Scope membership result alone is never authorization.\n","repository":{"type":"git","url":"git@gitea.g-hi.com:luoanwu/enterprise-platform.git"}}...
|
1
|
Edit
Delete
|
|
47
|
2
|
5
|
0.25.0
|
0.25.0
|
1791730166
|
0
|
{"scope":"@juhai","name":& {"scope":"@juhai","name":"kernel","description":"基础框架内核契约(租户/信封/状态机/重放/请求上下文/平台端口/RLS/告警/作业)——源码留在 base-framework 仓,上层按框架版本 pin","license":"UNLICENSED","dependencies":{"zod":"^3.24.1"},"development_dependencies":{"typescript":"^5.7.2","vitest":"^2.1.8"},"readme":"ERROR: No README data found!","repository":{"type":"git","url":"git@gitea.g-hi.com:luoanwu/base-framework.git"}}...
|
0
|
Edit
Delete
|
|
48
|
2
|
5
|
0.25.1
|
0.25.1
|
1791732150
|
0
|
{"scope":"@juhai","name":& {"scope":"@juhai","name":"kernel","description":"基础框架内核契约(租户/信封/状态机/重放/请求上下文/平台端口/RLS/告警/作业)——源码留在 base-framework 仓,上层按框架版本 pin","license":"UNLICENSED","dependencies":{"zod":"^3.24.1"},"development_dependencies":{"typescript":"^5.7.2","vitest":"^2.1.8"},"readme":"ERROR: No README data found!","repository":{"type":"git","url":"git@gitea.g-hi.com:luoanwu/base-framework.git"}}...
|
16
|
Edit
Delete
|
|
49
|
21
|
5
|
0.26.0
|
0.26.0
|
1792405543
|
0
|
{"scope":"@juhai","name":& {"scope":"@juhai","name":"governance-kit","description":"零外部依赖的工程治理工具:棘轮、报告输出、来源绑定、串行 runner、turbo env 注册表。平台契约与发布策略留给 @juhai/governance。","license":"UNLICENSED","bin":{"juhai-governance-kit":"bin/cli.mjs"},"readme":"# @juhai/governance-kit\n\n工程治理的零外部依赖 ESM 工具包,Node \u003e=20。0.26.0 是独立工具包版本,不抬高 kernel pin。\n\n- `./ratchet`:`compareRatchet`、`parseRegisterMetricArgs`,缺基线键与非法基线失败关闭。\n- `./report-output`:`reportOutputDir`、`writeReport`。非空绝对路径;quick 独占目录优先于 `GOV_REPORT_DIR`,再回退到仓根 `reports/`。只改输出,基线从真实仓根读取。\n- `./provenance`:框架 v1 报告上下文及 `captureGitState(root, {sourcePaths, fingerprint})`、`detectRunner`。消费者保留自己的报告 schema、输出排除策略、CI 信任规则及覆盖值验证。\n- `./runner`:`runSteps` 串行、有界输出、失败关闭;`runQuickChecks` 独占临时输出并清理。\n- `./turbo-env`:注册表 `{schemaVersion:1, variables:[变量名]}` 生成/核对 `turbo.globalEnv`,禁止重复项。\n\n```js\nimport { compareRatchet } from '@juhai/governance-kit/ratchet';\nconst result = compareRatchet([{key:'violations', value:0, dir:'down'}], {violations:0});\n```\n\nCLI:`juhai-governance-kit check:api` 校验版本/exports/实现摘要;`env:check registry.json turbo.json` 核对,`env:write registry.json turbo.json` 显式生成。发布前更新 API 锁须评审并随版本提交。\n\n平台 pins/Catalog/DEC/候选晋级/发布判定不进入此包;平台适配器可调用通用工具,框架不依赖平台。工程门禁的具体判据、业务指标、基线、迁移批准和运行验收仍由消费仓负责。采用包不能自动获得 CI、运行态或发布通过结论。\n","repository":{"type":"git","url":"git@gitea.g-hi.com:luoanwu/base-framework.git"}}...
|
3
|
Edit
Delete
|
|
50
|
21
|
5
|
0.27.0
|
0.27.0
|
1792471501
|
0
|
{"scope":"@juhai","name":& {"scope":"@juhai","name":"governance-kit","description":"零外部依赖的工程治理工具:棘轮、报告输出、来源绑定、串行 runner、turbo env 注册表。平台契约与发布策略留给 @juhai/governance。","license":"UNLICENSED","bin":{"juhai-governance-kit":"bin/cli.mjs"},"readme":"# @juhai/governance-kit\n\n工程治理的零外部依赖 ESM 工具包,Node \u003e=20。0.27.0 是独立工具包版本,不抬高 kernel pin。\n\n- `./ratchet`:`compareRatchet`、`parseRegisterMetricArgs`,缺基线键与非法基线失败关闭。\n- `./report-output`:`reportOutputDir`、`writeReport`。非空绝对路径;quick 独占目录优先于 `GOV_REPORT_DIR`,再回退到仓根 `reports/`。只改输出,基线从真实仓根读取。\n- `./provenance`:框架 v1 报告上下文及 `captureGitState(root, {sourcePaths, fingerprint})`、`detectRunner`。消费者保留自己的报告 schema、输出排除策略、CI 信任规则及覆盖值验证。\n- `./runner`:`runSteps` 串行、有界输出、失败关闭;`runQuickChecks` 独占临时输出并清理。\n- `./turbo-env`:注册表 `{schemaVersion:1, variables:[变量名]}` 生成/核对 `turbo.globalEnv`,禁止重复项。\n\n- `./write-conformance`:ORM 无关的完整写集/事务一致/提交前隔离/晚期失败/重启回执夹具,返回逐条结构化结果;消费仓接真实 Owner 路径,不能用内存通过替代真库。\n- `./module-kit`:`generateModule` / `checkModule`,从 Owner 原合同摘要、精确依赖、租户来源与副作用声明生成最小工程材料;平台准入不进入此工具。\n\n```js\nimport { compareRatchet } from '@juhai/governance-kit/ratchet';\nconst result = compareRatchet([{key:'violations', value:0, dir:'down'}], {violations:0});\n```\n\nCLI:`juhai-governance-kit check:api` 校验版本/exports/实现摘要;`env:check registry.json turbo.json` 核对,`env:write registry.json turbo.json` 显式生成。发布前更新 API 锁须评审并随版本提交。\n\n平台 pins/Catalog/DEC/候选晋级/发布判定不进入此包;平台适配器可调用通用工具,框架不依赖平台。工程门禁的具体判据、业务指标、基线、迁移批准和运行验收仍由消费仓负责。采用包不能自动获得 CI、运行态或发布通过结论。\n\n新增 CLI:`module:generate \u003croot\u003e \u003cspec.json\u003e \u003cpolicy.json\u003e \u003cnew-target\u003e`、`module:check \u003croot\u003e \u003cspec.json\u003e \u003cpolicy.json\u003e`。新目标必须不存在。画像/声明是静态输入,真实写集、Owner 授权、调用副作用和合同兼容仍由消费仓验收;本仓完整示例与真实数据库适配见仓内 `docs/omni-framework-conformance.md`。0.26.0 的六个原 JS 入口及原函数行为保持。\n","repository":{"type":"git","url":"git@gitea.g-hi.com:luoanwu/base-framework.git"}}...
|
81
|
Edit
Delete
|
|
51
|
2
|
5
|
0.26.0
|
0.26.0
|
1792753099
|
0
|
{"scope":"@juhai","name":& {"scope":"@juhai","name":"kernel","description":"基础框架内核契约(租户/信封/状态机/重放/请求上下文/平台端口/RLS/告警/作业)——源码留在 base-framework 仓,上层按框架版本 pin","license":"UNLICENSED","dependencies":{"zod":"^3.24.1"},"development_dependencies":{"typescript":"^5.7.2","vitest":"^2.1.8"},"readme":"ERROR: No README data found!","repository":{"type":"git","url":"git@gitea.g-hi.com:luoanwu/base-framework.git"}}...
|
3
|
Edit
Delete
|
|
52
|
2
|
5
|
0.27.0
|
0.27.0
|
1792797598
|
0
|
{"scope":"@juhai","name":& {"scope":"@juhai","name":"kernel","description":"基础框架内核契约(租户/信封/状态机/重放/请求上下文/平台端口/RLS/告警/作业)——源码留在 base-framework 仓,上层按框架版本 pin","license":"UNLICENSED","dependencies":{"zod":"^4.6.6"},"development_dependencies":{"typescript":"^5.7.2","vitest":"^3.2.6"},"readme":"ERROR: No README data found!","repository":{"type":"git","url":"git@gitea.g-hi.com:luoanwu/base-framework.git"}}...
|
68
|
Edit
Delete
|
|
2
|
1
|
1
|
sha256:5279ae77972b78dda8d292118b2c1c6f06425638204 sha256:5279ae77972b78dda8d292118b2c1c6f06425638204f769ba81e53c2438e8b5b...
|
sha256:5279ae77972b78dda8d292118b2c1c6f06425638204 sha256:5279ae77972b78dda8d292118b2c1c6f06425638204f769ba81e53c2438e8b5b...
|
1770877260
|
0
|
{"type":"oci","is_tagged": {"type":"oci","is_tagged":false,"platform":"linux/amd64","layer_creation":["ADD alpine-minirootfs-3.23.2-x86_64.tar.gz / # buildkit","CMD [\"/bin/sh\"]","ENV NODE_VERSION=20.19.6","RUN /bin/sh -c addgroup -g 1000 node \u0026\u0026 adduser -u 1000 -G node -s /bin/sh -D node \u0026\u0026 apk add --no-cache libstdc++ \u0026\u0026 apk add --no-cache --virtual .build-deps curl \u0026\u0026 ARCH= OPENSSL_ARCH='linux*' \u0026\u0026 alpineArch=\"$(apk --print-arch)\" \u0026\u0026 case \"${alpineArch##*-}\" in x86_64) ARCH='x64' CHECKSUM=\"a371d92fafee1b20ede35c3df747ca1c8b25fcb2e14d3a4c36b41166faae707f\" OPENSSL_ARCH=linux-x86_64;; x86) OPENSSL_ARCH=linux-elf;; aarch64) OPENSSL_ARCH=linux-aarch64;; arm*) OPENSSL_ARCH=linux-armv4;; ppc64le) OPENSSL_ARCH=linux-ppc64le;; s390x) OPENSSL_ARCH=linux-s390x;; *) ;; esac \u0026\u0026 if [ -n \"${CHECKSUM}\" ]; then set -eu; curl -fsSLO --compressed \"https://unofficial-builds.nodejs.org/download/release/v$NODE_VERSION/node-v$NODE_VERSION-linux-$ARCH-musl.tar.xz\"; echo \"$CHECKSUM node-v$NODE_VERSION-linux-$ARCH-musl.tar.xz\" | sha256sum -c - \u0026\u0026 tar -xJf \"node-v$NODE_VERSION-linux-$ARCH-musl.tar.xz\" -C /usr/local --strip-components=1 --no-same-owner \u0026\u0026 ln -s /usr/local/bin/node /usr/local/bin/nodejs; else echo \"Building from source\" \u0026\u0026 apk add --no-cache --virtual .build-deps-full binutils-gold g++ gcc gnupg libgcc linux-headers make python3 py-setuptools \u0026\u0026 export GNUPGHOME=\"$(mktemp -d)\" \u0026\u0026 for key in 5BE8A3F6C8A5C01D106C0AD820B1A390B168D356 DD792F5973C6DE52C432CBDAC77ABFA00DDBF2B7 CC68F5A3106FF448322E48ED27F5E38D5B0A215F 8FCCA13FEF1D0C2E91008E09770F7A9A5AE15600 890C08DB8579162FEE0DF9DB8BEAB4DFCF555EF4 C82FA3AE1CBEDC6BE46B9360C43CEC45C17AB93C 108F52B48DB57BB0CC439B2997B01419BD92F80A A363A499291CBBC940DD62E41F10027AF002F8B0 ; do { gpg --batch --keyserver hkps://keys.openpgp.org --recv-keys \"$key\" \u0026\u0026 gpg --batch --fingerprint \"$key\"; } || { gpg --batch --keyserver keyserver.ubuntu.com --recv-keys \"$key\" \u0026\u0026 gpg --batch --fingerprint \"$key\"; } ; done \u0026\u0026 curl -fsSLO --compressed \"https://nodejs.org/dist/v$NODE_VERSION/node-v$NODE_VERSION.tar.xz\" \u0026\u0026 curl -fsSLO --compressed \"https://nodejs.org/dist/v$NODE_VERSION/SHASUMS256.txt.asc\" \u0026\u0026 gpg --batch --decrypt --output SHASUMS256.txt SHASUMS256.txt.asc \u0026\u0026 gpgconf --kill all \u0026\u0026 rm -rf \"$GNUPGHOME\" \u0026\u0026 grep \" node-v$NODE_VERSION.tar.xz\\$\" SHASUMS256.txt | sha256sum -c - \u0026\u0026 tar -xf \"node-v$NODE_VERSION.tar.xz\" \u0026\u0026 cd \"node-v$NODE_VERSION\" \u0026\u0026 ./configure \u0026\u0026 make -j$(getconf _NPROCESSORS_ONLN) V= \u0026\u0026 make install \u0026\u0026 apk del .build-deps-full \u0026\u0026 cd .. \u0026\u0026 rm -Rf \"node-v$NODE_VERSION\" \u0026\u0026 rm \"node-v$NODE_VERSION.tar.xz\" SHASUMS256.txt.asc SHASUMS256.txt; fi \u0026\u0026 rm -f \"node-v$NODE_VERSION-linux-$ARCH-musl.tar.xz\" \u0026\u0026 find /usr/local/include/node/openssl/archs -mindepth 1 -maxdepth 1 ! -name \"$OPENSSL_ARCH\" -exec rm -rf {} \\; \u0026\u0026 apk del .build-deps \u0026\u0026 node --version \u0026\u0026 npm --version \u0026\u0026 rm -rf /tmp/* # buildkit","ENV YARN_VERSION=1.22.22","RUN /bin/sh -c apk add --no-cache --virtual .build-deps-yarn curl gnupg tar \u0026\u0026 export GNUPGHOME=\"$(mktemp -d)\" \u0026\u0026 for key in 6A010C5166006599AA17F08146C2130DFD2497F5 ; do { gpg --batch --keyserver hkps://keys.openpgp.org --recv-keys \"$key\" \u0026\u0026 gpg --batch --fingerprint \"$key\"; } || { gpg --batch --keyserver keyserver.ubuntu.com --recv-keys \"$key\" \u0026\u0026 gpg --batch --fingerprint \"$key\"; } ; done \u0026\u0026 curl -fsSLO --compressed \"https://yarnpkg.com/downloads/$YARN_VERSION/yarn-v$YARN_VERSION.tar.gz\" \u0026\u0026 curl -fsSLO --compressed \"https://yarnpkg.com/downloads/$YARN_VERSION/yarn-v$YARN_VERSION.tar.gz.asc\" \u0026\u0026 gpg --batch --verify yarn-v$YARN_VERSION.tar.gz.asc yarn-v$YARN_VERSION.tar.gz \u0026\u0026 gpgconf --kill all \u0026\u0026 rm -rf \"$GNUPGHOME\" \u0026\u0026 mkdir -p /opt \u0026\u0026 tar -xzf yarn-v$YARN_VERSION.tar.gz -C /opt/ \u0026\u0026 ln -s /opt/yarn-v$YARN_VERSION/bin/yarn /usr/local/bin/yarn \u0026\u0026 ln -s /opt/yarn-v$YARN_VERSION/bin/yarnpkg /usr/local/bin/yarnpkg \u0026\u0026 rm yarn-v$YARN_VERSION.tar.gz.asc yarn-v$YARN_VERSION.tar.gz \u0026\u0026 apk del .build-deps-yarn \u0026\u0026 yarn --version \u0026\u0026 rm -rf /tmp/* # buildkit","COPY docker-entrypoint.sh /usr/local/bin/ # buildkit","ENTRYPOINT [\"docker-entrypoint.sh\"]","CMD [\"node\"]","RUN /bin/sh -c apk add --no-cache rsync git openssh-client # buildkit","RUN /bin/sh -c rsync --version \u0026\u0026 git --version # buildkit","WORKDIR /workspace"]}...
|
0
|
Edit
Delete
|
|
3
|
1
|
1
|
sha256:065434a3d7289f393f9b6601259099b7ec9c2fc3391 sha256:065434a3d7289f393f9b6601259099b7ec9c2fc33913023bfefb2fc8d9e03fa6...
|
sha256:065434a3d7289f393f9b6601259099b7ec9c2fc3391 sha256:065434a3d7289f393f9b6601259099b7ec9c2fc33913023bfefb2fc8d9e03fa6...
|
1770877260
|
0
|
{"type":"oci","is_tagged": {"type":"oci","is_tagged":false,"platform":"unknown/unknown"}...
|
0
|
Edit
Delete
|