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
Commit c1602ba
Browse filesBrowse the repository at this point in the historyBrowse files
docs: shared picklist — NORTH-STAR feature line, two planned records-forms items, coverage waiver; upgrade skill stops claiming a connector sync ran (#20938)
Part of #19518
The Tier H docs follow-up for the shared picklist: the section "Also
with this card" on the card, plus one skills correction carried from
#20281 under ruling 5916259513. The card stays open until this lands;
the seat closes it by hand. Five files, no package source, nothing
published from any package.
## What changes
1. **`docs/NORTH-STAR.md`**: one new line in step ② 「本地跑起来、看到」, records
axis, with the card's text verbatim: `records ·
共享选项集:多个对象复用同一份选项,客户按组织追加值而不改应用源码 · records-forms ·
picklist-shared-across-objects, picklist-org-append`. It sits after the
last existing records row (search), so it ranks below every records
capability that already exists. Moving it up is a priority call for the
maintainer.
2. **`docs/qa/platform-checklist/areas/records-forms.json`**: two new
items, both `status: "planned"`, `since: null`, `P2`, with no steps
(README, "Implementation status"):
- `records-forms.picklist-shared-across-objects` covers phase 1. One
picklist on two objects: both are served the same resolved options, a
package `picklistExtensions` value reaches both, the write door refuses
a value outside the set, and a locale switch relabels the options. It
carries three drafted acceptance clauses taken from the design of record
and from the acceptance sentence of #19519, so the runtime PR has a
concrete target when it promotes the item.
- `records-forms.picklist-org-append` covers phase 2. Organization A
appends a value without editing the app source, A can write it, and
organization B is refused. It carries no acceptance clauses, because the
overlay's schema and write door are not designed. A `knownGaps` entry
records that the overlay is not declared: the picklist registry row has
`allowOrgOverride: false`, and ruling 5904864936 defers the overlay to
its own sub-issue.
3. **`docs/qa/platform-checklist/coverage.json`**: `picklist` gets a
waiver. It was UNCLASSIFIED. The waiver states the measured reason:
`packages/spec/liveness/picklist.json` grades every key `planned`, and
`check-stack-collection-maps` holds `picklists` and `picklistExtensions`
as PENDING rows for #19519. It names both planned ids and states what
retires the waiver.
4. **`skills/objectstack-upgrade/references/examples-upgrade.md`**: the
worked R1 walks a protocol-16 `connectors[].fieldMappings[].transform`
source. Since #20903 (0efbdc3), the chain removes the whole of
`fieldMappings` after `transform` (`connector-sync-keys-removed`,
toMajor 18, part of the default `os migrate meta --from 16` terminus),
and the author meets that key's tombstone. Three sentences said
otherwise, and each now says what is true:
- "the parse error is the prescription" pointed at a `transform`
tombstone. It now names the `fieldMappings` tombstone.
- "the connector has been landing raw values for as long as it has been
running" is now "no connector sync ever ran, so no value ever passed
through this mapping".
- The report template's "connector sync run against staging, 200 rows"
is now "nothing ever read the key, so no data changes".
- The report template's chain line now reads 16 → 18, the chain the
default run replays.
5. **`scripts/check-platform-checklist.mjs`**: four sentences (three
comments and the self-test success line) said the live ledger carries
zero planned items. They now say that no `coverage.json` entry maps a
planned item.
## How behaviour that does not exist yet is represented
The checklist's own rules settle the status. `planned` is for a
capability the definition requires and the platform does not implement
or verify yet. A planned item never runs and is never coverage. Both
items are planned: no runtime reads a picklist yet.
The coverage rule also settles the waiver. A kind whose only items are
planned is UNMAPPED, and the gate's instruction is "Add an item that
RUNS, or waive the kind with a reason". An entry cannot hold both, so
the planned ids are named in the waiver's prose. One consequence:
`checklist-select capability:picklist` matches nothing until the waiver
flips to `items`.
Two content choices are the rules' to leave open. The dev report asks
about both:
- **Locale relabel:** it is on the phase-1 item. The card's grouping put
it with the organization item, but promotion is per item and needs a
passing run, and the acceptance sentence of #19519 groups the relabel
with phase 1.
- **Organization append:** it is a planned requirement, as the card's
NORTH-STAR text says. Ruling 5904864936 defers the overlay until a
customer requirement measures it, so the maintainer may prefer to trim
the line's second half and drop the item.
## Skill readings (`skills/**`)
| reading | before (aaad682) | after (cab0e1b) |
| --- | --- | --- |
| `examples-upgrade.md` lines | 119 | 119 |
| `examples-upgrade.md` bytes / tokens (ceil(bytes/4), ceiling 1197) |
4788 / 1197 | 4751 / 1188 |
| package: all 10 `SKILL.md`, lines | 4394 | 4394 |
| token ratchet, authored total | 143461 | 143452 |
The additions are paid for by deleted content. Nothing was re-wrapped to
buy lines. The ceiling stays 1197, with headroom 9. Lowering it is a
separate edit to the ratchet script.
## Local verification, at cab0e1b
- `node scripts/pm/dispatch-gates.mjs --commands --repo
objectstack-ai/objectstack` derives 43 families from the five paths. All
43 ran; `--ran` answers "43 derived famil(ies) accounted for — 43 run, 0
NOT-MEASURED", exit 0.
- 42 families exit 0. `check:platform-checklist` exits 1 on the
pre-existing anchor below.
- `check:pm-dispatch-gates` exits 0 (1976 self-test cases).
- `check:doc-formula-expressions` first exited 3 (PREREQUISITE NOT MET:
no lint or formula dist). After a locked build of those two packages it
exits 0.
- `pnpm check:platform-checklist` exits 1, the same as on `origin/main`:
- before, 2 problems: `coverage.json · picklist: UNCLASSIFIED` and
`areas/identity-auth.json: ABSENT SYMBOL … auth-plugin.ts#twoFactor`;
- after, 1 problem: the same `twoFactor` anchor, which this diff does
not touch;
- the 5 anchors this diff adds resolve.
- `pnpm gen:checklist-status` lists records-forms as 40 active and 2
planned (264 active and 2 planned overall).
- `node scripts/check-skills-token-ratchet.mjs` exits 0:
"examples-upgrade.md is 1188 tokens (ceiling 1197; headroom 9)".
- `node scripts/pm/check-governed-merges.mjs --branch HEAD` exits 3,
GOVERNED, landing tier H. Two of five paths hit the register
(`skills/**`, `docs/NORTH-STAR.md`). The diff is +119 / -17.
- No changeset: the diff releases nothing, because `skills/` ships
through `npx skills add` and appears in no package's `files[]`.
`skip-changeset` is applied.
## Acceptance notes
- `scripts/check-platform-checklist.mjs` said in four places that the
live ledger carries zero planned items. This PR corrects them
(`cab0e1b557`); the tests are unaffected (221 assertions pass). Carrier:
this PR.
- `skills/objectstack-upgrade/evals/protocol-major-upgrade.json`, eval
3, was read and left unchanged. Its prompt, that the chain dropped
`fieldMappings[].transform`, is still true. Its expected answer, "delete
because the member never executed", is also still true, and it claims no
sync run.
- The card cites "ADR-0136 D2.4". No ADR-0136 exists in this
repository's registry (zero hits), so neither item cites it; the
design-of-record comment is cited instead.
- The `Path:` lines on #19518 and #19519 still read 清单项待写. They can name
the two ids once this lands.
## 维护者速读(草稿)
终稿以席位在本 PR 上的「维护者速读(终稿)」评论为准;下面与终稿一致。
**改了什么**:
- 北极星「路上的功能点」第②步 records 组末尾,加一行「共享选项集」,文字照卡片原文。
- 平台测试清单加两个 `planned` 项(已计划,还不能跑):
- 第一期:一份选项集两个对象共用、包扩展加值、越界值被拒、切语言换标签;
- 第二期:组织自己追加值、本组织能写、别的组织被拒。
- `coverage.json` 给 picklist 记一条带理由的豁免。
- upgrade 技能示例改正三句话,报告模板里的迁移链改成 16 → 18。第一句原本把处方指向一个已不存在的 `transform`
墓碑;第二、三句说连接器同步跑过、落过数据,实际从来没有引擎跑过。
- 清单门禁脚本里有四处说「清单里没有 planned 项」(注释和自测提示语),改成与现状相符。
**为什么改**:
- 卡片要求这一行和两个清单项随一个小文档 PR 落地。
- 规格层已合入,运行时(#19519)还没做,两个项都没东西可跑。清单规则规定这种情况标 `planned`、覆盖表用豁免,不能拿
`planned` 冒充覆盖。
- 技能文字错一句就是产品缺陷(北极星优先级第 4 条)。
**风险与代价(含回滚)**:
- 只改了文档、一份对外技能参考文件,以及一个门禁脚本的注释和自测提示语;不动任何包,不发版。技能文件仍是 119 行,token 从 1197
降到 1188。
- 回滚就是 revert 三个提交。回滚后,清单门禁会重新报 picklist UNCLASSIFIED。
- 两个版本都过了档位审查(`8e7420019e` 和 `cab0e1b557`),CI 全绿。
**席位意见**:
- 建议合并。
- 下面三处您合并时可以顺手改:
① 「客户按组织追加值」(第二期)现在就写进路线图和清单,作为 planned 需求。席位意见是保留:文字是卡片原文,planned
不算覆盖,也不宣称已经做到。但裁决 5904864936
说的是等有实测的客户需求再立子卡。您若不想现在就把它放上路,删掉那一行的后半句和第二个清单项即可。
② 「切语言换标签」放在第一期的项里(卡片原来归在第二期)。它在第一期就会交付,放在第二期要等很久才能验证。席位同意这样放。
③ 新行放在 records 组最后,排序最低。这张表的顺序就是优先级,您想提前就挪一下位置。
**你要做的**:
- 合并本 PR。这是 Tier H,需要您亲手合并;或者给出授权的 APPROVED,由席位落地。
---
_Generated by [Claude
Code](https://claude.ai/code/session_01Sfe5YjBLwB9J3y8fvm2xq1)_
---------
Co-authored-by: Claude <noreply@anthropic.com>
"title": "One shared picklist on two objects: both are served the same resolved options, a package extension adds to both, a value outside the set is refused, and a locale switch relabels",
4190
+
"since": null,
4191
+
"status": "planned",
4192
+
"revision": 1,
4193
+
"priority": "P2",
4194
+
"surface": "mixed",
4195
+
"personas": [
4196
+
"seeded admin (admin@objectos.ai / admin123)"
4197
+
],
4198
+
"fixtures": {
4199
+
"app": "showcase",
4200
+
"requires": [
4201
+
"a picklist declared once (`*.picklist.ts`) and referenced by `Field.select({ picklist })` on two showcase objects, a `picklistExtensions` entry that adds one value to it, and `picklists.NAME` labels for a second locale. Stock showcase has none of these, and nothing serves a picklist until the runtime layer (#19519) lands, so the fixture arrives with it"
4202
+
]
4203
+
},
4204
+
"acceptance": [
4205
+
{
4206
+
"clause": "both objects' fields are served with the SAME resolved `options` (the picklist's own values plus the extension's) beside the `picklist` name, and each object's form offers exactly that set",
4207
+
"oracle": "api",
4208
+
"verify": "read both objects' field metadata: each field parses as packages/spec/src/data/picklist.zod.ts#PicklistServedFieldSchema and the two option lists are equal; then enumerate the options each object's form offers",
4209
+
"evidence": "both served field bodies + both form option enumerations"
4210
+
},
4211
+
{
4212
+
"clause": "the write door judges both objects against the resolved set: the extension's value persists on object A, and a value outside the set is refused on object B, the refusal naming the picklist",
4213
+
"oracle": "api",
4214
+
"verify": "POST the extension's value to object A and re-read the row; POST an out-of-set value to object B and capture the refusal envelope",
4215
+
"evidence": "the re-read + the refusal envelope"
4216
+
},
4217
+
{
4218
+
"clause": "switching the locale relabels the options on both objects from the picklist's `picklists.NAME.options.VALUE` translations, and the stored values do not change",
4219
+
"oracle": "api",
4220
+
"verify": "read both objects' field metadata under each locale; a picklist-bound field takes its option labels through packages/spec/src/system/i18n-resolver.ts#translateObject, and the values are identical across locales",
4221
+
"evidence": "both served bodies under each locale"
4222
+
}
4223
+
],
4224
+
"negative": [
4225
+
"a picklist-bound field served WITHOUT `options` is a FAIL: renderers, the record validator and filter pickers read `options`, so they would have nothing to offer or judge",
4226
+
"a value outside the set accepted with 200 on either object is a FAIL: hiding it in the form is a client courtesy, and the write door is the boundary",
4227
+
"a field naming a picklist that does not exist, served as an empty option list, is a FAIL: it must be refused loudly at load, naming the field and the package",
4228
+
"an extension that duplicates, replaces or removes a base value is a FAIL: extensions are additive only, and a duplicate is refused loudly rather than last-wins"
4229
+
],
4230
+
"source": [
4231
+
"#18164 design of record (comment 5715762696), items 1 to 6: the kind, the field reference, server resolution, the additive package extension, the translation face, and the verification sentence that this item and records-forms.picklist-org-append split between them",
4232
+
"#19518, the spec layer (landed as addbbf02ab): packages/spec/src/data/picklist.zod.ts#PicklistSchema",
4233
+
"#19518, the extension shape: packages/spec/src/data/picklist.zod.ts#PicklistExtensionSchema",
4234
+
"#19519, the runtime layer this item waits on (load before `object`, additive merge, resolve at serve time, write validation against the resolved set); its acceptance sentence is this item's three clauses"
4235
+
],
4236
+
"history": [
4237
+
{
4238
+
"revision": 1,
4239
+
"date": "2026-09-30",
4240
+
"change": "initial — planned. The spec layer landed (#19518), but no runtime reads a picklist yet (packages/spec/liveness/picklist.json grades every key `planned`), so there is nothing to drive. The acceptance clauses are drafted from the design of record and #19519's acceptance; steps arrive with #19519, in the edit that promotes this item after a run in which it passes. The locale relabel sits on this item rather than on the organization item because it is phase-1 behaviour, and a promotion needs the whole item to pass",
4241
+
"ref": "#19518"
4242
+
}
4243
+
]
4244
+
},
4245
+
{
4246
+
"id": "records-forms.picklist-org-append",
4247
+
"title": "An organization appends a value to a shared picklist without changing the app source: that organization can write it, and another organization is refused",
4248
+
"since": null,
4249
+
"status": "planned",
4250
+
"revision": 1,
4251
+
"priority": "P2",
4252
+
"surface": "mixed",
4253
+
"personas": [
4254
+
"an admin of organization A (appends the value, then writes it)",
4255
+
"a member of organization B (the same app and picklist, without A's value)"
4256
+
],
4257
+
"fixtures": {
4258
+
"app": "showcase",
4259
+
"requires": [
4260
+
"two organizations on one environment, each with its own signed-in persona, sharing one app whose object has a picklist-bound field"
4261
+
],
4262
+
"knownGaps": [
4263
+
"NOT DECLARED: the per-organization overlay is phase 2 of the picklist design. The picklist row of packages/spec/src/kernel/metadata-plugin.zod.ts#DEFAULT_METADATA_TYPE_REGISTRY carries `allowOrgOverride: false`, the one opt-in ADR-0005 allows for an organization overlay, and ruling 5904864936 on #18164 defers the overlay to its own sub-issue, filed when a customer requirement measures it. Nothing here can run until that sub-issue lands the overlay. Package-level extension (phase 1) is records-forms.picklist-shared-across-objects"
4264
+
]
4265
+
},
4266
+
"negative": [
4267
+
"organization B writing the value that only organization A appended, accepted with 200, is a FAIL: the appended value belongs to A's overlay alone",
4268
+
"an organization overlay that removes or renames a value the owning package declared is a FAIL: the overlay adds values only, and removal or rename stays with the owning package",
4269
+
"an append that needed an edit to the app source or to the owning package does not demonstrate this item: the capability is appending without touching either"
4270
+
],
4271
+
"source": [
4272
+
"#18164 design of record (comment 5715762696), item 4 (a per-organization overlay of the picklist shape, additive only, whose allowance was left to the maintainer as an open point) and item 6 (the verification sentence: org A adds a value, A writes it, B is refused)",
4273
+
"#18164 ruling 5904864936 (the overlay stays deferred to its own sub-issue on a measured customer requirement) and #19518 Scope 5 (not declared in the spec layer)",
4274
+
"docs/adr/0005-metadata-customization-overlay.md (`allowOrgOverride` on the type registry is the only org-overlay opt-in)"
4275
+
],
4276
+
"history": [
4277
+
{
4278
+
"revision": 1,
4279
+
"date": "2026-09-30",
4280
+
"change": "initial — planned. The docs/NORTH-STAR.md feature-map line names per-organization append as half of the shared-picklist feature, and the design of record's verification sentence names this behaviour, so the ledger holds it as a planned requirement rather than leaving it off. It carries no acceptance clauses: neither the overlay's schema nor its write door is designed yet, and a clause would be written against a design nobody has settled",
Copy file name to clipboardExpand all lines: docs/qa/platform-checklist/coverage.json
+3Lines changed: 3 additions & 0 deletions
Original file line number
Diff line number
Diff line change
@@ -225,6 +225,9 @@
225
225
"api-backend.api-methods-verb-gate"
226
226
]
227
227
},
228
+
"picklist": {
229
+
"waived": "WAIVED 2026-09-30 — there is no runtime behaviour to drive yet, measured rather than asserted. The spec layer landed (#19518, addbbf02ab): PicklistSchema, `Field.select({ picklist })`, PicklistServedFieldSchema, `picklistExtensions` and the `picklists.NAME` translation face. No runtime reads a picklist: packages/spec/liveness/picklist.json grades every key `planned`, and scripts/check-stack-collection-maps.mjs carries `picklists` and `picklistExtensions` as rows PENDING the runtime layer (#19519) in the METADATA_ARRAY_KEYS and ARTIFACT_FIELD_TO_TYPE registration maps. No code resolves a picklist onto a field or judges a write against one, so an item written to RUN today could only assert absence. The two items that will carry this kind are authored as `planned`: records-forms.picklist-shared-across-objects (phase 1: two objects, the package extension, the write door, the locale relabel) and records-forms.picklist-org-append (phase 2: the per-organization overlay, deferred by ruling 5904864936 on #18164). They are not listed under `items`, because a kind whose only items are planned is UNMAPPED and an entry cannot hold a waiver and items together. WHAT RETIRES THIS WAIVER — #19519 lands resolve-at-serve, the additive merge and write validation; records-forms.picklist-shared-across-objects gains its steps, runs, passes and is promoted to `active`, and the same edit replaces this waiver with `items` naming it, the planned organization item beside it. ⚠️ Re-audit it every sweep, as SWEEP.md asks of every waiver."
// New with the `planned` status. Set at its landed count (headroom 0, the
1058
1058
// convention every entry above uses). The load-bearing third of it is the
1059
-
// coverage direction: the live ledger carries ZERO planned items today, so
1059
+
// coverage direction: no coverage.json entry maps a planned item today, so
1060
1060
// nothing but these fixtures can tell a working ratchet rule from a deleted
1061
1061
// one — the unreferenced-recipe argument, applied to a rule whose subject
1062
1062
// population is empty on purpose rather than by luck.
@@ -2277,10 +2277,10 @@ function selfTestSymbolAnchors() {
2277
2277
* ratchet. If a planned item ever counted as coverage, "凡是有的能力, 都要测试"
2278
2278
* would become "凡是有的能力, 都要打算测试", and the ratchet would go green on
2279
2279
* a kind nothing runs against. So the ratchet direction is pinned BOTH ways,
2280
-
* on fixtures, not on the tree: the live ledger carries zero planned items and
2281
-
* is expected to for a while, which means the real data cannot tell "this rule
2282
-
* works" from "this rule was deleted" — the same silent-success argument the
2283
-
* unreferenced-recipe battery above makes.
2280
+
* on fixtures, not on the tree: no coverage.json entry maps a planned item,
2281
+
* which means the real data cannot tell "this rule works" from "this rule was
2282
+
* deleted" — the same silent-success argument the unreferenced-recipe battery
2283
+
* above makes.
2284
2284
*/
2285
2285
functionselfTestPlannedStatus(){
2286
2286
constfailures=[];
@@ -2538,7 +2538,7 @@ if (process.argv.slice(2).includes('--self-test')) {
2538
2538
' and the `/meta` call-spelling refusal reads its vocabulary out of the live generated contract, fires on every folded spelling a `call` can instruct, and stays silent on the canonical singular, on parameter placeholders, and on the `why`/`expect`/`source`/`requires` prose that narrates the fold;'+
2539
2539
' and the line-citation limb DETECTS NOTHING ITSELF EITHER: the last forked grammar in this file went into the shared core at #18592, so what is pinned here is the BINDING — the corpus declaring `pathlessLineCitations`, a source read finding no citation regex and no detector while the same read DOES find the declaration, the binding driven ON and OFF against ONE text so the green is the declaration working rather than a text that would have matched anyway, the DARK case that a citation both grammars already agreed on keeps its verdict either way, the refusal to over-fire on this ledger\'s own HTTP statuses, config literals, URL ports, clock times and quoted JSON, and the live zero with the control that says it is a reading;'+
2540
2540
' and the symbol-anchor limb DETECTS NOTHING AND RESOLVES NOTHING ITSELF: it is a registered corpus (#18107), so the grammar, the walk and the verdict are all `scripts/symbol-anchors.mjs`\'s, pinned here by a source read that finds no local extension set, no anchor regex and no detector while the same read DOES find the registration, by the anchorable-extension vocabulary being the shared OBJECT rather than a copy of it, by the `runs/` exclusion driven three ways on the live corpus (the subtree holds files, none is swept, the areas beside it still are, and dropping the exclusion puts them back), and by the #16898 binding re-taken through the registration — a call site / import / local parameter / string-substring all reading ABSENT, the positive control that a declaration and a complete quoted token still resolve, a `.json` key resolving where a `.json` value does not, an INLINE object-literal key reading absent where one at the start of a line resolves — with the closed, grow-never residual and the per-file anchor floor held in both directions beside it;'+
2541
-
` and the \`planned\` status is driven on fixtures rather than on a ledger that carries none of it — the accept set widened without losing its closure, \`since: null\`/no-steps/personas relaxed for planned alone while the ${plannedStatus.liveItems} live items are judged exactly as before, and the coverage ratchet held BOTH ways: a planned item beside an active one is silent, a kind whose only items are planned is UNMAPPED, and the bearing set is pinned NOT to contain \`planned\`; and the two CALL SITES those rules ride on are pinned by a source read over comment-MASKED source driven ON and OFF, because severing either one — by deletion OR by commenting it out in place — left this very self-test green; \u26d4 that pin is a TEXT pin and G12 records the three semantic severings it cannot see.`,
2541
+
` and the \`planned\` status is driven on fixtures — the accept set widened without losing its closure, \`since: null\`/no-steps/personas relaxed for planned alone while the ${plannedStatus.liveItems} live items are judged exactly as before, and the coverage ratchet held BOTH ways: a planned item beside an active one is silent, a kind whose only items are planned is UNMAPPED, and the bearing set is pinned NOT to contain \`planned\`; and the two CALL SITES those rules ride on are pinned by a source read over comment-MASKED source driven ON and OFF, because severing either one — by deletion OR by commenting it out in place — left this very self-test green; \u26d4 that pin is a TEXT pin and G12 records the three semantic severings it cannot see.`,
2542
2542
);
2543
2543
process.exit(0);
2544
2544
}
@@ -2619,7 +2619,7 @@ if (symbolAnchorControl.failures.length) {
2619
2619
}
2620
2620
// And for the `planned` status. Its schema half is exercised by the tree the
2621
2621
// moment anyone authors a planned item; its COVERAGE half is not, and will not
2622
-
// be for as long as the ledger's planned count is the 0 this gate prints. A
2622
+
// be while no coverage.json entry maps a planned item. A
2623
2623
// deleted ratchet rule and an honest ledger print the same green, so the
2624
2624
// fixtures below it are the only thing that can tell them apart.
Copy file name to clipboardExpand all lines: skills/objectstack-upgrade/references/examples-upgrade.md
+10-10Lines changed: 10 additions & 10 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -16,10 +16,10 @@ The shape in a protocol-16 project:
16
16
}
17
17
```
18
18
19
-
The chain deletes the key (`field-mapping-transform-removed`) and the schema
20
-
tombstones it, so the parse error *is* the prescription: the union had five
21
-
members and **no runtime ever executed any of them**. The customer wrote it
22
-
because they wanted a transformation, and that need is real regardless.
19
+
The chain deletes the key (`field-mapping-transform-removed`), then all of
20
+
`fieldMappings` (`connector-sync-keys-removed`), whose tombstone *is* the
21
+
prescription: **nothing ever ran any connector field mapping**. The customer
22
+
wrote it because they wanted a transformation, and that need is real regardless.
23
23
24
24
The prescription names one live target; the rest is the business decision:
25
25
@@ -29,10 +29,10 @@ The prescription names one live target; the rest is the business decision:
29
29
| multi-source, multi-stage transformation |**nothing** — the L2 ETL layer retired at 17, unexecuted. Do it where it runs: warehouse ELT, a `flow`, a job. |
30
30
| nothing — the value was already correct | delete the key and record that the transformation never ran. |
31
31
32
-
That third row is frequently the truth: the member never executed, so the
33
-
connector has been landing raw values for as long as it has been running.
34
-
Whether the downstream data is wrong is a question only the owner can answer —
35
-
exactly the kind of finding the report exists to surface.
32
+
That third row is frequently the truth: no connector sync ever ran, so no value
33
+
ever passed through this mapping. Where the data really comes from, and whether
34
+
it is right, only the owner can answer — exactly the kind of finding the report
35
+
exists to surface.
36
36
37
37
### 3.4 The report — the human half
38
38
@@ -44,7 +44,7 @@ maintainer can read in five minutes and a year from now. Write
44
44
# Protocol 16 → 17 upgrade — <project>
45
45
46
46
**Status:** complete | complete with N open decisions
0 commit comments