Skip to content

Commit 5b103d6

Browse files
hotlongclaude
andauthored
ci(check-links): 恢复 pull_request 断链门,仅检仓内链接、advisory-first (#6028) (#6304)
* ci(check-links): 恢复 pull_request 断链门,仅检仓内链接 (#6028) 按维护者 2026-08-07 裁决恢复 `Check Links`:重新启用 `pull_request` 触发(branches: main),保留 `workflow_dispatch`,`fail: true` 不变; 方向②(留空壳写注释)已被否决,故被注释掉的 `push:` 残骸按 「declared = enforced」直接删除,而不是留在文件里继续误导读者。 ⛔ advisory-first:不进 required 集,也不加 `merge_group` —— advisory 车道不该消耗合并队列容量。日后若晋级 required,必须按 #6121 的教训在 同一次改动里补上 `merge_group`,否则队列会卡在一个永不上报的必需检查上。 仅检仓内链接的机制选 `--offline`,写在调用处而不是 lychee.toml: 实测 `offline = true` 这个配置键在 lychee 0.19.1 上被静默忽略、在 action 当前钉住的 0.24.2 上才生效,确定性保证不能取决于 action 恰好 装了哪个版本。`^https?://` 这类 exclude 也不够 —— 它要逐个枚举远程 scheme,漏一个就重新引入外网依赖。 门休眠半年期间配置已经漂移到跑不起来,这次一并修好(否则恢复触发器 只会让门以 exit 3 直接死掉,连链接都不检): - `follow_redirects` 在 0.24.2 上根本不是合法键 —— 硬解析错误; - `include_fragments` 已从 bool 变成枚举,裸 `false` 同样硬报错, 改为 `"none"` 保持原语义(不检 fragment)。 root-relative 链接是 content/** 的主力写法,而 lychee 在没有 root-dir 时对它们直接报错。补 `--root-dir <workspace>/content` + `--fallback-extensions mdx,md` 之后,1286 条此前完全没被检查的 `/docs/*` 链接首次纳入检查面(134 → 1476 条被检)。原来的 `remap` 块一次都没生效过(URI 构造在 remap 之前就失败),已按 declared = enforced 删除,能力由真正生效的 root-dir 承接。 修掉门首次真正运行后暴露的 22 条既有真断链(仅改链接目标,不改散文): - 14 条 ADR 链接归一到仓内既有约定(29 处在用的 GitHub blob URL): `/adr/*` 站点路由并不存在,apps/docs 只有 /[lang]/docs 与 /[lang]/blog 两条路由,也没有任何 /adr 重定向 —— 这些链接在线上 就是 404; - quick-reference 三行指向已退役 schema 的表项删除(audit.zod 按 ADR-0056 移除、registry.zod 按 #4939 退役、graphql.zod 全仓无踪), 并同步修正两处小节计数;connector-auth 有 schema 无页面,改为不带 链接保留信息;plugin-security 页面在 references/kernel 而非 cloud; - README 两处:`@objectstack/account` 已迁到 packages/apps/account; `service-feed` 已在 #1955 删除,整行移除。 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BDmDsu2575gDxeMCxXhDE3 * fix(spec): ADR-0020 链接改到源头 JSDoc,而不是只改生成物 (#6028) `content/docs/references/**` 是 `packages/spec` 的生成物(文件头写着 AUTO-GENERATED — DO NOT EDIT),上一个 commit 只改了生成出来的 state-machine.mdx,下一次 `gen:docs` 就会把它冲掉 —— 由 os-regen pre-commit 钩子当场拦下。 按 contract-first 修在生产者:`packages/spec/src/automation/state-machine.zod.ts` 的 JSDoc 里那条 ADR 链接原本写作 `../../../docs/adr/0020-...md`,从 `packages/spec/src/automation/` 出发解析到 `packages/docs/adr/...` —— 这个 目录并不存在,所以源头本身就是断的,生成物只是忠实地把它复制了出来。 改为仓内既有约定的 GitHub blob URL(全仓 29 处在用),它与文件位置无关, 生成到任何深度的目录都成立。 重新生成后 `content/docs/references/automation/state-machine.mdx` 与本次 生成输出完全一致(regen 后工作树对该文件零 diff),生成物与源头就此对齐。 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BDmDsu2575gDxeMCxXhDE3 * test(check-links): 反向验证探针 —— 故意把一条相对链接改指不存在路径 (#6028) 声明 B(咬合面)的红段:预期本次 push 让 Check Links 变红,且报错点名 content/docs/kernel/services-checklist.mdx:188 指向的 ./services-probe-6028-does-not-exist.mdx。下一个 commit 会 git revert 本提交,预期转绿;最终该文件相对 origin/main 净零 diff。 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BDmDsu2575gDxeMCxXhDE3 * chore(spec): 合并 main 后按新生成器重新生成 state-machine 参考页 (#6028) main 带来了 docs 生成器改动(changeset `docs-gen-description-line-layout-and-nested-links`:去掉逐行空行布局、 不再把行内代码路径转成嵌套链接)。该参考页是生成物,两边都改过, 文本合并的结果并不等于生成器的输出 —— os-regen 钩子说的正是这种 「被合并但没有真正重新生成」的状态。 `gen:schema && gen:docs` 后仅此一个文件有 diff(232 个生成文件里的 1 个),内容即新生成器的输出;本单在源头 JSDoc 里改的 ADR-0020 链接 原样保留。 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BDmDsu2575gDxeMCxXhDE3 * Revert "test(check-links): 反向验证探针 —— 故意把一条相对链接改指不存在路径 (#6028)" This reverts commit 34b5d9f. --------- Co-authored-by: Claude <noreply@anthropic.com>
1 parent 7e1b480 commit 5b103d6

10 files changed

Lines changed: 105 additions & 66 deletions

File tree

‎.github/workflows/check-links.yml‎

Lines changed: 41 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,33 @@
11
name: Check Links
22

3+
# Repo-internal link gate (#6028).
4+
#
5+
# `pull_request` was commented out in a59dc59e (2026-01-28) as a rider on an
6+
# unrelated commit, with no rationale recorded; the gate then sat dormant for
7+
# six months while `lychee.toml` and `fail: true` kept it looking alive.
8+
# Maintainer ruling 2026-08-07: restore the trigger, check REPO-INTERNAL links
9+
# only, and land it advisory-first (NOT in the required set) until it has shown
10+
# a stable green streak.
11+
#
12+
# ⛔ No `merge_group` trigger on purpose: this is an advisory lane, and an
13+
# advisory gate does not get to consume merge-queue capacity. If it is ever
14+
# promoted into the required set, `merge_group` MUST be added in the same
15+
# change or the queue stalls on a required check that never reports (#6121).
316
on:
417
workflow_dispatch:
5-
# push:
6-
# branches:
7-
# - main
8-
# pull_request:
9-
# branches:
10-
# - main
18+
pull_request:
19+
branches:
20+
- main
1121

1222
jobs:
1323
link-checker:
1424
name: Check Documentation Links
1525
runs-on: ubuntu-latest
26+
# Least privilege: the job only reads the tree and runs lychee offline.
27+
# There is no issue-filing step, and `--offline` makes zero network
28+
# requests, so neither `issues: write` nor a GITHUB_TOKEN is needed.
1629
permissions:
1730
contents: read
18-
issues: write
1931

2032
steps:
2133
- name: Checkout repository
@@ -24,14 +36,32 @@ jobs:
2436
- name: Check links with lychee
2537
uses: lycheeverse/lychee-action@v2
2638
with:
27-
# Use configuration file for path remapping and settings
39+
# `--offline` is the internal-only mechanism, and it lives HERE rather
40+
# than in lychee.toml on purpose: the equivalent `offline = true`
41+
# config key is silently ignored by older lychee (measured: ignored on
42+
# 0.19.1, honoured on the 0.24.2 this action pins). A determinism
43+
# guarantee must not depend on which lychee the action happens to
44+
# install, so it is asserted at the invocation site.
45+
#
46+
# Offline means only `file://` targets are resolved -- every http(s)
47+
# link is reported EXCLUDED, never requested. That is what makes this
48+
# gate deterministic and free of external-network flake.
49+
#
50+
# --root-dir is what makes ROOT-RELATIVE links checkable. Most internal
51+
# links in content/** are site routes (`/docs/permissions`), and lychee
52+
# hard-errors on those unless it is told which directory `/` means.
53+
# The Fumadocs content root is `content/`, so `/docs/x` resolves to
54+
# content/docs/x -- and --fallback-extensions supplies the .mdx/.md
55+
# suffix that a site route omits. Without this pair the gate cannot go
56+
# green at all: 1286 root-relative links fail as "Cannot resolve
57+
# root-relative link ... provide a root dir".
2858
args: >-
59+
--offline
60+
--root-dir ${{ github.workspace }}/content
61+
--fallback-extensions mdx,md
2962
--config lychee.toml
3063
'content/**/*.md'
3164
'content/**/*.mdx'
3265
'README.md'
3366
# Fail the job if broken links are found
3467
fail: true
35-
env:
36-
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
37-

‎README.md‎

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -321,7 +321,6 @@ For the browser, the typed client SDK and React hooks (`useQuery` / `useMutation
321321
| [`@objectstack/service-analytics`](packages/services/service-analytics) | Analytics — aggregations, time series, funnels, dashboards |
322322
| [`@objectstack/service-automation`](packages/services/service-automation) | Automation engine — flows, triggers, and workflow state machines |
323323
| [`@objectstack/service-cache`](packages/services/service-cache) | Cache — in-memory, Redis, multi-tier |
324-
| [`@objectstack/service-feed`](packages/services/service-feed) | Activity feed / chatter |
325324
| [`@objectstack/service-i18n`](packages/services/service-i18n) | Internationalization service |
326325
| [`@objectstack/service-job`](packages/services/service-job) | Cron & interval job scheduler |
327326
| [`@objectstack/service-package`](packages/services/service-package) | Package registry — publish, version, retrieve metadata packages |
@@ -343,7 +342,7 @@ For the browser, the typed client SDK and React hooks (`useQuery` / `useMutation
343342
| [`@objectstack/cli`](packages/cli) | CLI binary (`os` / `objectstack`) — `init`, `dev`, `start`, `serve`, `compile`, `publish`, `validate`, `generate`, `lint`, `doctor` |
344343
| [`create-objectstack`](packages/create-objectstack) | Project scaffolder (`npx create-objectstack`) |
345344
| [`@object-ui/console`](https://github.com/objectstack-ai/objectui/tree/main/apps/console) | Fork-ready runtime console SPA (lives in objectstack-ai/objectui, served via `@object-ui/console` on npm) |
346-
| [`@objectstack/account`](apps/account) | Account & identity portal — sign in, organizations, connected apps |
345+
| [`@objectstack/account`](packages/apps/account) | Account & identity portal — sign in, organizations, connected apps |
347346
| [`@objectstack/docs`](apps/docs) | Documentation site (Fumadocs + Next.js) |
348347

349348
### Examples

‎content/blog/metadata-driven-architecture.mdx‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -583,4 +583,4 @@ ObjectStack is our answer.
583583

584584
---
585585

586-
*Want to dive deeper? Explore our [technical specifications](/docs/specifications) or join the discussion on [GitHub](https://github.com/objectstack-ai/spec/issues).*
586+
*Want to dive deeper? Explore our [technical specifications](/docs/references) or join the discussion on [GitHub](https://github.com/objectstack-ai/spec/issues).*

‎content/docs/ai/connect-mcp.mdx‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,7 @@ full-authority local agent, mint the key on a platform-admin or dedicated
113113
**service** identity; for a scoped one, mint it on a user with exactly the
114114
access it should have. See
115115
[environment variables](/docs/deployment/environment-variables#mcp-server) for
116-
the switches and [ADR-0101](/adr/0101-mcp-stdio-principal-admission) for the
116+
the switches and [ADR-0101](https://github.com/objectstack-ai/objectstack/blob/main/docs/adr/0101-mcp-stdio-principal-admission.md) for the
117117
decision.
118118

119119
## What the agent gets

‎content/docs/getting-started/quick-reference.mdx‎

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -76,13 +76,12 @@ Plugin architecture, manifests, and kernel runtime.
7676
| **[Metadata Loader](/docs/references/kernel/metadata-loader)** | `metadata-loader.zod.ts` | MetadataLoaderContract | Metadata loading |
7777
| **[Package Registry](/docs/references/kernel/package-registry)** | `package-registry.zod.ts` | InstalledPackage, InstallPackageRequest | Package resolution |
7878

79-
## System Protocol (19 schemas)
79+
## System Protocol (18 schemas)
8080

8181
Runtime environment, logging, jobs, caching, and observability.
8282

8383
| Protocol | Source File | Key Schemas | Purpose |
8484
|:---------|:-----------|:------------|:--------|
85-
| **[Audit](/docs/references/system/audit)** | `audit.zod.ts` | AuditEvent, AuditConfig | Audit trail logging |
8685
| **[Auth Config](/docs/references/system/auth-config)** | `auth-config.zod.ts` | AuthConfig | Authentication configuration |
8786
| **[Cache](/docs/references/system/cache)** | `cache.zod.ts` | CacheConfig | Caching layer |
8887
| **[Change Management](/docs/references/system/change-management)** | `change-management.zod.ts` | ChangeRequest, RollbackPlan | Change tracking |
@@ -120,7 +119,7 @@ AI/ML capabilities - agents, skills, tools, MCP exposure, RAG, and cost tracking
120119
| **[Usage](/docs/references/ai/usage)** | `usage.zod.ts` | AIUsageRecord, TokenUsage | AI usage and cost tracking |
121120
| **[Solution Blueprint](/docs/references/ai/solution-blueprint)** | `solution-blueprint.zod.ts` | BlueprintObject, BlueprintApp | Blueprint format for AI app generation |
122121

123-
## API Protocol (19 schemas)
122+
## API Protocol (17 schemas)
124123

125124
REST/GraphQL endpoints, real-time subscriptions, and discovery.
126125

@@ -130,7 +129,6 @@ REST/GraphQL endpoints, real-time subscriptions, and discovery.
130129
| **[Endpoint](/docs/references/api/endpoint)** | `endpoint.zod.ts` | ApiEndpoint, ApiMapping | REST endpoint configuration |
131130
| **[Router](/docs/references/api/router)** | `router.zod.ts` | Router, Route | API routing rules |
132131
| **[OData](/docs/references/api/odata)** | `odata.zod.ts` | ODataQuery | OData protocol support |
133-
| **[GraphQL](/docs/references/api/graphql)** | `graphql.zod.ts` | GraphQLConfig, FederationEntity | GraphQL API config |
134132
| **[Realtime](/docs/references/api/realtime)** | `realtime.zod.ts` | Subscription, RealtimeEvent | WebSocket subscriptions |
135133
| **[WebSocket](/docs/references/api/websocket)** | `websocket.zod.ts` | WebSocketConfig | WebSocket protocol |
136134
| **[Discovery](/docs/references/api/discovery)** | `discovery.zod.ts` | Discovery, ServiceInfo | API discovery and metadata |
@@ -143,7 +141,6 @@ REST/GraphQL endpoints, real-time subscriptions, and discovery.
143141
| **[Analytics](/docs/references/api/analytics)** | `analytics.zod.ts` | Analytics | API usage analytics |
144142
| **[Documentation](/docs/references/api/documentation)** | `documentation.zod.ts` | Documentation | API docs generation |
145143
| **[Metadata](/docs/references/api/metadata)** | `metadata.zod.ts` | Metadata | API metadata endpoints |
146-
| **[Registry](/docs/references/api/registry)** | `registry.zod.ts` | Registry | API registry |
147144
| **[Storage](/docs/references/api/storage)** | `storage.zod.ts` | Storage | API storage operations |
148145

149146
## Automation Protocol (5 schemas)
@@ -188,7 +185,7 @@ Environments, marketplace, licensing, and multi-tenancy.
188185
| **[Environment](/docs/references/cloud/environment)** | `environment.zod.ts` | Environment, EnvironmentType | Deployment environments |
189186
| **[Marketplace](/docs/references/cloud/marketplace)** | `marketplace.zod.ts` | MarketplaceListing, PackageSubmission | Plugin marketplace |
190187
| **[Plugin Registry](/docs/references/kernel/plugin-registry)** | `plugin-registry.zod.ts` | PluginRegistryEntry, PluginVendor | Plugin registry entries and quality metrics |
191-
| **[Plugin Security](/docs/references/cloud/plugin-security)** | `plugin-security.zod.ts` | PluginSecurityProtocol, SBOM | Plugin security policies |
188+
| **[Plugin Security](/docs/references/kernel/plugin-security)** | `plugin-security.zod.ts` | PluginSecurityProtocol, SBOM | Plugin security policies |
192189
| **[Tenant](/docs/references/cloud/tenant)** | `tenant.zod.ts` | Tenant | Multi-tenancy isolation |
193190

194191
## Integration Protocol (1 schema)
@@ -214,7 +211,7 @@ Common utilities used across all protocols.
214211
| **[HTTP](/docs/references/shared/http)** | `http.zod.ts` | HttpRequest, HttpMethod, CorsConfig | HTTP utilities |
215212
| **[Identifiers](/docs/references/shared/identifiers)** | `identifiers.zod.ts` | SystemIdentifier, SnakeCaseIdentifier | Standard ID patterns |
216213
| **[Mapping](/docs/references/shared/mapping)** | `mapping.zod.ts` | FieldMapping | Field mapping utilities |
217-
| **[Connector Auth](/docs/references/shared/connector-auth)** | `connector-auth.zod.ts` | ConnectorAuthConfig | Connector auth patterns |
214+
| **Connector Auth** | `connector-auth.zod.ts` | ConnectorAuthConfig | Connector auth patterns |
218215

219216
## QA Protocol (1 schema)
220217

‎content/docs/permissions/attachments-access.mdx‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,7 @@ an auth service is wired, and stamp `owner_id` on the new `sys_file`.
103103

104104
Deleting attachments does not immediately delete the underlying bytes (a file
105105
can be shared across records). Reclamation is handled by the platform LifecycleService via declarative
106-
[reap guards](/adr/0057-system-data-lifecycle-and-retention):
106+
[reap guards](https://github.com/objectstack-ai/objectstack/blob/main/docs/adr/0057-system-data-lifecycle-and-retention.md):
107107

108108
- **`sys_file`** — when the last `sys_attachment` referencing an
109109
attachments-scope file is deleted, the file is tombstoned; a reap guard

‎content/docs/permissions/authorization.mdx‎

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -409,16 +409,16 @@ The complete, prioritized gap map lives in issue **#2561** (the production
409409

410410
| ADR | Owns |
411411
|---|---|
412-
| [0049](/adr/0049-no-unenforced-security-properties) | No unenforced security properties (enforce / mark / remove) |
413-
| [0054](/adr/0054-runtime-proof-for-authorable-surface) | Prove-it-runs — high-risk classes need runtime proofs |
414-
| [0056](/adr/0056-permission-model-landing-verification) | Permission-model landing: OWD, anonymous deny default, D10 matrix |
415-
| [0057](/adr/0057-erp-authorization-core-business-units-and-scope-depth) | Business units, scope depth, declarative RBAC seeding, platform-owned assignment |
416-
| [0066](/adr/0066-unified-authorization-model) | Unified model: capability registry, posture, precedence, future refinements |
417-
| [0068](/adr/0068-unified-user-context-and-built-in-identity-roles) | Built-in identity positions (formerly "identity roles"), `EvalUser` |
418-
| [0069](/adr/0069-enterprise-authentication-hardening) | Enterprise authentication hardening (phased) |
419-
| [0078](/adr/0078-no-silently-inert-metadata) | No inert declarable metadata |
420-
| [0086](/adr/0086-authz-metadata-config-boundary-and-cross-package-composition) | Metadata↔config boundary, package provenance, cross-package composition |
412+
| [0049](https://github.com/objectstack-ai/objectstack/blob/main/docs/adr/0049-no-unenforced-security-properties.md) | No unenforced security properties (enforce / mark / remove) |
413+
| [0054](https://github.com/objectstack-ai/objectstack/blob/main/docs/adr/0054-runtime-proof-for-authorable-surface.md) | Prove-it-runs — high-risk classes need runtime proofs |
414+
| [0056](https://github.com/objectstack-ai/objectstack/blob/main/docs/adr/0056-permission-model-landing-verification.md) | Permission-model landing: OWD, anonymous deny default, D10 matrix |
415+
| [0057](https://github.com/objectstack-ai/objectstack/blob/main/docs/adr/0057-erp-authorization-core-business-units-and-scope-depth.md) | Business units, scope depth, declarative RBAC seeding, platform-owned assignment |
416+
| [0066](https://github.com/objectstack-ai/objectstack/blob/main/docs/adr/0066-unified-authorization-model.md) | Unified model: capability registry, posture, precedence, future refinements |
417+
| [0068](https://github.com/objectstack-ai/objectstack/blob/main/docs/adr/0068-unified-user-context-and-built-in-identity-roles.md) | Built-in identity positions (formerly "identity roles"), `EvalUser` |
418+
| [0069](https://github.com/objectstack-ai/objectstack/blob/main/docs/adr/0069-enterprise-authentication-hardening.md) | Enterprise authentication hardening (phased) |
419+
| [0078](https://github.com/objectstack-ai/objectstack/blob/main/docs/adr/0078-no-silently-inert-metadata.md) | No inert declarable metadata |
420+
| [0086](https://github.com/objectstack-ai/objectstack/blob/main/docs/adr/0086-authz-metadata-config-boundary-and-cross-package-composition.md) | Metadata↔config boundary, package provenance, cross-package composition |
421421
| 0090 | Permission Model v2: position rename + vocabulary freeze, profile removal, fail-closed OWD default + external dial, audience anchors, principal taxonomy, publish linter, delegated administration, explain engine + access matrix |
422422
| 0091 | Grant lifecycle: validity windows + resolution-time filtering (L1, landed), delegation, break-glass, recertification substrate |
423-
| [0096](/adr/0096-execution-surface-identity-admission) | Execution-surface identity admission — no data-engine call without an explicit principal (the MCP HTTP surface admits identity here) |
424-
| [0101](/adr/0101-mcp-stdio-principal-admission) | MCP stdio principal admission — env-supplied API-key identity, fail-closed, no `system` bypass |
423+
| [0096](https://github.com/objectstack-ai/objectstack/blob/main/docs/adr/0096-execution-surface-identity-admission.md) | Execution-surface identity admission — no data-engine call without an explicit principal (the MCP HTTP surface admits identity here) |
424+
| [0101](https://github.com/objectstack-ai/objectstack/blob/main/docs/adr/0101-mcp-stdio-principal-admission.md) | MCP stdio principal admission — env-supplied API-key identity, fail-closed, no `system` bypass |

‎content/docs/references/automation/state-machine.mdx‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ transition the machine never declared.
1616

1717
The ledger carried these shapes as `authorable (p)` — provisional, because
1818
nobody had checked. Checking matters here more than usual, because
19-
[ADR-0020](../../../docs/adr/0020-state-machine-converge-and-enforce.md)
19+
[ADR-0020](https://github.com/objectstack-ai/objectstack/blob/main/docs/adr/0020-state-machine-converge-and-enforce.md)
2020
**retired this shape as a record-lifecycle declaration**: the top-level
2121
`workflow` metadata type and `object.stateMachines` are both gone, and a
2222
record's legal transitions are declared as a `state_machine` **validation

0 commit comments

Comments
 (0)