pumuki-ast-hooks 5.6.10 → 5.6.12

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 (28) hide show
  1. package/assets/Hook_01.png +0 -0
  2. package/assets/Hook_02.png +0 -0
  3. package/assets/ai-start.png +0 -0
  4. package/assets/ai_gate.png +0 -0
  5. package/assets/ast_intelligence_01.png +0 -0
  6. package/assets/ast_intelligence_01.svg +40 -0
  7. package/assets/ast_intelligence_02.png +0 -0
  8. package/assets/ast_intelligence_02.svg +39 -0
  9. package/assets/ast_intelligence_03.png +0 -0
  10. package/assets/ast_intelligence_03.svg +55 -0
  11. package/assets/ast_intelligence_04.png +0 -0
  12. package/assets/ast_intelligence_04.svg +39 -0
  13. package/assets/ast_intelligence_05.png +0 -0
  14. package/assets/ast_intelligence_05.svg +45 -0
  15. package/assets/logo.png +0 -0
  16. package/assets/logo_banner.svg +29 -0
  17. package/assets/pre-flight-check.png +0 -0
  18. package/package.json +2 -1
  19. package/scripts/hooks-system/.audit-reports/auto-recovery.log +1 -0
  20. package/scripts/hooks-system/.audit-reports/install-wizard.log +4 -0
  21. package/scripts/hooks-system/.audit_tmp/hook-metrics.jsonl +32 -0
  22. package/scripts/hooks-system/application/services/installation/VSCodeTaskConfigurator.js +5 -19
  23. package/scripts/hooks-system/application/services/installation/__tests__/VSCodeTaskConfigurator.spec.js +38 -0
  24. package/scripts/hooks-system/bin/__tests__/session-loader.spec.js +14 -0
  25. package/scripts/hooks-system/bin/session-loader.sh +3 -1
  26. package/scripts/hooks-system/infrastructure/ast/common/__tests__/ast-common.spec.js +30 -0
  27. package/scripts/hooks-system/infrastructure/ast/common/ast-common.js +12 -1
  28. package/scripts/hooks-system/infrastructure/watchdog/__tests__/.audit-reports/token-monitor.log +3 -0
Binary file
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pumuki-ast-hooks",
3
- "version": "5.6.10",
3
+ "version": "5.6.12",
4
4
  "description": "Enterprise-grade AST Intelligence System with multi-platform support (iOS, Android, Backend, Frontend) and Feature-First + DDD + Clean Architecture enforcement. Includes dynamic violations API for intelligent querying.",
5
5
  "main": "index.js",
6
6
  "bin": {
@@ -116,6 +116,7 @@
116
116
  "skills/",
117
117
  "hooks/",
118
118
  "docs/",
119
+ "assets/",
119
120
  "index.js",
120
121
  "README.md",
121
122
  "LICENSE"
@@ -8,3 +8,4 @@
8
8
  {"timestamp":"2026-01-11T18:44:21.682Z","level":"info","component":"AutoRecovery","event":"NotificationCenterService shutdown","data":{"totalEnqueued":0,"totalSent":0,"totalDeduplicated":0,"totalCooldownSkipped":0,"totalFailed":0,"totalRetries":0,"queueSize":0,"deduplication":{"size":0},"cooldowns":{"activeCooldowns":0}},"context":{}}
9
9
  {"timestamp":"2026-01-11T18:48:20.329Z","level":"info","component":"AutoRecovery","event":"NotificationCenterService shutdown","data":{"totalEnqueued":0,"totalSent":0,"totalDeduplicated":0,"totalCooldownSkipped":0,"totalFailed":0,"totalRetries":0,"queueSize":0,"deduplication":{"size":0},"cooldowns":{"activeCooldowns":0}},"context":{}}
10
10
  {"timestamp":"2026-01-11T18:54:50.282Z","level":"info","component":"AutoRecovery","event":"NotificationCenterService shutdown","data":{"totalEnqueued":0,"totalSent":0,"totalDeduplicated":0,"totalCooldownSkipped":0,"totalFailed":0,"totalRetries":0,"queueSize":0,"deduplication":{"size":0},"cooldowns":{"activeCooldowns":0}},"context":{}}
11
+ {"timestamp":"2026-01-11T19:08:34.232Z","level":"info","component":"AutoRecovery","event":"NotificationCenterService shutdown","data":{"totalEnqueued":0,"totalSent":0,"totalDeduplicated":0,"totalCooldownSkipped":0,"totalFailed":0,"totalRetries":0,"queueSize":0,"deduplication":{"size":0},"cooldowns":{"activeCooldowns":0}},"context":{}}
@@ -38,3 +38,7 @@
38
38
  {"timestamp":"2026-01-11T18:54:50.515Z","level":"info","component":"InstallWizard","event":"INSTALL_WIZARD_CONFIG_EXISTS","data":{"configPath":"/Users/juancarlosmerlosalbarracin/Developer/Projects/ast-intelligence-hooks/scripts/hooks-system/.hook-system/config.json"},"context":{}}
39
39
  {"timestamp":"2026-01-11T18:54:50.515Z","level":"error","component":"InstallWizard","event":"INSTALL_WIZARD_SYMLINK_FAILED","data":{"error":"EEXIST: file already exists, symlink '/Users/juancarlosmerlosalbarracin/Developer/Projects/ast-intelligence-hooks/scripts/hooks-system/scripts/hooks-system/bin/guard-supervisor.js' -> '/Users/juancarlosmerlosalbarracin/Developer/Projects/ast-intelligence-hooks/scripts/hooks-system/.git/hooks/guard-supervisor'"},"context":{}}
40
40
  {"timestamp":"2026-01-11T18:54:50.515Z","level":"info","component":"InstallWizard","event":"INSTALL_WIZARD_COMPLETED","data":{},"context":{}}
41
+ {"timestamp":"2026-01-11T19:08:34.068Z","level":"info","component":"InstallWizard","event":"INSTALL_WIZARD_START","data":{"repoRoot":"/Users/juancarlosmerlosalbarracin/Developer/Projects/ast-intelligence-hooks/scripts/hooks-system"},"context":{}}
42
+ {"timestamp":"2026-01-11T19:08:34.083Z","level":"info","component":"InstallWizard","event":"INSTALL_WIZARD_CONFIG_EXISTS","data":{"configPath":"/Users/juancarlosmerlosalbarracin/Developer/Projects/ast-intelligence-hooks/scripts/hooks-system/.hook-system/config.json"},"context":{}}
43
+ {"timestamp":"2026-01-11T19:08:34.083Z","level":"error","component":"InstallWizard","event":"INSTALL_WIZARD_SYMLINK_FAILED","data":{"error":"EEXIST: file already exists, symlink '/Users/juancarlosmerlosalbarracin/Developer/Projects/ast-intelligence-hooks/scripts/hooks-system/scripts/hooks-system/bin/guard-supervisor.js' -> '/Users/juancarlosmerlosalbarracin/Developer/Projects/ast-intelligence-hooks/scripts/hooks-system/.git/hooks/guard-supervisor'"},"context":{}}
44
+ {"timestamp":"2026-01-11T19:08:34.083Z","level":"info","component":"InstallWizard","event":"INSTALL_WIZARD_COMPLETED","data":{},"context":{}}
@@ -470,3 +470,35 @@
470
470
  {"timestamp":1768157690281,"hook":"audit_logger","operation":"ensure_dir","status":"started"}
471
471
  {"timestamp":1768157690281,"hook":"audit_logger","operation":"ensure_dir","status":"success"}
472
472
  {"timestamp":1768157690281,"hook":"audit_logger","operation":"constructor","status":"success","repoRoot":"/Users/juancarlosmerlosalbarracin/Developer/Projects/ast-intelligence-hooks/scripts/hooks-system"}
473
+ {"timestamp":1768157973980,"hook":"audit_logger","operation":"constructor","status":"started","repoRoot":"/Users/juancarlosmerlosalbarracin/Developer/Projects/ast-intelligence-hooks/scripts/hooks-system"}
474
+ {"timestamp":1768157973980,"hook":"audit_logger","operation":"ensure_dir","status":"started"}
475
+ {"timestamp":1768157973980,"hook":"audit_logger","operation":"ensure_dir","status":"success"}
476
+ {"timestamp":1768157973980,"hook":"audit_logger","operation":"constructor","status":"success","repoRoot":"/Users/juancarlosmerlosalbarracin/Developer/Projects/ast-intelligence-hooks/scripts/hooks-system"}
477
+ {"timestamp":1768158514228,"hook":"audit_logger","operation":"constructor","status":"started","repoRoot":"/Users/juancarlosmerlosalbarracin/Developer/Projects/ast-intelligence-hooks/scripts/hooks-system"}
478
+ {"timestamp":1768158514229,"hook":"audit_logger","operation":"ensure_dir","status":"started"}
479
+ {"timestamp":1768158514229,"hook":"audit_logger","operation":"ensure_dir","status":"success"}
480
+ {"timestamp":1768158514229,"hook":"audit_logger","operation":"constructor","status":"success","repoRoot":"/Users/juancarlosmerlosalbarracin/Developer/Projects/ast-intelligence-hooks/scripts/hooks-system"}
481
+ {"timestamp":1768158514229,"hook":"audit_logger","operation":"constructor","status":"started","repoRoot":"/Users/juancarlosmerlosalbarracin/Developer/Projects/ast-intelligence-hooks/scripts/hooks-system"}
482
+ {"timestamp":1768158514229,"hook":"audit_logger","operation":"ensure_dir","status":"started"}
483
+ {"timestamp":1768158514229,"hook":"audit_logger","operation":"ensure_dir","status":"success"}
484
+ {"timestamp":1768158514229,"hook":"audit_logger","operation":"constructor","status":"success","repoRoot":"/Users/juancarlosmerlosalbarracin/Developer/Projects/ast-intelligence-hooks/scripts/hooks-system"}
485
+ {"timestamp":1768158514230,"hook":"audit_logger","operation":"constructor","status":"started","repoRoot":"/Users/juancarlosmerlosalbarracin/Developer/Projects/ast-intelligence-hooks/scripts/hooks-system"}
486
+ {"timestamp":1768158514230,"hook":"audit_logger","operation":"ensure_dir","status":"started"}
487
+ {"timestamp":1768158514230,"hook":"audit_logger","operation":"ensure_dir","status":"success"}
488
+ {"timestamp":1768158514230,"hook":"audit_logger","operation":"constructor","status":"success","repoRoot":"/Users/juancarlosmerlosalbarracin/Developer/Projects/ast-intelligence-hooks/scripts/hooks-system"}
489
+ {"timestamp":1768158514230,"hook":"audit_logger","operation":"constructor","status":"started","repoRoot":"/Users/juancarlosmerlosalbarracin/Developer/Projects/ast-intelligence-hooks/scripts/hooks-system"}
490
+ {"timestamp":1768158514230,"hook":"audit_logger","operation":"ensure_dir","status":"started"}
491
+ {"timestamp":1768158514230,"hook":"audit_logger","operation":"ensure_dir","status":"success"}
492
+ {"timestamp":1768158514230,"hook":"audit_logger","operation":"constructor","status":"success","repoRoot":"/Users/juancarlosmerlosalbarracin/Developer/Projects/ast-intelligence-hooks/scripts/hooks-system"}
493
+ {"timestamp":1768158514230,"hook":"audit_logger","operation":"constructor","status":"started","repoRoot":"/Users/juancarlosmerlosalbarracin/Developer/Projects/ast-intelligence-hooks/scripts/hooks-system"}
494
+ {"timestamp":1768158514230,"hook":"audit_logger","operation":"ensure_dir","status":"started"}
495
+ {"timestamp":1768158514231,"hook":"audit_logger","operation":"ensure_dir","status":"success"}
496
+ {"timestamp":1768158514231,"hook":"audit_logger","operation":"constructor","status":"success","repoRoot":"/Users/juancarlosmerlosalbarracin/Developer/Projects/ast-intelligence-hooks/scripts/hooks-system"}
497
+ {"timestamp":1768158514231,"hook":"audit_logger","operation":"constructor","status":"started","repoRoot":"/Users/juancarlosmerlosalbarracin/Developer/Projects/ast-intelligence-hooks/scripts/hooks-system"}
498
+ {"timestamp":1768158514231,"hook":"audit_logger","operation":"ensure_dir","status":"started"}
499
+ {"timestamp":1768158514231,"hook":"audit_logger","operation":"ensure_dir","status":"success"}
500
+ {"timestamp":1768158514232,"hook":"audit_logger","operation":"constructor","status":"success","repoRoot":"/Users/juancarlosmerlosalbarracin/Developer/Projects/ast-intelligence-hooks/scripts/hooks-system"}
501
+ {"timestamp":1768158974401,"hook":"audit_logger","operation":"constructor","status":"started","repoRoot":"/Users/juancarlosmerlosalbarracin/Developer/Projects/ast-intelligence-hooks/scripts/hooks-system"}
502
+ {"timestamp":1768158974401,"hook":"audit_logger","operation":"ensure_dir","status":"started"}
503
+ {"timestamp":1768158974401,"hook":"audit_logger","operation":"ensure_dir","status":"success"}
504
+ {"timestamp":1768158974402,"hook":"audit_logger","operation":"constructor","status":"success","repoRoot":"/Users/juancarlosmerlosalbarracin/Developer/Projects/ast-intelligence-hooks/scripts/hooks-system"}
@@ -61,25 +61,11 @@ class VSCodeTaskConfigurator {
61
61
  args: [
62
62
  '-lc',
63
63
  [
64
- 'ROOT="${workspaceFolder}"',
65
- 'PRIMARY="$ROOT/scripts/hooks-system/bin/session-loader.sh"',
66
- 'FALLBACK="$ROOT/node_modules/pumuki-ast-hooks/scripts/hooks-system/bin/session-loader.sh"',
67
- 'FALLBACK2="$ROOT/node_modules/@pumuki/ast-intelligence-hooks/bin/session-loader.sh"',
68
- 'if [ -f "$PRIMARY" ]; then',
69
- ' exec bash "$PRIMARY"',
70
- 'elif [ -f "$FALLBACK" ]; then',
71
- ' exec bash "$FALLBACK"',
72
- 'elif [ -f "$FALLBACK2" ]; then',
73
- ' exec bash "$FALLBACK2"',
74
- 'else',
75
- ' echo "AST Session Loader not found." >&2',
76
- ' echo "Tried:" >&2',
77
- ' echo " - $PRIMARY" >&2',
78
- ' echo " - $FALLBACK" >&2',
79
- ' echo " - $FALLBACK2" >&2',
80
- ' exit 127',
81
- 'fi'
82
- ].join('\n')
64
+ 'bash "${workspaceFolder}/scripts/hooks-system/bin/session-loader.sh"',
65
+ '|| bash "${workspaceFolder}/node_modules/pumuki-ast-hooks/scripts/hooks-system/bin/session-loader.sh"',
66
+ '|| bash "${workspaceFolder}/node_modules/@pumuki/ast-intelligence-hooks/bin/session-loader.sh"',
67
+ '|| (echo "AST Session Loader not found." >&2; exit 127)'
68
+ ].join(' ')
83
69
  ],
84
70
  problemMatcher: [],
85
71
  runOptions: {
@@ -0,0 +1,38 @@
1
+ const fs = require('fs');
2
+ const os = require('os');
3
+ const path = require('path');
4
+
5
+ const VSCodeTaskConfigurator = require('../VSCodeTaskConfigurator');
6
+
7
+ describe('VSCodeTaskConfigurator', () => {
8
+ let testRoot;
9
+
10
+ beforeEach(() => {
11
+ testRoot = fs.mkdtempSync(path.join(os.tmpdir(), 'ast-hooks-vscode-task-'));
12
+ });
13
+
14
+ afterEach(() => {
15
+ if (testRoot && fs.existsSync(testRoot)) {
16
+ fs.rmSync(testRoot, { recursive: true, force: true });
17
+ }
18
+ });
19
+
20
+ it('should generate AST Session Loader task with a short command (no multiline bash -lc script)', () => {
21
+ const configurator = new VSCodeTaskConfigurator(testRoot, null);
22
+ configurator.configure();
23
+
24
+ const tasksJsonPath = path.join(testRoot, '.vscode', 'tasks.json');
25
+ expect(fs.existsSync(tasksJsonPath)).toBe(true);
26
+
27
+ const tasksJson = JSON.parse(fs.readFileSync(tasksJsonPath, 'utf8'));
28
+ const task = tasksJson.tasks.find(t => t.label === 'AST Session Loader' || t.identifier === 'ast-session-loader');
29
+ expect(task).toBeTruthy();
30
+
31
+ expect(task.command).toBe('bash');
32
+ expect(Array.isArray(task.args)).toBe(true);
33
+
34
+ // Current implementation embeds a multi-line script in args[1] (very noisy in terminal as "Executing task: ...")
35
+ // We want a single-line command.
36
+ expect(String(task.args[1] || '')).not.toContain('\n');
37
+ });
38
+ });
@@ -0,0 +1,14 @@
1
+ const fs = require('fs');
2
+ const path = require('path');
3
+
4
+ describe('session-loader.sh', () => {
5
+ it('should not hardcode the displayed version header', () => {
6
+ const filePath = path.join(__dirname, '..', 'session-loader.sh');
7
+ const content = fs.readFileSync(filePath, 'utf8');
8
+
9
+ expect(content).not.toContain('AST Intelligence Hooks v5.5.22');
10
+ expect(content).toMatch(/\bVERSION=/);
11
+ expect(content).toContain('package.json');
12
+ expect(content).toMatch(/AST Intelligence Hooks v\$VERSION/);
13
+ });
14
+ });
@@ -3,6 +3,8 @@
3
3
  # Runs on IDE startup to initialize AST hooks, show context and check tokens
4
4
  REPO_ROOT=$(git rev-parse --show-toplevel 2>/dev/null || echo ".")
5
5
 
6
+ VERSION=$(node -p "require('${REPO_ROOT}/package.json').version" 2>/dev/null || echo "unknown")
7
+
6
8
  BLUE='\033[0;34m'
7
9
  CYAN='\033[0;36m'
8
10
  GREEN='\033[0;32m'
@@ -22,7 +24,7 @@ fi
22
24
 
23
25
  echo ""
24
26
  echo -e "${BLUE}╔══════════════════════════════════════════════════════════╗${NC}"
25
- echo -e "${BLUE}║ 🤖 AST Intelligence Hooks v5.5.22 ║${NC}"
27
+ echo -e "${BLUE}║ 🤖 AST Intelligence Hooks v$VERSION ║${NC}"
26
28
  echo -e "${BLUE}║ Workspace Opened - Loading Context... ║${NC}"
27
29
  echo -e "${BLUE}╚══════════════════════════════════════════════════════════╝${NC}"
28
30
  echo ""
@@ -2,6 +2,7 @@ jest.mock('../BDDTDDWorkflowRules', () => ({
2
2
  BDDTDDWorkflowRules: jest.fn().mockImplementation(() => ({ analyze: jest.fn() }))
3
3
  }));
4
4
 
5
+ const fs = require('fs');
5
6
  const { Project } = require('../../ast-core');
6
7
  const { runCommonIntelligence } = require('../ast-common');
7
8
 
@@ -28,6 +29,35 @@ describe('AST Common Module', () => {
28
29
  expect(findings.some(f => f.ruleId === 'common.testing.missing_makesut')).toBe(false);
29
30
  expect(findings.some(f => f.ruleId === 'common.testing.missing_track_for_memory_leaks')).toBe(false);
30
31
  });
32
+
33
+ it('does not report false positives for Swift test files when getFullText is empty (fallback to disk)', () => {
34
+ const project = new Project({
35
+ useInMemoryFileSystem: true,
36
+ skipAddingFilesFromTsConfig: true,
37
+ });
38
+
39
+ const swiftPath = '/tmp/FooTests.spec.swift';
40
+ const swiftContent = [
41
+ 'import XCTest',
42
+ 'final class FooTests: XCTestCase {',
43
+ ' private func makeSUT() -> Foo { Foo() }',
44
+ ' func test_example() {',
45
+ ' let sut = makeSUT()',
46
+ ' trackForMemoryLeaks(sut, testCase: self, file: #file, line: #line)',
47
+ ' }',
48
+ '}',
49
+ ].join('\n');
50
+
51
+ const sf = project.createSourceFile(swiftPath, swiftContent);
52
+ jest.spyOn(sf, 'getFullText').mockReturnValue('');
53
+ jest.spyOn(fs, 'readFileSync').mockReturnValue(swiftContent);
54
+
55
+ const findings = [];
56
+ runCommonIntelligence(project, findings);
57
+
58
+ expect(findings.some(f => f.ruleId === 'common.testing.missing_makesut')).toBe(false);
59
+ expect(findings.some(f => f.ruleId === 'common.testing.missing_track_for_memory_leaks')).toBe(false);
60
+ });
31
61
  });
32
62
 
33
63
  describe('exports', () => {
@@ -1,4 +1,5 @@
1
1
  const path = require('path');
2
+ const fs = require('fs');
2
3
  const { pushFinding, SyntaxKind, platformOf, getRepoRoot } = require(path.join(__dirname, '../ast-core'));
3
4
  const { BDDTDDWorkflowRules } = require(path.join(__dirname, 'BDDTDDWorkflowRules'));
4
5
 
@@ -208,11 +209,21 @@ function runCommonIntelligence(project, findings) {
208
209
  if (/\/ast-(?:backend|frontend|android|ios|common|core|intelligence)\.js$/.test(filePath)) return;
209
210
 
210
211
  if (isTestFilePath(filePath)) {
211
- const content = sf.getFullText();
212
+ let content = sf.getFullText();
212
213
 
213
214
  const ext = path.extname(filePath).toLowerCase();
214
215
  const isSwiftOrKotlinTest = ext === '.swift' || ext === '.kt' || ext === '.kts';
215
216
 
217
+ if (isSwiftOrKotlinTest && (!content || content.trim().length === 0)) {
218
+ try {
219
+ content = fs.readFileSync(filePath, 'utf8');
220
+ } catch (error) {
221
+ if (process.env.DEBUG) {
222
+ console.debug(`[ast-common] Failed to read test file content for ${filePath}: ${error.message}`);
223
+ }
224
+ }
225
+ }
226
+
216
227
  if (isSwiftOrKotlinTest) {
217
228
  if (!shouldSkipMakeSUTRule(filePath) && !hasMakeSUT(content)) {
218
229
  pushFinding(
@@ -22,3 +22,6 @@
22
22
  {"timestamp":"2026-01-11T18:54:53.862Z","level":"info","component":"TokenMonitor","event":"TOKEN_MONITOR_RESULT","data":{"level":"ok","percentUsed":10,"tokensUsed":100000,"maxTokens":1000000,"source":"realtime","stale":false},"context":{"message":"Result level=ok percent=10% used=100000/1000000 source=realtime"}}
23
23
  {"timestamp":"2026-01-11T18:54:53.871Z","level":"info","component":"TokenMonitor","event":"TOKEN_MONITOR_RESULT","data":{"level":"warning","percentUsed":91,"tokensUsed":910000,"maxTokens":1000000,"source":"fallback","stale":false},"context":{"message":"Result level=warning percent=91% used=910000/1000000 source=fallback"}}
24
24
  {"timestamp":"2026-01-11T18:54:53.873Z","level":"info","component":"TokenMonitor","event":"TOKEN_MONITOR_RESULT","data":{"level":"critical","percentUsed":98,"tokensUsed":980000,"maxTokens":1000000,"source":"realtime","stale":true},"context":{"message":"Result level=critical percent=98% used=980000/1000000 source=realtime (stale)"}}
25
+ {"timestamp":"2026-01-11T19:08:37.452Z","level":"info","component":"TokenMonitor","event":"TOKEN_MONITOR_RESULT","data":{"level":"ok","percentUsed":10,"tokensUsed":100000,"maxTokens":1000000,"source":"realtime","stale":false},"context":{"message":"Result level=ok percent=10% used=100000/1000000 source=realtime"}}
26
+ {"timestamp":"2026-01-11T19:08:37.467Z","level":"info","component":"TokenMonitor","event":"TOKEN_MONITOR_RESULT","data":{"level":"warning","percentUsed":91,"tokensUsed":910000,"maxTokens":1000000,"source":"fallback","stale":false},"context":{"message":"Result level=warning percent=91% used=910000/1000000 source=fallback"}}
27
+ {"timestamp":"2026-01-11T19:08:37.468Z","level":"info","component":"TokenMonitor","event":"TOKEN_MONITOR_RESULT","data":{"level":"critical","percentUsed":98,"tokensUsed":980000,"maxTokens":1000000,"source":"realtime","stale":true},"context":{"message":"Result level=critical percent=98% used=980000/1000000 source=realtime (stale)"}}