thumbgate 1.15.0 → 1.16.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.
Files changed (129) hide show
  1. package/.claude-plugin/marketplace.json +6 -6
  2. package/.claude-plugin/plugin.json +3 -3
  3. package/.well-known/llms.txt +5 -5
  4. package/.well-known/mcp/server-card.json +1 -1
  5. package/README.md +59 -35
  6. package/adapters/chatgpt/openapi.yaml +118 -2
  7. package/adapters/claude/.mcp.json +2 -2
  8. package/adapters/mcp/server-stdio.js +210 -84
  9. package/adapters/opencode/opencode.json +1 -1
  10. package/bench/prompt-eval-suite.json +5 -1
  11. package/bin/cli.js +157 -8
  12. package/config/evals/agent-safety-eval.json +338 -22
  13. package/config/gates/routine.json +43 -0
  14. package/config/github-about.json +3 -3
  15. package/config/model-candidates.json +131 -0
  16. package/openapi/openapi.yaml +118 -2
  17. package/package.json +55 -48
  18. package/public/blog.html +7 -7
  19. package/public/codex-plugin.html +6 -6
  20. package/public/compare.html +29 -23
  21. package/public/dashboard.html +82 -10
  22. package/public/guide.html +28 -28
  23. package/public/index.html +216 -98
  24. package/public/learn.html +50 -22
  25. package/public/lessons.html +1 -1
  26. package/public/numbers.html +17 -17
  27. package/public/pro.html +82 -18
  28. package/scripts/agent-audit-trace.js +55 -0
  29. package/scripts/agent-memory-lifecycle.js +96 -0
  30. package/scripts/agent-readiness-plan.js +118 -0
  31. package/scripts/agentic-data-pipeline.js +21 -1
  32. package/scripts/agents-sdk-sandbox-plan.js +57 -0
  33. package/scripts/ai-org-governance.js +98 -0
  34. package/scripts/ai-search-distribution.js +43 -0
  35. package/scripts/artifact-agent-plan.js +81 -0
  36. package/scripts/billing.js +27 -8
  37. package/scripts/cli-schema.js +18 -2
  38. package/scripts/code-mode-mcp-plan.js +71 -0
  39. package/scripts/context-engine.js +1 -2
  40. package/scripts/context-manager.js +4 -1
  41. package/scripts/dashboard-render-spec.js +1 -1
  42. package/scripts/dashboard.js +275 -9
  43. package/scripts/decision-journal.js +13 -3
  44. package/scripts/document-workflow-governance.js +62 -0
  45. package/scripts/enterprise-agent-rollout.js +34 -0
  46. package/scripts/experience-replay-governance.js +69 -0
  47. package/scripts/export-hf-dataset.js +1 -1
  48. package/scripts/feedback-loop.js +92 -4
  49. package/scripts/feedback-to-rules.js +17 -23
  50. package/scripts/gates-engine.js +4 -6
  51. package/scripts/growth-campaigns.js +49 -0
  52. package/scripts/harness-selector.js +16 -4
  53. package/scripts/hybrid-supervisor-agent.js +64 -0
  54. package/scripts/inference-cache-policy.js +72 -0
  55. package/scripts/inference-economics.js +53 -0
  56. package/scripts/internal-agent-bootstrap.js +12 -2
  57. package/scripts/knowledge-layer-plan.js +108 -0
  58. package/scripts/lesson-inference.js +183 -44
  59. package/scripts/lesson-search.js +4 -1
  60. package/scripts/llm-client.js +157 -26
  61. package/scripts/mailer/resend-mailer.js +112 -1
  62. package/scripts/mcp-transport-strategy.js +66 -0
  63. package/scripts/memory-store-governance.js +60 -0
  64. package/scripts/meta-agent-loop.js +7 -13
  65. package/scripts/model-access-eligibility.js +38 -0
  66. package/scripts/model-migration-readiness.js +55 -0
  67. package/scripts/operational-integrity.js +96 -3
  68. package/scripts/otel-declarative-config.js +56 -0
  69. package/scripts/perplexity-client.js +1 -1
  70. package/scripts/post-training-governance.js +34 -0
  71. package/scripts/private-core-boundary.js +72 -0
  72. package/scripts/production-agent-readiness.js +40 -0
  73. package/scripts/prompt-eval.js +564 -32
  74. package/scripts/prompt-programs.js +93 -0
  75. package/scripts/provider-action-normalizer.js +585 -0
  76. package/scripts/scaling-law-claims.js +60 -0
  77. package/scripts/security-scanner.js +1 -1
  78. package/scripts/self-distill-agent.js +7 -32
  79. package/scripts/seo-gsd.js +232 -55
  80. package/scripts/skill-rag-router.js +53 -0
  81. package/scripts/spec-gate.js +1 -1
  82. package/scripts/student-consistent-training.js +73 -0
  83. package/scripts/synthetic-data-provenance.js +98 -0
  84. package/scripts/task-context-result.js +81 -0
  85. package/scripts/telemetry-analytics.js +149 -0
  86. package/scripts/thompson-sampling.js +2 -2
  87. package/scripts/token-savings.js +7 -6
  88. package/scripts/token-tco.js +46 -0
  89. package/scripts/tool-registry.js +63 -3
  90. package/scripts/verification-loop.js +10 -1
  91. package/scripts/verifier-scoring.js +71 -0
  92. package/scripts/workflow-sentinel.js +284 -28
  93. package/scripts/workspace-agent-routines.js +118 -0
  94. package/src/api/server.js +381 -120
  95. package/scripts/analytics-report.js +0 -328
  96. package/scripts/autonomous-workflow.js +0 -377
  97. package/scripts/billing-setup.js +0 -109
  98. package/scripts/creator-campaigns.js +0 -239
  99. package/scripts/cross-encoder-reranker.js +0 -235
  100. package/scripts/daemon-manager.js +0 -108
  101. package/scripts/decision-trace.js +0 -354
  102. package/scripts/delegation-runtime.js +0 -896
  103. package/scripts/dispatch-brief.js +0 -159
  104. package/scripts/distribution-surfaces.js +0 -110
  105. package/scripts/feedback-history-distiller.js +0 -382
  106. package/scripts/funnel-analytics.js +0 -35
  107. package/scripts/history-distiller.js +0 -200
  108. package/scripts/hosted-job-launcher.js +0 -256
  109. package/scripts/intent-router.js +0 -392
  110. package/scripts/lesson-reranker.js +0 -263
  111. package/scripts/lesson-retrieval.js +0 -148
  112. package/scripts/managed-lesson-agent.js +0 -183
  113. package/scripts/operational-dashboard.js +0 -103
  114. package/scripts/operational-summary.js +0 -129
  115. package/scripts/operator-artifacts.js +0 -608
  116. package/scripts/optimize-context.js +0 -17
  117. package/scripts/org-dashboard.js +0 -206
  118. package/scripts/partner-orchestration.js +0 -146
  119. package/scripts/predictive-insights.js +0 -356
  120. package/scripts/pulse.js +0 -80
  121. package/scripts/reflector-agent.js +0 -221
  122. package/scripts/sales-pipeline.js +0 -681
  123. package/scripts/session-episode-store.js +0 -329
  124. package/scripts/session-health-sensor.js +0 -242
  125. package/scripts/session-report.js +0 -120
  126. package/scripts/swarm-coordinator.js +0 -81
  127. package/scripts/tool-kpi-tracker.js +0 -12
  128. package/scripts/webhook-delivery.js +0 -62
  129. package/scripts/workflow-sprint-intake.js +0 -475
@@ -0,0 +1,71 @@
1
+ 'use strict';
2
+
3
+ function estimateToolSchemaTokens(endpointCount, tokensPerEndpoint = 450) {
4
+ return Math.max(0, Number(endpointCount || 0) * Number(tokensPerEndpoint || 0));
5
+ }
6
+
7
+ function buildCodeModeMcpPlan(options = {}) {
8
+ const endpointCount = Number(options.endpointCount || 0);
9
+ const traditionalTokens = estimateToolSchemaTokens(endpointCount, options.tokensPerEndpoint);
10
+ const codeModeTokens = Number(options.codeModeTokens || 1000);
11
+
12
+ return {
13
+ pattern: 'code_mode_mcp',
14
+ endpointCount,
15
+ traditionalTokens,
16
+ codeModeTokens,
17
+ tokenReductionPercent: traditionalTokens > 0
18
+ ? Number((((traditionalTokens - codeModeTokens) / traditionalTokens) * 100).toFixed(2))
19
+ : 0,
20
+ tools: [
21
+ {
22
+ name: 'search',
23
+ purpose: 'Find the relevant API area, path, operation, or type without loading the whole schema into context.',
24
+ },
25
+ {
26
+ name: 'execute',
27
+ purpose: 'Run a bounded code snippet against typed API helpers inside a sandbox.',
28
+ },
29
+ ],
30
+ sandbox: {
31
+ filesystem: 'none',
32
+ environmentVariables: 'not_exposed',
33
+ outboundRequests: 'explicit_handlers_only',
34
+ maxExecutionMs: Number(options.maxExecutionMs || 10000),
35
+ },
36
+ gates: [
37
+ 'search before execute',
38
+ 'execute only against typed helper SDK',
39
+ 'block raw credential access',
40
+ 'record code snippet and API calls in audit log',
41
+ 'require idempotency key for write operations',
42
+ ],
43
+ };
44
+ }
45
+
46
+ function evaluateCodeModeMcpPlan(plan = {}) {
47
+ const issues = [];
48
+ if (Number(plan.endpointCount || 0) < 100) issues.push('api_surface_too_small_for_code_mode');
49
+ if (!Array.isArray(plan.tools) || plan.tools.length !== 2) issues.push('expected_search_and_execute_only');
50
+ if (plan.sandbox?.filesystem !== 'none') issues.push('filesystem_must_be_disabled');
51
+ if (plan.sandbox?.environmentVariables !== 'not_exposed') issues.push('env_vars_must_not_be_exposed');
52
+ if (plan.sandbox?.outboundRequests !== 'explicit_handlers_only') issues.push('outbound_requests_need_handlers');
53
+ if (!Array.isArray(plan.gates) || !plan.gates.includes('search before execute')) {
54
+ issues.push('search_before_execute_required');
55
+ }
56
+ if (!Array.isArray(plan.gates) || !plan.gates.includes('require idempotency key for write operations')) {
57
+ issues.push('write_idempotency_required');
58
+ }
59
+
60
+ return {
61
+ decision: issues.length ? 'warn' : 'allow',
62
+ issues,
63
+ tokenReductionPercent: plan.tokenReductionPercent || 0,
64
+ };
65
+ }
66
+
67
+ module.exports = {
68
+ buildCodeModeMcpPlan,
69
+ estimateToolSchemaTokens,
70
+ evaluateCodeModeMcpPlan,
71
+ };
@@ -9,8 +9,7 @@
9
9
  * topical bundles and route queries to the most relevant subset. This reduces
10
10
  * MCP tool calls and context window consumption.
11
11
  *
12
- * Ported from Subway_RN_Demo/scripts/context-engine.js for ThumbGate.
13
- * Ported from Subway_RN_Demo/scripts/context-engine.js for thumbgate.
12
+ * Context assembly engine for ThumbGate feedback memory.
14
13
  * PATH: PROJECT_ROOT = path.join(__dirname, '..') — 1 level up from scripts/
15
14
  */
16
15
 
@@ -26,7 +26,10 @@ const {
26
26
  readSessionHandoff,
27
27
  recordProvenance,
28
28
  } = require('./contextfs');
29
- const { retrieveRelevantLessons } = require('./lesson-retrieval');
29
+ const { loadOptionalModule } = require('./private-core-boundary');
30
+ const { retrieveRelevantLessons } = loadOptionalModule('./lesson-retrieval', () => ({
31
+ retrieveRelevantLessons: () => [],
32
+ }));
30
33
  const { evaluatePretool } = require('./hybrid-feedback-context');
31
34
  const { loadProfile } = require('./user-profile');
32
35
  const {
@@ -243,7 +243,7 @@ function buildIncidentReviewSpec(data) {
243
243
  badge: String(gate.action || 'block').toUpperCase(),
244
244
  tone: gate.action === 'warn' ? 'info' : 'warning',
245
245
  })),
246
- 'No active gates configured.'
246
+ 'No active checks configured.'
247
247
  ),
248
248
  buildList(
249
249
  'Root cause clusters',
@@ -6,16 +6,36 @@ const path = require('path');
6
6
  const { aggregateFailureDiagnostics } = require('./failure-diagnostics');
7
7
  const { AUDIT_LOG_FILENAME } = require('./audit-trail');
8
8
  const { getBillingSummary, loadFunnelLedger, loadResolvedRevenueEvents } = require('./billing');
9
+ const {
10
+ createUnavailableReport,
11
+ loadOptionalModule,
12
+ } = require('./private-core-boundary');
9
13
  const { getTelemetryAnalytics, loadTelemetryEvents } = require('./telemetry-analytics');
10
14
  const { getAutoGatesPath } = require('./auto-promote-gates');
11
- const { summarizeDelegation } = require('./delegation-runtime');
12
15
  const { loadGatesConfig } = require('./gates-engine');
13
16
  const { filterEntriesForWindow, resolveAnalyticsWindow } = require('./analytics-window');
14
17
  const { resolveHostedBillingConfig } = require('./hosted-config');
15
18
  const { generateAgentReadinessReport } = require('./agent-readiness');
16
19
  const { summarizeGateTemplates } = require('./gate-templates');
17
- const { generateOrgDashboard } = require('./org-dashboard');
18
- const { buildPredictiveInsights } = require('./predictive-insights');
20
+ const { buildPredictiveInsights } = loadOptionalModule('./predictive-insights', () => ({
21
+ buildPredictiveInsights: () => ({
22
+ upgradePropensity: {
23
+ pro: { band: 'unavailable', score: 0 },
24
+ team: { band: 'unavailable', score: 0 },
25
+ },
26
+ revenueForecast: {
27
+ predictedBookedRevenueCents: 0,
28
+ incrementalOpportunityCents: 0,
29
+ },
30
+ anomalySummary: {
31
+ count: 0,
32
+ severity: 'none',
33
+ },
34
+ topCreators: [],
35
+ topSources: [],
36
+ ...createUnavailableReport('Predictive insights'),
37
+ }),
38
+ }));
19
39
  const { routeProfile } = require('./profile-router');
20
40
  const { getSettingsStatus } = require('./settings-hierarchy');
21
41
  const { summarizeWorkflowRuns } = require('./workflow-runs');
@@ -28,6 +48,40 @@ const DEFAULT_GATES_PATH = path.join(PROJECT_ROOT, 'config', 'gates', 'default.j
28
48
  const LANDING_PAGE_PATH = path.join(PROJECT_ROOT, 'public', 'index.html');
29
49
  const DASHBOARD_REVIEW_STATE_FILE = 'dashboard-review-state.json';
30
50
 
51
+ function loadOrgDashboardModule() {
52
+ const modulePath = path.resolve(__dirname, 'org-dashboard.js');
53
+ if (!fs.existsSync(modulePath)) return null;
54
+ return loadOptionalModule('./org-dashboard', () => ({
55
+ generateOrgDashboard: ({ windowHours } = {}) => buildUnavailableOrgDashboard(windowHours || 24),
56
+ }));
57
+ }
58
+
59
+ function loadDelegationRuntimeModule() {
60
+ const modulePath = path.resolve(__dirname, 'delegation-runtime.js');
61
+ if (!fs.existsSync(modulePath)) return null;
62
+ return require(modulePath);
63
+ }
64
+
65
+ function buildUnavailableOrgDashboard(windowHours) {
66
+ return {
67
+ available: false,
68
+ windowHours,
69
+ totalAgents: 0,
70
+ activeAgents: 0,
71
+ totalToolCalls: 0,
72
+ totalBlocked: 0,
73
+ totalWarned: 0,
74
+ totalAllowed: 0,
75
+ orgAdherenceRate: 100,
76
+ topBlockedGates: [],
77
+ riskAgents: [],
78
+ agents: [],
79
+ proRequired: true,
80
+ upgradeMessage: 'Org dashboard is available only in the private ThumbGate Core runtime (ThumbGate-Core).',
81
+ availability: 'private_core',
82
+ };
83
+ }
84
+
31
85
  // ---------------------------------------------------------------------------
32
86
  // Data readers
33
87
  // ---------------------------------------------------------------------------
@@ -665,6 +719,197 @@ function countCoverage(entries, resolver) {
665
719
  return safeRate(matched, entries.length);
666
720
  }
667
721
 
722
+ function sumCounterValues(counter = {}) {
723
+ return Object.values(counter).reduce((sum, value) => sum + (Number(value) || 0), 0);
724
+ }
725
+
726
+ function sumKeysMatching(counter = {}, matcher) {
727
+ return Object.entries(counter).reduce((sum, entry) => {
728
+ const [key, value] = entry;
729
+ return matcher(key) ? sum + (Number(value) || 0) : sum;
730
+ }, 0);
731
+ }
732
+
733
+ function rankCounter(counter = {}, limit = 5) {
734
+ return Object.entries(counter)
735
+ .sort((a, b) => b[1] - a[1])
736
+ .slice(0, limit)
737
+ .map(([key, count]) => ({ key, count }));
738
+ }
739
+
740
+ function mapBuyerLossTheme(reasonCode) {
741
+ const normalized = String(reasonCode || 'unknown').toLowerCase();
742
+ if (['too_expensive', 'price_shock', 'budget', 'need_budget_approval'].includes(normalized)) {
743
+ return 'pricing';
744
+ }
745
+ if (['need_more_proof', 'trust_gap', 'security_unclear'].includes(normalized)) {
746
+ return 'trust';
747
+ }
748
+ if (['not_ready', 'later', 'just_researching'].includes(normalized)) {
749
+ return 'timing';
750
+ }
751
+ if (['need_team_features', 'need_team_approval'].includes(normalized)) {
752
+ return 'team';
753
+ }
754
+ if (['integration_unclear', 'setup_confusing'].includes(normalized)) {
755
+ return 'integration';
756
+ }
757
+ if (['prefer_oss'].includes(normalized)) {
758
+ return 'open_source';
759
+ }
760
+ return 'unknown';
761
+ }
762
+
763
+ function buildLossAnalysis(analytics) {
764
+ const telemetry = analytics.telemetry || {};
765
+ const visitors = telemetry.visitors || {};
766
+ const ctas = telemetry.ctas || {};
767
+ const behavior = telemetry.behavior || {};
768
+ const buyerLoss = analytics.buyerLoss || {};
769
+ const conversionFunnel = telemetry.conversionFunnel || {};
770
+ const runtimeConfig = resolveHostedBillingConfig();
771
+ const monthlyPriceCents = Math.round((Number(runtimeConfig.proPriceDollars) || 19) * 100);
772
+ const pageViews = visitors.pageViews || 0;
773
+ const checkoutStarts = ctas.checkoutStarts || 0;
774
+ const paidOrders = analytics.funnel ? analytics.funnel.paidOrders || 0 : 0;
775
+ const trialEmails = conversionFunnel.trialEmails || 0;
776
+ const explicitReasons = buyerLoss.reasonsByCode || {};
777
+ const reasonThemes = {};
778
+ Object.entries(explicitReasons).forEach(([reasonCode, count]) => {
779
+ const theme = mapBuyerLossTheme(reasonCode);
780
+ reasonThemes[theme] = (reasonThemes[theme] || 0) + count;
781
+ });
782
+
783
+ const proImpressions = sumKeysMatching(behavior.ctaImpressionsById || {}, (key) => /pro|pricing/i.test(key));
784
+ const proClicks = sumKeysMatching(ctas.byId || {}, (key) => /pro|pricing/i.test(key));
785
+ const pricingViews = sumKeysMatching(behavior.sectionViewsById || {}, (key) => /pricing/i.test(key));
786
+ const proofViews = sumKeysMatching(behavior.sectionViewsById || {}, (key) => /proof/i.test(key));
787
+ const exitsBeforePricing = sumKeysMatching(behavior.exitsByLastVisibleSection || {}, (key) => !/pricing|faq/i.test(key));
788
+ const checkoutLossCount = Math.max(0, checkoutStarts - paidOrders);
789
+
790
+ const stageDropoff = [
791
+ {
792
+ key: 'landing_to_checkout',
793
+ stage: 'landing',
794
+ lostCount: Math.max(0, pageViews - checkoutStarts),
795
+ rate: safeRate(Math.max(0, pageViews - checkoutStarts), pageViews),
796
+ },
797
+ {
798
+ key: 'cta_impression_to_click',
799
+ stage: 'message',
800
+ lostCount: Math.max(0, proImpressions - proClicks),
801
+ rate: safeRate(Math.max(0, proImpressions - proClicks), proImpressions),
802
+ },
803
+ {
804
+ key: 'email_focus_to_capture',
805
+ stage: 'lead_capture',
806
+ lostCount: Math.max(0, (behavior.emailFocusEvents || 0) - trialEmails),
807
+ rate: safeRate(Math.max(0, (behavior.emailFocusEvents || 0) - trialEmails), behavior.emailFocusEvents || 0),
808
+ },
809
+ {
810
+ key: 'checkout_to_paid',
811
+ stage: 'checkout',
812
+ lostCount: checkoutLossCount,
813
+ rate: safeRate(checkoutLossCount, checkoutStarts),
814
+ },
815
+ ].sort((a, b) => b.lostCount - a.lostCount);
816
+
817
+ const inferredCauses = [];
818
+ if (exitsBeforePricing > 0) {
819
+ inferredCauses.push({
820
+ key: 'message_drop_before_pricing',
821
+ stage: 'landing',
822
+ count: exitsBeforePricing,
823
+ evidence: {
824
+ topExitSection: behavior.topExitSection,
825
+ pricingViews,
826
+ pageExits: behavior.pageExits || 0,
827
+ },
828
+ });
829
+ }
830
+ if (proImpressions > 0 && proClicks < proImpressions) {
831
+ inferredCauses.push({
832
+ key: 'weak_pricing_cta_response',
833
+ stage: 'message',
834
+ count: Math.max(0, proImpressions - proClicks),
835
+ evidence: {
836
+ proImpressions,
837
+ proClicks,
838
+ impressionToClickRate: safeRate(proClicks, proImpressions),
839
+ },
840
+ });
841
+ }
842
+ if ((behavior.emailAbandonEvents || 0) > 0) {
843
+ inferredCauses.push({
844
+ key: 'email_capture_friction',
845
+ stage: 'lead_capture',
846
+ count: behavior.emailAbandonEvents || 0,
847
+ evidence: {
848
+ emailFocusEvents: behavior.emailFocusEvents || 0,
849
+ emailAbandonEvents: behavior.emailAbandonEvents || 0,
850
+ emailAbandonRate: behavior.emailAbandonRate || 0,
851
+ },
852
+ });
853
+ }
854
+ if (checkoutLossCount > 0 || ctas.checkoutFailures || ctas.lookupFailures || ctas.checkoutCancelled || ctas.checkoutAbandoned) {
855
+ inferredCauses.push({
856
+ key: 'checkout_friction',
857
+ stage: 'checkout',
858
+ count: checkoutLossCount,
859
+ evidence: {
860
+ checkoutStarts,
861
+ paidOrders,
862
+ checkoutCancelled: ctas.checkoutCancelled || 0,
863
+ checkoutAbandoned: ctas.checkoutAbandoned || 0,
864
+ checkoutFailures: ctas.checkoutFailures || 0,
865
+ lookupFailures: ctas.lookupFailures || 0,
866
+ },
867
+ });
868
+ }
869
+ const topTheme = rankCounter(reasonThemes, 1)[0] || null;
870
+ if (topTheme) {
871
+ inferredCauses.push({
872
+ key: `explicit_${topTheme.key}`,
873
+ stage: topTheme.key === 'pricing' ? 'pricing' : 'objection',
874
+ count: topTheme.count,
875
+ evidence: {
876
+ theme: topTheme.key,
877
+ topReasons: rankCounter(explicitReasons, 3),
878
+ },
879
+ });
880
+ }
881
+
882
+ inferredCauses.sort((a, b) => b.count - a.count);
883
+
884
+ return {
885
+ primaryIssue: inferredCauses[0] || null,
886
+ stageDropoff,
887
+ inferredCauses,
888
+ explicitThemes: rankCounter(reasonThemes, 6),
889
+ explicitReasons: rankCounter(explicitReasons, 6),
890
+ behaviorSignals: {
891
+ topViewedSection: behavior.topViewedSection || null,
892
+ topExitSection: behavior.topExitSection || null,
893
+ topExitDwellBucket: behavior.topExitDwellBucket || null,
894
+ topImpressionCta: behavior.topImpressionCta || null,
895
+ pricingViews,
896
+ proofViews,
897
+ pageExits: behavior.pageExits || 0,
898
+ exitsBeforePricing,
899
+ averageExitEngagementMs: behavior.averageExitEngagementMs || 0,
900
+ averageExitScrollPercent: behavior.averageExitScrollPercent || 0,
901
+ emailFocusEvents: behavior.emailFocusEvents || 0,
902
+ emailAbandonEvents: behavior.emailAbandonEvents || 0,
903
+ },
904
+ revenueOpportunity: {
905
+ currentMonthlyPriceCents: monthlyPriceCents,
906
+ checkoutLossCount,
907
+ explicitBuyerLossCount: buyerLoss.totalSignals || 0,
908
+ opportunityAtCurrentMonthlyPriceCents: checkoutLossCount * monthlyPriceCents,
909
+ },
910
+ };
911
+ }
912
+
668
913
  function computeAnalyticsSummary(feedbackDir, options = {}) {
669
914
  const analyticsWindow = resolveAnalyticsWindow(options.analyticsWindow || options);
670
915
  const telemetryEntries = filterEntriesForWindow(
@@ -749,6 +994,13 @@ function computeAnalyticsSummary(feedbackDir, options = {}) {
749
994
  topSurface: null,
750
995
  topQuery: null,
751
996
  },
997
+ trackedLinks: telemetry.trackedLinks || {
998
+ totalHits: 0,
999
+ totalCheckoutStarts: 0,
1000
+ overallConversionRate: 0,
1001
+ bySlug: {},
1002
+ topSlug: null,
1003
+ },
752
1004
  efficiency,
753
1005
  revenue: billing.revenue || {
754
1006
  paidProviderEvents: 0,
@@ -1150,9 +1402,19 @@ function generateDashboard(feedbackDir, options = {}) {
1150
1402
  analyticsWindow,
1151
1403
  billingSummary,
1152
1404
  });
1405
+ analytics.lossAnalysis = buildLossAnalysis(analytics);
1153
1406
  const observability = computeObservabilityStats(diagnosticEntries, diagnostics, secretGuard, analytics.telemetry);
1154
1407
  const instrumentation = computeInstrumentationReadiness(analytics, billingSummary);
1155
- const delegation = summarizeDelegation(feedbackDir);
1408
+ const delegationRuntime = loadDelegationRuntimeModule();
1409
+ const delegation = delegationRuntime
1410
+ ? delegationRuntime.summarizeDelegation(feedbackDir)
1411
+ : {
1412
+ totalHandoffs: 0,
1413
+ successfulHandoffs: 0,
1414
+ blockedHandoffs: 0,
1415
+ activePlans: [],
1416
+ availability: 'private_core',
1417
+ };
1156
1418
  const readiness = generateAgentReadinessReport({ projectRoot: PROJECT_ROOT });
1157
1419
  const harness = computeHarnessOverview(feedbackDir, entries);
1158
1420
  const interventionPolicy = getInterventionPolicySummary(feedbackDir);
@@ -1219,11 +1481,15 @@ function generateDashboard(feedbackDir, options = {}) {
1219
1481
  day.lessons = lessonPipeline.lessonsByDay.get(day.dayKey) || 0;
1220
1482
  }
1221
1483
 
1222
- const team = generateOrgDashboard({
1223
- windowHours: resolveTeamWindowHours(analyticsWindow),
1224
- authContext: options.authContext,
1225
- proOverride: options.teamProOverride,
1226
- });
1484
+ const teamWindowHours = resolveTeamWindowHours(analyticsWindow);
1485
+ const orgDashboard = loadOrgDashboardModule();
1486
+ const team = orgDashboard
1487
+ ? orgDashboard.generateOrgDashboard({
1488
+ windowHours: teamWindowHours,
1489
+ authContext: options.authContext,
1490
+ proOverride: options.teamProOverride,
1491
+ })
1492
+ : buildUnavailableOrgDashboard(teamWindowHours);
1227
1493
  const templateLibrary = summarizeGateTemplates();
1228
1494
  const predictive = buildPredictiveInsights({
1229
1495
  telemetryAnalytics: analytics.telemetry,
@@ -192,8 +192,18 @@ function collapseDecisionTimeline(records) {
192
192
  });
193
193
  }
194
194
 
195
- function initializeDaySeries(dayCount) {
196
- const today = new Date();
195
+ function resolveNow(now) {
196
+ if (now instanceof Date) return new Date(now.getTime());
197
+ if (typeof now === 'number' && Number.isFinite(now)) return new Date(now);
198
+ if (typeof now === 'string' && now) {
199
+ const parsed = new Date(now);
200
+ if (!Number.isNaN(parsed.getTime())) return parsed;
201
+ }
202
+ return new Date();
203
+ }
204
+
205
+ function initializeDaySeries(dayCount, now) {
206
+ const today = resolveNow(now);
197
207
  today.setHours(0, 0, 0, 0);
198
208
  const days = [];
199
209
  for (let offset = dayCount - 1; offset >= 0; offset -= 1) {
@@ -224,7 +234,7 @@ function computeDecisionMetrics(feedbackDir, options = {}) {
224
234
  const dayCount = Number.isInteger(options.dayCount) ? options.dayCount : DEFAULT_DAY_COUNT;
225
235
  const records = readDecisionLog(getDecisionLogPath(feedbackDir));
226
236
  const actions = collapseDecisionTimeline(records).filter((entry) => entry.evaluation);
227
- const series = initializeDaySeries(dayCount);
237
+ const series = initializeDaySeries(dayCount, options.now);
228
238
  const dayMap = new Map(series.map((day) => [day.dayKey, day]));
229
239
  const outcomeCounts = {
230
240
  accepted: 0,
@@ -0,0 +1,62 @@
1
+ 'use strict';
2
+
3
+ function buildDocumentWorkflowPlan(options = {}) {
4
+ const provider = options.provider || 'secure_content_layer';
5
+ const workflow = options.workflow || 'document_intake_routing';
6
+
7
+ return {
8
+ workflow,
9
+ provider,
10
+ steps: [
11
+ 'discover eligible folders through approved connector scope',
12
+ 'extract document metadata inside sandbox',
13
+ 'classify document type with structured output',
14
+ 'route document to approved destination',
15
+ 'write audit event for every read, extraction, decision, and route',
16
+ ],
17
+ zeroTrust: {
18
+ leastPrivilegeScopes: true,
19
+ credentialsOutsideSandbox: true,
20
+ noRawDocumentExportByDefault: true,
21
+ perFolderApproval: true,
22
+ },
23
+ requiredEvidence: [
24
+ 'connector scope',
25
+ 'source document id',
26
+ 'classification result',
27
+ 'route destination',
28
+ 'audit event id',
29
+ 'sandbox manifest',
30
+ ],
31
+ gates: [
32
+ 'block routing when connector scope is missing',
33
+ 'block raw content export unless explicitly approved',
34
+ 'block completion claims without audit event id',
35
+ 'require human review for legal, financial, medical, or HR documents',
36
+ ],
37
+ };
38
+ }
39
+
40
+ function evaluateDocumentWorkflowRun(run = {}) {
41
+ const issues = [];
42
+ if (!run.connectorScope) issues.push('missing_connector_scope');
43
+ if (!run.sourceDocumentId) issues.push('missing_source_document_id');
44
+ if (!run.classification) issues.push('missing_classification');
45
+ if (!run.routeDestination) issues.push('missing_route_destination');
46
+ if (!run.auditEventId) issues.push('missing_audit_event_id');
47
+ if (!run.sandboxManifest) issues.push('missing_sandbox_manifest');
48
+ if (run.rawExport && !run.rawExportApproved) issues.push('raw_export_requires_approval');
49
+ if (['legal', 'financial', 'medical', 'hr'].includes(String(run.classification).toLowerCase()) && !run.humanReviewed) {
50
+ issues.push('sensitive_document_human_review_required');
51
+ }
52
+
53
+ return {
54
+ decision: issues.length ? 'deny' : 'allow',
55
+ issues,
56
+ };
57
+ }
58
+
59
+ module.exports = {
60
+ buildDocumentWorkflowPlan,
61
+ evaluateDocumentWorkflowRun,
62
+ };
@@ -0,0 +1,34 @@
1
+ #!/usr/bin/env node
2
+ 'use strict';
3
+
4
+ function buildEnterpriseAgentRollout(input = {}) {
5
+ const industry = input.industry || 'enterprise software';
6
+ return {
7
+ program: 'ThumbGate Enterprise Agent Acceleration',
8
+ industry,
9
+ operatingModel: {
10
+ forwardDeployedEngineer: true,
11
+ humanInTheLead: true,
12
+ domainExpertsRequired: true,
13
+ sovereignDeploymentOption: true,
14
+ },
15
+ phases: [
16
+ { id: 'discover', outcome: 'rank workflows by measurable business value and risk' },
17
+ { id: 'prototype', outcome: 'ship one governed agent with evidence and rollback' },
18
+ { id: 'scale', outcome: 'publish reusable agent catalog and approval policies' },
19
+ { id: 'operate', outcome: 'review traces, ROI, incidents, and policy drift weekly' },
20
+ ],
21
+ governance: [
22
+ 'human oversight for high-stakes recommendations',
23
+ 'sovereign data boundary when required',
24
+ 'agent catalog with owner and allowed tools',
25
+ 'decision journal for every business-critical action',
26
+ 'measurable outcome before expansion',
27
+ ],
28
+ metrics: ['cycle_time_saved', 'blocked_risky_actions', 'approved_agent_runs', 'business_value_cents', 'incident_rate'],
29
+ };
30
+ }
31
+
32
+ module.exports = {
33
+ buildEnterpriseAgentRollout,
34
+ };
@@ -0,0 +1,69 @@
1
+ 'use strict';
2
+
3
+ function buildExperienceReplayPolicy(options = {}) {
4
+ const maxStalenessHours = Number.isFinite(options.maxStalenessHours) ? options.maxStalenessHours : 24;
5
+ const replayRatio = Number.isFinite(options.replayRatio) ? options.replayRatio : 0.25;
6
+ const minEntropy = Number.isFinite(options.minEntropy) ? options.minEntropy : 0.65;
7
+
8
+ return {
9
+ policyId: 'feedback_experience_replay',
10
+ purpose: 'Reuse high-signal feedback trajectories without letting stale lessons dominate training.',
11
+ buffer: {
12
+ strategy: 'fifo_with_quality_filters',
13
+ maxStalenessHours,
14
+ replayRatio,
15
+ sampleWithoutRemoval: true,
16
+ },
17
+ filters: [
18
+ 'redacted',
19
+ 'source_feedback_id_present',
20
+ 'outcome_evidence_present',
21
+ 'not_contradicted_by_newer_lesson',
22
+ 'not_low_confidence_or_vague_feedback',
23
+ ],
24
+ monitors: {
25
+ maxStalenessHours,
26
+ minEntropy,
27
+ compareAgainstFreshOnly: true,
28
+ metrics: ['gate_precision', 'gate_recall', 'unsupported_claim_rate', 'policy_entropy', 'compute_saved_percent'],
29
+ },
30
+ };
31
+ }
32
+
33
+ function evaluateReplayCandidate(candidate = {}, policy = buildExperienceReplayPolicy()) {
34
+ const issues = [];
35
+ if (!candidate.sourceFeedbackId) issues.push('missing_source_feedback_id');
36
+ if (!candidate.redacted) issues.push('redaction_required');
37
+ if (!candidate.outcomeEvidence) issues.push('missing_outcome_evidence');
38
+ if (candidate.contradictedByNewerLesson) issues.push('contradicted_by_newer_lesson');
39
+ if (candidate.vagueFeedback) issues.push('vague_feedback_not_replayable');
40
+
41
+ const ageHours = Number(candidate.ageHours || 0);
42
+ if (ageHours > policy.buffer.maxStalenessHours) issues.push('stale_replay_sample');
43
+
44
+ return {
45
+ decision: issues.length ? 'reject' : 'accept',
46
+ issues,
47
+ replayWeight: issues.length ? 0 : Math.min(policy.buffer.replayRatio, Number(candidate.qualityScore || 1)),
48
+ };
49
+ }
50
+
51
+ function evaluateReplayRun(run = {}, policy = buildExperienceReplayPolicy()) {
52
+ const issues = [];
53
+ if (Number(run.replayRatio || 0) > 0.5) issues.push('replay_ratio_too_high');
54
+ if (Number(run.policyEntropy || 0) < policy.monitors.minEntropy) issues.push('policy_entropy_too_low');
55
+ if (!run.freshOnlyBaseline) issues.push('missing_fresh_only_baseline');
56
+ if (!run.computeSavedPercent && run.computeSavedPercent !== 0) issues.push('missing_compute_saved_metric');
57
+
58
+ return {
59
+ decision: issues.length ? 'warn' : 'allow',
60
+ issues,
61
+ computeEfficient: Number(run.computeSavedPercent || 0) > 0 && Number(run.policyEntropy || 0) >= policy.monitors.minEntropy,
62
+ };
63
+ }
64
+
65
+ module.exports = {
66
+ buildExperienceReplayPolicy,
67
+ evaluateReplayCandidate,
68
+ evaluateReplayRun,
69
+ };
@@ -123,7 +123,7 @@ function buildPreferenceRow(pair, index) {
123
123
  function buildDatasetInfo({ traceCount, preferenceCount, exportedAt }) {
124
124
  return {
125
125
  dataset_info: {
126
- description: 'Agent traces and DPO preference pairs from ThumbGate — pre-action gates for AI coding agents. Contains real-world tool call feedback, failure patterns, and learned corrections.',
126
+ description: 'Agent traces and DPO preference pairs from ThumbGate — pre-action checks for AI coding agents. Contains real-world tool call feedback, failure patterns, and learned corrections.',
127
127
  citation: '',
128
128
  homepage: 'https://github.com/IgorGanapolsky/ThumbGate',
129
129
  license: 'MIT',