Skip to content

Commit 5981f72

Browse files
committed
fix(docs): preserve accessible examples and gate index publication
1 parent 0eb43d5 commit 5981f72

29 files changed

Lines changed: 23008 additions & 100 deletions

‎.gitattributes‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,5 +42,5 @@ Dockerfile* text eol=lf
4242
*.eot binary
4343
*.pdf binary
4444

45-
apps/docs/migration/*.json linguist-generated=true
45+
apps/docs/migration/report.json linguist-generated=true
4646
apps/docs/migration/verification/** linguist-generated=true

‎.github/workflows/ci.yml‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1158,7 +1158,7 @@ jobs:
11581158
- 'apps/docs/lib/search/**'
11591159
- 'apps/docs/lib/openapi-specs.ts'
11601160
- 'apps/docs/lib/urls.ts'
1161-
- 'apps/docs/public/openapi*.json'
1161+
- 'apps/docs/openapi*.json'
11621162
- 'apps/docs/package.json'
11631163
- 'bun.lock'
11641164
- '.github/workflows/docs.yml'

‎.github/workflows/docs-negotiation.yml‎

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ permissions:
4545

4646
concurrency:
4747
group: docs-negotiation-${{ github.ref }}-${{ inputs.benchmark && 'benchmark' || 'verification' }}
48-
cancel-in-progress: true
48+
cancel-in-progress: ${{ !inputs.benchmark }}
4949

5050
jobs:
5151
benchmark:
@@ -89,7 +89,8 @@ jobs:
8989
cp .readiness-harness/apps/docs/scripts/benchmark-readiness.ts apps/docs/scripts/benchmark-readiness.ts
9090
if [ "$MEASURED_TARGET" = production ]; then
9191
gh api "repos/$GITHUB_REPOSITORY/deployments?environment=Production&per_page=1" >test-results/benchmark/deployment.json
92-
REVISION=$(jq -r '.[0].sha' test-results/benchmark/deployment.json)
92+
# Candidate deployments do not establish which revision owns the public alias.
93+
REVISION=unverified-public-origin
9394
else
9495
REVISION=$(git rev-parse HEAD)
9596
fi

‎.github/workflows/docs.yml‎

Lines changed: 38 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,25 @@ on:
77
required: false
88
OPENAI_API_KEY:
99
required: false
10-
workflow_dispatch: # Allow manual triggering
10+
workflow_dispatch:
11+
inputs:
12+
publish:
13+
description: I verified the matching docs deployment and a restorable index backup
14+
type: boolean
15+
required: true
16+
default: false
17+
deployed_revision:
18+
description: Full source SHA of the verified serving docs deployment
19+
type: string
20+
required: true
21+
deployment_id:
22+
description: Verified serving docs deployment ID
23+
type: string
24+
required: true
25+
backup_reference:
26+
description: Restorable docs_embeddings backup identifier (no credentials)
27+
type: string
28+
required: true
1129

1230
permissions:
1331
contents: read
@@ -18,16 +36,30 @@ jobs:
1836
# Network-bound on the embeddings API: ~9% CPU and ~3% peak memory on 8 vCPU.
1937
runs-on: ${{ (vars.CI_PROVIDER == '' || vars.CI_PROVIDER == 'blacksmith') && 'blacksmith-2vcpu-ubuntu-2404' || 'ubuntu-latest' }}
2038
timeout-minutes: 30
21-
if: github.ref == 'refs/heads/main'
39+
if: github.ref == 'refs/heads/main' && github.event_name == 'workflow_dispatch' && inputs.publish
2240
concurrency:
2341
group: docs-search-index-production
2442
cancel-in-progress: false
2543

2644
steps:
45+
- name: Record verified deployment and backup
46+
env:
47+
DEPLOYED_REVISION: ${{ inputs.deployed_revision }}
48+
DEPLOYMENT_ID: ${{ inputs.deployment_id }}
49+
BACKUP_REFERENCE: ${{ inputs.backup_reference }}
50+
run: |
51+
test "$DEPLOYED_REVISION" = "$GITHUB_SHA"
52+
test -n "$DEPLOYMENT_ID"
53+
test -n "$BACKUP_REFERENCE"
54+
jq -n --arg revision "$DEPLOYED_REVISION" --arg deployment "$DEPLOYMENT_ID" \
55+
--arg backup "$BACKUP_REFERENCE" --arg actor "$GITHUB_ACTOR" \
56+
'{revision: $revision, deploymentId: $deployment, backupReference: $backup, verifiedBy: $actor}' \
57+
> "$RUNNER_TEMP/docs-search-authorization.json"
58+
2759
- name: Checkout code
2860
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v6
2961
with:
30-
ref: main
62+
ref: ${{ github.sha }}
3163
persist-credentials: false
3264

3365
- name: Setup workspace
@@ -51,4 +83,6 @@ jobs:
5183
uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2
5284
with:
5385
name: docs-search-index
54-
path: apps/docs/test-results/docs-search-*.json
86+
path: |
87+
apps/docs/test-results/docs-search-*.json
88+
${{ runner.temp }}/docs-search-authorization.json

‎apps/docs/MACHINE_ACCESS.md‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ bun scripts/index-search.ts
6060

6161
`--plan` is local and read-only. `--check` requires the search database and reports missing, stale or retired documents without writes. It compares stored chunk text, embedding model and input identity, headings, citations and metadata with the canonical catalog. The final command prepares bounded embedding batches, atomically updates one document at a time, and removes retired documents only after all page updates succeed. A failed page leaves its previous index intact. Citation or metadata changes reuse existing vectors when the embedding input is unchanged. The canonical index includes authored content and generated API operations; the agent VFS retains its deliberate `academy` and `api-reference` exclusions.
6262

63-
Add one or more `--path=/introduction` arguments to plan, check or repair specific canonical pages. Scoped publication never retires other pages. Publication and checks acquire an exclusive PostgreSQL advisory lock; a competing invocation fails before changing rows. The main-branch workflow also serializes publisher jobs and checks out current `main`, including when an older queued workflow starts. Do not run an older publisher checkout against the index.
63+
Add one or more `--path=/introduction` arguments to plan, check or repair specific canonical pages. Scoped publication never retires other pages. Publication and checks acquire an exclusive PostgreSQL advisory lock; a competing invocation fails before changing rows. Automatic index publication is disabled. The main-branch workflow only publishes after a manual dispatch with `publish` confirmed, the serving docs deployment ID, its full source SHA, and a restorable index backup reference. It checks out the dispatch's exact SHA and rejects a different deployment revision before accessing the index. The operator must independently verify the serving deployment and backup before confirming; the workflow records that attestation but does not create or validate a backup. Publisher jobs remain serialized. Do not run an older publisher checkout against the index.
6464

6565
Set `DOCS_SEARCH_REPORT_PATH` to choose the JSON report destination. The default is `test-results/docs-search-index.json`. Reports include embedding request, input and provider token counts. The main-branch docs workflow retains separate publication and freshness reports; no production indexing is part of the docs build.
6666

‎apps/docs/app/[[...slug]]/page.tsx‎

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import { getMDXComponents } from '@/components/docs/mdx'
66
import { DocsPageFrame } from '@/components/docs/page-frame'
77
import { StructuredData } from '@/components/structured-data'
88
import { getPage, getPages } from '@/lib/content/catalog'
9-
import { DOCS_BASE_URL } from '@/lib/urls'
9+
import { DOCS_BASE_URL, getMarkdownPath } from '@/lib/urls'
1010
import { loadPage } from '@/.content/registry'
1111

1212
interface PageProps {
@@ -30,7 +30,8 @@ export async function generateMetadata({ params }: PageProps): Promise<Metadata>
3030
alternates: {
3131
canonical: url,
3232
types: {
33-
'text/markdown': `${url === `${DOCS_BASE_URL}/` ? `${DOCS_BASE_URL}/index` : url}.md`,
33+
'text/markdown': `${DOCS_BASE_URL}${getMarkdownPath(page.url)}`,
34+
'text/plain': `${DOCS_BASE_URL}/llms.txt`,
3435
},
3536
},
3637
openGraph: {

‎apps/docs/app/api/docs/pages/route.ts‎

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { listPages, listPagesSchema } from '@/lib/http/pages'
1+
import { listPages, listPagesSchema, UnknownPageCursorError } from '@/lib/http/pages'
22

33
export function GET(request: Request) {
44
const params = new URL(request.url).searchParams
@@ -14,7 +14,9 @@ export function GET(request: Request) {
1414
return Response.json(listPages(parsed.data), {
1515
headers: { 'Cache-Control': 'public, max-age=60, s-maxage=3600' },
1616
})
17-
} catch {
18-
return Response.json({ error: 'Unknown page cursor' }, { status: 400 })
17+
} catch (error) {
18+
if (error instanceof UnknownPageCursorError)
19+
return Response.json({ error: error.message }, { status: 400 })
20+
throw error
1921
}
2022
}

‎apps/docs/app/global.css‎

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,22 @@
33
@source '../../../packages/emcn/src';
44
@source '../../../packages/workflow-renderer/src';
55
@custom-variant dark (&:where(.dark, .dark *));
6+
@custom-variant hover-hover {
7+
@media (hover: hover) and (pointer: fine) {
8+
&:hover {
9+
@slot;
10+
}
11+
}
12+
}
13+
14+
@theme {
15+
--text-micro: 10px;
16+
--text-xs: 11px;
17+
--text-caption: 12px;
18+
--text-small: 13px;
19+
--text-base: 15px;
20+
--text-md: 16px;
21+
}
622

723
@theme inline {
824
--font-sans: var(--font-geist-sans);

‎apps/docs/app/layout.tsx‎

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,12 @@ export default function RootLayout({ children }: RootLayoutProps) {
4646
description,
4747
url: DOCS_BASE_URL,
4848
inLanguage: 'en',
49-
publisher: { '@type': 'Organization', name: 'Sim', url: SIM_SITE_URL },
49+
publisher: {
50+
'@type': 'Organization',
51+
'@id': `${SIM_SITE_URL}#organization`,
52+
name: 'Sim',
53+
url: SIM_SITE_URL,
54+
},
5055
}),
5156
}}
5257
/>

‎apps/docs/components/docs/page-actions.tsx‎

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import { useCopyToClipboard } from '@sim/emcn'
66
import { Check, ChevronDown, Duplicate, SquareArrowUpRight } from '@sim/emcn/icons'
77
import { cn } from '@/components/docs/classnames'
88
import { docsControlClass, docsMenuClass, docsMenuItemClass } from '@/components/docs/primitives'
9+
import { getMarkdownPath } from '@/lib/urls'
910

1011
interface PageActionsProps {
1112
url: string
@@ -15,12 +16,14 @@ export function PageActions({ url }: PageActionsProps) {
1516
const { copied, copy } = useCopyToClipboard()
1617
const [status, setStatus] = useState<'idle' | 'loading' | 'ready' | 'error'>('idle')
1718
const prepared = useRef<string | null>(null)
18-
const markdownUrl = `${url === '/' ? '/index' : url}.md`
19+
const markdownUrl = getMarkdownPath(url)
1920
const showCopied = copied && status === 'idle'
2021
async function copyPage() {
2122
setStatus('loading')
2223
const prepare = async () => {
23-
const response = await fetch(markdownUrl, { signal: AbortSignal.timeout(10000) })
24+
const signal =
25+
typeof AbortSignal.timeout === 'function' ? AbortSignal.timeout(10000) : undefined
26+
const response = await fetch(markdownUrl, { signal })
2427
if (!response.ok) throw new Error('Page could not be loaded')
2528
const markdown = await response.text()
2629
if (!markdown.trim()) throw new Error('Page is empty')

0 commit comments

Comments
 (0)