progmune-runtime 2.1.6 → 3.2.0
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.
- package/README.md +108 -468
- package/dist/ablation-study.js +144 -0
- package/dist/ablation-study.test.js +18 -0
- package/dist/action-runtime.js +3 -1
- package/dist/active-learning.js +211 -0
- package/dist/analytics.js +139 -0
- package/dist/asset-factory.js +309 -0
- package/dist/asset-growth.js +244 -0
- package/dist/asset-promotion.js +382 -0
- package/dist/asset-quality.js +550 -0
- package/dist/audit/business-translator.js +285 -0
- package/dist/audit/cli.js +66 -0
- package/dist/audit/formatters/html.js +379 -0
- package/dist/audit/formatters/json.js +11 -0
- package/dist/audit/formatters/markdown.js +192 -0
- package/dist/audit/formatters/terminal.js +189 -0
- package/dist/audit/index.js +25 -0
- package/dist/audit/report-builder.js +318 -0
- package/dist/audit/types.js +8 -0
- package/dist/audit.js +3 -3
- package/dist/auto-benchmark-generator.js +137 -0
- package/dist/auto-benchmark-generator.test.js +45 -0
- package/dist/auto-protocol-synthesizer.js +362 -0
- package/dist/auto-protocol-synthesizer.test.js +82 -0
- package/dist/autonomous-patch.js +175 -0
- package/dist/autonomous-patch.test.js +128 -0
- package/dist/badge/badge-server.js +98 -0
- package/dist/behavior-miner.js +442 -0
- package/dist/belief-layer.js +475 -0
- package/dist/benchmark-count.js +5 -0
- package/dist/benchmark-generator.js +211 -0
- package/dist/benchmark-harness.js +201 -0
- package/dist/benchmark-pass-rate.js +7 -0
- package/dist/benchmark-report.js +8 -3
- package/dist/benchmark-save.js +14 -1
- package/dist/bootstrap-validation.js +197 -0
- package/dist/bootstrap-validation.test.js +51 -0
- package/dist/branch-ledger.js +1 -1
- package/dist/capability-gap.js +130 -0
- package/dist/certify-html.js +351 -0
- package/dist/certify.js +326 -0
- package/dist/check.js +4 -4
- package/dist/compliance-miner.js +447 -0
- package/dist/continuous-benchmark.js +194 -0
- package/dist/continuous-benchmark.test.js +116 -0
- package/dist/corpus-stats.js +173 -0
- package/dist/counterfactual-engine.js +288 -0
- package/dist/coverage-dashboard.js +109 -0
- package/dist/coverage-system.test.js +205 -0
- package/dist/cross-repo-precision.js +352 -0
- package/dist/cve-benchmark.js +180 -0
- package/dist/cve-benchmark.test.js +28 -0
- package/dist/cve-collector.js +73 -0
- package/dist/data-quality.js +141 -0
- package/dist/decision-engine.js +388 -0
- package/dist/derive-metadata.js +250 -0
- package/dist/difficulty-active.test.js +198 -0
- package/dist/difficulty-map.js +244 -0
- package/dist/discovery-analytics.js +125 -0
- package/dist/discovery-model.js +149 -0
- package/dist/discovery-optimize.test.js +199 -0
- package/dist/discovery-trace.js +276 -0
- package/dist/discovery-trace.test.js +97 -0
- package/dist/emitter.js +83 -1
- package/dist/enterprise-dashboard.js +405 -0
- package/dist/eval-hardening.js +297 -0
- package/dist/eval-hardening.test.js +85 -0
- package/dist/evaluation-campaign.js +359 -0
- package/dist/evaluation-campaign.test.js +181 -0
- package/dist/evidence-growth.js +143 -0
- package/dist/evidence-repository.js +209 -0
- package/dist/evidence-system.js +441 -0
- package/dist/execute.js +15 -7
- package/dist/experimental/software-physics.js +291 -0
- package/dist/experimental/state-inference.js +516 -0
- package/dist/experimental/unsupervised-physics.js +230 -0
- package/dist/extract-ir-python.js +54 -7
- package/dist/extract-ir.js +376 -12
- package/dist/failure-collector.js +2 -2
- package/dist/failure-corpus.js +322 -9
- package/dist/feedback.js +16 -5
- package/dist/feedback.test.js +49 -0
- package/dist/file-lock.js +1 -1
- package/dist/flywheel-batch.js +292 -0
- package/dist/frameworks/express-cli.js +237 -0
- package/dist/frameworks/express-detector.js +445 -0
- package/dist/frameworks/express-detector.test.js +206 -0
- package/dist/frameworks/index.js +30 -0
- package/dist/frameworks/nestjs-detector.js +302 -0
- package/dist/frameworks/trpc-detector.js +161 -0
- package/dist/frameworks/version-awareness.js +179 -0
- package/dist/function-synonyms.js +164 -0
- package/dist/function-synonyms.test.js +68 -0
- package/dist/generalization.test.js +352 -0
- package/dist/goal-annotator.js +113 -0
- package/dist/goal-planner.js +563 -0
- package/dist/gold-cve.js +164 -0
- package/dist/gold-cve.test.js +104 -0
- package/dist/gold-quality.js +206 -0
- package/dist/gold-tiers.js +241 -0
- package/dist/governance-dashboard.js +327 -0
- package/dist/graph-viz.js +240 -0
- package/dist/guided-frontier.js +195 -0
- package/dist/hierarchical-planner.js +148 -0
- package/dist/identifier-parser.js +260 -0
- package/dist/immune-metrics.js +93 -0
- package/dist/immune-receiver.js +158 -0
- package/dist/immune-reporter.js +1 -1
- package/dist/improvement-orchestrator.js +206 -0
- package/dist/inject-p0-vocabulary.js +300 -0
- package/dist/intent-parser.js +218 -0
- package/dist/invariant-algebra.js +476 -0
- package/dist/invariant-calculus.js +533 -0
- package/dist/ir-utils.js +70 -0
- package/dist/ir-utils.test.js +50 -0
- package/dist/knowledge-api.js +312 -0
- package/dist/knowledge-evolution.js +452 -0
- package/dist/knowledge-explorer.js +506 -0
- package/dist/knowledge-flywheel.js +274 -0
- package/dist/knowledge-governance.js +338 -0
- package/dist/knowledge-governance.test.js +150 -0
- package/dist/knowledge-graph.js +181 -0
- package/dist/knowledge-guided-synth.js +246 -0
- package/dist/knowledge-loop.test.js +77 -0
- package/dist/knowledge-object.js +316 -0
- package/dist/knowledge-package.js +98 -0
- package/dist/kpi-dashboard.js +561 -0
- package/dist/l3-cross-function.js +280 -0
- package/dist/learning-ranker.js +148 -0
- package/dist/learning-ranker.test.js +291 -0
- package/dist/ledger/accountability.js +322 -0
- package/dist/ledger/chain-builder.js +185 -0
- package/dist/ledger/cli.js +222 -0
- package/dist/ledger/index.js +13 -0
- package/dist/ledger/signatures.js +193 -0
- package/dist/ledger/types.js +9 -0
- package/dist/llm.js +74 -3
- package/dist/load-benchmarks.js +8 -3
- package/dist/logger.js +66 -0
- package/dist/logger.test.js +37 -0
- package/dist/logistic-reward.js +339 -0
- package/dist/logistic-reward.test.js +180 -0
- package/dist/macro-graph.js +193 -0
- package/dist/macro-repair.js +183 -0
- package/dist/mcp-server.mjs +1202 -483
- package/dist/memory-layer.js +42 -5
- package/dist/multi-repo-precision.js +422 -0
- package/dist/name-free-protocol.js +425 -0
- package/dist/name-free-protocol.test.js +170 -0
- package/dist/name-scrambling.js +138 -0
- package/dist/name-scrambling.test.js +16 -0
- package/dist/p3-observability.test.js +281 -0
- package/dist/p5-orchestrator.test.js +225 -0
- package/dist/pairwise-preference.js +294 -0
- package/dist/pairwise-preference.test.js +140 -0
- package/dist/planner-constraints.js +104 -0
- package/dist/planner-prompts.js +155 -0
- package/dist/planner-telemetry.js +415 -0
- package/dist/planner-trace.js +214 -0
- package/dist/planner.js +162 -167
- package/dist/plsb/artifact.js +116 -0
- package/dist/plsb/cli.js +71 -0
- package/dist/plsb/index.js +19 -0
- package/dist/plsb/leaderboard.js +249 -0
- package/dist/plsb/report-md.js +156 -0
- package/dist/plsb/schema.js +179 -0
- package/dist/plsb-benchmark.js +284 -0
- package/dist/plsb-benchmark.test.js +119 -0
- package/dist/policy/cli.js +134 -0
- package/dist/policy/engine.js +333 -0
- package/dist/policy/index.js +12 -0
- package/dist/policy/types.js +59 -0
- package/dist/policy-miner.js +505 -0
- package/dist/precision-analyze.js +229 -0
- package/dist/precision-benchmark.js +147 -0
- package/dist/precision-label-c.js +134 -0
- package/dist/precision-label.js +193 -0
- package/dist/precision-report-c.js +149 -0
- package/dist/precision-report.js +246 -0
- package/dist/progmune-status.js +108 -0
- package/dist/proof-engine.js +479 -0
- package/dist/proof-provenance.js +315 -0
- package/dist/protocol-coverage.js +294 -0
- package/dist/protocol-detector.js +1189 -0
- package/dist/protocol-embedding-expanded.js +297 -0
- package/dist/protocol-embedding-expanded.test.js +97 -0
- package/dist/protocol-embedding.js +195 -0
- package/dist/protocol-embedding.test.js +82 -0
- package/dist/protocol-extractor-v2.js +354 -0
- package/dist/protocol-extractor-v2.test.js +140 -0
- package/dist/protocol-extractor.js +310 -0
- package/dist/protocol-extractor.test.js +113 -0
- package/dist/protocol-foundation.js +322 -0
- package/dist/protocol-foundation.test.js +163 -0
- package/dist/protocol-frontier.js +243 -0
- package/dist/protocol-frontier.test.js +92 -0
- package/dist/protocol-gap-analyzer.js +228 -0
- package/dist/protocol-gap-analyzer.test.js +49 -0
- package/dist/protocol-invariants.js +276 -0
- package/dist/protocol-invariants.test.js +111 -0
- package/dist/protocol-knowledge.js +464 -0
- package/dist/protocol-miner.js +343 -0
- package/dist/protocol-mining.js +207 -0
- package/dist/protocol-mining.test.js +37 -0
- package/dist/protocol-registry.js +1 -1
- package/dist/protocol-security-benchmark.js +222 -0
- package/dist/protocol-vulnerability.js +257 -0
- package/dist/protocol-vulnerability.test.js +60 -0
- package/dist/python-benchmark.js +120 -0
- package/dist/python-emitter.js +163 -45
- package/dist/python-protocol-extractor.js +187 -0
- package/dist/python-protocol-extractor.test.js +116 -0
- package/dist/realworld-benchmark.js +646 -0
- package/dist/realworld-benchmark.test.js +36 -0
- package/dist/repair-arch.test.js +411 -0
- package/dist/repair-evolution.test.js +454 -0
- package/dist/repair-executor.js +719 -0
- package/dist/repair-proposal.js +4 -4
- package/dist/repair-ranker.js +141 -0
- package/dist/repair-strategies.js +419 -0
- package/dist/repair-taxonomy.js +234 -0
- package/dist/repair-types.js +12 -0
- package/dist/repo-evaluator.js +250 -0
- package/dist/repo-evaluator.test.js +128 -0
- package/dist/resource-abstraction.js +242 -0
- package/dist/resource-detector.js +211 -0
- package/dist/result.test.js +43 -0
- package/dist/reward-system.js +411 -0
- package/dist/reward-system.test.js +175 -0
- package/dist/risk-model.js +215 -0
- package/dist/rule-miner.js +234 -7
- package/dist/rule-specificity.js +254 -0
- package/dist/runtime-types.js +27 -0
- package/dist/scaffold.js +208 -0
- package/dist/scale-collector.test.js +101 -0
- package/dist/scale-trajectory-collector.js +128 -0
- package/dist/sdk.js +250 -0
- package/dist/search-planner.js +4 -41
- package/dist/semantic-snapshot.js +1 -1
- package/dist/semantic-topology.js +121 -0
- package/dist/semantic-trace.js +310 -317
- package/dist/sequence-extractor.js +343 -0
- package/dist/skill-library.js +245 -0
- package/dist/skill-planner.test.js +189 -0
- package/dist/software-physics.js +291 -0
- package/dist/software-physics.test.js +81 -0
- package/dist/ssg-precision.js +478 -0
- package/dist/ssg-validator.js +71 -21
- package/dist/state-inference-doubleblind.test.js +160 -0
- package/dist/state-inference.js +516 -0
- package/dist/state-inference.test.js +115 -0
- package/dist/state-machine-fingerprint.js +345 -0
- package/dist/state-machine-fingerprint.test.js +120 -0
- package/dist/state-miner.js +386 -0
- package/dist/state-name-inference.js +213 -0
- package/dist/state-name-inference.test.js +69 -0
- package/dist/strategy-planner.js +262 -96
- package/dist/strategy-planner.test.js +135 -0
- package/dist/telemetry-analytics.test.js +402 -0
- package/dist/terminal-format.js +68 -0
- package/dist/terminal-format.test.js +83 -0
- package/dist/topology-factory.js +196 -0
- package/dist/topology-representation.js +242 -0
- package/dist/topology-representation.test.js +27 -0
- package/dist/trajectory-augmentation.js +254 -0
- package/dist/trajectory-augmentation.test.js +63 -0
- package/dist/trajectory-corpus.js +440 -0
- package/dist/trajectory-corpus.test.js +32 -0
- package/dist/trajectory-feedback.test.js +116 -0
- package/dist/transition-synthesizer.js +286 -0
- package/dist/transition-synthesizer.test.js +123 -0
- package/dist/trust/api-semantic-mapper.js +809 -0
- package/dist/trust/call-graph-propagator.js +225 -0
- package/dist/trust/cli.js +122 -0
- package/dist/trust/compliance-scorer.js +283 -0
- package/dist/trust/confidence-calculator.js +261 -0
- package/dist/trust/engine.js +1145 -0
- package/dist/trust/explainability.js +85 -0
- package/dist/trust/formatters/ci.js +42 -0
- package/dist/trust/formatters/json.js +11 -0
- package/dist/trust/formatters/terminal.js +152 -0
- package/dist/trust/index.js +39 -0
- package/dist/trust/phase1-verify.js +171 -0
- package/dist/trust/protocol-domain-validator.js +697 -0
- package/dist/trust/score-calculator.js +282 -0
- package/dist/trust/ssg-bridge.js +641 -0
- package/dist/trust/ssg-bridge.test.js +269 -0
- package/dist/trust/types.js +67 -0
- package/dist/trust/violation-trace.js +335 -0
- package/dist/trust-api.js +179 -0
- package/dist/trust-calibration.js +279 -0
- package/dist/unknown-protocol-discovery.js +339 -0
- package/dist/unknown-protocol-discovery.test.js +102 -0
- package/dist/unsupervised-physics.js +230 -0
- package/dist/unsupervised-physics.test.js +95 -0
- package/dist/utils.test.js +37 -0
- package/dist/validator.js +187 -10
- package/dist/verification-intelligence.js +475 -0
- package/dist/verify-api.js +432 -0
- package/dist/vi-impact-report.js +293 -0
- package/dist/wl-fingerprint.js +162 -0
- package/dist/wl-fingerprint.test.js +130 -0
- package/dist/zeroshot-strategy.js +139 -0
- package/docs/Progmune_/346/212/225/350/265/204/344/272/272/347/231/275/347/232/256/344/271/246_v2.0.html +576 -0
- package/docs/Progmune_/351/241/271/347/233/256/345/205/250/350/247/243.html +710 -0
- package/package.json +74 -7
- package/protocols.json +1956 -50
- package/.dockerignore +0 -14
- package/.mcp.json +0 -11
- package/.progmune_allowlist +0 -50
- package/.test_report/test_report.md +0 -87
- package/Dockerfile +0 -9
- package/FAQ.md +0 -167
- package/WHITEPAPER.md +0 -540
- package/demo-project/auth.ts +0 -55
- package/demo-project/tsconfig.json +0 -8
- package/dist/acl-breakdown.js +0 -13
- package/dist/all-sessions.js +0 -11
- package/dist/antibody-stats.js +0 -11
- package/dist/branch-tree-count.js +0 -14
- package/dist/common-fixpath.js +0 -12
- package/dist/constraint-types.js +0 -12
- package/dist/exec-metrics.js +0 -11
- package/dist/failure-report.js +0 -11
- package/dist/fast-path-hits.js +0 -13
- package/dist/fingerprint-list.js +0 -15
- package/dist/gen-history-log.js +0 -13
- package/dist/heatmap-data.js +0 -11
- package/dist/recent-session.js +0 -12
- package/dist/svl-distribution.js +0 -11
- package/dist/terminal-status.js +0 -11
- package/dist/token-savings.js +0 -11
- package/dist/total-repairs.js +0 -12
- package/dist/unresolved-count.js +0 -12
- package/dist/valid-fingerprints.js +0 -13
- package/dist/verify-ledgers.js +0 -11
- package/docs/whitepaper-style.css +0 -77
- package/docs/whitepaper-v2.1.md +0 -609
- package/docs/whitepaper-v2.2.md +0 -1064
- package/docs/whitepaper-v2.2.pdf +0 -0
- package/fly.toml +0 -31
- package/public/dashboard.html +0 -119
- package/server/hub.js +0 -116
- package/test/replay-golden/sess_1780063202050_mgeld.json +0 -9
- package/test/replay-golden/sess_1780064032560_gocld.json +0 -354
- package/test/replay-golden/sess_1780064413331_s2709.json +0 -606
- package/test/replay-golden/sess_1780064792710_y3avo.json +0 -614
- package/test/replay-golden.ts +0 -84
- package/test_benchmark.js +0 -165
- package/test_comprehensive.mjs +0 -638
- package/test_concurrency.js +0 -129
- package/test_ir_robustness.js +0 -85
- package/test_semantic_contracts.js +0 -269
- package/test_ssg_stress.js +0 -156
- package/test_svl3.js +0 -58
- package/tsconfig.json +0 -17
|
@@ -0,0 +1,229 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* FP Taxonomy Analyzer
|
|
4
|
+
*
|
|
5
|
+
* Classifies every false positive from a precision report into
|
|
6
|
+
* root cause categories. This tells us WHY precision is low
|
|
7
|
+
* before we attempt to fix anything.
|
|
8
|
+
*
|
|
9
|
+
* Usage:
|
|
10
|
+
* npx ts-node src/precision-analyze.ts benchmarks/curl
|
|
11
|
+
*/
|
|
12
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
13
|
+
if (k2 === undefined) k2 = k;
|
|
14
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
15
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
16
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
17
|
+
}
|
|
18
|
+
Object.defineProperty(o, k2, desc);
|
|
19
|
+
}) : (function(o, m, k, k2) {
|
|
20
|
+
if (k2 === undefined) k2 = k;
|
|
21
|
+
o[k2] = m[k];
|
|
22
|
+
}));
|
|
23
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
24
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
25
|
+
}) : function(o, v) {
|
|
26
|
+
o["default"] = v;
|
|
27
|
+
});
|
|
28
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
29
|
+
var ownKeys = function(o) {
|
|
30
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
31
|
+
var ar = [];
|
|
32
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
33
|
+
return ar;
|
|
34
|
+
};
|
|
35
|
+
return ownKeys(o);
|
|
36
|
+
};
|
|
37
|
+
return function (mod) {
|
|
38
|
+
if (mod && mod.__esModule) return mod;
|
|
39
|
+
var result = {};
|
|
40
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
41
|
+
__setModuleDefault(result, mod);
|
|
42
|
+
return result;
|
|
43
|
+
};
|
|
44
|
+
})();
|
|
45
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
46
|
+
const fs = __importStar(require("fs"));
|
|
47
|
+
const path = __importStar(require("path"));
|
|
48
|
+
const resource_detector_1 = require("./resource-detector");
|
|
49
|
+
// ── Classification Logic ──
|
|
50
|
+
function classifyFP(calls, funcName, reason) {
|
|
51
|
+
// 1. State inference noise: SSG auto-discovered rule rejected valid ordering
|
|
52
|
+
// Pattern: reason contains "requires [C0_S...] but state has [INIT,C0_S...]"
|
|
53
|
+
if (reason.includes("requires [C") && reason.includes("but state has [")) {
|
|
54
|
+
return "state_inference_noise";
|
|
55
|
+
}
|
|
56
|
+
// 2. Check if this is a resource lifecycle false positive
|
|
57
|
+
const resourceVios = (0, resource_detector_1.detectResourceViolations)(calls);
|
|
58
|
+
// 3. Allocator-return: function name suggests it's a factory/allocator
|
|
59
|
+
const allocatorPatterns = /\b(create|alloc|new|init|open|dup|clone|copy|build|make)\w*\b/i;
|
|
60
|
+
const isAllocator = allocatorPatterns.test(funcName);
|
|
61
|
+
if (isAllocator && resourceVios.some(v => v.type === "missing_release")) {
|
|
62
|
+
return "allocator_return";
|
|
63
|
+
}
|
|
64
|
+
// 4. Cross-function cleanup: resource acquired here, released elsewhere
|
|
65
|
+
// Pattern: has acquire calls + has no matching release in this function
|
|
66
|
+
const hasAcquire = /\b(malloc|calloc|open|connect|SSL_new|BIO_new|Curl_open|ngx_.*_init|ngx_.*_create)\b/i;
|
|
67
|
+
const hasRelease = /\b(free|close|disconnect|SSL_free|BIO_free|Curl_close|ngx_.*_free|ngx_.*_cleanup)\b/i;
|
|
68
|
+
const callsStr = calls.join(" ");
|
|
69
|
+
if (hasAcquire.test(callsStr) && !hasRelease.test(callsStr) && !isAllocator) {
|
|
70
|
+
return "cross_function_cleanup";
|
|
71
|
+
}
|
|
72
|
+
// 5. Callback ownership: common async/event pattern
|
|
73
|
+
const callbackPatterns = /\b(callback|cb_|_cb|handler|on_|_done|_complete|_finish)\b/i;
|
|
74
|
+
if (callbackPatterns.test(funcName) || calls.some(c => callbackPatterns.test(c))) {
|
|
75
|
+
return "callback_ownership";
|
|
76
|
+
}
|
|
77
|
+
// 6. Noise call: logging/debug/trace functions in the call list
|
|
78
|
+
const noisePatterns = /\b(infof|failf|DEBUGF|DEBUGASSERT|log|trace|debug|print|dump|assert)\b/i;
|
|
79
|
+
const noiseCount = calls.filter(c => noisePatterns.test(c)).length;
|
|
80
|
+
if (noiseCount >= calls.length * 0.3) {
|
|
81
|
+
return "noise_call";
|
|
82
|
+
}
|
|
83
|
+
// 7. Protocol extraction error: calls don't form a meaningful protocol sequence
|
|
84
|
+
const protocolPatterns = /\b(init|open|connect|send|recv|read|write|close|free|cleanup|finish|done|stop|start)\b/i;
|
|
85
|
+
const protocolCount = calls.filter(c => protocolPatterns.test(c)).length;
|
|
86
|
+
if (protocolCount < calls.length * 0.3) {
|
|
87
|
+
return "protocol_extraction_error";
|
|
88
|
+
}
|
|
89
|
+
return "unknown";
|
|
90
|
+
}
|
|
91
|
+
function classifyFN(calls, funcName, reason) {
|
|
92
|
+
// FN: human said violation, detector said clean
|
|
93
|
+
// Why didn't the detector catch this?
|
|
94
|
+
const callsStr = calls.join(" ");
|
|
95
|
+
// State machine functions that are missing transitions
|
|
96
|
+
const stateMachinePatterns = /\b(state|statemachine|_step|_phase)\w*\b/i;
|
|
97
|
+
if (stateMachinePatterns.test(funcName)) {
|
|
98
|
+
return "state_inference_noise"; // Detector didn't learn the state machine correctly
|
|
99
|
+
}
|
|
100
|
+
// Missing acquire before release
|
|
101
|
+
const hasRelease = /\b(free|close|disconnect|SSL_free|BIO_free|cleanup|destroy)\b/i;
|
|
102
|
+
const hasAcquire = /\b(malloc|open|connect|SSL_new|BIO_new|init|create)\b/i;
|
|
103
|
+
if (hasRelease.test(callsStr) && !hasAcquire.test(callsStr)) {
|
|
104
|
+
return "cross_function_cleanup"; // Release without acquire in same function
|
|
105
|
+
}
|
|
106
|
+
return "unknown";
|
|
107
|
+
}
|
|
108
|
+
// ── Main Analyzer ──
|
|
109
|
+
function analyze(repoPath) {
|
|
110
|
+
const precFile = path.join(path.dirname(repoPath), `${path.basename(repoPath)}-precision.json`);
|
|
111
|
+
if (!fs.existsSync(precFile)) {
|
|
112
|
+
console.error(`❌ Precision report not found: ${precFile}`);
|
|
113
|
+
process.exit(1);
|
|
114
|
+
}
|
|
115
|
+
const report = JSON.parse(fs.readFileSync(precFile, "utf-8"));
|
|
116
|
+
const details = report.details || [];
|
|
117
|
+
const fpCases = details.filter((d) => d.expected === "clean" && d.detected === "violation");
|
|
118
|
+
const fnCases = details.filter((d) => d.expected === "violation" && d.detected === "clean");
|
|
119
|
+
console.error(`\nAnalyzing ${report.total} samples: ${report.fp} FP, ${report.fn} FN`);
|
|
120
|
+
// Classify FPs
|
|
121
|
+
const fpByCategory = new Map();
|
|
122
|
+
for (const d of fpCases) {
|
|
123
|
+
const cat = classifyFP(d.calls || [], d.calls?.[0] || "", d.reason || "");
|
|
124
|
+
if (!fpByCategory.has(cat))
|
|
125
|
+
fpByCategory.set(cat, []);
|
|
126
|
+
fpByCategory.get(cat).push(d);
|
|
127
|
+
}
|
|
128
|
+
// Classify FNs
|
|
129
|
+
const fnByCategory = new Map();
|
|
130
|
+
for (const d of fnCases) {
|
|
131
|
+
const cat = classifyFN(d.calls || [], d.calls?.[0] || "", d.reason || "");
|
|
132
|
+
if (!fnByCategory.has(cat))
|
|
133
|
+
fnByCategory.set(cat, []);
|
|
134
|
+
fnByCategory.get(cat).push(d);
|
|
135
|
+
}
|
|
136
|
+
// ═══ FP Taxonomy Report ═══
|
|
137
|
+
const C = {
|
|
138
|
+
reset: "\x1b[0m", bold: "\x1b[1m", dim: "\x1b[2m",
|
|
139
|
+
green: "\x1b[32m", red: "\x1b[31m", yellow: "\x1b[33m", cyan: "\x1b[36m",
|
|
140
|
+
};
|
|
141
|
+
const CATEGORY_LABELS = {
|
|
142
|
+
state_inference_noise: {
|
|
143
|
+
label: "State inference noise",
|
|
144
|
+
desc: "Auto-discovered SSG rules overfit to call order. Valid protocol sequences flagged because they don't match the learned adjacency pattern.",
|
|
145
|
+
fix: "Replace auto-discovered rules with hand-written protocol definitions. Increase clean training sequences from 29 to 100+.",
|
|
146
|
+
},
|
|
147
|
+
cross_function_cleanup: {
|
|
148
|
+
label: "Cross-function cleanup",
|
|
149
|
+
desc: "Resource acquired in this function but released elsewhere (caller, callback, cleanup phase). Detector assumes acquire+release must be in same scope.",
|
|
150
|
+
fix: "Model protocol lifecycle across function boundaries. Recognize that acquire in step1() may be released in cleanup().",
|
|
151
|
+
},
|
|
152
|
+
allocator_return: {
|
|
153
|
+
label: "Allocator-return pattern",
|
|
154
|
+
desc: "Function allocates resource and returns it to caller. Detector sees malloc without free and flags as leak — but the caller is responsible for cleanup.",
|
|
155
|
+
fix: "Identify factory/allocator functions by name pattern. Exclude them from acquire-without-release checks.",
|
|
156
|
+
},
|
|
157
|
+
callback_ownership: {
|
|
158
|
+
label: "Callback ownership",
|
|
159
|
+
desc: "Resource passed to async callback. Ownership transfers — cleanup responsibility moves to callback or event handler.",
|
|
160
|
+
fix: "Track resource ownership across callback boundaries. Recognize event-driven cleanup patterns.",
|
|
161
|
+
},
|
|
162
|
+
noise_call: {
|
|
163
|
+
label: "Noise call in sequence",
|
|
164
|
+
desc: "Logging, debug, or trace calls mixed into protocol sequences. These create false adjacency patterns in SSG rule discovery.",
|
|
165
|
+
fix: "Filter noise calls (infof, failf, DEBUGF, etc.) before rule discovery.",
|
|
166
|
+
},
|
|
167
|
+
protocol_extraction_error: {
|
|
168
|
+
label: "Protocol extraction error",
|
|
169
|
+
desc: "Extracted calls don't form a real protocol sequence. C function call extraction picked up utility calls rather than protocol steps.",
|
|
170
|
+
fix: "Improve C call extraction: filter utility functions, focus on named protocol operations.",
|
|
171
|
+
},
|
|
172
|
+
unknown: {
|
|
173
|
+
label: "Unknown / Other",
|
|
174
|
+
desc: "Doesn't match any known FP pattern. Requires manual inspection.",
|
|
175
|
+
fix: "Manual review of individual cases.",
|
|
176
|
+
},
|
|
177
|
+
};
|
|
178
|
+
console.log(`\n${C.bold}${C.cyan}╔══════════════════════════════════════════════════════════════╗${C.reset}`);
|
|
179
|
+
console.log(`${C.bold}${C.cyan}║${C.reset} ${C.bold}FP Taxonomy Report — curl${C.reset} ${C.bold}${C.cyan}║${C.reset}`);
|
|
180
|
+
console.log(`${C.bold}${C.cyan}╚══════════════════════════════════════════════════════════════╝${C.reset}`);
|
|
181
|
+
console.log("");
|
|
182
|
+
// FP Breakdown
|
|
183
|
+
console.log(`${C.bold}False Positives (${fpCases.length}):${C.reset}\n`);
|
|
184
|
+
const fpSorted = [...fpByCategory.entries()].sort((a, b) => b[1].length - a[1].length);
|
|
185
|
+
for (const [cat, cases] of fpSorted) {
|
|
186
|
+
const pct = ((cases.length / fpCases.length) * 100).toFixed(0);
|
|
187
|
+
const bar = "█".repeat(Math.round(cases.length / fpCases.length * 30));
|
|
188
|
+
const info = CATEGORY_LABELS[cat];
|
|
189
|
+
console.log(` ${C.red}${bar}${C.reset} ${pct}% ${C.bold}${info.label}${C.reset} (${cases.length} cases)`);
|
|
190
|
+
console.log(` ${C.dim}${info.desc}${C.reset}`);
|
|
191
|
+
// Show 2 examples
|
|
192
|
+
for (const ex of cases.slice(0, 2)) {
|
|
193
|
+
console.log(` ${C.dim} ex: ${(ex.calls || []).slice(0, 4).join(" → ")}${C.reset}`);
|
|
194
|
+
}
|
|
195
|
+
console.log("");
|
|
196
|
+
}
|
|
197
|
+
// FN Breakdown
|
|
198
|
+
console.log(`${C.bold}False Negatives (${fnCases.length}):${C.reset}\n`);
|
|
199
|
+
const fnSorted = [...fnByCategory.entries()].sort((a, b) => b[1].length - a[1].length);
|
|
200
|
+
for (const [cat, cases] of fnSorted) {
|
|
201
|
+
const pct = ((cases.length / fnCases.length) * 100).toFixed(0);
|
|
202
|
+
const bar = "█".repeat(Math.round(cases.length / Math.max(1, fnCases.length) * 30));
|
|
203
|
+
const info = CATEGORY_LABELS[cat];
|
|
204
|
+
console.log(` ${C.yellow}${bar}${C.reset} ${pct}% ${C.bold}${info.label}${C.reset} (${cases.length} cases)`);
|
|
205
|
+
for (const ex of cases.slice(0, 2)) {
|
|
206
|
+
console.log(` ${C.dim} ex: ${(ex.calls || []).slice(0, 4).join(" → ")}${C.reset}`);
|
|
207
|
+
}
|
|
208
|
+
console.log("");
|
|
209
|
+
}
|
|
210
|
+
// Fix priority
|
|
211
|
+
console.log(`${C.bold}Fix Priority:${C.reset}`);
|
|
212
|
+
const topFP = fpSorted[0];
|
|
213
|
+
if (topFP) {
|
|
214
|
+
const info = CATEGORY_LABELS[topFP[0]];
|
|
215
|
+
console.log(` 1. ${C.red}${info.label}${C.reset} — ${topFP[1].length} cases (${((topFP[1].length / fpCases.length) * 100).toFixed(0)}% of FP)`);
|
|
216
|
+
console.log(` ${C.dim}→ ${info.fix}${C.reset}`);
|
|
217
|
+
}
|
|
218
|
+
if (fpSorted[1]) {
|
|
219
|
+
const info = CATEGORY_LABELS[fpSorted[1][0]];
|
|
220
|
+
console.log(` 2. ${info.label} — ${fpSorted[1][1].length} cases`);
|
|
221
|
+
}
|
|
222
|
+
console.log(` 3. Expand curl labels from ${report.total} to 100-150 samples`);
|
|
223
|
+
console.log(` 4. Re-measure Precision after fixing top category`);
|
|
224
|
+
console.log("");
|
|
225
|
+
}
|
|
226
|
+
// CLI
|
|
227
|
+
const args = process.argv.slice(2);
|
|
228
|
+
const repoPath = path.resolve(args.find(a => !a.startsWith("--")) || ".");
|
|
229
|
+
analyze(repoPath);
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.runPrecisionBenchmark = runPrecisionBenchmark;
|
|
37
|
+
const fs = __importStar(require("fs"));
|
|
38
|
+
const state_inference_1 = require("./experimental/state-inference");
|
|
39
|
+
/**
|
|
40
|
+
* Run precision benchmark with labeled data.
|
|
41
|
+
*
|
|
42
|
+
* Detection logic (structural, not template-matching):
|
|
43
|
+
* 1. Build REFERENCE SM from clean-labeled sequences
|
|
44
|
+
* 2. For each test sequence, build its SM
|
|
45
|
+
* 3. Compare: if a sequence has ≥2 fewer states than the reference,
|
|
46
|
+
* OR has illegal transitions not in the reference, it's flagged.
|
|
47
|
+
* 4. Measure TP/FP/TN/FN against labels.
|
|
48
|
+
*/
|
|
49
|
+
function runPrecisionBenchmark(sequences, labels) {
|
|
50
|
+
// Build reference SM from clean sequences only
|
|
51
|
+
const cleanSeqs = sequences
|
|
52
|
+
.filter(s => labels[s.index] === 'clean' && s.calls.length >= 2)
|
|
53
|
+
.map(s => s.calls);
|
|
54
|
+
if (cleanSeqs.length === 0) {
|
|
55
|
+
return { total: 0, truePositive: 0, falsePositive: 0, trueNegative: 0, falseNegative: 0, precision: 0, recall: 0, f1: 0, mismatches: [] };
|
|
56
|
+
}
|
|
57
|
+
const referenceSM = (0, state_inference_1.inferStateMachine)(cleanSeqs);
|
|
58
|
+
const refStateCount = referenceSM.stateCount;
|
|
59
|
+
// Extract reference edge set (what transitions are "normal")
|
|
60
|
+
const refEdges = new Set();
|
|
61
|
+
for (let i = 0; i < referenceSM.stateTransitions.length; i++)
|
|
62
|
+
for (let j = 0; j < (referenceSM.stateTransitions[i] || []).length; j++)
|
|
63
|
+
if (referenceSM.stateTransitions[i][j] > 0)
|
|
64
|
+
refEdges.add(`${i}→${j}`);
|
|
65
|
+
let tp = 0, fp = 0, tn = 0, fn = 0;
|
|
66
|
+
const mismatches = [];
|
|
67
|
+
for (const seq of sequences) {
|
|
68
|
+
const expected = labels[seq.index] || 'skip';
|
|
69
|
+
if (expected === 'skip')
|
|
70
|
+
continue;
|
|
71
|
+
if (seq.calls.length < 2) {
|
|
72
|
+
tn++;
|
|
73
|
+
continue;
|
|
74
|
+
}
|
|
75
|
+
const testSM = (0, state_inference_1.inferStateMachine)([seq.calls]);
|
|
76
|
+
const stateDiff = refStateCount - testSM.stateCount;
|
|
77
|
+
// Detection: flagged if ≥2 fewer states than reference
|
|
78
|
+
const detected = stateDiff >= 2 ? 'violation' : 'clean';
|
|
79
|
+
let matched = false;
|
|
80
|
+
if (expected === 'clean' && detected === 'clean') {
|
|
81
|
+
tn++;
|
|
82
|
+
matched = true;
|
|
83
|
+
}
|
|
84
|
+
else if (expected === 'violation' && detected === 'violation') {
|
|
85
|
+
tp++;
|
|
86
|
+
matched = true;
|
|
87
|
+
}
|
|
88
|
+
else if (expected === 'clean' && detected === 'violation') {
|
|
89
|
+
fp++;
|
|
90
|
+
}
|
|
91
|
+
else if (expected === 'violation' && detected === 'clean') {
|
|
92
|
+
fn++;
|
|
93
|
+
}
|
|
94
|
+
if (!matched) {
|
|
95
|
+
mismatches.push({
|
|
96
|
+
index: seq.index,
|
|
97
|
+
functionName: seq.functionName,
|
|
98
|
+
expected,
|
|
99
|
+
detected,
|
|
100
|
+
stateDiff,
|
|
101
|
+
calls: seq.calls,
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
const total = tp + fp + tn + fn;
|
|
106
|
+
const precision = total > 0 ? tp / (tp + fp) : 0;
|
|
107
|
+
const recall = total > 0 ? tp / (tp + fn) : 0;
|
|
108
|
+
const f1 = precision + recall > 0 ? 2 * precision * recall / (precision + recall) : 0;
|
|
109
|
+
return { total, truePositive: tp, falsePositive: fp, trueNegative: tn, falseNegative: fn, precision, recall, f1, mismatches };
|
|
110
|
+
}
|
|
111
|
+
// ================ CLI ================
|
|
112
|
+
const args = process.argv.slice(2);
|
|
113
|
+
const seqFile = args[0];
|
|
114
|
+
const labelFile = args[1];
|
|
115
|
+
if (!seqFile || !labelFile) {
|
|
116
|
+
console.error('Usage: npx tsx src/precision-benchmark.ts <sequences.json> <labels.json>');
|
|
117
|
+
process.exit(1);
|
|
118
|
+
}
|
|
119
|
+
const seqData = JSON.parse(fs.readFileSync(seqFile, 'utf-8'));
|
|
120
|
+
const sequences = seqData.sequences || seqData;
|
|
121
|
+
const labels = JSON.parse(fs.readFileSync(labelFile, 'utf-8'));
|
|
122
|
+
console.log('Running precision benchmark...');
|
|
123
|
+
const result = runPrecisionBenchmark(sequences, labels);
|
|
124
|
+
console.log('\n=== Precision Benchmark Results ===');
|
|
125
|
+
console.log(`Total sequences evaluated: ${result.total}`);
|
|
126
|
+
console.log(`True Positives: ${result.truePositive}`);
|
|
127
|
+
console.log(`False Positives: ${result.falsePositive}`);
|
|
128
|
+
console.log(`True Negatives: ${result.trueNegative}`);
|
|
129
|
+
console.log(`False Negatives: ${result.falseNegative}`);
|
|
130
|
+
console.log(`\nPrecision: ${(result.precision * 100).toFixed(1)}%`);
|
|
131
|
+
console.log(`Recall: ${(result.recall * 100).toFixed(1)}%`);
|
|
132
|
+
console.log(`F1 Score: ${(result.f1 * 100).toFixed(1)}%`);
|
|
133
|
+
// 显示不匹配的详情
|
|
134
|
+
const mismatches = (result.details || []).filter((d) => !d.matched);
|
|
135
|
+
if (mismatches.length > 0) {
|
|
136
|
+
console.log(`\n--- Mismatches (${mismatches.length}) ---`);
|
|
137
|
+
for (const m of mismatches) {
|
|
138
|
+
console.log(` [${m.index}] ${m.functionName}: expected=${m.expected}, detected=${m.detected}`);
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
// 保存报告
|
|
142
|
+
const report = {
|
|
143
|
+
timestamp: new Date().toISOString(),
|
|
144
|
+
result
|
|
145
|
+
};
|
|
146
|
+
fs.writeFileSync('benchmarks/precision-report.json', JSON.stringify(report, null, 2));
|
|
147
|
+
console.log('\nReport saved to benchmarks/precision-report.json');
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Precision Labeling Tool for C/C++ projects
|
|
4
|
+
*
|
|
5
|
+
* Reads pre-extracted sequences JSON and saves labels.
|
|
6
|
+
* For TypeScript projects, use precision-label.ts instead.
|
|
7
|
+
*
|
|
8
|
+
* Usage:
|
|
9
|
+
* npx ts-node src/precision-label-c.ts benchmarks/curl
|
|
10
|
+
*/
|
|
11
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
12
|
+
if (k2 === undefined) k2 = k;
|
|
13
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
14
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
15
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
16
|
+
}
|
|
17
|
+
Object.defineProperty(o, k2, desc);
|
|
18
|
+
}) : (function(o, m, k, k2) {
|
|
19
|
+
if (k2 === undefined) k2 = k;
|
|
20
|
+
o[k2] = m[k];
|
|
21
|
+
}));
|
|
22
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
23
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
24
|
+
}) : function(o, v) {
|
|
25
|
+
o["default"] = v;
|
|
26
|
+
});
|
|
27
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
28
|
+
var ownKeys = function(o) {
|
|
29
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
30
|
+
var ar = [];
|
|
31
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
32
|
+
return ar;
|
|
33
|
+
};
|
|
34
|
+
return ownKeys(o);
|
|
35
|
+
};
|
|
36
|
+
return function (mod) {
|
|
37
|
+
if (mod && mod.__esModule) return mod;
|
|
38
|
+
var result = {};
|
|
39
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
40
|
+
__setModuleDefault(result, mod);
|
|
41
|
+
return result;
|
|
42
|
+
};
|
|
43
|
+
})();
|
|
44
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
45
|
+
const fs = __importStar(require("fs"));
|
|
46
|
+
const path = __importStar(require("path"));
|
|
47
|
+
const readline = __importStar(require("readline"));
|
|
48
|
+
const C = {
|
|
49
|
+
reset: "\x1b[0m", bold: "\x1b[1m", dim: "\x1b[2m",
|
|
50
|
+
green: "\x1b[32m", red: "\x1b[31m", yellow: "\x1b[33m", cyan: "\x1b[36m",
|
|
51
|
+
};
|
|
52
|
+
async function main() {
|
|
53
|
+
const args = process.argv.slice(2);
|
|
54
|
+
const repoPath = path.resolve(args.find(a => !a.startsWith("--")) || ".");
|
|
55
|
+
const maxSeq = parseInt(args.includes("--max") ? args[args.indexOf("--max") + 1] : "50", 10);
|
|
56
|
+
const resume = args.includes("--resume");
|
|
57
|
+
const seqFile = path.join(path.dirname(repoPath), `${path.basename(repoPath)}-sequences.json`);
|
|
58
|
+
const labelFile = path.join(path.dirname(repoPath), `${path.basename(repoPath)}-labels.json`);
|
|
59
|
+
if (!fs.existsSync(seqFile)) {
|
|
60
|
+
console.error(`❌ Sequences file not found: ${seqFile}`);
|
|
61
|
+
console.error(` Run C extraction first to generate this file.`);
|
|
62
|
+
process.exit(1);
|
|
63
|
+
}
|
|
64
|
+
// Load sequences
|
|
65
|
+
const allSeqs = JSON.parse(fs.readFileSync(seqFile, "utf-8"));
|
|
66
|
+
const sequences = allSeqs.slice(0, maxSeq);
|
|
67
|
+
// Load existing labels (resume)
|
|
68
|
+
let data = { repo: repoPath, labeledAt: "", total: 0, labels: {}, sequences: {} };
|
|
69
|
+
if (fs.existsSync(labelFile) && resume) {
|
|
70
|
+
data = JSON.parse(fs.readFileSync(labelFile, "utf-8"));
|
|
71
|
+
}
|
|
72
|
+
else if (fs.existsSync(labelFile)) {
|
|
73
|
+
data = JSON.parse(fs.readFileSync(labelFile, "utf-8"));
|
|
74
|
+
}
|
|
75
|
+
const alreadyLabeled = Object.keys(data.labels).length;
|
|
76
|
+
console.error(`\n${C.bold}${C.cyan}Precision Labeling — C/C++ Projects${C.reset}`);
|
|
77
|
+
console.error(` Sequences: ${sequences.length} (${alreadyLabeled} already labeled)`);
|
|
78
|
+
console.error(` Commands: ${C.green}c${C.reset}=clean ${C.red}v${C.reset}=violation ${C.yellow}s${C.reset}=skip q=quit\n`);
|
|
79
|
+
console.error(` ${C.dim}clean = protocol looks complete (init→use→cleanup present)${C.reset}`);
|
|
80
|
+
console.error(` ${C.dim}violation = protocol incomplete (missing init/cleanup, wrong order)${C.reset}`);
|
|
81
|
+
console.error(``);
|
|
82
|
+
const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
|
|
83
|
+
const ask = (q) => new Promise(resolve => rl.question(q, resolve));
|
|
84
|
+
let labeled = 0;
|
|
85
|
+
let skipped = 0;
|
|
86
|
+
for (let i = 0; i < sequences.length; i++) {
|
|
87
|
+
if (data.labels[i] !== undefined)
|
|
88
|
+
continue;
|
|
89
|
+
const seq = sequences[i];
|
|
90
|
+
const calls = seq.calls.slice(0, 8);
|
|
91
|
+
const more = seq.calls.length > 8 ? ` … (+${seq.calls.length - 8} more)` : "";
|
|
92
|
+
console.error(`${C.bold}[${i + 1}/${sequences.length}]${C.reset} ${C.dim}${seq.file || ""}${C.reset}`);
|
|
93
|
+
console.error(` ${C.cyan}${seq.function}${C.reset}`);
|
|
94
|
+
console.error(` → ${calls.join(" → ")}${more}`);
|
|
95
|
+
const answer = await ask(` ${C.green}[c]lean${C.reset} ${C.red}[v]iolation${C.reset} ${C.yellow}[s]kip${C.reset} [q]uit: `);
|
|
96
|
+
switch (answer) {
|
|
97
|
+
case "q":
|
|
98
|
+
console.error(`\n Quit. Saving ${labeled} new labels...`);
|
|
99
|
+
rl.close();
|
|
100
|
+
saveLabels(labelFile, data, labeled + alreadyLabeled);
|
|
101
|
+
return;
|
|
102
|
+
case "s":
|
|
103
|
+
skipped++;
|
|
104
|
+
console.error(` ${C.yellow}↻ skipped${C.reset}\n`);
|
|
105
|
+
continue;
|
|
106
|
+
case "c":
|
|
107
|
+
data.labels[i] = "clean";
|
|
108
|
+
data.sequences[i] = seq.calls;
|
|
109
|
+
labeled++;
|
|
110
|
+
console.error(` ${C.green}✓ clean${C.reset}\n`);
|
|
111
|
+
break;
|
|
112
|
+
case "v":
|
|
113
|
+
data.labels[i] = "violation";
|
|
114
|
+
data.sequences[i] = seq.calls;
|
|
115
|
+
labeled++;
|
|
116
|
+
console.error(` ${C.red}✗ violation${C.reset}\n`);
|
|
117
|
+
break;
|
|
118
|
+
default:
|
|
119
|
+
console.error(` ${C.yellow}? unknown — use c/v/s/q${C.reset}\n`);
|
|
120
|
+
break;
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
rl.close();
|
|
124
|
+
saveLabels(labelFile, data, labeled + alreadyLabeled);
|
|
125
|
+
console.error(`\n Clean: ${Object.values(data.labels).filter((l) => l === "clean").length}`);
|
|
126
|
+
console.error(` Violation: ${Object.values(data.labels).filter((l) => l === "violation").length}`);
|
|
127
|
+
console.error(`\n Next: npx ts-node src/precision-report-c.ts ${repoPath}\n`);
|
|
128
|
+
}
|
|
129
|
+
function saveLabels(filePath, data, total) {
|
|
130
|
+
data.labeledAt = new Date().toISOString();
|
|
131
|
+
data.total = total;
|
|
132
|
+
fs.writeFileSync(filePath, JSON.stringify(data, null, 2), "utf-8");
|
|
133
|
+
}
|
|
134
|
+
main().catch(e => { console.error(e); process.exit(1); });
|