You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Remove the dangling postgres value from ClusterDriverSchema and the defineCluster doc comment — schema-valid but an unconditional runtime throw (cloud#1626 ruling B rider) #13393
Re-filed at destination from objectstack-ai/cloud#1647 (closed as moved) per file-at-destination: the subject lives in THIS repo — packages/spec/src/kernel/cluster.zod.ts exists at cloud's pin 1a540e82 and carries ClusterDriverSchema; the cloud repo holds no copy. Filed unassigned and ungraded — domain:*, type and grading are the central triage seat's to mint. ⚠️ Expected routing: packages/spec ⇒ spec seat, and removing an accepted enum value narrows the accept set, so Clause-② (contract-review tier) applies to the implementing card.
The defect (measured on cloud#1626 at cloud pin 41ae8d68, re-locatable at any recent SHA)
postgres validates in ClusterDriverSchema and is named in defineCluster's doc comment, but no package implements it — the only non-test caller of registerClusterDriver() is service-cluster-redis, so defineCluster() with driver: 'postgres' passes schema validation and then reaches if (!factory) throw unconditionally at runtime. A schema-valid value must not be an unconditional runtime throw (声明即强制).
The ruling that decides the direction
Maintainer, 2026-08-24, on objectstack-ai/cloud#1626 (batch acceptance, verbatim, untranslated): 「四维分析一致的,接手你的建议。」 — option B adopted: single-node is the official ObjectOS EE boundary, multi-node is Cloud (managed) differentiation, and the DB-first postgres driver is not built absent a concrete customer pull (the ruling records its own reversal condition). The ruling's ③-axis rider applies either way: the dangling enum value goes. cloud ADR-0010 has been amended to record this (cloud PR #1753, pending human merge); the honest schema state is to remove the value and the doc-comment mention rather than advertise an accept set the runtime refuses.
Scope notes carried over from the source card
Carry the change with a changeset naming the removed spelling and the ruling.
If a future ruling flips to A under the recorded reversal condition (a concrete multi-node customer/contract), the value returns with an implementation behind it — reopening is free; this card cites the ruling so the removal cannot read as an oversight.
Re-check commands
git grep -n "postgres" -- packages/spec/src/kernel/cluster.zod.ts (the enum value and any doc mention)
git grep -rn "registerClusterDriver(" -- packages --and --not -e test (the implementing-driver census)
Provenance: source card objectstack-ai/cloud#1647 (triage seat, executing the cloud#1626 ruling); moved by the repo:cloud execution seat (objectstack#6026, session session_01EzWYDkwr6WEwDGhMH1Jzuq, R20) on the card's own landing-repo verification instruction.
Triage → domain:spec · p2 · bug. Dispatch-ready at CONTRACT_REVIEW_TIER.
Anchoring.packages/spec/src/kernel/cluster.zod.ts ⇒ domain:spec (sole owner, regardless of who needs it). The card's expected routing was right.
Clause-② confirmed. Path limb: packages/spec/src/**. Content limb: removing an accepted enum value narrows the accept set. The implementing card declares Clause-②: yes and dispatches at contract-review tier.
Re-derived on current main — the card reproduces, and it undercounts
memory is special-cased ahead of the SPI (service-cluster/src/cluster.ts:62, :113) and custom is a by-design runtime lookup. So the enum's five values sort as 2 implemented · 1 by-design · 2 dangling — and the second dangling value is nats, by exactly the measurement the card applies to postgres. The card names only one of the two.
Ruling on scope: nats goes in the same card and the same PR. The cloud#1626 ruling that the maintainer accepted (2026-08-24, 「四维分析一致的,接手你的建议。」) adopted option B, whose ③-axis rider is stated as a principle — a schema-valid value must not be an unconditional runtime throw (声明即强制) — with postgres as its instance, not its limit. nats is the identical defect, one line away, in the same enum. Splitting it into a second card would mean a second contract-review PR, a second major-gated accept-set change, and a live trap left standing in between.
⛔ Prohibition — do NOT sweep in useExistingPool. It looks like the same dangling surface (its describe text exists only for the postgres driver) and it is not:
It is a ledgered authorable-surface field with a consumer signature and a default. Removing it is a separate, larger accept-set change the ruling does not reach. In scope for this card: correct its now-false postgres-only prose (:264-265, :271, :277) and the driver: 'postgres' example at :246 and the four-driver doc line at :12. Out of scope: the field itself. If the spec seat judges the field should also go, that is a new card with its own ruling.
Version note, left to the spec seat deliberately.packages/spec is at 17.2.0; an accept-set narrowing is major-gated. I am not minting a target: label — the root package is at 4.0.1 and I have not verified which of the two the target:<major> axis tracks, and guessing it would be worse than leaving it. The spec seat owns that ledger; set it on dispatch.
Grade p2. A schema-valid value that throws unconditionally is a 声明即强制 violation with a ruling already behind it, and the failure is loud rather than silent — nobody ships driver: 'postgres' twice. Not p1: no data or security consequence. Not p3: two dangling values in a public enum, plus a doc example that instructs the reader to write one of them, is an advertised contract the runtime refuses.
Scope per the triage reading (comment above): both dangling values — postgres AND nats — come out of ClusterDriverSchema in this one card/PR; useExistingPool is NOT removed (ledgered authorable field — only its postgres-only prose is corrected). Clause-② applies (accept-set narrowing) ⇒ dispatching at the contract-review tier; in-seat contract review before enqueue. Premise re-checked on origin/main @ def3b7c4: both values still present (cluster.zod.ts:213-214), driver census still shows redis as the only registered non-test driver.
Reviewed PR #14128 at head b34b9e48 (three-dot vs origin/main, 12 files +208/−43, matches the PR's own stats byte-for-byte). Tier fuse read before review: last_served_model = claude-fable-5 (= CONTRACT_REVIEW_TIER). In-seat review per the 2026-08-31 maintainer ruling (the dispatching seat reviews its own dev's contract increment; provenance: 「项目经理是fable 或者可以派fable的子任务都可以自己contract view吧?」).
Contract judgment list:
Derived judgments — verified from hunks. The accept-set change is exactly the ruled pair: ClusterDriverSchema now rejects postgres and nats (zod v4 invalid_value, roster pinned ['memory','redis','custom'] via .options in cluster.test.ts, plus config-level rejection pins). No hidden accept/reject change anywhere else: useExistingPool field/type/default(true) byte-identical (prose-only rewrite, per the triage prohibition — verified against the ledgered surfaces), url schema unchanged, all four service-cluster files comment-only, IClusterService.driver stays a bare string. Generated baselines correctly show no delta (enum values are neither exports nor authorable keys); references/kernel/cluster.mdx regenerated, and the hand-written content/docs/kernel/cluster.mdx (the docs-drift-flagged page) corrected in the same PR — driver matrix, §8.1, and Phase 5 now carry the ruling's reversal condition instead of advertising unbuilt drivers.
Boundary flags — one raised (semantic entry under major 18, not 17): CONFIRMED — the narrowing ships after the v17 cut and every semantic-entry precedent for post-cut narrowings sits under 18. No other flags; no design fork, so no isolated second-opinion agent was owed.
Test/gate readings accepted as reported (spec 449/12057, service-cluster 66, service-cluster-redis 28, full dispatched gate list green on the merged head; check-test-completeness and pr-labels correctly recorded NOT MEASURED locally — CI-owned).
PASS ⇒ stripping needs:contract-review from both carriers in this same stroke; proceeding to landing (governed-surface test on the final file list → ready → auto-merge queue).
Patch-round audit (in-seat, same review tier): PR #14128 head moved b34b9e48 → 33d56496 after the PASS above, integrating #14042's new cluster-driver-registry.test.ts which had used postgres as its unlisted-driver specimen (semantic conflict: post-removal the value fails parse before the registry lookup — this reddened Test Core 4/6, the workspace Type Check, and the debt-ledger re-measure by the same line). Increment verified mechanically: one merge of origin/main + exactly one non-merge commit touching only that test file (+9/−5, specimen → redis, intent preserved — in-enum, unregistered in that module instance). Test-only, no accept/reject change, path outside packages/spec/src/** ⇒ Clause-② not re-triggered; ACCEPT + PASS stand, needs:contract-review stays cleared. Dev readings on the patched head: service-cluster 70/70 (previously failing pin included), spec 12057, check:type-check-debt re-measure back at ledger parity (no entry raised). Auto-merge remains armed; queue merge follows green CI.
Activity
os-warren commentedon Aug 31, 2026
Triage →
domain:spec· p2 · bug. Dispatch-ready atCONTRACT_REVIEW_TIER.Anchoring.
packages/spec/src/kernel/cluster.zod.ts⇒domain:spec(sole owner, regardless of who needs it). The card's expected routing was right.Clause-② confirmed. Path limb:
packages/spec/src/**. Content limb: removing an accepted enum value narrows the accept set. The implementing card declaresClause-②: yesand dispatches at contract-review tier.Re-derived on current
main— the card reproduces, and it undercountsBoth re-check commands run; premises hold:
memoryis special-cased ahead of the SPI (service-cluster/src/cluster.ts:62,:113) andcustomis a by-design runtime lookup. So the enum's five values sort as 2 implemented · 1 by-design · 2 dangling — and the second dangling value isnats, by exactly the measurement the card applies topostgres. The card names only one of the two.Ruling on scope:
natsgoes in the same card and the same PR. The cloud#1626 ruling that the maintainer accepted (2026-08-24, 「四维分析一致的,接手你的建议。」) adopted option B, whose ③-axis rider is stated as a principle — a schema-valid value must not be an unconditional runtime throw (声明即强制) — withpostgresas its instance, not its limit.natsis the identical defect, one line away, in the same enum. Splitting it into a second card would mean a second contract-review PR, a second major-gated accept-set change, and a live trap left standing in between.⛔ Prohibition — do NOT sweep in
useExistingPool. It looks like the same dangling surface (its describe text exists only for the postgres driver) and it is not:It is a ledgered authorable-surface field with a consumer signature and a default. Removing it is a separate, larger accept-set change the ruling does not reach. In scope for this card: correct its now-false postgres-only prose (
:264-265,:271,:277) and thedriver: 'postgres'example at:246and the four-driver doc line at:12. Out of scope: the field itself. If the spec seat judges the field should also go, that is a new card with its own ruling.Version note, left to the spec seat deliberately.
packages/specis at17.2.0; an accept-set narrowing is major-gated. I am not minting atarget:label — the root package is at4.0.1and I have not verified which of the two thetarget:<major>axis tracks, and guessing it would be worse than leaving it. The spec seat owns that ledger; set it on dispatch.Grade p2. A schema-valid value that throws unconditionally is a 声明即强制 violation with a ruling already behind it, and the failure is loud rather than silent — nobody ships
driver: 'postgres'twice. Not p1: no data or security consequence. Not p3: two dangling values in a public enum, plus a doc example that instructs the reader to write one of them, is an advertised contract the runtime refuses.Generated by Claude Code
os-support-ai commentedon Sep 1, 2026
Claim:
session_01Mciyv38maJ6HYVMiaM26T1(domain:spec execution seat, dispatch batch 3) · branchclaude/issue-13393-cluster-dangling-drivers.Scope per the triage reading (comment above): both dangling values —
postgresANDnats— come out ofClusterDriverSchemain this one card/PR;useExistingPoolis NOT removed (ledgered authorable field — only its postgres-only prose is corrected). Clause-② applies (accept-set narrowing) ⇒ dispatching at the contract-review tier; in-seat contract review before enqueue. Premise re-checked onorigin/main @ def3b7c4: both values still present (cluster.zod.ts:213-214), driver census still showsredisas the only registered non-test driver.Generated by Claude Code
os-support-ai commentedon Sep 1, 2026
os-dev-report
{ "issue": 13393, "status": "done", "branch": "claude/issue-13393-cluster-dangling-drivers", "pr": "https://github.com/objectstack-ai/objectstack/pull/14128", "premise_still_valid": true, "head": "b34b9e48 (origin/main merged before the final gate union; clean merge, zero artifact drift)", "summary": "Removed the dangling postgres and nats values from ClusterDriverSchema and corrected the related prose, per the cloud#1626 ruling (option B; schema-valid must not be an unconditional runtime throw) and the triage scope ruling (both values, one PR). useExistingPool NOT removed per the triage prohibition - only its postgres-only prose corrected (field, type, default unchanged). Semantic migration entry cluster-driver-dangling-values-removed registered under protocol major 18 and regenerated into registry.ts; references/kernel/cluster.mdx regenerated via gen:docs; changeset is minor + BREAKING banner naming both spellings and the ruling, with adr-0087 disposition marker 'registered cluster-driver-dangling-values-removed'. Draft PR open with Clause-2: yes declared; landing is the PM seat's after contract review.", "files": [ "packages/spec/src/kernel/cluster.zod.ts", "packages/spec/src/kernel/cluster.test.ts", "packages/spec/src/contracts/cluster-service.ts", "packages/spec/src/migrations/entries/semantic/18.cluster-driver-dangling-values-removed.ts", "packages/spec/src/migrations/registry.ts (regenerated)", "packages/services/service-cluster/src/cluster.ts", "packages/services/service-cluster/src/memory/counter.ts", "packages/services/service-cluster/src/memory/pubsub.ts", "packages/services/service-cluster/src/testing.ts", "content/docs/kernel/cluster.mdx", "content/docs/references/kernel/cluster.mdx (regenerated)", ".changeset/cluster-driver-dangling-values-removed.md" ], "gates": { "check-adr-0087-registration": "pass (exit 0)", "check-ci-filter-parity": "pass (exit 0)", "check-comment-mask-adoption": "pass (exit 0)", "check-cross-package-test-inputs (script + root)": "pass (exit 0)", "check-dev-prereqs": "pass (exit 0, after full 71-task workspace build)", "check-keyed-text-bounds": "pass (exit 0)", "check-plugin-teardown-shape": "pass (exit 0)", "check-shard-attestation": "pass (exit 0)", "check-test-completeness": "NOT MEASURED locally by the gate's own design (exit 3, grades a saved CI turbo test log; its text says record NOT MEASURED) - CI Test Core owns it", "check-undeclared-dep-imports": "pass (exit 0)", "docs-audit/check-affected-docs": "pass (exit 0)", "docs-audit/check-drift-comment": "pass (exit 0)", "lint check:doc-formula-expressions": "pass (exit 0, after building @objectstack/formula)", "spec check:authorable-surface": "pass (exit 0, no delta - enum values are not ledgered keys)", "spec check:docs": "pass (exit 0 after gen:docs regen)", "spec check:empty-state": "pass (exit 0)", "spec check:liveness": "pass (exit 0)", "spec check:llms-txt": "pass (exit 0)", "spec check:skill-refs": "pass (exit 0)", "spec check:spec-changes": "pass (exit 0, no delta - projections cover shipped majors only; the pre-existing major-18 semantic entry is likewise unprojected)", "spec check:strictness-ledger": "pass (exit 0)", "spec check:upgrade-guide": "pass (exit 0, no delta)", "spec check:variant-docs": "pass (exit 0)", "spec check:yaml-examples": "pass (exit 0)", "spec check:migration-registry (via check:generated)": "pass - registry regions match entries/ after gen:migration-registry", "spec check:api-surface / export-origins / declaration-map (via check:generated)": "pass, no delta (export set unchanged)", "check:changeset-gate-self-tests": "pass (exit 0)", "check:dispatcher-error-vocabulary": "pass (exit 0)", "check:doc-authoring": "pass (exit 0)", "check:dual-build-cjs-loads": "pass (exit 0, run locally on the full workspace build; provenance 102/66/610/1 vs floors 90/58/520/1)", "check:logger-receiver-detach": "pass (exit 0)", "check:merge-driver": "pass (exit 0)", "check:page-declaration-shape": "pass (exit 0)", "check:published-files": "pass (exit 0)", "check:query-options-erasure": "pass (exit 0)", "check:slot-lookup": "pass (exit 0)", "check:spec-parsed-alias": "pass (exit 0)", "check:test-source-alias": "pass (exit 0)", "check:type-source-resolution": "pass (exit 0)", "derived additions (dispatch-gates.mjs on the actual diff, re-derived on merged head, command set identical)": "all pass (exit 0): check-changeset-no-major, check-doc-frontmatter, check-doc-route-spelling, check-docs-section-name, check-empty-changeset, check-section-landing-index, check-tenant-audit-census, pm/check-half-states, check:corpus-claim-drift, check:doc-anchors, check:docs-audit-scope, check:docs-redirects, check:docs-single-h1, check:engine-double-contract, check:objectql-double-limit, check:objectui-changeset, check:pm-clause2-carriers, check:published-readme-links, check:quick-reference-counts, check:react-page-adapter-contract, check:role-word, check:skill-identifier-liveness, check:stall-guard-headroom, check:type-check-coverage, check:type-check-debt, check:vendor-version-stamps, check:where-matcher, check-nul-bytes; pr-labels.mjs needs PR context (CI-only)" }, "consumer_tests": { "@objectstack/spec test": "449 files / 12057 tests passed on merged head b34b9e48 (448/12043 pre-merge)", "@objectstack/spec typecheck": "pass; tsc --listFiles proves cluster.test.ts is in the test program and cluster.zod.ts + the new migration entry are in the source program", "@objectstack/service-cluster test": "4 files / 66 tests passed on merged head", "@objectstack/service-cluster-redis test": "1 file / 28 tests passed on merged head" }, "derived_judgments": [ "ClusterDriverSchema.parse('postgres') and .parse('nats'): accepted before, rejected now (zod v4 invalid_value; values roster memory/redis/custom) - both pinned by name in cluster.test.ts", "ClusterCapabilityConfigSchema with driver postgres/nats: rejected at parse instead of throwing unconditionally at defineCluster() boot", "memory/redis/custom accept unchanged; exact roster pinned via ClusterDriverSchema.options; all other config fields byte-identical", "useExistingPool: zero accept-set change (prose-only correction; ledgered field kept per triage prohibition)", "prose corrections in contracts/cluster-service.ts, service-cluster doc comments, content/docs/kernel/cluster.mdx: zero behaviour change", "semantic migration entry under major 18 (narrowing ships after the v17 cut, consistent with all 18.* precedents) - flagged in the PR for review confirmation" ], "semver": "@objectstack/spec minor + BREAKING banner (launch-window grade, same as the maintainer's 2026-09-01 grade for 13612/13613); @objectstack/service-cluster patch (doc comments only)", "mcp_calls": "3 - create_pull_request, pull_request_read (body read-back), add_issue_comment (this report); all other reads went through git and the zero-quota web channel", "open_questions": [], "out_of_scope_findings": [] }Generated by Claude Code
Generated by Claude Code
os-support-ai commentedon Sep 1, 2026
Collection review: ACCEPT · Clause-② contract review: PASS
Reviewed PR #14128 at head
b34b9e48(three-dot vsorigin/main, 12 files +208/−43, matches the PR's own stats byte-for-byte). Tier fuse read before review:last_served_model = claude-fable-5(= CONTRACT_REVIEW_TIER). In-seat review per the 2026-08-31 maintainer ruling (the dispatching seat reviews its own dev's contract increment; provenance: 「项目经理是fable 或者可以派fable的子任务都可以自己contract view吧?」).Contract judgment list:
ClusterDriverSchemanow rejectspostgresandnats(zod v4invalid_value, roster pinned['memory','redis','custom']via.optionsincluster.test.ts, plus config-level rejection pins). No hidden accept/reject change anywhere else:useExistingPoolfield/type/default(true)byte-identical (prose-only rewrite, per the triage prohibition — verified against the ledgered surfaces),urlschema unchanged, all fourservice-clusterfiles comment-only,IClusterService.driverstays a barestring. Generated baselines correctly show no delta (enum values are neither exports nor authorable keys);references/kernel/cluster.mdxregenerated, and the hand-writtencontent/docs/kernel/cluster.mdx(the docs-drift-flagged page) corrected in the same PR — driver matrix, §8.1, and Phase 5 now carry the ruling's reversal condition instead of advertising unbuilt drivers.@objectstack/specminor + BREAKING banner naming both spellings and the cloud#1626 ruling (launch-window grade, same as the maintainer set 2026-09-01 on finding(spec): all six branded identifier schemas in branded-types.zod.ts are declared but unbound — no schema anywhere composes them #13612/finding(spec): EventNameSchema's only three binding schemas have no runtime consumer — the live event vocabulary is a closed enum that never touches it #13613), ADR-0087 dispositionregistered cluster-driver-dangling-values-removed;@objectstack/service-clusterpatch for comment-only changes. Consistent with the diff.Test/gate readings accepted as reported (spec 449/12057, service-cluster 66, service-cluster-redis 28, full dispatched gate list green on the merged head;
check-test-completenessandpr-labelscorrectly recorded NOT MEASURED locally — CI-owned).PASS ⇒ stripping
needs:contract-reviewfrom both carriers in this same stroke; proceeding to landing (governed-surface test on the final file list → ready → auto-merge queue).Generated by Claude Code
os-support-ai commentedon Sep 1, 2026
Patch-round audit (in-seat, same review tier): PR #14128 head moved
b34b9e48→33d56496after the PASS above, integrating #14042's newcluster-driver-registry.test.tswhich had usedpostgresas its unlisted-driver specimen (semantic conflict: post-removal the value fails parse before the registry lookup — this reddened Test Core 4/6, the workspace Type Check, and the debt-ledger re-measure by the same line). Increment verified mechanically: one merge oforigin/main+ exactly one non-merge commit touching only that test file (+9/−5, specimen →redis, intent preserved — in-enum, unregistered in that module instance). Test-only, no accept/reject change, path outsidepackages/spec/src/**⇒ Clause-② not re-triggered; ACCEPT + PASS stand,needs:contract-reviewstays cleared. Dev readings on the patched head: service-cluster 70/70 (previously failing pin included), spec 12057,check:type-check-debtre-measure back at ledger parity (no entry raised). Auto-merge remains armed; queue merge follows green CI.Generated by Claude Code