Skip to content

Add hosted catalog snapshot fallback#95877

Merged
giodl73-repo merged 3 commits into
mainfrom
feeds-hosted-catalog-snapshot-cache
Jun 27, 2026
Merged

Add hosted catalog snapshot fallback#95877
giodl73-repo merged 3 commits into
mainfrom
feeds-hosted-catalog-snapshot-cache

Conversation

@giodl73-repo

@giodl73-repo giodl73-repo commented Jun 22, 2026

Copy link
Copy Markdown
Contributor

Hosted Marketplace Feed Stack

This is PR3 in the hosted marketplace feed stack. The stack should land in order, with maintainer review at each step before the later PRs wire hosted marketplace data into broader user flows.

  1. Refactor external plugin catalog toward feeds #95846: refactor the bundled external plugin catalog toward the feed-shaped data model.
  2. Add hosted external catalog feed loader #95868: add the lazy hosted marketplace feed loader for the configured public feed URL, with guarded HTTPS fetch, checksum, schema, size, timeout, and bundled fallback behavior.
  3. Add hosted catalog snapshot fallback #95877: add accepted hosted snapshot fallback so a failed or unchanged hosted fetch can reuse the last valid feed payload.
  4. Persist hosted catalog snapshots in state #95964: persist hosted marketplace feed snapshots in OpenClaw state.
  5. Add hosted catalog source profile validation #95969: add marketplace source profile validation for hosted feed install candidates.
  6. Add hosted catalog config profiles #95981: add configurable marketplaces.feeds and marketplaces.sources profiles.
  7. Add marketplace feed refresh command #96155: add openclaw plugins marketplace refresh as the explicit manual snapshot refresh path.
  8. Add marketplace feed entries command #96158: add openclaw plugins marketplace entries as the explicit manual read path over hosted, snapshot, or bundled fallback entries.
  9. Add marketplace feed telemetry #96194: add marketplace feed telemetry.

The broader follow-up after this stack is to decide whether and how marketplace entries should feed install/search/startup behavior, add automatic conditional refresh using ETag / Last-Modified, or move to ClawHub producer-side validation for /v1/feeds/plugins and /v1/feeds/skills.

Journey Context

This is step 3 of the hosted OpenClaw feed path from RFC 19. #95846 made the bundled catalog feed-shaped. #95868 added guarded hosted fetch. This PR adds the last-known-good snapshot contract that makes the hosted path safe when the register endpoint is unchanged or temporarily unhealthy.

Current head 5f71635bba is restacked on main after #95868 merged.

What This PR Does

  • Adds a narrow HostedOfficialExternalPluginCatalogSnapshotStore interface.
  • Adds an in-memory snapshot store for tests and future runtime binding.
  • Writes the exact hosted response body plus hosted metadata and savedAt after a successful hosted load.
  • Uses a cached snapshot on 304, non-OK hosted responses, invalid hosted JSON/schema, or fetch failures.
  • Validates cached snapshot body checksum before use.
  • Validates cached snapshot schema before use.
  • Preserves expectedSha256 pinning for snapshots, so a stale cached body cannot satisfy a caller-pinned checksum it does not match.
  • Honors request validators when serving snapshots, so conditional callers do not reuse a stale URL-only snapshot after ETag / Last-Modified changes.
  • Falls back to the bundled catalog when no valid snapshot exists.

What This PR Intentionally Does Not Do

This PR does not choose a production persistence location, wire SQLite/runtime storage, enable the hosted loader by default, add source profiles, add auth, add signed envelopes, add regional feeds, or change search/install behavior. It defines the loader-level snapshot semantics that a later runtime-owned persistent store can bind to.

How To Review

Review this as fallback semantics, not as the final storage implementation. The key behavior is: hosted feed first, validated last-known-good snapshot second, bundled catalog last. A snapshot write failure is intentionally non-fatal because a good hosted response should still be usable even if cache persistence fails.

Validation

  • pnpm exec oxlint --deny-warnings src/plugins/official-external-plugin-catalog.ts src/plugins/official-external-plugin-catalog.test.ts
  • pnpm exec oxfmt --check src/plugins/official-external-plugin-catalog.ts src/plugins/official-external-plugin-catalog.test.ts
  • git diff --check
  • CI=1 node scripts/test-projects.mjs src/plugins/official-external-plugin-catalog.test.ts (33 tests)
  • codex review --base origin/main reported no actionable correctness issues.
  • Live guarded snapshot proof: node --import tsx - source harness against https://clawhub.ai/v1/feeds/plugins with a file-backed snapshot store under C:\tmp\openclaw-feeds-proof\pr95877-live-snapshot.

Real Behavior Proof

Behavior or issue addressed:
The hosted loader reuses a last-known-good hosted snapshot when a later hosted fetch cannot provide an acceptable fresh payload, while refusing stale snapshots when the caller supplied request validators that no longer match the snapshot metadata.

Real environment tested:
Windows checkout C:\src\openclaw-prflow\.worktrees\pr-95877 at head 5f71635bba, live guarded HTTPS fetch to https://clawhub.ai/v1/feeds/plugins, and a file-backed HostedOfficialExternalPluginCatalogSnapshotStore writing the exact snapshot body and metadata to C:\tmp\openclaw-feeds-proof\pr95877-live-snapshot\official-external-plugin-catalog.snapshot.json.

Exact steps or command run after this patch:

  1. pnpm exec oxlint --deny-warnings src/plugins/official-external-plugin-catalog.ts src/plugins/official-external-plugin-catalog.test.ts
  2. pnpm exec oxfmt --check src/plugins/official-external-plugin-catalog.ts src/plugins/official-external-plugin-catalog.test.ts
  3. git diff --check
  4. CI=1 node scripts/test-projects.mjs src/plugins/official-external-plugin-catalog.test.ts
  5. codex review --base origin/main
  6. node --import tsx - with a source harness that:
    • calls loadHostedOfficialExternalPluginCatalogEntries({ snapshotStore }) against the live default feed,
    • persists the successful hosted response through a file-backed snapshot store,
    • calls loadHostedOfficialExternalPluginCatalogEntries({ snapshotStore, ifNoneMatch: first.metadata.etag }), and
    • verifies the second conditional request returns source: "hosted-snapshot" with error: "hosted catalog feed returned HTTP 304".

Evidence after fix:

Test Files  1 passed (1)
Tests  33 passed (33)
[test] passed 1 Vitest shard in 27.60s

Codex review: No actionable correctness issues were found in the changed catalog snapshot logic or its adjacent tests.

Live guarded snapshot proof output:
{
  "repoHead": "5f71635bbafe75c8109248da66b297b8ee4f9657",
  "feedUrl": "https://clawhub.ai/v1/feeds/plugins",
  "snapshotPath": "C:\\tmp\\openclaw-feeds-proof\\pr95877-live-snapshot\\official-external-plugin-catalog.snapshot.json",
  "firstLoad": {
    "source": "hosted",
    "status": 200,
    "entries": 59,
    "feedId": "clawhub-official",
    "sequence": 16,
    "etag": "\"sha256:cf3d85c1d6ede1907ca265e9b214ac6ff1c715c90c30ec65e8017addb590e32d-gzip\"",
    "lastModified": "Sat, 27 Jun 2026 18:43:36 GMT",
    "checksum": "sha256:cf3d85c1d6ede1907ca265e9b214ac6ff1c715c90c30ec65e8017addb590e32d"
  },
  "secondConditionalLoad": {
    "requestIfNoneMatch": "\"sha256:cf3d85c1d6ede1907ca265e9b214ac6ff1c715c90c30ec65e8017addb590e32d-gzip\"",
    "source": "hosted-snapshot",
    "status": 200,
    "entries": 59,
    "feedId": "clawhub-official",
    "sequence": 16,
    "error": "hosted catalog feed returned HTTP 304",
    "snapshotSavedAt": "2026-06-27T20:54:47.927Z"
  },
  "persistedSnapshot": {
    "url": "https://clawhub.ai/v1/feeds/plugins",
    "savedAt": "2026-06-27T20:54:47.927Z",
    "etag": "\"sha256:cf3d85c1d6ede1907ca265e9b214ac6ff1c715c90c30ec65e8017addb590e32d-gzip\"",
    "checksum": "sha256:cf3d85c1d6ede1907ca265e9b214ac6ff1c715c90c30ec65e8017addb590e32d",
    "bytes": 21942
  }
}

Observed result after fix:
The live proof first loaded the ClawHub feed over the guarded hosted path and persisted a snapshot. The second load sent the returned live ETag as If-None-Match, received HTTP 304 from the live service, validated the persisted snapshot metadata/body, and returned source: "hosted-snapshot" with the same 59-entry clawhub-official sequence 16 feed.

What was not tested:
This PR still does not test production SQLite persistence because that is the next PR in the stack. This proof uses a file-backed implementation of the snapshot-store interface to exercise the loader contract with the live hosted feed.

@giodl73-repo
giodl73-repo force-pushed the feeds-hosted-catalog-snapshot-cache branch from b1cb838 to b486def Compare June 23, 2026 16:11
@clawsweeper

clawsweeper Bot commented Jun 23, 2026

Copy link
Copy Markdown
Contributor

Codex review: needs maintainer review before merge. Reviewed June 27, 2026, 5:05 PM ET / 21:05 UTC.

Summary
The PR adds a hosted catalog snapshot-store contract and in-memory test store, writes validated hosted payload snapshots, and returns a validated hosted-snapshot fallback before bundled fallback.

PR surface: Source +157, Tests +302. Total +459 across 2 files.

Reproducibility: not applicable. this is a feature PR, not a bug report. The relevant proof path is source inspection plus the PR body's copied live-output run showing hosted snapshot reuse after HTTP 304.

Review metrics: 2 noteworthy metrics.

  • Hosted Result Mode: 1 added: hosted-snapshot. A new accepted data source changes how follow-up marketplace callers can interpret freshness and fallback.
  • Snapshot Store Surface: 1 exported interface, 1 in-memory implementation added. The exported seam is likely to become the contract later persistent snapshot storage binds to.

Stored data model
Persistent data-model change detected: database schema: src/plugins/official-external-plugin-catalog.test.ts, serialized state: src/plugins/official-external-plugin-catalog.test.ts, vector/embedding metadata: src/plugins/official-external-plugin-catalog.ts. Confirm migration or upgrade compatibility proof before merge.

Root-cause cluster
Relationship: canonical
Canonical: #95877
Summary: This PR is the canonical open stack slice for loader-level hosted catalog snapshot fallback; related stack PRs are predecessors or follow-up rollout slices rather than duplicates.

Members:

Proposal only: this assessment does not dispatch repair, suppress jobs, mutate sibling items, close, or merge anything.

Merge readiness
Overall: 🦞 diamond lobster
Proof: 🦞 diamond lobster
Patch quality: 🦞 diamond lobster
Result: ready for maintainer review.

Overall follows the weaker of proof and patch quality, so missing proof can cap an otherwise strong patch.

Risk before merge

  • [P1] Merging this slice establishes loader-level last-known-good remote feed trust semantics that follow-up persistence, CLI, install, and search slices may consume.
  • [P1] The protected maintainer label and stack body mean this hosted marketplace sequence needs explicit human stack review before merge.

Maintainer options:

  1. Accept The Loader Contract After Stack Review (recommended)
    Maintainers can land this slice once they are comfortable that validated last-known-good hosted snapshots are the intended fallback contract for later marketplace surfaces.
  2. Hold Until Persistence Is Reviewed
    Pause this PR if maintainers want to evaluate the in-memory contract together with the SQLite-backed follow-up before accepting the fallback behavior.
  3. Narrow The Snapshot API First
    If maintainers do not want this exported loader seam yet, ask for a smaller internal-only contract before any persistent store binds to it.

Next step before merge

  • [P2] Protected maintainer labeling and remote feed trust semantics require human stack acceptance; there is no narrow automated repair to queue.

Security
Cleared: No concrete security or supply-chain defect was found in the diff; remote feed snapshot trust remains an explicit maintainer merge-risk decision.

Review details

Best possible solution:

Have maintainers review and either accept this loader-level snapshot trust contract before the persistence/config/CLI follow-ups, or hold it until they want the hosted marketplace stack evaluated together.

Do we have a high-confidence way to reproduce the issue?

Not applicable: this is a feature PR, not a bug report. The relevant proof path is source inspection plus the PR body's copied live-output run showing hosted snapshot reuse after HTTP 304.

Is this the best way to solve the issue?

Yes for the loader-level slice: the implementation is bounded to the hosted catalog loader and validates checksum, schema, expected pins, and request validators before using a snapshot. The merge decision still depends on maintainer acceptance of the remote snapshot trust contract.

AGENTS.md: found and applied where relevant.

Codex review notes: model internal, reasoning high; reviewed against 1b8b8500cee0.

Label changes

Label justifications:

  • P2: This is normal-priority hosted marketplace infrastructure with limited immediate user blast radius but meaningful maintainer-review needs.
  • merge-risk: 🚨 compatibility: The PR changes official catalog fallback semantics by adding a last-known-good source that later marketplace paths may depend on.
  • merge-risk: 🚨 security-boundary: The PR handles remote marketplace feed snapshot trust, including URL, checksum, schema, validator, and fallback behavior.
  • rating: 🦞 diamond lobster: Overall readiness is 🦞 diamond lobster; proof is 🦞 diamond lobster and patch quality is 🦞 diamond lobster.
  • status: 👀 ready for maintainer look: ClawSweeper has no concrete contributor-facing blocker left for this PR. Sufficient (live_output): The PR body includes copied live output from a real Windows checkout at head 5f71635 showing live ClawHub fetch, file-backed snapshot persistence, and hosted-snapshot reuse after HTTP 304.
  • proof: sufficient: Contributor real behavior proof is sufficient. The PR body includes copied live output from a real Windows checkout at head 5f71635 showing live ClawHub fetch, file-backed snapshot persistence, and hosted-snapshot reuse after HTTP 304.
Evidence reviewed

PR surface:

Source +157, Tests +302. Total +459 across 2 files.

View PR surface stats
Area Files Added Removed Net
Source 1 179 22 +157
Tests 1 303 1 +302
Docs 0 0 0 0
Config 0 0 0 0
Generated 0 0 0 0
Other 0 0 0 0
Total 2 482 23 +459

What I checked:

Likely related people:

  • giodl73-repo: Merged current-main history shows this account authored the feed-shaped catalog and hosted loader commits that this PR extends. (role: feature-history owner; confidence: high; commits: 4010b81a77f4, c29e1fe764f3; files: src/plugins/official-external-plugin-catalog.ts, src/plugins/official-external-plugin-catalog.test.ts, scripts/lib/official-external-plugin-catalog.json)
  • Patrick-Erichsen: Live PR metadata shows approval on this PR and on the merged hosted-loader predecessor in the same stack. (role: reviewer; confidence: medium; commits: 4010b81a77f4, c29e1fe764f3; files: src/plugins/official-external-plugin-catalog.ts)
What the crustacean ranks mean
  • 🦀 challenger crab: rare, exceptional readiness with strong proof, clean implementation, and convincing validation.
  • 🦞 diamond lobster: very strong readiness with only minor maintainer review expected.
  • 🐚 platinum hermit: good normal PR, likely mergeable with ordinary maintainer review.
  • 🦐 gold shrimp: useful signal, but proof or patch confidence is still limited.
  • 🦪 silver shellfish: thin signal; proof, validation, or implementation needs work.
  • 🧂 unranked krab: not merge-ready because proof is missing/unusable or there are serious correctness or safety concerns.
  • 🌊 off-meta tidepool: rating does not apply to this item.

Shiny media proof means a screenshot, video, or linked artifact directly shows the changed behavior. Runtime, network, CSP, and security claims still need visible diagnostics.

How this review workflow works
  • ClawSweeper keeps one durable marker-backed review comment per issue or PR.
  • Re-runs edit this comment so the latest verdict, findings, and automation markers stay together instead of adding duplicate bot comments.
  • A fresh review can be triggered by eligible @clawsweeper re-review comments, exact-item GitHub events, scheduled/background review runs, or manual workflow dispatch.
  • PR/issue authors and users with repository write access can comment @clawsweeper re-review or @clawsweeper re-run on an open PR or issue to request a fresh review only.
  • Maintainers can also comment @clawsweeper review to request a fresh review only.
  • Fresh-review commands do not start repair, autofix, rebase, CI repair, or automerge.
  • Maintainer-only repair and merge flows require explicit commands such as @clawsweeper autofix, @clawsweeper automerge, @clawsweeper fix ci, or @clawsweeper address review.
  • Maintainers can comment @clawsweeper explain to ask for more context, or @clawsweeper stop to stop active automation.

@clawsweeper clawsweeper Bot added rating: 🧂 unranked krab Not merge-ready due to missing proof or serious correctness/safety concerns. status: 📣 needs proof The PR needs real behavior proof before ClawSweeper can clear the contributor ask. P2 Normal backlog priority with limited blast radius. labels Jun 23, 2026
@clawsweeper clawsweeper Bot added merge-risk: 🚨 compatibility 🚨 May break existing users, config, migrations, defaults, or upgrade paths. merge-risk: 🚨 security-boundary 🚨 May affect sandboxing, authorization, credentials, or sensitive data. labels Jun 24, 2026
@giodl73-repo

Copy link
Copy Markdown
Contributor Author

@clawsweeper re-review

@clawsweeper

clawsweeper Bot commented Jun 24, 2026

Copy link
Copy Markdown
Contributor

🦞🧹
ClawSweeper re-review requested.

I asked ClawSweeper to review this item again.
Action: item re-review queued (workflow sweep.yml, event repository_dispatch).
Result: the existing ClawSweeper review comment will be edited in place when the review finishes.

@giodl73-repo

Copy link
Copy Markdown
Contributor Author

@clawsweeper re-review

@clawsweeper

clawsweeper Bot commented Jun 24, 2026

Copy link
Copy Markdown
Contributor

🦞🧹
ClawSweeper re-review requested.

I asked ClawSweeper to review this item again.
Action: item re-review queued (workflow sweep.yml, event repository_dispatch).
Result: the existing ClawSweeper review comment will be edited in place when the review finishes.

@clawsweeper clawsweeper Bot added rating: 🦪 silver shellfish Thin PR readiness signal; proof, validation, or implementation needs work. and removed rating: 🧂 unranked krab Not merge-ready due to missing proof or serious correctness/safety concerns. labels Jun 24, 2026
@giodl73-repo
giodl73-repo force-pushed the feeds-hosted-catalog-snapshot-cache branch from 68a85a8 to be8678a Compare June 26, 2026 05:26
@giodl73-repo

Copy link
Copy Markdown
Contributor Author

@clawsweeper re-review

@clawsweeper

clawsweeper Bot commented Jun 26, 2026

Copy link
Copy Markdown
Contributor

🦞🧹
ClawSweeper re-review requested.

I asked ClawSweeper to review this item again.
Action: item re-review queued (workflow sweep.yml, event repository_dispatch).
Result: the existing ClawSweeper review comment will be edited in place when the review finishes.

@giodl73-repo
giodl73-repo force-pushed the feeds-hosted-catalog-snapshot-cache branch from be8678a to 5f71635 Compare June 27, 2026 20:41
@openclaw-barnacle openclaw-barnacle Bot removed the scripts Repository scripts label Jun 27, 2026
@giodl73-repo
giodl73-repo marked this pull request as ready for review June 27, 2026 20:42
@giodl73-repo

Copy link
Copy Markdown
Contributor Author

@clawsweeper re-review

Restacked after #95868 and pushed current proof at 5f71635. Please review the current head.

@clawsweeper

clawsweeper Bot commented Jun 27, 2026

Copy link
Copy Markdown
Contributor

🦞🧹
ClawSweeper re-review requested.

I asked ClawSweeper to review this item again.
Action: item re-review queued (workflow sweep.yml, event repository_dispatch).
Result: the existing ClawSweeper review comment will be edited in place when the review finishes.

@giodl73-repo

Copy link
Copy Markdown
Contributor Author

@clawsweeper re-review

Added live guarded ClawHub snapshot proof to the PR body for current head 5f71635: first load writes a file-backed snapshot, second conditional load sends If-None-Match and returns source=hosted-snapshot after HTTP 304.

@clawsweeper clawsweeper Bot added proof: sufficient ClawSweeper judged the real behavior proof convincing. rating: 🦞 diamond lobster Very strong PR readiness with only minor maintainer review expected. status: 👀 ready for maintainer look ClawSweeper has no concrete contributor-facing blocker left for this PR. and removed rating: 🦪 silver shellfish Thin PR readiness signal; proof, validation, or implementation needs work. status: 📣 needs proof The PR needs real behavior proof before ClawSweeper can clear the contributor ask. labels Jun 27, 2026
@giodl73-repo
giodl73-repo merged commit 12685ee into main Jun 27, 2026
177 of 187 checks passed
@giodl73-repo
giodl73-repo deleted the feeds-hosted-catalog-snapshot-cache branch June 27, 2026 22:26
@giodl73-repo

Copy link
Copy Markdown
Contributor Author

Merged via squash.

Thanks @giodl73-repo!

github-actions Bot pushed a commit to Desicool/openclaw that referenced this pull request Jun 28, 2026
Merged via squash.

Prepared head SHA: 5f71635
Co-authored-by: giodl73-repo <[email protected]>
Co-authored-by: giodl73-repo <[email protected]>
Reviewed-by: @giodl73-repo
QiuYuang pushed a commit to QiuYuang/openclaw that referenced this pull request Jul 1, 2026
Merged via squash.

Prepared head SHA: 5f71635
Co-authored-by: giodl73-repo <[email protected]>
Co-authored-by: giodl73-repo <[email protected]>
Reviewed-by: @giodl73-repo
chenyangjun-xy pushed a commit to chenyangjun-xy/openclaw that referenced this pull request Jul 1, 2026
Merged via squash.

Prepared head SHA: 5f71635
Co-authored-by: giodl73-repo <[email protected]>
Co-authored-by: giodl73-repo <[email protected]>
Reviewed-by: @giodl73-repo
chenyangjun-xy pushed a commit to chenyangjun-xy/openclaw that referenced this pull request Jul 3, 2026
Merged via squash.

Prepared head SHA: 5f71635
Co-authored-by: giodl73-repo <[email protected]>
Co-authored-by: giodl73-repo <[email protected]>
Reviewed-by: @giodl73-repo
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

maintainer Maintainer-authored PR merge-risk: 🚨 compatibility 🚨 May break existing users, config, migrations, defaults, or upgrade paths. merge-risk: 🚨 security-boundary 🚨 May affect sandboxing, authorization, credentials, or sensitive data. P2 Normal backlog priority with limited blast radius. proof: sufficient ClawSweeper judged the real behavior proof convincing. rating: 🦞 diamond lobster Very strong PR readiness with only minor maintainer review expected. size: L status: 👀 ready for maintainer look ClawSweeper has no concrete contributor-facing blocker left for this PR.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants