@@ -13,6 +13,7 @@ This document provides essential context for LLMs performing development tasks i
1313- Analyze composable definitions and usage across projects
1414- Compare files across documentation versions
1515- Count documentation pages and tested code examples
16+ - Generate reports on testable code examples from analytics data
1617
1718** Target Users** : MongoDB technical writers performing maintenance, scoping work, and reporting.
1819
@@ -36,29 +37,42 @@ audit-cli/
3637│ │ └── composables/ # Analyze composable definitions and usage
3738│ ├── compare/ # Compare files across versions
3839│ │ └── file-contents/ # Compare file contents
39- │ └── count/ # Count documentation content
40- │ ├── tested-examples/ # Count tested code examples
41- │ └── pages/ # Count documentation pages
40+ │ ├── count/ # Count documentation content
41+ │ │ ├── tested-examples/ # Count tested code examples
42+ │ │ └── pages/ # Count documentation pages
43+ │ └── report/ # Generate reports from documentation data
44+ │ └── testable-code/ # Analyze testable code examples from analytics
4245├── internal/ # Internal packages (not importable externally)
4346│ ├── config/ # Configuration management
4447│ │ ├── config.go # Config loading from file/env/args
45- │ │ └── config_test.go # Config tests
48+ │ │ ├── config_test.go # Config tests
49+ │ │ ├── url_mapping.go # URL-to-source-file mapping via Snooty Data API
50+ │ │ └── url_mapping_test.go # URL mapping tests
51+ │ ├── language/ # Programming language utilities
52+ │ │ ├── language.go # Language normalization, extensions, products
53+ │ │ └── language_test.go # Language tests
4654│ ├── projectinfo/ # MongoDB docs project structure utilities
47- │ │ ├── pathresolver.go # Path resolution
48- │ │ ├── source_finder.go # Source directory detection
55+ │ │ ├── pathresolver.go # Path resolution
56+ │ │ ├── products.go # Content directory to product mapping
57+ │ │ ├── source_finder.go # Source directory detection
4958│ │ └── version_resolver.go # Version path resolution
50- │ └── rst/ # RST parsing utilities
51- │ ├── parser.go # Generic parsing with includes
52- │ ├── directive_parser.go # Directive parsing
53- │ ├── directive_regex.go # Regex patterns for directives
54- │ ├── parse_procedures.go # Procedure parsing (core logic)
55- │ ├── get_procedure_variations.go # Variation extraction
56- │ └── rstspec.go # Fetch and parse canonical rstspec.toml
59+ │ ├── rst/ # RST parsing utilities
60+ │ │ ├── parser.go # Generic parsing with includes
61+ │ │ ├── directive_parser.go # Directive parsing with language resolution
62+ │ │ ├── directive_regex.go # Regex patterns for directives
63+ │ │ ├── parse_procedures.go # Procedure parsing (core logic)
64+ │ │ ├── get_procedure_variations.go # Variation extraction
65+ │ │ ├── rstspec.go # Fetch and parse canonical rstspec.toml
66+ │ │ └── yaml_steps_parser.go # Parse YAML steps files for code examples
67+ │ └── snooty/ # Snooty.toml parsing utilities
68+ │ ├── snooty.go # Parse snooty.toml, find project config
69+ │ └── snooty_test.go # Snooty tests
5770├── testdata/ # Test fixtures (auto-ignored by Go build)
5871│ ├── input-files/source/ # Test RST files
5972│ ├── expected-output/ # Expected extraction results
6073│ ├── compare/ # Compare command test data
61- │ └── count-test-monorepo/ # Count command test data
74+ │ ├── count-test-monorepo/ # Count command test data
75+ │ └── testable-code-test/ # Testable code report test data
6276├── bin/ # Build output directory
6377├── docs/ # Additional documentation
6478│ └── PROCEDURE_PARSING.md # Detailed procedure parsing logic
@@ -393,6 +407,103 @@ func NewExtractCommand() *cobra.Command {
393407- Support multiple output formats (text, JSON) where applicable
394408- Use consistent formatting (headers with ` = ` separators, indentation)
395409
410+ ### Network Request Caching
411+
412+ All network requests to external APIs should implement caching to avoid repeated requests and support offline usage. The caching pattern is implemented in ` internal/config/url_mapping.go ` (for Snooty Data API) and ` internal/rst/rstspec.go ` (for rstspec.toml).
413+
414+ ** Cache Location** : ` ~/.audit-cli/ ` directory
415+ - URL mapping cache: ` ~/.audit-cli/url-mapping-cache.json `
416+ - Rstspec cache: ` ~/.audit-cli/rstspec-cache.json `
417+
418+ ** Cache TTL** : 24 hours (configurable per cache type)
419+
420+ ** Implementation Pattern** :
421+
422+ 1 . ** Define cache constants** :
423+ ``` go
424+ const CacheTTL = 24 * time.Hour
425+ const CacheDir = " .audit-cli"
426+ const CacheFileName = " my-cache.json"
427+ ```
428+
429+ 2 . ** Create cache struct** with timestamp and data:
430+ ``` go
431+ type MyCache struct {
432+ Timestamp time.Time ` json:"timestamp"`
433+ Data MyData ` json:"data"`
434+ }
435+ ```
436+
437+ 3 . ** Implement cache functions** :
438+ ``` go
439+ // getCachePath returns the path to the cache file
440+ func getCachePath () (string , error ) {
441+ homeDir , err := os.UserHomeDir ()
442+ if err != nil {
443+ return " " , fmt.Errorf (" failed to get home directory: % w" , err)
444+ }
445+ return filepath.Join (homeDir, CacheDir, CacheFileName), nil
446+ }
447+
448+ // loadCache loads from cache, returns error if missing or expired
449+ func loadCache () (*MyData , error ) {
450+ // Read file, unmarshal JSON, check TTL
451+ }
452+
453+ // saveCache saves data to cache with current timestamp
454+ func saveCache (data *MyData ) error {
455+ // Create directory if needed, marshal JSON, write file
456+ }
457+
458+ // fetchFromAPI fetches fresh data from the network
459+ func fetchFromAPI () (*MyData , error ) {
460+ // HTTP request, parse response
461+ }
462+ ```
463+
464+ 4 . ** Main fetch function with fallback logic** :
465+ ``` go
466+ func FetchData () (*MyData , error ) {
467+ // Try cache first
468+ data , err := loadCache ()
469+ if err == nil {
470+ return data, nil
471+ }
472+
473+ // Cache miss or expired, try network
474+ data , fetchErr := fetchFromAPI ()
475+ if fetchErr != nil {
476+ // Network failed - try expired cache as offline fallback
477+ // (read cache file without TTL check)
478+ if expiredData := loadExpiredCache (); expiredData != nil {
479+ fmt.Fprintf (os.Stderr , " Warning: Using expired cache\n " )
480+ return expiredData, nil
481+ }
482+ return nil , fetchErr
483+ }
484+
485+ // Save to cache for next time
486+ if saveErr := saveCache (data); saveErr != nil {
487+ fmt.Fprintf (os.Stderr , " Warning: Could not save cache: %v \n " , saveErr)
488+ }
489+
490+ return data, nil
491+ }
492+ ```
493+
494+ ** Key Behaviors** :
495+ - Cache is stored in user's home directory for persistence across sessions
496+ - Expired cache is used as fallback when network is unavailable (offline support)
497+ - Cache save failures are logged as warnings but don't fail the operation
498+ - JSON format for easy debugging and human readability
499+
500+ ** When Adding New Network Calls** :
501+ 1 . Follow the pattern above
502+ 2 . Add cache file name constant
503+ 3 . Implement the four cache functions
504+ 4 . Use the same ` ~/.audit-cli/ ` directory for consistency
505+ 5 . Consider appropriate TTL (24 hours is default, adjust if data changes more/less frequently)
506+
396507## Key Design Decisions
397508
398509### RST Parsing Strategy
0 commit comments