Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 22 additions & 1 deletion docs/REGISTRY_API.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,11 +27,32 @@ to GitHub. No workflow enables or purchases a Workers plan.

## Publish the first feed

### Current Free-plan deployment

Live acceptance on 2026-10-11 verified 6,842 skills from 81 repositories,
all selectors and pagination, and a 292,366-character body reconstructed from
10 hash-verified segments. Cloudflare measured API CPU P50 of 1.43 ms and P99
of 560 ms, and isolate memory P99 of approximately 83 MiB. These are sampled
metrics from the acceptance requests, including cold loads.

The account is on Workers Free. Cold loads and snapshot refreshes exceed its
10 ms CPU allowance; repeated refresh testing returned resource-limit 503s.
The maintainer explicitly deferred a paid upgrade. The current deployment is
therefore available for evaluation but cannot guarantee successful cold loads
or refreshes. No subscription was changed.

For a future approved Workers Paid deployment, configure
`"limits": { "cpu_ms": 1000 }` in `wrangler.jsonc`, deploy with Wrangler and
repeat cold-load/refresh acceptance. The Paid subscription starts at US$5/month;
see [Cloudflare pricing](https://developers.cloudflare.com/workers/platform/pricing/).
Free accounts reject this CPU-limit configuration, so it is intentionally absent
from the current config.

The first release requires a manual “Deploy Skill Catalog” run with
`bootstrap_feed=true`. The existing directory becomes the baseline, with no
historical notification flood. Future runs read `feed-state.json` from the last
successful Pages publication and compare its source revision with the latest
successful `github-pages` deployment. A later missing/corrupt state cannot be
completed successful production publication workflow. A later missing/corrupt state cannot be
bootstrapped again: recover the last published artifact instead.

Production publishes are serialized through verification of the new public
Expand Down
5 changes: 3 additions & 2 deletions src/api/api.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -237,6 +237,7 @@ describe("catalog API", () => {
`https://raw.githubusercontent.com/alpha/skills/${"a".repeat(40)}/SKILL.md`,
);
expect(fetcher.mock.calls[1][1]?.headers).toBeUndefined();
expect(fetcher.mock.calls[1][1]?.redirect).toBe("manual");
expect(
(
await worker.fetch(
Expand All @@ -250,7 +251,7 @@ describe("catalog API", () => {
});

it("reports legacy provenance, unavailable upstream and mismatched hash", async () => {
for (const scenario of ["legacy", "missing", "hash", "timeout"]) {
for (const scenario of ["legacy", "missing", "redirect", "hash", "timeout"]) {
const s = await fixtureSnapshot();
if (scenario === "legacy") delete s.skills[0].sourceCommit;
const fetcher: typeof fetch = async (input) => {
Expand All @@ -259,7 +260,7 @@ describe("catalog API", () => {
if (scenario === "timeout")
throw new DOMException("timeout", "TimeoutError");
return new Response("wrong", {
status: scenario === "missing" ? 404 : 200,
status: scenario === "missing" ? 404 : scenario === "redirect" ? 302 : 200,
});
};
const response = await createWorker(fetcher).fetch(
Expand Down
4 changes: 3 additions & 1 deletion src/api/worker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,9 @@ export function createWorker(
try {
const response = await fetcher(sourceUrl, {
signal: AbortSignal.timeout(10_000),
redirect: "error",
// workerd supports manual/follow only. Reject redirect status codes
// below to preserve the commit-pinned origin contract.
redirect: "manual",
});
if (!response.ok || !response.body) throw new Error("Source unavailable");
const reader = response.body.getReader();
Expand Down
Loading