graph { graph [engine:dot rankdir:LR applyCss:true clusterize:true intention:semi grayscale:false desaturate:true] ast_lake -> ast_lake__commands_ [reverse: false] ast_lake__commands_ -> ast_lake__commands____ast_lake__info [reverse: false] ast_lake__commands_ -> ast_lake__commands____ast_lake__init [reverse: false] ast_lake__commands_ -> ast_lake__commands____ast_lake__reset [reverse: false] ast_lake__commands_ -> ast_lake__commands____ast_lake__cleanup [reverse: false] ast_lake__commands_ -> ast_lake__commands____ast_lake__restart [reverse: false] ast_lake__commands____ast_lake__restart -> ast_lake__commands____ast_lake__restart___ast_lake__commands____ast_lake__reset_nodes [reverse: false] ast_lake *= ast_lake__commands_ [reverse: false] ast_lake__commands_ *= ast_lake__commands____ast_lake__add [reverse: false] ast_lake__commands_ *= ast_lake__commands____ast_lake__populate [reverse: false] ast_lake__commands_ *= ast_lake__commands____ast_lake__query_TERM [reverse: false] ast_lake__commands_ *= ast_lake__commands____ast_lake__queryraw_TERM [reverse: false] ast_lake__commands_ *= ast_lake__commands____ast_lake__flast [reverse: false] ast_lake__commands_ *= ast_lake__commands____ast_lake__nodes [reverse: false] ast_lake__commands_ *= ast_lake__commands____ast_lake__mdg [reverse: false] ast_lake__commands_ *= ast_lake__commands____ast_lake__mosaic [reverse: false] ast_lake__commands_ *= ast_lake__commands____ast_lake__mprocs [reverse: false] ast_lake *= ast_lake__recent_updates [reverse: false] ast_lake__recent_updates *= ast_lake__recent_updates___ast_lake__2025_12_01 [reverse: false] db_tables -> db_tables__The_pipeline__how_data_flows_ [reverse: false] db_tables -> db_tables__cache_ast_lake_flast____cache_ast_lake_nodes____cache_ast_lake_nodes_ref____cache_ast_lake_nodes_backup_ [reverse: false] db_tables__cache_ast_lake_flast____cache_ast_lake_nodes____cache_ast_lake_nodes_ref____cache_ast_lake_nodes_backup_ -> db_tables__cache_ast_lake_flast____cache_ast_lake_nodes____cache_ast_lake_nodes_ref____cache_ast_lake_nodes_backup____db_tables__cache_ast_lake_flast_ [reverse: false] db_tables__cache_ast_lake_flast____cache_ast_lake_nodes____cache_ast_lake_nodes_ref____cache_ast_lake_nodes_backup_ -> db_tables__cache_ast_lake_flast____cache_ast_lake_nodes____cache_ast_lake_nodes_ref____cache_ast_lake_nodes_backup____db_tables__cache_ast_lake_nodes_ [reverse: false] db_tables__cache_ast_lake_flast____cache_ast_lake_nodes____cache_ast_lake_nodes_ref____cache_ast_lake_nodes_backup_ -> db_tables__cache_ast_lake_flast____cache_ast_lake_nodes____cache_ast_lake_nodes_ref____cache_ast_lake_nodes_backup____db_tables__cache_ast_lake_nodes_ref_ [reverse: false] db_tables__cache_ast_lake_flast____cache_ast_lake_nodes____cache_ast_lake_nodes_ref____cache_ast_lake_nodes_backup_ -> db_tables__cache_ast_lake_flast____cache_ast_lake_nodes____cache_ast_lake_nodes_ref____cache_ast_lake_nodes_backup____db_tables__cache_ast_lake_nodes_backup_ [reverse: false] db_tables *= db_tables__linetime_ [reverse: false] db_tables *= db_tables__repo_voting_ [reverse: false] ast_lake [z: 9.5 @html: "
| ast-lake usage: ast-lake 【command】 【args...】 | ||
|
| commands: |
| info | |
|
| init | |
|
| reset | ||
|
| cleanup | |
|
| restart | ||
|
| reset-nodes | ||
|
| add | ||||||
| ||||||
ast-lake add '*.mdd' '*.json' | ||||||
| ||||||
# --base-directory $dir fd --absolute-path -tf ".+【.】(mdd)$" | rg -v test > $dbPopulateList fd -tf --absolute-path "$filterFilesPattern" > $dbPopulateList | rg -v node_modules | rg -v test > $dbPopulateList # or only add arbitrary files: rg TERM --files-with-matches | xargs realpath {} >> $dbPopulateList | ||||||
|
| populate | |
|
| query TERM | |||
|
| queryraw TERM | |
|
| flast | ||
|
| nodes | |
|
| mdg | ||
|
| mosaic | ||
|
| mprocs | |
|
| recent updates |
| 2025-12-01 | |||
|
| db tables These tables are in our ast-lake SQLite database. They hold the state derived from parsing mdd/md/js files into AST nodes. Two parallel implementations exist: | ||
| ||
| Both follow the same pipeline: extract flast → normalize → store nodes. |
| The pipeline how data flows File on disk │ ▼ astHole() → astNavigator() — reads file, calls language-specific extractor │ (extractFlastMarkdown, extractFlastJavascript, │ extractFlastJson, extractFlastBash, ...) ▼ cache_ast_lake_flast — one row per file; id=filepath, value=JSON flast array │ ▼ actualizeNodes() → normalizeNodes() — extracts symbolic types from flast │ (heading, link, comment, FunctionDeclaration, Identifier) ▼ cache_ast_lake_nodes — one row per AST node; id=fn:offset cache_ast_lake_nodes_ref — same rows, different ref format (readable refId) cache_ast_lake_nodes_backup — backup of old nodes before update |
| cache_ast_lake_flast Schema from sqlCreateTableCache(tblName) in ast-lake.mjs:51 . All four share the same column layout but each column has different semantics per table : | |||||||||||||||||||||||||||
| |||||||||||||||||||||||||||
| Shared indexes: num1 , num2 , sem , ref (each named {table}_idx_{col} ). | |||||||||||||||||||||||||||
| cache_ast_lake_flast Role: Raw flattened AST cache — one row per file. Stores the complete AST produced by the language-specific extractor. | ||||||||||||
| ||||||||||||
| How it's populated: Written by astNavigator.mjs via cacheFlast(fnIn, data) (line 1571), using initSqliteCache from sqlito.mjs . The data.value is the array of fragments produced by extractors like extractFlastMarkdown , extractFlastJavascript , etc. Query pattern (in actualizeNodes() ): SELECT id, value, mt FROM cache_ast_lake_flast WHERE unixepoch(mt) > <lastSync> Only changed files (newer mtime) are reprocessed. Node value structure (each element in the JSON flast array): { "id": "node-id", "dim": 【"file", "listItem.0", "property.key"】, "type": "heading|link|code|paragraph|list|...", "code": "raw text content", "loc": { "line": { "s": 1, "e": 3 }, "column": { "s": 1, "e": 80 } }, "symbName": null, "symbRangeL": null } | ||||||||||||
| cache_ast_lake_nodes Role: Individual AST node storage — one row per symbolic node. Produced by normalizeNodes() in actualizeNodes() (ast-lake.mjs:183-266), which extracts only symbolicTypes (heading, link, comment, FunctionDeclaration, Identifier) from the flast. | |||||||||||||||||||||||||||
| |||||||||||||||||||||||||||
| Normalized node value structure (the JSON in the value column): { "fn": "/home/.../repo/repolero/paper/file.mdd", "trail": 【"getting-started", "installation"】, "type": "heading", "nomen": "Installation", "code": "## Installation", "symbName": null, "symbBlame": 【"abc123def", "456ghi789"】, "outerCode": "full subtree text...", "position": 【42, 1】, "lineRange": 【42, 85】, "offset": 42, "symbMt": "2025-06-15T10:30:00Z", "symbUser": "author@example.com", "mt": "2025-06-15T10:30:00Z" } Key normalization details (from normalizeNodes() at ast-lake.mjs:183): | |||||||||||||||||||||||||||
| |||||||||||||||||||||||||||
| Query pattern (voting dashboard): SELECT n.id, n.body, n.num1 as headingLevel, r.ref FROM cache_ast_lake_nodes n INNER JOIN cache_ast_lake_nodes_ref r USING(id) INNER JOIN repo_voting v ON v.ref = r.ref WHERE n.sem = 'heading' | |||||||||||||||||||||||||||
| cache_ast_lake_nodes_ref Role: Readable refId mirror of nodes. Stores the user-visible fragment reference string (the one used in URLs and voting) instead of the last-trail-segment ref. | |||||||||||||||
| |||||||||||||||
| [object Object] (ast-lake.mjs:29-44): | |||||||||||||||
| |||||||||||||||
| [object Object] (ast-lake.mjs:46-48): | |||||||||||||||
| |||||||||||||||
| Why two ref tables? cache_ast_lake_nodes.ref has the short, per-node ref (last trail segment). cache_ast_lake_nodes_ref.ref has the full, human-readable fragment path including the file prefix. The voting system uses the full refId from nodes_ref . | |||||||||||||||
| cache_ast_lake_nodes_backup Role: Rollback copy. Before updating a file's nodes in cache_ast_lake_nodes , the old rows are copied here (ast-lake.mjs:500-514): INSERT OR REPLACE INTO cache_ast_lake_nodes_backup (id, value, mt, sem, num1, num2, ref, body) SELECT id, value, mt, sem, num1, num2, ref, body FROM cache_ast_lake_nodes WHERE id LIKE '<escapedFn>:%' Then the old rows are deleted from both cache_ast_lake_nodes and cache_ast_lake_nodes_ref before inserting the new normalized nodes. If a sync fails, the backup can be restored.Note: cache_ast_lake_nodes_ref does NOT have a backup table — the ref table is rebuilt from scratch each time. | |
| linetime Role: Git blame line-history cache. Maps each line in each file to its git blame metadata (commit hash, author, timestamp). Used by normalizeNodes() to attach symbBlame / symbMt / symbUser to each node.Schema (commented inline in ast-lake.mjs:122-131 ): | ||||||||||||||||||||||||
| ||||||||||||||||||||||||
| Query pattern (in actualizeNodes() , ast-lake.mjs:473): SELECT line, mt, user, hash FROM linetime WHERE fn='<filepath>' AND hash!="" ORDER BY line The result is used to compute symbRangeL → symbBlame for each node: all commit hashes for lines within the node's source range.See linetime-parse-blame.jq for the processing logic that parses git blame --line-porcelain output into linetime rows. | ||||||||||||||||||||||||
| repo_voting Role: Voting event log. Records voting actions (cast, uncast, hot, pin, weak, veto) on fragments within campaigns. Schema from sqlCreateTableEventSource(tblName) in ast-lake.mjs:85 . | ||||||||||||||||||||||||||||||
| ||||||||||||||||||||||||||||||
| Indexes: num1 , num2 , campaign , operation , ref . Key query patterns: Dashboard voting (count per ref): SELECT ref, operation, COUNT(*) as count, SUM(num1) as total FROM repo_voting WHERE campaign = 'eisenhower' GROUP BY ref, operation Heading-changes metadata check ( hasMetaData ): SELECT DISTINCT ref FROM repo_voting WHERE ref IN ('ref1', 'ref2', ...) ref format: Must match cache_ast_lake_nodes_ref.ref — the readable refId from buildNodeAbsoluteId() . Format: relative/path/file.mdd::sanitized/trail/path . For links: ...::trail#nomen:tinyHash(url) . Cleanup on file deletion (ast-lake.mjs cleanup() at line 305): | ||||||||||||||||||||||||||||||
|