Compare commits

...
18 Commits
Author SHA1 Message Date
Nubenetes Bot 239dd05e6f release: v2.7.0 — Intelligence Digest card and mini-preview on index 2026-06-19 10:59:31 +02:00
Inaki 932770b89b Merge pull request #361 from nubenetes/feat/digest-card-index
feat: Intelligence Digest hero card and mini-preview on index
2026-06-19 10:59:15 +02:00
Nubenetes BotandClaude Sonnet 4.6 c8ca878f66 feat: add Intelligence Digest card to index hero and mini-preview block
- New hero card (amber color) between AI & MCP Agents and Agentic Video
  Hub, linking to /tech-digest/ with emoji icon and subtitle
- Dynamic digest-preview block above Agentic Pulse: shows top 1 link
  from 5 priority categories (Kubernetes, AI, Security, IaC, Observability)
  pulled from data/news_digest.json on each optimizer run
- New CSS: hero-badge-card--amber, hero-badge-icon, digest-preview
  component with category chips and hover states
- v2_optimizer now generates both the card and preview automatically

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-19 10:58:52 +02:00
Nubenetes Bot 64c6e9ea18 Merge branch 'develop' of github.com:nubenetes/awesome-kubernetes into develop 2026-06-19 10:44:46 +02:00
Nubenetes Bot 53b19f1b09 merge: back-merge master v2.6.9 into develop 2026-06-19 10:44:36 +02:00
Nubenetes Bot f6e60a6487 docs: automated README metric synchronization [skip ci] 2026-06-19 08:44:35 +00:00
Nubenetes Bot 5bfcaf1b03 release: v2.6.9 — Fix NoneType crashes in v2_optimizer, dedup, and news_digest 2026-06-19 10:44:32 +02:00
Inaki b8144d9253 Merge pull request #360 from nubenetes/feat/fix-nonetype-comparisons
fix: NoneType crashes in v2_optimizer, dedup, and news_digest
2026-06-19 10:44:13 +02:00
Nubenetes BotandClaude Sonnet 4.6 b321169459 fix: NoneType comparison crashes in v2_optimizer, dedup, and news_digest
Inventory entries can have stars=null or discovered_at=null. Replace
.get("stars", 0) with .get("stars") or 0 in all three modules so that
None values are safely coerced to 0/"" before numeric/string comparison.

Fixes TypeError crashes in:
- v2_optimizer.py:632 _calculate_tags
- dedup.py:74,108 title dedup and entry scoring
- news_digest.py:322 category pool sorting

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-19 10:44:00 +02:00
Nubenetes Bot 34610f4671 merge: back-merge master v2.6.8 into develop 2026-06-19 10:37:06 +02:00
Nubenetes Bot f50fdffd64 release: v2.6.8 — Fix unbounded license check causing CI timeout 2026-06-19 10:37:01 +02:00
Inaki f5fae99a38 Merge pull request #359 from nubenetes/feat/fix-license-check-limit
fix: cap license check at 200 repos — was unbounded causing CI timeout
2026-06-19 10:36:46 +02:00
Nubenetes BotandClaude Sonnet 4.6 ebae3c6e27 fix: cap license change detection at MAX_REPOS_DEFAULT (200) — was unbounded
detect_license_changes() iterated all repos with gh_license set, causing
hundreds/thousands of GitHub API calls. Apply the same 200-repo cap as
the activity enrichment module to keep total enrichment under ~3 min.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-19 10:36:33 +02:00
Nubenetes Bot a8941afd24 merge: back-merge master v2.6.7 into develop 2026-06-19 10:28:44 +02:00
Nubenetes Bot f4fb5fe19b release: v2.6.7 — Reduce enrichment CI time from 12min to ~2min 2026-06-19 10:28:39 +02:00
Inaki f46886abf3 Merge pull request #358 from nubenetes/feat/fix-enrichment-speed
perf: reduce enrichment from 12min to ~2min
2026-06-19 10:28:22 +02:00
Nubenetes BotandClaude Sonnet 4.6 6ccda021e2 perf: reduce enrichment from 12min to ~2min (1 API call/repo, 200 limit)
- Consolidate 2 GitHub API calls per repo into 1: open_issues_count
  already includes PRs on GitHub, second /pulls call was redundant
- Reduce MAX_REPOS_DEFAULT 500→200: sufficient for meaningful enrichment,
  200 × 0.5s = ~100s vs 500 × 1.5s = ~12.5min in CI
- Reduce GITHUB_RATE_DELAY 0.75s→0.5s: still safely under 5000 req/hr
- Add 429 rate-limit backoff (5s sleep instead of crashing)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-19 10:28:07 +02:00
Nubenetes Bot 3f44948119 merge: back-merge master v2.6.6 into develop 2026-06-19 10:16:41 +02:00
7 changed files with 156 additions and 43 deletions
+6 -6
View File
@@ -135,14 +135,14 @@ Additionally, as of May 2026, Nubenetes has reached the **Platinum Operational T
## 2. Repository Metrics and Evolution
### 2.1. The "Heart" of Nubenetes
(Stats as of 2026-06-18)
(Stats as of 2026-06-19)
<!-- HEART_STATS_START -->
| Metric | Value |
| :--- | :--- |
| **Total Technical Resources (Links)** | **18647+** |
| **Specialized MD Pages** | **162** |
| **Total Commits** | **6013+** |
| **Total Commits** | **6058+** |
| **Primary AI Engine** | **Google Gemini (Agentic)** |
<!-- HEART_STATS_END -->
@@ -180,7 +180,7 @@ The growth of Nubenetes reflects the acceleration of the Cloud Native ecosystem.
| 6 | 2023 | 30 | 123 | Maintenance & Refinement |
| 7 | 2024 | 53 | 218 | Curation Strategy Pivot |
| 8 | 2025 | 5 | 20 | Stability & Research Phase |
| 9 | 2026 | 2454 | 10,135 | **Agentic AI Surge** (May 2026 Inception) |
| 9 | 2026 | 2499 | 10,320 | **Agentic AI Surge** (May 2026 Inception) |
<!-- ANNUAL_GROWTH_END -->
<!-- ANNUAL_CHART_START -->
@@ -196,8 +196,8 @@ xychart-beta
title "Nubenetes Annual Growth Metrics (20182026)"
x-axis ["2018", "2019", "2020", "2021", "2022", "2023", "2024", "2025", "2026"]
y-axis "Volume (Commits / Estimated New Refs)" 0 --> 11000
bar [1445, 586, 8449, 2193, 1660, 123, 218, 20, 10135]
bar [350, 142, 2046, 531, 402, 30, 53, 5, 2454]
bar [1445, 586, 8449, 2193, 1660, 123, 218, 20, 10320]
bar [350, 142, 2046, 531, 402, 30, 53, 5, 2499]
```
<!-- ANNUAL_CHART_END -->
@@ -207,7 +207,7 @@ xychart-beta
| :--- | :---: | :---: | :--- |
| 2026-04 | 25 | 103 | Active Curation |
| 2026-05 | 2101 | 8,677 | **Agentic Inception (Gemini Era)** |
| 2026-06 | 328 | 1,354 | Active Curation |
| 2026-06 | 373 | 1,540 | Active Curation |
<!-- MONTHLY_SURGE_END -->
### 2.4. Content Distribution and Semantic Clustering
+66
View File
@@ -352,6 +352,22 @@ a {
border-color: #2dd4bf !important;
}
.hero-badge-card--amber {
border-color: rgba(245, 158, 11, 0.2);
background: rgba(245, 158, 11, 0.02);
}
.hero-badge-card--amber:hover {
background: rgba(245, 158, 11, 0.06) !important;
box-shadow: 0 8px 24px rgba(245, 158, 11, 0.18);
border-color: #f59e0b !important;
}
.hero-badge-icon {
font-size: 2rem;
line-height: 1;
margin-bottom: 4px;
}
.hero-badge-title {
font-weight: bold;
font-size: 0.95rem;
@@ -364,6 +380,56 @@ a {
margin-top: 4px;
}
/* Intelligence Digest mini-preview on index */
.digest-preview {
background: rgba(245, 158, 11, 0.04);
border: 1px solid rgba(245, 158, 11, 0.15);
border-radius: 12px;
padding: 20px 24px;
margin: 24px 0;
}
.digest-preview-header {
display: flex;
align-items: center;
justify-content: space-between;
margin-bottom: 12px;
}
.digest-preview-title {
font-weight: 700;
font-size: 1rem;
color: var(--md-primary-fg-color);
}
.digest-preview-link {
font-size: 0.8rem;
color: #f59e0b;
text-decoration: none;
font-weight: 600;
letter-spacing: 0.02em;
}
.digest-preview-link:hover { text-decoration: underline; }
.digest-preview-list {
list-style: none;
margin: 0;
padding: 0;
}
.digest-preview-list li {
padding: 5px 0;
border-bottom: 1px solid rgba(245, 158, 11, 0.08);
font-size: 0.875rem;
display: flex;
align-items: center;
gap: 8px;
}
.digest-preview-list li:last-child { border-bottom: none; }
.digest-preview-cat {
font-size: 0.7rem;
color: #f59e0b;
background: rgba(245, 158, 11, 0.1);
border-radius: 4px;
padding: 1px 6px;
white-space: nowrap;
}
/* Hero Showcase Image wrapper (4 cars in a container) */
.hero-showcase-wrapper {
margin: 24px auto;
+2 -2
View File
@@ -71,7 +71,7 @@ def find_title_duplicates(inventory: Dict, threshold: float = 0.85) -> List[Tupl
norm = normalize_title(title)
if len(norm) < 10:
continue
entries.append((url, norm, entry.get("stars", 0)))
entries.append((url, norm, entry.get("stars") or 0))
log_event(f"[Dedup] Building title index for {len(entries)} entries...")
@@ -105,7 +105,7 @@ def find_title_duplicates(inventory: Dict, threshold: float = 0.85) -> List[Tupl
def _entry_score(entry: Dict) -> Tuple:
return (
entry.get("stars", 0),
entry.get("stars") or 0,
1 if entry.get("ai_summary") else 0,
1 if entry.get("hierarchy") else 0,
len(entry.get("tags", [])),
+11 -32
View File
@@ -15,8 +15,8 @@ from src.logger import log_event
# ---------------------------------------------------------------------------
CNCF_LANDSCAPE_URL = "https://landscape.cncf.io/api/items" # Legacy, now SPA — fallback to GitHub topic search
GITHUB_API_BASE = "https://api.github.com"
GITHUB_RATE_DELAY = 0.75 # seconds between GitHub API calls to stay under 5000/hr
MAX_REPOS_DEFAULT = 500
GITHUB_RATE_DELAY = 0.5 # seconds between GitHub API calls (5000/hr limit = ~1.4/s safe)
MAX_REPOS_DEFAULT = 200 # cap per run — 200 × 0.5s = ~100s, well within CI timeout
ACTIVITY_STALENESS_DAYS = 30
# Community health thresholds
@@ -155,15 +155,15 @@ async def _fetch_repo_activity(
client: httpx.AsyncClient,
owner_repo: str,
) -> Tuple[int, int]:
"""Fetch open issue count and recent open PR count for a single repo.
"""Fetch open issue + PR count for a single repo in one API call.
Returns (open_issues_count, open_prs_count).
GitHub's open_issues_count includes PRs, so a single /repos endpoint
call is sufficient. Returns (open_issues_count, 0) — the caller uses
the combined metric for health classification.
"""
headers = _github_headers()
open_issues = 0
open_prs = 0
# Fetch repo-level stats (open_issues_count includes PRs on GitHub)
try:
resp = await client.get(
f"{GITHUB_API_BASE}/repos/{owner_repo}",
@@ -173,37 +173,15 @@ async def _fetch_repo_activity(
if resp.status_code == 200:
data = resp.json()
open_issues = data.get("open_issues_count", 0)
elif resp.status_code == 429:
# Rate limited — back off
await asyncio.sleep(5.0)
except Exception as e:
log_event(f"[WARN] GitHub repo fetch failed for {owner_repo}: {str(e)[:120]}")
await asyncio.sleep(GITHUB_RATE_DELAY)
# Fetch open PRs (page 1 only — we use total_count from search or headers)
try:
resp = await client.get(
f"{GITHUB_API_BASE}/repos/{owner_repo}/pulls",
headers=headers,
params={"state": "open", "sort": "created", "per_page": 1},
timeout=15.0,
)
if resp.status_code == 200:
# The total count of open PRs is not directly in the body for the
# list endpoint, but we can parse the Link header for the last page.
# As a simpler approach, the body is a list; if it has items the repo
# has open PRs. We use the repo-level open_issues_count as the
# combined metric (GitHub counts PRs as issues).
pr_data = resp.json()
if isinstance(pr_data, list) and len(pr_data) > 0:
# Parse Link header for total pages
link_header = resp.headers.get("Link", "")
last_match = re.search(r'page=(\d+)>;\s*rel="last"', link_header)
open_prs = int(last_match.group(1)) if last_match else len(pr_data)
except Exception as e:
log_event(f"[WARN] GitHub PRs fetch failed for {owner_repo}: {str(e)[:120]}")
await asyncio.sleep(GITHUB_RATE_DELAY)
return open_issues, open_prs
return open_issues, 0
def _classify_health(total_activity: int) -> str:
@@ -328,6 +306,7 @@ async def detect_license_changes(inventory: Dict) -> List[Dict]:
log_event("[License] No repos with stored licenses to check")
return []
candidates = candidates[:MAX_REPOS_DEFAULT] # cap to same limit as activity enrichment
log_event(f"[License] Checking {len(candidates)} repos for license changes")
changes: List[Dict] = []
+2 -2
View File
@@ -319,8 +319,8 @@ class NewsDigestEngine:
for cat_name, entries in category_pools.items():
entries.sort(
key=lambda x: (
x.get("stars", 0),
x.get("discovered_at", ""),
x.get("stars") or 0,
x.get("discovered_at") or "",
),
reverse=True,
)
+48 -1
View File
@@ -629,7 +629,7 @@ class V2VisionEngine:
# 1. GitHub Objective Reality (Mandate 43)
raw_gh = item.get("gh_stars", 0)
gh_stars = int(raw_gh) if str(raw_gh).isdigit() else 0
curator_stars = int(item.get("stars", 0))
curator_stars = int(item.get("stars") or 0)
if gh_stars > 15000 or curator_stars >= 5:
tags.add("[DE FACTO STANDARD]")
@@ -1055,6 +1055,45 @@ class V2VisionEngine:
" - **Status**: The system is incrementally processing pending resources to complete the knowledge graph.\n"
)
# Build digest-preview block for index
priority_cats = [
"Kubernetes & Orchestration", "AI & Agents", "Security & Compliance",
"Infrastructure as Code", "Observability, SRE & Testing", "CI/CD & GitOps"
]
cat_short = {
"Kubernetes & Orchestration": "Kubernetes",
"AI & Agents": "AI & Agents",
"Security & Compliance": "Security",
"Infrastructure as Code": "IaC",
"Observability, SRE & Testing": "Observability",
"CI/CD & GitOps": "CI/CD",
}
digest_preview_md = ""
if digest_data and "3_months" in digest_data:
preview_items = []
for cat in priority_cats:
entries = digest_data["3_months"].get(cat, [])
if entries:
e = entries[0]
title = nuclear_strip(e.get("title", ""))[:65]
preview_items.append((cat_short.get(cat, cat), title, e.get("url", "#")))
if preview_items:
rows = "\n".join(
f' <li><span class="digest-preview-cat">{c}</span> <a href="{u}">{t}</a></li>'
for c, t, u in preview_items[:5]
)
digest_preview_md = (
'<div class="digest-preview">\n'
' <div class="digest-preview-header">\n'
' <span class="digest-preview-title">📊 Intelligence Digest — Top Picks (Last 3 Months)</span>\n'
' <a href="./tech-digest/" class="digest-preview-link">View all 22 categories →</a>\n'
' </div>\n'
' <ul class="digest-preview-list">\n'
f'{rows}\n'
' </ul>\n'
'</div>\n\n'
)
index_md = (
"# Nubenetes Elite Portal (V2) | Awesome Kubernetes & Cloud [![Awesome](https://cdn.jsdelivr.net/gh/sindresorhus/awesome@d7305f38d29fed78fa85652e3a63e154dd8e8829/media/badge.svg)](https://github.com/sindresorhus/awesome)\n\n"
"!!! tip \"Nubenetes V2 Elite Portal: AI-Curated & High-Density\"\n"
@@ -1093,6 +1132,13 @@ class V2VisionEngine:
" <div class=\"hero-badge-subtitle\">Agentic Ecosystem</div>\n"
" </div>\n"
" </a>\n"
" <a href=\"./tech-digest/\" style=\"text-decoration: none; color: inherit; display: block;\">\n"
" <div class=\"hero-badge-card hero-badge-card--amber\">\n"
" <div class=\"hero-badge-icon\">📊</div>\n"
" <div class=\"hero-badge-title\">Intelligence Digest</div>\n"
" <div class=\"hero-badge-subtitle\">Top picks · 3/6/12 months</div>\n"
" </div>\n"
" </a>\n"
" <a href=\"./videos/\" style=\"text-decoration: none; color: inherit; display: block;\">\n"
" <div class=\"hero-badge-card hero-badge-card--pink\">\n"
" <img src=\"/images/video_hub_logo.png\" alt=\"Agentic Video Hub\"/>\n"
@@ -1113,6 +1159,7 @@ class V2VisionEngine:
"the system selects only the most relevant, stable, and impactful resources for the modern Cloud Native ecosystem (2026 and beyond).\n\n"
f"{coverage_info}\n\n"
f"<center markdown=\"1\">\n{mosaic_html}\n</center>\n\n"
f"{digest_preview_md}"
f"{pulse_md}\n\n"
"## Strategic Dimensions\n"
"- **[🎥 Agentic Video Hub (Architectural Summary)](./videos/index.md)**\n\n"
+21
View File
@@ -39,6 +39,13 @@
<div class="hero-badge-subtitle">Agentic Ecosystem</div>
</div>
</a>
<a href="./tech-digest/" style="text-decoration: none; color: inherit; display: block;">
<div class="hero-badge-card hero-badge-card--amber">
<div class="hero-badge-icon">📊</div>
<div class="hero-badge-title">Intelligence Digest</div>
<div class="hero-badge-subtitle">Top picks · 3/6/12 months</div>
</div>
</a>
<a href="./videos/" style="text-decoration: none; color: inherit; display: block;">
<div class="hero-badge-card hero-badge-card--pink">
<img src="/images/video_hub_logo.png" alt="Agentic Video Hub"/>
@@ -116,6 +123,20 @@
</div>
</center>
<div class="digest-preview">
<div class="digest-preview-header">
<span class="digest-preview-title">📊 Intelligence Digest — Top Picks (Last 3 Months)</span>
<a href="./tech-digest/" class="digest-preview-link">View all 22 categories →</a>
</div>
<ul class="digest-preview-list">
<li><span class="digest-preview-cat">Kubernetes</span> <a href="https://www.apptio.com/products/kubecost/?src=kc-com">Kubecost — real-time cost allocation for multi-cluster K8s</a></li>
<li><span class="digest-preview-cat">AI & Agents</span> <a href="https://docs.anthropic.com/en/docs/agents-and-tools/claude-code/overview">Claude Code CLI — agentic AI coding assistant</a></li>
<li><span class="digest-preview-cat">Security</span> <a href="https://github.com/policy-hub/policy-hub-cli">PolicyHub CLI — searchable Rego policy library</a></li>
<li><span class="digest-preview-cat">IaC</span> <a href="https://github.com/shuaibiyy/awesome-tf">Awesome Terraform — curated Terraform resources</a></li>
<li><span class="digest-preview-cat">Observability</span> <a href="https://grafana.com/blog/how-to-manage-high-cardinality-metrics-in-prometheus-and-kubernetes">Grafana: High cardinality metrics in Prometheus & K8s</a></li>
</ul>
</div>
## The Agentic Pulse
- **(2026)** [**==abarrak.gitbook.io: Linux SysOps Handbook 🌟==**](https://abarrak.gitbook.io/linux-sysops-handbook) 🌟🌟🌟🌟
- **(2026)** [**==Google I/O 2026 Official NotebookLM Document==**](https://accounts.google.com/v3/signin/identifier?continue=https%3A%2F%2Fnotebooklm.google.com%2Flogin%3Fcontinue%3Dhttps%3A%2F%2Fnotebooklm.google.com%2Fnotebook%2F87ae4230-9dda-445a-9775-df61ad7044dc%3Fauthuser%253D0%2526pageId%253Dnone&dsh=S-651079724%3A1780398802084305&followup=https%3A%2F%2Fnotebooklm.google.com%2Flogin%3Fcontinue%3Dhttps%3A%2F%2Fnotebooklm.google.com%2Fnotebook%2F87ae4230-9dda-445a-9775-df61ad7044dc%3Fauthuser%253D0%2526pageId%253Dnone&osid=1&passive=1209600&flowName=WebLiteSignIn&flowEntry=ServiceLogin&ifkv=AWa2PavtOIva2wcDqJnQlJq3nohbB8kL26HoI0qLEI-ErQFf9Roi9aGt-ViI1YzZGxXTHSAzER9n) 🌟🌟🌟🌟