Skip to content

feat(objectql,metadata-protocol): validate and insertMany answer which row lost which field - #21041

Merged
objectstack-fleet[bot] merged 4 commits into
mainfrom
claude/issue-20922-per-row-dropped-fields
Oct 1, 2026
Merged

objectstack-fleet[bot] merged 4 commits into
mainfrom
claude/issue-20922-per-row-dropped-fields

Conversation

@objectstack-fleet

@objectstack-fleet objectstack-fleet Bot commented Oct 1, 2026 •

Copy link
Copy Markdown
Contributor

Fixes #20922
Clause-②: yes (widening)

What changes

The dry run and the partial-success batch insert now say which row lost which field.

  • Dry run. ObjectQL.validate answers droppedFields on each accepted row of results: the fields the write would strip from that row, one DroppedFieldsEvent per reason. validateData relays the verdict, so its answer now fills ValidateDataResponseSchema.results[].droppedFields.
  • Commit. ObjectQL.insertMany answers droppedFields on each ok outcome: the fields stripped from that row. insertManyData passes the outcomes through, and its declared return type now names the key.
  • The key is absent when nothing was taken from the row. A preview row the verdict refuses, and an ok: false outcome, carry none: a drop means the write completed without the field (the DroppedFieldsEventSchema contract), and the write does not complete that row.

How

  • Row attribution is recorded at the strips. stripComputedWriteFields now also returns droppedPerRow (the keys taken from each row, index-aligned). The caller-write strips (stripRuntimeOwnedFields, the static readonly strip, and stripReadonlyFields on an update-mode preview) record each taken key into the existing union and into the taking row's own list, in the same step. Nothing is reconstructed from the union afterwards. That matters because a beforeInsert hook can exempt a key on one row and not another (hookWrittenKeys), so "which rows supplied N" is not "which rows dropped N".
  • One builder for both channels. droppedFieldEvents(object, computed, readonly) turns a strip result into events: one per reason, computed before readonly, the order the strips run. It builds the batch-level union events (validate's listener, insert's insertDrops) and the per-row lists, so the two cannot disagree on a reason or its order. There is no second strip and no second reason vocabulary.
  • The batch-level union is unchanged. The onFieldsDropped events of insert, insertMany and validate are still one per reason, naming no row, built from the same union arrays in the same order. insertManyData's top-level droppedFields and both union docblocks (engine.ts insertMany, protocol.ts insertManyData) are byte-identical. The per-row channel is documented on InsertManyRowOutcome and at the code points instead.
  • Untouched: insert(object, rows[]) still returns the records with no per-row slot. strictReadonlyWrites still refuses the whole batch before any outcome is built. The engine's aggregate door and the packaged-base door in protocol.ts are not touched.

Spec docblocks (two TSDoc sentences, no schema change)

  • packages/spec/src/api/protocol.zod.ts, the ValidateDataResponseSchema docblock: "the engine's validate already runs the write's strips ... no server sets the key until it does" now says what the producer does. validate runs the computed-field strip and the static readonly / runtime-owned strips, records what each takes per row, and reports it on an accepted row. validateData relays it. An update-mode preview does not run the readonlyWhen or primary-key strips, so it can report fewer drops than the update it predicts.
  • packages/spec/src/api/export.zod.ts, the ImportRowResultSchema docblock: "pinned at the wire" now names what is pinned. The synchronous route is pinned by import-dryrun-parity.test.ts, and no test reads warnings off the async job's results.
  • Both are TSDoc comments, not .describe(). check:generated reports all 15 artifacts up to date after a spec build. The diff touches packages/spec/src/**, so the landing owes an at-tier contract review.

Premise checks (measured at 9b0de7de7 before the first edit)

  • H1 holds. engine.validate built computedStrip.dropped and readonlyDropped across all rows and emitted one event per reason. It already built per-row results, and the per-row channel now rides them.
  • H2 holds. insertManyData calls engine.insertMany, which is insert(…, { __partialRowErrors: true }). The outcomes are assembled in insert's partial-mode branch, and that is where the per-outcome report is attached, from the strips' own record. insertManyData adds nothing.
  • H3, insert mode: no fork. An insert-mode preview runs the same three strips the write runs (computed, runtime-owned, static readonly with its re-default), in the same order and under the same isSystem gate. A row's preview drops therefore equal its outcome drops (pinned row for row). The one known difference is the documented "no hooks run" gap: a key a beforeInsert hook assigns is reported by the preview and kept by the write.
  • H3, update mode: a fork, not settled here. An update-mode preview runs no readonlyWhen or primary-key strip, while the update it predicts does. The import route previews an upsert's matched rows in update mode and commits them through updateData. On a row whose readonlyWhen is true (for example the showcase invoice's tax_rate once status == 'paid'), the dry run names nothing for that field and the update drops it under readonly_when. This PR keeps the existing named limit, and the spec docblock now states it. The options and their costs are in the report on the card.
  • H4. Both sentences are TSDoc, so no generated artifact moved.

Tests

The tests ran at 24ca898f8 / 99a7547af. HEAD 886ad2c43 adds only a merge of origin/main, whose three commits touch none of objectql, metadata-protocol, spec or rest. The gate union ran at 886ad2c43.

  • New packages/objectql/src/engine-per-row-dropped-fields.test.ts (14 cases, recording driver). It pins a formula column (computed) and a readonly column (readonly) through the dry run, the commit, and both relayed through the real protocol (validateData, insertManyData). A clean row carries none (the control), and the batch-level union is unchanged. A refused row and a failed outcome carry none. A hook-exempted row is not named. Under isSystem, only the computed strip reports. update-mode previews report per row too.
  • engine-autonumber-runtime-owned.test.ts: the case that pinned "names no row" against the real engine now pins the row that lost account_number on its own outcome, beside the unchanged union.
  • protocol.dropped-fields.bulk.test.ts: a new case checks that an engine-attributed outcome passes through as answered. The existing cases still pin that the seam derives nothing from the union.
  • pnpm --filter @objectstack/objectql exec vitest run --project local --maxWorkers=2: 349 files, 6835 tests passed.
  • pnpm --filter @objectstack/metadata-protocol exec vitest run --maxWorkers=2: 195 passed / 3 skipped files, 2897 passed / 19 skipped tests.
  • pnpm --filter @objectstack/objectql --filter @objectstack/metadata-protocol run typecheck: exit 0 (check:test-typecheck OK, ledger unchanged).
  • Downstream consumers, against rebuilt dist/: all 25 packages/rest/src/import-*.test.ts files (622 passed, 21 skipped), and four plugin-security preview/write tests (132 passed).
  • Ablation A1 (via scripts/ablation-replace.mjs, which landed and restored the mutation on disk; the test reads engine.ts from src): the insertMany outcome was given the batch union instead of its row's list. Result: 4 failed / 10 passed. The tree was restored to the HEAD blob, and git diff HEAD was empty.
  • Ablation A2: the same on validate's rows. Result: 5 failed / 9 passed, then restored.
  • Reverse check of the cross-package type read: a typo key on insertManyData's outcome (read through @objectstack/metadata-protocol's rebuilt .d.ts) turned check:test-typecheck red (1 type error in the new file). It was then restored.

Gates

  • node scripts/pm/dispatch-gates.mjs --commands was derived at 886ad2c43 and named 89 families. All were run: 87 exited 0, and 2 exited 3. Reconciled with --ran: "89 derived famil(ies) accounted for, 87 run, 2 NOT-MEASURED (2 DERIVED from a recorded exit 3)".
  • NOT MEASURED: check:dual-build-cjs-loads, check:type-check-debt. Reason: PREREQUISITE NOT MET, because both read a full workspace build this worktree does not have. CI builds it.
  • NOT MEASURED locally: packages/runtime integration tier (undeclared-field-write-driver-split.integration.test.ts calls validate). Reason: 16 packages in runtime's closure are unbuilt here. It makes no deep-equality assertion on results. Declared to CI.
  • eslint, narrowed to the 7 touched .ts files with --no-inline-config --format json: 7 files, 0 errors, 0 warnings. Each file is inside the config's population (--print-config resolves it, and no "file ignored" warning). The narrowing excludes nothing: eslint.config.mjs enables no type-aware linting for any file (its own note near line 327), so this diff cannot move a verdict on an untouched file.

Changeset

.changeset/20922-per-row-dropped-fields.md grades @objectstack/objectql: minor and @objectstack/metadata-protocol: minor by the WHICH LEVEL rule. Each widens a published method's declared answer with a new optional key: InsertManyRowOutcome gains droppedFields, and so does each outcome of insertManyData's return type. That is an additive widening of the public surface. Nothing is removed, renamed or refused. The spec edits are comments, so the spec carries no entry.

Acceptance notes


Generated by Claude Code

claude added 4 commits October 1, 2026 02:05
…and insertMany outcomes

engine.validate answers each accepted row's droppedFields, and an ok
insertMany outcome carries what the strips took from that row, both
recorded at the strips themselves. The batch-level onFieldsDropped union
is unchanged. validateData relays the verdict; insertManyData passes the
outcomes through. Two spec TSDoc sentences now say what the producer does.

Claude-Session: https://claude.ai/code/session_01Ujdtvqs7ree7WyQmEDwEnG
Co-authored-by: Claude <noreply@anthropic.com>
@github-actions github-actions Bot added size/l documentation Improvements or additions to documentation tests tooling labels Oct 1, 2026
@github-actions

github-actions Bot commented Oct 1, 2026

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

This PR changes 3 package(s): @objectstack/metadata-protocol, @objectstack/objectql, @objectstack/spec, touching 5 documentable anchor(s). ⚠️ 2 changed file(s) yielded no anchor (packages/spec/src/api/export.zod.ts, packages/spec/src/api/protocol.zod.ts), so the pages documenting them are NOT COVERED by this run — this is not a clean bill of health for those files.

2 hand-written doc(s) NAME something this change touched and may need an implementation-accuracy re-verification:

  • content/docs/concepts/metadata-lifecycle.mdx (via ObjectStackProtocolImplementation (symbol, a top-level class))
  • content/docs/kernel/contracts/data-engine.mdx (via insertManyData (symbol, a method of class ObjectStackProtocolImplementation))

⛔ 4 release-owned page(s) also name something this change touched. These are read-only:

  • content/docs/releases/v16.mdx (via ObjectStackProtocolImplementation (symbol, a top-level class))
  • content/docs/releases/v17/17-0.mdx (via ObjectStackProtocolImplementation (symbol, a top-level class))
  • content/docs/releases/v17/17-4.mdx (via insertManyData (symbol, a method of class ObjectStackProtocolImplementation))
  • content/docs/releases/v17/17-5.mdx (via insertManyData (symbol, a method of class ObjectStackProtocolImplementation))

content/docs/releases/ is RELEASE-OWNED (AGENTS.md "Documentation Guardrails"): release
notes are written centrally at release time, and a code PR that edits them is the exact PR
that guardrail exists to stop. They are still audited — read-only. If one of them is actually
wrong, file an issue or open a dedicated docs-only PR; do not edit it here.

What this run could not see
  • 2 changed file(s) yielded no anchor (packages/spec/src/api/export.zod.ts, packages/spec/src/api/protocol.zod.ts) — pages documenting those are invisible to this run
  • 1 anchor(s) matched too much of the corpus to be a work list: ObjectQL (symbol, 70 pages)
  • 2 name(s) were too generic to anchor anything (single lowercase words)
  • the SDK route bridge reached 54 of 206 client-bound route-ledger rows — the other 152 have no registrar path: tail to select them, so pages documenting THEIR client methods cannot appear above, on this or any run. Of those 152: 0 are remediable by widening that discovery convention (an in-repo file declares the path; the convention did not scan it); 55 are structural — on a ledger where NOT ONE row is declared in-repo, so no discovery change reaches them at any price; 97 are undecided (no in-repo declaration, on a ledger that has other in-repo registrars — absence and an unreadable spelling are not distinguishable here). The rows themselves: node scripts/docs-audit/affected-docs.mjs --bridge-coverage
  • a page that states a rule by its inputs shares no identifier with the emitter that implements the rule, so an emitter-only diff cannot list it — not on this run and not on any run. Measured on fix(driver-sql): emit varchar(maxLength) for a text field a declared index keys on #11430: content/docs/protocol/objectql/types.mdx documents the text-family column mapping by the ObjectQL type names it maps FROM (text / textarea / html) while the diff changed createColumn; it went unlisted, and it was the page that diff falsified, in four places. No shared token exists to detect this on, so a rule your change carries has to be re-read by hand in the pages that restate it.
  • a key NAME is not a key, so the hand re-read the line above prescribes can land on the wrong schema. The same spelling is authorable on one governed type and a [REMOVED] tombstone on another for each of active, aria, joins, objects, template, tools and version (censused on [finding] tools is a key on BOTH AgentSchema (tombstoned, dead) and SkillSchema (live, cloud-attested), so a name-based search attributes skill examples to the agent key — it produced a false stop-the-line alarm on PR #19059 #19093 over the liveness ledger's governed types, top-level keys); nothing in a search result distinguishes the two, so a grep hit on a LIVE example reads as evidence about the DEAD key. Measured on fix(spec): the agent.tools liveness row says dead — it claimed live on a key the schema tombstoned #19059: content/docs/ai/agents.mdx was reported as contradicting the agent.tools tombstone over its tools: example at :161, which is inside the defineSkill({ block opened at :155 — the page was already correct. Settle ownership by PARSING the value against both schemas, never by the name: that literal PASSES SkillSchema, and as an AgentSchema it FAILS at tools with the tombstone prescription. ⛔ These names are not the whole class — a key retired through a .strict() guidance map leaves no tombstone in the walked shape and none of them here (tool.category, live as AIToolDefinition.category).

Coarse fallback — 139 page(s) merely mention a changed package (the pre-#9192 predicate, kept for the deliberately-wide backstop): node scripts/docs-audit/affected-docs.mjs --json 2f2fa11d756f665a4c06160480c1dce15b9d67a4 → packageMentionDocs.

Which tree this was computed on

This run read content/docs from c139b7f3c17d3452fff2cbfd8eefdd36ccb08109 — the merge of head 886ad2c43ee3a561d9f81bc41f65de09f8a3a8b6 into base 2f2fa11d756f665a4c06160480c1dce15b9d67a4, which is what actions/checkout gives a pull_request run. Not the PR head.

A worktree cut from an older main holds a different content/docs, so re-deriving there can legitimately return a different list — that is a different tree, not a wrong row. To answer on the same tree:

# while this PR is open — GitHub drops the merge commit once it closes
git fetch origin c139b7f3c17d3452fff2cbfd8eefdd36ccb08109 && git checkout c139b7f3c17d3452fff2cbfd8eefdd36ccb08109
# afterwards, rebuild it from the two parents, which stay fetchable
git fetch origin 2f2fa11d756f665a4c06160480c1dce15b9d67a4 886ad2c43ee3a561d9f81bc41f65de09f8a3a8b6 && git checkout -B drift-repro 2f2fa11d756f665a4c06160480c1dce15b9d67a4 && git merge --no-ff 886ad2c43ee3a561d9f81bc41f65de09f8a3a8b6

node scripts/docs-audit/affected-docs.mjs --json 2f2fa11d756f665a4c06160480c1dce15b9d67a4

⚠️ That checkout carried uncommitted changes, so the commit above does not fully identify what was read.

Advisory only, and a precision-first one (#9192): a page is listed because it names a
symbol, wire route or SDK method this diff touched — not because it mentions a changed
package. Each row says which anchor put it there, so a wrong row is reportable rather than
merely annoying. To re-verify, run the docs-accuracy-audit workflow scoped to these files:
node scripts/docs-audit/affected-docs.mjs 2f2fa11d756f665a4c06160480c1dce15b9d67a4 → pass the list as
args.docs, on the commit named under Which tree this was computed on.

@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

Contract review

Served-tier: CONTRACT_REVIEW_TIER
Head-sha: 886ad2c43ee3a561d9f81bc41f65de09f8a3a8b6
Local-runs: none

Inputs read: card #20922 (its body and all five comments, 5919693532 through 5924083608), PR #21041 (its body, its eight-file list, and the net diff of the branch head against merge-base 2f2fa11d7), and the 40 check-runs on the head, read at 2026-10-01T03:33Z. Nothing was built, run or re-run; git fetch, git diff, git show and git grep over the shared checkout were the only local acts.

① Derived judgments

Public surface, as the two packages' .d.ts publish it:

  1. @objectstack/objectql — InsertManyRowOutcome (exported at index.ts:279; the element of ObjectQL.insertMany's declared answer): its ok: true arm gains droppedFields?: DroppedFieldsEvent[]. An additive optional key on a published type — a widening. Right.
  2. @objectstack/objectql — ObjectQL.validate: declared answer unchanged (ValidateDataResponse from spec, whose results[].droppedFields spec: declare the write-drop signal on the validate and import answers (an optional per-row dropped-fields key on ImportRowResultSchema and on ValidateDataResponseSchema) and declare the served ImportRowResult.warnings: #20701 item 1, spec half #20921 declared). The behaviour now fills that key on each accepted row. No .d.ts movement; a pre-declared key produced. Right.
  3. @objectstack/metadata-protocol — ObjectStackProtocolImplementation.insertManyData: the declared outcomes element gains droppedFields?: DroppedFieldsEvent[]; the top-level droppedFields union slot and the union docblock above the signature are untouched. An additive widening. Right.
  4. @objectstack/metadata-protocol — validateData: signature and body untouched (a TSDoc note only); it returns engine.validate's answer whole, so the per-row key rides through. No listener is forwarded (the card title's mechanism): ValidateDataResponse has no batch-level slot, and triage's unlock 5919741392 had already said forwarding alone cannot fill a per-row key. What the scope asks for — the answer carries the drops in spec: declare the write-drop signal on the validate and import answers (an optional per-row dropped-fields key on ImportRowResultSchema and on ValidateDataResponseSchema) and declare the served ImportRowResult.warnings: #20701 item 1, spec half #20921's declared key — is met. Right.
  5. @objectstack/spec — protocol.zod.ts (hunk at :2119) and export.zod.ts (hunk at :327): every changed line is a * TSDoc line. No non-comment line moved; no schema, .describe() or inferred type moved; no generated artifact and no changeset entry is owed. Right.
    • The new ValidateDataResponseSchema prose states only what this head does. Read against validate at the head: stripComputedWriteFields runs in every context (before the isSystem gate); under !isSystem the runtime-owned and static-readonly strips run in insert mode and stripReadonlyFields in update mode; each records per row (computedStrip.droppedPerRow, readonlyDroppedPerRow); the key is set only on the valid: true return; validateData relays it; readonlyWhen and the primary-key strip are not run on an update-mode preview (the engine's own comment at the strips says the same). One omission, not a falsehood: the runtime-owned strip is also preserveAudit-exempt, which the sentence folds under "isSystem-gated".
    • The new ImportRowResultSchema prose: git grep over packages/rest/src/import-*.test.ts at the head finds warnings read only off synchronous-route responses (import-dryrun-parity.test.ts:204; import-integration.test.ts:824, a direct route.handler call with no job poll). "No test reads it off the async job's results" holds.
    • The droppedFields bullet left standing in export.zod.ts ("until both do, no server sets the key") stays true: the REST route does not copy the report yet.

Accept set: unchanged everywhere. Nothing is newly refused or admitted. strictReadonlyWrites still refuses the whole batch before any outcome is built (the insertDrops branch is the same, now fed by the builder); the declared-field door and the computed strip's refused skip are as they were. Right.

Batch-level union: validate's and insert's onFieldsDropped events are built by the new droppedFieldEvents(object, computed, readonly) from the same computedStrip.dropped / readonlyDropped / insertDropped arrays — one event per reason, computed then readonly, naming no row. Content identical to the base; the one observable difference is that an event now carries a copy of the array rather than the engine's own, which no contract exposes. insert(object, rows[]) outside partial mode still returns the records. Right.

Per-row attribution, judged at the code: recorded at the strips (droppedPerRow inside stripComputedWriteFields; recordTaken in validate; recordInsertTaken in insert), never derived from the union — the hookWrittenKeys case (one row's beforeInsert keeps the key, its sibling loses it) is pinned, and it is the case a reconstruction gets wrong. Index alignment holds: in validate, submittedRows → computedStrip.rows → rows (one map, same length and order) → results mapped over rows by index; in insert partial mode, computedStrip runs over opCtx.data with undeclaredPerRow, rows is rowHookContexts in input order, and the outcome map reads index i of both per-row arrays. A refused or failed row gets [] at the strips and ok: false at the outcome, so it carries none. Right.

Scope item 3 (no second strip, no second reason vocabulary): one builder, one reason set (computed, readonly), the same DroppedFieldsEvent element from @objectstack/spec/data. Right.

Pins the card names: a formula column (computed) and a readonly column (readonly) through dry run and commit, the clean-row control, and the unchanged union are pinned in the new engine-per-row-dropped-fields.test.ts, at the engine and through the real protocol, beside a refused row and a failed outcome carrying none, isSystem, update mode, the hook-exempted row, and the non-partial insert. The engine-autonumber-runtime-owned.test.ts case that pinned "names no row" now pins the row's own outcome beside the unchanged union; protocol.dropped-fields.bulk.test.ts pins pass-through with nothing derived at the seam. Right.

Docs named by the drift comment (5924017625). content/docs/kernel/contracts/data-engine.mdx: every sentence read stays true — the listener still fires once per strip pass with the union, DroppedFieldsEvent is unchanged, and the Callout's "insertManyData ... surface this seam's onFieldsDropped as their response droppedFields" still describes the top-level union; the page says nothing about per-row attribution, so the new channel contradicts nothing (a gap the REST carrier can fill, not a falsehood). content/docs/concepts/metadata-lifecycle.mdx: names ObjectStackProtocolImplementation only for getOverlayRepo() and layered metadata, which this diff does not touch. No sentence on either page is made false.

② Semver level

  • Changeset .changeset/20922-per-row-dropped-fields.md: @objectstack/objectql: minor, @objectstack/metadata-protocol: minor. Each package's .d.ts gains an optional key on a published answer (items 1 and 3 above): an additive widening, nothing removed, renamed or refused, so minor is the level the WHICH LEVEL rule gives. @objectstack/spec carries no entry and none is owed: its diff is TSDoc only and publishes no surface change. The body describes what the diff does, the unchanged union and the update-mode limit included. Right.
  • Clause-②: yes (widening) — PR body line 2, as the seat answer 5924083608 regraded the claim's no. A consumer typed by either package can read a key it could not before, so yes is the truthful value; (widening) is the matching arm of the closed pair (clause2-line.mjs lists yes (widening) as a well-formed spelling); yes takes at least minor, which both entries are. No BREAKING banner and no ADR-0087 marker are owed: nothing narrows. Right.
  • Gate read: Check Changeset (the changeset-check job, which runs check-changeset-no-major and check-adr-0087-registration against the PR body's Clause-② line and re-runs on edited) succeeded twice on this head; the second run (36810354039) started after the PR body's last edit, so the yes (widening) line, not the claim's no, is the one it passed. Governed Surface Queue Guard and Lint & Repo Gates succeeded. The declaration, the changeset and its gates read consistently. Right.

③ Boundary flags

Open questions (report 5924041038):

  • Q1, an update-mode preview runs no readonlyWhen / primary-key strip — the seat answered A (keep the named limit). Judged: answered, and right for this card. The limit pre-dates this PR (the engine's own comment at the strips), the key's .describe() already says absence proves nothing, and this head writes the limit into the ValidateDataResponseSchema TSDoc and the changeset; the commit still reports the drop on its own channel. Option B is a preview-contract change with no measured pull; C discards exact information. Not escalated.
  • Q2, the Clause-② line — the seat answered B and edited the body to yes (widening). Judged right in ② above. Not escalated.

Deviations (five):

  • No listener forwarded from validateData — judged right in ① item 4; the card's pins are met by the engine's own answer.
  • origin/main merged (the head is a merge of 2f2fa11d7) before the final gate derivation — the net diff against the merge-base is the eight files above and nothing else. No flag.
  • The first vitest launch was relaunched with its flag read correctly, and no measurement came from the first. Hygiene; no flag.
  • Unit and package tests ran at 24ca898f8 / 99a7547af, the gate union at the head — the merge brought in no file this PR touches; the head's own test verdict is CI's (below). No flag.
  • The protocol.zod.ts sentence became two — both inside the one docblock the card named. No flag.

Dev-declared NOT MEASURED, answered by the head's check-runs: check:dual-build-cjs-loads is hosted by Build Core — success; check:type-check-debt by Type Check · debt ledger — success. The packages/runtime integration tier is CI's Test Core — still in progress (below).

Out-of-scope findings (two, carried to the PR that lands #20701's REST item 1): the half-stale ImportRowResultSchema bullet is still true, and ImportProtocolLike.insertManyData in packages/rest/src/import-runner.ts types its outcomes without the optional key, which the real protocol still satisfies. Carried, not filed — rightly.

Check-runs on the head (40, read at the time stamped above): 26 success; 5 skipped (Auto Label, Build Docs, Check PR Size, Console Pin Gate, Packed-tarball smoke (opt-in) — path-skipped, not verdicts against this diff); and 9 still in_progress, which are NOT verdicts and are named as such: Test Core (1/6), Test Core (2/6), Test Core (3/6), Test Core (4/6), Test Core (5/6), Test Core (6/6), Temporal Conformance (live PG + MySQL), Dogfood Regression Gate (the aggregate; its three shards succeeded), and Type Check · workspace. The landing rule needs every check green; this record does not wait for them.

Implemented-by: claude/issue-20922-per-row-dropped-fields
Reviewed-by: session_01Ujdtvqs7ree7WyQmEDwEnG

VERDICT: PASS

@objectstack-fleet
objectstack-fleet Bot marked this pull request as ready for review October 1, 2026 03:39
@objectstack-fleet
objectstack-fleet Bot enabled auto-merge October 1, 2026 03:40
@objectstack-fleet
objectstack-fleet Bot added this pull request to the merge queue Oct 1, 2026
Merged via the queue into main with commit 657b6b7 Oct 1, 2026
44 checks passed
@objectstack-fleet
objectstack-fleet Bot deleted the claude/issue-20922-per-row-dropped-fields branch October 1, 2026 04:52
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation size/l tests tooling

Projects

None yet

2 participants