|
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"}}...
|
77
|
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"}}...
|
2
|
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":""}}...
|
4
|
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":""}}...
|
4
|
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":""}}...
|
2
|
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":""}}...
|
2
|
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
|
|
4
|
1
|
1
|
node20-rsync-v1
|
node20-rsync-v1
|
1770877260
|
0
|
{"type":"oci","is_tagged": {"type":"oci","is_tagged":true,"manifests":[{"platform":"linux/amd64","digest":"sha256:5279ae77972b78dda8d292118b2c1c6f06425638204f769ba81e53c2438e8b5b","size":56372025},{"platform":"unknown/unknown","digest":"sha256:065434a3d7289f393f9b6601259099b7ec9c2fc33913023bfefb2fc8d9e03fa6","size":1781}]}...
|
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
|
|
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
|