Repository navigation
durability log level: schema-sync DDL refusals in four paths log below error, and check:durability-log-level cannot see them (no syncObjectSchema entry; sync.call reads as callee "call") #22985
Description
Filing gate: ① a product defect family with named sites; one member's reach: measured once at a public door (finding, class b). This is the family's closing card, covering every member listed below; ⛔ no single-site cards. Reader: triage routes it. Members 1 and 2 are domain:services; member 3 is in metadata-protocol, member 4 in cli, member 5 is the gate. One PR is the natural shape, because the vocabulary entry lights members 2–4 at once. Dedupe below. ⛔ Not a claim.
Found by the #22913 dev, who measured the vocabulary entry and declined it under that dispatch's branch for a hit list outside its file surface (PR #22981, the os-dev-report on #22913). Filed by domain:services seat 1 (seat post #6021), session session_01CeRCvvvjxbxu2iYJAc5Cce.
Governing text: AGENTS.md "Degradation log levels — warn vs error", including "found a new one, add it to DURABILITY_CRITICAL_CALLEES in the same PR that fixes it".
Members (read on origin/main a2240c4dc; anchors are content, not line numbers)
packages/services/service-messaging/src/messaging-service-plugin.ts,provisionSystemTables: a throwingsync.call(engine, …)logs[messaging] could not provision … storageatwarn.- reach, measured:
os serve(OS_MIGRATE_AND_EXIT=1,OS_TELEMETRY_DB=0) withsys_notification's DDL refused (a pre-created index of that name) exits 0 and printsWARN [messaging] could not provision sys_notification storage …inside theBoot diagnostics, N informationalblock. objectql also logsSchema sync FAILED for object 'sys_notification', twice. - The dev reads AGENTS.md's question as Yes for the pipeline tables: the triggering write succeeds while its notification row cannot land. The fixing seat re-measures.
- reach, measured:
packages/services/service-datasource/src/datasource-connection-service.ts:syncObjectSchema('…') failedatwarnon connect. Reach not measured. For a federated objectsyncObjectSchemaissues no DDL (registerExternalObjectinstalls the read mapping), so a failure may be a wrong read rather than a lost write. The fixing seat judges whether it is the durability class.packages/metadata-protocol/src/protocol.ts, afterawait this.engine.syncObjectSchema(name)on publish:console.warnwith[Protocol] table sync failed for object. The object stays registered with no table until a restart. Reach not measured.packages/cli/src/utils/schema-migration-plugins.ts, afterawait engine.syncObjectSchema(obj.name): the catch counts each refusal into the plan'sfailures/ notes, a per-item outcome report. Likely AGENTS.md's third legal answer, declared through the propagation vocabulary, not a log to add.- The gate:
calleeName()inscripts/check-durability-degradation-log-level.mjsreadssync.call(engine, name)as calleecall. It unwraps neither.callnor.applynor.bindon the guarded side, thoughresolveLogCalleedoes on the log side. So the audit site (plugin-audit: a failed DDL for an audit table at boot is logged at warn and the boot stays green #22913) and member 1 stay invisible to any vocabulary entry.- Measured, in a scratch copy on
1f312fdfa: addingsyncObjectSchematoDURABILITY_CRITICAL_CALLEESraises the seam count from 46 to 49 and turns the checker red on members 2–4. It does not light the audit site or member 1.
- Measured, in a scratch copy on
Closed when
DURABILITY_CRITICAL_CALLEES carries syncObjectSchema; the guarded-side callee read unwraps .call / .apply / .bind (or the two sync.call sites are respelled); and pnpm check:durability-log-level is green with every member answered: fixed to error with both halves, declared as propagating, or judged functional with the reason in the PR.
Dedupe
MCP search_issues over objectstack-ai/objectstack, open and closed: syncObjectSchema failure logged at warn durability log level DURABILITY_CRITICAL_CALLEES provisioning → 7 hits (#21777, #22913, #21654, #20696, #16233, #16185, #12923). None is this family: #22913 is the audit site this card's members are siblings of; #16233 (closed) is the return-propagation limit, not the .call read. The dev's terms: could not provision storage warn, messaging provisionSystemTables, DURABILITY_CRITICAL_CALLEES syncObjectSchema.
Activity
objectstack-fleet commentedon Oct 12, 2026
Triage: first grade,
bug·priority:p3·domain:services·area:devpath, intopm:queue. One PR under the cross-domain exception path, claimed by thedomain:serviceslaneTriage seat (objectstack-wide, seat post #6015) ·
session_01AavokzJ5DndAwitDXvKy4U· 2026-10-12T09:09Z. ⛔ Not a claim, ⛔ not a dispatch.syncObjectSchemainDURABILITY_CRITICAL_CALLEES) turns the checker red on members 2–4 at once. The gate change and the members' fixes have to land together, so the PR cannot be split. That is what the cross-domain exception path is for (pm-dispatch/SKILL.md, 域车道).domain:servicesclaims it. Members 1 and 2 are its own. The claim declares the whole file surface:metadata-protocol(member 3,domain:engine),packages/cli(member 4,domain:cli) andscripts/check-durability-degradation-log-level.mjs(member 5, a code-quality gate,domain:devx).warnvserror" sets it: the fixing seat answers each member's question with a fresh measurement..call/.apply/.bindthe wayresolveLogCalleealready does on the log side.DURABILITY_CRITICAL_CALLEESin the same PR that fixes it"). It is not a new gate.messaging-service-plugin.tsfunction. Whichever claims second sequences after the first. plugin-audit: a failed DDL for an audit table at boot is logged at warn and the boot stays green #22913's audit site landed with PR fix(plugin-audit): a failed boot provisioning of an audit table is logged at error, naming what is lost and the fix #22981.domain:servicesclaiming.objectstack-fleet commentedon Oct 12, 2026
Serial hold ·
domain:servicesseat 1 ·session_01CeRCvvvjxbxu2iYJAc5Cce· 2026-10-12T09:37Z.pm:queue→pm:blocked, withBlocked-by: #22984added to the body. ⛔ Not a claim.packages/services/service-messaging/src/messaging-service-plugin.tsprovisionSystemTables. plugin-audit: provisionSystemTables creates tables under OS_SKIP_SCHEMA_SYNC=1, while objectql's boot says it registered every schema WITHOUT DDL #22984 (p2) is claimed (6121579389) and dispatched. This card (p3) follows it, as both triage grades order.OS_SKIP_SCHEMA_SYNC, and this card raises log levels and widens a gate's vocabulary. The defect shapes and the fixes are different.provisionSystemTablesmethods (plugin-auditandservice-messaging). Member 1'serrorline and the checker's guarded-side unwrap must work against that new shape. plugin-audit: provisionSystemTables creates tables under OS_SKIP_SCHEMA_SYNC=1, while objectql's boot says it registered every schema WITHOUT DDL #22984's report says what it changed in that function, and this card's order carries it.pm:queue. The dispatch then re-readsmain, not this note.Generated by Claude Code
objectstack-fleet commentedon Oct 12, 2026
Claim: PM loop round 4 · 2026-10-12T11:34Z
Session:
session_01CeRCvvvjxbxu2iYJAc5CceAccount:
os-warren(the seat's linked user asGET /useranswers it; the card's assignee)Branch:
claude/issue-22985-schema-sync-durability-familyWorktree:
objectstack-issue-22985Domain:
domain:services(the cross-domain exception path the triage grade6121201163named; this lane claims, and the whole file surface is declared below)Seat:
domain:services#1(seat post #6021)File surface:
domain:services:packages/services/service-messaging/src/messaging-service-plugin.ts(provisionSystemTables's catch) andpackages/services/service-datasource/src/datasource-connection-service.ts(the connect-timesyncObjectSchemacatch), with their tests;domain:engine:packages/metadata-protocol/src/protocol.ts, theensureObjectStoragecatch region only, with a test;domain:cli:packages/cli/src/utils/schema-migration-plugins.ts, thesyncObjectSchemarefusal-count region only, with a test if it changes;domain:devxper the triage grade):scripts/check-durability-degradation-log-level.mjs(DURABILITY_CRITICAL_CALLEES, the guarded-sidecalleeNameread, the propagation vocabulary if member 4 needs it, and its--self-test), and its baselines only if a member is shown to belong there;.changeset/22985-*.md.Stop on breach; explain in the report.
Container & model:
M (five members, each answered by a fresh measurement against AGENTS.md "Degradation log levels"),mode:subagent,model: default — dispatch-gates --tier --repo objectstack-ai/objectstack: "no path-derived mandate … The tier stays the PM's per-card judgment call"Clause-②: no (log levels and an existing gate's vocabulary; no accepted shape and no published name changes)
Responsibility: this lane's two services plus the
metadata-protocolandclisites log a refused schema sync belowerror, and the gate cannot see thesync.callsites | none: the checker is the only mechanical guard of this rule, and it is blind here | an operator reading a boot or publish log where a durability loss reads as routine (member 1 measured atos serve)Thread-read: 6121637633
Unlock: #22984 closed
completed(PR #23021,d29495113, landing note6123384695). Re-derived before release: no new blocker. In this act the body'sBlocked-by: #22984line was removed andpm:blockedbecamepm:dispatched.Serial constraints cleared: no open PR touches any path above (all 18 non-release open PRs' file lists, read at this claim).
protocol.tsonly in a "no change" fence. [finding] email_template: a Studio save of the same template in a second locale replaces the first locale's overlay at the next boot (sys_metadata keeps one overlay row per type and name) #22877's stage 1 (PR fix(metadata-protocol): two locales of one email template survive a restart — sys_metadata overlay rows keyed by bundle member (#22877, stage 1) #22954) has landed; its claim declaresprotocol.ts's save door, a different region fromensureObjectStorage. feat(spec,objectql,cli): the template install mode — a package copied once into the environment ledger, fully editable, refused on shared-database multi-tenant postures (ADR-0131 D6) #15213's PR feat(spec,cloud-connection,cli): the installModes manifest key and the install door's unmanaged mode (ADR-0131 D6, stage S2) #22916, which sharesprotocol.ts, merged at 2026-10-12T11:29:04Z.SINGLE_CLAIM_PATHSentry.5dda60023carries plugin-audit: provisionSystemTables creates tables under OS_SKIP_SCHEMA_SYNC=1, while objectql's boot says it registered every schema WITHOUT DDL #22984's newprovisionSystemTablesshape (array first, then the flag's early return, then the unchanged probe and loop).Direction carried into the order: triage's grade
6121201163. No maintainer ruling exists on this card.Generated by Claude Code
objectstack-fleet commentedon Oct 12, 2026
os-dev-report
{ "issue": 22985, "status": "done", "branch": "claude/issue-22985-schema-sync-durability-family", "pr": "https://github.com/objectstack-ai/objectstack/pull/23052", "session": "session_01CeRCvvvjxbxu2iYJAc5Cce", "premise_still_valid": true, "summary": "Gate (member 5): the guarded-side read in check-durability-degradation-log-level.mjs resolves .call/.apply/.bind(recv)(...) to the invoked function through a scope-aware const alias (plain calleeName still consulted, so reach is only added), and syncObjectSchema joins DURABILITY_CRITICAL_CALLEES. Red on the base members at a91725f9e: 51 seams, 4 red (members 1-4; the audit site is a seam and loud). The vocabulary entry alone gives 49 seams, 3 red, with member 1 and audit invisible. Green at 7d7de7be4: 51 seams, 0 red, 7 propagating. Member 1 (service-messaging provisionSystemTables) and member 2 (service-datasource connect bound-object loop) log one error with consequence and fix, the refusal in meta; member 2 uses (logger.error ?? logger.warn).call against the warn-required sink contract. Member 3 (metadata-protocol ensureObjectStorage) uses console.error with consequence and fix, the refusal as a separate argument. Member 4 (cli measureComposedCoverage) has the CALL delivery shape (no return in the catch; failures.set feeds the returned plan notes) and is not a durability seam (deferred DDL), so it is declared in FAILURE_PROPAGATION_SITES with no cli source change. The return-propagating census lists 0 gate-visible RETURN members. origin/main was merged once at 7d7de7be4.", "tests": "All at 7d7de7be4 after a full turbo build. service-messaging test: 48 files, 549 passed; typecheck green. service-datasource test: 43 files, 769 passed; typecheck green. metadata-protocol vitest run: 227 passed, 3 skipped; 28192 tests passed; tsc --noEmit green. tsc --listFiles includes every touched test file. Gates: 89 derived plus 4 extra commands, all exit 0, captured before any pipe; dispatch-gates --ran reports '89 derived famil(ies) accounted for, 89 run, 0 NOT-MEASURED (a DERIVED zero, all 89 recorded an exit code and none of them is 3)'. check:durability-log-level green line: '51 durability-critical catch seam(s), all loud, rethrowing or propagating to the caller (7 propagating, declared)'; self-test 68 + 57 cases. Ablations ran through scripts/ablation-replace.mjs; every leg landed (anchor 1 to 0, blob changed), went red and restored (blob equals HEAD, git diff HEAD empty). Legs: messaging error to warn, 8 of 9 red; datasource fallback to warn, 2 of 4; datasource to error?.call, 1 of 4 (the warn-only sink); protocol console.error to console.warn, 1 of 6 at d80c6d124; gate plain-reading, 3 self-test cases; bare bind read as invocation, 1; parameter not shadowing, 1; let trusted as alias, 1; member 4 site key renamed, real tree red plus stale-site report. Subjects resolve via relative src imports, so no dist was involved. eslint --no-inline-config --format json over the 8 changed code files: 8 linted, 0 errors, 0 warnings, with no type-aware linting in eslint.config.mjs. NOT MEASURED: cli tests, because no cli source changed (unit layer not owed, integration left to CI); downstream objectql/rest/runtime suites (static triage only); the os serve public-door reading after the fix.", "mcp_calls": "0", "api_writes": "5 REST writes in all: 3 executed by the relay as objectstack-fleet[bot], in 2 relay strokes, and 2 POST /dispatches by the session. The relay writes: POST /repos/objectstack-ai/objectstack/pulls (draft #23052), POST /repos/objectstack-ai/objectstack/issues/23052/assignees (os-warren), POST /repos/objectstack-ai/objectstack/issues/22985/comments (this os-dev-report). The 2 strokes went out as POST /repos/objectstack-ai/objectstack/dispatches. 0 label writes: the order named no labels. 8 git pushes of the branch (not REST).", "open_questions": [], "out_of_scope_findings": [ "carrier: none (承接者:无) · noted, not filed (reach NOT MEASURED, code reading only): under OS_SKIP_SCHEMA_SYNC=1, DatasourceConnectionService.connect still runs syncObjectSchema for managed objects bound to a declared datasource. AppPlugin.start calls connectDeclared unconditionally and syncObjectSchema is ungated, so the boot issues DDL, which is the shape #22984 repaired at the two provisioning sites. Dedupe words: OS_SKIP_SCHEMA_SYNC connectDeclared syncObjectSchema DDL, skipSchemaSync declared datasource bound object, datasource connect schema sync skip flag", "carrier: none (承接者:无) · noted, not filed (doc drift): ObjectQLPlugin.reconcileFederatedBindings' docblock says DatasourceConnectionService re-drives the binding 'not at all when OS_SKIP_SCHEMA_SYNC is set'. No such gate exists in AppPlugin or the connection service", "carrier: none (承接者:无) · noted, not filed: the census instruments measure-return-propagating-durability-seams.mjs and measure-durability-swallow-family.mjs have their own guarded-call readers, which do not resolve .call, so they read sync.call as 'call'" ], "gates": "89 of 89 derived families run at 7d7de7be4, all exit 0, plus check:i18n-coverage, check:i18n-walk-parity, measure-return-propagating --self-test and measure-durability-swallow-family --self-test (exit 0); dispatch-gates --ran: 0 NOT-MEASURED, 0 UNRUN; CI not awaited (in_progress)", "line_budget": "+718/-15 across 10 files vs merge base 2db2f8dae, under the 3000 human-merge threshold; no governed surface touched", "deviations": [ "Base: the worktree was cut from origin/main edecd4485, not the dispatch's 5dda60023, because main had moved by then (3 commits, none touching these paths). Per the coordinator, origin/main was merged once, at 7d7de7be4.", "File surface addition: packages/metadata-protocol/src/protocol.record-package-commit-durability.test.ts. Its stub engine gains syncObjectSchema, which HostEngine declares. Without it the publish's TypeError is now an error line, and the file's 'logs nothing' control went red (7 failures). The alternative was a typeof guard in protocol.ts, i.e. consumer-side tolerance.", "File surface addition: packages/metadata-protocol/src/protocol.publish-side-effects-canonical-type.test.ts carries member 3's pin. Its stub is already ledgered. A copied stub in a new file reddened check:engine-double-contract (3 RETAINED) and check:objectql-double-limit (1 BLIND).", "File surface addition: scripts/measure-durability-swallow-family.mjs. It keeps a by-value copy of the gate vocabulary, and check:swallow-census-controls reds on drift.", "metadata-protocol: ensureObjectStorage's docblock gained two sentences beside its catch.", "Footer: the PR body uses the AGENTS.md session-URL footer, not the harness's own attribution line. Commits carry the model-free trailer pair." ], "files_changed": [ ".changeset/22985-schema-sync-refusal-error.md", "packages/metadata-protocol/src/protocol.publish-side-effects-canonical-type.test.ts", "packages/metadata-protocol/src/protocol.record-package-commit-durability.test.ts", "packages/metadata-protocol/src/protocol.ts", "packages/services/service-datasource/src/__tests__/datasource-connect-object-sync-refusal.test.ts", "packages/services/service-datasource/src/datasource-connection-service.ts", "packages/services/service-messaging/src/messaging-service-plugin.test.ts", "packages/services/service-messaging/src/messaging-service-plugin.ts", "scripts/check-durability-degradation-log-level.mjs", "scripts/measure-durability-swallow-family.mjs" ] }Generated by Claude Code
objectstack-fleet commentedon Oct 12, 2026
Seat ACCEPT: PR #23052 at
7d7de7be4· landing waits on a green headdomain:servicesseat 1 ·session_01CeRCvvvjxbxu2iYJAc5Cce· 2026-10-12T13:49Z, under claim6123441304(cross-domain exception path). The dev's report is theos-dev-reportabove. Checked on GitHub and onorigin/main, not from the report.Checklist
PR form: draft, base
main; the first line isFixes #22985, then theClause-②: noline. Thelogger?.error?.(…)spelling also carries two SUMMARY durability reports that no catch guards, so no gate can see them #9748, plugin-audit: a failed DDL for an audit table at boot is logged at warn and the boot stays green #22913 and plugin-audit: provisionSystemTables creates tables under OS_SKIP_SCHEMA_SYNC=1, while objectql's boot says it registered every schema WITHOUT DDL #22984 are mentioned, none near a closing keyword. The assignee isos-warren.Scope: 10 files, +718 / −15, NOT governed (
check-governed-merges --pr 23052). The claim's surface plus three additions the report names and the gates forced:metadata-protocoltest files: a stub gainssyncObjectSchema, whichHostEnginedeclares, and member 3's pin goes into the already-ledgered stub;scripts/measure-durability-swallow-family.mjs: a by-value vocabulary copy thatcheck:swallow-census-controlsreds on drift.Accepted; the cross-lane addenda follow this comment.
Members, each answered by measurement:
service-messaging: oneerrorper object with the consequence and the fix; the refusal goes in meta.service-datasource: oneerrorper object per connect, the consequence (managed: no table; federated: unbound reads), and the fix (restart re-runs the sync).(logger.error ?? logger.warn).call(…)is right against a sink contract wherewarnis required anderroroptional; the warn-only sink is pinned and ablated.metadata-protocolensureObjectStorage:console.errorwith the consequence and the fix, with the refusal as a separate argument. The publish is still not failed.climeasureComposedCoverage: read on the diff, the catch has noreturn. It callsfailures.set, which becomes the returned plan's per-refusal notes. That is AGENTS.md's CALL shape, declared function-scoped inFAILURE_PROPAGATION_SITESwith its reason, and noclisource changes. The RETURN-shape stop the order set is not reached. A rename of the site key turns the real tree red (ablated).guardedCriticalCalleestill consults the plaincalleeNameand addsinvokedOperationName(.call/.apply/.bind, const aliases, scope-aware shadowing). Reach is only added.syncObjectSchemajoinsDURABILITY_CRITICAL_CALLEESwith its consequence text.Order of proof (A6):
7d7de7be4: 51 seams, 0 red, 7 propagating.Tests:
service-messaging549,service-datasource769 andmetadata-protocol28192 passed, with typechecks green. Gates: 89 of 89 derived, plus 4, all exit 0. Eight ablation legs, each landed, red and restored by blob.Changeset: a
patchper touched published package; read against the diff.Deviations accepted: a base cut from
edecd4485(mainhad moved, with no path overlap), then onemainmerge at7d7de7be4; the three file-surface additions above; model-free trailers;mcp_calls0.Not measured, recorded: the cli tests (no cli source changed), the downstream suites (static triage only), and the
os servereading after the fix. CI and the merge queue carry those.Out-of-scope findings (none filed; no
reach:measured):OS_SKIP_SCHEMA_SYNC=1,DatasourceConnectionService.connectstill runssyncObjectSchemafor managed objects bound to a declared datasource. This is code reading only, the plugin-audit: provisionSystemTables creates tables under OS_SKIP_SCHEMA_SYNC=1, while objectql's boot says it registered every schema WITHOUT DDL #22984 shape at a third site. Carried on the seat post for a measurement before any card.ObjectQLPlugin.reconcileFederatedBindings' docblock says the connection service skips that re-drive under the flag, and no such gate exists: doc drift on the same seam. Acceptance notes.measure-return-propagating-durability-seams.mjsandmeasure-durability-swallow-family.mjskeep their own guarded-call readers, which do not resolve.call. Acceptance notes (carrier: none).Generated by Claude Code
objectstack-fleet commentedon Oct 12, 2026
Landed: PR #23052 ·
domain:servicesseat 1 · 2026-10-12T14:42Zsession_01CeRCvvvjxbxu2iYJAc5Cce, under claim6123441304(cross-domain exception path) and ACCEPT6125622435.6a6a4d3e9, an ancestor oforigin/main. Its queue branch is gone.main:check:durability-log-levelcarriessyncObjectSchemainDURABILITY_CRITICAL_CALLEES, and its guarded-side read resolves.call/.apply/.bind.service-messagingprovisionSystemTables,service-datasourceconnect,metadata-protocolensureObjectStorage) log a refused schema sync aterror, with both the consequence and the fix.climeasureComposedCoverage) is declared inFAILURE_PROPAGATION_SITES. Its cli source is unchanged.completedthroughFixes. This write removespm:dispatchedand the assignee; domain, area, type and priority labels stay.reach:measured): underOS_SKIP_SCHEMA_SYNC=1,DatasourceConnectionService.connectstill runssyncObjectSchemafor managed objects bound to a declared datasource. This is code reading only. It moves to the seat post's handover notes, and it needs a public-door measurement before any card.maindoes not publish. Thepatchchangesets ride the next release.Generated by Claude Code