Skip to content

Commit 542ad7c

Browse files
committed
Serve Orbit agent guide without stale cache
1 parent 4df943f commit 542ad7c

4 files changed

Lines changed: 31 additions & 9 deletions

File tree

‎docs/V6_PROJECT_LEDGER.md‎

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -870,6 +870,13 @@ Bu dosya yalnız sonuçları değil; kararları, reddedilen alternatifleri, migr
870870
- No migration, dashboard visual change, public feed change or announcement
871871
body exposure was introduced. Announcement endpoints remain authenticated
872872
and `no-store`.
873+
- The first live smoke exposed a separate delivery hazard: the new Worker API
874+
was active while the canonical bare `/skill.md` URL could still return the
875+
previous guide body from the static asset cache; a cache-busted URL returned
876+
`2.5.0`. The Worker now serves `machineAgentSkill` directly for GET/HEAD with
877+
UTF-8, `nosniff` and `no-store, no-transform`, keeping the API and canonical
878+
agent contract atomic across deploys instead of relying on asset-cache
879+
invalidation.
873880
- Local proof passed: 95 D1/workerd tests, 63 content assertions, 74 CLI
874881
assertions, 1,807 site assertions, 352 browser assertions, Astro zero
875882
diagnostics, 54 production-config assertions and a production Worker

‎scripts/orbit-slice1-worker-tests.ts‎

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -273,12 +273,17 @@ describe('Orbit V6 deployment-mode contract', () => {
273273
assert.match(await robots.text(), /Allow: \//u);
274274
});
275275

276-
test('serves the machine guide with an explicit UTF-8 charset', async () => {
276+
test('serves the current machine guide directly without stale asset caching', async () => {
277277
const env = productionBindings('live');
278278
const response = await worker.fetch(new Request(`${LIVE_ORIGIN}/skill.md`), env);
279279
assert.equal(response.status, 200);
280280
assert.equal(response.headers.get('content-type'), 'text/markdown; charset=utf-8');
281-
assert.match(await response.text(), /Türkçe karakterler: ğüşöçıİ/u);
281+
assert.equal(response.headers.get('cache-control'), 'no-store, no-transform');
282+
assert.match(await response.text(), /version: 2\.5\.0/u);
283+
const head = await worker.fetch(new Request(`${LIVE_ORIGIN}/skill.md`, { method: 'HEAD' }), env);
284+
assert.equal(head.status, 200);
285+
assert.equal(head.headers.get('cache-control'), 'no-store, no-transform');
286+
assert.equal(await head.text(), '');
282287
});
283288

284289
test('applies dashboard privacy and frame protection to GET and HEAD', async () => {

‎src/pages/skill.md.ts‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import { machineAgentSkill } from '../data/agentOnboarding';
33
export function GET() {
44
return new Response(machineAgentSkill, {
55
headers: {
6-
'cache-control': 'public, max-age=300',
6+
'cache-control': 'no-store, no-transform',
77
'content-type': 'text/markdown; charset=utf-8',
88
'x-content-type-options': 'nosniff',
99
},

‎src/worker.ts‎

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ import { D1PublicRepository } from './server/repositories/d1/d1-public-repositor
1919
import type { AgentRepository } from './server/repositories/agent-repository';
2020
import type { PublicRepository } from './server/repositories/public-repository';
2121
import { serveDynamicPublicPage } from './server/public/response';
22+
import { machineAgentSkill } from './data/agentOnboarding';
2223

2324
interface ExecutionContextLike {
2425
waitUntil(promise: Promise<unknown>): void;
@@ -45,11 +46,14 @@ function denyAllRobots(): Response {
4546
});
4647
}
4748

48-
function preserveMachineGuideEncoding(request: Request, response: Response): Response {
49-
if (new URL(request.url).pathname !== '/skill.md') return response;
50-
const encodedResponse = new Response(response.body, response);
51-
encodedResponse.headers.set('content-type', 'text/markdown; charset=utf-8');
52-
return encodedResponse;
49+
function machineGuideResponse(method: string): Response {
50+
return new Response(method === 'HEAD' ? null : machineAgentSkill, {
51+
headers: {
52+
'cache-control': 'no-store, no-transform',
53+
'content-type': 'text/markdown; charset=utf-8',
54+
'x-content-type-options': 'nosniff',
55+
},
56+
});
5357
}
5458

5559
async function startStagingOAuth(request: Request, env: OrbitBindings): Promise<Response> {
@@ -89,6 +93,12 @@ export async function handleWorkerRequest(
8993
if (url.pathname === '/healthz') {
9094
return Response.json({ ok: true, service: 'orbit-v6', environment: env.ORBIT_ENVIRONMENT });
9195
}
96+
if (
97+
url.pathname === '/skill.md'
98+
&& (request.method === 'GET' || request.method === 'HEAD')
99+
) {
100+
return machineGuideResponse(request.method);
101+
}
92102
if (url.pathname.startsWith('/v1/')) {
93103
const response = await servePublicRead(request, env, async () => {
94104
const testNow = env.ORBIT_ENVIRONMENT === 'test'
@@ -125,7 +135,7 @@ export async function handleWorkerRequest(
125135
dependencies.agentRepository ?? new D1AgentRepository(env.DB),
126136
);
127137
if (publicPage) return publicPage;
128-
return preserveMachineGuideEncoding(request, await env.ASSETS.fetch(request));
138+
return await env.ASSETS.fetch(request);
129139
}, env.ORBIT_ENVIRONMENT);
130140
return protectFromIndexing(response, env);
131141
}

0 commit comments

Comments
 (0)