progmune-runtime 3.3.8 → 3.4.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -308,10 +308,26 @@ function checkLedgerConsistency(ledger, namespaceInitialStates = new Map([["_glo
308
308
  running.set(ns, new Set());
309
309
  }
310
310
  }
311
- // Normalize a snapshot: ensure all known namespaces are present
311
+ // Normalize a snapshot: 只比较 ledger 中实际出现过的命名空间。
312
+ // 历史 session 只记录其触及的命名空间(protocol-registry 包目录回退修复前,
313
+ // 无 protocols.json 的 cwd 下 nsInit 退化为仅 _global)——用全量 nsInit
314
+ // 重建时未记录的 ns 不应参与比较,否则旧数据 before-consistency 全量误报。
315
+ // 更严格一步:只记录"有过非空快照"的 ns——早期 session 对 file/db 等
316
+ // 记录空数组(键存在但无信息),空数组不携带可比较的状态信息。
317
+ const recordedNamespaces = new Set();
318
+ for (const t of ledger) {
319
+ for (const [ns, states] of Object.entries(t.statesBefore)) {
320
+ if ((states || []).length > 0)
321
+ recordedNamespaces.add(ns);
322
+ }
323
+ for (const [ns, states] of Object.entries(t.statesAfter)) {
324
+ if ((states || []).length > 0)
325
+ recordedNamespaces.add(ns);
326
+ }
327
+ }
312
328
  function normalizeSnap(snap) {
313
329
  const out = {};
314
- for (const ns of allNamespaces) {
330
+ for (const ns of recordedNamespaces) {
315
331
  out[ns] = [...(snap[ns] || [])].sort();
316
332
  }
317
333
  return out;
@@ -704,12 +704,53 @@ async function collectProtocolViolations(ctx, callGraph) {
704
704
  let ssgMatchedCalls = 0;
705
705
  let ssgViolationCount = 0;
706
706
  try {
707
+ // ── P4.5 校准:TS/JS 项目在 ir.json 缺失时先提取 IR ──
708
+ // 序列必须来自「函数体内真实调用」而非「文件内函数声明名单」——
709
+ // 声明顺序 ≠ 执行顺序:正则扫描会把声明当调用(auth.ts 误报),
710
+ // 也会因调用数不足阈值漏掉单调用违规文件(bad_flow 漏报)。
711
+ if (!ctx.language || ctx.language === "typescript" || ctx.language === "javascript") {
712
+ try {
713
+ const fs = require("fs");
714
+ if (!fs.existsSync(path.join(ctx.projectPath, "ir.json"))) {
715
+ const { extractIR } = require("../extract-ir");
716
+ const ir = extractIR(ctx.projectPath);
717
+ fs.writeFileSync(path.join(ctx.projectPath, "ir.json"), JSON.stringify(ir, null, 2));
718
+ }
719
+ }
720
+ catch { /* best-effort — 回退正则扫描 */ }
721
+ }
707
722
  // ── Phase 1-5 Semantic Pipeline ──
708
723
  const callSequences = extractCallSequencesFromProject(ctx.projectPath, ctx.language);
709
724
  const flaggedCount = { value: 0 };
710
725
  const cleanCount = { value: 0 };
711
726
  // ── SSG State Machine: load protocol rules once ──
712
727
  protocolRulesData = (0, ssg_bridge_1.loadProtocolRules)(ctx.projectPath);
728
+ // ── P4.5: 合并项目 IR 注解协议(IR 优先,缺 namespace 继承内置 JSON) ──
729
+ // 内置 protocols.json 的规则是通用弱约束(如 generate_jwt pre=[]),
730
+ // 项目文件里的 @protocol 注解才是项目真实协议(如 pre=[PASSWORD_VERIFIED])。
731
+ // planner 已用此合并语义,trust 引擎需对齐,否则项目级前置约束不生效。
732
+ if (protocolRulesData) {
733
+ try {
734
+ const fs = require("fs");
735
+ const irPath = path.join(ctx.projectPath, "ir.json");
736
+ if (fs.existsSync(irPath)) {
737
+ const ir = JSON.parse(fs.readFileSync(irPath, "utf-8"));
738
+ if (Array.isArray(ir)) {
739
+ for (const f of ir) {
740
+ if (!f.protocol)
741
+ continue;
742
+ const protocol = { ...f.protocol };
743
+ const existing = protocolRulesData.rules.get(String(f.name));
744
+ if (existing?.namespace && !protocol.namespace) {
745
+ protocol.namespace = existing.namespace;
746
+ }
747
+ protocolRulesData.rules.set(String(f.name), protocol);
748
+ }
749
+ }
750
+ }
751
+ }
752
+ catch { /* best-effort */ }
753
+ }
713
754
  for (const seq of callSequences) {
714
755
  try {
715
756
  const semantic = await (0, api_semantic_mapper_1.mapSequenceToSemanticWithLLM)(seq.calls);
@@ -864,6 +905,46 @@ async function collectProtocolViolations(ctx, callGraph) {
864
905
  };
865
906
  }
866
907
  function extractCallSequencesFromProject(projectPath, language) {
908
+ // P4.5: 优先 IR 精确序列(每个函数体内的真实调用,从各自入口验证)
909
+ const irSequences = extractCallSequencesFromIR(projectPath);
910
+ if (irSequences.length > 0)
911
+ return irSequences;
912
+ // 回退:正则扫描(C 等无 IR 语言保持原行为)
913
+ return extractCallSequencesRegex(projectPath, language);
914
+ }
915
+ /**
916
+ * P4.5: 从 ir.json 构建 per-function 调用序列。
917
+ * 每个函数体内的 calls[] 是一条独立序列(从协议初始状态起步验证)——
918
+ * 函数声明名单不再是验证对象;语义 marker(__progmune_*)供规则消费,不作真实调用。
919
+ */
920
+ function extractCallSequencesFromIR(projectPath) {
921
+ try {
922
+ const fs = require("fs");
923
+ const irPath = path.join(projectPath, "ir.json");
924
+ if (!fs.existsSync(irPath))
925
+ return [];
926
+ const ir = JSON.parse(fs.readFileSync(irPath, "utf-8"));
927
+ if (!Array.isArray(ir))
928
+ return [];
929
+ const sequences = [];
930
+ for (const f of ir) {
931
+ const calls = (f.calls || []).filter((c) => typeof c === "string" && !c.startsWith("__progmune_"));
932
+ if (calls.length === 0)
933
+ continue;
934
+ sequences.push({
935
+ calls,
936
+ file: String(f.file || ""),
937
+ function: String(f.name || "unknown"),
938
+ });
939
+ }
940
+ return sequences;
941
+ }
942
+ catch {
943
+ return [];
944
+ }
945
+ }
946
+ /** 正则扫描回退路径(原实现):按文件扫调用样 token,≥4 才成序列。 */
947
+ function extractCallSequencesRegex(projectPath, language) {
867
948
  const sequences = [];
868
949
  try {
869
950
  const fs = require("fs");
package/package.json CHANGED
@@ -1,10 +1,11 @@
1
1
  {
2
2
  "name": "progmune-runtime",
3
- "version": "3.3.8",
3
+ "version": "3.4.1",
4
4
  "description": "Progmune — AI Trust Decision Engine. Verify AI-generated code before it reaches production. Outputs APPROVED / NEEDS_REVIEW / BLOCKED with evidence.",
5
5
  "files": [
6
6
  "dist/",
7
7
  "protocols.json",
8
+ "CHANGELOG.md",
8
9
  "docs/Progmune_项目全解.html",
9
10
  "docs/Progmune_投资人白皮书_v2.0.html"
10
11
  ],
@@ -30,6 +31,8 @@
30
31
  "governance:json": "node dist/audit/cli.js --all --json",
31
32
  "governance:md": "node dist/audit/cli.js --all --markdown",
32
33
  "certify": "node dist/certify.js",
34
+ "agent": "node dist/agent-cli.js",
35
+ "patrol": "node dist/patrol-cli.js",
33
36
  "certify:html": "node dist/certify-html.js",
34
37
  "policy": "node dist/policy/cli.js check",
35
38
  "precision": "node dist/multi-repo-precision.js",