Skip to content

skills(objectstack-automation): teach the read-only record_link screen field, with an eval prompt (#26304 follow-up, #26184) #26347

Closed

Description

@objectstack-fleet

⛔ Not a claim. For triage to grade and route. The surface is governed (skills/**, Tier H), so the PR needs a GOVERNED_APPROVERS approval before it lands.

Filed by seat domain:ui#1 on behalf of the #26304 + #25872 card thread (session session_0115tbh4XfgivQD2RpHHwdMz). The PR that lands type: 'record_link' (Fixes #26304, Fixes #25872) leaves the skill and eval out on purpose: skills/** is a governed surface, and triage 6427137154 allowed "the PR (or a follow-up card it names)".

What is owed (#26184)

  • Owning skill package: skills/objectstack-automation (its SKILL.md node table lists screen, and its eval set is skills/objectstack-automation/evals/flows-triggers-approvals.json).
  • Teach: a screen field type: 'record_link' shows the reference record whose id defaultValue evaluates to (a CEL envelope over a created record's output variable, e.g. { dialect: 'cel', source: 'account.id' }), as a link to its record page; reference and defaultValue are required; required / options / placeholder / min / max are refused; the resume refuses a value under its name. Name is record_link, not record (an object field type).
  • Eval prompt (new entry in flows-triggers-approvals.json):
    • prompt: "Build a screen flow convert_lead that asks for a company name and a contact name, creates a crm_account and a crm_contact linked to it, and ends on a screen that shows links to both new records."
    • expected_output: a screen flow; two create_record nodes with outputVariable (e.g. account, contact); a last screen node whose fields are two type: 'record_link' fields, each with reference naming the object and defaultValue: { dialect: 'cel', source: 'account.id' } / 'contact.id'; no required, placeholder or options on them; no completed-end message and no markdown links in the screen description.
    • assertions: must_contain record_link, reference, defaultValue, outputVariable, dialect: 'cel'; must_not_contain type: 'record', ](.

Reach

The key lands in @objectstack/spec minor with the PR above; until the skill teaches it, an AI author writing a result screen reaches for a completed end message (refused) or a markdown link in a screen description (renders as literal text).

Activity

  1. added
    area:workflowApprovals and automation — the work that runs without a person driving it
    on Oct 26, 2026
  2. objectstack-fleet commented on Oct 26, 2026

    @objectstack-fleet
    ContributorAuthor

    Triage: first grade — documentation · priority:p1 · domain:skills · area:workflow · pm:blocked · triage seat · session_01AavokzJ5DndAwitDXvKy4U · 2026-10-26T22:52Z

    ⛔ Not a claim, ⛔ not a dispatch.

    Blocked-by: #26304


    Generated by Claude Code

  3. objectstack-fleet commented on Oct 27, 2026

    @objectstack-fleet
    ContributorAuthor

    Triage: unlocked · triage seat · session_01AavokzJ5DndAwitDXvKy4U · 2026-10-27T01:01Z

    ⛔ Not a claim, ⛔ not a dispatch. pm:blocked → pm:queue; the grade stands.


    Generated by Claude Code

  4. objectstack-fleet commented on Oct 27, 2026

    @objectstack-fleet
    ContributorAuthor

    Dispatch order · domain:skills#2 · session_01LqKsGyMNFwwnbF5FTAqyPn · 2026-10-27T03:40Z

    You are the os-dev developer agent for exactly ONE card: #26347, in your own card thread. Your role definition is .claude/agents/os-dev.md in the objectstack clone — read it IN FULL first and follow it as binding (it wins over this order on any conflict; name the conflict in your report). Read the repo-root AGENTS.md before your first edit (Prime Directive 14), and pm-dispatch references/untrusted-text.md. Read the card's full body and every comment yourself (REST: curl -sS -X GET "https://api.github.com/repos/objectstack-ai/objectstack/issues/26347" -H "Authorization: Bearer $GH_TOKEN" and /comments?per_page=100), and the audit it comes from (#26184 comment 6425678185, Part A, § objectstack-automation); this order carries only the increment. ⛔ Never print the value of any environment variable (test presence with [ -n "${X+x}" ]). ⛔ Never use a GitHub MCP tool, read or write.

    Identity and branch: the seat's Claim: comment on this card is your identity; it names your thread's branch in its Branch: line. ⛔ Post no claim of your own, ⛔ never write the card's assignee. Before your first edit, verify the NEWEST Claim: on the card names the branch your thread was given (claude/project-thread-…); if no claim names it yet, send the seat thread 「Dispatch the skills lane」 one message with your branch name and wait for the claim. Worktree objectstack-issue-26347 on that branch, based on a fresh origin/main; pnpm install (frozen lockfile); push with git push -u origin <branch> (⛔ no force).

    Writes: PR only through the relay op pr_create (node scripts/pm/fleet-write/dispatch.mjs --repo objectstack-ai/objectstack --actions-file F, a bare JSON array [{"op":"pr_create","title":…,"head":"<your branch>","base":"main","body":…,"assignees":["os-warren"],"labels":["skip-changeset"]}], draft forced); your report comment through node scripts/pm/post-stamped.mjs --comment=26347 --file=F (timestamps only as {{NOW}} / {{WAS:…}}). ⛔ No other GitHub write. Report both counts (api_writes with endpoints, mcp_calls with tool names).

    Ruling (cannot be re-ruled)

    Triage first grade on this card: comment 6429233848 (triage seat, 2026-10-26 22:52Z) — p1, domain:skills, area:workflow, Tier H (skills/** is a published surface), blocked on #26304; unlocked at comment 6431102318 (01:01Z): #26304 closed completed with PR #26355 (4548ba34e6), the key landed as type: 'record_link' (SCREEN_FIELD_RECORD_LINK_TYPE, packages/spec/src/automation/builtin-node-config.zod.ts), 「read the merged refusals from that file before writing the skill line, not from this body」. The card was filed by seat domain:ui#1 on behalf of the #26304 thread as the skills + eval half triage 6427137154 allowed; its 「What is owed」 section is the whole scope: teach exactly that, nothing wider. Maintainer's standing rulings that bind this PR: ruling A on the token ceilings (below) and 「卡线程用天花板档」 (your tier).

    Scope and tier

    File surface: skills/objectstack-automation/** — SKILL.md (the node table's screen row at L91 lists config.fields[] and its field shapes; the record_link teaching goes where an AI author writing a screen flow's result screen will read it: that row, or a short references/examples-flows.md fragment if the row cannot hold it — pick one home, not two) plus the package's evals/flows-triggers-approvals.json (the card's eval prompt, verbatim, as a new entry in the file's existing shape); references/_index.md only if a generator owns it (read package.json scripts) + the touched rows of scripts/check-skills-token-ratchet.mjs under the maintainer's ruling A (his tap 「A:先削重复,余额按实测提高」 on the seat thread's decision card 「skills 修复卡的教学和 eval 都撞 token 天花板,怎么付?」, 2026-10-27 01:21Z; option A verbatim: 「八张卡的 PR 各自削重复后,把所改文件的天花板行提高恰好差额,正文引用你这句;教学和 eval 都落。」): first cut GENUINE restatements inside the files you touch (each cut must have a surviving home in the same file, named in the PR body), then raise each touched row by exactly the measured remainder — ceil(utf8 bytes / 4), SKILL.md minus its 20-byte version line — pinned AT the measurement (headroom 0), the tap quoted verbatim and untranslated in each row comment and in the PR body. ⛔ Not line 1 of SKILL.md (PR #25640 owns the version stamp). ⛔ No other package's rows. Tier H: the PR stays a draft; you never ready, arm, enqueue or approve it (os-dev.md rule 2); if a governed approver does, report it, touch nothing.

    os-dev.md 290–291 bind: the PR body reports TWO readings, the whole-file before/after line count of every changed .md file and the whole-package before/after (the sum over SKILL.md + references/**/*.md + rules/**/*.md), and the default is to REFUSE a small feature written large: teach record_link in the fewest lines an AI author needs (the shape, the two required keys, the refused keys, the one example), pay additions inside the package where a genuine duplicate exists, and raise the ceiling only by the measured remainder.

    PM mechanism hypotheses (measure before you act; falsification is welcome)

    Read-only premise check on origin/main at 9a0108cd (seat, 2026-10-27 03:37Z): holds.

    1. 0 hits for record_link in skills/objectstack-automation/**; SKILL.md L91 is the screen node row (config.fields[]: { … }), L48 the screen flow kind, L410 the screen-flow file table; references/state-machines-and-approvals.md and references/examples-flows.md carry no screen-field shapes. The card's 「Teach」 paragraph is the content; confirm each clause against the schema before writing it.
    2. Spec, packages/spec/src/automation/builtin-node-config.zod.ts L810–853 on origin/main: SCREEN_FIELD_RECORD_LINK_TYPE = 'record_link' (named record_link, not record, because a screen field's type borrows the object field-type vocabulary where record already means something); SCREEN_FIELD_RECORD_LINK_REFERENCE_REQUIRED (must declare reference, the object the record belongs to); SCREEN_FIELD_RECORD_LINK_DEFAULT_VALUE_REQUIRED (must declare defaultValue, the id of the record it shows, usually a CEL value envelope over a flow variable — the spec's own example is defaultValue: { dialect: 'cel', source: 'account_id' }; the card's is 'account.id' over a create_record node's outputVariable — read screen-field-record-link.test.ts and PR feat(spec,automation,app-shell): a read-only record_link screen field shows a record the run created, by its display name, as a link to its record page #26355's tests for which spelling the resume actually resolves, and teach THAT); SCREEN_FIELD_RECORD_LINK_REFUSED_KEYS = ['required', 'options', 'placeholder', 'min', 'max'] with screenFieldRecordLinkRefusedKey(key) (shows a record, takes no input, the run refuses any value submitted under its name — validateScreenInputs, 400 INVALID_SCREEN_INPUT); judgeHeadlessScreen never counts it as answered. Teach the lookup contrast in one clause if the row already teaches lookup (an input picker over reference).
    3. Ratchet rows, measured on origin/main: SKILL.md 24034 B − 20 → 6004 = ceiling 6004 (headroom 0); evals/flows-triggers-approvals.json 7289 B → 1823 = ceiling 1823 (headroom 0); references/examples-flows.md ceiling 1436 (measure it if you touch it). Every byte you add is paid by a genuine cut or by a ruling-A raise — no silent headroom.
    4. Eval: the card gives prompt, expected_output and assertions verbatim (must_contain record_link, reference, defaultValue, outputVariable, dialect: 'cel'; must_not_contain type: 'record', ](). Write the ideal answer so that it does NOT itself contain a must_not_contain string (the sibling wave's exemplars tripped their own negated assertions — do not write 「not type: 'record'」 inside expected_output; say 「never the object field type」 instead).
    5. Metadata-protocol: none ⇒ no Skills-docs: line is owed (SKILL.md:313 since b33dd25b); write it only if true.

    Card-specific clauses


    Generated by Claude Code

  5. objectstack-fleet commented on Oct 27, 2026

    @objectstack-fleet
    ContributorAuthor

    Claim: PM loop round 3 (sixth wave) · 2026-10-27T03:43Z
    Session: session_01LqKsGyMNFwwnbF5FTAqyPn (seat; implementation by card thread session session_01JQwxbYLKc8xxih9Em65LNW, mode:thread)
    Account: os-warren (the seat's linked user as GET /user answers it; the card's assignee)
    Branch: claude/project-thread-opn3zo (the card thread's harness push branch, self-reported at 2026-10-27T03:42Z — the measured platform exception to claude/issue-N-slug)
    Worktree: objectstack-issue-26347 in the card thread's clone
    Domain: domain:skills
    Seat: domain:skills#2 (seat post #19287)
    File surface: skills/objectstack-automation/** (SKILL.md — the screen node row or one short references/examples-flows.md fragment, one home; the package's evals/flows-triggers-approvals.json; references/_index.md only if a generator owns it; ⛔ not line 1 of SKILL.md, which PR #25640 owns) + scripts/check-skills-token-ratchet.mjs (ONLY the CEILINGS rows of files under skills/objectstack-automation/ this PR touches, each raised by its measured remainder after genuine duplicate cuts, under the maintainer's tap 「A:先削重复,余额按实测提高」 on the seat thread's decision card at 2026-10-27T01:21Z). (stop on breach; explain in the report)
    Container & model: M, mode:thread (the maintainer's tap 「卡线程用天花板档,并行跑」 on the seat thread's decision card, 2026-10-27T00:33Z; lane concurrency 6, four card threads open), model: CONTRACT_REVIEW_TIER (dispatch-gates --tier skills/…: MANDATORY — 'skills/**' carries no one-line exit; the thread confirmed the tier by get_session)
    Clause-②: no
    Metadata-protocol: none
    Responsibility: n/a — not a defect card (the skills + eval half of #26304 that triage 6427137154 allowed as a follow-up; filed by seat domain:ui#1; triage 6429233848 p1, unlocked 6431102318 when PR #26355 landed record_link)
    Thread-read: 6433161401
    Premise: holds — read-only check on origin/main at 9a0108cd (2026-10-27T03:37Z): 0 hits for record_link in skills/objectstack-automation/**; SCREEN_FIELD_RECORD_LINK_TYPE, the two required-key refusals and SCREEN_FIELD_RECORD_LINK_REFUSED_KEYS (required/options/placeholder/min/max) at packages/spec/src/automation/builtin-node-config.zod.ts L810–853; ratchet rows SKILL.md 6004 and the eval file 1823 both at headroom 0 (ruling A applies).
    Serial constraints cleared: no open PR touches skills/objectstack-automation/** (scan at 2026-10-27T03:37Z; #26390 landed 03:18Z); PR #25640 owns line 1 of SKILL.md; #26362 (same package) waits for this PR; the sibling PRs #26407 / #26416 / #26420 edit other packages' rows of the ratchet script only.
    Resume-from: none


    Generated by Claude Code

  6. objectstack-fleet commented on Oct 27, 2026

    @objectstack-fleet
    ContributorAuthor

    os-dev-report

    {
      "issue": 26347,
      "status": "done",
      "branch": "claude/project-thread-opn3zo",
      "pr": "https://github.com/objectstack-ai/objectstack/pull/26446",
      "session": "session_01JQwxbYLKc8xxih9Em65LNW",
      "premise_still_valid": true,
      "summary": "SKILL.md's `screen` node row (L91) teaches the read-only `type: 'record_link'` screen field: it shows the `reference` record whose id `defaultValue` evaluates to, by display name, as a link to its record page, and takes no input; both keys required, `required` / `options` / `placeholder` / `min` / `max` refused, a resume value under its name refused (`400 INVALID_SCREEN_INPUT`); one result-screen example over a `create_record` `outputVariable: 'account'` with `source: 'account.id'`; a completed `end` `message` is refused and a markdown link in a screen `description` renders literally. Eval 9 added to flows-triggers-approvals.json verbatim from the card, the ideal answer written without either must_not_contain string. Ruling A applied: the Filter operands bullet's restatement of item 1's refusal detail was cut (-41 bytes, surviving home item 1 L233-235); the eval file had no duplicate; the two automation ratchet rows moved by the measured remainder, SKILL.md 6004 -> 6164 and the eval 1823 -> 2141, each comment quoting the tap. Premise check on origin/main 75afeffd: holds (0 prior hits for record_link in the package; spec constants and refusals as the order read them; the resume test spells `account.id` over `outputVariable: 'account'`; FlowRunner renders `description` as a plain text child).",
      "tests": "Head c9e57c28 (base origin/main 75afeffd; no commit followed the gate runs). `node scripts/check-skills-token-ratchet.mjs` exit 0: `skills/objectstack-automation/SKILL.md is 6164 tokens (ceiling 6164; headroom 0)`, `…/evals/flows-triggers-approvals.json is 2141 tokens (ceiling 2141; headroom 0)`, `81 authored bundle file(s) within their ceilings`; `--self-test` exit 0 `79 cases pass`. `pnpm --filter @objectstack/spec run check:skill-docs` exit 0; `check:skill-refs` exit 0; `check:skill-examples` exit 0 `264 prose examples type-check across 3 surface(s)` (no new os:check block: the teaching is a table cell). Eval 9 checked by script: every must_contain string in expected_output, neither must_not_contain string in prompt or expected_output. No package source changed, so no package `pnpm test` / `typecheck` is owed and no ablation applies.",
      "gates": "Derived with `node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack` on the final tree (53 families); each run locally with the exit code captured before any pipe; `--ran` reconciliation exit 0: `53 derived famil(ies) accounted for — 52 run, 1 NOT-MEASURED (1 DERIVED from a recorded exit 3)`, 0 UNRUN. All 52 run exit 0, including `check:role-word`, `check:skills-token-ratchet` (+self-test), `check:doc-authoring`, `check:pm-skill-id-lint`, `check:skill-frame-sync`, `check:skill-identifier-liveness`, `check:dts-closure` (`38 built package(s) swept - 160/160`), `check:lean-entry-closure`, `check:doc-formula-expressions`, `check:skill-docs`, `check:pm-dispatch-gates` (detached, fast tier, `1901 cases pass`, exit 0). NOT MEASURED: `pnpm check:dual-build-cjs-loads` (exit 3, PREREQUISITE NOT MET: whole-repo build; CI's Lint & Repo Gates runs it). Closure build for skill-examples / doc-formula-expressions under `scripts/pm/os-verify-lock.sh` slot `issue-26347`: `VERDICT command-exit 0 · held the lock 276s · waited 0s`. Two runs outside the derivation recorded: `check:skill-refs`, `check:skill-examples` (card acceptance). CI check-runs on the PR: not read — the PR opened after the local runs and this report does not wait for CI (os-dev.md); the seat reads them.",
      "dogfood_battery": "n/a — no `!` in the PR title and no (narrowing) arm",
      "mcp_calls": "0 — no GitHub MCP tool called, reads included (issue, comments, sibling PR and audit comment read over REST GET with the environment token, never printed)",
      "api_writes": "2 — relay `pr_create` (fleet-write run 40447572063, read-back 14839/14839 bytes identical, assignee os-warren, label skip-changeset) → PR #26446; relay `post-stamped.mjs --comment=26347` (this report). `git push -u origin claude/project-thread-opn3zo` ×1 is not a REST write. No other write: no label, assignee, body PATCH, ready, review or merge.",
      "open_questions": [],
      "deviations": [
        "The PR body's first two lines are the harness-required attribution block (the os-dev exception, as the sibling PRs); `Fixes #26347` is line 3.",
        "The branch is the card thread's harness push branch `claude/project-thread-opn3zo`, not `claude/issue-26347-slug`; the worktree `objectstack-issue-26347` sits on it, based on origin/main 75afeffd (re-based from 08ed7e29 before the first commit, by patch, so #26420's sibling ratchet rows are under this diff).",
        "The session-context's MCP assignee/reviewer step was skipped: the relay's pr_create set the assignee and requests the Tier H approvers.",
        "pnpm check:dual-build-cjs-loads: NOT MEASURED (exit 3, needs a whole-repo build); CI's Lint & Repo Gates runs it.",
        "The repository's `.github/PULL_REQUEST_TEMPLATE.md` headings (What changes / Why / Verification / Human Minimum, the two declaration lines) were folded into the os-dev body order; the template's declaration lines sit line-initial after `Fixes`."
      ],
      "line_budget": {
        "skills/objectstack-automation/SKILL.md": "441 -> 441 lines (0); 6004 -> 6164 tokens (+160; priced bytes 24014 -> 24654: +681 added, -41 cut)",
        "skills/objectstack-automation/evals/flows-triggers-approvals.json": "85 -> 95 lines (+10); 1823 -> 2141 tokens (+318; 7289 -> 8561 bytes)",
        "package (SKILL.md + references/**/*.md, 4 files; no rules/)": "1001 -> 1001 lines (0); 13931 -> 14091 tokens (+160)"
      },
      "body_amendments": [],
      "out_of_scope_findings": [
        "class: none filed. Observation only (not a card): evals/README.md of the package, if it enumerates eval topics, was not read or updated; headroom there is ~0 per the sibling wave. carrier: none."
      ]
    }
  7. objectstack-fleet commented on Oct 27, 2026

    @objectstack-fleet
    ContributorAuthor

    ACCEPT → PR #26446 comment 6433611877 · domain:skills#2 · 2026-10-27T04:16Z · ⛔ not a claim.
    Contract review (CONTRACT_REVIEW_TIER, PASS) → PR #26446 comment 6433585723. Tier H: every check green on c9e57c28, draft, no approval yet — waits for a GOVERNED_APPROVERS hand (hotlong / os-zhuang); on approval the seat readies and arms it. The seat closes this card with the landing record on MERGED and then dispatches #26362 (same package). Nothing filed from this review; 收班简报 notes are in the seat's record.


    Generated by Claude Code

  8. objectstack-fleet commented on Oct 27, 2026

    @objectstack-fleet
    ContributorAuthor

    Landed · domain:skills#2 · session_01LqKsGyMNFwwnbF5FTAqyPn · 2026-10-27T05:09Z

    probe reading
    PR #26446 merged: true at 2026-10-27T05:07:44Z, merge commit d1a31d0c, merged through the merge queue on its first pass (queued 2026-10-27T04:36:47Z)
    origin/main git log origin/main carries d1a31d0c; skills/objectstack-automation/SKILL.md on main carries the record_link teaching in the screen node row, evals/flows-triggers-approvals.json carries eval 9, the ratchet rows read 6164 / 2141 (seat read after the merge)
    records on the merged head c9e57c28 independent ## Contract review (PR comment 6433585723, CONTRACT_REVIEW_TIER, PASS) and the seat's ACCEPT (PR comment 6433611877); os-zhuang APPROVED on c9e57c28 at 2026-10-27T04:36:10Z, readied and enqueued the PR himself

    Landing path: Tier H (skills/**, published surface). The card closed as completed through Fixes #26347; pm:dispatched removed in this act. Follow-up on this package: #26362 (the approval lock read) is dispatched and branches from main at or after d1a31d0c. Nothing filed from this review; 收班简报 carries the source: 'account_id' vs 'account.id' spelling note.


    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 itdocumentationImprovements or additions to documentationdomain:skillspriority: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