36 Commits

Author SHA1 Message Date
Naomi Rue Golding
4467133bf5 feat(fallback): TTL default 30s + chain-probe decoupling + admin chain-tester UI (#78)
## Summary

Closes #78. Stacks on PR #77 (which carries #79's strict-freshness cache architecture); base is `feat/fallback-repo-binding` so #78's cache-architecture deps are already merged in.

Three pieces:

1. **TTL default 300 → 30s** — `cfg.fallback.cache_ttl_seconds` and `RepoSourceCache.__init__(ttl_seconds=30)`. `config-example.toml` updated. Self-heal window for transient bound-source failures shrinks 10×; the 30s bound is still long enough for hf_hub session consistency.

2. **Chain-probe decoupling — `core.probe_chain` pure function**. New `src/kohakuhub/api/fallback/core.py` with:
   - `ProbeAttempt` / `ProbeReport` dataclasses
   - `probe_chain(op, repo_type, namespace, name, sources, ...)` — pure async, no cache writes, no binding lock, no FastAPI request context
   - Per-op HTTP method dispatch (HEAD for resolve, POST for paths_info, GET for info/tree)
   - Reuses `utils.classify_upstream` so verdicts match production
   - Captures **body preview** (UTF-8 decoded, 4 KB cap, binary-safe fallback) and curated **response headers** per attempt
   - Sets `final_response` to the bound attempt's full shape so the UI can show what a production caller would receive
   - 100% coverage in `test_core.py` (31 tests)

3. **Admin Chain Tester UI** — single-page panel on `fallback-sources.vue`:
   - **System state — draft editor**. Independent of live config; ``Load from System`` deep-copies live sources into the draft; every edit toggles a "Draft modified" tag; ``Push to System`` runs strong-confirm + atomic `bulk-replace`; ``Discard Draft`` resets.
   - **User state — simulation**. Identity radio (anonymous / username / user_id) + free-form Authorization-header-style per-URL token overrides (the `Bearer xxx|url,token|...` shape, pre-decoded).
   - **Run + timeline**. Two run buttons: ``Simulate`` against the draft, ``Real`` against live config + impersonated identity. Result renders as final-outcome tag → bound source → per-attempt rows (status, X-Error-Code, curated headers, expandable body preview) → final response section.
   - Op selector uses HF-API-equivalent labels (`Repo info` / `List files` / `Resolve file` / `paths_info`).

## New backend endpoints

| Method | Path | Purpose |
|---|---|---|
| `PUT` | `/admin/api/fallback/sources-bulk-replace` | Atomic transactional replace of every `FallbackSource` row. Triggers `cache.clear()`. |
| `POST` | `/admin/api/fallback/test/simulate` | Run `probe_chain` with operator-supplied source list + per-URL token overlay. No cache writes. |
| `POST` | `/admin/api/fallback/test/real` | Run `probe_chain` against live `get_enabled_sources(...)`, optionally impersonating a user (DB tokens layered with header-style overrides per the production `get_merged_external_tokens` precedence). |

## Files touched

| File | Change |
|---|---|
| `src/kohakuhub/api/fallback/cache.py` | Default TTL 300 → 30. Updated docstring. |
| `src/kohakuhub/api/fallback/core.py` | **NEW** — pure `probe_chain` + `ProbeAttempt` / `ProbeReport`. |
| `src/kohakuhub/api/admin/routers/fallback.py` | Three new endpoints (bulk-replace + test/simulate + test/real). |
| `src/kohakuhub/config.py` | Default 300 → 30. |
| `config-example.toml` | Default + comment. |
| `src/kohaku-hub-admin/src/utils/api.js` | Three wrappers (`bulkReplaceFallbackSources`, `testFallbackChainSimulate`, `testFallbackChainReal`). |
| `src/kohaku-hub-admin/src/pages/fallback-sources.vue` | Chain Tester card (~600 added lines). |
| `test/kohakuhub/api/fallback/test_core.py` | **NEW** — 31 tests at 100% line coverage. |
| `test/kohakuhub/api/admin/routers/test_fallback_debug.py` | **NEW** — 21 tests for the three admin endpoints. |
| `test/kohaku-hub-admin/pages/test_fallback_sources_page.test.js` | Extended from 60 to 91 tests covering every tester flow. |
| `test/kohaku-hub-admin/utils/test_api.test.js` | Invocation + URL asserts for the three new wrappers. |

## Test plan

- [x] `pytest test/kohakuhub/api/fallback/test_core.py` — 31/31 pass; `core.py` 100% line coverage
- [x] `pytest test/kohakuhub/api/admin/routers/test_fallback_debug.py` — 21/21 pass
- [x] Combined fallback + admin coverage — `core.py` 100%, admin router 91% (only pre-existing CRUD exception handlers uncovered)
- [x] `npm test` — 91/91 pass; `fallback-sources.vue` 100% lines + statements, 96.47% branches
- [x] Backend regression suite (changed-area scope): **477 passed, 1 skipped** in 239s
- [x] `pnpm build` — admin SPA bundles cleanly
- [ ] CI matrix (Python 3.10/3.11/3.12 × hf_hub versions)

## Notes for reviewers

- The chain tester's probe is intentionally simpler than the production binding path (no HEAD-then-GET commit for resolve; single per-source call). The verdict (BIND_AND_RESPOND / BIND_AND_PROPAGATE / TRY_NEXT_SOURCE) matches production via the shared `classify_upstream`, so a tester says-it-binds source will bind in production too.
- `final_response` is `None` for `CHAIN_EXHAUSTED` — the production aggregate is built from `utils.build_aggregate_failure_response` which depends on op-specific scope semantics the tester deliberately doesn't impose. The per-attempt list is sufficient to diagnose what each source said.
- "Push to system" replaces every row atomically. There's no per-row Save anymore for draft edits — the user explicitly asked for batched-edit + final-save semantics in lieu of inline auto-save (matches the workflow in their direction).
- Live-server browser verification deferred to the user's own `make reset-and-seed backend` per their stated workflow; the SPA infrastructure is identical to PR #81's admin frontend (already Playwright-verified) and the page builds cleanly.

Refs: #78, #77, #79
2026-05-04 18:15:06 +08:00
Naomi Rue Golding
1993885026 Merge pull request #74 from deepghs/perf/cache-infra
perf(cache): Valkey-based L2 cache infrastructure (TODO 0 of #73)
2026-04-30 21:06:12 +08:00
narugo1992
aff9fd47ef perf(cache): add Valkey-based L2 cache infrastructure
Introduces the prerequisite cache layer tracked in #73. No business code
yet consumes the helpers — this is plumbing only, gated by
KOHAKU_HUB_CACHE_ENABLED (default: false). Subsequent issues will adopt
specific cache patterns on top of this foundation.

Why now: every hot read endpoint currently makes 1–3 LakeFS REST calls
plus several Postgres queries per request, with the only existing cache
being a per-process cachetools.TTLCache in fallback/cache.py — useless
across the default 4-worker uvicorn deployment.

Design highlights (full design in docs/development/cache.md):

- Pure cache, no source-of-truth state. Silent-degradation contract:
  every cache call is wrapped in try/except and falls back to L3 when
  Valkey is unreachable. CI runs a dedicated cache-disabled job to
  regression-guard this.
- L1 (per-worker cachetools) restricted to immutable / content-addressed
  data only — multi-worker uvicorn has no portable cross-worker
  invalidation channel, and constraining L1 to "key contains its own
  version" sidesteps that entirely.
- L2 (Valkey) holds everything. Helpers ship with TTL jitter (±15%
  default), two-level singleflight (asyncio.Lock + Valkey SET NX EX),
  negative cache, generation counters, and per-namespace metrics.
- Persistence: RDB on, AOF off, persistent volume. Mode-A
  (lakefs:commit, lakefs:stat, lakefs:list — commit_id-keyed) survives
  restart safely. Mode-B (mutable) namespaces are flushed on every
  Valkey restart by a run_id-based bootstrap coordinator that
  serializes the flush across workers.

Includes:

- src/kohakuhub/cache.py — the helper module (319 stmts, 83% coverage
  via the new test module).
- src/kohakuhub/api/admin/routers/cache.py — admin endpoints exposing
  hit/miss/error counters, Valkey memory state, and bootstrap-flush
  metadata.
- test/kohakuhub/test_cache.py — 34 tests against a real Valkey,
  covering: round-trips, TTL jitter spread, SCAN-based prefix delete
  over >SCAN_BATCH_SIZE keys, two-level singleflight (100 concurrent
  calls fold to 1 fetch), bootstrap flush selectivity (Mode-A survives,
  Mode-B is wiped, exactly), two-worker bootstrap coordination, silent
  degradation when Valkey is disabled OR unreachable, generation
  counters, negative cache, the Mode-B prefix list shape contract.
- docker-compose.example.yml — adds the valkey service with RDB +
  LFU + bind-mounted hub-meta/valkey-data, mirroring the persistence
  pattern of the other stateful services.
- scripts/dev/up_infra.sh / down_infra.sh / reset_local_data.sh —
  Valkey container plumbing for local dev (host port 26379).
- .github/workflows/fullstack-tests.yml — adds valkey to the existing
  matrix services and adds a separate single-Python job
  (backend-tests-cache-disabled) running with KOHAKU_HUB_CACHE_ENABLED=false
  as the silent-degradation contract regression guard.
- docs/development/cache.md — the design doc referenced by the cache
  module's docstrings.

Refs: #73

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-30 19:21:04 +08:00
lxy
498688087a 改为monorepo,使用pnpm 2026-04-29 21:03:37 +08:00
narugo1992
19ab0352f5 docs(lakefs): document v0.54.0+ minimum version requirement
The previous commit (perf(tree): use LakeFS path-filtered logCommits ...)
relies on the ``objects=`` / ``prefixes=`` / ``limit=`` query parameters on
``logCommits``, introduced in LakeFS v0.54.0 (released 2021-11-08).
Pre-v0.54 servers silently ignore those parameters and would surface
incorrect ``lastCommit`` metadata on the file-list ``expand=true`` page.

The shipped docker bundle pins ``treeverse/lakefs:latest`` so default
deployments are always compatible. The constraint only matters for
self-deployments that pin an older LakeFS image.

Document the requirement in:

  * README — Architecture/Stack line and the Quick Start "Prereq" callout.
  * docs/setup.md — new "Prerequisites" section.
  * docs/deployment.md — new "Component Version Requirements" section.
  * docs/deployment/production.md — new "Component Versions" section.
  * docs/deployment/docker.md — extended ``lakefs`` service description.

Code-side docstrings on ``LakeFSRestClient.log_commits`` and
``tree.resolve_last_commits_for_paths`` already carry the same note from
the original perf commit.
2026-04-29 13:50:07 +08:00
narugo1992
d0445282fb feat: pure-client safetensors/parquet metadata preview (#27)
Implements issue #27 v4: file-level HF-compatible metadata preview
computed entirely in the browser via HTTP Range reads against the
existing /resolve/ 302 → presigned S3/MinIO URL. Zero new backend
preview code, zero LRU, zero precomputation, zero new DB state.

Backend (minimal CORS plumbing only):
- main.py CORSMiddleware: add `expose_headers` so browsers can read
  Content-Range / X-Linked-* / X-Repo-Commit / ETag / Location off
  the final 206 response that follows the /resolve/ 302.
- docker-compose.example.yml + scripts/dev/up_infra.sh: wire
  `MINIO_API_CORS_ALLOW_ORIGIN` so the SPA can cross-origin Range-read
  presigned targets. Configurable via `DEV_MINIO_CORS_ALLOW_ORIGIN`.
- docs/development/local-dev.md: MinIO CORS section explaining the
  hard prerequisite + smoke-test probe + how to recreate the container.

Frontend:
- utils/safetensors.js (~190 LOC): pure-JS parser mirroring
  huggingface_hub.parse_safetensors_file_metadata byte-for-byte
  (speculative 100 KB first read, two-read fallback for fat headers,
  SAFETENSORS_MAX_HEADER_LENGTH guard). Exposes parseSafetensorsMetadata
  + summarizeSafetensors.
- utils/parquet.js: thin wrapper over hyparquet's asyncBufferFromUrl +
  parquetMetadataAsync with mode:"cors" + credentials:"omit" so cookies
  never leak onto presigned URLs. Normalizes BigInt row counts.
- components/repo/preview/FilePreviewDialog.vue: ElDialog with
  per-phase spinner text (range-head → parsing → done for safetensors,
  head → footer → parsing → done for parquet), dtype/row-group tables,
  and an explicit "CORS likely misconfigured" placeholder on failure.
- RepoViewer.vue: HF-style chart-line-data icon next to .safetensors
  and .parquet rows; click opens the modal with the resolved /resolve/
  URL for the current branch.

Tests + fixtures:
- test_files.py::test_resolve_get_302_exposes_cors_headers_for_browser_preview
  pins the `Access-Control-Expose-Headers` list against regressions.
- test/kohaku-hub-ui/utils/test_safetensors.test.js: 6 cases covering
  the real-HF-format fixture, dtype summary, progress phases, fat-header
  fallback, oversized-header guard, and non-206 error paths.
- test/kohaku-hub-ui/utils/test_parquet.test.js: footer parse +
  progress phase assertions.
- test/kohaku-hub-ui/fixtures/previews/{tiny.safetensors,tiny.parquet}:
  byte-identical-to-HF fixtures produced by the real safetensors /
  pyarrow libs via scripts/dev/generate_preview_test_fixtures.py
  (committed so tests stay offline per AGENTS.md §5.2).

Seed:
- seed_demo_data.py: add two RemoteAsset entries for real HF-hosted
  small fixtures pinned by sha256, and wire them into visible paths
  (open-media-lab/vision-language-assistant-3b/fixtures/hf-tiny-random-bert.safetensors,
  open-media-lab/multimodal-benchmark-suite/fixtures/hf-no-robots-test.parquet)
  so the preview can be exercised against files that actually came off
  huggingface.co rather than purely local pyarrow/safetensors output.
  SEED_VERSION bumped to local-dev-demo-v4.

Verified end-to-end against the dev stack: safetensors parser output
on the seeded fixtures matches huggingface_hub.parse_safetensors_file_metadata
byte-for-byte on the same file (100 tensors, 126,851 params, I64=512
/ F32=126,339, metadata `{format: pt, ...}`). Browser preview modal
renders both file kinds correctly.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-24 13:41:26 +08:00
narugo1992
f76a8d49f2 Refine local dev reset workflow 2026-04-21 12:50:30 +08:00
narugo1992
f448aa0be8 Stop loading .env inside tests 2026-04-20 12:39:12 +08:00
narugo1992
e12c5cce78 Add service-backed backend test workflow 2026-04-20 12:34:01 +08:00
narugo1992
0fac181a57 Add fast backend test harness and CI workflow 2026-04-19 22:14:32 +08:00
narugo1992
4c6dba6458 Add local development bootstrap and deterministic demo fixtures 2026-04-19 14:14:15 +08:00
migo
f41728fa60 fix(api): update path handling in file and directory conversion functions 2026-02-04 10:47:59 +08:00
Kohaku-Blueleaf
3c8f7ac1e2 seperate KohakuBoard to standalone repo 2025-10-29 16:57:23 +08:00
Kohaku-Blueleaf
c0efc9a026 tiny fixes 2025-10-29 16:02:48 +08:00
KohakuBlueleaf
c1ae4402e6 add comprehensive docs for kohakuboard 2025-10-29 14:59:43 +08:00
Kohaku-Blueleaf
817344654b clean up redundant test script/temp doc 2025-10-28 21:15:46 +08:00
Kohaku-Blueleaf
6b88fbc4b6 KohakuBoard related doc early version 2025-10-27 12:28:08 +08:00
Kohaku-Blueleaf
37c431b3ea KohakuBoard related doc early version 2025-10-27 12:27:48 +08:00
Kohaku-Blueleaf
88a2e3c328 update document for APIs 2025-10-24 18:45:55 +08:00
Kohaku-Blueleaf
e4658f831f add licensing doc 2025-10-24 16:28:27 +08:00
Kohaku-Blueleaf
2ca4cdb2bc update docs for non-commercial features and add agpl only build 2025-10-24 16:08:59 +08:00
Kohaku-Blueleaf
edaee890db update doc and Docker related utils 2025-10-22 23:25:41 +08:00
Kohaku-Blueleaf
5ef51adb95 update all documents 2025-10-22 02:42:35 +08:00
Kohaku-Blueleaf
d5e7edcd0d update documents 2025-10-20 15:21:30 +08:00
Kohaku-Blueleaf
ae09f94b91 update whole doc system 2025-10-20 01:36:48 +08:00
Kohaku-Blueleaf
ef35a514de Update documents 2025-10-18 12:01:44 +08:00
Kohaku-Blueleaf
51c1a936ca Update documents 2025-10-14 22:53:48 +08:00
Kohaku-Blueleaf
a023ba593b update docs 2025-10-11 22:28:24 +08:00
Kohaku-Blueleaf
1a7100a586 minor fixes 2025-10-11 13:03:58 +08:00
Kohaku-Blueleaf
25341dfe2f add docker compose generator 2025-10-10 17:18:03 +08:00
Kohaku-Blueleaf
a4bfc18b2e Minor fix for frontend, Update documents 2025-10-09 18:02:25 +08:00
Kohaku-Blueleaf
10163f4d50 clean up 2025-10-09 15:47:18 +08:00
Kohaku-Blueleaf
45fccb6af8 fix LFS handle 2025-10-09 13:05:41 +08:00
Kohaku-Blueleaf
5ca5336528 Add git clone implementation 2025-10-09 03:53:52 +08:00
Kohaku-Blueleaf
a299394dea update documents 2025-10-06 15:14:03 +08:00
Kohaku-Blueleaf
e719fd0768 update all documents 2025-10-05 22:56:17 +08:00