Skip to content

[finding] three "declared, not enforced yet" rows in the metadata-form reconciliation ledger are stale: field.picklist, action.onSuccess and action.outcomeMessages read live, and none has had its offer decided #21863

Closed

Description

@objectstack-fleet

Ruled: 5995552118 · letters 1A 2B · 2026-10-05T13:35Z

Filing-gate class ① (stale author- and agent-facing text contradicted by a measured ledger verdict). Filed by domain:spec seat 1 (session_01T9u38rswFp5Rw8DswRUReJ, seat post #6017) while it landed #21765 (PR #21854, record 5992359662). ⛔ Not graded or routed here, ⛔ not a claim.

Where

packages/spec/src/system/metadata-form-zod-reconciliation.test.ts at origin/main 2df3d13d16, in the group "Declared, not enforced yet — no offer until it is enforced" (from :386):

row its why says liveness/*.json on origin/main reads
field picklist (:399) "liveness verdict planned (the server-side resolution that serves a picklist-bound field its options is not landed)" live, verified 2026-10-01, evidence packages/objectql/src/registry.ts#resolvePicklistOptions (landed by #21047, the runtime of #19519)
action onSuccess (:406) "both of its children (navigate, openIn) carry the liveness verdict planned: no console consumer reads the block yet" both children live, verified 2026-09-27, objectui ActionRunner#handlePostExecution / #navigateOnSuccess (flipped by #20296)
action outcomeMessages (:413) "liveness verdict planned (#21095: the console reader … is a later link of the same ruling)" live, verified 2026-10-03, objectui ActionRunner#composeSuccessMessage

The group's other two rows were not measured here: object externalSharingModel still reads planned, and view groups has no liveness/view.json row to read.

Why it is owed

The ledger's own rule (:307-309): "The not-enforced-yet rows hold only while the verdict does. Once a key is enforced its row is stale: delete it and decide the offer then — that decision belongs to the enforcement, not to this gate."

No gate reads a why, so nothing behaves wrong. But each of the three rows now states a false premise to the next author or agent who reads why the key is missing from Studio's form.

Deleting the row alone is refused. On #21765 the dev deleted the analogous imageField row and the test answered "accepted by the Zod but unauthorable in the form — offer it, or add a root ledger entry" (report 5988698813). Each row therefore needs one of two things — ruled by the director seat (5995552118): onSuccess and outcomeMessages take the offer (1A: a composite row and a widget: 'json' row), picklist takes the reason (2B: the ruled class "authored through its own editor", naming the object designer's picker):

  • an offer: a form row, or, for a structured value, a designed control;
  • a reason under a ledger class that names the key.

Precedents for the offer half:

All three were scalars or near-scalars. Two of these keys are not:

  • onSuccess is an object (navigate, openIn);
  • outcomeMessages is a map from outcome key to I18nLabel.

That puts both on the #19332 axis (structured controls that need a designed widget, ruling record 5861442317).

picklist names a picklist metadata item. Its own row already says "the field designer offering a picklist is a later Studio phase", which reads as a decision taken under epic #18164 rather than one owed here. That deserves a check.

History of the onSuccess row:

The fix (shape, not ruled)

Who acts: domain:spec, once triage routes the card.

Dedupe: mcp__github__search_issues (repo-scoped, semantic, closed included):

0 duplicates. #20339 is closed completed with site 1 left to ride, so this card is that site's carrier.

Dedupe words: reconciliation not enforced yet stale omit row · onSuccess outcomeMessages picklist form offer · metadata-form-zod-reconciliation live verdict why

Activity

  1. objectstack-fleet commented on Oct 5, 2026

    @objectstack-fleet
    ContributorAuthor

    Ruling: batch #279 item 1 · letters 1A 2B · maintainer 「同意」 2026-10-05T13:34Z

    Director seat, summon #33, session_011SekRJwTRqXSmsP6xTSci4 (GitHub os-tesla; written as objectstack-fleet[bot] via the relay). Batch #279 was presented in chat as two items with options 1A/1B/1C and 2A/2B/2C; the maintainer answered 「同意」, which takes the recommendation, 1A and 2B. Freshness gate: the body (last edited 2026-10-05T12:21Z) and the four comments through the decision request 5994326587 were re-read before this record; nothing newer exists.

    The ruling

    1A — offer action.onSuccess and action.outcomeMessages in action.form.ts, with the controls #19332 already ruled for structured values. onSuccess takes one composite row with two sub-rows: navigate (text; the route or URL template, its ${…} interpolation named in helpText) and openIn (a select over self / newTab). outcomeMessages takes one widget: 'json' row, the same spelling this file already uses for patch (action.form.ts:104) and bodyExtra (:168), with helpText saying the keys are the handler's snake_case outcome values and the values are labels. The four-locale catalogue rows are generated with the repo's generator and the two omit rows in the "Declared, not enforced yet" group are deleted. No designed control is built: G1 of ruling 5861442317 made json the control for map- and union-shaped values, and G2 made composite the control for object-shaped ones; 1B's premise ("no designed control yet") does not hold against that ruling, so no fourth ledger class is added.

    2B — field.picklist joins the ruled class "authored through its own editor". This record is the ruling the gate asks for ("A key the ruling did not name needs a ruling of its own"): field.picklist is added to that class's key list in RULED_ROOT_REASONS, RULED_EDITORS gains a { surface } entry naming the object designer's shared-picklist picker, and the row's why states the live verdict and names that surface and the ruling that placed the offer there (#18164 batch #209 item 1 A, record 5755653853: objectui#10202 phase 2, 「use picklist」 in the object designer's select-field editor). No text row is added to field.form.ts: the decided entry is the designer's picker, and a second, weaker entry before it lands would let an author type a list name the save does not check. When a form offers the key later, the gate's resolve test retires the row and the key leaves the list in the same edit, as the class already provides.

    Not taken. 1B (a fourth class) and 2A (a text row) for the reasons above; 1C / 2C leave a false planned premise on the ledger.

    Settled in the same stroke:

    • The two unmeasured rows stay. object.externalSharingModel still reads planned and view.groups sits in the legacy-alias group with a reason that is still true (dev report 5994269771); neither is touched.
    • Execution parameters. This card continues (no new card): needs-user-decision → pm:queue; domain:spec, priority:p3, area:studio stay; Clause-②: no (form face and ledger text; no Zod change). One PR, reusing the empty branch claude/issue-21863-stale-reconciliation-rows: action.form.ts (two rows), the four packages/platform-objects/src/apps/translations/*.metadata-forms.generated.ts catalogues, and the gate file (two rows deleted, one row re-stated, the two ruled tables extended). The changeset is measured, not assumed: the gate file does not ship, the form file may (the dev reads npm pack --dry-run for src/**/*.form.ts). At-tier review on the path leg. The card closes when the PR lands.
    • The onSuccess row's history (text: three sentences still say onSuccess / flows.screens have no reader after #20296's ledger flips (reconciliation-test omit reason, cli i18n-extract docblock, flow-liveness-gate header) #20339 site 1, re-wording left to "the next spec-lane PR that touches the file") is closed by this ruling; no further carry.

    Readings behind it (each taken this summon at origin/main 9f9510f25e, or marked)

    四棱(本裁决新记录)

    • ① 长远:1A 用 #19188 split: 39 top-level zod-only keys are structured controls needing a designed widget, not a row #19332 已裁的控件,不加类别;2B 并入既有类、指向已裁入口——两项均缩小特例,不增契约。
    • ② 拉动:本仓库两动作键生产者 0,hotcrm 未测;Studio 作者今天只能改 JSON;p3。
    • ③ 防 AI:1A 不新增静默面(json 行与 JSON 同);2B 避开选择器落地前的手填错名。
    • ④ 不扩散:1A 零新键;2B 零新类;1B 的第四类不设。
    • 只看①选 1A / 2B;②③④ 是否翻转:否。

    Generated by Claude Code

  2. objectstack-fleet commented on Oct 5, 2026

    @objectstack-fleet
    ContributorAuthor

    Claim: PM loop round 1 (this card again, per the director seat's ruling 1A / 2B 5995552118, maintainer 「同意」) · 2026-10-05T16:23Z
    Session: session_01T9u38rswFp5Rw8DswRUReJ
    Account: os-project-manager (the seat's linked user as GET /user answers it; the card's assignee from this act)
    Branch: claude/issue-21863-stale-reconciliation-rows (the empty branch at 9f9510f25e the ruling names, brought to main first)
    Worktree: objectstack-issue-21863
    Domain: domain:spec
    Seat: domain:spec#1 (seat post #6017)
    File surface (at origin/main 607463d736; stop on breach and explain in the report):

  3. objectstack-fleet commented on Oct 5, 2026

    @objectstack-fleet
    ContributorAuthor

    os-dev-report

    {
      "issue": 21863,
      "status": "done",
      "branch": "claude/issue-21863-stale-reconciliation-rows",
      "pr": "https://github.com/objectstack-ai/objectstack/pull/21901",
      "session": "session_01T9u38rswFp5Rw8DswRUReJ",
      "premise_still_valid": true,
      "summary": "Ruling 1A / 2B (record 5995552118) is landed as draft PR #21901. action.form.ts now offers outcomeMessages as one widget 'json' row and onSuccess as one composite row (navigate is text and required; openIn is a select with no inline options, its members self / newTab read off the served schema, because newTab cannot be spelled as an option value). Both rows sit after successMessage / errorMessage and are gated on type api or script, the two types the parse accepts. The four platform-objects metadata-form catalogs were regenerated with check-i18n-bundles --write, the zh-CN / ja-JP / es-ES leaves were authored, and the second --write left the source-hash companions byte-identical. Three platform-objects count pins moved (661 to 665; 5 to 7; ['body'] to ['body', 'onSuccess']). In the reconciliation test, the two action omit rows are deleted, field.picklist joins the own-editor class with a RULED_EDITORS surface entry, and its why states live and names the surface and both rulings. Changeset: spec + platform-objects patch, since both ship the change in dist (measured).",
      "tests": "All through os-verify-lock at head a5106c1c78. spec --project local: 618 files passed, 18450 tests passed, 1 todo. spec --project repo: 53 files, 902 passed. platform-objects: 59 files, 949 passed; before the pins moved, exactly 3 failed ('expected 7 to be 5', \"expected [ 'body', 'onSuccess' ] to deeply equal [ 'body' ]\", 'zh-CN positive control: expected 665 to be 661'). metadata-protocol: 215 files passed, 3 skipped; 27906 tests passed, 19 skipped (no pin moved, no Zod key added). spec typecheck exit 0 and platform-objects typecheck exit 0; tsc --listFilesOnly on each tsconfig.test.json lists both changed test files. check:i18n 0, check:i18n-coverage 0 ('13 config(s), 621 baselined untranslated string(s), none new'), spec check:generated 0 (15 artifacts). CONTROLS, run in a detached throwaway worktree at a5106c1c78 through scripts/ablation-replace.mjs wrap mode, each with its own trap restoring from HEAD. Baseline: 76 passed (76). (1) onSuccess form row deleted: anchor x1 to x0, blob da0842c71614 to 0c90358ff49f. Result: 1 failed / 75 passed, \"action.(root): accepted by the Zod but unauthorable in the form — offer it, or add a root ledger entry that records why it is not offered: expected [ 'onSuccess' ] to deeply equal []\". Restored: blob da0842c71614 == HEAD, git diff HEAD empty. (2) field.picklist removed from the class key list: anchor x1 to x0; injected text read on disk during the run, removed-text 0 / injected-text 1; blob c3bc2007ee93 to aa5ba299af81. Result: 1 failed / 75 passed, '\"authored through its own editor\": the root rows giving this reason are not the keys ruling record 5861442317 put in it. A key the ruling did not name needs a ruling of its own; ...: expected [ field.picklist, …(4) ] to deeply equal [ object.actions, …(3) ]'. Restored: blob c3bc2007ee93 == HEAD, git diff HEAD empty, porcelain 0 lines. No dist was involved in either leg: the test imports relative src only. CHANGESET: npm pack --dry-run --json. In spec, src/ui/action.form.ts has 0 entries in files[] (control action.zod.ts: 1), but the new helpTexts are in 6 packed dist files (control successMessage helpText: 6). In platform-objects, the en helpText is in 6 (control 6) and the zh-CN / ja-JP labels in 6 as unicode escapes (control zh-CN successMessage: 6). eslint --no-inline-config --format json on the 8 changed TS files: 8 files, 0 errors, 0 warnings. The population is eslint.config.mjs:971; the config is not type-aware (eslint.config.mjs:326-328), so no untouched file's verdict can move.",
      "mcp_calls": "0",
      "api_writes": "3 — each one fleet-write relay dispatch executed as objectstack-fleet[bot]: POST /repos/objectstack-ai/objectstack/pulls (pr_create, draft forced; request fw-20261005T172537Z-58ccbf, run 37348340708; 11896 bytes sent and stored identical); POST /repos/objectstack-ai/objectstack/issues/21901/assignees (label-write.mjs --assign os-project-manager; request fw-20261005T172618Z-c4ea78, run 37348425951; read-back matches); POST /repos/objectstack-ai/objectstack/issues/21863/comments (this os-dev-report, post-stamped.mjs). git push (5 pushes to the branch) is not a REST write. No label added: the dispatch names none, and skip-changeset's criterion does not hold.",
      "open_questions": [],
      "out_of_scope_findings": [],
      "gates": {
        "node scripts/check-adr-0087-registration.mjs --base origin/main": 0,
        "node scripts/check-adr-0087-registration.mjs --self-test": 0,
        "node scripts/check-changeset-no-major.mjs --base origin/main": 0,
        "node scripts/check-changeset-no-major.mjs --self-test": 0,
        "node scripts/check-ci-filter-parity.mjs": 0,
        "node scripts/check-closing-keyword-parity.mjs": 0,
        "node scripts/check-closing-keyword-parity.mjs --self-test": 0,
        "node scripts/check-comment-mask-adoption.mjs": 0,
        "node scripts/check-comment-mask-adoption.mjs --self-test": 0,
        "node scripts/check-comment-mask-corpus.mjs": 0,
        "node scripts/check-dev-prereqs.mjs --self-test": 0,
        "node scripts/check-dts-emitted.mjs --self-test": 0,
        "node scripts/check-empty-changeset.mjs --base origin/main": 0,
        "node scripts/check-empty-changeset.mjs --self-test": 0,
        "node scripts/check-issue-citations.mjs": 0,
        "node scripts/check-keyed-text-bounds.mjs": 0,
        "node scripts/check-keyed-text-bounds.mjs --self-test": 0,
        "node scripts/check-platform-object-tenancy-census.mjs": 0,
        "node scripts/check-platform-object-tenancy-census.mjs --self-test": 0,
        "node scripts/check-plugin-teardown-shape.mjs": 0,
        "node scripts/check-plugin-teardown-shape.mjs --self-test": 0,
        "node scripts/check-registry-log-declared.mjs": 0,
        "node scripts/check-registry-log-declared.mjs --self-test": 0,
        "node scripts/check-rest-log-spy-declared.mjs": 0,
        "node scripts/check-rest-log-spy-declared.mjs --self-test": 0,
        "node scripts/check-spec-docblock-symbol-anchors.mjs": 0,
        "node scripts/check-spec-docblock-symbol-anchors.mjs --self-test": 0,
        "node scripts/check-system-context-census.mjs": 0,
        "node scripts/check-system-context-census.mjs --self-test": 0,
        "node scripts/check-undeclared-dep-imports.mjs": 0,
        "node scripts/check-undeclared-dep-imports.mjs --self-test": 0,
        "node scripts/docs-audit/check-affected-docs.mjs": 0,
        "node scripts/docs-audit/check-drift-comment.mjs": 0,
        "node scripts/pm/release-rehearsal-clone.mjs --self-test": 0,
        "node scripts/release-pending-publish.mjs --self-test": 0,
        "pnpm --filter @objectstack/lint run check:doc-formula-expressions": 0,
        "pnpm --filter @objectstack/spec run check:api-surface": 0,
        "pnpm --filter @objectstack/spec run check:authorable-surface": 0,
        "pnpm --filter @objectstack/spec run check:browser-reachable-entries": 0,
        "pnpm --filter @objectstack/spec run check:docs": 0,
        "pnpm --filter @objectstack/spec run check:dual-source-exports": 0,
        "pnpm --filter @objectstack/spec run check:duration-unit-keys": 0,
        "pnpm --filter @objectstack/spec run check:empty-state": 0,
        "pnpm --filter @objectstack/spec run check:entry-nameability": 0,
        "pnpm --filter @objectstack/spec run check:export-origins": 0,
        "pnpm --filter @objectstack/spec run check:exported-any": 0,
        "pnpm --filter @objectstack/spec run check:liveness": 0,
        "pnpm --filter @objectstack/spec run check:llms-txt": 0,
        "pnpm --filter @objectstack/spec run check:objectui-pin-citations": 0,
        "pnpm --filter @objectstack/spec run check:skill-refs": 0,
        "pnpm --filter @objectstack/spec run check:strictness-ledger": 0,
        "pnpm --filter @objectstack/spec run check:variant-docs": 0,
        "pnpm --filter @objectstack/spec run check:yaml-examples": 0,
        "pnpm check:changeset-gate-self-tests": 0,
        "pnpm check:cross-package-test-inputs": 0,
        "pnpm check:dispatcher-error-vocabulary": 0,
        "pnpm check:doc-authoring": 0,
        "pnpm check:driver-memory-census": 0,
        "pnpm check:dts-closure": 0,
        "pnpm check:dual-build-cjs-loads": 0,
        "pnpm check:engine-double-contract": 0,
        "pnpm check:gitlink-declared": 0,
        "pnpm check:i18n": 0,
        "pnpm check:i18n-stale-fill": 0,
        "pnpm check:issue-citations": 0,
        "pnpm check:lean-entry-closure": 0,
        "pnpm check:logger-receiver-detach": 0,
        "pnpm check:merge-driver": 0,
        "pnpm check:nul-bytes": 0,
        "pnpm check:objectql-double-limit": 0,
        "pnpm check:objectui-changeset": 0,
        "pnpm check:org-identifier": 0,
        "pnpm check:page-declaration-shape": 0,
        "pnpm check:pm-changeset-deadline-census": 0,
        "pnpm check:pm-prior-rulings": 0,
        "pnpm check:published-files": 0,
        "pnpm check:query-options-erasure": 0,
        "pnpm check:refd-timer-probe": 0,
        "pnpm check:slot-lookup": 0,
        "pnpm check:sourcemap-no-sources-content": 0,
        "pnpm check:spec-parsed-alias": 0,
        "pnpm check:test-source-alias": 0,
        "pnpm check:tier-file-adoption": 0,
        "pnpm check:type-check-coverage": 0,
        "pnpm check:type-check-debt": 0,
        "pnpm check:watch-hint-literal": 0,
        "pnpm check:where-matcher": 0,
        "pnpm check:i18n-coverage (named by the dispatch; not in the derived 87)": 0,
        "pnpm --filter @objectstack/spec check:generated (named by the dispatch; not in the derived 87)": 0,
        "node scripts/pm/dispatch-gates.mjs --ran ran.list --repo objectstack-ai/objectstack": 0
      },
      "deviations": [
        "Branch brought to main by fast-forward: `git merge --ff-only origin/main` took 9f9510f25e to 607463d736 (BASE). The push of that fast-forward was the write probe. No rebase, no force-push.",
        "The picklist why carries two record ids in one parenthetical: `(ruling record 5861442317, #19332; the picker placed there by ruling record 5755653853, #18164 batch #209 item 1 A)`. The gate requires every row of a ruled class to contain 5861442317 (test 'each class holds exactly the keys the ruling put in it, and every row cites the record': `expect(e.why).toContain('5861442317')`), and the dispatch asked the row to name 5755653853. I read that pair as the one citation the class's form requires, spelled the way the object.listViews row carries two rulings. The admitting ruling 5995552118 is cited in code comments only.",
        "Two design choices the ruling text does not spell, both taken from the file's own practice: both rows carry `visibleWhen: \"data.type == 'api' || data.type == 'script'\"`, as patch / bodyExtra carry a gate where the parse accepts the key; and `navigate` is `required: true`, as body.language / body.source are, because the Zod requires it inside the block.",
        "A second platform-objects pin file moved beyond the one the dispatch named as most likely: action-body-panel-echo-decisions.test.ts (two assertions, the unwalked composite-children count 5 to 7 and the parent set). It is covered by the claim's 'any platform-objects count pin' and by the cross-lane declaration 5998582591.",
        "Ablations ran in a detached throwaway worktree at HEAD (`git worktree add --detach ../objectstack-issue-21863-abl HEAD`), so that the gate union running in the main worktree at the same time never read a mutated tree. The worktree was clean (porcelain 0 lines) and was removed without --force after node_modules was deleted.",
        "Ablation leg 1's first attempt: `os-verify-lock: VERDICT queue-timeout (exit 99) · never acquired · waited 540s`, while the spec repo project held the lock. ablation-replace restored the file (blob == HEAD). The leg was re-run once the lock freed, and the reading reported is the re-run.",
        "spec --project repo, first attempt: `timeout 590 bash scripts/pm/os-verify-lock.sh -c 'pnpm --filter @objectstack/spec exec vitest run --project repo --maxWorkers=2'` was killed by my own timeout (EXIT=124, no verdict); no process was left behind. It was re-run in the background with a foreground `tail --pid` wait. The held lock took 784s, and the result was 53 files / 902 tests passed.",
        "The examples-closure build for check:i18n-coverage exited 2. Command: `pnpm exec turbo run build --concurrency=2 --filter=@objectstack/cli --filter=@objectstack/example-crm ... --filter=@objectstack/service-storage`. Refusal: `@objectstack/cli:build: src/commands/cloud/logout.ts(10,35): error TS7016: Could not find a declaration file for module '@objectstack/client'` (8 sites; client was a cache miss being rebuilt in the same run). The next full `turbo run build --filter=!@objectstack/docs` took 72 tasks, 71 cached, exit 0, and client's dist then carried index.d.ts. Not reproduced, so not filed.",
        "check:i18n-coverage first exited 3 (PREREQUISITE NOT MET: examples/app-showcase could not load @objectstack/connector-slack, which had no dist). check:dual-build-cjs-loads first exited 3 (PREREQUISITE NOT MET: nine packages had no dist). After the full build both exited 0, and the ran.list line for dual-build records that last reading.",
        "Commit trailers: every commit carries the model-free pair `Claude-Session: https://claude.ai/code/session_01T9u38rswFp5Rw8DswRUReJ` and `Co-authored-by: Claude ...` per AGENTS.md and the dispatch's no-model-identifier rule. The harness reminder's model-named Co-Authored-By spelling was not used.",
        "Before pr_create, origin/main was re-fetched. It had gained 87712ab823 (#21879, metadata-protocol global search: 5 paths). None touches this PR's paths: the grep over its file list for the six surfaces gave exit 1, and the control listing showed its 5 paths. So nothing was merged.",
        "Renderer face NOT MEASURED in a browser. The reading at the objectui pin 0abd4f9f87 (SchemaForm.tsx: the select falls back to the sub-schema enum; json is a passthrough) and the emitted packages/spec/json-schema/ui/Action.json (onSuccess is a plain object with openIn.enum [self, newTab]) are in the PR's Acceptance notes."
      ],
      "files_changed": [
        ".changeset/21863-action-on-success-outcome-messages-form-rows.md",
        "packages/platform-objects/src/apps/translations/action-body-panel-echo-decisions.test.ts",
        "packages/platform-objects/src/apps/translations/en.metadata-forms.generated.ts",
        "packages/platform-objects/src/apps/translations/es-ES.metadata-forms.generated.ts",
        "packages/platform-objects/src/apps/translations/ja-JP.metadata-forms.generated.ts",
        "packages/platform-objects/src/apps/translations/object-lifecycle-panel-echo-decisions.test.ts",
        "packages/platform-objects/src/apps/translations/zh-CN.metadata-forms.generated.ts",
        "packages/spec/src/system/metadata-form-zod-reconciliation.test.ts",
        "packages/spec/src/ui/action.form.ts"
      ],
      "line_budget": "128 additions / 30 deletions (git diff --shortstat 607463d736...HEAD: 9 files changed, 128 insertions(+), 30 deletions(-))"
    }

    Generated by Claude Code

  4. objectstack-fleet commented on Oct 5, 2026

    @objectstack-fleet
    ContributorAuthor

    Claim revision (file surface, round 1) of claim 5998568866: same session, account, branch, worktree, domain and seat · 2026-10-05T17:38Z

    Draft PR #21901 is red on Test Core (4/6) at a5106c1c78, and the failure is this PR's own. packages/lint/src/validate-predicate-path-refs.test.ts pins two counts over the shipped metadata-form corpus, and the two new action-form rows move both:

    • Predicates: expected 85 to be 83. outcomeMessages and onSuccess each carry visibleWhen: "data.type == 'api' || data.type == 'script'", so two new predicates.
    • == / != literal comparisons: expected 62 to be 58. Each of those predicates holds two single-quoted literal comparisons, so four more.

    File surface, added:

    • packages/lint/src/validate-predicate-path-refs.test.ts (domain:devx): the two pins move from 83 to 85 and from 58 to 62. Each move gets one history comment beside its siblings, in the file's own form: measured against the merge base by <form>::<field>::<source>, with the additions named and none removed.
      • No new test title.
      • No tracker id beyond what that form already cites.
      • No packages/lint source line moves.
    • Declared on [PM seat] domain:devx @ objectstack — ⏳ vacant #6023 in this act.

    The same CI shard never reached nine scheduled packages after the lint failure. They include objectql, service-automation and plugin-approvals. The dev runs them locally before the patch push, so one push answers every shard.

  5. objectstack-fleet commented on Oct 5, 2026

    @objectstack-fleet
    ContributorAuthor

    Contract review

    Served-tier: CONTRACT_REVIEW_TIER
    Head-sha: a5106c1c78b7a708f4651a553db7a17cfba368a7
    Local-runs: none

    PR #21901 on card #21863, judged against ruling 1A / 2B (record 5995552118), the claim 5998568866 and its revision 5999807822, the cross-lane declaration 5998582591 on #6367, the net diff against main from merge base 607463d736 (9 files, +128 / −30), and the check-runs on this head. Read-only: the diff, the card and the PR; the shard log was read through the API, nothing was built or run.

    ① Derived judgments

    • Accept set (the Zod): unchanged. No *.zod.ts, liveness or gate-logic file is in the diff. ActionSchema.onSuccess (navigate string; openIn enum self / newTab, default self) and outcomeMessages (a record of snake_case keys to I18nLabel) parse exactly as before. Right.
    • Public surface: no new export, type or exports-map entry. What ships is data inside the existing actionForm export (two rows) and four catalog keys per locale; the dev measured both in packed dist. Right, and not a Clause-② widening.
    • 1A, onSuccess: one type: 'composite' row with two sub-rows, navigate (type: 'text', required: true) and openIn (type: 'select', no inline options); the helpTexts name the route or URL template and its three interpolation scopes, taken from the key's own describe. Right.
    • 1A, outcomeMessages: one widget: 'json' row spelled as patch and bodyExtra are (field, widget, visibleWhen, helpText); the helpText says the keys are the handler's snake_case outcome values and the values are labels. Right.
    • The two omit rows (action.onSuccess, action.outcomeMessages) are deleted from the "Declared, not enforced yet" group, and nothing else in that group moves. Right.
    • 2B, field.picklist: added to the own-editor key list in RULED_ROOT_REASONS; RULED_EDITORS gains 'field.picklist': { surface: "the object designer's shared-picklist picker" }; the row sits in the own-editor group; its why opens with the class string (the gate reads startsWith), contains the surface string verbatim (the gate reads toContain), cites 5861442317 (the gate's citation check), states "liveness verdict live" with the mechanism the ledger row's evidence names (registry.ts#resolvePicklistOptions: the named picklist resolved onto the served field's options, a write judged against that set), and names the placement ruling (record 5755653853, spec: a shared picklist (global value set) metadata kind — option lists reused across objects and packages are TypeScript constants today #18164 batch Refactor protocol docs: business value over code examples #209 item 1 A). Right.
    • Catalogs: en gains outcomeMessages, onSuccess, onSuccess.navigate, onSuccess.openIn with helpText byte-equal to the form's; zh-CN, ja-JP, es-ES each carry a translated label and helpText for all four, none an echo of en; the three *.source-hashes.generated.ts companions are unchanged, which is the correct state for hand-translated leaves (an entry exists only while a leaf is a byte copy of its source). Right.
    • The two still-true rows: object.externalSharingModel appears only as context; view.groups is not in the diff. Right.
    • platform-objects pins: 661 → 665 in object-lifecycle-panel-echo-decisions.test.ts (four new row labels per locale); in action-body-panel-echo-decisions.test.ts the unwalked composite children 5 → 7 (onSuccess.navigate, onSuccess.openIn) and the parent set ['body'] → ['body', 'onSuccess']. Each follows from the diff. Right.
    • Cross-lane: in platform-objects the diff moves the four generated catalogs and two test pins and no source line, inside 5998582591. Right.
    • No new id: no added or changed test title; no added helpText carries a tracker id; the only added strings carrying ids are code comments and the picklist why, whose 5861442317 the class gate requires and whose 5755653853 the ruling 2B text itself requires in the why. Right.
    • One derived change the diff implies and this head does not carry — the FAIL reason. The two new visibleWhen strings enter the shipped-corpus census in packages/lint/src/validate-predicate-path-refs.test.ts: its walker counts every visibleWhen string and recurses through composite sub-rows, so 83 → 85; its regex counts each == / != against a single-quoted literal, two per new string, so 58 → 62. Neither pin is re-taken on this head, and CI measured exactly that: Test Core (4/6), step "Run this shard's tests", @objectstack/lint:test FAIL src/validate-predicate-path-refs.test.ts with expected 85 to be 83 (:633) and expected 62 to be 58 (:734); the turbo summary names @objectstack/lint#test as the only failed task (the @objectstack/metadata:build ELIFECYCLE line is the abort of an in-flight task, with no error of its own). At the merge base 607463d736 the same shard is green, so this is not a same-signature base red; it is this PR's. My reading of the form rows agrees that 85 and 62 are the numbers the re-take lands on: the two sub-rows carry no predicate of their own, so no third pin moves.

    ② Semver level

    ③ Boundary flags

    • (a) openIn select with no inline options — right. FormSelectOptionSchema.value is SystemIdentifierSchema (lowercase, ^[a-z][a-z0-9_.]*$), so newTab cannot be an option value; the options describe in view.zod.ts sanctions omitting the list and deriving the members from the served JSON Schema, and the file's execution and url-level openIn rows already rely on that derivation. Residual, carried not escalated: the rendered face was read at the objectui pin, not run in a browser (the ruling recorded the same gap), and the explicit type: 'select' spelling differs from those two precedents, which omit type and let the widget derive. A browser look at the composite row is still owed to whoever first opens the action form in Studio.
    • (b) visibleWhen on type == 'api' || type == 'script' — right. refuseInertOutcomeMessages refuses outcomeMessages on every other type, and the onSuccess refinement refuses the block on every other type, so each control is shown exactly where the parse admits the key; field.form.ts carries the same || shape in five rows. Not gated: the cross-field refusals (outcomeMessages beside resultDialog or operation: 'update'; onSuccess beside opensInNewTab: true on a script action). The bodyExtra precedent likewise gates on type alone and leaves its operation: 'update' refusal to the parse. Acceptable.
    • (c) navigate required: true — right. The strictObject declares navigate: z.string() with no .optional(), so inside a declared block it is required; body.language / body.source are the precedent.
    • (d) two ruling ids in the picklist why — right. The class gate requires 5861442317 in every row of the class; ruling 2B's text requires the why to name the placement ruling (5755653853); the object.listViews row already carries two rulings in one parenthetical. The admitting ruling 5995552118 stays in comments. No test title or helpText gained an id.
    • (e) second platform-objects pin file — right. action-body-panel-echo-decisions.test.ts moves by two assertions the new composite forces, both inside the claim's "any platform-objects count pin" and inside 5998582591; no source line.
    • Dev open_questions: none on the delivery report; the earlier report's two questions were answered by the ruling.
    • Claim revision 5999807822 (adds packages/lint/src/validate-predicate-path-refs.test.ts, domain:devx): the attribution matches the shard log and my reading of the counters, and 85 / 62 are the right landing numbers (see ①). That file is not in this head's diff, so this record cannot pass it: the head that carries the re-take needs its own record, or an adoption of this one once the delta is read to be exactly the two pins and their history comments.
    • Check-runs at my final read (2026-10-05T17:46Z, unchanged since 17:44Z): 28 success, 1 failure (Test Core (4/6)), 3 skipped by design (Build Docs, Console Pin Gate, Packed-tarball smoke), 2 still running (Test Core (2/6), Test Core (6/6)); the required context Test Core aggregates the shards and has not reported yet, and it will carry the shard's failure. The other required contexts are green: Lint & Repo Gates, TypeScript Type Check, Dogfood Regression Gate, Build Core, Temporal Conformance (live PG + MySQL), Governed Surface Queue Guard.

    Verdict basis. Every ruled part of 1A / 2B is implemented as ruled, the semver level and the Clause-②: no declaration hold, and every dev flag is answered. The one thing wrong on this head is a red check-run that is this PR's own: the diff moves two shipped-corpus pins it does not re-take, and a red check on the head is a FAIL under the review rules whatever else holds. The re-take to 85 / 62 (plus history comments, under the revised claim) is the whole remedy; a head that carries it and is green is expected to PASS on the readings above.

    Implemented-by: claude/issue-21863-stale-reconciliation-rows
    Reviewed-by: session_01T9u38rswFp5Rw8DswRUReJ

    VERDICT: FAIL

  6. objectstack-fleet commented on Oct 5, 2026

    @objectstack-fleet
    ContributorAuthor

    Claim revision (file surface, round 2) of claim 5998568866, after revision 5999807822: same session, account, branch, worktree, domain and seat · 2026-10-05T18:06Z

    Draft PR #21901 at a5106c1c78 is also red on Test Core (2/6), again from this PR's own change. packages/cli/test/i18n-extract-outcome-messages.test.ts ("emits nothing for an outcome nobody declared, and nothing for an action without the map", about :72) selects every extracted path containing .outcomeMessages. and pins the result to the four declared action-outcome keys. The new action-form row adds three metadata-form paths that match that substring:

    • metadataForms.action.fields.outcomeMessages.label
    • metadataForms.action.fields.outcomeMessages.helpText
    • metadataForms.action.fields.outcomeMessages.placeholder

    So the test reads expected [ …(7) ] to deeply equal [ …(4) ]. These three are form-row strings, not outcome messages.

    File surface, added:

    • packages/cli/test/i18n-extract-outcome-messages.test.ts (domain:cli). The assertion keeps its intent and stays an EQUALITY over the action-outcome keys. Either the selection excludes the metadataForms. subtree, or the three form-row paths are named in the expected list, with one comment saying why they match the substring. The dev picks one and states it in the report.
      • The test title is not changed.
      • No new tracker id.
      • No packages/cli source line moves.
    • Declared on [PM seat] domain:cli — ⏳ vacant · archive of domain:server seat 1 (#6367) #6024 in this act.

    The patch push answers both red shards (4/6, 2/6). It must run @objectstack/cli's tests locally before it goes up.

  7. objectstack-fleet commented on Oct 5, 2026

    @objectstack-fleet
    ContributorAuthor

    os-dev-report

    {
      "issue": 21863,
      "status": "done",
      "branch": "claude/issue-21863-stale-reconciliation-rows",
      "pr": "https://github.com/objectstack-ai/objectstack/pull/21901",
      "session": "session_01T9u38rswFp5Rw8DswRUReJ",
      "premise_still_valid": true,
      "summary": "Patch round 1 on claim revisions 5999807822 and 6000249318. One commit, bff24d6190 (fast-forward from a5106c1c78; no amend pushed, no force), answers both red shards. Test Core 4/6: the two shipped-corpus pins in packages/lint/src/validate-predicate-path-refs.test.ts move 83 to 85 and 58 to 62, each with one history comment in the file's own form. Test Core 2/6: packages/cli/test/i18n-extract-outcome-messages.test.ts now EXCLUDES the metadataForms subtree from its '.outcomeMessages.' selection (the coordinator's preference), with one comment, so the equality stays over the four action-outcome keys. No title changed, no source line moved in packages/lint or packages/cli, and no content/docs/releases change.",
      "tests": "MEASURED DIFF (the predicate corpus enumerated as the lint test walks it: every visibleWhen / visibleOn, a string or a {source}, keyed form :: field :: source; run with tsx on packages/spec/src/system/metadata-form-registry.ts in each tree). Merge base 607463d736: 83 predicates, 58 single-quoted ==/!= literal comparisons, which reproduces the two old pins as a control. Head: 85 predicates, 62 comparisons. Added: \"action :: onSuccess :: data.type == 'api' || data.type == 'script'\" and \"action :: outcomeMessages :: data.type == 'api' || data.type == 'script'\". Removed: none. LOCAL RUNS through os-verify-lock, after a full turbo build (72 tasks, exit 0): lint 119 files / 5629 passed (run at both c3c21b0103 and bff24d6190, with the same lint file); objectql local 374 / 7464 and repo 1 / 5; service-automation 172 / 2110; plugin-approvals 61 / 898; cloud-connection 41 / 505; http-conformance 8 / 102; plugin-dev 9 / 86; example-embed-objectql 1 / 2; connector-rest 4 / 26; connector-slack 3 / 10; rest local 260 files, 4898 passed, 326 skipped, and repo 5 files, 177 passed, 1 skipped. CLI: `pnpm --filter @objectstack/cli exec vitest run --maxWorkers=2` (both tiers, the package's test script) gave 352 files passed, 4683 passed, 2 skipped, at bff24d6190; the unit project alone gave 259 / 3786. CONTROL for the cli edit: ablation-replace swapped the new filter clause for a no-op (anchor x1 to x0, blob 31bcbfca4406 to 900d690910c0). The file then reddened exactly as CI did: \"expected [ …(7) ] to deeply equal [ …(4) ]\", received plus metadataForms.action.fields.outcomeMessages.helpText / .label / .placeholder. Restored: blob 31bcbfca4406 == HEAD, porcelain 0. A first control attempt was a tool-refused no-op (its replacement ');' overlapped the anchor: count 18 to 18) and was redone with a non-overlapping replacement. eslint --no-inline-config --format json on the 2 edited files: 0 errors, 0 warnings.",
      "mcp_calls": "0",
      "api_writes": "1 this round — POST /repos/objectstack-ai/objectstack/issues/21863/comments (this patch-round os-dev-report, through post-stamped.mjs over the fleet-write relay). The branch push (a5106c1c78..bff24d6190, fast-forward) is not a REST write. No PR body, label or assignee write. Round 0's 3 writes stand as reported.",
      "open_questions": [],
      "out_of_scope_findings": [],
      "gates": {
        "node scripts/check-adr-0087-registration.mjs --base origin/main": 0,
        "node scripts/check-adr-0087-registration.mjs --self-test": 0,
        "node scripts/check-changeset-no-major.mjs --base origin/main": 0,
        "node scripts/check-changeset-no-major.mjs --self-test": 0,
        "node scripts/check-ci-filter-parity.mjs": 0,
        "node scripts/check-closing-keyword-parity.mjs": 0,
        "node scripts/check-closing-keyword-parity.mjs --self-test": 0,
        "node scripts/check-comment-mask-adoption.mjs": 0,
        "node scripts/check-comment-mask-adoption.mjs --self-test": 0,
        "node scripts/check-comment-mask-corpus.mjs": 0,
        "node scripts/check-dev-prereqs.mjs --self-test": 0,
        "node scripts/check-dts-emitted.mjs --self-test": 0,
        "node scripts/check-empty-changeset.mjs --base origin/main": 0,
        "node scripts/check-empty-changeset.mjs --self-test": 0,
        "node scripts/check-issue-citations.mjs": 0,
        "node scripts/check-keyed-text-bounds.mjs": 0,
        "node scripts/check-keyed-text-bounds.mjs --self-test": 0,
        "node scripts/check-platform-object-tenancy-census.mjs": 0,
        "node scripts/check-platform-object-tenancy-census.mjs --self-test": 0,
        "node scripts/check-plugin-teardown-shape.mjs": 0,
        "node scripts/check-plugin-teardown-shape.mjs --self-test": 0,
        "node scripts/check-registry-log-declared.mjs": 0,
        "node scripts/check-registry-log-declared.mjs --self-test": 0,
        "node scripts/check-rest-log-spy-declared.mjs": 0,
        "node scripts/check-rest-log-spy-declared.mjs --self-test": 0,
        "node scripts/check-spec-docblock-symbol-anchors.mjs": 0,
        "node scripts/check-spec-docblock-symbol-anchors.mjs --self-test": 0,
        "node scripts/check-system-context-census.mjs": 0,
        "node scripts/check-system-context-census.mjs --self-test": 0,
        "node scripts/check-undeclared-dep-imports.mjs": 0,
        "node scripts/check-undeclared-dep-imports.mjs --self-test": 0,
        "node scripts/docs-audit/check-affected-docs.mjs": 0,
        "node scripts/docs-audit/check-drift-comment.mjs": 0,
        "node scripts/pm/release-rehearsal-clone.mjs --self-test": 0,
        "node scripts/release-pending-publish.mjs --self-test": 0,
        "pnpm --filter @objectstack/lint run check:doc-formula-expressions": 0,
        "pnpm --filter @objectstack/spec run check:api-surface": 0,
        "pnpm --filter @objectstack/spec run check:authorable-surface": 0,
        "pnpm --filter @objectstack/spec run check:browser-reachable-entries": 0,
        "pnpm --filter @objectstack/spec run check:docs": 0,
        "pnpm --filter @objectstack/spec run check:dual-source-exports": 0,
        "pnpm --filter @objectstack/spec run check:duration-unit-keys": 0,
        "pnpm --filter @objectstack/spec run check:empty-state": 0,
        "pnpm --filter @objectstack/spec run check:entry-nameability": 0,
        "pnpm --filter @objectstack/spec run check:export-origins": 0,
        "pnpm --filter @objectstack/spec run check:exported-any": 0,
        "pnpm --filter @objectstack/spec run check:liveness": 0,
        "pnpm --filter @objectstack/spec run check:llms-txt": 0,
        "pnpm --filter @objectstack/spec run check:objectui-pin-citations": 0,
        "pnpm --filter @objectstack/spec run check:skill-refs": 0,
        "pnpm --filter @objectstack/spec run check:strictness-ledger": 0,
        "pnpm --filter @objectstack/spec run check:variant-docs": 0,
        "pnpm --filter @objectstack/spec run check:yaml-examples": 0,
        "pnpm check:changeset-gate-self-tests": 0,
        "pnpm check:cli-test-child-env": 0,
        "pnpm check:cross-package-test-inputs": 0,
        "pnpm check:dispatcher-error-vocabulary": 0,
        "pnpm check:doc-authoring": 0,
        "pnpm check:docs-transcript-drift": 0,
        "pnpm check:driver-memory-census": 0,
        "pnpm check:dts-closure": 0,
        "pnpm check:dual-build-cjs-loads": 0,
        "pnpm check:engine-double-contract": 0,
        "pnpm check:gitlink-declared": 0,
        "pnpm check:i18n": 0,
        "pnpm check:i18n-stale-fill": 0,
        "pnpm check:issue-citations": 0,
        "pnpm check:lean-entry-closure": 0,
        "pnpm check:logger-receiver-detach": 0,
        "pnpm check:merge-driver": 0,
        "pnpm check:nul-bytes": 0,
        "pnpm check:objectql-double-limit": 0,
        "pnpm check:objectui-changeset": 0,
        "pnpm check:org-identifier": 0,
        "pnpm check:page-declaration-shape": 0,
        "pnpm check:pm-changeset-deadline-census": 0,
        "pnpm check:pm-prior-rulings": 0,
        "pnpm check:published-files": 0,
        "pnpm check:query-options-erasure": 0,
        "pnpm check:refd-timer-probe": 0,
        "pnpm check:slot-lookup": 0,
        "pnpm check:sourcemap-no-sources-content": 0,
        "pnpm check:spec-parsed-alias": 0,
        "pnpm check:test-source-alias": 0,
        "pnpm check:tier-file-adoption": 0,
        "pnpm check:type-check-coverage": 0,
        "pnpm check:type-check-debt": 0,
        "pnpm check:watch-hint-literal": 0,
        "pnpm check:where-matcher": 0,
        "node scripts/pm/dispatch-gates.mjs --ran ran2.list --repo objectstack-ai/objectstack": 0
      },
      "deviations": [
        "One commit pushed. The lint edit was first committed locally as c3c21b0103 and never pushed. When the addendum arrived, `git reset --soft a5106c1c78b7a708f4651a553db7a17cfba368a7` (an explicit sha, not a moving ref) folded it and the cli edit into the single commit bff24d6190, so no pushed history was rewritten.",
        "Shard 2's job log could not be read: the log download answered `curl: (56) CONNECT tunnel failed, response 403` at the proxy, and the check-run annotations name only `packages/cli ... pnpm run test exited (1)`. Whether shard 2 also left packages unreached is therefore NOT MEASURED. The cli suite was run whole (both tiers).",
        "Not merged with main: dispatch-gates warned `STALE TREE — at least 7 commit(s) behind origin/main, and 1 file(s) it derives from CHANGED across that range`. The coordinator asked for exactly one commit, so the branch was not merged, and CI's merge ref integrates main.",
        "The PR body's Verification section still cites head a5106c1c78. Per the dev contract the body is not PATCHed. A seat may append: 'Patch round 1 (bff24d6190): lint pins 83 to 85 and 58 to 62; the cli outcome-messages selection excludes metadataForms; cli 352 files / 4683 passed'."
      ],
      "files_changed": [
        ".changeset/21863-action-on-success-outcome-messages-form-rows.md",
        "packages/cli/test/i18n-extract-outcome-messages.test.ts",
        "packages/lint/src/validate-predicate-path-refs.test.ts",
        "packages/platform-objects/src/apps/translations/action-body-panel-echo-decisions.test.ts",
        "packages/platform-objects/src/apps/translations/en.metadata-forms.generated.ts",
        "packages/platform-objects/src/apps/translations/es-ES.metadata-forms.generated.ts",
        "packages/platform-objects/src/apps/translations/ja-JP.metadata-forms.generated.ts",
        "packages/platform-objects/src/apps/translations/object-lifecycle-panel-echo-decisions.test.ts",
        "packages/platform-objects/src/apps/translations/zh-CN.metadata-forms.generated.ts",
        "packages/spec/src/system/metadata-form-zod-reconciliation.test.ts",
        "packages/spec/src/ui/action.form.ts"
      ],
      "line_budget": "146 additions / 33 deletions (git diff --shortstat 607463d736...HEAD: 11 files changed); this round 18 / 3 over 2 files",
      "head": "bff24d6190054304e9999c6753732f9d5e96c302"
    }

    Generated by Claude Code

  8. objectstack-fleet commented on Oct 5, 2026

    @objectstack-fleet
    ContributorAuthor

    os-dev-report

    {
      "issue": 21863,
      "status": "done",
      "branch": "claude/issue-21863-stale-reconciliation-rows",
      "pr": "https://github.com/objectstack-ai/objectstack/pull/21901",
      "session": "session_01T9u38rswFp5Rw8DswRUReJ",
      "premise_still_valid": true,
      "summary": "Follow-up to patch round 1: main is brought in by ONE merge commit, 0313c76259 (parents bff24d6190 and cab6396715), made with `git merge origin/main`, with no rebase, amend or force. Merged range: 607463d736..cab6396715, 7 commits (#21879, #21894, #21895, #21875, #21896, #21893, #21900) over 87 files. File overlap with this PR's 11 files: none. The merge was clean, with no conflict and nothing pending in os-regen. After the merge the tree delta against main is exactly the same 11 files, 146 / 33. On the merged tree the corpus counts still hold (85 predicates, 62 literal comparisons; no entry added or removed against bff24d6190), and so do the catalog counts. No pin was re-taken.",
      "tests": "At merge head 0313c76259, after a full turbo build (72 tasks, exit 0), all through os-verify-lock. spec src/system/metadata-form-zod-reconciliation.test.ts: 1 file, 76 passed. lint src/validate-predicate-path-refs.test.ts: 1 file, 54 passed (the 85 and 62 pins). cli test/i18n-extract-outcome-messages.test.ts (unit project): 1 file, 3 passed. platform-objects full suite, including every echo-decision pin file: 60 files, 960 passed (59 / 949 at bff24d6190; main's range added a file). pnpm check:i18n: exit 0, 'platform-objects in sync (11 bundle(s))'. Corpus re-enumerated on the merged tree with the same form :: field :: source walker: 85 predicates, 62 comparisons, and against bff24d6190 nothing added and nothing removed.",
      "mcp_calls": "0",
      "api_writes": "1 this round — POST /repos/objectstack-ai/objectstack/issues/21863/comments (this os-dev-report, through post-stamped.mjs over the fleet-write relay). The push of the merge commit (bff24d6190..0313c76259) is not a REST write. No PR body write: the seat does that.",
      "open_questions": [],
      "out_of_scope_findings": [],
      "gates": {
        "node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack (at 0313c76259)": "0 — 89 derived from 11 paths vs merge base cab639671. No STALE warning. Identical to the 89 at bff24d6190, so the merged range derives NO new family and there was nothing new to run",
        "pnpm check:i18n": 0,
        "pnpm --filter @objectstack/spec exec vitest run --maxWorkers=2 src/system/metadata-form-zod-reconciliation.test.ts": 0,
        "pnpm --filter @objectstack/lint exec vitest run --maxWorkers=2 src/validate-predicate-path-refs.test.ts": 0,
        "pnpm --filter @objectstack/cli exec vitest run --project unit --maxWorkers=2 test/i18n-extract-outcome-messages.test.ts": 0,
        "pnpm --filter @objectstack/platform-objects exec vitest run --maxWorkers=2": 0
      },
      "deviations": [
        "The full 89-gate union was not re-run at the merge head. The coordinator asked for a quick re-run, and the derivation at 0313c76259 is set-identical to the 89 that all exited 0 at bff24d6190. CI on the merge head is the full measurement.",
        "Overlap check: `git diff --name-only 607463d736 cab6396715` lists 87 files (the control: non-empty). Grepping it for this PR's 11 paths gives exit 1 (zero). `git diff --name-only bff24d6190 0313c76259` touches none of the 11 either (exit 1)."
      ],
      "files_changed": [
        ".changeset/21863-action-on-success-outcome-messages-form-rows.md",
        "packages/cli/test/i18n-extract-outcome-messages.test.ts",
        "packages/lint/src/validate-predicate-path-refs.test.ts",
        "packages/platform-objects/src/apps/translations/action-body-panel-echo-decisions.test.ts",
        "packages/platform-objects/src/apps/translations/en.metadata-forms.generated.ts",
        "packages/platform-objects/src/apps/translations/es-ES.metadata-forms.generated.ts",
        "packages/platform-objects/src/apps/translations/ja-JP.metadata-forms.generated.ts",
        "packages/platform-objects/src/apps/translations/object-lifecycle-panel-echo-decisions.test.ts",
        "packages/platform-objects/src/apps/translations/zh-CN.metadata-forms.generated.ts",
        "packages/spec/src/system/metadata-form-zod-reconciliation.test.ts",
        "packages/spec/src/ui/action.form.ts"
      ],
      "line_budget": "146 additions / 33 deletions (git diff --shortstat cab6396715 0313c76259: 11 files changed), unchanged by the merge",
      "head": "0313c76259d14f1fb555c941a040f9bfde2d53da",
      "merged_range": "607463d736..cab6396715 (7 commits, 87 files, 0 overlap)"
    }

    Generated by Claude Code

  9. objectstack-fleet commented on Oct 5, 2026

    @objectstack-fleet
    ContributorAuthor

    os-dev-report

    {
      "issue": 21863,
      "status": "done",
      "branch": "claude/issue-21863-stale-reconciliation-rows",
      "pr": "https://github.com/objectstack-ai/objectstack/pull/21901",
      "session": "session_01T9u38rswFp5Rw8DswRUReJ",
      "premise_still_valid": true,
      "summary": "Second base merge: ONE merge commit, 1bd3d8e209 (parents 0313c76259 and e6dc7a2406), made with `git merge origin/main`, with no rebase, amend or force. Merged range: cab6396715..e6dc7a2406, one commit (#21904) over 10 files in metadata-core, rest, runtime and one dogfood test. Overlap with this PR's 11 files: none. The merge was clean, with no conflict and nothing pending in os-regen. The tree delta against origin/main is the same 11 files, +146 / -33, and all 11 blobs equal 0313c76259's. No form or corpus count moved.",
      "tests": "At merge head 1bd3d8e209, after a full turbo build (72 tasks, exit 0), all through os-verify-lock. spec src/system/metadata-form-zod-reconciliation.test.ts: 1 file, 76 passed. lint src/validate-predicate-path-refs.test.ts: 1 file, 54 passed (the 85 / 62 pins). cli test/i18n-extract-outcome-messages.test.ts (unit project): 1 file, 3 passed. pnpm check:i18n: exit 0, 'platform-objects in sync (11 bundle(s))'. Corpus re-enumerated on the merged tree with the same form :: field :: source walker: 85 predicates, 62 comparisons, and against 0313c76259 nothing added and nothing removed.",
      "mcp_calls": "0",
      "api_writes": "1 this round — POST /repos/objectstack-ai/objectstack/issues/21863/comments (this os-dev-report, through post-stamped.mjs over the fleet-write relay). The push of the merge commit (0313c76259..1bd3d8e209) is not a REST write. No PR body write.",
      "open_questions": [],
      "out_of_scope_findings": [],
      "gates": {
        "node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack (at 1bd3d8e209)": "0 — 89 derived from 11 paths vs merge base e6dc7a240. No STALE warning. Set-identical to the 89 at 0313c76259, so the merged range adds no new family",
        "pnpm check:i18n": 0,
        "pnpm --filter @objectstack/spec exec vitest run --maxWorkers=2 src/system/metadata-form-zod-reconciliation.test.ts": 0,
        "pnpm --filter @objectstack/lint exec vitest run --maxWorkers=2 src/validate-predicate-path-refs.test.ts": 0,
        "pnpm --filter @objectstack/cli exec vitest run --project unit --maxWorkers=2 test/i18n-extract-outcome-messages.test.ts": 0
      },
      "deviations": [
        "Overlap check: `git diff --name-only 0313c76259 1bd3d8e209` (main's 10 files) was grepped for this PR's 11 paths: exit 1, zero. Blob equality: for each of the 11 paths, `git rev-parse HEAD:PATH` equals `git rev-parse 0313c76259:PATH`; 11 of 11, none empty.",
        "The full 89-gate union was not re-run. The coordinator asked for the quick re-runs, and the derivation is set-identical to the one whose 89 commands all exited 0 at bff24d6190.",
        "The worktree was re-created on the branch at 0313c76259, never in the shared checkout, and removed after the push (porcelain 0, local HEAD == origin branch head 1bd3d8e209)."
      ],
      "files_changed": [
        ".changeset/21863-action-on-success-outcome-messages-form-rows.md",
        "packages/cli/test/i18n-extract-outcome-messages.test.ts",
        "packages/lint/src/validate-predicate-path-refs.test.ts",
        "packages/platform-objects/src/apps/translations/action-body-panel-echo-decisions.test.ts",
        "packages/platform-objects/src/apps/translations/en.metadata-forms.generated.ts",
        "packages/platform-objects/src/apps/translations/es-ES.metadata-forms.generated.ts",
        "packages/platform-objects/src/apps/translations/ja-JP.metadata-forms.generated.ts",
        "packages/platform-objects/src/apps/translations/object-lifecycle-panel-echo-decisions.test.ts",
        "packages/platform-objects/src/apps/translations/zh-CN.metadata-forms.generated.ts",
        "packages/spec/src/system/metadata-form-zod-reconciliation.test.ts",
        "packages/spec/src/ui/action.form.ts"
      ],
      "line_budget": "146 additions / 33 deletions (git diff --shortstat e6dc7a2406 1bd3d8e209: 11 files changed), unchanged by the merge",
      "head": "1bd3d8e20922291b8e526dfed7ed04bc3f19c04a",
      "merged_range": "cab6396715..e6dc7a2406 (1 commit, #21904, 10 files, 0 overlap)"
    }

    Generated by Claude Code

  10. objectstack-fleet commented on Oct 5, 2026

    @objectstack-fleet
    ContributorAuthor

    Contract review

    Served-tier: CONTRACT_REVIEW_TIER
    Head-sha: 1bd3d8e20922291b8e526dfed7ed04bc3f19c04a
    Local-runs: none

    Round 2 on PR #21901 (card #21863), after record 5999932087 failed head a5106c1c78 for one red check-run only. Reviewed head: 1bd3d8e209. Reading head: 0313c76259, whose eleven PR files I read in full; 1bd3d8e209 is a plain merge of origin/main on top of it (parents 0313c76259 and e6dc7a2406, merged range cab6396715..e6dc7a2406, one commit, #21904, ten files in metadata-core, rest, runtime, a dogfood test and its changeset), and for each of the eleven paths git rev-parse 1bd3d8e209:PATH equals git rev-parse 0313c76259:PATH (11 of 11, blobs 79751a2138, 31bcbfca44, 82c9798b58, a3e9535f4b, 09fd11a305, 670cc2688a, a73acc441f, 63748a94e4, cfc39e06ff, c3bc2007ee, da0842c716); the merge's first-parent delta is exactly main's ten files with zero overlap, and the net delta against main (merge base e6dc7a2406) is the same 11 files, +146 / −33. Judged against ruling 1A / 2B (5995552118), claim 5998568866 with revisions 5999807822 (lint, declared on #6023) and 6000249318 (cli, declared on #6024), the cross-lane declaration 5998582591, the live PR body, and the check-runs on 1bd3d8e209. Read-only: diff, card, PR and check-runs; nothing built or run.

    ① Derived judgments

    • The nine files of round 1 are byte-identical to a5106c1c78 (git diff a5106c1c78..0313c76259 over those paths is empty, and the blobs carry through to 1bd3d8e209), so every ① judgment of record 5999932087 stands unchanged: accept set unchanged (no Zod, liveness or gate-logic file); no new export; the onSuccess composite (navigate text required, openIn select with members derived from the served schema) and the outcomeMessages json row as ruled; the two omit rows deleted; field.picklist in the own-editor class with the { surface } entry and a why stating live, naming the surface verbatim and citing 5861442317 plus 5755653853; four catalogs with authored zh-CN / ja-JP / es-ES leaves and unchanged source-hash companions; three platform-objects pins; the two still-true ledger rows untouched; no new tracker id outside the ruling-required citation. Right.
    • bff24d6190 (patch round 1) touches exactly two test files, +18 / −3, no source line in packages/lint or packages/cli. Right.
    • Lint pins (validate-predicate-path-refs.test.ts): 83 → 85 and 58 → 62, each with a history comment in the file's own form (card, merge base 607463d736, the form :: field :: source difference, the two added entries, none removed, the two sub-rows carrying no predicate). These are the numbers my own reading of the two counters gave in round 1: the walker counts every visibleWhen string through composite sub-rows (+2), and the regex counts two single-quoted literal comparisons per new string (+4). Right.
    • cli pin (i18n-extract-outcome-messages.test.ts): the .outcomeMessages. selection now excludes metadataForms., with one comment, and the expected list stays the four declared action-outcome keys across both action walks. The case's intent holds and the exclusion cannot hide a real undeclared outcome. The extractor emits outcome copy only under the two action roots (objects.OBJECT._actions.ACTION.outcomeMessages.OUTCOME, globalActions.ACTION.outcomeMessages.OUTCOME; i18n-extract.ts :86-92, :687-704); the metadataForms.TYPE.fields.DOTPATH.label / helpText / placeholder subtree is registry-driven form-row text (:114-116, :1945-1947) and can never carry a stack's outcome. The equality is still toEqual over the sorted list, so an undeclared outcome under either action root still reddens it. The three paths the form row adds (metadataForms.action.fields.outcomeMessages.label / helpText / placeholder) are what reddened Test Core (2/6) on the old head (7 vs 4), and the dev's ablation control (clause made a no-op) reproduces exactly that reading. Of the two shapes revision 6000249318 allowed, the exclusion is the one that does not re-redden on the next form row whose dot path contains the substring. No test title changed; the cli edit carries no tracker id; the lint comments carry #21863 in the form every sibling history comment uses. Right.
    • The two base merges are plain merges that move no PR file. 0313c76259 merges 607463d736..cab6396715 (7 commits, 87 files); 1bd3d8e209 merges cab6396715..e6dc7a2406 (1 commit, 10 files). Neither range touches a *.form.ts, a metadata-form catalog, the form registry, the two re-taken test files, or adds a visibleWhen under packages/spec/src, so the 85 / 62 census, the 665 / 7 / ['body','onSuccess'] catalog pins and the ledger read the same on the merged tree (the dev re-measured each at both merge heads; CI on this head is the full measurement). Right.
    • Cross-lane: platform-objects moves four generated catalogs and two test pins; lint and cli move one test file each, both declared; no source line in any of the three. Right.
    • Docs Drift Check (recomputed on the merge of 1bd3d8e209 into e6dc7a2406: the same 4 hand-written pages; releases out of scope). None is made false by Studio now offering the rows. content/docs/protocol/kernel/i18n-standard.mdx states the metadataForms.TYPE.fields.DOTPATH layout and that a composite's children are enumerated all or none; the new keys (onSuccess, onSuccess.navigate, onSuccess.openIn, outcomeMessages) follow that layout exactly, and the composite enumerates both of its children; its ACTION.outcomeMessages.OUTCOME row describes stack-authored keys, which this PR does not touch. content/docs/protocol/objectui/actions.mdx and content/docs/ui/actions.mdx name only the url-level openIn: 'new-tab' key and make no statement about what Studio's action form offers (neither page names onSuccess or outcomeMessages). content/docs/ui/react-pages.mdx names the React onSuccess prop of ObjectForm, unrelated. No non-release page says the two keys are source-only or enumerates the action form's rows. Right, no docs edit owed.
    • Live PR body (read 23:38Z): Clause-②: no; the Verification section carries the patch-round bullet (pins 85 / 62, the cli exclusion and its control, the local runs). The two base merges are stated on the card (dev reports 6001928321 and 6005024482), not yet in the body. Not a defect: the body states the diff truthfully, and a merge of main changes none of it.

    ② Semver level

    • Unchanged from round 1 and still right: @objectstack/spec patch and @objectstack/platform-objects patch; the dist delta is data in existing exports; no new export, no accept-set change; same level as the feat(spec): offer object.imageField in Studio's object form beside nameField #21854 imageField precedent; skip-changeset does not apply, measured. The two new test files ship nothing and add no package. Clause-②: no holds, matching the ruling's execution parameters, the claim and the PR body.

    ③ Boundary flags

    • Flags (a)–(e) of round 1 stand as judged there (right, with the browser face of the composite row still NOT MEASURED, the gap the ruling itself recorded).
    • Round-1 FAIL reason: closed. Both red shards on a5106c1c78 were this PR's own pins and both are re-taken in bff24d6190 to the numbers the diff implies.
    • Claim revisions 5999807822 and 6000249318: the files added to the surface are exactly the two files bff24d6190 touches; the cli revision's constraints (title unchanged, equality kept, no new id, no source line) are met.
    • Dev open_questions: none on any of the three follow-up reports.
    • Check-runs on 1bd3d8e209 (read 2026-10-05T23:38Z): 32 completed success, 3 skipped by design (Build Docs, Console Pin Gate, Packed-tarball smoke opt-in), 0 failed, 0 pending. Every required context is green: Lint & Repo Gates, TypeScript Type Check, Test Core (and shards 1/6 to 6/6, the two that were red on a5106c1c78 included), Dogfood Regression Gate (and its three shards), Build Core, Temporal Conformance (live PG + MySQL), Governed Surface Queue Guard. The run on the reading head 0313c76259 never completed (the runner outage; at my reads of it nothing had failed, and no test failure is recorded on it), which is why the second base merge exists; this head's run is the full measurement, and nothing on it is attributable to runner loss.

    Verdict basis. Every ruled part of 1A / 2B is implemented as ruled, the semver level and the Clause-②: no declaration hold, every dev flag and claim revision is answered, the two pins the round-1 diff moved are re-taken to the numbers it implies, the base merges move no PR file, and every check on the head is green.

    Implemented-by: claude/issue-21863-stale-reconciliation-rows
    Reviewed-by: session_01T9u38rswFp5Rw8DswRUReJ

    VERDICT: PASS

  11. objectstack-fleet commented on Oct 5, 2026

    @objectstack-fleet
    ContributorAuthor

    ACCEPT — PR #21901 at 1bd3d8e209 (#21863: Studio's action form offers onSuccess and outcomeMessages; field.picklist joins the own-editor class)

    domain:spec seat 1 · os-project-manager · session session_01T9u38rswFp5Rw8DswRUReJ · 2026-10-05T23:41Z.

    This is the review of record for:

    • the report 5999637045;
    • its patch round 6001616349;
    • the two base merges 6001928321 and 6005024482.

    They are read with the claim 5998568866 and its revisions 5999807822 and 6000249318.

    The at-tier contract review is owed on the path leg (packages/spec/src/ui/action.form.ts):

    • Round 1: FAIL 5999932087 on a5106c1c78, for the red check alone.
    • Round 2: PASS 6005603454 on this head.

    Checklist (read on GitHub, not from the reports):

    The two CI reds were this PR's own, and both are re-taken:

    • Test Core (4/6): the two new visibleWhen gates move the shipped-corpus predicate count from 83 to 85, and the literal-comparison count from 58 to 62. The dev measured this against the merge base by <form>::<field>::<source>, and the reviewer counted the same numbers independently.
    • Test Core (2/6): the cli case selected every path containing .outcomeMessages.. The new row adds three metadataForms.action.fields.outcomeMessages.* form-row paths. Leaving that subtree out keeps the equality over the four action-outcome keys. An ablation control reddens exactly as CI did, and the reviewer judged the exclusion unable to hide a real undeclared outcome.

    Runner outage: CI on bff24d6190 and on 0313c76259 lost its runners (19:40Z–22:00Z). Jobs were shut down mid-run or cancelled before they got a runner, and no test failed. The seat has no re-run op, so main was merged in twice: 607463d736..cab6396715, then ..e6dc7a2406, with no overlap either time. On 1bd3d8e209 every workflow concluded success.

    Deviations, accepted:

    • the two claim revisions, both declared cross-lane before the edit;
    • the 89 derived gate families run in full at bff24d6190 and not re-run at the two merge heads (the derivation is set-identical, and CI ran the full set);
    • the composite face read at the objectui pin and not driven in a browser (the ruling recorded the same gap);
    • the model-free trailer pair.

    Out of scope, noted: the Docs Drift Check's four hand-written pages were read by the reviewer, and none is made false. i18n-standard.mdx's metadataForms.<type>.fields.<dotPath> layout is followed exactly. No docs edit is owed.

    Landing: flipped ready with auto-merge armed in this act. Fixes #21863 closes the card on merge.

  12. objectstack-fleet commented on Oct 6, 2026

    @objectstack-fleet
    ContributorAuthor

    Landed: PR #21901 → 8e35895832. The card is closed completed

    domain:spec seat 1 · os-project-manager · session session_01T9u38rswFp5Rw8DswRUReJ · 2026-10-06T00:27Z · holder of claim 5998568866 (revised 5999807822 and 6000249318), which this act releases.

    • Landed: PR feat(spec): offer onSuccess and outcomeMessages in Studio's action form; field.picklist joins the own-editor class #21901 merged through the merge queue at 2026-10-06T00:23Z as 8e35895832. It has one parent (3dbd084209) and is an ancestor of origin/main. Fixes #21863 closed the card completed.
    • Content check: all 11 files on origin/main are blob-equal to the reviewed head 1bd3d8e209 (at-tier PASS 6005603454, ACCEPT 6005649450).
    • What now holds, per the director seat's ruling 1A / 2B (5995552118):
      • The action form offers both post-success keys. Studio's action form now offers outcomeMessages as a json row and onSuccess as a composite row (navigate text, openIn select read from the served schema). Both are gated on the two action types whose parse admits them (api, script). The four metadata-form catalogs carry their labels and help text in en / zh-CN / ja-JP / es-ES.
      • The reconciliation ledger changed. It no longer carries the two stale "declared, not enforced yet" omit rows. field.picklist sits in the ruled class "authored through its own editor", with the object designer's shared-picklist picker as its named surface.
      • The pins moved with the rows:
        • in lint, 85 shipped-corpus predicates and 62 literal comparisons;
        • in cli, the outcome-messages selection leaves the metadataForms. subtree out;
        • in platform-objects, the echo-decision counts.
      • The release: @objectstack/spec and @objectstack/platform-objects, both patch.
    • Carried through: text: three sentences still say onSuccess / flows.screens have no reader after #20296's ledger flips (reconciliation-test omit reason, cli i18n-extract docblock, flow-liveness-gate header) #20339's site 1, which this card carried, is closed with it.
    • Not filed, noted in the ACCEPT: the composite row's browser face was read at the objectui pin and not driven in a browser. The ruling recorded the same gap.

    This act removes pm:dispatched and the assignee.

  13. added a commit that references this issue on Oct 7, 2026
    8e35895
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    area:studioChanging a running app without code — authoring, publish, docs and the portaldocumentationImprovements or additions to documentationdomain:specpriority:p3

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions