Koder hub coverage

Koder Hub — Publication Coverage Registry

Tracks which Koder Stack components are reachable via the Hub publication API GET https://hub.koder.dev/api/v1/apps/<slug>. Source of registered components: registries/component-names.md.

The audit probes three name variants per row of the source registry (type ∈ {product, service, engine}meta and umbrella types are non-publishable and excluded):

  1. <slug> — the canonical registry slug
  2. <aliases[0]> — the first coloquial alias, if any
  3. koder-<aliases[0]> — the registry-noncompliant compound form

A row passes when (1) returns HTTP 200. The other variants are auxiliary: a 200 on (2) or (3) without (1) means the package was published under a noncanonical name and should be republished under <slug> (the registry is authoritative; release engineering should align with it).

Status values

Value Meaning
*K_CANONICAL* Published as <slug> (registry-aligned)
*RIFT_AS:name* Published only as <name>, where <name> ≠ <slug>
*UAL* Both <slug> and a non-canonical variant return 200
*ISSING* None of the probed variants exist (expected for components that have not shipped a first release)
*RR* Probe error (rate-limit retry exhausted or network)

Last audit: 20260520 (Kruze + Box spot probes)

Spot probe 20260520: GET https://hub.koder.dev/api/v1/apps/koder-kruze → HTTP 200, slug=koder-kruze, version 1.0.20 (Flow has v1.0.23). Aliased kruze → HTTP 404. Classified *K_CANONICAL* row added under that section. Hub-side version drift tracked in products/horizontal/kruze/app/backlog/pending/157. Kruze had been absent from component-names.md until this commit landed the row.

Spot probe 20260520: GET https://hub.koder.dev/api/v1/apps/koder-box → HTTP 404; kbox alias → HTTP 404. Classified MISSING; row added below. Follow-up to publish tracked in infra/net/box/backlog/pending/107.

Previous audit: 20260514 (post #119 data fix)

Probed via curl -sS https://hub.koder.dev/api/v1/apps/<name> with 0.3s between requests + exponential backoff on 429.

Total publishable components (product+service+engine from component-names.md): *15*

State Count
OK_CANONICAL 25
DRIFT_AS 0
DUAL 0
MISSING 89

#119 data fix — completed 20260514

All 5 non-aligned publications resolved. The 4 DRIFT cases were renamed via PATCH /api/v1/publish/<old-slug>/rename (#107 primitive: atomically updates apps.slug to canonical AND records old_slug in slug_reservations AND prepends to previous_slugs). Old URLs continue resolving to the canonical record by app_id — verified postrename: `GET apps<oldslug> and GET appscanonical-slug return the same id. The DUAL case (kmail + koder-mail) was deduplicated by archiving the kmail record (soft delete; hard delete is gated by KODERHUBDEV_DESTRUCTIVE=1 and not enabled in production — acceptable since kmail` v1.0.0 was a placeholder seed with no real downloads).

Registry slug Old slug App ID Action Pre-state Post-state
koder-term kterm a4c343cd1830fa2e24724c997eb36112 rename kterm 200 / koder-term 404 both 200, same id
koder-icon kicon a181b8f67ddcab31e9fb0690e7649c60 rename kicon 200 / koder-icon 404 both 200, same id
koder-pkg koder-kpkg 4dc5ee97514ee0207a95597f5c011a33 rename koder-kpkg 200 / koder-pkg 404 both 200, same id
koder-termux koder-ktermux a118be2aaa6f80a58c933f1d3f5b2a67 rename koder-ktermux 200 / koder-termux 404 both 200, same id
koder-mail kmail (id 0583031114687b1746a1e1eac7ae48c0) cdfa21dddf5546d0bc9b31ce31260c16 archive kmail both 200 (different ids) kmail 404, koder-mail 200

Bonus alias-resolution behavior

After rename, GET /api/v1/apps/<old-slug> returns HTTP 200 with the canonical record in the body (not 301 as the handler intends via ResolveSlughttp.Redirect path). Cause: kdbnext keeps the stale idxAppBySlug secondary index entry pointing the old slug at the app row, so GetAppBySlug(old) still succeeds and ResolveSlug returns redirected=false. This is friendlier than 301 for clients (no extra round-trip) but indicates the index update should be investigated as a follow-up — see products/dev/hub/backlog/pending/ for the index-cleanup ticket if/when one is opened. *unctionally*the outcome matches the #119 acceptance criterion: alias and canonical resolve to the same id.


OK_CANONICAL (27)

Slug Alias Hub version
koder-flow kflow v1.0.0
koder-hub khub v2.29.87
koder-eye keye v1.0.0
kode v1.7.9
koder-tools ktools v0.3.2
koder-sky ksky v1.0.2
koder-domains kdomains v1.0.0
koder-talk ktalk v1.0.1
koder-chat kchat v0.1.4
koder-drive kdrive v1.20.0
koder-calc kcalc v1.0.2
koder-beats kbeats v1.0.0
koder-craft kcraft v1.0.0
koder-dek v1.9.30
koder-flash kflash v1.0.0
koder-sign ksign v1.0.2
koder-id kid v1.0.0
koder-pass kpass v1.0.6
koder-bot kbot v1.1.2
koder-cloud kcloud v1.0.0
koder-dash kdash v1.0.0
koder-term kterm v1.32.1 (renamed from kterm 20260514)
koder-icon kicon v0.2.9 (renamed from kicon 20260514)
koder-pkg kpkg v1.0.0 (renamed from koder-kpkg 20260514)
koder-termux ktermux v0.118.3-koder1 (renamed from koder-ktermux 20260514)
koder-mail kmail v1.0.0 (DUAL deduplicated 20260514; kmail archived)
koder-kruze kruze v1.0.20 (added 20260520; spot probe — Hub still serving 1.0.20 while Flow has v1.0.21v1.0.22v1.0.23 published. Hubside bump tracked in `productshorizontalkruzeappbacklogpending157hubversiondrift.md, blocked on Hub admin endpoint per productsdevhub#116#117#103. Aliased probe kruze → 404 as expected; registry-canonical slug is koder-kruze`)

MISSING (89)

Most of these are aspirational components — registered in component-names.md for naming reservation but not yet shipped a first release. No action needed until the component has artifacts to publish.

Slug Alias
koder-bridge kbridge
koder-box kbox
koder-dev kdev
koder-notebook knotebook
koder-pages kpages
koder-grid kgrid
koder-ci
krypt
koder-cal kcal
koder-board kboard
koder-cine kcine
koder-crew kcrew
koder-dok
koder-form kform
koder-hand khand
koder-imago
kall
kampus
kanvas
koru
koder-relay krelay

…and 69 others (full list regenerable from the probe script below).


Refresh procedure

# Extract (type, slug, alias) from registry
awk -F'|' '
  /^\| (product|service|engine|meta|umbrella) \|/ {
    type=$2; slug=$5; alias=$7
    gsub(/^[ \t]+|[ \t]+$/, "", type); gsub(/^[ \t]+|[ \t]+$/, "", slug); gsub(/^[ \t]+|[ \t]+$/, "", alias)
    n=split(alias, parts, ";"); first=parts[1]
    gsub(/^[ \t]+|[ \t]+$/, "", first)
    print type "\t" slug "\t" first
  }
' meta/docs/stack/registries/component-names.md > /tmp/registry-slugs.tsv

# Probe Hub (Python script, rate-limited with 0.3s + backoff on 429)
python3 - <<'PY'
import urllib.request, json, time
from urllib.error import HTTPError, URLError
def probe(s, retries=3):
    for a in range(retries):
        try:
            with urllib.request.urlopen(f"https://hub.koder.dev/api/v1/apps/{s}", timeout=10) as r:
                d = json.load(r); return 200, d.get('version','?')
        except HTTPError as e:
            if e.code == 429 and a < retries-1: time.sleep(2*(a+1)); continue
            return e.code, '-'
        except (URLError, Exception) as e: return -1, str(e)[:30]
with open('/tmp/registry-slugs.tsv') as f:
    for line in f:
        t, s, al = (line.rstrip().split('\t') + ['',''])[:3]
        if t not in ('product','service','engine'): continue
        sc, sv = probe(s); time.sleep(0.3)
        ac, av = probe(al) if al else ('', '');  time.sleep(0.3) if al else None
        ka = f"koder-{al}" if al and not al.startswith("koder-") else al
        kc, kv = (probe(ka) if (al and ka != s) else ('', ''))
        print(f"{t}\t{s}\t{al}\t{sc}({sv})\t{ac}({av})\t{kc}({kv})")
PY

  • registries/component-names.md — source of truth for slugs (authoritative)
  • specs/naming/forms.kmd — naming rules (R1R6, T1T11)
  • specs/binaries-and-cli/naming.kmd — binary name derivation (aliases[0] || slug)

Audit cadence

  • Refresh on every Hub publication/unpublication.
  • Drift cases block release engineering for affected components until

    the publication is realigned with `componentnames.md`.

  • MISSING rows are informational only; not a block.

Companion CI workflow

.gitea/workflows/audit-hub-coverage.yml runs the probe automatically:

  • *chedule:*daily at 04:17 BRT
  • *riggers:*push touching component-names.md,

    koder-hub-coverage.md, or the workflow file itself; manual via workflow_dispatch

  • *utput:*state counts in workflow summary + drift/dual table

    attached as artifact (hub-coverage-tsv, 30-day retention)

  • *ate:*soft-fails if DRIFT_AS + DUAL exceeds baseline (5) + 1,

    catching new drift without false-flagging the documented state. Tighten to "any drift = fail" once the 5 known cases are resolved.

Manual refresh of this document remains a human task — the workflow exposes regressions but does not auto-edit the prose.

Source: ../home/koder/dev/koder/meta/docs/stack/registries/koder-hub-coverage.md