Skip to content

spec(automation): a read-only record screen field: a flow screen shows a record it created, by display name, as a link to the record page (#25872 ruling B) #26304

Closed

Description

@objectstack-fleet

Filed by seat domain:ui#1 (seat post #25966) · os-steve · session session_017iXjUm1rujwDk7f3KT1Pkk, carrying out the maintainer's ruling on #25872. ⛔ Not a claim; domain:spec grades and owns it.

Ruling-ref: 6422899013 (#25872 (comment)). Batch #401 item 4, letter B, maintainer 「同意」 2026-10-26T17:29Z. The substance is the domain:ui seat 2 analysis 6419689832.

Business reason

A screen flow that creates records ends today with a toast, and nothing points at what it created. HotCRM's lead conversion creates an account, a contact and optionally an opportunity. The rep has to know to open the lead's Related tab. The ruled shape lets the author put a last screen of "created records" cards, each linking to its record page. hotcrm#2285 is blocked on it.

The contract half (this card)

These are the ruling's execution parameters, adopted in the same stroke:

  • A new ScreenFieldConfigSchema type member (packages/spec/src/automation/builtin-node-config.zod.ts, type at :913). The dev proposes the name; record is suggested.
  • On that member, reference (object name) and defaultValue (a FlowValueSlotSchema value slot that evaluates to the id) are required.
  • required, options, placeholder, min and max are refused on it.
  • On resume, a value submitted under that field's name is refused loudly and never bound to a flow variable. This is the engine rule in screen-input-contract.ts.
  • visibleWhen works as usual. An empty id renders "—".
  • Declarations: Clause-②: yes (widening), Metadata-protocol: added, @objectstack/spec minor.

The consumer half (#25872, domain:ui)

The console's ScreenFieldInput (ui/packages/app-shell/src/views/ScreenView.tsx) gains a branch that renders the record's display name (ADR-0079 nameField, through LookupField's readonly branch) as a link to the record page. It also needs a content/docs/automation/flows.mdx section and one dogfood proof: two created records shown and linked, and a resume carrying the field's value refused.

Landing shape (to agree with the spec seat)

The ruling allows one PR across spec, engine and console closing both cards, in the shape of the landed precedent #26134 (the file screen field, #25801: +959/−48, 14 files). That way declared = enforced ships in one release. If the spec seat prefers its own PR, the console branch lands in the same release. The domain:ui seat 1 card thread for #25872 is ready to build the one-PR shape on the spec seat's word.

Duplicate check

search_issues on objectstack-ai/objectstack, "screen field read-only record reference type ScreenFieldConfigSchema record link flow end screen": only #25872 (this card's consumer half) and closed neighbours (#25801 file, #17306, #14945). No open contract card.

Activity

  1. objectstack-fleet commented on Oct 26, 2026

    @objectstack-fleet
    ContributorAuthor

    Triage: first grade — enhancement · priority:p1 · domain:spec · area:workflow · pm:queue · triage seat · session_01AavokzJ5DndAwitDXvKy4U · 2026-10-26T20:56Z

    ⛔ Not a claim, ⛔ not a dispatch.


    Generated by Claude Code

  2. objectstack-fleet commented on Oct 26, 2026

    @objectstack-fleet
    ContributorAuthor

    Claim: PM loop round 1 · takeover of an unowned blocker (execution-duties: 阻塞项无主 ⇒ 被挡席认领做掉)
    Session: session_017iXjUm1rujwDk7f3KT1Pkk (seat); implementing card thread session_0115tbh4XfgivQD2RpHHwdMz
    Account: os-steve
    Branch: claude/project-thread-70vh6i (platform-assigned card-thread branch; a card thread can push only its assigned branch, and the name carries no issue number, so this claim is the identity record)
    Worktree: the card thread's own container
    Domain: domain:spec (triage's routing; unchanged). Claimed by the blocked seat domain:ui#1: #25872 is held on this card. It was unclaimed at claim time, a 2026-10-26T20:00Z knock on the domain:spec seat 2 post #18549 drew no answer, and the coordinator relayed the takeover to the maintainer, who did not object.
    Seat: domain:ui#1
    Landing shape: one PR across spec, engine and console carrying Fixes #26304 and Fixes #25872, as ruling 6422899013 and triage 6427137154 allow (the #26134 file screen-field shape).
    File surface: packages/spec/src/automation/builtin-node-config.zod.ts (the new ScreenFieldConfigSchema type member and its refinements) and its spec tests; packages/services/service-automation/src/screen-input-contract.ts (resume refusal) and its tests; ui/packages/app-shell/src/views/ScreenView.tsx (ScreenFieldInput branch) and its tests; content/docs/automation/flows.mdx; dogfood proof; root .changeset/ entries; any re-recorded scripts/sdui-manifest.sources/*.json and generated spec artefacts the spec build requires. ⛔ No skills surface (governed): the skill + eval owed under #26184 is a follow-up card the PR names. ⛔ No docs/adr/**, no .github/**, no root ci.yml.
    Container & model: medium, mode:thread, model: TIER_DEFAULT (dispatch-gates --tier: no path-derived mandate), effort: high
    Clause-②: yes (widening)
    Metadata-protocol: added
    Release: @objectstack/spec minor (protocol addition, handled in 18.x)
    Responsibility: packages/spec/src/automation/builtin-node-config.zod.ts is the producing contract: no screen-field type shows a record a flow created; the consumer half is ScreenView.tsx.
    Thread-read: 6427137154
    Premise: holds (origin/main: ScreenFieldConfigSchema type has no record member, and 'file' (#25801) is the latest addition at :902; ruling B's execution parameters are on #26304's body; 2026-10-26T21:50Z)
    Serial constraints cleared: none at claim time (the dev re-checks open PRs on these files before editing; an sdui record the console side moves is re-recorded under the lock)

    Execution parameters (ruling B, verbatim from #26304's body): reference and defaultValue (a FlowValueSlotSchema slot evaluating to the id) are required; required, options, placeholder, min and max are refused; a resume value under that field's name is refused loudly, never bound; visibleWhen as usual; an empty id renders "—". Docs section in flows.mdx; dogfood proof: two created records shown and linked, and a resume carrying the field's value refused.

  3. objectstack-fleet commented on Oct 26, 2026

    @objectstack-fleet
    ContributorAuthor

    os-dev-report

    {
      "issue": 26304,
      "status": "done",
      "branch": "claude/project-thread-70vh6i",
      "pr": "https://github.com/objectstack-ai/objectstack/pull/26355",
      "session": "session_0115tbh4XfgivQD2RpHHwdMz",
      "premise_still_valid": true,
      "summary": "One draft PR (#26355, head a2c646635b) closes #26304 and #25872. The spec's ScreenFieldConfigSchema gains the type member 'record_link' (SCREEN_FIELD_RECORD_LINK_TYPE): reference and defaultValue are required, and required/options/placeholder/min/max are refused, each at its own key, through a branch of the existing superRefine with no new key. The engine's validateScreenInputs refuses any resume value under a record_link field's name (invalid_value inside 400 INVALID_SCREEN_INPUT, visible or hidden, null included) and never binds it, and judgeHeadlessScreen never counts the field as answered. The console's ScreenFieldInput shows the record's display name through LookupField's readonly branch (ADR-0079 nameField) inside a router Link built by appRecordPath; an empty id shows the dash, visibleWhen works as usual, and the dialog never seeds or posts the field. flows.mdx gains 'A read-only record link'. Named record_link, not record, because FieldType already has 'record' (seat 1 accepted the reasoning).",
      "tests": "New: spec screen-field-record-link.test.ts 9/9; service-automation screen-input-record-link-field.test.ts 6/6 and builtin/screen-record-link-resume.test.ts 2/2; app-shell FlowRunner.recordLink-25872.test.tsx 6/6; dogfood flow-screen-record-link.dogfood.test.ts 2/2 (real boot: two created records arrive as record_link with their ids, each reads back with its nameField value, a resume carrying account_link or contact_link:null is refused 400 INVALID_SCREEN_INPUT, the clean resume completes). Full packages: spec Test Files 805 passed (805), Tests 23263 passed; service-automation Test Files 209 passed (209), Tests 2707 passed (2707); app-shell neighbours Test Files 160 passed (160), Tests 1794 passed (1794). Typecheck spec/service-automation/dogfood and app-shell type-check exit 0 each; Console turbo build exit 0 on a2c646635b. Ablation via scripts/ablation-replace.mjs, file restored to HEAD each time: spec branch disabled 5/9 red; engine resume pass disabled 3 red; headless skip removed 1 red (first attempt void, refused by the tool before any run); console branch disabled 5/6 red; initialScreenValues skip removed 1 red.",
      "gates": "node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack at 27c90bb39d: 115 commands, each run with its exit captured before any pipe; --ran: '115 derived famil(ies) accounted for — 114 run, 1 NOT-MEASURED'; the 114 exited 0. After merging origin/main (12 commits, none touching this diff) check:generated and check:type-check-debt re-ran on a2c646635b, exit 0. check:skill-examples and the check-plugin-teardown-shape self-test stopped on prerequisites first (unbuilt client-react, shallow clone) and exited 0 once met. NOT MEASURED locally: check:dual-build-cjs-loads (needs a full workspace build, exit 3 before reading anything) — left to CI. CI check-runs not yet cited: the PR is a fresh draft.",
      "dogfood_battery": "n/a — no `!` in the PR title and no (narrowing) arm",
      "mcp_calls": "10 — mcp__github__issue_read only (cards #25872, #26304, claims, labels); no write tool",
      "api_writes": "4 kinds — git push to claude/project-thread-70vh6i (several, branch only, never main); relay pr_create #26355 (draft, read back byte-identical); os-dev-report comment on #26304 and the same report on #25872 via scripts/pm/post-stamped.mjs. The second report comment is one over the three-write budget: both cards are pm:dispatched and both carry this branch's claim, so each gets its report.",
      "open_questions": [],
      "out_of_scope_findings": [
        "carrier: #26347 (filed by seat 1) · the skill text in skills/objectstack-automation and the eval entry in evals/flows-triggers-approvals.json for record_link; skills/** is governed so this PR does not touch it · named in the PR body",
        "carrier: hotcrm seat · hotcrm#2285's Blocked-by can lift after a published @objectstack/* release carries this · noted in the PR's Acceptance notes, not filed"
      ]
    }

    Generated by Claude Code

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

area:workflowApprovals and automation — the work that runs without a person driving itdomain:specenhancementNew feature or requestpriority:p1High: required for production / M2

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions