thumbgate 1.2.0 → 1.4.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 (160) hide show
  1. package/.claude-plugin/README.md +4 -4
  2. package/.claude-plugin/marketplace.json +32 -13
  3. package/.claude-plugin/plugin.json +15 -2
  4. package/.well-known/llms.txt +60 -0
  5. package/.well-known/mcp/server-card.json +1 -1
  6. package/README.md +133 -23
  7. package/adapters/README.md +1 -1
  8. package/adapters/chatgpt/openapi.yaml +168 -0
  9. package/adapters/claude/.mcp.json +2 -2
  10. package/adapters/codex/config.toml +2 -2
  11. package/adapters/mcp/server-stdio.js +85 -2
  12. package/adapters/opencode/opencode.json +1 -1
  13. package/bin/cli.js +215 -19
  14. package/bin/postinstall.js +8 -2
  15. package/config/budget.json +18 -0
  16. package/config/gates/code-edit.json +61 -0
  17. package/config/gates/db-write.json +61 -0
  18. package/config/gates/default.json +154 -3
  19. package/config/gates/deploy.json +61 -0
  20. package/config/github-about.json +2 -1
  21. package/config/merge-quality-checks.json +23 -0
  22. package/config/model-tiers.json +11 -0
  23. package/openapi/openapi.yaml +168 -0
  24. package/package.json +47 -13
  25. package/plugins/claude-codex-bridge/.claude-plugin/plugin.json +1 -1
  26. package/plugins/claude-codex-bridge/.mcp.json +1 -1
  27. package/plugins/claude-codex-bridge/scripts/codex-bridge.js +1 -3
  28. package/plugins/codex-profile/.codex-plugin/plugin.json +1 -1
  29. package/plugins/codex-profile/.mcp.json +1 -1
  30. package/plugins/codex-profile/INSTALL.md +27 -4
  31. package/plugins/codex-profile/README.md +33 -9
  32. package/plugins/cursor-marketplace/.cursor-plugin/plugin.json +1 -1
  33. package/plugins/cursor-marketplace/README.md +2 -2
  34. package/plugins/cursor-marketplace/commands/capture-feedback.md +2 -2
  35. package/plugins/cursor-marketplace/rules/feedback-capture.mdc +3 -3
  36. package/plugins/cursor-marketplace/skills/capture-feedback/SKILL.md +3 -2
  37. package/plugins/opencode-profile/INSTALL.md +1 -1
  38. package/public/blog.html +73 -0
  39. package/public/compare/mem0.html +189 -0
  40. package/public/compare/speclock.html +180 -0
  41. package/public/compare.html +12 -4
  42. package/public/guide.html +5 -5
  43. package/public/guides/claude-code-prevent-repeated-mistakes.html +161 -0
  44. package/public/guides/codex-cli-guardrails.html +158 -0
  45. package/public/guides/cursor-prevent-repeated-mistakes.html +161 -0
  46. package/public/guides/pre-action-gates.html +162 -0
  47. package/public/guides/stop-repeated-ai-agent-mistakes.html +159 -0
  48. package/public/index.html +169 -70
  49. package/public/learn/ai-agent-persistent-memory.html +1 -0
  50. package/public/lessons.html +334 -17
  51. package/public/llm-context.md +140 -0
  52. package/public/pro.html +24 -22
  53. package/scripts/__pycache__/train_from_feedback.cpython-312.pyc +0 -0
  54. package/scripts/access-anomaly-detector.js +1 -1
  55. package/scripts/adk-consolidator.js +1 -5
  56. package/scripts/agent-security-hardening.js +4 -6
  57. package/scripts/agentic-data-pipeline.js +1 -3
  58. package/scripts/async-job-runner.js +1 -5
  59. package/scripts/audit-trail.js +7 -5
  60. package/scripts/background-agent-governance.js +2 -10
  61. package/scripts/billing.js +2 -16
  62. package/scripts/budget-enforcer.js +173 -0
  63. package/scripts/build-codex-plugin.js +152 -0
  64. package/scripts/capture-railway-diagnostics.sh +97 -0
  65. package/scripts/check-congruence.js +133 -15
  66. package/scripts/claude-feedback-sync.js +320 -0
  67. package/scripts/cli-telemetry.js +4 -1
  68. package/scripts/commercial-offer.js +5 -7
  69. package/scripts/content-engine/linkedin-content-generator.js +154 -0
  70. package/scripts/content-engine/output/linkedin-memento-validation.md +17 -0
  71. package/scripts/content-engine/output/linkedin-posts-2026-04-09.md +175 -0
  72. package/scripts/content-engine/reddit-thread-finder.js +154 -0
  73. package/scripts/context-engine.js +21 -6
  74. package/scripts/contextfs.js +33 -44
  75. package/scripts/dashboard.js +104 -0
  76. package/scripts/decision-journal.js +341 -0
  77. package/scripts/delegation-runtime.js +1 -5
  78. package/scripts/distribution-surfaces.js +26 -0
  79. package/scripts/document-intake.js +927 -0
  80. package/scripts/ephemeral-agent-store.js +1 -8
  81. package/scripts/evolution-state.js +1 -5
  82. package/scripts/experiment-tracker.js +1 -5
  83. package/scripts/export-databricks-bundle.js +1 -5
  84. package/scripts/export-hf-dataset.js +1 -5
  85. package/scripts/export-training.js +1 -5
  86. package/scripts/feedback-attribution.js +1 -16
  87. package/scripts/feedback-history-distiller.js +1 -16
  88. package/scripts/feedback-loop.js +17 -5
  89. package/scripts/feedback-root-consolidator.js +2 -21
  90. package/scripts/feedback-session.js +49 -0
  91. package/scripts/feedback-to-rules.js +188 -28
  92. package/scripts/filesystem-search.js +1 -9
  93. package/scripts/fs-utils.js +104 -0
  94. package/scripts/gates-engine.js +149 -4
  95. package/scripts/github-about.js +32 -8
  96. package/scripts/gtm-revenue-loop.js +1 -5
  97. package/scripts/harness-selector.js +148 -0
  98. package/scripts/hosted-job-launcher.js +1 -5
  99. package/scripts/hybrid-feedback-context.js +7 -33
  100. package/scripts/intervention-policy.js +753 -0
  101. package/scripts/lesson-db.js +3 -18
  102. package/scripts/lesson-inference.js +194 -16
  103. package/scripts/lesson-retrieval.js +60 -24
  104. package/scripts/llm-client.js +59 -0
  105. package/scripts/local-model-profile.js +18 -2
  106. package/scripts/managed-lesson-agent.js +183 -0
  107. package/scripts/marketing-experiment.js +8 -22
  108. package/scripts/meta-agent-loop.js +624 -0
  109. package/scripts/metered-billing.js +1 -1
  110. package/scripts/model-tier-router.js +10 -1
  111. package/scripts/money-watcher.js +1 -4
  112. package/scripts/obsidian-export.js +1 -5
  113. package/scripts/operational-integrity.js +369 -34
  114. package/scripts/org-dashboard.js +6 -1
  115. package/scripts/per-step-scoring.js +2 -4
  116. package/scripts/pr-manager.js +201 -19
  117. package/scripts/pro-features.js +3 -2
  118. package/scripts/prompt-dlp.js +3 -3
  119. package/scripts/prove-adapters.js +2 -5
  120. package/scripts/prove-attribution.js +1 -5
  121. package/scripts/prove-automation.js +3 -5
  122. package/scripts/prove-cloudflare-sandbox.js +1 -3
  123. package/scripts/prove-data-pipeline.js +1 -3
  124. package/scripts/prove-intelligence.js +1 -3
  125. package/scripts/prove-lancedb.js +1 -5
  126. package/scripts/prove-local-intelligence.js +1 -3
  127. package/scripts/prove-packaged-runtime.js +326 -0
  128. package/scripts/prove-predictive-insights.js +1 -3
  129. package/scripts/prove-runtime.js +13 -0
  130. package/scripts/prove-training-export.js +1 -3
  131. package/scripts/prove-workflow-contract.js +1 -5
  132. package/scripts/rate-limiter.js +6 -4
  133. package/scripts/reddit-dm-outreach.js +14 -4
  134. package/scripts/schedule-manager.js +3 -5
  135. package/scripts/security-scanner.js +448 -0
  136. package/scripts/self-distill-agent.js +579 -0
  137. package/scripts/semantic-dedup.js +115 -0
  138. package/scripts/skill-exporter.js +1 -3
  139. package/scripts/skill-generator.js +1 -5
  140. package/scripts/social-analytics/engagement-audit.js +1 -18
  141. package/scripts/social-analytics/pollers/linkedin.js +26 -16
  142. package/scripts/social-analytics/publishers/linkedin.js +1 -1
  143. package/scripts/social-analytics/publishers/zernio.js +51 -0
  144. package/scripts/social-pipeline.js +1 -3
  145. package/scripts/social-post-hourly.js +47 -4
  146. package/scripts/statusline-links.js +6 -5
  147. package/scripts/statusline-local-stats.js +2 -0
  148. package/scripts/statusline.sh +38 -7
  149. package/scripts/sync-branch-protection.js +340 -0
  150. package/scripts/tessl-export.js +1 -3
  151. package/scripts/thumbgate-search.js +32 -1
  152. package/scripts/tool-kpi-tracker.js +1 -1
  153. package/scripts/tool-registry.js +108 -4
  154. package/scripts/vector-store.js +1 -5
  155. package/scripts/weekly-auto-post.js +1 -1
  156. package/scripts/workflow-sentinel.js +205 -4
  157. package/skills/thumbgate/SKILL.md +2 -2
  158. package/src/api/server.js +273 -4
  159. package/scripts/social-analytics/db/social-analytics.db-shm +0 -0
  160. /package/scripts/social-analytics/db/{social-analytics.db-wal → analytics.sqlite} +0 -0
@@ -16,6 +16,7 @@ const {
16
16
  } = require('./operational-integrity');
17
17
  const { buildDockerSandboxPlan } = require('./docker-sandbox-planner');
18
18
  const { evaluatePretool } = require('./hybrid-feedback-context');
19
+ const { getInterventionRecommendation } = require('./intervention-policy');
19
20
 
20
21
  const GOVERNANCE_STATE_PATH = path.join(process.env.HOME || '/tmp', '.thumbgate', 'governance-state.json');
21
22
  const DEFAULT_PROTECTED_FILE_GLOBS = [
@@ -387,6 +388,7 @@ function scoreRisk({
387
388
  affectedFiles,
388
389
  integrity,
389
390
  memoryGuard,
391
+ learnedPolicy,
390
392
  blastRadius,
391
393
  taskScopeViolation,
392
394
  protectedSurface,
@@ -472,6 +474,43 @@ function scoreRisk({
472
474
  { mode: memoryGuard.mode }
473
475
  );
474
476
  }
477
+ if (learnedPolicy && learnedPolicy.enabled && learnedPolicy.prediction) {
478
+ const confidence = learnedPolicy.prediction.confidence || 0;
479
+ const label = learnedPolicy.prediction.label;
480
+ if (label === 'deny' && confidence >= 0.6) {
481
+ addDriver(
482
+ drivers,
483
+ 'learned_policy_deny',
484
+ Math.min(0.26, 0.16 + (confidence * 0.12)),
485
+ 'Learned intervention policy predicts a deny-worthy failure pattern.',
486
+ { confidence, label }
487
+ );
488
+ } else if (label === 'warn' && confidence >= 0.3) {
489
+ addDriver(
490
+ drivers,
491
+ 'learned_policy_warn',
492
+ Math.min(0.18, 0.1 + (confidence * 0.08)),
493
+ 'Learned intervention policy predicts elevated execution risk.',
494
+ { confidence, label }
495
+ );
496
+ } else if (label === 'verify' && confidence >= 0.3) {
497
+ addDriver(
498
+ drivers,
499
+ 'learned_policy_verify',
500
+ Math.min(0.16, 0.08 + (confidence * 0.06)),
501
+ 'Learned intervention policy predicts a verification gap before close-out.',
502
+ { confidence, label }
503
+ );
504
+ } else if (label === 'recall' && confidence >= 0.3) {
505
+ addDriver(
506
+ drivers,
507
+ 'learned_policy_recall',
508
+ Math.min(0.14, 0.06 + (confidence * 0.05)),
509
+ 'Learned intervention policy predicts prior lessons are needed before execution.',
510
+ { confidence, label }
511
+ );
512
+ }
513
+ }
475
514
 
476
515
  const score = Math.min(1, drivers.reduce((sum, driver) => sum + driver.weight, 0));
477
516
  return {
@@ -492,6 +531,7 @@ function scoreRisk({
492
531
  function buildEvidence({
493
532
  integrity,
494
533
  memoryGuard,
534
+ learnedPolicy,
495
535
  blastRadius,
496
536
  taskScopeViolation,
497
537
  protectedSurface,
@@ -500,6 +540,16 @@ function buildEvidence({
500
540
  if (memoryGuard && memoryGuard.mode && memoryGuard.mode !== 'allow') {
501
541
  evidence.push(`Memory guard predicted ${memoryGuard.mode}: ${memoryGuard.reason}`);
502
542
  }
543
+ if (learnedPolicy && learnedPolicy.enabled && learnedPolicy.prediction) {
544
+ const topTokens = Array.isArray(learnedPolicy.topTokens)
545
+ ? learnedPolicy.topTokens.map((entry) => entry.token).slice(0, 3)
546
+ : [];
547
+ evidence.push(
548
+ `Learned policy predicted ${learnedPolicy.prediction.label} (${Math.round((learnedPolicy.prediction.confidence || 0) * 100)}% confidence)`
549
+ + (topTokens.length ? ` from ${topTokens.join(', ')}` : '')
550
+ + '.'
551
+ );
552
+ }
503
553
  if (taskScopeViolation) {
504
554
  evidence.push(
505
555
  taskScopeViolation.reasonCode === 'missing_task_scope'
@@ -575,6 +625,7 @@ function buildRemediations({
575
625
  protectedSurface,
576
626
  blastRadius,
577
627
  memoryGuard,
628
+ learnedPolicy,
578
629
  executionSurface,
579
630
  }) {
580
631
  const remediations = [];
@@ -611,6 +662,24 @@ function buildRemediations({
611
662
  'The system already has evidence that this action pattern failed before.'
612
663
  );
613
664
  }
665
+ if (learnedPolicy && learnedPolicy.enabled && learnedPolicy.prediction) {
666
+ if (learnedPolicy.prediction.label === 'verify' && learnedPolicy.prediction.confidence >= 0.3) {
667
+ push(
668
+ 'verify_before_closeout',
669
+ 'Raise verification before claiming success',
670
+ 'Run the relevant proof or test command and confirm the exact output before retrying or closing out.',
671
+ 'The learned policy predicts this path tends to fail at verification time.'
672
+ );
673
+ }
674
+ if (learnedPolicy.prediction.label === 'recall' && learnedPolicy.prediction.confidence >= 0.3) {
675
+ push(
676
+ 'retrieve_lessons',
677
+ 'Inspect prior lessons',
678
+ 'Call retrieve_lessons or search_lessons for this tool context before retrying.',
679
+ 'The learned policy predicts this action needs prior lessons and corrective context.'
680
+ );
681
+ }
682
+ }
614
683
  if (blastRadius.fileCount >= 4 || blastRadius.surfaceCount >= 3) {
615
684
  push(
616
685
  'split_blast_radius',
@@ -636,6 +705,16 @@ function buildReasoning(report) {
636
705
  `Workflow sentinel risk ${report.band} (${report.riskScore}) for ${report.toolName}.`,
637
706
  `Blast radius: ${report.blastRadius.summary}.`,
638
707
  ];
708
+ if (report.decisionControl) {
709
+ lines.push(
710
+ `Decision control: ${report.decisionControl.decisionOwner} owns a ${report.decisionControl.reversibility} action via ${report.decisionControl.executionMode}.`
711
+ );
712
+ }
713
+ if (report.learnedPolicy && report.learnedPolicy.enabled && report.learnedPolicy.prediction) {
714
+ lines.push(
715
+ `Learned policy predicted ${report.learnedPolicy.prediction.label} (${report.learnedPolicy.prediction.confidence}).`
716
+ );
717
+ }
639
718
  if (report.executionSurface?.shouldSandbox) {
640
719
  lines.push(`Execution surface: ${report.executionSurface.summary}`);
641
720
  }
@@ -658,15 +737,106 @@ function getSentinelActionType(toolName) {
658
737
  return '';
659
738
  }
660
739
 
661
- function chooseDecision({ riskScore, integrity, memoryGuard, blastRadius, command }) {
740
+ function classifyReversibility({ command, blastRadius, integrity, protectedSurface }) {
741
+ const text = String(command || '');
742
+ const blockers = integrity && Array.isArray(integrity.blockers) ? integrity.blockers : [];
743
+ const destructiveCommand = /\bgit\s+push\b.*(?:--force|-f)\b/i.test(text)
744
+ || /\bgh\s+pr\s+merge\b.*--admin\b/i.test(text)
745
+ || /\brm\s+-rf\b/i.test(text)
746
+ || /\b(?:npm|yarn|pnpm)\s+publish\b/i.test(text)
747
+ || /\bgh\s+release\s+create\b/i.test(text)
748
+ || /\bgit\s+tag\b/i.test(text);
749
+ const releaseSensitive = blastRadius && Array.isArray(blastRadius.releaseSensitiveFiles)
750
+ ? blastRadius.releaseSensitiveFiles.length > 0
751
+ : false;
752
+ const unapprovedProtected = protectedSurface && Array.isArray(protectedSurface.unapprovedProtectedFiles)
753
+ ? protectedSurface.unapprovedProtectedFiles.length > 0
754
+ : false;
755
+ const hardBlockers = blockers.some((blocker) => /publish|merge|release|protected/i.test(String(blocker.code || '')));
756
+
757
+ if (destructiveCommand || releaseSensitive || unapprovedProtected || hardBlockers) {
758
+ return 'one_way_door';
759
+ }
760
+ if ((blastRadius && blastRadius.fileCount >= 4) || (blastRadius && blastRadius.surfaceCount >= 2)) {
761
+ return 'reviewable';
762
+ }
763
+ return 'two_way_door';
764
+ }
765
+
766
+ function buildDecisionControl({
767
+ decision,
768
+ risk,
769
+ command,
770
+ blastRadius,
771
+ integrity,
772
+ protectedSurface,
773
+ }) {
774
+ const reversibility = classifyReversibility({
775
+ command,
776
+ blastRadius,
777
+ integrity,
778
+ protectedSurface,
779
+ });
780
+ const hasOperationalBlockers = Boolean(integrity && Array.isArray(integrity.blockers) && integrity.blockers.length > 0);
781
+ const requiresCheckpoint = decision === 'warn'
782
+ || (decision === 'allow' && (reversibility !== 'two_way_door' || hasOperationalBlockers));
783
+ const executionMode = decision === 'deny'
784
+ ? 'blocked'
785
+ : requiresCheckpoint
786
+ ? 'checkpoint_required'
787
+ : 'auto_execute';
788
+ const decisionOwner = executionMode === 'blocked'
789
+ ? 'human'
790
+ : executionMode === 'checkpoint_required'
791
+ ? reversibility === 'two_way_door' && !hasOperationalBlockers
792
+ ? 'shared'
793
+ : 'human'
794
+ : 'agent';
795
+
796
+ return {
797
+ executionMode,
798
+ decisionOwner,
799
+ reversibility,
800
+ requiresHumanApproval: executionMode === 'checkpoint_required' && decisionOwner !== 'agent',
801
+ recommendedAction: executionMode === 'blocked'
802
+ ? 'halt'
803
+ : executionMode === 'checkpoint_required'
804
+ ? 'review'
805
+ : 'proceed',
806
+ summary: executionMode === 'blocked'
807
+ ? 'Do not proceed until the remediation steps are completed.'
808
+ : executionMode === 'checkpoint_required'
809
+ ? 'Pause for explicit review before executing this action.'
810
+ : 'Safe to execute quickly with standard evidence capture.',
811
+ };
812
+ }
813
+
814
+ function chooseDecision({ riskScore, integrity, memoryGuard, learnedPolicy, blastRadius, command }) {
662
815
  const hasOperationalBlockers = Boolean(integrity && Array.isArray(integrity.blockers) && integrity.blockers.length > 0);
663
816
  const destructiveBypass = /\bgit\s+push\b.*(?:--force|-f)\b/i.test(command) || /\bgh\s+pr\s+merge\b.*--admin\b/i.test(command);
817
+ const learnedPrediction = learnedPolicy && learnedPolicy.enabled ? learnedPolicy.prediction : null;
818
+ const learnedHardStop = Boolean(
819
+ learnedPrediction
820
+ && learnedPrediction.label === 'deny'
821
+ && learnedPrediction.confidence >= 0.7
822
+ );
823
+ const learnedWarning = Boolean(
824
+ learnedPrediction
825
+ && ['warn', 'verify', 'deny'].includes(learnedPrediction.label)
826
+ && learnedPrediction.confidence >= 0.3
827
+ );
828
+ const learnedRecall = Boolean(
829
+ learnedPrediction
830
+ && learnedPrediction.label === 'recall'
831
+ && learnedPrediction.confidence >= 0.3
832
+ );
664
833
  const lowBlastRadius = blastRadius.fileCount <= 1
665
834
  && blastRadius.surfaceCount <= 1
666
835
  && blastRadius.releaseSensitiveFiles.length === 0
667
836
  && blastRadius.unapprovedProtectedFiles === 0;
668
837
  const lowRiskHandoff = /\bgit\s+push\b|\bgh\s+pr\s+(?:create|merge)\b/i.test(command)
669
838
  && !destructiveBypass
839
+ && !learnedHardStop
670
840
  && lowBlastRadius
671
841
  && !hasOperationalBlockers
672
842
  && memoryGuard
@@ -686,10 +856,10 @@ function chooseDecision({ riskScore, integrity, memoryGuard, blastRadius, comman
686
856
  if (lowRiskHandoff) {
687
857
  return 'allow';
688
858
  }
689
- if (destructiveBypass || repeatedHighBlast || (hasOperationalBlockers && riskScore >= 0.72) || riskScore >= 0.86) {
859
+ if (destructiveBypass || learnedHardStop || repeatedHighBlast || (hasOperationalBlockers && riskScore >= 0.72) || riskScore >= 0.86) {
690
860
  return 'deny';
691
861
  }
692
- if (riskScore >= 0.45) {
862
+ if (riskScore >= 0.45 || (learnedWarning && riskScore >= 0.3) || (learnedRecall && riskScore >= 0.34)) {
693
863
  return 'warn';
694
864
  }
695
865
  return 'allow';
@@ -732,6 +902,20 @@ function evaluateWorkflowSentinel(toolName, toolInput = {}, options = {}) {
732
902
  affectedFiles,
733
903
  }), options.feedbackOptions || {});
734
904
  const memoryGuard = normalizeMemoryGuardForSentinel(rawMemoryGuard, highRiskAction);
905
+ const learnedPolicy = getInterventionRecommendation({
906
+ toolName,
907
+ command: toolInput.command || '',
908
+ affectedFiles,
909
+ integrity,
910
+ memoryGuard,
911
+ riskBand: highRiskAction ? 'high' : 'low',
912
+ taskScopeViolation,
913
+ protectedSurface: protectedSurfaceForRisk,
914
+ }, {
915
+ feedbackDir: options.feedbackDir
916
+ || process.env.THUMBGATE_FEEDBACK_DIR
917
+ || (repoRoot ? path.join(repoRoot, '.thumbgate') : null),
918
+ });
735
919
  const blastRadius = buildBlastRadius({
736
920
  affectedFiles,
737
921
  integrity,
@@ -743,6 +927,7 @@ function evaluateWorkflowSentinel(toolName, toolInput = {}, options = {}) {
743
927
  affectedFiles,
744
928
  integrity,
745
929
  memoryGuard,
930
+ learnedPolicy,
746
931
  blastRadius,
747
932
  taskScopeViolation,
748
933
  protectedSurface: protectedSurfaceForRisk,
@@ -763,6 +948,7 @@ function evaluateWorkflowSentinel(toolName, toolInput = {}, options = {}) {
763
948
  riskScore: risk.score,
764
949
  integrity,
765
950
  memoryGuard,
951
+ learnedPolicy,
766
952
  blastRadius: {
767
953
  ...blastRadius,
768
954
  unapprovedProtectedFiles: protectedSurfaceForRisk.unapprovedProtectedFiles.length,
@@ -772,6 +958,7 @@ function evaluateWorkflowSentinel(toolName, toolInput = {}, options = {}) {
772
958
  const evidence = buildEvidence({
773
959
  integrity,
774
960
  memoryGuard,
961
+ learnedPolicy,
775
962
  blastRadius,
776
963
  taskScopeViolation,
777
964
  protectedSurface: protectedSurfaceForRisk,
@@ -782,6 +969,7 @@ function evaluateWorkflowSentinel(toolName, toolInput = {}, options = {}) {
782
969
  protectedSurface: protectedSurfaceForRisk,
783
970
  blastRadius,
784
971
  memoryGuard,
972
+ learnedPolicy,
785
973
  executionSurface,
786
974
  });
787
975
  const summary = decision === 'allow'
@@ -790,7 +978,7 @@ function evaluateWorkflowSentinel(toolName, toolInput = {}, options = {}) {
790
978
  ? 'Predicted workflow risk is elevated before execution.'
791
979
  : 'Predicted workflow failure before execution.';
792
980
  const report = {
793
- sentinelVersion: 'workflow-sentinel-v1',
981
+ sentinelVersion: 'workflow-sentinel-v2',
794
982
  toolName,
795
983
  decision,
796
984
  riskScore: risk.score,
@@ -802,6 +990,7 @@ function evaluateWorkflowSentinel(toolName, toolInput = {}, options = {}) {
802
990
  remediations,
803
991
  executionSurface,
804
992
  memoryGuard,
993
+ learnedPolicy,
805
994
  taskScopeViolation,
806
995
  operationalIntegrity: {
807
996
  ok: integrity.ok,
@@ -813,11 +1002,23 @@ function evaluateWorkflowSentinel(toolName, toolInput = {}, options = {}) {
813
1002
  commandInfo: integrity.commandInfo,
814
1003
  },
815
1004
  };
1005
+ report.decisionControl = buildDecisionControl({
1006
+ decision,
1007
+ risk,
1008
+ command: toolInput.command || '',
1009
+ blastRadius: {
1010
+ ...blastRadius,
1011
+ unapprovedProtectedFiles: protectedSurfaceForRisk.unapprovedProtectedFiles.length,
1012
+ },
1013
+ integrity,
1014
+ protectedSurface: protectedSurfaceForRisk,
1015
+ });
816
1016
  report.reasoning = buildReasoning(report);
817
1017
  return report;
818
1018
  }
819
1019
 
820
1020
  module.exports = {
1021
+ buildDecisionControl,
821
1022
  DEFAULT_PROTECTED_FILE_GLOBS,
822
1023
  buildBlastRadius,
823
1024
  buildEvidence,
@@ -86,13 +86,13 @@ Bounded retrieval of relevant feedback history for the current task. The agent g
86
86
 
87
87
  | | Free | Pro | Team |
88
88
  |---|---|---|---|
89
- | Feedback capture | Unlimited | Unlimited | Unlimited |
89
+ | Feedback capture | 3/day | Unlimited | Unlimited |
90
90
  | Lesson search | 5/day | Unlimited | Unlimited |
91
91
  | Active gates | 5 | Unlimited | Unlimited |
92
92
  | Dashboard | - | Yes | Yes |
93
93
  | DPO export | - | Yes | Yes |
94
94
  | Seats | 1 | 1 | Per-seat |
95
- | Price | $0 | $19/mo | $12/seat/mo |
95
+ | Price | $0 | $19/mo | $99/seat/mo |
96
96
 
97
97
  Start a 7-day free trial of Pro: <https://buy.stripe.com/fZu9AT3Ug6zcdWh0XN3sI08>
98
98