Skip to content

studio: risky or no-op defaults — New action defaults to sandboxed JS, New hook can target every object incl. sys_* without warning, a new validation rule is created as a no-op #11820

Description

@objectstack-fleet

Filing gate ② — a product decision only the maintainer can make.

Who acts on it: objectui triage → the Studio / app-shell owner. ⛔ Not a claim. Found in a manual browser QA pass of Studio on 2026-10-07; filed one card per finding on the maintainer's word: 「你发现的问题全部提交 issue」, and on the one-card-per-finding question 「覆盖规则,逐条立卡」.

Maintainer quick-read

Three Studio defaults lean risky or produce no-ops. Change them?

Defaults seen

  • New action starts as Script — run an expression / sandboxed JS ("Runs in the sandbox as (input, ctx) => Promise").
  • New hook created from a package object lists All objects (*), every other package's objects and sys_* tables (sys_api_key, sys_approval_token, …) with no warning about reach; events are raw camelCase (beforeInsert, afterUpdateMany, beforeFind).
  • New validation rule: choosing a type immediately autosaves validation_1 with condition false and no Runs on event checked — a rule that never fires.

Options

  • A — action default Update field/Run flow; hook target defaults to the object with a warning for other packages and sys_*; new rule defaults to Create + Update and is not saved until it has a condition.
  • B — only the validation default.
  • C — status quo.

Environment

objectstack 879bd38c · examples/app-showcase booted with objectstack dev --ui --seed-admin on an isolated port and SQLite file · objectui 179f6fe9 (HEAD; the framework pin .objectui-sha is a58626c8) served by the console's Vite dev server, perf numbers from a vite build of the same commit · Chromium 141 at 1440×900 · signed in as the seeded platform admin admin@objectos.ai unless stated.

Duplicate check

Dedupe words: new action default script · hook target all objects sys tables warning · validation rule created no-op false

Filed by Claude Code (session session_01D76mrPJrSSdaKRxR2rvrMG) from that QA pass.


Generated by Claude Code

Activity

  1. added
    enhancementNew feature or request
    domain:uiobjectui ui stream: fix lands on the published library or apps — objectui execution seat
    area:studioChanging a running app without code — authoring, publish, docs and the portal
    on Oct 7, 2026
  2. objectstack-fleet commented on Oct 7, 2026

    @objectstack-fleet
    ContributorAuthor

    Path: write metadata — Studio's new-item defaults | 缺项 | P3

    Triage: first grade, enhancement · priority:p3 · domain:ui · area:studio · pm:queue. Filed as ②, but routed as a Studio UX defect: what Studio offers and saves by default changes no contract. Direction: the body's option A

    Triage seat (objectstack-wide, seat post objectstack-ai/objectstack#6015) · session_01AavokzJ5DndAwitDXvKy4U · 2026-10-07T17:45Z. ⛔ Not a claim, ⛔ not a dispatch.

    Triage: lands in the Studio create flows for actions, hooks and validation rules (studio-design/ObjectValidationsPanel.tsx for rules) ⇒ domain:ui; rationale: a Studio or console surface in objectui. Filed from the browser QA pass of 2026-10-07 (objectstack 879bd38c, objectui 179f6fe9); paths re-read on objectui main 9990f9e122.

    • Why not the decision box: these are Studio defaults; no server rule changes. Why p3: a no-op rule is saved, and a broad hook target is offered without a word.
    • Direction:
      • a new validation rule is not saved until it has a condition, and starts with Create + Update checked
      • a new hook targets the current object; other packages' objects and platform objects sit in their own group with a warning about reach
      • a new action defaults to a declarative type
    • ⛔ This card changes only what Studio offers and says. Whether the server binds an authored hook to a platform object is not measured here, and it is a security boundary, so it is the maintainer's. carrier: the claimant reads that path and reports in Acceptance notes; triage routes what it finds.
    • Clause-②: no. Patch changeset in objectui.
  3. objectstack-fleet commented on Oct 8, 2026

    @objectstack-fleet
    ContributorAuthor

    Claim: PM loop round 3
    Session: session_01CGZy1BGCjdN5cXqL9cnvB8
    Account: os-support-ai
    Branch: claude/issue-11820-studio-safe-defaults
    Worktree: objectui-issue-11820
    Domain: domain:ui
    Seat: domain:ui#3
    File surface (on 5e446ab), under packages/app-shell/src/views/:

    • studio-design/ObjectValidationsPanel.tsx: a new rule's defaults (condition: 'false' at about :162–:177) and when a new rule is first saved;
    • studio-design/ObjectHooksPanel.tsx and metadata-admin/inspectors/HookDefaultInspector.tsx: a new hook's target default and the target picker's grouping and warning (ALL_OBJECTS about :69, the toggle about :224);
    • studio-design/ObjectActionsPanel.tsx: a new action's default type (type: 'script' about :170);
    • new engine.studio.* / engine.inspector.hook.* rows of metadata-admin/i18n.ts (en and zh) for the warning and group headings;
    • the tests beside these, and .changeset/11820-*.md.

    ⛔ Not on it: what the server binds or refuses for a hook on a platform object (triage 6043523725: a security boundary, the maintainer's); packages/i18n/**; packages/components/src/ui/**. Any file outside this list: the dev reports it before opening the PR (stop on breach; explain in the report)
    Container & model: M, mode:subagent, model: opus (dispatch-gates --tier --repo objectstack-ai/objectui: no path-derived mandate; default tier)
    Clause-②: no
    Responsibility: objectui app-shell Studio: a new validation rule autosaves as a no-op (condition false, no event), a new hook offers every object including sys_* with no word about reach, and a new action starts as sandboxed JS | the platform path: each panel already owns its create defaults and its picker; only what Studio offers and saves first changes | every author adding a rule, hook or action to an object in Studio
    Thread-read: 6043523725
    Serial constraints cleared: seat 2's objectui#11781 (which touched ObjectValidationsPanel.tsx's read-only look) has landed. No in-flight claim in the lane names these four files, and no open objectui PR touches them (read 2026-10-08T05:27Z).

    Why Clause-②: no: Studio defaults and copy inside @object-ui/app-shell, with rows in the designer's own string table. A published export, prop, type member or language-pack key is a stop: the dev reports it before opening the PR, and the seat amends this line.


    Generated by Claude Code

  4. objectstack-fleet commented on Oct 8, 2026

    @objectstack-fleet
    ContributorAuthor

    os-dev-report
    {
    "issue": 11820,
    "status": "done",
    "branch": "claude/issue-11820-studio-safe-defaults",
    "pr": "#11918",
    "session": "session_01CGZy1BGCjdN5cXqL9cnvB8 — subagent mode, the dispatching seat's id (domain:ui#3, PM loop round 3)",
    "premise_still_valid": true,
    "summary": "Draft PR #11918 (head 54f36e2, Fixes #11820, Clause-② line copied) implements option A in @object-ui/app-shell only, all on the claim's file surface. Validation rules: a new Script/Cross-field/Conditional rule is held in the panel (listed, marked 'Not saved — needs a condition', with the objectui#11786 hold's line and input hint) and written to the draft only once it has a condition (a Conditional also needs its Then rule's); every new rule starts on Create + Update; an existing rule's type switch keeps the valid 'false' placeholder. Hooks: ObjectHooksPanel provides the package's objects (loadPackageSurfaces, published + draft) through a module-internal HookTargetScopeContext, and HookDefaultInspector splits the picker into 'This package' and 'Other objects' (other packages' and sys_* alike) with a reach warning; 'All objects ()' gets one too. Actions: a new action is operation 'update' + patch {} (type left to the spec default), no sandboxed JS. Premise notes: the hook half 'targets the current object' was already true on 5e446ab (addHook seeds object: objectName) and is now pinned; the card's 'no Runs on event checked' rule did run on insert+update (spec default, measured) — its no-op came from condition 'false' alone. Zone 2 #1 measured: the pillar's hold (objectHeldEdit in metadataError.ts, Show-me routing in StudioDesignSurface.tsx, which objectui#11823 step 2 holds) is off this surface, so the panel holds the unsaved rule itself and reuses the hold's wording; stated cost: leaving Rules before a condition drops the rule, and Publish does not wait for it. Zone 2 #3 measured: update_field is not an ActionType; url/flow/modal/api/form are refused without target; operation 'update' + patch {} is the one declarative skeleton that parses. CI at report time: 42 check runs, 21 success, 3 skipped, 18 in_progress, 0 failed (one read, not awaited).",
    "tests": "All on 54f36e2 via os-verify-lock (slot os-dev-11820), from the worktree root. (1) pnpm exec vitest run --maxWorkers=2 packages/app-shell/src/views/studio-design/ — 'Test Files 122 passed (122)', 'Tests 762 passed (762)'. (2) pnpm exec vitest run --maxWorkers=2 packages/app-shell/src/views/metadata-admin/inspectors/ + 12 grep-derived files outside studio-design/ and metadata-admin/inspectors/ (ConditionWidget.conditionSubjects, ResourceEditPage.conditionScope, src/tests/select-placeholder-literal-11252, data-objectstack draft-envelope + metadata-client.get-envelope, 3 packages/i18n key tests, scripts/tests check-doc-component-types / check-i18n-call-site-keys / check-i18n-dead-keys / vite-dts-explicit-extensions) — 'Test Files 155 passed (155)', 'Tests 2394 passed | 1 skipped (2395)' (skip = pre-existing spec-gated skipIf in flow-node-config.spec-reconciliation). Declared narrowing: app-shell has 1133 test files; not run here = the rest of metadata-admin and app-shell, none of which names a changed module or a changed i18n string (git grep); blind spot = a test reaching a changed module only through a registry/barrel without naming it; full pnpm test is CI's. (3) pnpm --filter @object-ui/app-shell type-check ('tsc --noEmit && tsc -p tsconfig.test.json') exit 0 after building the dependency closure (turbo build --filter='@object-ui/app-shell^...' --concurrency=2: 28/28 cached); tsc -p tsconfig.test.json --listFilesOnly lists all 6 changed test files; run on the working tree later committed unchanged as 54f36e2. (4) eslint on the 11 changed .ts/.tsx files: 11 files judged (--format json), 0 errors, 4 warnings (1 new react-refresh/only-export-components on the exported context; 3 pre-existing react-hooks/set-state-in-effect); narrowing proof: population = eslint.config.js over the repo, no type-aware linting configured and no custom eslint-rules/
    reading other files, so the diff cannot move an untouched file's verdict. (5) Ablation via objectstack scripts/ablation-replace.mjs WRAP mode (no build: the pins import the panel from src by relative path): addRule's wait replaced by the old immediate write with condition 'false' — anchor count 1 to 0, blob 21757a5a4e64 to da230345381a, marker grep 1 on disk; ObjectValidationsPanel.newRuleWaits-11820 / .whenKey / .test went red 'Tests 14 failed | 15 passed (29)', all assertions (13 AssertionError, 1 jest-dom toBeChecked), no crash; restore proven: blob after restore 21757a5a4e64 == HEAD blob, git diff HEAD empty. Direction observed: red (as expected).",
    "mcp_calls": "0",
    "api_writes": "3 REST writes through the fleet relay (objectstack-fleet[bot]): pr_create POST /repos/objectstack-ai/objectui/pulls (draft #11918, read-back 12535 bytes sent == stored); assign POST /repos//issues/11918/assignees os-support-ai (label-write.mjs, read-back MATCHES); comment POST /repos//issues/11820/comments (this os-dev-report). Not REST: git push x2 (empty-branch probe, then 54f36e2). Reads only otherwise (gh api GET of the card, comments, PR, check-runs).",
    "open_questions": [
    {
    "question": "The unsaved-rule hold lives in ObjectValidationsPanel, not in the Data pillar's objectui#11786 hold. Move it onto objectHeldEdit later?",
    "options": [
    "A — keep the panel hold (this PR): no StudioDesignSurface.tsx edit; cost: leaving Rules or the object before a condition drops the rule, and Publish does not wait for it",
    "B — follow-up card: put an empty-guard rule in the draft and extend objectHeldEdit (metadataError.ts) + the held notice's Show-me routing to the Rules view (StudioDesignSurface.tsx): survives view switches and Publish refuses, but holds every other edit of the object while the rule lacks a condition"
    ],
    "recommendation": "A for now, B only if authors report losing unsaved rules: business need — the loss is a rule with no condition yet, which saves nothing anyone runs; long-term — B is the one hold mechanism, but it needs StudioDesignSurface.tsx, which objectui#11823 step 2 holds; AI-error axis — both write nothing the spec refuses; startup focus — A adds no surface beyond this card."
    },
    {
    "question": "The 'What it does' path from the new default back to a script is refused until a language is picked (ActionDefaultInspector, off this surface). File it before this merges?",
    "options": [
    "A — the seat files it as its own card (ActionDefaultInspector.commitOperation seeds no body; patchBody writes no language) and lets this PR land",
    "B — hold this PR until that card lands"
    ],
    "recommendation": "A: the defect predates this PR (any update action switched to script hits it) and picking 'Sandboxed JS (L2)' explicitly gets through today; holding the safe default behind it buys nothing."
    }
    ],
    "out_of_scope_findings": [
    "class: a · reach: named producer — Studio Actions, New (now an update action), 'What it does: Run a script', type a body: ActionDefaultInspector.commitOperation clears operation/patch and seeds no body, patchBody writes { source } without language; ActionSchema refuses the switched action at 'body' ('A script action requires either an inline body … or a target') and, after typing, at 'body.language' ("Invalid discriminator value. Expected 'expression' | 'js'") until a language is picked — measured through the spec's ActionSchema on the shapes those two functions write · this PR makes it the path for every author who wants a script action · dedupe words: action what it does run a script body language refused; commitOperation seeds no body; update action switch to script",
    "class: b · reach: named producer — ObjectValidationsPanel's 'Runs on' row (EVENTS includes 'delete') writes events [..., 'delete']; ObjectSchema.safeParse answers invalid_value at validations.0.events.N ('expected one of "insert"|"update"') · Seam: spec:BASE_VALIDATION_SHAPE.events (enum insert|update, 'delete is intentionally absent') → renderer:ObjectValidationsPanel Runs-on checkboxes · not fixed here: a refused value offered is not this card's no-op-default class · dedupe words: validation rule runs on delete checkbox; events delete refused; studio rules delete event",
    "class: b · reach: named producer — a rule with no 'events' (authored in code or by AI) opened in Studio shows no Runs-on box checked, while ValidationRuleSchema parses it to ['insert','update'] (measured); ticking 'Create' writes ['insert'], narrowing a rule that ran on both · Seam: spec:BASE_VALIDATION_SHAPE.events default → renderer:ObjectValidationsPanel Runs-on checkboxes · dedupe words: runs on checkboxes absent events default; validation events default insert update display",
    "carrier: 承接者:无 · noted, not filed — ConditionBuilder's empty state 'Always — no condition.' renders at the validation guard (a required fail condition) right above the 'Required' hint on a new rule (polish, ConditionBuilder.tsx off this surface)",
    "carrier: 承接者:无 · noted, not filed — hook events are labelled with raw camelCase names (beforeInsert, afterUpdateMany); the designer string table has no label pattern for them, so none was invented (polish, per the dispatch)",
    "carrier: 承接者:无 · noted, not filed — an update action written by the inspector's 'What it does' carries explicit type 'script' (Actions list shows a SCRIPT chip) while the new default leaves type off (no chip); the inspector's disabled Type control still reads 'Script — run an expression / sandboxed JS' on update actions by objectui#7551's design (polish)",
    "security carrier (dispatch Zone 2 #4, read only, not filed; in the PR's Acceptance notes): objectstack main c6fe02d7 — packages/objectql/src/hook-binder.ts bindHooksToEngine registers every authored hook on each object normalizeObjects(hook.object) names, '' included (only an empty target refused); packages/objectql/src/plugin.ts ObjectQLPlugin.readAuthoredHookRows/resyncAuthoredHooksNow read Studio-authored hook rows from sys_metadata across all organizations and bind them under package 'metadata-service'; the only platform-object refusal found is packages/spec/src/data/hook.zod.ts refuseBodyOnStoredMetadataTarget + packages/runtime/src/sandbox/body-runner.ts hookBodyRunnerFactory (storedMetadataBodyHookBindingRefusal) for a body-carrying hook naming sys_metadata/sys_metadata_history; nothing else found refuses sys_, isSystem or another package's objects (hook-wrappers.ts: zero hits for organization/tenant/_packageId/isSystem, control hit in hook-run-as.ts)"
    ],
    "gates": [
    {
    "command": "pnpm exec vitest run --maxWorkers=2 packages/app-shell/src/views/studio-design/ (lock)",
    "exit": 0,
    "verdict": "Test Files 122 passed (122) · Tests 762 passed (762) · os-verify-lock: VERDICT command-exit 0"
    },
    {
    "command": "pnpm exec vitest run --maxWorkers=2 packages/app-shell/src/views/metadata-admin/inspectors/ + 12 grep-derived files (lock)",
    "exit": 0,
    "verdict": "Test Files 155 passed (155) · Tests 2394 passed | 1 skipped (2395) · os-verify-lock: VERDICT command-exit 0"
    },
    {
    "command": "pnpm --filter @object-ui/app-shell type-check (lock)",
    "exit": 0,
    "verdict": "os-verify-lock: VERDICT command-exit 0 (tsc --noEmit && tsc -p tsconfig.test.json)"
    },
    {
    "command": "pnpm --filter @object-ui/app-shell build (lock)",
    "exit": 0,
    "verdict": "os-verify-lock: VERDICT command-exit 0; HookTargetScope only in dist/views/metadata-admin/inspectors/HookDefaultInspector.d.ts, imported by no other .d.ts"
    },
    {
    "command": "pnpm exec eslint (11 changed .ts/.tsx)",
    "exit": 0,
    "verdict": "11 files, 0 errors, 4 warnings"
    },
    {
    "command": "pnpm check:control-bytes",
    "exit": 0,
    "verdict": "check-control-bytes: OK (scanned 7924 tracked text file(s); skipped 85 binary)."
    },
    {
    "command": "pnpm check:test-path-roots",
    "exit": 0,
    "verdict": "check-test-path-roots: OK"
    },
    {
    "command": "pnpm check:changeset-claims (after commit)",
    "exit": 0,
    "verdict": "No pending changeset names a file this change touches."
    },
    {
    "command": "pnpm check:pending-changeset-literals",
    "exit": 0,
    "verdict": "No test source names a pending changeset."
    },
    {
    "command": "pnpm check:i18n-keys",
    "exit": 0,
    "verdict": "Every in-scope call-site key resolves against the en pack"
    },
    {
    "command": "pnpm check:i18n-drift",
    "exit": 0,
    "verdict": "Every changed designer-table en value was followed by its zh row."
    },
    {
    "command": "pnpm check:i18n-dead-keys",
    "exit": 0,
    "verdict": "report-only; none of the added keys listed"
    },
    {
    "command": "pnpm check:i18n-designer-parity",
    "exit": 0,
    "verdict": "Every en row has a zh row, and every shared row carries the same placeholders."
    },
    {
    "command": "pnpm check:new-line-citations",
    "exit": 0,
    "verdict": "VERDICT new-cross-file-line-citations: 0 new citation(s), enforcement report-only → exit 0"
    },
    {
    "command": "pnpm check:action-forward-parity",
    "exit": 0,
    "verdict": "exit 0"
    },
    {
    "command": "pnpm check:designer-field-key-parity",
    "exit": 0,
    "verdict": "designer-field-key-parity: OK"
    },
    {
    "command": "node scripts/check-changeset-presence.mjs",
    "exit": 0,
    "verdict": "11 source file(s) of 1 released package(s) changed, and this change declares 1 changeset(s): .changeset/11820-studio-safe-defaults.md."
    },
    {
    "command": "node scripts/check-changeset-no-major.mjs",
    "exit": 0,
    "verdict": "No changeset declares a major bump."
    },
    {
    "command": "node scripts/check-changeset-fixed.mjs",
    "exit": 0,
    "verdict": "All workspace packages are in the changeset fixed group."
    },
    {
    "command": "node scripts/check-changeset-overwrite.mjs",
    "exit": 0,
    "verdict": "No pre-existing changeset was modified or deleted."
    },
    {
    "command": "pnpm check:readme-exports",
    "exit": 1,
    "verdict": "NOT MEASURED: 73 README imports of packages whose dist/index.d.ts is not built in this worktree (none app-shell); prerequisite not met, and app-shell's exports are unchanged"
    }
    ],
    "deviations": [
    "Zone 2 #1 (reuse the objectui#11786 hold): measured the hold's predicate (objectHeldEdit, metadataError.ts) and Show-me routing (StudioDesignSurface.tsx, held by objectui#11823 step 2) off this surface; the panel holds the unsaved rule itself and reuses the hold's i18n line and input hint. Cost stated in the panel header, PR and changeset.",
    "i18n.ts: besides the 5 new keys (en+zh), the panel's existing rows engine.studio.rules.celMid was reworded and engine.studio.rules.celPost removed (the caption claimed new rules default to false); the claim's line names new rows.",
    "New module-internal exports HookTargetScopeContext / HookTargetScope from HookDefaultInspector.tsx — measured not reached by the built entry (dist/index.d.ts); no claim amendment needed under the dispatch's public-surface definition.",
    "ObjectHooksPanel: the new-hook target default was already the current object on 5e446ab; the change there is the package-scope provider, plus a pin.",
    "Tests narrowed (declared in 'tests'); type-check ran on the bytes later committed unchanged as 54f36e2.",
    "Rewrote ObjectValidationsPanel.test.tsx's case that pinned the 'false' default and whenKeyPin's New-menu cases (they pinned exactly the removed branch)."
    ],
    "files_changed": [
    ".changeset/11820-studio-safe-defaults.md",
    "packages/app-shell/src/views/metadata-admin/i18n.ts",
    "packages/app-shell/src/views/metadata-admin/inspectors/HookDefaultInspector.tsx",
    "packages/app-shell/src/views/metadata-admin/inspectors/HookDefaultInspector.reach-11820.test.tsx",
    "packages/app-shell/src/views/studio-design/ObjectActionsPanel.tsx",
    "packages/app-shell/src/views/studio-design/ObjectActionsPanel.newActionDefault-11820.test.tsx",
    "packages/app-shell/src/views/studio-design/ObjectHooksPanel.tsx",
    "packages/app-shell/src/views/studio-design/ObjectHooksPanel.newHookTarget-11820.test.tsx",
    "packages/app-shell/src/views/studio-design/ObjectValidationsPanel.tsx",
    "packages/app-shell/src/views/studio-design/ObjectValidationsPanel.test.tsx",
    "packages/app-shell/src/views/studio-design/ObjectValidationsPanel.whenKey.test.tsx",
    "packages/app-shell/src/views/studio-design/ObjectValidationsPanel.newRuleWaits-11820.test.tsx"
    ],
    "line_budget": "not applicable (no skills/** surface)",
    "cleanup": "worktree /home/user/objectui-issue-11820 removed (node_modules first, no --force); private ref refs/os-dev-11820/os-main deleted from the objectstack checkout; no dev server or monitor started"
    }


    Generated by Claude Code

  5. objectstack-fleet commented on Oct 8, 2026

    @objectstack-fleet
    ContributorAuthor

    ACCEPT — domain:ui seat 3, session_01CGZy1BGCjdN5cXqL9cnvB8, 2026-10-08T06:44Z. PR objectui#11918, head 54f36e2.

    • PR shape: draft against main, branched from 5e446ab, no rebase. git merge-tree of the current main (a49c4bd) and this head is clean; the queue tests that merge. First line Fixes #11820, no other closing keyword. Clause-②: no at line start. The commit carries only the model-free trailer pair. Assigned to os-support-ai.
    • Scope: 12 files, +950/−92, on the claim's surface (6053007704): the four panels and inspectors, designer rows in i18n.ts, their pins and the changeset (patch on @object-ui/app-shell). A module-internal HookTargetScopeContext is exported from HookDefaultInspector.tsx; the dev measured that the built entry does not reach it. Two existing designer rows were reworded or removed, because their caption claimed new rules default to false. No governed path.
    • Diff read (the seat's own):
      • Rules. New builds the rule with an empty guard and events: ['insert', 'update']. A guarded type (script, cross-field, conditional) with no condition is held in the panel's own unsaved list, marked with objectui#11786's hint, and committed only when missingGuard clears. For a conditional, the Then rule needs its condition too. An existing rule's type switch keeps the valid false placeholder.
      • Hooks. ObjectHooksPanel supplies the package's objects (published and draft). HookDefaultInspector groups the picker into This package and Other objects (other packages' and sys_*), with a reach warning on that group and on All objects (*). A new hook's target is the current object, as it already was; that is now pinned.
      • Actions. A new action is operation: 'update', patch: {}, with no sandboxed JS.
    • Brief readings, measured:
      • Zone 2 Implement visual designer for Object UI schemas #1: the pillar's hold lives in regions this card does not hold, so the panel holds the rule itself and reuses the hold's wording. The stated cost: leaving Rules before a condition drops the rule, and Publish does not wait for it.
      • The card's "no Runs on event" rule did run on insert and update (the spec's default), so its no-op came from condition: 'false' alone.
      • Zone 2 Add public roadmap, VitePress documentation site, and GitHub Pages deployment #3: update_field is not an ActionType, and url, flow, modal, api and form are refused without a target. operation: 'update' with patch: {} is the one declarative skeleton that parses.
    • The dev's open questions:
    • Security carrier (triage 6043523725): the dev read objectstack main c6fe02d7. hook-binder.ts's bindHooksToEngine registers an authored hook on every object its target names, * included. ObjectQLPlugin reads Studio-authored hook rows from sys_metadata across all organizations. The only platform-object refusal found is the stored-metadata body-hook guard (sys_metadata / sys_metadata_history). Nothing else refuses sys_* or another package's objects. This is in the PR's Acceptance notes for triage to route. ⛔ This seat changes nothing there: it is the maintainer's boundary.
    • Ruling honoured (triage 6043523725, option A): a new rule is not saved until it has a condition and starts on Create + Update; a hook's target defaults to the current object, with other packages' and platform objects grouped behind a warning; an action defaults to a declarative type.
    • Reverse verification (dev report):
      • Ablation through ablation-replace.mjs (the rule written at once with condition: 'false'): 14 red across the three rule pin files. Restored with the blob equal to HEAD.
      • studio-design/: 122 files, 762 tests passed. metadata-admin/inspectors/ plus 12 derived files: 2394 tests passed.
      • The type-check exited 0.
    • Gates: CI on 54f36e2 (head_sha equals the PR head): 43 runs, 40 success, 3 skipped (Test (coverage), its shard template, dependabot), 0 failure. Lint and Type Check are success. Mergeable state clean.
    • Contract review: not required (Clause-②: no).

    Findings:

    Landing: ready + auto-merge through the queue, now.


    Generated by Claude Code

  6. objectstack-fleet commented on Oct 8, 2026

    @objectstack-fleet
    ContributorAuthor

    Landed — domain:ui seat 3, session_01CGZy1BGCjdN5cXqL9cnvB8, 2026-10-08T07:03Z. PR objectui#11918 merged through the queue as b4693b7 at 2026-10-08T07:02Z.


    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:studioChanging a running app without code — authoring, publish, docs and the portaldomain:uiobjectui ui stream: fix lands on the published library or apps — objectui execution seatenhancementNew feature or requestpriority:p3

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions