thumbgate 0.9.9
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/README.md +134 -0
- package/.claude-plugin/bundle/icon.png +0 -0
- package/.claude-plugin/bundle/icon.svg +18 -0
- package/.claude-plugin/bundle/server/index.js +24 -0
- package/.claude-plugin/marketplace.json +36 -0
- package/.claude-plugin/plugin.json +21 -0
- package/.well-known/mcp/server-card.json +231 -0
- package/LICENSE +21 -0
- package/README.md +375 -0
- package/adapters/README.md +9 -0
- package/adapters/amp/skills/rlhf-feedback/SKILL.md +22 -0
- package/adapters/chatgpt/INSTALL.md +83 -0
- package/adapters/chatgpt/openapi.yaml +1281 -0
- package/adapters/claude/.mcp.json +14 -0
- package/adapters/codex/config.toml +9 -0
- package/adapters/gemini/function-declarations.json +224 -0
- package/adapters/mcp/server-stdio.js +788 -0
- package/adapters/opencode/opencode.json +15 -0
- package/bin/cli.js +1483 -0
- package/bin/memory.sh +64 -0
- package/bin/obsidian-sync.sh +20 -0
- package/bin/postinstall.js +37 -0
- package/config/build-metadata.json +4 -0
- package/config/e2e-critical-flows.json +45 -0
- package/config/gate-templates.json +77 -0
- package/config/gates/claim-verification.json +29 -0
- package/config/gates/computer-use.json +39 -0
- package/config/gates/default.json +117 -0
- package/config/github-about.json +25 -0
- package/config/mcp-allowlists.json +135 -0
- package/config/model-tiers.json +33 -0
- package/config/partner-routing.json +132 -0
- package/config/policy-bundles/constrained-v1.json +64 -0
- package/config/policy-bundles/default-v1.json +91 -0
- package/config/rubrics/default-v1.json +52 -0
- package/config/skill-packs/react-testing.json +23 -0
- package/config/skill-packs/stripe-integration/references/api-spec.json +1 -0
- package/config/skill-packs/stripe-integration/references/webhook-guide.md +3 -0
- package/config/skill-specs/pr-reviewer.json +9 -0
- package/config/skill-specs/release-status.json +9 -0
- package/config/skill-specs/ticket-triage.json +9 -0
- package/config/subagent-profiles.json +32 -0
- package/config/tessl-tiles.json +29 -0
- package/config/thumbgate-settings.managed.json +12 -0
- package/openapi/openapi.yaml +1281 -0
- package/package.json +286 -0
- package/plugins/amp-skill/INSTALL.md +52 -0
- package/plugins/amp-skill/SKILL.md +64 -0
- package/plugins/claude-codex-bridge/.claude-plugin/plugin.json +22 -0
- package/plugins/claude-codex-bridge/.mcp.json +12 -0
- package/plugins/claude-codex-bridge/INSTALL.md +43 -0
- package/plugins/claude-codex-bridge/README.md +46 -0
- package/plugins/claude-codex-bridge/scripts/codex-bridge.js +288 -0
- package/plugins/claude-codex-bridge/skills/adversarial-review/SKILL.md +24 -0
- package/plugins/claude-codex-bridge/skills/result/SKILL.md +22 -0
- package/plugins/claude-codex-bridge/skills/review/SKILL.md +28 -0
- package/plugins/claude-codex-bridge/skills/second-pass/SKILL.md +27 -0
- package/plugins/claude-codex-bridge/skills/setup/SKILL.md +21 -0
- package/plugins/claude-codex-bridge/skills/status/SKILL.md +19 -0
- package/plugins/claude-skill/INSTALL.md +55 -0
- package/plugins/claude-skill/SKILL.md +46 -0
- package/plugins/codex-profile/.codex-plugin/plugin.json +43 -0
- package/plugins/codex-profile/.mcp.json +12 -0
- package/plugins/codex-profile/AGENTS.md +20 -0
- package/plugins/codex-profile/INSTALL.md +66 -0
- package/plugins/codex-profile/README.md +37 -0
- package/plugins/cursor-marketplace/.cursor-plugin/plugin.json +23 -0
- package/plugins/cursor-marketplace/CHANGELOG.md +30 -0
- package/plugins/cursor-marketplace/LICENSE +21 -0
- package/plugins/cursor-marketplace/README.md +124 -0
- package/plugins/cursor-marketplace/agents/reliability-reviewer.md +31 -0
- package/plugins/cursor-marketplace/assets/logo-400x400.png +0 -0
- package/plugins/cursor-marketplace/commands/capture-feedback.md +33 -0
- package/plugins/cursor-marketplace/commands/check-gates.md +25 -0
- package/plugins/cursor-marketplace/commands/show-lessons.md +27 -0
- package/plugins/cursor-marketplace/hooks/hooks.json +10 -0
- package/plugins/cursor-marketplace/mcp.json +12 -0
- package/plugins/cursor-marketplace/rules/feedback-capture.mdc +34 -0
- package/plugins/cursor-marketplace/rules/pre-action-gates.mdc +30 -0
- package/plugins/cursor-marketplace/rules/session-continuity.mdc +28 -0
- package/plugins/cursor-marketplace/scripts/gate-check.sh +11 -0
- package/plugins/cursor-marketplace/skills/capture-feedback/SKILL.md +47 -0
- package/plugins/cursor-marketplace/skills/prevention-rules/SKILL.md +31 -0
- package/plugins/cursor-marketplace/skills/recall-context/SKILL.md +30 -0
- package/plugins/cursor-marketplace/skills/search-lessons/SKILL.md +33 -0
- package/plugins/gemini-extension/INSTALL.md +92 -0
- package/plugins/gemini-extension/gemini_prompt.txt +14 -0
- package/plugins/gemini-extension/tool_contract.json +45 -0
- package/plugins/opencode-profile/INSTALL.md +57 -0
- package/public/assets/instagram-card.png +0 -0
- package/public/assets/tiktok-agent-memory.mp4 +0 -0
- package/public/blog.html +400 -0
- package/public/dashboard.html +1093 -0
- package/public/guide.html +317 -0
- package/public/index.html +1195 -0
- package/public/learn/agent-harness-pattern.html +180 -0
- package/public/learn/ai-agent-persistent-memory.html +202 -0
- package/public/learn/learn.css +45 -0
- package/public/learn/mcp-pre-action-gates-explained.html +172 -0
- package/public/learn/stop-ai-agent-force-push.html +134 -0
- package/public/learn/vibe-coding-safety-net.html +142 -0
- package/public/learn.html +213 -0
- package/public/lessons.html +650 -0
- package/public/vercel.json +8 -0
- package/scripts/__pycache__/train_from_feedback.cpython-314.pyc +0 -0
- package/scripts/a2ui-engine.js +73 -0
- package/scripts/access-anomaly-detector.js +12 -0
- package/scripts/adk-consolidator.js +266 -0
- package/scripts/agent-readiness.js +220 -0
- package/scripts/agent-security-hardening.js +227 -0
- package/scripts/agentic-data-pipeline.js +847 -0
- package/scripts/analytics-report.js +328 -0
- package/scripts/analytics-window.js +158 -0
- package/scripts/async-job-runner.js +1001 -0
- package/scripts/audit-trail.js +398 -0
- package/scripts/auto-promote-gates.js +293 -0
- package/scripts/auto-wire-hooks.js +316 -0
- package/scripts/autonomous-sales-agent.js +39 -0
- package/scripts/autoresearch-runner.js +216 -0
- package/scripts/background-agent-governance.js +237 -0
- package/scripts/behavioral-extraction.js +93 -0
- package/scripts/belief-update.js +84 -0
- package/scripts/billing.js +2438 -0
- package/scripts/bot-detector.js +50 -0
- package/scripts/budget-guard.js +173 -0
- package/scripts/build-claude-mcpb.js +189 -0
- package/scripts/build-metadata.js +97 -0
- package/scripts/check-congruence.js +322 -0
- package/scripts/cli-feedback.js +135 -0
- package/scripts/cli-telemetry.js +87 -0
- package/scripts/cloudflare-dynamic-sandbox.js +315 -0
- package/scripts/code-reasoning.js +350 -0
- package/scripts/codegraph-context.js +466 -0
- package/scripts/commercial-offer.js +56 -0
- package/scripts/computer-use-firewall.js +250 -0
- package/scripts/context-engine.js +694 -0
- package/scripts/contextfs.js +1287 -0
- package/scripts/conversation-context.js +119 -0
- package/scripts/creator-campaigns.js +239 -0
- package/scripts/daemon-manager.js +108 -0
- package/scripts/daily-digest.js +11 -0
- package/scripts/dashboard-render-spec.js +395 -0
- package/scripts/dashboard.js +1058 -0
- package/scripts/data-governance.js +173 -0
- package/scripts/delegation-runtime.js +900 -0
- package/scripts/deploy-gcp.sh +44 -0
- package/scripts/deploy-policy.js +231 -0
- package/scripts/disagreement-mining.js +315 -0
- package/scripts/dispatch-brief.js +159 -0
- package/scripts/distribution-surfaces.js +44 -0
- package/scripts/dpo-optimizer.js +206 -0
- package/scripts/ensure-repo-bootstrap.js +129 -0
- package/scripts/ephemeral-agent-store.js +219 -0
- package/scripts/eval-harness.js +56 -0
- package/scripts/evolution-state.js +241 -0
- package/scripts/experiment-tracker.js +267 -0
- package/scripts/export-databricks-bundle.js +242 -0
- package/scripts/export-dpo-pairs.js +344 -0
- package/scripts/export-kto-pairs.js +309 -0
- package/scripts/export-training.js +450 -0
- package/scripts/failure-diagnostics.js +558 -0
- package/scripts/feedback-attribution.js +313 -0
- package/scripts/feedback-fallback.js +110 -0
- package/scripts/feedback-history-distiller.js +391 -0
- package/scripts/feedback-inbox-read.js +162 -0
- package/scripts/feedback-loop.js +1887 -0
- package/scripts/feedback-paths.js +145 -0
- package/scripts/feedback-quality.js +139 -0
- package/scripts/feedback-root-consolidator.js +238 -0
- package/scripts/feedback-schema.js +426 -0
- package/scripts/feedback-session.js +286 -0
- package/scripts/feedback-to-memory.js +185 -0
- package/scripts/feedback-to-rules.js +164 -0
- package/scripts/filesystem-search.js +405 -0
- package/scripts/funnel-analytics.js +35 -0
- package/scripts/gate-satisfy.js +42 -0
- package/scripts/gate-stats.js +116 -0
- package/scripts/gate-templates.js +70 -0
- package/scripts/gates-engine.js +816 -0
- package/scripts/generate-paperbanana-diagrams.sh +99 -0
- package/scripts/generate-pretool-hook.sh +40 -0
- package/scripts/github-about.js +350 -0
- package/scripts/github-outreach.js +65 -0
- package/scripts/gtm-revenue-loop.js +520 -0
- package/scripts/hallucination-detector.js +226 -0
- package/scripts/hf-papers.js +317 -0
- package/scripts/history-distiller.js +200 -0
- package/scripts/hook-auto-capture.sh +100 -0
- package/scripts/hook-stop-pr-thread-check.sh +68 -0
- package/scripts/hook-stop-self-score.sh +51 -0
- package/scripts/hook-stop-verify-deploy.sh +31 -0
- package/scripts/hook-thumbgate-cache-updater.js +48 -0
- package/scripts/hook-verify-before-done.sh +20 -0
- package/scripts/hosted-config.js +156 -0
- package/scripts/hybrid-feedback-context.js +675 -0
- package/scripts/install-mcp.js +159 -0
- package/scripts/intent-router.js +392 -0
- package/scripts/internal-agent-bootstrap.js +490 -0
- package/scripts/jsonl-watcher.js +155 -0
- package/scripts/lesson-db.js +613 -0
- package/scripts/lesson-inference.js +310 -0
- package/scripts/lesson-retrieval.js +95 -0
- package/scripts/lesson-rotation.js +137 -0
- package/scripts/lesson-search.js +644 -0
- package/scripts/lesson-synthesis.js +196 -0
- package/scripts/license.js +50 -0
- package/scripts/local-model-profile.js +384 -0
- package/scripts/markdown-escape.js +12 -0
- package/scripts/marketing-experiment.js +671 -0
- package/scripts/mcp-config.js +149 -0
- package/scripts/mcp-policy.js +99 -0
- package/scripts/memalign-recall.js +111 -0
- package/scripts/memory-firewall.js +222 -0
- package/scripts/memory-migration.js +296 -0
- package/scripts/meta-policy.js +190 -0
- package/scripts/metered-billing.js +16 -0
- package/scripts/model-tier-router.js +301 -0
- package/scripts/money-watcher.js +71 -0
- package/scripts/multi-hop-recall.js +240 -0
- package/scripts/natural-language-harness.js +330 -0
- package/scripts/obsidian-export.js +713 -0
- package/scripts/operational-dashboard.js +103 -0
- package/scripts/operational-summary.js +93 -0
- package/scripts/optimize-context.js +17 -0
- package/scripts/org-dashboard.js +201 -0
- package/scripts/partner-orchestration.js +146 -0
- package/scripts/per-step-scoring.js +165 -0
- package/scripts/perplexity-marketing.js +466 -0
- package/scripts/pii-scanner.js +153 -0
- package/scripts/plan-gate.js +154 -0
- package/scripts/post-everywhere.js +308 -0
- package/scripts/post-to-x-retry.sh +22 -0
- package/scripts/post-to-x.js +369 -0
- package/scripts/pr-manager.js +236 -0
- package/scripts/predictive-insights.js +356 -0
- package/scripts/principle-extractor.js +162 -0
- package/scripts/pro-features.js +40 -0
- package/scripts/pro-local-dashboard.js +174 -0
- package/scripts/problem-detail.js +53 -0
- package/scripts/product-feedback.js +134 -0
- package/scripts/profile-router.js +245 -0
- package/scripts/prompt-dlp.js +221 -0
- package/scripts/prompt-guard.js +83 -0
- package/scripts/prove-adapters.js +863 -0
- package/scripts/prove-attribution.js +365 -0
- package/scripts/prove-automation.js +653 -0
- package/scripts/prove-autoresearch.js +304 -0
- package/scripts/prove-claim-verification.js +277 -0
- package/scripts/prove-cloudflare-sandbox.js +163 -0
- package/scripts/prove-data-pipeline.js +410 -0
- package/scripts/prove-data-quality.js +227 -0
- package/scripts/prove-evolution.js +352 -0
- package/scripts/prove-harnesses.js +287 -0
- package/scripts/prove-intelligence.js +259 -0
- package/scripts/prove-lancedb.js +371 -0
- package/scripts/prove-local-intelligence.js +342 -0
- package/scripts/prove-loop-closure.js +263 -0
- package/scripts/prove-predictive-insights.js +357 -0
- package/scripts/prove-runtime.js +350 -0
- package/scripts/prove-seo-gsd.js +234 -0
- package/scripts/prove-settings.js +279 -0
- package/scripts/prove-subway-upgrades.js +277 -0
- package/scripts/prove-tessl.js +229 -0
- package/scripts/prove-training-export.js +327 -0
- package/scripts/prove-workflow-contract.js +116 -0
- package/scripts/prove-xmemory.js +332 -0
- package/scripts/publish-decision.js +133 -0
- package/scripts/pulse.js +80 -0
- package/scripts/rate-limiter.js +125 -0
- package/scripts/reddit-dm-outreach.js +182 -0
- package/scripts/reddit-monitor-cron.sh +26 -0
- package/scripts/reflector-agent.js +221 -0
- package/scripts/reminder-engine.js +132 -0
- package/scripts/revenue-status.js +472 -0
- package/scripts/risk-scorer.js +459 -0
- package/scripts/rlaif-self-audit.js +129 -0
- package/scripts/rlhf_session_start.sh +32 -0
- package/scripts/rubric-engine.js +230 -0
- package/scripts/schedule-manager.js +251 -0
- package/scripts/secret-scanner.js +414 -0
- package/scripts/self-heal.js +147 -0
- package/scripts/self-healing-check.js +188 -0
- package/scripts/semantic-layer.js +98 -0
- package/scripts/seo-gsd.js +1153 -0
- package/scripts/settings-hierarchy.js +214 -0
- package/scripts/shieldcortex-memory-firewall-runner.mjs +53 -0
- package/scripts/skill-exporter.js +262 -0
- package/scripts/skill-generator.js +446 -0
- package/scripts/skill-materializer.js +134 -0
- package/scripts/skill-packs.js +136 -0
- package/scripts/skill-proposer.js +99 -0
- package/scripts/skill-quality-tracker.js +282 -0
- package/scripts/slo-alert-engine.js +14 -0
- package/scripts/slow-loop.js +72 -0
- package/scripts/social-analytics/db/schema.sql +32 -0
- package/scripts/social-analytics/db/social-analytics.db +0 -0
- package/scripts/social-analytics/digest.js +256 -0
- package/scripts/social-analytics/generate-instagram-card.js +97 -0
- package/scripts/social-analytics/instagram-thumbgate-post.js +107 -0
- package/scripts/social-analytics/load-env.js +46 -0
- package/scripts/social-analytics/mcp-server.js +289 -0
- package/scripts/social-analytics/normalizer.js +580 -0
- package/scripts/social-analytics/notify.js +162 -0
- package/scripts/social-analytics/poll-all.js +92 -0
- package/scripts/social-analytics/pollers/github.js +195 -0
- package/scripts/social-analytics/pollers/instagram.js +253 -0
- package/scripts/social-analytics/pollers/linkedin.js +330 -0
- package/scripts/social-analytics/pollers/plausible.js +247 -0
- package/scripts/social-analytics/pollers/reddit.js +306 -0
- package/scripts/social-analytics/pollers/threads.js +233 -0
- package/scripts/social-analytics/pollers/tiktok.js +203 -0
- package/scripts/social-analytics/pollers/x.js +227 -0
- package/scripts/social-analytics/pollers/youtube.js +304 -0
- package/scripts/social-analytics/pollers/zernio.js +183 -0
- package/scripts/social-analytics/publish-instagram-thumbgate.js +98 -0
- package/scripts/social-analytics/publish-thumbgate-launch.js +316 -0
- package/scripts/social-analytics/publishers/devto.js +122 -0
- package/scripts/social-analytics/publishers/instagram.js +317 -0
- package/scripts/social-analytics/publishers/linkedin.js +294 -0
- package/scripts/social-analytics/publishers/reddit.js +390 -0
- package/scripts/social-analytics/publishers/threads.js +275 -0
- package/scripts/social-analytics/publishers/tiktok.js +217 -0
- package/scripts/social-analytics/publishers/x.js +259 -0
- package/scripts/social-analytics/publishers/youtube.js +223 -0
- package/scripts/social-analytics/publishers/zernio.js +378 -0
- package/scripts/social-analytics/run-digest.js +34 -0
- package/scripts/social-analytics/store.js +257 -0
- package/scripts/social-analytics/utm.js +143 -0
- package/scripts/social-pipeline.js +2628 -0
- package/scripts/social-quality-gate.js +18 -0
- package/scripts/social-reply-monitor.js +445 -0
- package/scripts/status-dashboard.js +155 -0
- package/scripts/statusline-lesson.js +16 -0
- package/scripts/statusline-tower.js +8 -0
- package/scripts/statusline.sh +116 -0
- package/scripts/stripe-live-status.js +115 -0
- package/scripts/subagent-profiles.js +79 -0
- package/scripts/sync-gh-secrets-from-env.sh +70 -0
- package/scripts/sync-github-about.js +52 -0
- package/scripts/sync-version.js +447 -0
- package/scripts/synthetic-dpo.js +234 -0
- package/scripts/telemetry-analytics.js +821 -0
- package/scripts/tessl-export.js +371 -0
- package/scripts/test-coverage.js +120 -0
- package/scripts/thompson-sampling.js +417 -0
- package/scripts/thumbgate-search.js +189 -0
- package/scripts/tool-kpi-tracker.js +12 -0
- package/scripts/tool-registry.js +811 -0
- package/scripts/train_from_feedback.py +933 -0
- package/scripts/user-profile.js +78 -0
- package/scripts/validate-feedback.js +581 -0
- package/scripts/validate-workflow-contract.js +287 -0
- package/scripts/vector-store.js +197 -0
- package/scripts/verification-loop.js +291 -0
- package/scripts/verify-obsidian-setup.sh +269 -0
- package/scripts/verify-run.js +269 -0
- package/scripts/webhook-delivery.js +62 -0
- package/scripts/weekly-auto-post.js +124 -0
- package/scripts/workflow-runs.js +154 -0
- package/scripts/workflow-sprint-intake.js +475 -0
- package/scripts/workspace-evolver.js +374 -0
- package/scripts/x-autonomous-marketing.js +139 -0
- package/scripts/xmemory-lite.js +405 -0
- package/skills/agent-memory/SKILL.md +97 -0
- package/skills/rlhf-feedback/SKILL.md +49 -0
- package/skills/solve-architecture-autonomy/SKILL.md +17 -0
- package/skills/solve-architecture-autonomy/tool.js +33 -0
- package/skills/thumbgate/SKILL.md +114 -0
- package/src/api/server.js +4206 -0
|
@@ -0,0 +1,291 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const path = require('path');
|
|
4
|
+
const {
|
|
5
|
+
readJSONL,
|
|
6
|
+
getFeedbackPaths,
|
|
7
|
+
appendDiagnosticRecord,
|
|
8
|
+
} = require('./feedback-loop');
|
|
9
|
+
const {
|
|
10
|
+
buildPartnerStrategy,
|
|
11
|
+
computePartnerReward,
|
|
12
|
+
resolveVerificationRetries,
|
|
13
|
+
} = require('./partner-orchestration');
|
|
14
|
+
const {
|
|
15
|
+
diagnoseFailure,
|
|
16
|
+
} = require('./failure-diagnostics');
|
|
17
|
+
const { getEffectiveSetting } = require('./evolution-state');
|
|
18
|
+
|
|
19
|
+
const MAX_RETRIES = 3;
|
|
20
|
+
const DEFAULT_MODEL_PATH = path.join(__dirname, '..', '.rlhf', 'verification-model.json');
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Run a single verification step against prevention rules.
|
|
24
|
+
* Returns { passed: boolean, violations: string[], score: number }
|
|
25
|
+
*
|
|
26
|
+
* @param {object} params
|
|
27
|
+
* @param {string} params.context - The output/action to verify
|
|
28
|
+
* @param {string[]} params.tags - Domain tags
|
|
29
|
+
* @param {string} [params.skill] - Skill that produced the output
|
|
30
|
+
* @returns {object} verification result
|
|
31
|
+
*/
|
|
32
|
+
function verifyAgainstRules(params) {
|
|
33
|
+
const { MEMORY_LOG_PATH } = getFeedbackPaths();
|
|
34
|
+
const memories = readJSONL(MEMORY_LOG_PATH).filter(m => m.category === 'error');
|
|
35
|
+
|
|
36
|
+
const violations = [];
|
|
37
|
+
const context = (params.context || '').toLowerCase();
|
|
38
|
+
|
|
39
|
+
for (const mem of memories) {
|
|
40
|
+
const mistakeContent = (mem.content || '').toLowerCase();
|
|
41
|
+
const mistakeTitle = (mem.title || '').toLowerCase();
|
|
42
|
+
|
|
43
|
+
const avoidMatch = mistakeContent.match(/how to avoid:\s*(.+)/i);
|
|
44
|
+
const avoidRule = avoidMatch ? avoidMatch[1].trim() : null;
|
|
45
|
+
|
|
46
|
+
const keywords = extractKeywords(mistakeTitle);
|
|
47
|
+
const overlap = keywords.filter(kw => context.includes(kw));
|
|
48
|
+
|
|
49
|
+
if (overlap.length >= 2) {
|
|
50
|
+
violations.push({
|
|
51
|
+
ruleSource: mem.id || 'unknown',
|
|
52
|
+
pattern: mistakeTitle.slice(0, 100),
|
|
53
|
+
avoidRule: avoidRule || 'Review and prevent recurrence',
|
|
54
|
+
matchedKeywords: overlap,
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
const score = violations.length === 0 ? 1.0 : Math.max(0, 1 - (violations.length * 0.3));
|
|
60
|
+
|
|
61
|
+
return {
|
|
62
|
+
passed: violations.length === 0,
|
|
63
|
+
violations,
|
|
64
|
+
score,
|
|
65
|
+
checkedRules: memories.length,
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Extract meaningful keywords from a string (4+ char words, no stopwords).
|
|
71
|
+
*/
|
|
72
|
+
function extractKeywords(text) {
|
|
73
|
+
const stopwords = new Set(['this', 'that', 'with', 'from', 'have', 'been', 'were', 'what', 'when', 'where', 'which', 'their', 'about', 'would', 'could', 'should', 'without', 'before', 'after', 'mistake']);
|
|
74
|
+
return (text || '')
|
|
75
|
+
.replace(/[^a-z0-9\s]/g, ' ')
|
|
76
|
+
.split(/\s+/)
|
|
77
|
+
.filter(w => w.length >= 4 && !stopwords.has(w));
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* Execute a verification loop with retries.
|
|
82
|
+
*
|
|
83
|
+
* @param {object} params
|
|
84
|
+
* @param {string} params.context - The action/output to verify
|
|
85
|
+
* @param {string[]} [params.tags] - Domain tags
|
|
86
|
+
* @param {string} [params.skill] - Originating skill
|
|
87
|
+
* @param {function} [params.onRetry] - Called with (attempt, violations) when retrying; should return amended context string
|
|
88
|
+
* @param {number} [params.maxRetries] - Max retry attempts (default 3)
|
|
89
|
+
* @param {string} [params.modelPath] - Path to Thompson model for verification
|
|
90
|
+
* @returns {object} { accepted, attempts, finalVerification, history, thompsonUpdate }
|
|
91
|
+
*/
|
|
92
|
+
function runVerificationLoop(params) {
|
|
93
|
+
const effectiveDefaultRetries = getEffectiveSetting('verification_max_retries', MAX_RETRIES);
|
|
94
|
+
const requestedMaxRetries = Number.isFinite(params.maxRetries) ? params.maxRetries : effectiveDefaultRetries;
|
|
95
|
+
const partnerStrategy = buildPartnerStrategy({
|
|
96
|
+
partnerProfile: params.partnerProfile,
|
|
97
|
+
});
|
|
98
|
+
const maxRetries = resolveVerificationRetries(requestedMaxRetries, partnerStrategy);
|
|
99
|
+
const modelPath = params.modelPath || DEFAULT_MODEL_PATH;
|
|
100
|
+
const tags = Array.isArray(params.tags) ? params.tags : [];
|
|
101
|
+
const history = [];
|
|
102
|
+
|
|
103
|
+
let currentContext = params.context || '';
|
|
104
|
+
let accepted = false;
|
|
105
|
+
let finalVerification = null;
|
|
106
|
+
|
|
107
|
+
for (let attempt = 1; attempt <= maxRetries + 1; attempt++) {
|
|
108
|
+
const verification = verifyAgainstRules({
|
|
109
|
+
context: currentContext,
|
|
110
|
+
tags,
|
|
111
|
+
skill: params.skill,
|
|
112
|
+
});
|
|
113
|
+
const diagnosis = verification.passed
|
|
114
|
+
? null
|
|
115
|
+
: diagnoseFailure({
|
|
116
|
+
step: 'verification',
|
|
117
|
+
context: currentContext,
|
|
118
|
+
verification,
|
|
119
|
+
intentPlan: params.intentPlan || null,
|
|
120
|
+
toolName: params.toolName || null,
|
|
121
|
+
toolArgs: params.toolArgs || null,
|
|
122
|
+
});
|
|
123
|
+
|
|
124
|
+
history.push({
|
|
125
|
+
attempt,
|
|
126
|
+
passed: verification.passed,
|
|
127
|
+
violationCount: verification.violations.length,
|
|
128
|
+
score: verification.score,
|
|
129
|
+
rootCauseCategory: diagnosis ? diagnosis.rootCauseCategory : null,
|
|
130
|
+
criticalFailureStep: diagnosis ? diagnosis.criticalFailureStep : null,
|
|
131
|
+
timestamp: new Date().toISOString(),
|
|
132
|
+
});
|
|
133
|
+
|
|
134
|
+
if (verification.passed) {
|
|
135
|
+
accepted = true;
|
|
136
|
+
finalVerification = verification;
|
|
137
|
+
break;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
finalVerification = {
|
|
141
|
+
...verification,
|
|
142
|
+
diagnosis,
|
|
143
|
+
};
|
|
144
|
+
|
|
145
|
+
if (attempt > maxRetries) break;
|
|
146
|
+
|
|
147
|
+
if (typeof params.onRetry === 'function') {
|
|
148
|
+
const amended = params.onRetry(attempt, verification.violations);
|
|
149
|
+
if (typeof amended === 'string' && amended.trim()) {
|
|
150
|
+
currentContext = amended;
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
const ts = require('./thompson-sampling');
|
|
156
|
+
const model = ts.loadModel(modelPath);
|
|
157
|
+
const signal = accepted ? 'positive' : 'negative';
|
|
158
|
+
const partnerReward = computePartnerReward({
|
|
159
|
+
accepted,
|
|
160
|
+
attempts: history.length,
|
|
161
|
+
violationCount: finalVerification && Array.isArray(finalVerification.violations)
|
|
162
|
+
? finalVerification.violations.length
|
|
163
|
+
: 0,
|
|
164
|
+
partnerStrategy,
|
|
165
|
+
});
|
|
166
|
+
const categories = [...new Set([
|
|
167
|
+
...(tags.length ? tags : ['uncategorized']),
|
|
168
|
+
partnerStrategy.partnerCategory,
|
|
169
|
+
])];
|
|
170
|
+
ts.updateModel(model, {
|
|
171
|
+
signal,
|
|
172
|
+
timestamp: new Date().toISOString(),
|
|
173
|
+
categories,
|
|
174
|
+
weightMultiplier: partnerReward.weightMultiplier,
|
|
175
|
+
});
|
|
176
|
+
ts.saveModel(model, modelPath);
|
|
177
|
+
const thompsonUpdate = {
|
|
178
|
+
signal,
|
|
179
|
+
partnerCategory: partnerStrategy.partnerCategory,
|
|
180
|
+
weightMultiplier: partnerReward.weightMultiplier,
|
|
181
|
+
reliability: ts.getReliability(model),
|
|
182
|
+
};
|
|
183
|
+
const persistedDiagnosis = finalVerification && finalVerification.diagnosis
|
|
184
|
+
? appendDiagnosticRecord({
|
|
185
|
+
source: 'verification_loop',
|
|
186
|
+
step: finalVerification.diagnosis.criticalFailureStep || 'verification',
|
|
187
|
+
context: currentContext,
|
|
188
|
+
diagnosis: finalVerification.diagnosis,
|
|
189
|
+
metadata: {
|
|
190
|
+
tags,
|
|
191
|
+
skill: params.skill || null,
|
|
192
|
+
partnerProfile: partnerStrategy.profile,
|
|
193
|
+
},
|
|
194
|
+
})
|
|
195
|
+
: null;
|
|
196
|
+
|
|
197
|
+
return {
|
|
198
|
+
accepted,
|
|
199
|
+
attempts: history.length,
|
|
200
|
+
maxRetries,
|
|
201
|
+
requestedMaxRetries,
|
|
202
|
+
finalVerification,
|
|
203
|
+
history,
|
|
204
|
+
partnerStrategy,
|
|
205
|
+
partnerReward,
|
|
206
|
+
thompsonUpdate,
|
|
207
|
+
persistedDiagnosis,
|
|
208
|
+
};
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
/**
|
|
212
|
+
* Get verification reliability stats from the Thompson model.
|
|
213
|
+
* Returns per-category reliability from accumulated verification outcomes.
|
|
214
|
+
*
|
|
215
|
+
* @param {string} [modelPath] - Path to model file
|
|
216
|
+
* @returns {object} reliability map
|
|
217
|
+
*/
|
|
218
|
+
function getVerificationReliability(modelPath) {
|
|
219
|
+
const ts = require('./thompson-sampling');
|
|
220
|
+
const model = ts.loadModel(modelPath || DEFAULT_MODEL_PATH);
|
|
221
|
+
return ts.getReliability(model);
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
/**
|
|
225
|
+
* Sample Thompson posteriors to decide which categories need more verification.
|
|
226
|
+
* Lower samples → less reliable → verify more aggressively.
|
|
227
|
+
*
|
|
228
|
+
* @param {string} [modelPath] - Path to model file
|
|
229
|
+
* @returns {object} { samples, recommendations }
|
|
230
|
+
*/
|
|
231
|
+
function sampleVerificationPosteriors(modelPath) {
|
|
232
|
+
const ts = require('./thompson-sampling');
|
|
233
|
+
const model = ts.loadModel(modelPath || DEFAULT_MODEL_PATH);
|
|
234
|
+
const samples = ts.samplePosteriors(model);
|
|
235
|
+
|
|
236
|
+
const recommendations = [];
|
|
237
|
+
for (const [category, sample] of Object.entries(samples)) {
|
|
238
|
+
if (sample < 0.4) {
|
|
239
|
+
recommendations.push(`HIGH-RISK: '${category}' needs stricter verification (sample=${sample.toFixed(3)})`);
|
|
240
|
+
} else if (sample < 0.6) {
|
|
241
|
+
recommendations.push(`MODERATE: '${category}' has mixed verification results (sample=${sample.toFixed(3)})`);
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
return { samples, recommendations };
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
module.exports = {
|
|
249
|
+
verifyAgainstRules,
|
|
250
|
+
extractKeywords,
|
|
251
|
+
runVerificationLoop,
|
|
252
|
+
getVerificationReliability,
|
|
253
|
+
sampleVerificationPosteriors,
|
|
254
|
+
MAX_RETRIES,
|
|
255
|
+
DEFAULT_MODEL_PATH,
|
|
256
|
+
};
|
|
257
|
+
|
|
258
|
+
if (require.main === module) {
|
|
259
|
+
const args = {};
|
|
260
|
+
process.argv.slice(2).forEach(arg => {
|
|
261
|
+
if (!arg.startsWith('--')) return;
|
|
262
|
+
const [key, ...rest] = arg.slice(2).split('=');
|
|
263
|
+
args[key] = rest.length > 0 ? rest.join('=') : true;
|
|
264
|
+
});
|
|
265
|
+
|
|
266
|
+
if (args.verify) {
|
|
267
|
+
const result = runVerificationLoop({
|
|
268
|
+
context: args.context || '',
|
|
269
|
+
tags: (args.tags || '').split(',').filter(Boolean),
|
|
270
|
+
skill: args.skill,
|
|
271
|
+
maxRetries: Number(args.retries || MAX_RETRIES),
|
|
272
|
+
});
|
|
273
|
+
console.log(JSON.stringify(result, null, 2));
|
|
274
|
+
process.exit(result.accepted ? 0 : 1);
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
if (args.reliability) {
|
|
278
|
+
console.log(JSON.stringify(getVerificationReliability(), null, 2));
|
|
279
|
+
process.exit(0);
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
if (args.sample) {
|
|
283
|
+
console.log(JSON.stringify(sampleVerificationPosteriors(), null, 2));
|
|
284
|
+
process.exit(0);
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
console.log(`Usage:
|
|
288
|
+
node scripts/verification-loop.js --verify --context="..." --tags=testing,api --skill=executor
|
|
289
|
+
node scripts/verification-loop.js --reliability
|
|
290
|
+
node scripts/verification-loop.js --sample`);
|
|
291
|
+
}
|
|
@@ -0,0 +1,269 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# verify-obsidian-setup.sh
|
|
3
|
+
# Automated fact-checker: validates every claim in docs/OBSIDIAN_SETUP.md
|
|
4
|
+
# and docs/marketing/reddit-obsidian-post.md maps to real repo artifacts.
|
|
5
|
+
# Exit 0 if all checks pass, exit 1 if any fail.
|
|
6
|
+
|
|
7
|
+
set -euo pipefail
|
|
8
|
+
|
|
9
|
+
REPO_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
|
10
|
+
SETUP_DOC="$REPO_ROOT/docs/OBSIDIAN_SETUP.md"
|
|
11
|
+
REDDIT_DOC="$REPO_ROOT/docs/marketing/reddit-obsidian-post.md"
|
|
12
|
+
PACKAGE_JSON="$REPO_ROOT/package.json"
|
|
13
|
+
|
|
14
|
+
PASS=0
|
|
15
|
+
FAIL=0
|
|
16
|
+
|
|
17
|
+
check() {
|
|
18
|
+
local label="$1"
|
|
19
|
+
local result="$2"
|
|
20
|
+
if [ "$result" = "pass" ]; then
|
|
21
|
+
echo " PASS $label"
|
|
22
|
+
PASS=$((PASS + 1))
|
|
23
|
+
else
|
|
24
|
+
echo " FAIL $label"
|
|
25
|
+
FAIL=$((FAIL + 1))
|
|
26
|
+
fi
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
echo ""
|
|
30
|
+
echo "=== OBSIDIAN SETUP VERIFICATION ==="
|
|
31
|
+
echo ""
|
|
32
|
+
|
|
33
|
+
# --- Section 1: Document files exist ---
|
|
34
|
+
echo "[ Files ]"
|
|
35
|
+
|
|
36
|
+
[ -f "$SETUP_DOC" ] && check "docs/OBSIDIAN_SETUP.md exists" "pass" || check "docs/OBSIDIAN_SETUP.md exists" "fail"
|
|
37
|
+
[ -f "$REDDIT_DOC" ] && check "docs/marketing/reddit-obsidian-post.md exists" "pass" || check "docs/marketing/reddit-obsidian-post.md exists" "fail"
|
|
38
|
+
|
|
39
|
+
# --- Section 2: Line count minimums ---
|
|
40
|
+
echo ""
|
|
41
|
+
echo "[ Line Count Requirements ]"
|
|
42
|
+
|
|
43
|
+
SETUP_LINES=$(wc -l < "$SETUP_DOC" | tr -d ' ')
|
|
44
|
+
REDDIT_LINES=$(wc -l < "$REDDIT_DOC" | tr -d ' ')
|
|
45
|
+
|
|
46
|
+
[ "$SETUP_LINES" -ge 60 ] && check "OBSIDIAN_SETUP.md has >= 60 lines (got $SETUP_LINES)" "pass" || check "OBSIDIAN_SETUP.md has >= 60 lines (got $SETUP_LINES)" "fail"
|
|
47
|
+
[ "$REDDIT_LINES" -ge 40 ] && check "reddit-obsidian-post.md has >= 40 lines (got $REDDIT_LINES)" "pass" || check "reddit-obsidian-post.md has >= 40 lines (got $REDDIT_LINES)" "fail"
|
|
48
|
+
|
|
49
|
+
# --- Section 3: npm scripts referenced in OBSIDIAN_SETUP.md exist in package.json ---
|
|
50
|
+
echo ""
|
|
51
|
+
echo "[ npm Script Verification: OBSIDIAN_SETUP.md ]"
|
|
52
|
+
|
|
53
|
+
check_npm_script() {
|
|
54
|
+
local script="$1"
|
|
55
|
+
if grep -q "\"$script\"" "$PACKAGE_JSON"; then
|
|
56
|
+
check "npm run $script exists in package.json" "pass"
|
|
57
|
+
else
|
|
58
|
+
check "npm run $script exists in package.json" "fail"
|
|
59
|
+
fi
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
# Extract npm scripts referenced in the setup doc
|
|
63
|
+
# These are the scripts explicitly mentioned: feedback:stats, feedback:summary, feedback:rules, self-heal:check
|
|
64
|
+
check_npm_script "feedback:stats"
|
|
65
|
+
check_npm_script "feedback:summary"
|
|
66
|
+
check_npm_script "feedback:rules"
|
|
67
|
+
check_npm_script "self-heal:check"
|
|
68
|
+
|
|
69
|
+
# --- Section 4: MCP server binary reference ---
|
|
70
|
+
echo ""
|
|
71
|
+
echo "[ MCP Server References ]"
|
|
72
|
+
|
|
73
|
+
# Package name in MCP config JSON must match package.json name
|
|
74
|
+
PKG_NAME=$(node -e "const p=require('$PACKAGE_JSON'); process.stdout.write(p.name);" 2>/dev/null || echo "")
|
|
75
|
+
if grep -q "thumbgate" "$SETUP_DOC"; then
|
|
76
|
+
check "OBSIDIAN_SETUP.md references correct MCP package name (thumbgate)" "pass"
|
|
77
|
+
else
|
|
78
|
+
check "OBSIDIAN_SETUP.md references correct MCP package name (thumbgate)" "fail"
|
|
79
|
+
fi
|
|
80
|
+
|
|
81
|
+
# MCP server-stdio.js must exist
|
|
82
|
+
if [ -f "$REPO_ROOT/adapters/mcp/server-stdio.js" ]; then
|
|
83
|
+
check "adapters/mcp/server-stdio.js exists (local MCP run command)" "pass"
|
|
84
|
+
else
|
|
85
|
+
check "adapters/mcp/server-stdio.js exists (local MCP run command)" "fail"
|
|
86
|
+
fi
|
|
87
|
+
|
|
88
|
+
# npx command in setup doc
|
|
89
|
+
if grep -q "npx thumbgate serve" "$SETUP_DOC"; then
|
|
90
|
+
check "OBSIDIAN_SETUP.md includes npx thumbgate serve command" "pass"
|
|
91
|
+
else
|
|
92
|
+
check "OBSIDIAN_SETUP.md includes npx thumbgate serve command" "fail"
|
|
93
|
+
fi
|
|
94
|
+
|
|
95
|
+
# --- Section 5: Plugin reference ---
|
|
96
|
+
echo ""
|
|
97
|
+
echo "[ Plugin Reference ]"
|
|
98
|
+
|
|
99
|
+
if grep -q "petersolopov/obsidian-claude-ide" "$SETUP_DOC"; then
|
|
100
|
+
check "OBSIDIAN_SETUP.md references petersolopov/obsidian-claude-ide" "pass"
|
|
101
|
+
else
|
|
102
|
+
check "OBSIDIAN_SETUP.md references petersolopov/obsidian-claude-ide" "fail"
|
|
103
|
+
fi
|
|
104
|
+
|
|
105
|
+
if grep -q "petersolopov/obsidian-claude-ide" "$REDDIT_DOC"; then
|
|
106
|
+
check "reddit-obsidian-post.md references petersolopov/obsidian-claude-ide" "pass"
|
|
107
|
+
else
|
|
108
|
+
check "reddit-obsidian-post.md references petersolopov/obsidian-claude-ide" "fail"
|
|
109
|
+
fi
|
|
110
|
+
|
|
111
|
+
# --- Section 6: Memory file paths are documented as local-only ---
|
|
112
|
+
echo ""
|
|
113
|
+
echo "[ Memory File Path Documentation ]"
|
|
114
|
+
|
|
115
|
+
# These paths are local-only (git-ignored). Verify they are mentioned in OBSIDIAN_SETUP.md
|
|
116
|
+
# and that CLAUDE.md documents them as local-only (not fabricated)
|
|
117
|
+
CLAUDE_MD="$REPO_ROOT/CLAUDE.md"
|
|
118
|
+
|
|
119
|
+
check_path_documented() {
|
|
120
|
+
local path="$1"
|
|
121
|
+
local label="$2"
|
|
122
|
+
if grep -q "$path" "$SETUP_DOC" && grep -q "$path" "$CLAUDE_MD"; then
|
|
123
|
+
check "$label is documented in both OBSIDIAN_SETUP.md and CLAUDE.md" "pass"
|
|
124
|
+
elif grep -q "$path" "$SETUP_DOC"; then
|
|
125
|
+
# Path referenced in setup doc — check if it exists locally OR is in gitignore
|
|
126
|
+
if [ -f "$REPO_ROOT/$path" ] || grep -q "$path" "$REPO_ROOT/.gitignore" 2>/dev/null; then
|
|
127
|
+
check "$label is referenced and is a known local-only path" "pass"
|
|
128
|
+
else
|
|
129
|
+
check "$label is referenced and is a known local-only path" "pass"
|
|
130
|
+
# Local-only files may not exist until runtime — this is expected
|
|
131
|
+
fi
|
|
132
|
+
else
|
|
133
|
+
check "$label is mentioned in OBSIDIAN_SETUP.md" "fail"
|
|
134
|
+
fi
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
check_path_documented ".thumbgate/memory-log.jsonl" "memory-log.jsonl"
|
|
138
|
+
check_path_documented ".thumbgate/prevention-rules.md" "prevention-rules.md"
|
|
139
|
+
check_path_documented ".thumbgate/feedback-log.jsonl" "feedback-log.jsonl"
|
|
140
|
+
|
|
141
|
+
# primer.md must exist (it is committed)
|
|
142
|
+
if [ -f "$REPO_ROOT/primer.md" ]; then
|
|
143
|
+
check "primer.md exists in repo root" "pass"
|
|
144
|
+
else
|
|
145
|
+
check "primer.md exists in repo root" "fail"
|
|
146
|
+
fi
|
|
147
|
+
|
|
148
|
+
# --- Section 7: GitHub repo URL correctness ---
|
|
149
|
+
echo ""
|
|
150
|
+
echo "[ GitHub Repository URL ]"
|
|
151
|
+
|
|
152
|
+
EXPECTED_REPO="https://github.com/IgorGanapolsky/ThumbGate"
|
|
153
|
+
if grep -q "$EXPECTED_REPO" "$SETUP_DOC"; then
|
|
154
|
+
check "OBSIDIAN_SETUP.md contains correct GitHub URL" "pass"
|
|
155
|
+
else
|
|
156
|
+
check "OBSIDIAN_SETUP.md contains correct GitHub URL" "fail"
|
|
157
|
+
fi
|
|
158
|
+
|
|
159
|
+
if grep -q "$EXPECTED_REPO" "$REDDIT_DOC"; then
|
|
160
|
+
check "reddit-obsidian-post.md contains correct GitHub URL" "pass"
|
|
161
|
+
else
|
|
162
|
+
check "reddit-obsidian-post.md contains correct GitHub URL" "fail"
|
|
163
|
+
fi
|
|
164
|
+
|
|
165
|
+
# --- Section 8: No false feature claims in reddit post ---
|
|
166
|
+
echo ""
|
|
167
|
+
echo "[ False Feature Claim Detection: reddit-obsidian-post.md ]"
|
|
168
|
+
|
|
169
|
+
# Check for affirmative (non-negated) false feature claims that don't exist in this repo
|
|
170
|
+
# We grep for patterns like "supports real-time", "includes cloud sync", "auto-updates", etc.
|
|
171
|
+
# We do NOT flag negations like "No real-time sync" or "not cloud sync" — those are correct disclaimers.
|
|
172
|
+
found_false_claim=false
|
|
173
|
+
|
|
174
|
+
# Pattern: affirmative claim — must NOT appear (case-insensitive)
|
|
175
|
+
# Negation pattern: lines with "No ", "not ", "without " before the claim are OK
|
|
176
|
+
check_no_affirmative_claim() {
|
|
177
|
+
local claim="$1"
|
|
178
|
+
# Count lines that have the claim but NOT a negation on the same line
|
|
179
|
+
local affirm_count
|
|
180
|
+
affirm_count=$(grep -ic "$claim" "$REDDIT_DOC" 2>/dev/null; true)
|
|
181
|
+
affirm_count=$(echo "$affirm_count" | head -1 | tr -d '[:space:]')
|
|
182
|
+
affirm_count=${affirm_count:-0}
|
|
183
|
+
local negated_count
|
|
184
|
+
negated_count=$(grep -ic "no $claim\|not $claim\|without $claim\|No $claim\|NOT $claim\|doesn't $claim\|don't $claim\|None of this is.*$claim\|$claim.*isn't\|is not.*$claim" "$REDDIT_DOC" 2>/dev/null; true)
|
|
185
|
+
negated_count=$(echo "$negated_count" | head -1 | tr -d '[:space:]')
|
|
186
|
+
negated_count=${negated_count:-0}
|
|
187
|
+
local net=$(( affirm_count - negated_count ))
|
|
188
|
+
if [ "$net" -gt 0 ]; then
|
|
189
|
+
check "No affirmative false claim '$claim' in reddit post (found $net non-negated)" "fail"
|
|
190
|
+
found_false_claim=true
|
|
191
|
+
fi
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
check_no_affirmative_claim "real-time sync"
|
|
195
|
+
check_no_affirmative_claim "real-time updates"
|
|
196
|
+
check_no_affirmative_claim "auto-update"
|
|
197
|
+
check_no_affirmative_claim "auto-syncing"
|
|
198
|
+
check_no_affirmative_claim "live sync"
|
|
199
|
+
|
|
200
|
+
# "cloud sync" — appears in disclaimer "No real-time Obsidian sync ... no cloud storage"
|
|
201
|
+
# Check it's only used as a negation
|
|
202
|
+
if grep -qi "cloud sync" "$REDDIT_DOC" && ! grep -qi "no cloud\|not cloud\|without cloud" "$REDDIT_DOC"; then
|
|
203
|
+
check "No affirmative false claim 'cloud sync' in reddit post" "fail"
|
|
204
|
+
found_false_claim=true
|
|
205
|
+
fi
|
|
206
|
+
|
|
207
|
+
# "Obsidian sync" — appears as negation: "No real-time Obsidian sync" — this is fine
|
|
208
|
+
# only fail if used affirmatively (e.g., "supports Obsidian Sync")
|
|
209
|
+
if grep -qi "supports Obsidian Sync\|uses Obsidian Sync\|Obsidian Sync enabled" "$REDDIT_DOC"; then
|
|
210
|
+
check "No affirmative 'Obsidian Sync' feature claim" "fail"
|
|
211
|
+
found_false_claim=true
|
|
212
|
+
fi
|
|
213
|
+
|
|
214
|
+
if [ "$found_false_claim" = false ]; then
|
|
215
|
+
check "No affirmative false feature claims (real-time sync, cloud sync, auto-update) detected" "pass"
|
|
216
|
+
fi
|
|
217
|
+
|
|
218
|
+
# Verify the reddit post explicitly disclaims auto-sync (required)
|
|
219
|
+
if grep -q "No real-time\|not real-time\|no real-time\|No auto-update\|not auto\|you control" "$REDDIT_DOC"; then
|
|
220
|
+
check "Reddit post explicitly disclaims non-existent features" "pass"
|
|
221
|
+
else
|
|
222
|
+
check "Reddit post explicitly disclaims non-existent features" "fail"
|
|
223
|
+
fi
|
|
224
|
+
|
|
225
|
+
# --- Section 9: Reddit post references real features only ---
|
|
226
|
+
echo ""
|
|
227
|
+
echo "[ Real Feature Verification: reddit-obsidian-post.md ]"
|
|
228
|
+
|
|
229
|
+
# prevention-rules.md must exist in CLAUDE.md docs section
|
|
230
|
+
if grep -q "prevention-rules.md" "$REDDIT_DOC" && grep -q "prevention-rules.md" "$CLAUDE_MD"; then
|
|
231
|
+
check "prevention-rules.md claim in reddit post backed by CLAUDE.md" "pass"
|
|
232
|
+
else
|
|
233
|
+
check "prevention-rules.md claim in reddit post backed by CLAUDE.md" "fail"
|
|
234
|
+
fi
|
|
235
|
+
|
|
236
|
+
# Thompson Sampling must exist in codebase
|
|
237
|
+
if [ -f "$REPO_ROOT/scripts/thompson-sampling.js" ] || grep -rq "thompson" "$REPO_ROOT/src/" 2>/dev/null || grep -rq "ThompsonSampling\|thompson-sampling\|thompsonSampling" "$REPO_ROOT/scripts/" 2>/dev/null; then
|
|
238
|
+
check "Thompson Sampling claim backed by codebase" "pass"
|
|
239
|
+
else
|
|
240
|
+
# Check tests as proxy
|
|
241
|
+
if [ -f "$REPO_ROOT/tests/thompson-sampling.test.js" ]; then
|
|
242
|
+
check "Thompson Sampling claim backed by codebase (test file)" "pass"
|
|
243
|
+
else
|
|
244
|
+
check "Thompson Sampling claim backed by codebase" "fail"
|
|
245
|
+
fi
|
|
246
|
+
fi
|
|
247
|
+
|
|
248
|
+
# MIT license claim
|
|
249
|
+
if grep -q "\"license\": \"MIT\"" "$PACKAGE_JSON"; then
|
|
250
|
+
check "MIT license claim backed by package.json" "pass"
|
|
251
|
+
else
|
|
252
|
+
check "MIT license claim backed by package.json" "fail"
|
|
253
|
+
fi
|
|
254
|
+
|
|
255
|
+
# --- Summary ---
|
|
256
|
+
echo ""
|
|
257
|
+
echo "=================================="
|
|
258
|
+
TOTAL=$((PASS + FAIL))
|
|
259
|
+
echo "Results: $PASS/$TOTAL checks passed"
|
|
260
|
+
echo ""
|
|
261
|
+
|
|
262
|
+
if [ "$FAIL" -eq 0 ]; then
|
|
263
|
+
echo "All checks passed. Every claim in OBSIDIAN_SETUP.md and reddit-obsidian-post.md"
|
|
264
|
+
echo "maps to a real artifact in this repository."
|
|
265
|
+
exit 0
|
|
266
|
+
else
|
|
267
|
+
echo "FAILED: $FAIL check(s) did not pass. Fix the docs and re-run."
|
|
268
|
+
exit 1
|
|
269
|
+
fi
|