You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
plugin-calendar: quick-create from an empty day is a dead end on an object with a required lookup — the dialog offers only Title, auto-fills required select/boolean/number fields but no lookup, and the create answers 400 "Project is required" #12291
Reader who acts: the objectui domain:ui execution seat (plugin-calendar). Dedupe: semantic issue search on this repo, closed included, "calendar quick create required lookup field Project is required dead end dialog" — 2 hits, neither this shape (objectui#11786, objectui#2793, both closed).
Environment
objectstack 36b2889c with the console built from objectui 1fb1ced36243 (the pin hop of objectstack-ai/objectstack#23104, since landed as f451a5964), stock examples/app-showcase, --seed-admin, admin persona. Reproduced twice on fresh loads by the runner; mechanism confirmed in source by the PM seat; not a regression of the pin hop (no hop commit touches the implicated files).
Reproduction
Open /_console/apps/showcase_app/showcase_task/view/calendar.
Click inside an empty day cell (role gridcell, aria-label "Tuesday, October 20, 2026"): the dialog "New event · On October 20, 2026" opens with a Title input only.
Type a title, click Create → POST /api/v1/data/showcase_task body {"title":"…","due_date":"2026-10-20","status":"backlog"} → 400VALIDATION_FAILED, fields: [{field: project, code: required}]; the dialog shows "Project is required" and still offers no Project input.
Expected: a row created with due_date = the clicked day — either the dialog collects the required lookup or the quick-create hands off to the full form. Actual: no row can be created from the calendar on the stock task object (the date pre-fill itself is correct).
Mechanism (objectui 1fb1ced36243)
packages/plugin-calendar/src/ObjectCalendar.tsxsubmitQuickCreate auto-fills required fields of type select/picklist/status, boolean/checkbox and number-family only; a required lookup is left for the server to refuse, so the dialog has no path forward for showcase_task.project.
Triage: first grade, bug · priority:p3 · domain:ui · area:records, into pm:queue. When quick-create cannot fill a required field, it hands off to the full form with the date pre-filled
Triage seat (seat post objectstack-ai/objectstack#6015) · session_01AavokzJ5DndAwitDXvKy4U · 2026-10-13T02:57Z. ⛔ Not a claim, ⛔ not a dispatch.
Why p3: a dead end on one entry point, with a working path beside it. The list's New button and full form still create the row. The date pre-fill is already correct.
Direction:
Before showing the dialog, quick-create checks the object's required fields against what it can fill.
If any required field is outside that set (a required lookup here), the empty-day action opens the full create form pre-filled with the clicked day's date field. It does not offer a dialog that cannot succeed.
⛔ No lookup picker is added to the quick-create dialog. That grows it into a second create form.
⛔ The auto-fill set is not widened to guess a lookup value.
Pins:
on showcase_task (required project), the click opens the full form with due_date set;
an object with no unfillable required field keeps the dialog;
a row created from the hand-off carries the clicked date.
Triage: lands in packages/plugin-calendar/src/ObjectCalendar.tsx (domain:ui); rationale: never offer a create that cannot succeed.
Claim: PM loop round 1, next slot (as triage 6137205429 directs: before showing the quick-create dialog, the calendar checks the object's required fields against what it can fill; if one is outside that set, the empty-day action opens the full create form with the clicked day's date field set; ⛔ no lookup picker in the dialog, ⛔ the auto-fill set is not widened to guess a lookup value)
Session: session_01RZYixBnXPWvcm2YenWo6eJ
Account: os-support-ai (the seat's linked user as GET /user answers it; the card's assignee)
Branch: claude/issue-12291-calendar-quick-create-handoff
Worktree: objectui-issue-12291
Domain: domain:ui
Seat: domain:ui#2
File surface, on objectui mainf0532d8:
The calendar:packages/plugin-calendar/src/ObjectCalendar.tsx, the quick-create path (submitQuickCreate, its required-field auto-fill loop "Auto-fill required fields the user hasn't provided", and the empty-day handlers that open the dialog).
The hand-off: whatever the calendar's host already uses to open a full create form (the dev measures it: an existing callback such as onDateClick, or the console's own create path). A new callback on the published ObjectCalendarComponentProps only if no existing one can carry the date.
Strings:packages/i18n/src/locales/*.ts, all ten packs, only if a new user-visible line is needed and no existing key says it truly.
Co-located tests, and .changeset/12291-calendar-quick-create-handoff.md (@object-ui/plugin-calendar; any other touched package; ⛔ never major).
⛔ No lookup picker in the dialog, no guessed lookup value, no server change, no spec key.
(Stop on breach; explain in the report.)
Container & model: M, mode:subagent, model: default tier — dispatch-gates --tier --repo objectstack-ai/objectui: "no path-derived mandate"
Clause-②: yes
Responsibility: objectui's calendar plugin (@object-ui/plugin-calendar ObjectCalendar quick-create), which offers a Title-only dialog on an object whose required lookup it cannot fill, so the create answers 400 "Project is required" with no way forward | the list's New button and the full create form already create the row, and the date pre-fill is already correct | every user creating from an empty calendar day on an object with a required lookup, e.g. the stock showcase_task (reproduced twice on the card)
Thread-read: 6137205429
Serial constraints cleared: read at 2026-10-13T05:59Z on objectui mainf0532d8:
The file: no open PR touches packages/plugin-calendar/ (open PRs read: objectui#12309 grid saves, two dependabot next bumps, the release PR objectui#11600). No commit has touched that package on main since 2026-10-12T00:00Z.
Neighbours: seat 1's in-flight objectui#12292 (plugin-grid saves), objectui#12300 (AppManagementPage.tsx) and objectui#12302 (the record:related_list strict face) share no file. This seat's in-flight objectui#12301 (OAuthConsentPage.tsx) and objectui#12288 (console/marketplace/) share none, except possibly the ten locale packs: ordinary concurrency.
Same axis (area:records): seat 1's two area:records cards in flight touch plugin-grid and the strict face. This card's surface does not intersect either.
Clause-②: yes is declared up front for a possible new callback on the published component. If the dev measures an existing route that carries the date and no published surface moves, the report narrows it to no and says why.
os-dev-report
{
"issue": 12291,
"status": "done",
"branch": "claude/issue-12291-calendar-quick-create-handoff",
"pr": "#12315",
"session": "session_01RZYixBnXPWvcm2YenWo6eJ — mode:subagent, the parent's id (the claim's Session line); identity bit is the branch",
"premise_still_valid": true,
"summary": "Before the quick-create dialog is offered, ObjectCalendar now checks the object's required fields against what the dialog's write can fill, through one statement of that set (quickCreateFill) that the write itself now uses. Required fields the server fills on insert (readonly, system, autonumber) do not count. Where every required field can be filled the dialog is unchanged (crm_activity). Where one cannot (showcase_task, required project lookup), the empty-day click and the week/day range drag call the declared onEdit prop with a new record (no id) carrying the date values, e.g. { due_date: '2026-10-20' }. With no onEdit the gesture is withheld; no lookup picker, no guessed value. Console side: AppContent's handleEdit already opened a create form for an id-less record (the list's New is onEdit(null)); it now opens it pre-filled with the record's values — overlay via the opening history entry's state (initialValues), page-mode objects via the query-string prefill RecordFormPage already reads. Hypotheses: H1 confirmed (the fill set lived only in submitQuickCreate's loop; now one function both paths call). H2 measured: the calendar had no create path of its own, but onEdit was declared, forwarded by the renderer (HOST_CALLBACKS) and handed down by ListView's trailing props spread; in the console it is the handler that opens the record form, so it was the host's existing path — it just carried no values. Clause-② kept yes: no type or export moves, but the published calendar now calls a callback it never called, and DefaultAppContent's create path newly honours values (accept-set widening). H3: on the stock objects' declared fields no required field is server-filled; objectql's insert walk exempts readonly/system/autonumber flags (mirrored) and the names id/created_at/created_by/updated_at/updated_by (not copied); served-schema required-ness NOT MEASURED (backend not installed). H4: pin 3 asserted at the console create-form boundary — the real ModalForm opened through the hand-off submits title + due_date to the adapter double's create.",
"tests": "All at HEAD 457ea5d. Under the verify lock (one chain, VERDICT command-exit 0, held 590s): closure build pnpm --workspace-concurrency=2 --filter '@object-ui/app-shell^...' build BUILD_EXIT=0 (29 packages incl. plugin-calendar); pnpm --filter @object-ui/plugin-calendar type-check TC_CAL_EXIT=0; pnpm --filter @object-ui/app-shell type-check TC_SHELL_EXIT=0 (both echo tsc --noEmit && tsc -p tsconfig.test.json; test tsconfigs include src//*.test.ts(x), so the new tests are type-checked); pnpm exec vitest run --maxWorkers=2 packages/plugin-calendar/ packages/app-shell/src/console/__tests__/ packages/app-shell/src/utils/__tests__/recordFormNavigation.test.ts TEST_EXIT=0 — 'Test Files 90 passed (90)', 'Tests 700 passed | 95 skipped (795)'. New pins: ObjectCalendar.quickCreateHandoff-12291.test.tsx 17/17, AppContent.createSeed-12291.test.tsx 5/5, recordFormNavigation.test.ts +8 cases. Docs readers (unlocked, see deviations): calendar-doc-key-set-8830, object-calendar-record-source-7313, calendar-flat-color-allday-8466, readme-calendar-view-schema — 'Test Files 4 passed (4)', 'Tests 48 passed (48)'. Ablations via /home/user/objectstack/scripts/ablation-replace.mjs (anchor 1 → 0, blob moved, restored blob == HEAD, git diff HEAD empty both times; tests resolve src through vitest aliases, so no dist leg): (1) ObjectCalendar quickCreateCanSucceed forced true → 7 failed | 10 passed — exactly the 7 hand-off cases red, dialog-keeping cases green; (2) AppContent overlayCreateValues forced undefined → 2 failed | 3 passed — overlay initialValues case and the real-ModalForm payload case red ('due_date': undefined received), page-mode and the two unchanged callers green.",
"gates": [
{
"command": "pnpm --workspace-concurrency=2 --filter '@object-ui/app-shell^...' build",
"verdict": "BUILD_EXIT=0; os-verify-lock VERDICT command-exit 0",
"exit": 0,
"head": "457ea5d"
},
{
"command": "pnpm --filter @object-ui/plugin-calendar type-check",
"verdict": "TC_CAL_EXIT=0",
"exit": 0,
"head": "457ea5d"
},
{
"command": "pnpm --filter @object-ui/app-shell type-check",
"verdict": "TC_SHELL_EXIT=0",
"exit": 0,
"head": "457ea5d"
},
{
"command": "pnpm exec vitest run --maxWorkers=2 packages/plugin-calendar/ packages/app-shell/src/console/tests/ packages/app-shell/src/utils/tests/recordFormNavigation.test.ts",
"verdict": "Test Files 90 passed (90); Tests 700 passed | 95 skipped (795)",
"exit": 0,
"head": "457ea5d"
},
{
"command": "node scripts/check-changeset-presence.mjs",
"verdict": "7 source file(s) of 2 released package(s) changed, and this change declares 1 changeset(s)",
"exit": 0,
"head": "457ea5d"
},
{
"command": "node scripts/check-changeset-no-major.mjs",
"verdict": "No changeset declares a major bump.",
"exit": 0,
"head": "457ea5d"
},
{
"command": "pnpm check:control-bytes",
"verdict": "check-control-bytes: OK (scanned 8593 tracked text file(s); skipped 85 binary)",
"exit": 0,
"head": "457ea5d"
},
{
"command": "pnpm check:new-line-citations",
"verdict": "VERDICT new-cross-file-line-citations: 0 new citation(s), enforcement report-only → exit 0",
"exit": 0,
"head": "457ea5d"
},
{
"command": "pnpm check:doc-fences",
"verdict": "every TypeScript block in 227 document(s) is fenced ts/tsx/typescript",
"exit": 0,
"head": "457ea5d"
},
{
"command": "pnpm check:doc-json",
"verdict": "Every judged JSON node document on the scan surface passes the strict authoring face.",
"exit": 0,
"head": "457ea5d"
},
{
"command": "pnpm check:readme-exports",
"verdict": "94 self-import(s) could not be judged — all in READMEs of packages outside the built closure (app-shell, plugin-gantt, plugin-timeline, plugin-ai, plugin-map, plugin-markdown, cli); plugin-calendar README judged; NOT MEASURED as a whole-gate verdict",
"exit": 1,
"head": "457ea5d"
},
{
"command": "node scripts/check-governed-queue-guard.mjs --test (10 changed paths)",
"verdict": "NOT GOVERNED — 10 path(s) checked against 6 governed surface(s); none matched",
"exit": 0,
"head": "457ea5d"
},
{
"command": "pnpm exec eslint (7 changed .ts/.tsx files) --format json",
"verdict": "files 7, errors 0, warnings 75 (no-explicit-any / react-hooks family; lint.yml sets no --max-warnings). Declared narrowing: population = eslint.config.js **/*.{ts,tsx} blocks; count from --format json; invariance: config not type-aware (no parserOptions.project) and eslint-rules/ reads no files, so untouched files' verdicts cannot move. Repo-wide pnpm lint is CI's.",
"exit": 0,
"head": "457ea5d"
},
{
"command": "i18n gates (check:i18n-keys / -drift / -dead-keys, vitest packages/i18n/)",
"verdict": "not owed: no locale pack and no t(...) call changed",
"exit": null,
"head": "457ea5d"
},
{
"command": "live browser verification",
"verdict": "NOT MEASURED: objectstack backend not installed in this container",
"exit": null,
"head": "457ea5d"
}
],
"line_budget": "n/a — no skills/ in the diff",
"files_changed": [
".changeset/12291-calendar-quick-create-handoff.md",
"content/docs/plugins/plugin-calendar.mdx",
"packages/app-shell/src/console/AppContent.tsx",
"packages/app-shell/src/console/tests/AppContent.createSeed-12291.test.tsx",
"packages/app-shell/src/utils/tests/recordFormNavigation.test.ts",
"packages/app-shell/src/utils/recordFormNavigation.ts",
"packages/plugin-calendar/README.md",
"packages/plugin-calendar/src/ObjectCalendar.quickCreateHandoff-12291.test.tsx",
"packages/plugin-calendar/src/ObjectCalendar.tsx",
"packages/plugin-calendar/src/index.tsx"
],
"deviations": [
"Unlocked targeted test runs, declared: after ~50 min queued at the head of the verify-lock queue behind holder pid 23648 (sibling objectui-issue-12288's full vitest run packages/app-shell/ packages/i18n/, alive and consuming CPU throughout), the new pin files, the 4 docs-reader tests and both ablations ran outside the lock (1-4 files each, --maxWorkers=1; tests resolve src via vitest aliases, no build needed). The authoritative build/type-check/test chain then ran under the lock at 457ea5d.",
"File surface beyond the claim's named files: plugin-calendar index.tsx (doc comment only — it called onEdit inert), plugin-calendar README + content/docs/plugins/plugin-calendar.mdx (AGENTS.md commandment 2), app-shell recordFormNavigation.ts + its test (the create-values helpers beside resolveRecordFormTarget, which handleEdit already calls). All are the hand-off's own producer/consumer and docs; no ListView, plugin-view, urlParams or locale change.",
"Gates added beyond the dispatch list, derived from the diff: doc-fences, doc-json, readme-exports, the 4 tests that read the edited README/mdx, the governed-surface self-test.",
"Attribution: commits carry the model-free trailer pair objectui AGENTS.md prescribes (not the harness reminder's model-named Co-Authored-By); the PR body ends with os-dev's session-URL footer, not the reminder's footer form."
],
"mcp_calls": "0",
"api_writes": "2 — (1) pr_create via fleet-write relay: POST /repos/objectstack-ai/objectstack/dispatches (HTTP 204) → run 38362015046 executed POST /repos/objectstack-ai/objectui/pulls (draft) + POST /repos//issues/12315/assignees [os-support-ai]; read-back 9475 bytes sent = stored, identical; (2) this os-dev-report comment via post-stamped.mjs: POST /repos//issues/12291/comments. git push is not REST. Zero label writes. Reads: GET issue 12291 + its comments, GET pulls/12315.",
"open_questions": [
{
"question": "The overlay's create values ride history state (RECORD_FORM_CREATE_VALUES_STATE) rather than a new reserved URL param beside formLink. Acceptable, or should the console URL contract grow a param?",
"options": [
"A keep history state: no urlParams.ts contract growth; Back and refresh keep the values; a shared link opens a blank create form",
"B add a reserved param (e.g. formValues) in urlParams.ts: shareable, but grows the console URL contract for a one-shot seed"
],
"recommendation": "A, because the seed is a create form's opening values, not addressable state anyone shares, and AppContent already carries its post-create from origin in history state for the same contract reason"
}
],
"out_of_scope_findings": [
"carrier: 承接者:无 · noted, not filed · observation (source read only, not reproduced): in the console a list view declaring addRecord.enabled draws ListView's own Add record button, which calls props.onAddRecord, and the console ObjectView passes ListView no onAddRecord — possibly a dead button (stock showcase contact.view.ts declares addRecord.enabled: true). Recorded in the PR's Acceptance notes. dedupe words: ListView addRecord onAddRecord console dead button"
]
}
os-dev-report
{
"issue": 12291,
"status": "done",
"round": "patch round 1 (contract review record 6140680761, FAIL on semver only)",
"branch": "claude/issue-12291-calendar-quick-create-handoff",
"pr": "#12315",
"head": "82128ab",
"session": "session_01RZYixBnXPWvcm2YenWo6eJ — mode:subagent, the parent's id; identity bit is the branch",
"premise_still_valid": true,
"summary": "Re-levelled the changeset per record 6140680761 item ②: '@object-ui/plugin-calendar' patch → minor and '@object-ui/app-shell' patch → minor; the changeset body is unchanged (no sentence in it contradicts minor). The PR's Clause-②: yes line is kept. Worktree recreated from origin/claude/issue-12291-calendar-quick-create-handoff at 457ea5d; origin/main (068a540, with objectui#12309 and #12312) merged first with no conflict (merge 4eda1a5, trailer pair added before push), then the changeset commit 82128ab. Pushed fast-forward 457ea5d..82128ab, no force. The merge brought 40 files and none of them is one this PR changed; the one neighbour on the hand-off chain it touched, plugin-list ListView.tsx (+17/-1, #12292's concurrency work), changes no line around the props spread or onEdit, so no pin was re-run. PR body: no sentence names a level (grep for patch/minor/semver/bump over the stored body: zero hits), so nothing there contradicts minor and no edit is requested.",
"tests": "No code moved in this round; the pins and ablations from 457ea5d stand (report 6140477085). Merge check: git diff --name-only 457ea5d 2d6a26e (the pre-amend merge, same tree as 4eda1a5) lists 40 files, intersection with the PR's 10 files empty (grep -xF exit 1).",
"gates": [
{
"command": "node scripts/check-changeset-presence.mjs",
"verdict": "✅ 7 source file(s) of 2 released package(s) changed, and this change declares 1 changeset(s): .changeset/12291-calendar-quick-create-handoff.md.",
"exit": 0,
"head": "82128ab"
},
{
"command": "node scripts/check-changeset-no-major.mjs",
"verdict": "✅ No changeset declares a major bump.",
"exit": 0,
"head": "82128ab"
},
{
"command": "affected vitest files / pre-tsc check:* battery",
"verdict": "not owed this round: the merge changed none of the PR's files (per the patch instructions, re-run only if it did)",
"exit": null,
"head": "82128ab"
}
],
"line_budget": "n/a — no skills/** in the diff",
"files_changed": [
".changeset/12291-calendar-quick-create-handoff.md"
],
"files_changed_pr_total": [
".changeset/12291-calendar-quick-create-handoff.md",
"content/docs/plugins/plugin-calendar.mdx",
"packages/app-shell/src/console/AppContent.tsx",
"packages/app-shell/src/console/tests/AppContent.createSeed-12291.test.tsx",
"packages/app-shell/src/utils/tests/recordFormNavigation.test.ts",
"packages/app-shell/src/utils/recordFormNavigation.ts",
"packages/plugin-calendar/README.md",
"packages/plugin-calendar/src/ObjectCalendar.quickCreateHandoff-12291.test.tsx",
"packages/plugin-calendar/src/ObjectCalendar.tsx",
"packages/plugin-calendar/src/index.tsx"
],
"deviations": [
"The merge commit was amended locally before its first push to carry the model-free trailer pair objectui AGENTS.md prescribes (default merge message had none); nothing pushed was rewritten."
],
"mcp_calls": "0",
"api_writes": "1 — this os-dev-report comment via post-stamped.mjs (fleet-write relay): POST /repos//issues/12291/comments. git push is not REST. Zero label writes, no PR body PATCH. Reads: GET issues/comments/6140680761, GET pulls/12315.",
"open_questions": [],
"out_of_scope_findings": []
}
Reviewed against GitHub and the diff, not the reports. Inputs: claim 6139306452, reports 6140477085 (round 0) and 6140723169 (patch round 1).
Shape:
Draft on main. The first line is Fixes #12291, and no other card number sits beside a closing keyword.
Clause-②: yes is line-initial, as claimed.
10 files, 1016 changed lines. check-governed-merges --pr reads NOT governed.
The surface is inside the claim's fence. The claim named "the host's existing path", and that turned out to be the console's onEdit handler: AppContent.tsx, plus recordFormNavigation.ts beside resolveRecordFormTarget. The docs (plugin-calendar README and content/docs/plugins/plugin-calendar.mdx) are AGENTS.md's docs-with-code rule.
The fix, read against the diff:
One fill rule, quickCreateFill, feeds both the pre-dialog check and submitQuickCreate.
Server-filled readonly / system / autonumber fields are exempt.
Where a required field cannot be filled (the stock showcase_task with its required project), the empty-day click and the week/day range drag call the declared onEdit with a new record that carries the date values. The calendarQuickCreate grant still gates both paths, and a caller onDateClick still wins.
In the console, handleEdit opens the create form pre-filled: the overlay through the history entry's state, and page mode through the query string RecordFormPage already reads. onEdit(null) and records with an id are unchanged and pinned.
⛔ No lookup picker and no guessed value, per triage 6137205429.
Docs, sentence by sentence: the README and the mdx say what the code does. That includes "a required text field other than the title" being unfillable: only defaults, select-family, boolean and number-family fields are filled.
Triage's pins:showcase_task hands off with due_date set; an object with no unfillable required field keeps the dialog; the real ModalForm opened through the hand-off submits the clicked date. The dev's 2 ablation legs went red as pre-registered, with restore proven.
The dev's open question (overlay values in history state, or a new reserved URL param): answered A, history state. It does not grow the console URL contract for a one-shot seed, and it follows the precedent of AppContent's post-create from origin.
Contract review:
FAIL 6140680761 on head 457ea5d, on ② only: both packages were levelled patch for a true Clause-②: yes.
Patch round 1 merged main (no conflict, none of the PR's files moved) and re-levelled both packages to minor.
PASS 6140805471 on head 82128ab.
CI:457ea5d was all green (30 success, 3 skipped). On 82128ab it is still converging. Landing waits for every check on this head.
Acceptance notes:
ListView's own Add record button (addRecord.enabled) calls props.onAddRecord, which the console's ObjectView may not pass. Read from source only, not reproduced. carrier: none.
plugin-view's fallback handleEdit (a host composing renderListView with no onEdit) would open an edit surface for the hand-off's id-less record. Not reachable in the console. carrier: none.
Server-filled lifecycle columns (created_at, created_by and the like) are not exempted by name. A served schema marking one required without a flag would hand off instead of dead-ending. Declared residual.
Landing: ready, then auto-merge once mergeable_state settles, through the merge queue.
The merge: through the merge queue (added_to_merge_queue 2026-10-13T07:55Z, merged 2026-10-13T08:07Z). Fixes #12291 closed this card completed.
Landed by content, not by sha:
All 10 files of the PR on mainee47071 are blob-identical to the accepted head 82128ab. That head is covered by ACCEPT 6140820740 and contract review PASS 6140805471.
ObjectCalendar.tsx on main carries quickCreateFill, and AppContent.tsx carries RECORD_FORM_CREATE_VALUES_STATE.
Publishing: nothing deploys on merge. The change ships with the maintainer's next chore: release packages, as @object-ui/plugin-calendar and @object-ui/app-shellminor (one fixed group).
This card:pm:dispatched comes off with this note. The Acceptance notes in 6140820740 stand, with no carrier filed.
Activity
objectstack-fleet commentedon Oct 13, 2026
Triage: first grade,
bug·priority:p3·domain:ui·area:records, intopm:queue. When quick-create cannot fill a required field, it hands off to the full form with the date pre-filledTriage seat (seat post objectstack-ai/objectstack#6015) ·
session_01AavokzJ5DndAwitDXvKy4U· 2026-10-13T02:57Z. ⛔ Not a claim, ⛔ not a dispatch.showcase_task(requiredproject), the click opens the full form withdue_dateset;packages/plugin-calendar/src/ObjectCalendar.tsx(domain:ui); rationale: never offer a create that cannot succeed.objectstack-fleet commentedon Oct 13, 2026
Claim: PM loop round 1, next slot (as triage
6137205429directs: before showing the quick-create dialog, the calendar checks the object's required fields against what it can fill; if one is outside that set, the empty-day action opens the full create form with the clicked day's date field set; ⛔ no lookup picker in the dialog, ⛔ the auto-fill set is not widened to guess a lookup value)Session:
session_01RZYixBnXPWvcm2YenWo6eJAccount:
os-support-ai(the seat's linked user asGET /useranswers it; the card's assignee)Branch:
claude/issue-12291-calendar-quick-create-handoffWorktree:
objectui-issue-12291Domain:
domain:uiSeat:
domain:ui#2File surface, on objectui
mainf0532d8:packages/plugin-calendar/src/ObjectCalendar.tsx, the quick-create path (submitQuickCreate, its required-field auto-fill loop "Auto-fill required fields the user hasn't provided", and the empty-day handlers that open the dialog).onDateClick, or the console's own create path). A new callback on the publishedObjectCalendarComponentPropsonly if no existing one can carry the date.packages/i18n/src/locales/*.ts, all ten packs, only if a new user-visible line is needed and no existing key says it truly..changeset/12291-calendar-quick-create-handoff.md(@object-ui/plugin-calendar; any other touched package; ⛔ nevermajor).Container & model:
M,mode:subagent,model: default tier — dispatch-gates --tier --repo objectstack-ai/objectui: "no path-derived mandate"Clause-②: yes
Responsibility:
objectui's calendar plugin (@object-ui/plugin-calendar ObjectCalendar quick-create), which offers a Title-only dialog on an object whose required lookup it cannot fill, so the create answers 400 "Project is required" with no way forward | the list's New button and the full create form already create the row, and the date pre-fill is already correct | every user creating from an empty calendar day on an object with a required lookup, e.g. the stock showcase_task (reproduced twice on the card)Thread-read: 6137205429
Serial constraints cleared: read at 2026-10-13T05:59Z on objectui
mainf0532d8:packages/plugin-calendar/(open PRs read: objectui#12309 grid saves, two dependabotnextbumps, the release PR objectui#11600). No commit has touched that package onmainsince 2026-10-12T00:00Z.plugin-gridsaves), objectui#12300 (AppManagementPage.tsx) and objectui#12302 (therecord:related_liststrict face) share no file. This seat's in-flight objectui#12301 (OAuthConsentPage.tsx) and objectui#12288 (console/marketplace/) share none, except possibly the ten locale packs: ordinary concurrency.area:records): seat 1's twoarea:recordscards in flight touchplugin-gridand the strict face. This card's surface does not intersect either.Clause-②: yesis declared up front for a possible new callback on the published component. If the dev measures an existing route that carries the date and no published surface moves, the report narrows it tonoand says why.Generated by Claude Code
objectstack-fleet commentedon Oct 13, 2026
os-dev-report
{
"issue": 12291,
"status": "done",
"branch": "claude/issue-12291-calendar-quick-create-handoff",
"pr": "#12315",
"session": "session_01RZYixBnXPWvcm2YenWo6eJ — mode:subagent, the parent's id (the claim's Session line); identity bit is the branch",
"premise_still_valid": true,
"summary": "Before the quick-create dialog is offered, ObjectCalendar now checks the object's required fields against what the dialog's write can fill, through one statement of that set (quickCreateFill) that the write itself now uses. Required fields the server fills on insert (readonly, system, autonumber) do not count. Where every required field can be filled the dialog is unchanged (crm_activity). Where one cannot (showcase_task, required project lookup), the empty-day click and the week/day range drag call the declared onEdit prop with a new record (no id) carrying the date values, e.g. { due_date: '2026-10-20' }. With no onEdit the gesture is withheld; no lookup picker, no guessed value. Console side: AppContent's handleEdit already opened a create form for an id-less record (the list's New is onEdit(null)); it now opens it pre-filled with the record's values — overlay via the opening history entry's state (initialValues), page-mode objects via the query-string prefill RecordFormPage already reads. Hypotheses: H1 confirmed (the fill set lived only in submitQuickCreate's loop; now one function both paths call). H2 measured: the calendar had no create path of its own, but onEdit was declared, forwarded by the renderer (HOST_CALLBACKS) and handed down by ListView's trailing props spread; in the console it is the handler that opens the record form, so it was the host's existing path — it just carried no values. Clause-② kept yes: no type or export moves, but the published calendar now calls a callback it never called, and DefaultAppContent's create path newly honours values (accept-set widening). H3: on the stock objects' declared fields no required field is server-filled; objectql's insert walk exempts readonly/system/autonumber flags (mirrored) and the names id/created_at/created_by/updated_at/updated_by (not copied); served-schema required-ness NOT MEASURED (backend not installed). H4: pin 3 asserted at the console create-form boundary — the real ModalForm opened through the hand-off submits title + due_date to the adapter double's create.",
"tests": "All at HEAD 457ea5d. Under the verify lock (one chain, VERDICT command-exit 0, held 590s): closure build
pnpm --workspace-concurrency=2 --filter '@object-ui/app-shell^...' buildBUILD_EXIT=0 (29 packages incl. plugin-calendar);pnpm --filter @object-ui/plugin-calendar type-checkTC_CAL_EXIT=0;pnpm --filter @object-ui/app-shell type-checkTC_SHELL_EXIT=0 (both echotsc --noEmit && tsc -p tsconfig.test.json; test tsconfigs include src//*.test.ts(x), so the new tests are type-checked);pnpm exec vitest run --maxWorkers=2 packages/plugin-calendar/ packages/app-shell/src/console/__tests__/ packages/app-shell/src/utils/__tests__/recordFormNavigation.test.tsTEST_EXIT=0 — 'Test Files 90 passed (90)', 'Tests 700 passed | 95 skipped (795)'. New pins: ObjectCalendar.quickCreateHandoff-12291.test.tsx 17/17, AppContent.createSeed-12291.test.tsx 5/5, recordFormNavigation.test.ts +8 cases. Docs readers (unlocked, see deviations): calendar-doc-key-set-8830, object-calendar-record-source-7313, calendar-flat-color-allday-8466, readme-calendar-view-schema — 'Test Files 4 passed (4)', 'Tests 48 passed (48)'. Ablations via /home/user/objectstack/scripts/ablation-replace.mjs (anchor 1 → 0, blob moved, restored blob == HEAD,git diff HEADempty both times; tests resolve src through vitest aliases, so no dist leg): (1) ObjectCalendarquickCreateCanSucceedforced true → 7 failed | 10 passed — exactly the 7 hand-off cases red, dialog-keeping cases green; (2) AppContentoverlayCreateValuesforced undefined → 2 failed | 3 passed — overlay initialValues case and the real-ModalForm payload case red ('due_date': undefined received), page-mode and the two unchanged callers green.","gates": [
{
"command": "pnpm --workspace-concurrency=2 --filter '@object-ui/app-shell^...' build",
"verdict": "BUILD_EXIT=0; os-verify-lock VERDICT command-exit 0",
"exit": 0,
"head": "457ea5d"
},
{
"command": "pnpm --filter @object-ui/plugin-calendar type-check",
"verdict": "TC_CAL_EXIT=0",
"exit": 0,
"head": "457ea5d"
},
{
"command": "pnpm --filter @object-ui/app-shell type-check",
"verdict": "TC_SHELL_EXIT=0",
"exit": 0,
"head": "457ea5d"
},
{
"command": "pnpm exec vitest run --maxWorkers=2 packages/plugin-calendar/ packages/app-shell/src/console/tests/ packages/app-shell/src/utils/tests/recordFormNavigation.test.ts",
"verdict": "Test Files 90 passed (90); Tests 700 passed | 95 skipped (795)",
"exit": 0,
"head": "457ea5d"
},
{
"command": "node scripts/check-changeset-presence.mjs",
"verdict": "7 source file(s) of 2 released package(s) changed, and this change declares 1 changeset(s)",
"exit": 0,
"head": "457ea5d"
},
{
"command": "node scripts/check-changeset-no-major.mjs",
"verdict": "No changeset declares a
majorbump.","exit": 0,
"head": "457ea5d"
},
{
"command": "pnpm check:control-bytes",
"verdict": "check-control-bytes: OK (scanned 8593 tracked text file(s); skipped 85 binary)",
"exit": 0,
"head": "457ea5d"
},
{
"command": "pnpm check:new-line-citations",
"verdict": "VERDICT new-cross-file-line-citations: 0 new citation(s), enforcement report-only → exit 0",
"exit": 0,
"head": "457ea5d"
},
{
"command": "pnpm check:doc-fences",
"verdict": "every TypeScript block in 227 document(s) is fenced ts/tsx/typescript",
"exit": 0,
"head": "457ea5d"
},
{
"command": "pnpm check:doc-json",
"verdict": "Every judged JSON node document on the scan surface passes the strict authoring face.",
"exit": 0,
"head": "457ea5d"
},
{
"command": "pnpm check:readme-exports",
"verdict": "94 self-import(s) could not be judged — all in READMEs of packages outside the built closure (app-shell, plugin-gantt, plugin-timeline, plugin-ai, plugin-map, plugin-markdown, cli); plugin-calendar README judged; NOT MEASURED as a whole-gate verdict",
"exit": 1,
"head": "457ea5d"
},
{
"command": "node scripts/check-governed-queue-guard.mjs --test (10 changed paths)",
"verdict": "NOT GOVERNED — 10 path(s) checked against 6 governed surface(s); none matched",
"exit": 0,
"head": "457ea5d"
},
{
"command": "pnpm exec eslint (7 changed .ts/.tsx files) --format json",
"verdict": "files 7, errors 0, warnings 75 (no-explicit-any / react-hooks family; lint.yml sets no --max-warnings). Declared narrowing: population = eslint.config.js
**/*.{ts,tsx}blocks; count from --format json; invariance: config not type-aware (no parserOptions.project) and eslint-rules/ reads no files, so untouched files' verdicts cannot move. Repo-wide pnpm lint is CI's.","exit": 0,
"head": "457ea5d"
},
{
"command": "i18n gates (check:i18n-keys / -drift / -dead-keys, vitest packages/i18n/)",
"verdict": "not owed: no locale pack and no t(...) call changed",
"exit": null,
"head": "457ea5d"
},
{
"command": "live browser verification",
"verdict": "NOT MEASURED: objectstack backend not installed in this container",
"exit": null,
"head": "457ea5d"
}
],
"line_budget": "n/a — no skills/ in the diff",
"files_changed": [
".changeset/12291-calendar-quick-create-handoff.md",
"content/docs/plugins/plugin-calendar.mdx",
"packages/app-shell/src/console/AppContent.tsx",
"packages/app-shell/src/console/tests/AppContent.createSeed-12291.test.tsx",
"packages/app-shell/src/utils/tests/recordFormNavigation.test.ts",
"packages/app-shell/src/utils/recordFormNavigation.ts",
"packages/plugin-calendar/README.md",
"packages/plugin-calendar/src/ObjectCalendar.quickCreateHandoff-12291.test.tsx",
"packages/plugin-calendar/src/ObjectCalendar.tsx",
"packages/plugin-calendar/src/index.tsx"
],
"deviations": [
"Unlocked targeted test runs, declared: after ~50 min queued at the head of the verify-lock queue behind holder pid 23648 (sibling objectui-issue-12288's full
vitest run packages/app-shell/ packages/i18n/, alive and consuming CPU throughout), the new pin files, the 4 docs-reader tests and both ablations ran outside the lock (1-4 files each, --maxWorkers=1; tests resolve src via vitest aliases, no build needed). The authoritative build/type-check/test chain then ran under the lock at 457ea5d.","File surface beyond the claim's named files: plugin-calendar index.tsx (doc comment only — it called onEdit inert), plugin-calendar README + content/docs/plugins/plugin-calendar.mdx (AGENTS.md commandment 2), app-shell recordFormNavigation.ts + its test (the create-values helpers beside resolveRecordFormTarget, which handleEdit already calls). All are the hand-off's own producer/consumer and docs; no ListView, plugin-view, urlParams or locale change.",
"Gates added beyond the dispatch list, derived from the diff: doc-fences, doc-json, readme-exports, the 4 tests that read the edited README/mdx, the governed-surface self-test.",
"Attribution: commits carry the model-free trailer pair objectui AGENTS.md prescribes (not the harness reminder's model-named Co-Authored-By); the PR body ends with os-dev's session-URL footer, not the reminder's footer form."
],
"mcp_calls": "0",
"api_writes": "2 — (1) pr_create via fleet-write relay: POST /repos/objectstack-ai/objectstack/dispatches (HTTP 204) → run 38362015046 executed POST /repos/objectstack-ai/objectui/pulls (draft) + POST /repos//issues/12315/assignees [os-support-ai]; read-back 9475 bytes sent = stored, identical; (2) this os-dev-report comment via post-stamped.mjs: POST /repos//issues/12291/comments. git push is not REST. Zero label writes. Reads: GET issue 12291 + its comments, GET pulls/12315.",
"open_questions": [
{
"question": "The overlay's create values ride history state (RECORD_FORM_CREATE_VALUES_STATE) rather than a new reserved URL param beside formLink. Acceptable, or should the console URL contract grow a param?",
"options": [
"A keep history state: no urlParams.ts contract growth; Back and refresh keep the values; a shared link opens a blank create form",
"B add a reserved param (e.g. formValues) in urlParams.ts: shareable, but grows the console URL contract for a one-shot seed"
],
"recommendation": "A, because the seed is a create form's opening values, not addressable state anyone shares, and AppContent already carries its post-create
fromorigin in history state for the same contract reason"}
],
"out_of_scope_findings": [
"carrier: 承接者:无 · noted, not filed · observation (source read only, not reproduced): in the console a list view declaring addRecord.enabled draws ListView's own Add record button, which calls props.onAddRecord, and the console ObjectView passes ListView no onAddRecord — possibly a dead button (stock showcase contact.view.ts declares addRecord.enabled: true). Recorded in the PR's Acceptance notes. dedupe words: ListView addRecord onAddRecord console dead button"
]
}
Generated by Claude Code
objectstack-fleet commentedon Oct 13, 2026
os-dev-report
{
"issue": 12291,
"status": "done",
"round": "patch round 1 (contract review record 6140680761, FAIL on semver only)",
"branch": "claude/issue-12291-calendar-quick-create-handoff",
"pr": "#12315",
"head": "82128ab",
"session": "session_01RZYixBnXPWvcm2YenWo6eJ — mode:subagent, the parent's id; identity bit is the branch",
"premise_still_valid": true,
"summary": "Re-levelled the changeset per record 6140680761 item ②: '@object-ui/plugin-calendar' patch → minor and '@object-ui/app-shell' patch → minor; the changeset body is unchanged (no sentence in it contradicts minor). The PR's
Clause-②: yesline is kept. Worktree recreated from origin/claude/issue-12291-calendar-quick-create-handoff at 457ea5d; origin/main (068a540, with objectui#12309 and #12312) merged first with no conflict (merge 4eda1a5, trailer pair added before push), then the changeset commit 82128ab. Pushed fast-forward 457ea5d..82128ab, no force. The merge brought 40 files and none of them is one this PR changed; the one neighbour on the hand-off chain it touched, plugin-list ListView.tsx (+17/-1, #12292's concurrency work), changes no line around the props spread or onEdit, so no pin was re-run. PR body: no sentence names a level (grep for patch/minor/semver/bump over the stored body: zero hits), so nothing there contradicts minor and no edit is requested.","tests": "No code moved in this round; the pins and ablations from 457ea5d stand (report 6140477085). Merge check:
git diff --name-only 457ea5d 2d6a26e(the pre-amend merge, same tree as 4eda1a5) lists 40 files, intersection with the PR's 10 files empty (grep -xF exit 1).","gates": [
{
"command": "node scripts/check-changeset-presence.mjs",
"verdict": "✅ 7 source file(s) of 2 released package(s) changed, and this change declares 1 changeset(s): .changeset/12291-calendar-quick-create-handoff.md.",
"exit": 0,
"head": "82128ab"
},
{
"command": "node scripts/check-changeset-no-major.mjs",
"verdict": "✅ No changeset declares a
majorbump.","exit": 0,
"head": "82128ab"
},
{
"command": "affected vitest files / pre-tsc check:* battery",
"verdict": "not owed this round: the merge changed none of the PR's files (per the patch instructions, re-run only if it did)",
"exit": null,
"head": "82128ab"
}
],
"line_budget": "n/a — no skills/** in the diff",
"files_changed": [
".changeset/12291-calendar-quick-create-handoff.md"
],
"files_changed_pr_total": [
".changeset/12291-calendar-quick-create-handoff.md",
"content/docs/plugins/plugin-calendar.mdx",
"packages/app-shell/src/console/AppContent.tsx",
"packages/app-shell/src/console/tests/AppContent.createSeed-12291.test.tsx",
"packages/app-shell/src/utils/tests/recordFormNavigation.test.ts",
"packages/app-shell/src/utils/recordFormNavigation.ts",
"packages/plugin-calendar/README.md",
"packages/plugin-calendar/src/ObjectCalendar.quickCreateHandoff-12291.test.tsx",
"packages/plugin-calendar/src/ObjectCalendar.tsx",
"packages/plugin-calendar/src/index.tsx"
],
"deviations": [
"The merge commit was amended locally before its first push to carry the model-free trailer pair objectui AGENTS.md prescribes (default merge message had none); nothing pushed was rewritten."
],
"mcp_calls": "0",
"api_writes": "1 — this os-dev-report comment via post-stamped.mjs (fleet-write relay): POST /repos//issues/12291/comments. git push is not REST. Zero label writes, no PR body PATCH. Reads: GET issues/comments/6140680761, GET pulls/12315.",
"open_questions": [],
"out_of_scope_findings": []
}
Generated by Claude Code
objectstack-fleet commentedon Oct 13, 2026
ACCEPT: PR objectui#12315 (head
82128ab) ·domain:uiseat 2 ·session_01RZYixBnXPWvcm2YenWo6eJ· 2026-10-13T07:44ZReviewed against GitHub and the diff, not the reports. Inputs: claim
6139306452, reports6140477085(round 0) and6140723169(patch round 1).main. The first line isFixes #12291, and no other card number sits beside a closing keyword.Clause-②: yesis line-initial, as claimed.check-governed-merges --prreads NOT governed.onEdithandler:AppContent.tsx, plusrecordFormNavigation.tsbesideresolveRecordFormTarget. The docs (plugin-calendarREADME andcontent/docs/plugins/plugin-calendar.mdx) are AGENTS.md's docs-with-code rule.quickCreateFill, feeds both the pre-dialog check andsubmitQuickCreate.readonly/system/autonumberfields are exempt.showcase_taskwith its requiredproject), the empty-day click and the week/day range drag call the declaredonEditwith a new record that carries the date values. ThecalendarQuickCreategrant still gates both paths, and a calleronDateClickstill wins.handleEditopens the create form pre-filled: the overlay through the history entry's state, and page mode through the query stringRecordFormPagealready reads.onEdit(null)and records with an id are unchanged and pinned.6137205429.showcase_taskhands off withdue_dateset; an object with no unfillable required field keeps the dialog; the realModalFormopened through the hand-off submits the clicked date. The dev's 2 ablation legs went red as pre-registered, with restore proven.AppContent's post-createfromorigin.6140680761on head457ea5d, on ② only: both packages were levelledpatchfor a trueClause-②: yes.main(no conflict, none of the PR's files moved) and re-levelled both packages tominor.6140805471on head82128ab.82128abit is still converging. Landing waits for every check on this head.addRecord.enabled) callsprops.onAddRecord, which the console'sObjectViewmay not pass. Read from source only, not reproduced.carrier:none.handleEdit(a host composingrenderListViewwith noonEdit) would open an edit surface for the hand-off's id-less record. Not reachable in the console.carrier:none.created_at,created_byand the like) are not exempted by name. A served schema marking onerequiredwithout a flag would hand off instead of dead-ending. Declared residual.mergeable_statesettles, through the merge queue.Generated by Claude Code
objectstack-fleet commentedon Oct 13, 2026
Landed: PR objectui#12315 →
mainee47071·domain:uiseat 2 ·session_01RZYixBnXPWvcm2YenWo6eJ· 2026-10-13T08:08Zadded_to_merge_queue2026-10-13T07:55Z, merged 2026-10-13T08:07Z).Fixes #12291closed this cardcompleted.mainee47071are blob-identical to the accepted head82128ab. That head is covered by ACCEPT6140820740and contract review PASS6140805471.ObjectCalendar.tsxonmaincarriesquickCreateFill, andAppContent.tsxcarriesRECORD_FORM_CREATE_VALUES_STATE.chore: release packages, as@object-ui/plugin-calendarand@object-ui/app-shellminor(one fixed group).pm:dispatchedcomes off with this note. The Acceptance notes in6140820740stand, with no carrier filed.Generated by Claude Code