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
39 changes: 39 additions & 0 deletions .changeset/15141-cluster-doc-pointer-site-urls.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
---
'@objectstack/spec': patch
---

`EventMetadata.cluster` and `ServiceMetadata.cluster` cite the live docs page by SITE URL, not a dead filename

Both `.describe()` strings pointed at `cluster-semantics.mdx`, a page that is no
longer in the tree — `apps/docs/redirects.mjs` has redirected
`/docs/concepts/cluster-semantics` to `/docs/kernel/cluster` since the page was
folded in. The section numbers still resolved, so nothing was broken for a
reader following a link; what was broken is retrieval by filename, which finds
nothing.

These two strings are the published half. `gen:docs` copies them into
`content/docs/references/kernel/events-core.mdx` and `service-registry.mdx`, and
they also ship as JSON Schema `description` values under `packages/spec/json-schema/`
and as string literals in `packages/spec/dist/`. So the citation had to become
something a SITE reader can follow:

```
- See cluster-semantics.mdx §4. (a file that does not exist)
+ See /docs/kernel/cluster §4. (the address the redirect already resolves to)
```

⛔ Deliberately NOT the in-repo house style. Source comments elsewhere in the
tree cite `` `content/docs/kernel/cluster.mdx` §N `` — a repo path, correct for a
reader who has the repo checked out. Copying that convention into a `.describe()`
would tell a docs-site reader to open a `content/docs/...` file they do not
have, which is the same class of unfollowable reference pointed the other way.
There is no in-repo precedent to copy either way: these are the only two
`.describe()` strings in `packages/spec/src` that cite a docs page at all.

The site URL is also redirect-independent — it is the redirect's own target, so
the reference survives the redirect being retired.

No accept set moves and no authorable key is added or removed: the schemas,
their parse behaviour and their exported types are byte-identical apart from
these two description strings. The two regenerated reference pages carry the
same one-line change on three rows.
4 changes: 2 additions & 2 deletions content/docs/references/kernel/events-core.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ const result = EventSchema.parse(data);
| **correlationId** | `string` | optional | Correlation ID for event tracing |
| **causationId** | `string` | optional | ID of the event that caused this event |
| **priority** | `Enum<'critical' \| 'high' \| 'normal' \| 'low' \| 'background'>` | optional (default: `"normal"`) | Event priority |
| **cluster** | `{ scope: Enum<'local' \| 'cluster' \| 'tenant'>; deliverySemantics?: Enum<'best-effort' \| 'at-least-once' \| 'exactly-once'>; partitionKey?: string }` | optional | Per-emit cluster routing & delivery options. See cluster-semantics.mdx §4. |
| **cluster** | `{ scope: Enum<'local' \| 'cluster' \| 'tenant'>; deliverySemantics?: Enum<'best-effort' \| 'at-least-once' \| 'exactly-once'>; partitionKey?: string }` | optional | Per-emit cluster routing & delivery options. See /docs/kernel/cluster §4. |


---
Expand All @@ -61,7 +61,7 @@ const result = EventSchema.parse(data);
| **correlationId** | `string` | optional | Correlation ID for event tracing |
| **causationId** | `string` | optional | ID of the event that caused this event |
| **priority** | `Enum<'critical' \| 'high' \| 'normal' \| 'low' \| 'background'>` | optional (default: `"normal"`) | Event priority |
| **cluster** | `{ scope: Enum<'local' \| 'cluster' \| 'tenant'>; deliverySemantics?: Enum<'best-effort' \| 'at-least-once' \| 'exactly-once'>; partitionKey?: string }` | optional | Per-emit cluster routing & delivery options. See cluster-semantics.mdx §4. |
| **cluster** | `{ scope: Enum<'local' \| 'cluster' \| 'tenant'>; deliverySemantics?: Enum<'best-effort' \| 'at-least-once' \| 'exactly-once'>; partitionKey?: string }` | optional | Per-emit cluster routing & delivery options. See /docs/kernel/cluster §4. |

### Nested Shape: `EventMetadata.cluster`

Expand Down
2 changes: 1 addition & 1 deletion content/docs/references/kernel/service-registry.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ const result = ScopeConfigSchema.parse(data);
| **type** | `string` | optional | Service type or interface name |
| **registeredAt** | `integer` | optional | Unix timestamp in milliseconds when service was registered |
| **metadata** | `Record<string, any>` | optional | Additional service-specific metadata |
| **cluster** | `{ clusterScope: Enum<'node' \| 'cluster'>; leaderStrategy?: Enum<'leader-elected' \| 'partitioned' \| 'idempotent-broadcast'>; clusterId?: string }` | optional | Cluster scope & leader strategy. See cluster-semantics.mdx §5. |
| **cluster** | `{ clusterScope: Enum<'node' \| 'cluster'>; leaderStrategy?: Enum<'leader-elected' \| 'partitioned' \| 'idempotent-broadcast'>; clusterId?: string }` | optional | Cluster scope & leader strategy. See /docs/kernel/cluster §5. |

### Nested Shape: `ServiceMetadata.cluster`

Expand Down
6 changes: 3 additions & 3 deletions packages/metadata/src/metadata-manager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -499,7 +499,7 @@ export class MetadataManager implements IMetadataService {
// Realtime service for event publishing
private realtimeService?: IRealtimeService;

// ── Cluster wiring (cluster-semantics.mdx §5) ────────────────────────
// ── Cluster wiring (`content/docs/kernel/cluster.mdx` §6.2, lane 1) ──
// When attached via `attachClusterPubSub()`, metadata-change events
// become cluster-wide:
// • Local notifyWatchers() publishes on `metadata.changed` so peers
Expand Down Expand Up @@ -3108,8 +3108,8 @@ export class MetadataManager implements IMetadataService {
protected notifyWatchers(type: string, event: MetadataWatchEvent) {
this.notifyWatchersLocal(type, event);

// Cluster fan-out (cluster-semantics.mdx §5). Best-effort: a publish
// failure must never block the local update.
// Cluster fan-out (`content/docs/kernel/cluster.mdx` §6.2, lane 1).
// Best-effort: a publish failure must never block the local update.
if (this.clusterPubSub) {
const payload: ClusterMetadataChangedPayload = {
originNode: this.clusterNodeId,
Expand Down
2 changes: 1 addition & 1 deletion packages/spec/src/kernel/events/core.zod.ts
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ export const EventMetadataSchema = lazySchema(() => z.object({
* @see content/docs/kernel/cluster.mdx §4
*/
cluster: EventClusterOptionsSchema.optional()
.describe('Per-emit cluster routing & delivery options. See cluster-semantics.mdx §4.'),
.describe('Per-emit cluster routing & delivery options. See /docs/kernel/cluster §4.'),
}));

// ==========================================
Expand Down
2 changes: 1 addition & 1 deletion packages/spec/src/kernel/service-registry.zod.ts
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ export const ServiceMetadataSchema = lazySchema(() => z.object({
* @see content/docs/kernel/cluster.mdx §5
*/
cluster: ServiceClusterAnnotationsSchema.optional()
.describe('Cluster scope & leader strategy. See cluster-semantics.mdx §5.'),
.describe('Cluster scope & leader strategy. See /docs/kernel/cluster §5.'),
}));

export type ServiceMetadata = z.input<typeof ServiceMetadataSchema>;
Expand Down
Loading