thumbgate 1.4.3 → 1.4.5
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/.claude-plugin/marketplace.json +2 -2
- package/.claude-plugin/plugin.json +1 -1
- package/.well-known/llms.txt +12 -8
- package/.well-known/mcp/server-card.json +1 -1
- package/README.md +18 -8
- package/adapters/README.md +1 -1
- package/adapters/claude/.mcp.json +2 -2
- package/adapters/codex/config.toml +2 -2
- package/adapters/mcp/server-stdio.js +1 -1
- package/adapters/opencode/opencode.json +1 -1
- package/config/github-about.json +2 -2
- package/package.json +158 -10
- package/scripts/billing.js +5 -2
- package/scripts/statusline.sh +1 -0
- package/src/api/server.js +113 -16
- package/src/index.js +3 -0
- package/.claude-plugin/bundle/icon.png +0 -0
- package/.claude-plugin/bundle/icon.svg +0 -18
- package/.claude-plugin/bundle/server/index.js +0 -24
- package/adapters/chatgpt/INSTALL.md +0 -158
- package/adapters/perplexity/.mcp.json +0 -36
- package/adapters/perplexity/config.toml +0 -16
- package/adapters/perplexity/opencode.json +0 -29
- package/bin/memory.sh +0 -64
- package/bin/obsidian-sync.sh +0 -20
- package/plugins/amp-skill/INSTALL.md +0 -52
- package/plugins/amp-skill/SKILL.md +0 -64
- package/plugins/claude-codex-bridge/.claude-plugin/plugin.json +0 -22
- package/plugins/claude-codex-bridge/.mcp.json +0 -14
- package/plugins/claude-codex-bridge/INSTALL.md +0 -43
- package/plugins/claude-codex-bridge/README.md +0 -46
- package/plugins/claude-codex-bridge/scripts/codex-bridge.js +0 -286
- package/plugins/claude-codex-bridge/skills/adversarial-review/SKILL.md +0 -24
- package/plugins/claude-codex-bridge/skills/result/SKILL.md +0 -22
- package/plugins/claude-codex-bridge/skills/review/SKILL.md +0 -28
- package/plugins/claude-codex-bridge/skills/second-pass/SKILL.md +0 -27
- package/plugins/claude-codex-bridge/skills/setup/SKILL.md +0 -21
- package/plugins/claude-codex-bridge/skills/status/SKILL.md +0 -19
- package/plugins/claude-skill/INSTALL.md +0 -55
- package/plugins/claude-skill/SKILL.md +0 -46
- package/plugins/codex-profile/.codex-plugin/plugin.json +0 -43
- package/plugins/codex-profile/.mcp.json +0 -14
- package/plugins/codex-profile/AGENTS.md +0 -20
- package/plugins/codex-profile/INSTALL.md +0 -89
- package/plugins/codex-profile/README.md +0 -61
- package/plugins/cursor-marketplace/.cursor-plugin/plugin.json +0 -23
- package/plugins/cursor-marketplace/CHANGELOG.md +0 -30
- package/plugins/cursor-marketplace/LICENSE +0 -21
- package/plugins/cursor-marketplace/README.md +0 -124
- package/plugins/cursor-marketplace/agents/reliability-reviewer.md +0 -31
- package/plugins/cursor-marketplace/assets/logo-400x400.png +0 -0
- package/plugins/cursor-marketplace/commands/capture-feedback.md +0 -33
- package/plugins/cursor-marketplace/commands/check-gates.md +0 -25
- package/plugins/cursor-marketplace/commands/show-lessons.md +0 -27
- package/plugins/cursor-marketplace/hooks/hooks.json +0 -10
- package/plugins/cursor-marketplace/mcp.json +0 -14
- package/plugins/cursor-marketplace/rules/feedback-capture.mdc +0 -34
- package/plugins/cursor-marketplace/rules/pre-action-gates.mdc +0 -30
- package/plugins/cursor-marketplace/rules/session-continuity.mdc +0 -28
- package/plugins/cursor-marketplace/scripts/gate-check.sh +0 -21
- package/plugins/cursor-marketplace/skills/capture-feedback/SKILL.md +0 -48
- package/plugins/cursor-marketplace/skills/prevention-rules/SKILL.md +0 -31
- package/plugins/cursor-marketplace/skills/recall-context/SKILL.md +0 -30
- package/plugins/cursor-marketplace/skills/search-lessons/SKILL.md +0 -33
- package/plugins/gemini-extension/INSTALL.md +0 -92
- package/plugins/gemini-extension/gemini_prompt.txt +0 -14
- package/plugins/gemini-extension/tool_contract.json +0 -45
- package/plugins/opencode-profile/INSTALL.md +0 -57
- package/public/assets/instagram-card.png +0 -0
- package/public/assets/tiktok-agent-memory.mp4 +0 -0
- package/public/blog.html +0 -474
- package/public/compare/mem0.html +0 -189
- package/public/compare/speclock.html +0 -180
- package/public/compare.html +0 -310
- package/public/dashboard.html +0 -1100
- package/public/guide.html +0 -317
- package/public/guides/claude-code-prevent-repeated-mistakes.html +0 -161
- package/public/guides/codex-cli-guardrails.html +0 -158
- package/public/guides/cursor-prevent-repeated-mistakes.html +0 -161
- package/public/guides/pre-action-gates.html +0 -162
- package/public/guides/stop-repeated-ai-agent-mistakes.html +0 -159
- package/public/index.html +0 -1225
- package/public/js/buyer-intent.js +0 -252
- package/public/learn/agent-harness-pattern.html +0 -180
- package/public/learn/ai-agent-persistent-memory.html +0 -203
- package/public/learn/learn.css +0 -45
- package/public/learn/mcp-pre-action-gates-explained.html +0 -172
- package/public/learn/stop-ai-agent-force-push.html +0 -134
- package/public/learn/vibe-coding-safety-net.html +0 -142
- package/public/learn.html +0 -274
- package/public/lessons.html +0 -967
- package/public/llm-context.md +0 -156
- package/public/pro.html +0 -1087
- package/public/vercel.json +0 -8
- package/scripts/a2ui-engine.js +0 -73
- package/scripts/adk-consolidator.js +0 -274
- package/scripts/agent-security-hardening.js +0 -225
- package/scripts/ai-search-visibility.js +0 -116
- package/scripts/autonomous-sales-agent.js +0 -39
- package/scripts/autoresearch-runner.js +0 -216
- package/scripts/background-agent-governance.js +0 -229
- package/scripts/behavioral-extraction.js +0 -93
- package/scripts/budget-enforcer.js +0 -173
- package/scripts/budget-guard.js +0 -173
- package/scripts/build-claude-mcpb.js +0 -255
- package/scripts/build-codex-plugin.js +0 -152
- package/scripts/capture-railway-diagnostics.sh +0 -97
- package/scripts/changeset-check.js +0 -372
- package/scripts/check-congruence.js +0 -443
- package/scripts/computer-use-firewall.js +0 -280
- package/scripts/content-engine/linkedin-content-generator.js +0 -154
- package/scripts/content-engine/output/linkedin-memento-validation.md +0 -17
- package/scripts/content-engine/output/linkedin-posts-2026-04-09.md +0 -175
- package/scripts/content-engine/reddit-thread-finder.js +0 -154
- package/scripts/context-engine.js +0 -710
- package/scripts/daily-digest.js +0 -11
- package/scripts/data-governance.js +0 -173
- package/scripts/deploy-gcp.sh +0 -44
- package/scripts/deploy-policy.js +0 -249
- package/scripts/disagreement-mining.js +0 -315
- package/scripts/dpo-optimizer.js +0 -206
- package/scripts/ensure-repo-bootstrap.js +0 -130
- package/scripts/ephemeral-agent-store.js +0 -212
- package/scripts/eval-harness.js +0 -56
- package/scripts/export-kto-pairs.js +0 -309
- package/scripts/export-training.js +0 -446
- package/scripts/feedback-fallback.js +0 -111
- package/scripts/feedback-inbox-read.js +0 -162
- package/scripts/feedback-root-consolidator.js +0 -233
- package/scripts/feedback-to-memory.js +0 -185
- package/scripts/gate-satisfy.js +0 -42
- package/scripts/generate-paperbanana-diagrams.sh +0 -99
- package/scripts/generate-pretool-hook.sh +0 -40
- package/scripts/github-about.js +0 -430
- package/scripts/github-outreach.js +0 -65
- package/scripts/gtm-revenue-loop.js +0 -535
- package/scripts/hallucination-detector.js +0 -226
- package/scripts/hf-papers.js +0 -317
- package/scripts/hook-auto-capture.sh +0 -100
- package/scripts/hook-stop-pr-thread-check.sh +0 -68
- package/scripts/hook-stop-self-score.sh +0 -51
- package/scripts/hook-stop-verify-deploy.sh +0 -31
- package/scripts/hook-verify-before-done.sh +0 -20
- package/scripts/managed-dpo-export.js +0 -91
- package/scripts/markdown-escape.js +0 -12
- package/scripts/marketing-experiment.js +0 -657
- package/scripts/memalign-recall.js +0 -111
- package/scripts/memory-migration.js +0 -296
- package/scripts/meta-policy.js +0 -190
- package/scripts/metered-billing.js +0 -16
- package/scripts/model-tier-router.js +0 -310
- package/scripts/money-watcher.js +0 -218
- package/scripts/multi-hop-recall.js +0 -240
- package/scripts/per-step-scoring.js +0 -163
- package/scripts/perplexity-command-center.js +0 -644
- package/scripts/perplexity-marketing.js +0 -454
- package/scripts/pii-scanner.js +0 -153
- package/scripts/plan-gate.js +0 -154
- package/scripts/post-everywhere.js +0 -341
- package/scripts/post-to-x-retry.sh +0 -22
- package/scripts/post-to-x.js +0 -369
- package/scripts/pr-manager.js +0 -421
- package/scripts/principle-extractor.js +0 -162
- package/scripts/pro-features.js +0 -41
- package/scripts/prompt-dlp.js +0 -222
- package/scripts/prove-adapters.js +0 -860
- package/scripts/prove-attribution.js +0 -361
- package/scripts/prove-automation.js +0 -651
- package/scripts/prove-autoresearch.js +0 -304
- package/scripts/prove-claim-verification.js +0 -277
- package/scripts/prove-cloudflare-sandbox.js +0 -161
- package/scripts/prove-data-pipeline.js +0 -408
- package/scripts/prove-data-quality.js +0 -227
- package/scripts/prove-evolution.js +0 -352
- package/scripts/prove-harnesses.js +0 -287
- package/scripts/prove-intelligence.js +0 -257
- package/scripts/prove-lancedb.js +0 -425
- package/scripts/prove-local-intelligence.js +0 -340
- package/scripts/prove-loop-closure.js +0 -263
- package/scripts/prove-packaged-runtime.js +0 -327
- package/scripts/prove-predictive-insights.js +0 -355
- package/scripts/prove-runtime.js +0 -363
- package/scripts/prove-seo-gsd.js +0 -234
- package/scripts/prove-settings.js +0 -279
- package/scripts/prove-subway-upgrades.js +0 -277
- package/scripts/prove-tessl.js +0 -229
- package/scripts/prove-training-export.js +0 -325
- package/scripts/prove-workflow-contract.js +0 -112
- package/scripts/prove-xmemory.js +0 -332
- package/scripts/publish-decision.js +0 -159
- package/scripts/ralph-loop.js +0 -376
- package/scripts/ralph-mode-ci.js +0 -434
- package/scripts/reddit-dm-outreach.js +0 -192
- package/scripts/reddit-monitor-cron.sh +0 -26
- package/scripts/reminder-engine.js +0 -132
- package/scripts/revenue-status.js +0 -472
- package/scripts/rotate-stripe-webhook-secret.js +0 -314
- package/scripts/schedule-manager.js +0 -249
- package/scripts/self-healing-check.js +0 -193
- package/scripts/session-analyzer.js +0 -533
- package/scripts/shieldcortex-memory-firewall-runner.mjs +0 -53
- package/scripts/skill-exporter.js +0 -260
- package/scripts/skill-materializer.js +0 -134
- package/scripts/skill-packs.js +0 -136
- package/scripts/skill-proposer.js +0 -99
- package/scripts/skill-quality-tracker.js +0 -282
- package/scripts/slow-loop.js +0 -72
- package/scripts/social-analytics/db/marketing-db.js +0 -179
- package/scripts/social-analytics/db/schema.sql +0 -55
- package/scripts/social-analytics/digest.js +0 -256
- package/scripts/social-analytics/engagement-audit.js +0 -185
- package/scripts/social-analytics/generate-instagram-card.js +0 -123
- package/scripts/social-analytics/generate-slides.js +0 -268
- package/scripts/social-analytics/instagram-thumbgate-post.js +0 -111
- package/scripts/social-analytics/install-growth-automation.js +0 -114
- package/scripts/social-analytics/load-env.js +0 -77
- package/scripts/social-analytics/mcp-server.js +0 -289
- package/scripts/social-analytics/normalizer.js +0 -580
- package/scripts/social-analytics/notify.js +0 -162
- package/scripts/social-analytics/poll-all.js +0 -107
- package/scripts/social-analytics/pollers/github.js +0 -195
- package/scripts/social-analytics/pollers/instagram.js +0 -253
- package/scripts/social-analytics/pollers/linkedin.js +0 -340
- package/scripts/social-analytics/pollers/plausible.js +0 -245
- package/scripts/social-analytics/pollers/reddit.js +0 -306
- package/scripts/social-analytics/pollers/threads.js +0 -233
- package/scripts/social-analytics/pollers/tiktok.js +0 -203
- package/scripts/social-analytics/pollers/x.js +0 -227
- package/scripts/social-analytics/pollers/youtube.js +0 -304
- package/scripts/social-analytics/pollers/zernio.js +0 -183
- package/scripts/social-analytics/post-video.js +0 -316
- package/scripts/social-analytics/publish-instagram-thumbgate.js +0 -104
- package/scripts/social-analytics/publish-thumbgate-launch.js +0 -322
- package/scripts/social-analytics/publishers/devto.js +0 -122
- package/scripts/social-analytics/publishers/instagram.js +0 -317
- package/scripts/social-analytics/publishers/linkedin.js +0 -294
- package/scripts/social-analytics/publishers/reddit.js +0 -385
- package/scripts/social-analytics/publishers/threads.js +0 -275
- package/scripts/social-analytics/publishers/tiktok.js +0 -217
- package/scripts/social-analytics/publishers/x.js +0 -259
- package/scripts/social-analytics/publishers/youtube.js +0 -223
- package/scripts/social-analytics/publishers/zernio.js +0 -568
- package/scripts/social-analytics/reconcile-thumbgate-campaign.js +0 -165
- package/scripts/social-analytics/run-digest.js +0 -34
- package/scripts/social-analytics/schedule-thumbgate-campaign.js +0 -275
- package/scripts/social-analytics/store.js +0 -455
- package/scripts/social-analytics/sync-launch-assets.js +0 -185
- package/scripts/social-analytics/utm.js +0 -143
- package/scripts/social-pipeline.js +0 -2626
- package/scripts/social-post-hourly.js +0 -228
- package/scripts/social-quality-gate.js +0 -134
- package/scripts/social-reply-monitor.js +0 -592
- package/scripts/status-dashboard.js +0 -155
- package/scripts/stripe-live-status.js +0 -115
- package/scripts/subagent-profiles.js +0 -79
- package/scripts/sync-branch-protection.js +0 -340
- package/scripts/sync-gh-secrets-from-env.sh +0 -70
- package/scripts/sync-github-about.js +0 -55
- package/scripts/sync-version.js +0 -479
- package/scripts/synthetic-dpo.js +0 -234
- package/scripts/tessl-export.js +0 -369
- package/scripts/test-coverage.js +0 -128
- package/scripts/thumbgate-bench.js +0 -494
- package/scripts/thumbgate_session_start.sh +0 -32
- package/scripts/train_from_feedback.py +0 -929
- package/scripts/validate-feedback.js +0 -581
- package/scripts/verify-obsidian-setup.sh +0 -269
- package/scripts/verify-run.js +0 -269
- package/scripts/weekly-auto-post.js +0 -124
- package/scripts/x-autonomous-marketing.js +0 -139
|
@@ -1,340 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
'use strict';
|
|
3
|
-
|
|
4
|
-
const fs = require('fs');
|
|
5
|
-
const os = require('os');
|
|
6
|
-
const path = require('path');
|
|
7
|
-
const { execSync } = require('child_process');
|
|
8
|
-
const { ensureDir } = require('./fs-utils');
|
|
9
|
-
|
|
10
|
-
const ROOT = path.join(__dirname, '..');
|
|
11
|
-
const DEFAULT_PROOF_DIR = process.env.THUMBGATE_PROOF_DIR || path.join(ROOT, 'proof');
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
function runTests() {
|
|
15
|
-
try {
|
|
16
|
-
return execSync(
|
|
17
|
-
'node --test tests/local-model-profile.test.js tests/model-tier-router.test.js tests/profile-router.test.js tests/risk-scorer.test.js tests/vector-store.test.js tests/feedback-sequences.test.js tests/feedback-history-distiller.test.js tests/feedback-loop.test.js',
|
|
18
|
-
{ cwd: ROOT, encoding: 'utf8', stdio: ['pipe', 'pipe', 'pipe'] }
|
|
19
|
-
);
|
|
20
|
-
} catch (err) {
|
|
21
|
-
return err.stdout || err.stderr || String(err);
|
|
22
|
-
}
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
function parseTestOutput(output) {
|
|
26
|
-
const passMatch = output.match(/ℹ pass (\d+)/);
|
|
27
|
-
const failMatch = output.match(/ℹ fail (\d+)/);
|
|
28
|
-
return {
|
|
29
|
-
passed: passMatch ? Number(passMatch[1]) : 0,
|
|
30
|
-
failed: failMatch ? Number(failMatch[1]) : 0,
|
|
31
|
-
};
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
async function main() {
|
|
35
|
-
const output = runTests();
|
|
36
|
-
const testResults = parseTestOutput(output);
|
|
37
|
-
const proofDir = DEFAULT_PROOF_DIR;
|
|
38
|
-
ensureDir(proofDir);
|
|
39
|
-
|
|
40
|
-
const tmpFeedbackDir = fs.mkdtempSync(path.join(os.tmpdir(), 'thumbgate-local-intel-'));
|
|
41
|
-
const report = {
|
|
42
|
-
generatedAt: new Date().toISOString(),
|
|
43
|
-
checks: [],
|
|
44
|
-
summary: { passed: 0, failed: 0 },
|
|
45
|
-
testResults,
|
|
46
|
-
};
|
|
47
|
-
|
|
48
|
-
function addResult(id, passed, evidence) {
|
|
49
|
-
report.checks.push({ id, passed, evidence });
|
|
50
|
-
if (passed) report.summary.passed += 1;
|
|
51
|
-
else report.summary.failed += 1;
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
try {
|
|
55
|
-
const {
|
|
56
|
-
writeModelFitReport,
|
|
57
|
-
detectInferenceBackend,
|
|
58
|
-
recommendInferenceBackend,
|
|
59
|
-
} = require('./local-model-profile');
|
|
60
|
-
const { recommendExecutionPlan } = require('./model-tier-router');
|
|
61
|
-
const { routeInference } = require('./profile-router');
|
|
62
|
-
const { reportPath, report: modelFitReport } = writeModelFitReport(tmpFeedbackDir, {
|
|
63
|
-
resolved: require('./local-model-profile').resolveEmbeddingProfile({
|
|
64
|
-
THUMBGATE_RAM_BYTES_OVERRIDE: String(4 * 1024 ** 3),
|
|
65
|
-
THUMBGATE_CPU_COUNT_OVERRIDE: '4',
|
|
66
|
-
}),
|
|
67
|
-
});
|
|
68
|
-
addResult(
|
|
69
|
-
'FIT-01',
|
|
70
|
-
fs.existsSync(reportPath) && modelFitReport.selectedProfile.id === 'compact',
|
|
71
|
-
`model-fit report written; selected profile=${modelFitReport.selectedProfile.id}; maxChars=${modelFitReport.selectedProfile.maxChars}`
|
|
72
|
-
);
|
|
73
|
-
|
|
74
|
-
process.env.THUMBGATE_FEEDBACK_DIR = tmpFeedbackDir;
|
|
75
|
-
process.env.THUMBGATE_MODEL_FIT_PROFILE = 'quality';
|
|
76
|
-
process.env.THUMBGATE_VECTOR_FORCE_PRIMARY_FAILURE = 'true';
|
|
77
|
-
delete process.env.THUMBGATE_VECTOR_STUB_EMBED;
|
|
78
|
-
delete require.cache[require.resolve('./vector-store')];
|
|
79
|
-
const vectorStore = require('./vector-store');
|
|
80
|
-
vectorStore.setLanceLoaderForTests(async () => {
|
|
81
|
-
const tables = new Map();
|
|
82
|
-
return {
|
|
83
|
-
connect: async () => ({
|
|
84
|
-
tableNames: async () => [...tables.keys()],
|
|
85
|
-
openTable: async (name) => {
|
|
86
|
-
const rows = tables.get(name) || [];
|
|
87
|
-
return {
|
|
88
|
-
add: async (records) => {
|
|
89
|
-
rows.push(...records);
|
|
90
|
-
tables.set(name, rows);
|
|
91
|
-
},
|
|
92
|
-
search: () => ({
|
|
93
|
-
limit: (limit) => ({
|
|
94
|
-
toArray: async () => rows.slice(0, limit),
|
|
95
|
-
}),
|
|
96
|
-
}),
|
|
97
|
-
};
|
|
98
|
-
},
|
|
99
|
-
createTable: async (name, records) => {
|
|
100
|
-
tables.set(name, [...records]);
|
|
101
|
-
return {
|
|
102
|
-
add: async (more) => {
|
|
103
|
-
const rows = tables.get(name) || [];
|
|
104
|
-
rows.push(...more);
|
|
105
|
-
tables.set(name, rows);
|
|
106
|
-
},
|
|
107
|
-
};
|
|
108
|
-
},
|
|
109
|
-
}),
|
|
110
|
-
};
|
|
111
|
-
});
|
|
112
|
-
vectorStore.setPipelineLoaderForTests(async (_task, model, opts) => async () => ({
|
|
113
|
-
data: Float32Array.from({ length: 384 }, (_, index) => (index === 0 ? 1 : 0)),
|
|
114
|
-
model,
|
|
115
|
-
opts,
|
|
116
|
-
}));
|
|
117
|
-
await vectorStore.upsertFeedback({
|
|
118
|
-
id: 'proof-local-intel',
|
|
119
|
-
signal: 'positive',
|
|
120
|
-
context: 'vector fallback proof',
|
|
121
|
-
tags: ['proof'],
|
|
122
|
-
timestamp: new Date().toISOString(),
|
|
123
|
-
});
|
|
124
|
-
const fallbackProfile = vectorStore.getLastEmbeddingProfile();
|
|
125
|
-
addResult(
|
|
126
|
-
'FIT-02',
|
|
127
|
-
Boolean(fallbackProfile && fallbackProfile.fallbackUsed),
|
|
128
|
-
`vector-store active profile=${fallbackProfile && fallbackProfile.activeProfile ? fallbackProfile.activeProfile.id : 'none'}; fallbackUsed=${fallbackProfile ? fallbackProfile.fallbackUsed : false}; reason=${fallbackProfile ? fallbackProfile.fallbackReason : 'n/a'}`
|
|
129
|
-
);
|
|
130
|
-
|
|
131
|
-
const sparseBackend = detectInferenceBackend({
|
|
132
|
-
THUMBGATE_PROVIDER_MODE: 'local',
|
|
133
|
-
THUMBGATE_LOCAL_MODEL_FAMILY: 'deepseek-r1',
|
|
134
|
-
THUMBGATE_LOCAL_MODEL_SERVER: 'sglang',
|
|
135
|
-
THUMBGATE_INDEXCACHE_ENABLED: 'true',
|
|
136
|
-
});
|
|
137
|
-
addResult(
|
|
138
|
-
'IDX-01',
|
|
139
|
-
sparseBackend.indexCacheEligible && sparseBackend.indexCacheEnabled,
|
|
140
|
-
`backend=${sparseBackend.id}; server=${sparseBackend.serverEngine}; eligible=${sparseBackend.indexCacheEligible}; enabled=${sparseBackend.indexCacheEnabled}`
|
|
141
|
-
);
|
|
142
|
-
|
|
143
|
-
const recommendation = recommendInferenceBackend({
|
|
144
|
-
type: 'large-context',
|
|
145
|
-
contextTokens: 240000,
|
|
146
|
-
tags: ['xmemory'],
|
|
147
|
-
}, {
|
|
148
|
-
THUMBGATE_PROVIDER_MODE: 'local',
|
|
149
|
-
THUMBGATE_LOCAL_MODEL_FAMILY: 'glm-4.5',
|
|
150
|
-
THUMBGATE_LOCAL_MODEL_SERVER: 'vllm',
|
|
151
|
-
});
|
|
152
|
-
addResult(
|
|
153
|
-
'IDX-02',
|
|
154
|
-
recommendation.recommendationClass === 'indexcache_eligible',
|
|
155
|
-
`class=${recommendation.recommendationClass}; backend=${recommendation.backend.id}; reason=${recommendation.reason}`
|
|
156
|
-
);
|
|
157
|
-
|
|
158
|
-
const executionPlan = recommendExecutionPlan({
|
|
159
|
-
type: 'code-edit',
|
|
160
|
-
contextTokens: 260000,
|
|
161
|
-
tags: ['retrieval-heavy'],
|
|
162
|
-
}, {
|
|
163
|
-
THUMBGATE_PROVIDER_MODE: 'local',
|
|
164
|
-
THUMBGATE_LOCAL_MODEL_FAMILY: 'deepseek-v3',
|
|
165
|
-
THUMBGATE_LOCAL_MODEL_SERVER: 'sglang',
|
|
166
|
-
THUMBGATE_INDEXCACHE_ENABLED: 'true',
|
|
167
|
-
});
|
|
168
|
-
addResult(
|
|
169
|
-
'IDX-03',
|
|
170
|
-
executionPlan.tier === 'frontier' && executionPlan.recommendationClass === 'indexcache_active',
|
|
171
|
-
`tier=${executionPlan.tier}; backend=${executionPlan.backendId}; class=${executionPlan.recommendationClass}`
|
|
172
|
-
);
|
|
173
|
-
|
|
174
|
-
const routed = routeInference({
|
|
175
|
-
toolName: 'verify_claim',
|
|
176
|
-
toolInput: { claim: 'long-context repo audit' },
|
|
177
|
-
taskType: 'large-context',
|
|
178
|
-
contextTokens: 220000,
|
|
179
|
-
tags: ['xmemory'],
|
|
180
|
-
env: {
|
|
181
|
-
THUMBGATE_PROVIDER_MODE: 'managed',
|
|
182
|
-
},
|
|
183
|
-
});
|
|
184
|
-
addResult(
|
|
185
|
-
'IDX-04',
|
|
186
|
-
routed.route === 'local' && routed.privacy.route === 'local',
|
|
187
|
-
`route=${routed.route}; privacy=${routed.privacy.route}; class=${routed.recommendationClass}`
|
|
188
|
-
);
|
|
189
|
-
|
|
190
|
-
delete require.cache[require.resolve('./feedback-loop')];
|
|
191
|
-
const { captureFeedback, analyzeFeedback } = require('./feedback-loop');
|
|
192
|
-
const { recordConversationEntry } = require('./feedback-history-distiller');
|
|
193
|
-
captureFeedback({
|
|
194
|
-
signal: 'up',
|
|
195
|
-
context: 'ran tests and included logs',
|
|
196
|
-
whatWorked: 'verification complete',
|
|
197
|
-
tags: ['testing', 'verification'],
|
|
198
|
-
});
|
|
199
|
-
captureFeedback({
|
|
200
|
-
signal: 'down',
|
|
201
|
-
context: 'skipped tests and missing logs caused failure',
|
|
202
|
-
whatWentWrong: 'verification skipped',
|
|
203
|
-
whatToChange: 'always run tests',
|
|
204
|
-
tags: ['debugging', 'verification'],
|
|
205
|
-
});
|
|
206
|
-
captureFeedback({
|
|
207
|
-
signal: 'up',
|
|
208
|
-
context: 'proof attached and verification complete',
|
|
209
|
-
whatWorked: 'full evidence',
|
|
210
|
-
tags: ['testing', 'verification'],
|
|
211
|
-
});
|
|
212
|
-
captureFeedback({
|
|
213
|
-
signal: 'down',
|
|
214
|
-
context: 'unsafe path and security risk caused rejection',
|
|
215
|
-
whatWentWrong: 'unsafe path',
|
|
216
|
-
whatToChange: 'validate paths',
|
|
217
|
-
tags: ['security'],
|
|
218
|
-
});
|
|
219
|
-
const clarification = captureFeedback({
|
|
220
|
-
signal: 'up',
|
|
221
|
-
context: 'thumbs up',
|
|
222
|
-
tags: ['verification'],
|
|
223
|
-
});
|
|
224
|
-
addResult(
|
|
225
|
-
'VETO-01',
|
|
226
|
-
clarification.status === 'clarification_required' && clarification.needsClarification === true,
|
|
227
|
-
`vague feedback status=${clarification.status}; prompt=${clarification.prompt || 'n/a'}`
|
|
228
|
-
);
|
|
229
|
-
captureFeedback({
|
|
230
|
-
signal: 'positive',
|
|
231
|
-
context: 'claimed success without logs',
|
|
232
|
-
whatWorked: 'Reviewer approved despite missing logs',
|
|
233
|
-
tags: ['verification'],
|
|
234
|
-
rubricScores: [
|
|
235
|
-
{ criterion: 'verification_evidence', score: 5, judge: 'judge-a' },
|
|
236
|
-
{ criterion: 'verification_evidence', score: 2, judge: 'judge-b', evidence: 'missing logs' },
|
|
237
|
-
],
|
|
238
|
-
guardrails: {
|
|
239
|
-
testsPassed: false,
|
|
240
|
-
pathSafety: true,
|
|
241
|
-
budgetCompliant: true,
|
|
242
|
-
},
|
|
243
|
-
});
|
|
244
|
-
captureFeedback({
|
|
245
|
-
signal: 'down',
|
|
246
|
-
context: 'regression due to skipped verification',
|
|
247
|
-
whatWentWrong: 'regression shipped',
|
|
248
|
-
whatToChange: 'add regression tests',
|
|
249
|
-
tags: ['debugging', 'verification'],
|
|
250
|
-
});
|
|
251
|
-
|
|
252
|
-
const riskModelPath = path.join(tmpFeedbackDir, 'risk-model.json');
|
|
253
|
-
const analysis = analyzeFeedback();
|
|
254
|
-
addResult(
|
|
255
|
-
'RISK-01',
|
|
256
|
-
fs.existsSync(riskModelPath),
|
|
257
|
-
'risk-model artifact written'
|
|
258
|
-
);
|
|
259
|
-
addResult(
|
|
260
|
-
'RISK-02',
|
|
261
|
-
Boolean(analysis.boostedRisk && analysis.boostedRisk.exampleCount >= 6),
|
|
262
|
-
`boostedRisk exampleCount=${analysis.boostedRisk ? analysis.boostedRisk.exampleCount : 0}; mode=${analysis.boostedRisk ? analysis.boostedRisk.mode : 'none'}; topDomain=${analysis.boostedRisk && analysis.boostedRisk.highRiskDomains[0] ? analysis.boostedRisk.highRiskDomains[0].key : 'none'}`
|
|
263
|
-
);
|
|
264
|
-
|
|
265
|
-
const distilled = captureFeedback({
|
|
266
|
-
signal: 'down',
|
|
267
|
-
context: 'thumbs down',
|
|
268
|
-
chatHistory: [
|
|
269
|
-
{ author: 'user', text: 'Do not use Tailwind in this repo.' },
|
|
270
|
-
{ author: 'assistant', text: 'I used Tailwind classes in the hero rewrite.' },
|
|
271
|
-
],
|
|
272
|
-
tags: ['ui'],
|
|
273
|
-
});
|
|
274
|
-
addResult(
|
|
275
|
-
'DISTILL-01',
|
|
276
|
-
distilled.accepted === true && /ignored a prior instruction/i.test(distilled.feedbackEvent.whatWentWrong || ''),
|
|
277
|
-
`accepted=${distilled.accepted}; whatWentWrong=${distilled.feedbackEvent.whatWentWrong || 'n/a'}`
|
|
278
|
-
);
|
|
279
|
-
|
|
280
|
-
recordConversationEntry({
|
|
281
|
-
author: 'assistant',
|
|
282
|
-
text: 'Ran npm test and attached the output before closing the task.',
|
|
283
|
-
source: 'proof',
|
|
284
|
-
}, { feedbackDir: tmpFeedbackDir });
|
|
285
|
-
const fallback = captureFeedback({
|
|
286
|
-
signal: 'up',
|
|
287
|
-
context: 'thumbs up',
|
|
288
|
-
allowLocalConversationFallback: true,
|
|
289
|
-
tags: ['verification'],
|
|
290
|
-
});
|
|
291
|
-
addResult(
|
|
292
|
-
'DISTILL-02',
|
|
293
|
-
fallback.accepted === true && /successful pattern/i.test(fallback.feedbackEvent.whatWorked || ''),
|
|
294
|
-
`accepted=${fallback.accepted}; whatWorked=${fallback.feedbackEvent.whatWorked || 'n/a'}`
|
|
295
|
-
);
|
|
296
|
-
} finally {
|
|
297
|
-
delete process.env.THUMBGATE_FEEDBACK_DIR;
|
|
298
|
-
delete process.env.THUMBGATE_MODEL_FIT_PROFILE;
|
|
299
|
-
delete process.env.THUMBGATE_VECTOR_FORCE_PRIMARY_FAILURE;
|
|
300
|
-
delete process.env.THUMBGATE_VECTOR_STUB_EMBED;
|
|
301
|
-
fs.rmSync(tmpFeedbackDir, { recursive: true, force: true });
|
|
302
|
-
}
|
|
303
|
-
|
|
304
|
-
const passed = report.summary.failed === 0 && report.testResults.failed === 0;
|
|
305
|
-
const jsonPath = path.join(proofDir, 'local-intelligence-report.json');
|
|
306
|
-
const mdPath = path.join(proofDir, 'local-intelligence-report.md');
|
|
307
|
-
|
|
308
|
-
fs.writeFileSync(jsonPath, `${JSON.stringify(report, null, 2)}\n`);
|
|
309
|
-
|
|
310
|
-
const lines = [
|
|
311
|
-
'# Local Intelligence Proof Report',
|
|
312
|
-
'',
|
|
313
|
-
`Status: ${passed ? 'PASSED' : 'FAILED'}`,
|
|
314
|
-
`Generated: ${report.generatedAt}`,
|
|
315
|
-
'',
|
|
316
|
-
'## Test Results',
|
|
317
|
-
'',
|
|
318
|
-
`- Passed: ${report.testResults.passed}`,
|
|
319
|
-
`- Failed: ${report.testResults.failed}`,
|
|
320
|
-
'',
|
|
321
|
-
'## Checks',
|
|
322
|
-
'',
|
|
323
|
-
];
|
|
324
|
-
|
|
325
|
-
report.checks.forEach((check) => {
|
|
326
|
-
lines.push(`- ${check.id}: ${check.passed ? 'PASS' : 'FAIL'} — ${check.evidence}`);
|
|
327
|
-
});
|
|
328
|
-
|
|
329
|
-
fs.writeFileSync(mdPath, `${lines.join('\n')}\n`);
|
|
330
|
-
|
|
331
|
-
process.stdout.write(`Status: ${passed ? 'PASSED' : 'FAILED'}\n`);
|
|
332
|
-
process.stdout.write(`JSON report: ${jsonPath}\n`);
|
|
333
|
-
process.stdout.write(`Markdown report: ${mdPath}\n`);
|
|
334
|
-
process.exit(passed ? 0 : 1);
|
|
335
|
-
}
|
|
336
|
-
|
|
337
|
-
main().catch((err) => {
|
|
338
|
-
console.error(`prove-local-intelligence failed: ${err.message}`);
|
|
339
|
-
process.exit(1);
|
|
340
|
-
});
|
|
@@ -1,263 +0,0 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
/**
|
|
3
|
-
* Phase 8: Loop Closure — Proof Gate
|
|
4
|
-
*
|
|
5
|
-
* Validates all LOOP-01 through LOOP-05 requirements offline.
|
|
6
|
-
* Mirrors the pattern of prove-attribution.js (mkdtempSync + env override + execSync).
|
|
7
|
-
*
|
|
8
|
-
* Usage:
|
|
9
|
-
* node scripts/prove-loop-closure.js
|
|
10
|
-
*
|
|
11
|
-
* Produces:
|
|
12
|
-
* proof/loop-closure-report.json
|
|
13
|
-
* proof/loop-closure-report.md
|
|
14
|
-
*/
|
|
15
|
-
|
|
16
|
-
const { execSync } = require('child_process');
|
|
17
|
-
const fs = require('fs');
|
|
18
|
-
const os = require('os');
|
|
19
|
-
const path = require('path');
|
|
20
|
-
|
|
21
|
-
const ROOT = path.join(__dirname, '..');
|
|
22
|
-
|
|
23
|
-
function resolveProofPaths() {
|
|
24
|
-
const proofDir = process.env.THUMBGATE_PROOF_DIR || path.join(ROOT, 'proof');
|
|
25
|
-
return {
|
|
26
|
-
proofDir,
|
|
27
|
-
reportJson: path.join(proofDir, 'loop-closure-report.json'),
|
|
28
|
-
reportMd: path.join(proofDir, 'loop-closure-report.md'),
|
|
29
|
-
};
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
function run() {
|
|
33
|
-
const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'thumbgate-loop-proof-'));
|
|
34
|
-
const results = { passed: 0, failed: 0, requirements: {} };
|
|
35
|
-
const { proofDir, reportJson, reportMd } = resolveProofPaths();
|
|
36
|
-
|
|
37
|
-
const checks = [
|
|
38
|
-
{
|
|
39
|
-
id: 'LOOP-01',
|
|
40
|
-
desc: 'feedback-to-rules.js: analyze() produces recurringIssues + toRules() emits NEVER bullets',
|
|
41
|
-
fn: () => {
|
|
42
|
-
delete require.cache[require.resolve('./feedback-to-rules')];
|
|
43
|
-
const m = require('./feedback-to-rules');
|
|
44
|
-
if (typeof m.parseFeedbackFile !== 'function') throw new Error('parseFeedbackFile not exported');
|
|
45
|
-
if (typeof m.classifySignal !== 'function') throw new Error('classifySignal not exported');
|
|
46
|
-
if (typeof m.analyze !== 'function') throw new Error('analyze not exported');
|
|
47
|
-
if (typeof m.toRules !== 'function') throw new Error('toRules not exported');
|
|
48
|
-
|
|
49
|
-
const ctx = 'Agent claimed done without running tests first';
|
|
50
|
-
const entries = [
|
|
51
|
-
{ signal: 'negative', context: ctx },
|
|
52
|
-
{ signal: 'negative', context: ctx },
|
|
53
|
-
];
|
|
54
|
-
const report = m.analyze(entries);
|
|
55
|
-
if (report.recurringIssues.length < 1) throw new Error('Expected at least 1 recurring issue');
|
|
56
|
-
const rules = m.toRules(report);
|
|
57
|
-
if (!rules.includes('NEVER')) throw new Error('toRules must emit NEVER bullets');
|
|
58
|
-
if (!rules.startsWith('# Suggested Rules from Feedback Analysis')) {
|
|
59
|
-
throw new Error('toRules must start with header');
|
|
60
|
-
}
|
|
61
|
-
},
|
|
62
|
-
},
|
|
63
|
-
{
|
|
64
|
-
id: 'LOOP-02',
|
|
65
|
-
desc: 'plan-gate.js: validatePlan() rejects structurally invalid PRD, passes valid one',
|
|
66
|
-
fn: () => {
|
|
67
|
-
delete require.cache[require.resolve('./plan-gate')];
|
|
68
|
-
const m = require('./plan-gate');
|
|
69
|
-
if (typeof m.validatePlan !== 'function') throw new Error('validatePlan not exported');
|
|
70
|
-
if (typeof m.formatReport !== 'function') throw new Error('formatReport not exported');
|
|
71
|
-
|
|
72
|
-
// Invalid: missing required sections
|
|
73
|
-
const invalid = m.validatePlan('# Minimal plan\nNo sections here');
|
|
74
|
-
if (invalid.allPass) throw new Error('Expected allPass=false for structurally invalid PRD');
|
|
75
|
-
|
|
76
|
-
// Valid: all gates satisfied
|
|
77
|
-
const valid = m.validatePlan([
|
|
78
|
-
'# My Plan',
|
|
79
|
-
'',
|
|
80
|
-
'## Status',
|
|
81
|
-
'DRAFT',
|
|
82
|
-
'',
|
|
83
|
-
'## Clarifying Questions Resolved',
|
|
84
|
-
'| Q | A |',
|
|
85
|
-
'|---|---|',
|
|
86
|
-
'| q1 | a1 |',
|
|
87
|
-
'| q2 | a2 |',
|
|
88
|
-
'| q3 | a3 |',
|
|
89
|
-
'',
|
|
90
|
-
'## Contracts',
|
|
91
|
-
'```',
|
|
92
|
-
'interface Foo { bar: string }',
|
|
93
|
-
'```',
|
|
94
|
-
'',
|
|
95
|
-
'## Validation Checklist',
|
|
96
|
-
'- [ ] scenario 1',
|
|
97
|
-
'- [ ] scenario 2',
|
|
98
|
-
].join('\n'));
|
|
99
|
-
if (!valid.allPass) throw new Error('Expected allPass=true for valid PRD');
|
|
100
|
-
|
|
101
|
-
const report = m.formatReport(valid);
|
|
102
|
-
if (!report.includes('RESULT: PASS')) throw new Error('formatReport must include RESULT: PASS');
|
|
103
|
-
},
|
|
104
|
-
},
|
|
105
|
-
{
|
|
106
|
-
id: 'LOOP-03',
|
|
107
|
-
desc: 'feedback-inbox-read.js: getNewEntries reads in cursor order, no re-reads on next call',
|
|
108
|
-
fn: () => {
|
|
109
|
-
delete require.cache[require.resolve('./feedback-inbox-read')];
|
|
110
|
-
const m = require('./feedback-inbox-read');
|
|
111
|
-
if (typeof m.getNewEntries !== 'function') throw new Error('getNewEntries not exported');
|
|
112
|
-
if (typeof m.readInbox !== 'function') throw new Error('readInbox not exported');
|
|
113
|
-
if (typeof m.loadCursor !== 'function') throw new Error('loadCursor not exported');
|
|
114
|
-
if (typeof m.saveCursor !== 'function') throw new Error('saveCursor not exported');
|
|
115
|
-
|
|
116
|
-
// Verify cursor filtering logic
|
|
117
|
-
const allEntries = [
|
|
118
|
-
{ _lineIndex: 0, signal: 'negative' },
|
|
119
|
-
{ _lineIndex: 1, signal: 'positive' },
|
|
120
|
-
{ _lineIndex: 2, signal: 'negative' },
|
|
121
|
-
];
|
|
122
|
-
const cursor = { lastLineIndex: 0 };
|
|
123
|
-
const afterFirst = allEntries.filter((e) => e._lineIndex > cursor.lastLineIndex);
|
|
124
|
-
if (afterFirst.length !== 2) throw new Error('Expected 2 entries after cursor=0');
|
|
125
|
-
|
|
126
|
-
const cursor2 = { lastLineIndex: 2 };
|
|
127
|
-
const afterAll = allEntries.filter((e) => e._lineIndex > cursor2.lastLineIndex);
|
|
128
|
-
if (afterAll.length !== 0) throw new Error('Expected 0 entries after cursor=2 (no re-reads)');
|
|
129
|
-
|
|
130
|
-
// Verify paths are exported
|
|
131
|
-
if (typeof m.INBOX_PATH !== 'string') throw new Error('INBOX_PATH must be exported string');
|
|
132
|
-
if (typeof m.CURSOR_PATH !== 'string') throw new Error('CURSOR_PATH must be exported string');
|
|
133
|
-
},
|
|
134
|
-
},
|
|
135
|
-
{
|
|
136
|
-
id: 'LOOP-04',
|
|
137
|
-
desc: 'feedback-to-memory.js: convertFeedbackToMemory() emits valid MCP memory format on round-trip',
|
|
138
|
-
fn: () => {
|
|
139
|
-
delete require.cache[require.resolve('./feedback-to-memory')];
|
|
140
|
-
const m = require('./feedback-to-memory');
|
|
141
|
-
if (typeof m.convertFeedbackToMemory !== 'function') {
|
|
142
|
-
throw new Error('convertFeedbackToMemory not exported');
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
// Valid negative → memory
|
|
146
|
-
const neg = m.convertFeedbackToMemory({
|
|
147
|
-
signal: 'negative',
|
|
148
|
-
context: 'Agent claimed fix without test evidence',
|
|
149
|
-
whatWentWrong: 'No tests were run before claiming done',
|
|
150
|
-
whatToChange: 'Always run tests before claiming done',
|
|
151
|
-
tags: ['verification', 'testing'],
|
|
152
|
-
});
|
|
153
|
-
if (!neg.ok) throw new Error(`Valid negative should return ok=true: ${neg.reason}`);
|
|
154
|
-
if (neg.actionType !== 'store-mistake') throw new Error('Expected actionType=store-mistake');
|
|
155
|
-
if (!neg.memory.title.startsWith('MISTAKE:')) throw new Error('Expected MISTAKE: prefix');
|
|
156
|
-
if (neg.memory.category !== 'error') throw new Error('Expected category=error');
|
|
157
|
-
if (!Array.isArray(neg.memory.tags)) throw new Error('Expected tags array');
|
|
158
|
-
|
|
159
|
-
// Valid positive → memory
|
|
160
|
-
const pos = m.convertFeedbackToMemory({
|
|
161
|
-
signal: 'positive',
|
|
162
|
-
whatWorked: 'Ran full test suite before claiming done',
|
|
163
|
-
tags: ['verification'],
|
|
164
|
-
});
|
|
165
|
-
if (!pos.ok) throw new Error(`Valid positive should return ok=true: ${pos.reason}`);
|
|
166
|
-
if (pos.actionType !== 'store-learning') throw new Error('Expected actionType=store-learning');
|
|
167
|
-
if (!pos.memory.title.startsWith('SUCCESS:')) throw new Error('Expected SUCCESS: prefix');
|
|
168
|
-
|
|
169
|
-
// Bare negative → rejected (no context)
|
|
170
|
-
const bare = m.convertFeedbackToMemory({ signal: 'negative' });
|
|
171
|
-
if (bare.ok) throw new Error('Bare negative without context should be rejected');
|
|
172
|
-
},
|
|
173
|
-
},
|
|
174
|
-
{
|
|
175
|
-
id: 'LOOP-05',
|
|
176
|
-
desc: 'test:loop-closure (node --test tests/loop-closure.test.js) passes with 0 failures',
|
|
177
|
-
fn: () => {
|
|
178
|
-
const out = execSync('node --test tests/loop-closure.test.js', {
|
|
179
|
-
cwd: ROOT,
|
|
180
|
-
env: { ...process.env, THUMBGATE_FEEDBACK_DIR: tmpDir },
|
|
181
|
-
encoding: 'utf8',
|
|
182
|
-
stdio: 'pipe',
|
|
183
|
-
});
|
|
184
|
-
const failMatch = out.match(/ℹ fail (\d+)/);
|
|
185
|
-
if (failMatch && parseInt(failMatch[1], 10) > 0) {
|
|
186
|
-
throw new Error(`Tests failed: ${failMatch[1]} failure(s)\n${out.slice(-500)}`);
|
|
187
|
-
}
|
|
188
|
-
},
|
|
189
|
-
},
|
|
190
|
-
];
|
|
191
|
-
|
|
192
|
-
console.log('Phase 8: Loop Closure — Proof Gate\n');
|
|
193
|
-
console.log('Checking requirements:\n');
|
|
194
|
-
|
|
195
|
-
for (const check of checks) {
|
|
196
|
-
try {
|
|
197
|
-
check.fn();
|
|
198
|
-
results.passed++;
|
|
199
|
-
results.requirements[check.id] = { status: 'pass', desc: check.desc };
|
|
200
|
-
console.log(` PASS ${check.id}: ${check.desc}`);
|
|
201
|
-
} catch (err) {
|
|
202
|
-
results.failed++;
|
|
203
|
-
results.requirements[check.id] = {
|
|
204
|
-
status: 'fail',
|
|
205
|
-
desc: check.desc,
|
|
206
|
-
error: err.message,
|
|
207
|
-
};
|
|
208
|
-
console.error(` FAIL ${check.id}: ${err.message}`);
|
|
209
|
-
}
|
|
210
|
-
}
|
|
211
|
-
|
|
212
|
-
// Cleanup tmp dir
|
|
213
|
-
try {
|
|
214
|
-
fs.rmSync(tmpDir, { recursive: true, force: true });
|
|
215
|
-
} catch {}
|
|
216
|
-
|
|
217
|
-
// Write proof artifacts
|
|
218
|
-
fs.mkdirSync(proofDir, { recursive: true });
|
|
219
|
-
|
|
220
|
-
const report = {
|
|
221
|
-
phase: '08-loop-closure',
|
|
222
|
-
generatedAt: new Date().toISOString(),
|
|
223
|
-
passed: results.passed,
|
|
224
|
-
failed: results.failed,
|
|
225
|
-
total: checks.length,
|
|
226
|
-
requirements: results.requirements,
|
|
227
|
-
};
|
|
228
|
-
|
|
229
|
-
fs.writeFileSync(reportJson, JSON.stringify(report, null, 2) + '\n');
|
|
230
|
-
|
|
231
|
-
const md = [
|
|
232
|
-
'# Phase 8: Loop Closure — Proof Report',
|
|
233
|
-
'',
|
|
234
|
-
`Generated: ${report.generatedAt}`,
|
|
235
|
-
`Result: ${results.passed}/${checks.length} passed`,
|
|
236
|
-
'',
|
|
237
|
-
'## Requirements',
|
|
238
|
-
'',
|
|
239
|
-
...Object.entries(results.requirements).map(([id, r]) => {
|
|
240
|
-
const checkbox = r.status === 'pass' ? '[x]' : '[ ]';
|
|
241
|
-
const errLine = r.error ? `\n - Error: \`${r.error}\`` : '';
|
|
242
|
-
return `- ${checkbox} **${id}**: ${r.desc}${errLine}`;
|
|
243
|
-
}),
|
|
244
|
-
'',
|
|
245
|
-
'## Evidence',
|
|
246
|
-
'',
|
|
247
|
-
'- `scripts/feedback-to-rules.js` — Feedback pattern analysis + CLAUDE.md-compatible rule generation',
|
|
248
|
-
'- `scripts/plan-gate.js` — PRD structural validation gate (questions, contracts, checklist, status)',
|
|
249
|
-
'- `scripts/feedback-inbox-read.js` — Cursor-based inbox reader with no re-read guarantee',
|
|
250
|
-
'- `scripts/feedback-to-memory.js` — Stdin JSON → MCP memory format bridge with schema validation',
|
|
251
|
-
'- `tests/loop-closure.test.js` — 44 node:test cases covering all LOOP requirements',
|
|
252
|
-
'',
|
|
253
|
-
].join('\n');
|
|
254
|
-
|
|
255
|
-
fs.writeFileSync(reportMd, md);
|
|
256
|
-
|
|
257
|
-
console.log(`\nPhase 8 proof: ${results.passed} passed, ${results.failed} failed`);
|
|
258
|
-
console.log(`Report: ${reportJson}`);
|
|
259
|
-
|
|
260
|
-
if (results.failed > 0) process.exit(1);
|
|
261
|
-
}
|
|
262
|
-
|
|
263
|
-
run();
|