Repository navigation
feat(spec)!: retire connector.errorMapping — eleven inert authorable keys, one spelled like the live userMessage channel (#14676, ADR-0049) - #15299
Conversation
… conversion, entries, pins, changeset Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01H2oQebDDxYKfWZusyd8GXk
…spec artifacts on the new dist Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01H2oQebDDxYKfWZusyd8GXk
…tire-connector-error-mapping
…keys, one spelled like the live userMessage channel (#14676, ADR-0049) retiredKey() tombstone on ConnectorSchema.errorMapping (inherited by DeclarativeConnectorEntrySchema); ErrorMappingConfig / ErrorMappingRule / ConnectorErrorCategory leave whole; D2 conversion connector-error-mapping-removed in the step-18 chain; RETIRED_KEYS / RETIRED_DEFS entries under 18; pins; generated artifacts; changeset. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01H2oQebDDxYKfWZusyd8GXk
📓 Docs Drift CheckThis PR changes 1 package(s): 7 hand-written doc(s) NAME something this change touched and may need an implementation-accuracy re-verification:
⛔ 2 release-owned page(s) also name something this change touched. These are read-only:
What this run could not see
Coarse fallback — 128 page(s) merely mention a changed package (the pre-#9192 predicate, kept for the deliberately-wide backstop): Which tree this was computed onThis run read A worktree cut from an older # while this PR is open — GitHub drops the merge commit once it closes
git fetch origin 98c48de347d8f38f47144b581032b67e51e3c06b && git checkout 98c48de347d8f38f47144b581032b67e51e3c06b
# afterwards, rebuild it from the two parents, which stay fetchable
git fetch origin 2ed6be649d3c45af2397fa731265706845107705 bc695037078206a6dbbd3e5b1893878b6630486e && git checkout -B drift-repro 2ed6be649d3c45af2397fa731265706845107705 && git merge --no-ff bc695037078206a6dbbd3e5b1893878b6630486e
node scripts/docs-audit/affected-docs.mjs --json 2ed6be649d3c45af2397fa731265706845107705
|
…tire-connector-error-mapping
|
Provenance (seat landing stroke, 2026-09-04T12:41Z): Clause ② PASS · ACCEPT recorded on #14676 (comment 5539828597) by the Generated by Claude Code |
…erging main (#15299 + this card)
…zation is the one read face for the user's language (objectstack-ai#14788) (objectstack-ai#15386) * wip: retire SessionUser.language; /auth/me/localization user-column-first locale (objectstack-ai#14788) * feat(spec,hono-server): retire SessionUser.language; /auth/me/localization locale = sys_user.locale → Accept-Language → deployment default (objectstack-ai#14788) * fix(spec): tombstone prescription cites the ADR, not an issue id (check:doc-authoring) * chore(spec): regenerate the migration registry and references after merging main (objectstack-ai#15299 + this card) --------- Co-authored-by: Claude <noreply@anthropic.com>
Fixes #14676
Retires
ConnectorSchema.errorMappingunder ADR-0049 enforce-or-remove, executing the triage ruling (comment 5516704842) and the seat claim (5537492862): the eleven authorable keys ofErrorMappingConfig(4) andErrorMappingRule(7) had zero consumers, and one of them was spelleduserMessage— the name of the live API-error channel — so a connector rule validated, published, and showed nobody anything. Removal settles the name collision by deletion; the live channel (ApiErrorSchema/EnhancedApiErrorSchema) is untouched, and #14674 is not addressed here.Triage ruling — operative sentences (quoted from 5516704842)
Split condition — downstream consumer measurement (checked before the first edit)
origin/main0d8fd7c(fetched 2026-09-04, read-only sibling checkout)git grep -n -E 'errorMapping|ErrorMapping' origin/main460134aferrorMappingkey acrosspackages/**,examples/**,skills/**, non-generatedcontent/docs/**,*.form.ts, theqa/dogfoodconformance ledgerconnector.zod.ts, its unit test, and theIso382type-identity pinNo downstream consumer found ⇒ the split condition is not met and the ruling's removal route stands (no
needs_decision).Route — playbook §2, tombstone row
ConnectorSchemais a non-strictz.object, soerrorMappingis aretiredKey()tombstone (ERROR_MAPPING_RETIRED), never a bare deletion (zod would strip it silently — the shape the tombstones exist to prevent).DeclarativeConnectorEntrySchemaisConnectorSchema.superRefine(...), so one tombstone covers both carriers: the refusal reachesstack.connectors[](stack.zod.ts:679) and thePUT /api/v1/meta/connector/:namedoor (kernel/metadata-type-schemas.ts:254). §2's third row ("nobody parses it") therefore does not apply, and a D2 conversion is wired (playbook §3). The three defs leave whole (ErrorMappingConfig,ErrorMappingRule, and — see deviations — the orphanedConnectorErrorCategoryenum) withretired-defsentries under major 18.PM mechanism assumptions — which held
integration/Connector:errorMapping,integration/DeclarativeConnectorEntry:errorMapping); the def schemas and their type aliases deleted, withretired-defs/18.*entries spelled like their neighbours.stack.zod.ts:679parsesconnectors: z.array(DeclarativeConnectorEntrySchema);metadata-type-schemas.ts:254binds it to/meta. The conversion is wired, not omitted.connector-error-mapping-removed(stripKeysinsidemapCollection(stack, 'connectors', …)),toMajor: 18,retiredFromLoadPath: true, fixtureexpectedNotices: 1— one notice perconnectors[]entry carrying the block; the eleven nested keys leave with it. Disjoint from every other conversion (the only otherconnectors[]conversions touchrateLimitConfigandfieldMappings[].transform; the fixture carries neither).MIGRATIONS_BY_MAJOR[18].conversionIdsand its rationale extended;gen:migration-registrythencheck:migration-registrygreen (150 semantic, 88 retired-key, 97 retired-def).origin/main(where Aparallelbranch inside aloopbody overloads the step record'siterationwith the branch index — the enclosing loop iteration is lost, so a branch step cannot be attributed to its row #14414 / PR feat(spec)!: ExecutionStepLog.iteration is single-valued (the enclosing loop iteration); the parallel branch index moves to a new optionalbranchkey (#14414) #15227 regeneratedregistry.ts) merged viascripts/pm/os-regen-merge.sh— merge committed first, regenerated after; both sides verified present and Aparallelbranch inside aloopbody overloads the step record'siterationwith the branch index — the enclosing loop iteration is lost, so a branch step cannot be attributed to its row #14414's implementation body byte-identical toorigin/main.api-surface/integration.jsonloses seven exports, not five (the orphan enum, below). The gates fired in the order the playbook predicts and their output is the route evidence: first the manifest ratchet —❌ 3 previously published schema(s) disappeared from this build(ConnectorErrorCategory / ErrorMappingConfig / ErrorMappingRule) — answered by deleting the threejson-schema.manifest/integration.jsonrows; then gate (a) —❌ 11 authorable key(s) disappeared from the contract— answered by deleting the elevenauthorable-surface/integration.jsonrows; then check (c) accepted both:3 schema(s) left the published set since 4dd5041bd0be, each declared (#4725)and2 baseline deletion(s) since 4dd5041bd0be carry their own proof (#4650). The tombstoned key readsintegration/Connector:errorMapping [RETIRED]andintegration/DeclarativeConnectorEntry:errorMapping [RETIRED];authorable-defaults/integration.jsonlost its twoErrorMappingConfigdefault rows;declaration-map/,export-origins/,content/docs/references/**regenerated bycheck:generated --fix, then a clean second run:✓ All 15 generated artifacts are up to date.authorable-surface.base.jsonwas never hand-edited; the criterion,check:authorable-surface, is green.Iso382(andIso381, the enum) leave, and the file's own self-count moved 828 → 826 with a ledger line in its house form.check:spec-parsed-alias:1516 bare z.input aliases, 826 pinned isomorphic, 690 paired with an XParsed. OK.connectorhas no liveness ledger;check:livenessandcheck:strictness-ledgergreen with no edit.spec-changes.jsonand the upgrade guide project nothing for the unreleased major 18 (the siblings' 18-era entries are absent too —handlerStatus,allowRestore: 0 hits);check:spec-changes/check:upgrade-guidegreen, no diff..changeset/connector-error-mapping-retired.md:@objectstack/specminor, BREAKING banner, FROM → TO block, ADR-0087 marker —check-adr-0087-registration: 1 declared-breaking changeset(s), each carrying an ADR-0087 disposition … registered connector-error-mapping-removed (new here);check-changeset-no-major:✓ This diff introduces no major bump.Deviations from the claim surface
ConnectorErrorCategorySchema/ConnectorErrorCategoryremoved as well (same file; declared in the dev claim comment 5537594722 before the first edit). Its only consumers wereErrorMappingRule.targetCategoryandErrorMappingConfig.defaultCategory; outside the declaring file it was referenced only by a value round-trip inconnector.test.tsand theIso381pin. Playbook §4's orphan-value-schema row (refactor(spec)!: remove the plugin sandboxing / integrity / approval config that never existed (#3896 follow-up) #3950; theapi/HandlerStatusenum went the same way in the most recent retirement).retired-defs/18.integration__ConnectorErrorCategory.ts.api/ErrorCategory(the HTTP-response vocabulary, ADR-0112 D9a) is unaffected.type-alias-convention.pin.test.ts:Iso381leaves withIso382; the self-count statements (header,ittitle,toHaveLength) moved with a ledger line — the file's own convention, asserted by its runtime companion.json-schema.manifest/integration.json(−3) andauthorable-surface/integration.json(−11 rows, +2[RETIRED]rows) carry hand-deletions the gates demanded;authorable-defaults/integration.json(−2) is regenerated. Generated-artifact paths, listed for completeness.connector.test.tsalso carries an idempotence pin at the spec seam (a second replay over the converted snapshot emits zero notices and returns the input by reference), because the CLImigrate-metae2e could not run here (see Measurements).Not touched: #14674's surface (
ApiErrorSchema/EnhancedApiErrorSchema),plugin-auth'swithValidationErrorMapping, any SKILL.md,content/docs/releases/,docs/adr/**(ADR-0122 appendix D lists the retired aliases as a measured-corpus record of its time; governed, left as history).Reverse verification
connector.test.ts,[#14676]): an authorederrorMappingis refused onConnectorSchema,DeclarativeConnectorEntrySchema, the registry-resolvedconnectorschema andObjectStackSchema.connectors[]— issuecode: 'invalid_type',path: ['errorMapping']/['connectors', 0, 'errorMapping'], and the message is the prescription (matched on the key, "was removed", "nothing ever read it", "Delete the key",ApiError.userMessage, "no error-mapping engine exists", the houseos migrate meta --from 17sentence as the last sentence,ADR-0049, and no issue-id token). Positive control: the same stack minus the key parses.Connectorliteral carrying the key needs@ts-expect-error(input typenever);check:test-typecheckcompiles the test layer, so an unused directive would red it —check:test-typecheck: OK — 54 file(s) / 261 error(s) / 145 pinned signature(s).conversionId: 'connector-error-mapping-removed',toMajor: 18,path: 'connectors[0].errorMapping'); the output parses through the authoring schema; a second replay yields zero notices and the same reference. The chain-replay fixture test passes for the new id (conversions.test.ts) — i.e. the conversion is wired (playbook §3 reading).connector.zod.tswith a bare deletion — the silent-strip regression the pins guard. Mutation proved on disk before measuring (tombstone lines before=1 after=0 marker=1). No rebuild was needed and none was done:connector.test.tsresolves./connector.zodand../stack.zodfrom source under vitest (no dist, no alias), so the mutation is measured where it lands. Direction observed: 4 red / 59 green — the three refusal pins and the tsc-agreement pin went red; the no-materialize pin stayed green (absence stays absence either way, as predicted). Restore:git checkout HEAD -- ABSOLUTE_PATHinside anEXIT INT TERMtrap; proof:git hash-objecton disk988ef8cbeb0e3072a7f9d413a65283708e203da0==HEADblob988ef8cbeb0e3072a7f9d413a65283708e203da0,git diff HEADempty for the path, marker count 0, tombstone count 1.Measurements — head
ea77fa6ef(every exit captured before any pipe; verdict lines are the gates' own)pnpm --filter @objectstack/spec build(underos-verify-lock.sh)os-verify-lock: VERDICT command-exit 0 · held the lock 146ssrc/integration/connector.test.ts src/conversions src/migrations src/shared/retired-key-migrate-sentence.test.ts src/type-alias-convention.pin.test.ts(--maxWorkers=2, locked)Test Files 9 passed (9)/Tests 438 passed (438)pnpm --filter @objectstack/spec typecheck(locked)check:test-typecheck: OK …/os-verify-lock: VERDICT command-exit 0check:generated(clean run after--fix)✓ All 15 generated artifacts are up to date.check:authorable-surface,check:api-surface,check:docs,check:export-origins,check:declaration-map,check:spec-changes,check:upgrade-guide,check:migration-registry,check:liveness,check:strictness-ledger,check:exported-any,check:dual-source-exports,check:entry-nameability,check:browser-reachable-entries✓line (all rows in the os-dev-report on #14676)check:spec-parsed-aliasADR-0122 type-alias convention: 1516 bare z.input aliases, 826 pinned isomorphic, 690 paired with an XParsed. OKnode scripts/check-adr-0087-registration.mjs --base origin/main✓ check-adr-0087-registration: 1 declared-breaking changeset(s), each carrying an ADR-0087 disposition.node scripts/check-changeset-no-major.mjs --base origin/main✓ This diff introduces no major bump.pnpm check:doc-authoring✓ doc authoring guard: 14736 customer-facing string(s) across 734 spec sources cleanpnpm check:nul-bytescheck-nul-bytes: OK (scanned 8286 text file(s) …)node scripts/check-system-context-census.mjscheck-system-context-census: OK — 106 elevation read sites in 20 packages across 45 files, all anchoredpnpm lint(whole repo,eslint . --no-inline-config, 89s)node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack --commands(no path args; 20 paths vs merge base4dd5041bd) — 90 commands@objectstack/lint check:doc-formula-expressions(PREREQUISITE NOT MET — the workspace package @objectstack/formula is not built),check:doc-security-posture(… @objectstack/lint is not built),spec check:skill-examples(packages/client-react/dist holds no .d.ts declarations — the package is not built),pnpm check:dual-build-cjs-loads(Run pnpm build first. ⛔ This is NOT a pass: nothing was measured.),pnpm check:type-check-debt(exit 3 — its own could-not-measure code). All need the whole-repo build, which exceeds this container's foreground cap; CI'sLint & Repo Gates/TypeScript Type Checkown them.packages/cli/test/migrate-meta.e2e.test.tsbin/run-dev.js, whose ~50 workspace dependencies have nodistin this worktree; building that closure exceeds the foreground cap. Idempotence is pinned at the spec seam instead (deviation 4), andstripKeysis idempotent by construction (playbook §3). CI'sTest Coreruns the e2e.pnpm --filter '...@objectstack/spec' typecheck(the tombstone's tsc sweep of every authoring site) is not runnable within the cap; replaced by the grep census above (zero hits for the seven identifiers and the key acrosspackages/**,examples/**,skills/**, docs). CI'sTypeScript Type Checkis the sweep.Changeset
.changeset/connector-error-mapping-retired.md—@objectstack/spec: minor(launch-window convention for a post-17.0.0 accept-set narrowing; the no-major gate is green), BREAKING banner naming the retired key, the seven exports that leave, what stays byte-identical, FROM → TO, and the retirement kit. ADR-0087 marker: registeredconnector-error-mapping-removed.Review
Clause ②:
needs:contract-reviewon this PR and on #14676 — the published accept set narrows (errorMappinggoes from accepted to refused/stripped). Draft on purpose; the seat flips ready after its review.🤖 Generated with Claude Code
https://claude.ai/code/session_01H2oQebDDxYKfWZusyd8GXk
Generated by Claude Code