From e48d56a1d50a3b975fa96bca84d979cbe3d018c0 Mon Sep 17 00:00:00 2001 From: Nubenetes Bot Date: Fri, 15 May 2026 01:06:14 +0200 Subject: [PATCH] feat: improve V2 architecture with detailed logging and dynamic navigation --- .github/workflows/agentic_v2_builder.yml | 2 +- GEMINI.md | 3 ++ src/v2_optimizer.py | 67 +++++++++++++++++++++++- 3 files changed, 69 insertions(+), 3 deletions(-) diff --git a/.github/workflows/agentic_v2_builder.yml b/.github/workflows/agentic_v2_builder.yml index 6c51d081..62e09107 100644 --- a/.github/workflows/agentic_v2_builder.yml +++ b/.github/workflows/agentic_v2_builder.yml @@ -39,7 +39,7 @@ jobs: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} PYTHONPATH: . run: | - python src/v2_optimizer.py + python -u src/v2_optimizer.py - name: Create Pull Request for V2 Elite Update uses: peter-evans/create-pull-request@v6 diff --git a/GEMINI.md b/GEMINI.md index 9e800ab3..c4b61c31 100644 --- a/GEMINI.md +++ b/GEMINI.md @@ -15,6 +15,7 @@ This file contains the accumulated instructions and long-term vision for the aut 9. **URL Expansion**: All shortened links (t.co, bit.ly, buff.ly, etc.) MUST be expanded to their original long version before being evaluated or injected. This ensures inventory homogeneity and improves global deduplication precision. 10. **Official Language (English Only)**: All injected content (titles, descriptions, headers), execution logs, and automated communications (PRs) MUST be exclusively in ENGLISH. Nubenetes is a global resource and linguistic consistency is critical. 11. **Workflow-Config Synchronization**: The GitHub Actions curation workflow form (`agentic_cron.yml`) MUST remain perfectly synchronized with the curation sources configuration file (`data/curation_sources.yaml`). Any addition, removal, or renaming of topics/categories in the configuration file requires a corresponding update to the workflow's input fields (checkboxes) to ensure users can toggle those sources manually. This maintains consistency between data-driven sources and the UI trigger. +12. **V2 Elite Maintenance**: The Nubenetes V2 (Agentic Elite) edition is a derived view of the V1 archive. It is managed via the `src/v2_optimizer.py` script and stored in the `v2-docs/` directory. AI agents MUST NOT modify `v2-docs/` directly via standard curation workflows; they must only use the `agentic_v2_builder.yml` workflow to perform the periodic "Elite Selection" process. Standard curation and cleaning workflows must always target the `docs/` directory as the primary source of truth. ## 🛠️ Structural Evolution & Navigation @@ -31,6 +32,7 @@ This file contains the accumulated instructions and long-term vision for the aut * **Semantic Polish**: When a section becomes excessively flat, the AI should propose and implement a reorganization into logical sub-sections purely to improve readability and classification, without restricting the volume of content. * **Navigation Integrity**: Every structural change must be reflected in: * `mkdocs.yml` (Navigation menu). + * `v2-mkdocs.yml` (V2 Navigation menu). * `docs/index.md` (Main Table of Contents). * The internal TOC of the modified page. * **Orphan Curation**: Periodically audit the `docs/` folder to find unlinked files and integrate them into the navigation based on their topic. @@ -51,3 +53,4 @@ The bot must rotate between profiles to avoid detection: * **May 2026**: Generation of PRs with visual analytics (Mermaid) and Health Matrix. * **May 2026**: Implementation of Backup-based Curation (JSON/MD) to avoid X.com blocks. * **May 2026**: Implementation of multi-source curation and category-based filtering in GitHub Workflow. +* **May 2026**: Introduction of **Nubenetes V2 (Agentic Elite)** architecture. Implemented persistent `v2-docs/` storage, the `v2_optimizer.py` engine for 2026 standard filtering, and a dual-deployment pipeline to host both V1 (Exhaustive) and V2 (Elite) versions in parallel. diff --git a/src/v2_optimizer.py b/src/v2_optimizer.py index e160efc9..7d551981 100644 --- a/src/v2_optimizer.py +++ b/src/v2_optimizer.py @@ -84,18 +84,81 @@ class V2Optimizer: async def run_full_optimization(self): log_event("STARTING V2 AGENTIC OPTIMIZATION (THE ARCHITECT'S CUT)", section_break=True) - files = [f for f in os.listdir(V1_DIR) if f.endswith(".md") and f != "index.md"] + if not os.path.exists(V1_DIR): + log_event(f"[!] CRITICAL: Source directory {V1_DIR} not found.") + return + + files = [f for f in os.listdir(V1_DIR) if f.endswith(".md") and f != "index.md"] + log_event(f"[*] Found {len(files)} files to process in {V1_DIR}") + + if not files: + log_event("[!] No markdown files found to optimize.") + return + + # Ensure output directory exists + os.makedirs(V2_DIR, exist_ok=True) + log_event(f"[*] Output directory verified: {V2_DIR}") + # Batch processing to avoid rate limits - for i in range(0, len(files), 5): + total_files = len(files) + for i in range(0, total_files, 5): batch = files[i:i+5] + log_event(f">>> Processing batch {i//5 + 1} ({len(batch)} files)...") await asyncio.gather(*[self.optimize_file(f) for f in batch]) await asyncio.sleep(2) # Generate Landing Page + log_event("[*] Generating V2 landing page...") await self._generate_v2_index() + + # Sync Navigation + log_event("[*] Syncing V2 navigation from original mkdocs.yml...") + await self._sync_navigation() + log_event("V2 OPTIMIZATION FINISHED SUCCESSFULLY.", section_break=True) + async def _sync_navigation(self): + """ + Reads mkdocs.yml and generates a filtered nav for v2-mkdocs.yml + """ + try: + with open("mkdocs.yml", "r") as f: + v1_config = yaml.safe_load(f) + + with open("v2-mkdocs.yml", "r") as f: + v2_config = yaml.safe_load(f) + + v1_nav = v1_config.get("nav", []) + + def filter_nav(nav_item): + if isinstance(nav_item, str): + return nav_item if os.path.exists(os.path.join(V2_DIR, nav_item)) else None + if isinstance(nav_item, dict): + new_item = {} + for key, value in nav_item.items(): + if isinstance(value, list): + filtered_list = [filter_nav(i) for i in value] + filtered_list = [i for i in filtered_list if i is not None] + if filtered_list: new_item[key] = filtered_list + else: + if os.path.exists(os.path.join(V2_DIR, value)): + new_item[key] = value + return new_item if new_item else None + return None + + v2_nav = [filter_nav(item) for item in v1_nav] + v2_nav = [item for item in v2_nav if item is not None] + + v2_config["nav"] = v2_nav + + with open("v2-mkdocs.yml", "w") as f: + yaml.dump(v2_config, f, sort_keys=False) + + log_event(" [OK] v2-mkdocs.yml navigation updated.") + except Exception as e: + log_event(f" [!] Error syncing navigation: {e}") + async def _generate_v2_index(self): v2_index = ( "# Welcome to Nubenetes V2\n\n"