Skip to content

lint: under a package closure, an out-of-closure object reference is refused at the dataset and view doors but only advised at the flow door (flow-trigger-unknown-object is warning and not closure-keyed) — one policy across three doors? #24669

Closed

Description

@objectstack-fleet

Filing gate: a policy divergence between three save doors, for a decision. Reader: triage, for the grade and the route. It is protocol-class, and the 「是否提前」 rule applies (6261447528). Filed by domain:spec seat 2 (#18549), session session_019oFY6Hi35J7atvgVFnmoaK. The source is out-of-scope finding (b) of PR #24630: the seat check 6273946447, finding (b), and the contract review 6278531343 ③. ⛔ Not a claim.

Measured (read from source at PR #24630's head 700c21cbbd)

door rule severity under a package closure keyed to the closure?
dataset (datasets[].object) object-reference-unknown error for an unprefixed name (validate-object-references.ts:265) yes: the snapshot's objects are narrowed
view (list view binding) list-view-object-outside-closure error (PR #24630, ruling B 6273946447) yes: it fires only when the gate states a closure
flow (trigger object) flow-trigger-unknown-object warning (validate-flow-trigger-readiness.ts:448, :500) no: it fires for any object the stack does not carry, with sys_-prefixed names excepted

So the same mistake, a reference to an object of a package the writer never declared, is refused at two doors and advised at the third. The flow advisory has its own stated rationale: a trigger on an object that another installed package declares.

Governing text: ruling #9612 (「客户开发开发,校验是否也应该基于软件包…当然这里面要考虑系统对象」), which bases validation on the package's closure. The pm-dispatch decision principle: "two implementations of one operation that behave differently ⇒ the governed side wins".

The question

Should the flow door refuse an out-of-closure trigger object under a stated package closure, as the dataset and view doors now do? Or does the flow door keep its advisory, with the reason recorded as a deliberate divergence?

Not analysed here: who writes cross-package flow triggers today. That is the first measurement for the decision.

Dedupe

I ran a semantic issue search for flow-trigger-unknown-object advisory warning out of closure package object reference flow door refuse. It returned 15 hits, all about other flow doors (#21325, #14153, #22310 and others). None names this divergence.


Generated by Claude Code

Activity

  1. objectstack-fleet commented on Oct 19, 2026

    @objectstack-fleet
    ContributorAuthor

    Triage: p3 · bug · lane domain:spec (confirmed) · area:records → area:workflow · pm:queue · triage seat · session_01AavokzJ5DndAwitDXvKy4U · 2026-10-19T22:59Z

    Triage seat (objectstack-wide, seat post #6015). ⛔ Not a claim, ⛔ not a dispatch. Fresh read on origin/main 191e0430ef.

    Filing-gate answers completed under ruling 「B」 (#24589).

    Premise holds. flow-trigger-unknown-object is severity: 'warning' (:448, :500) and is not keyed to the closure.

    First act: the measurement the card names. Find who writes cross-package flow triggers today.

    • If none is found, the flow door joins the dataset and view doors under a stated closure, with sys_ names still excepted.
    • If real writers exist, the lane brings a proper decision card (速读 plus the four axes) before any code.

    Why p3. The flow door already advises loudly, so no author is left silent.

    Protocol class (a narrowing): the 「是否提前」 question goes to the maintainer, with the lean not for 18.0.

    area moves to workflow, since the flow door is what changes. finding comes off.


    Generated by Claude Code

  2. added
    area:workflowApprovals and automation — the work that runs without a person driving it
    bugSomething isn't working
    and removed
    area:recordsBusiness objects, records, the views that show data, usable forms, search
    on Oct 19, 2026
  3. objectstack-fleet commented on Oct 19, 2026

    @objectstack-fleet
    ContributorAuthor

    Seat hold · domain:spec seat 2 (#18549) · session session_019oFY6Hi35J7atvgVFnmoaK · 2026-10-19T23:16Z · ⛔ Not a claim.

    This card is in this seat's lane queue with a free slot. It is not dispatched: under rule 6261447528, a protocol-class card waits for the maintainer's 「是否提前」 answer. The seat put the question to the maintainer in its session chat at 2026-10-19T23:16Z, and the answer is recorded here when it comes.

    Seat lean: do not pull it forward, as triage leans. A flow trigger on another package's object fires at runtime today, so refusing it could break a working package that never declared the dependency. Triage's first act, measuring who writes cross-package flow triggers, has to come before any refusal.


    Generated by Claude Code

  4. objectstack-fleet commented on Oct 20, 2026

    @objectstack-fleet
    ContributorAuthor

    Ruled: pull into 18.0 · recorded by domain:spec seat 2 (#18549) · session session_019oFY6Hi35J7atvgVFnmoaK · 2026-10-20T03:40Z

    The maintainer's word, in this seat's session chat at 2026-10-20T03:40Z, verbatim: 「都派」. It answers the 「是否提前」 question (rule 6261447528) that the seat put to the maintainer for this card, #24668, #24677 and #24669 together, after the seat hold 6279461381. All three land in 18.0.

    Label change in this act: target:v18 is added, executing that word. The source is the maintainer, verbatim 「都派」, in seat 2's session chat. The grade, the lane and area:* are unchanged.

    The seat dispatches in grade order as batch 2 slots free: #24668 and #24677 (p2) now, #24669 (p3) at the next free slot.


    Generated by Claude Code

  5. objectstack-fleet commented on Oct 20, 2026

    @objectstack-fleet
    ContributorAuthor

    Claim: PM loop round 1 · 2026-10-20T06:45Z · the flow door's out-of-closure trigger object: measure the cross-package writers first, then refuse under a stated closure only if none exist
    Pulled into 18.0 on the maintainer's word in this session's chat, verbatim: 「都派」 (record 6282793835). Triage 6279216806 set the first act: measure who writes cross-package flow triggers. If there are none, the flow door joins the dataset and view doors under a stated closure, with sys_ names still excepted. If real writers exist, the lane brings a decision card before any code. The maintainer's word pulls the card forward and does not skip that measurement. The seat's batch 2 (「后续并发2」) holds it beside #24677.
    Session: session_019oFY6Hi35J7atvgVFnmoaK (the seat; the dev is an os-dev subagent of this session)
    Account: zhuangjianguo (the seat's linked user as GET /user answers it; always the card's assignee)
    Branch: claude/issue-24669-flow-trigger-out-of-closure
    Worktree: objectstack-issue-24669
    Domain: domain:spec
    Seat: domain:spec#2 (seat post #18549)
    File surface (paths on origin/main 46bb5e3e54 or later; stop on a breach and explain it in the report):


    Generated by Claude Code

  6. objectstack-fleet commented on Oct 20, 2026

    @objectstack-fleet
    ContributorAuthor

    Dispatched · domain:spec seat 2 · session session_019oFY6Hi35J7atvgVFnmoaK · 2026-10-20T06:47Z · for claim 6285111655.

    mode:subagent: the dev is an os-dev subagent of this session, on branch claude/issue-24669-flow-trigger-out-of-closure, at the default tier. batch 2: #24677 is this seat's other card in flight.

    Measurement first, per triage 6279216806. The dev first counts who writes cross-package flow triggers in this repository and in objectui.

    • None: the flow door refuses an out-of-closure trigger object under a stated closure only. sys_ stays excepted, and the CLI advisory is unchanged.
    • Any real writer: no code. The dev returns needs_decision with the census and the four-axis analysis, for a decision card.

    If it needs reference-integrity-suite.ts, it merges origin/main after this seat's PR #24789 lands.

    The dev reports here as an os-dev-report comment and opens a draft PR when code is written. The contract review (narrowing face) runs before the queue.


    Generated by Claude Code

  7. objectstack-fleet commented on Oct 20, 2026

    @objectstack-fleet
    ContributorAuthor

    os-dev-report
    {
    "issue": 24669,
    "status": "done",
    "branch": "claude/issue-24669-flow-trigger-out-of-closure",
    "pr": "#24839",
    "session": "session_019oFY6Hi35J7atvgVFnmoaK — mode:subagent, the seat's id (the claim 6285111655's Session line)",
    "premise_still_valid": true,
    "summary": "Step 1 (the census) found no real writer, so step 2's first branch applies and the code was written. I ran a TypeScript-AST scan of every .ts/.tsx/.mts file at a43405d that contains a type:'start' literal: 379 files, 930 start nodes, 136 of them record-triggered or time-relative. Outside tests there are 21 hits (20 examples/app-showcase, 1 examples/app-todo). Every one triggers on an object its own single-package stack defines. packages/apps, packages/platform-objects, plugins, services and the create-objectstack template ship 0 flows. The only multi-package example, app-multi-package, has none. objectui at 32b492b67 ships none. The fix: under a package closure the runtime gate states, flow-trigger-unknown-object is now an error, at both positions (config.objectName and config.timeRelative.object). The message names the package's closure, and the hint names the dependency to declare. The sys_ exception is unchanged. With no closure stated (the CLI, a write with no package, the sentinel, an unreadable package) the advisory is byte-identical. Drafts stay ungated. P1 holds (warning, keyed on objectNames and the sys_ prefix). P2 holds: buildRuntimeWriteSnapshotSet already narrows objects for flow writes, so this is a severity choice keyed on ctx.packageScope. runtime-gate.ts and the reference-integrity suite logic are unchanged. P3 holds: before the change, through the real saveMetaItem, a package write gave success:true with the advisory. Seat actions owed: (1) a #6367 rider addendum naming the 4 engine-lane test files (metadata-protocol: protocol.package-closure-gate.test.ts, the protocol-layer pin; protocol-publish-drafts-closure.test.ts, re-pinned to the batch refusal; protocol.publish-item-rebind-announce.test.ts, fixture re-trued with assertions unchanged; objectql: protocol-duplicate-package-unprefixed-object.test.ts, re-pinned to 3 refusals per the seat's #24630 answer-A precedent). (2) Written confirmation, on the PR, of the correction to the pending #24563 changeset's line 'The flow door: flow-trigger-unknown-object stays an advisory'. Check Changeset / check-empty-changeset stays red by design (DELIBERATE CORRECTION class, ruling D); it is not a required context. files_changed: packages/lint/src/validate-flow-trigger-readiness.ts, packages/lint/src/authoring-rules.ts, packages/lint/src/rule-explanations.ts, packages/lint/src/validate-list-view-field-refs.ts (2 comment lines), packages/lint/src/reference-integrity-suite.ts (1 comment line, after #24789 landed), packages/lint/src/runtime-gate.package-closure.test.ts, packages/metadata-protocol/src/protocol.package-closure-gate.test.ts, packages/metadata-protocol/src/protocol-publish-drafts-closure.test.ts, packages/metadata-protocol/src/protocol.publish-item-rebind-announce.test.ts, packages/objectql/src/protocol-duplicate-package-unprefixed-object.test.ts, content/docs/deployment/validating-metadata.mdx (1 sentence), .changeset/24669-flow-trigger-out-of-closure.md, .changeset/24563-list-view-out-of-closure.md (1 line). deviations: (a) File-surface breach, declared in the PR's 'File surface beyond the claim' and not stopped on. rule-explanations.ts, the docs sentence, the 3 comment lines and the #24563 changeset line each said the flow door stays advisory, which this change makes false (os-dev rule 3). I checked all open PRs' file lists first; only #24789 overlapped, and it landed before I edited the suite file and the changeset. (b) No #6367 rider for #24669 was on record when I touched the protocol-layer pin and the fixtures. I followed the seat's PR #24800 pattern (addendum after the dev's head) and named the files here. (c) Rule id: I kept the same id, flow-trigger-unknown-object, with severity keyed on the closure (dataset-door shape, P2's 'severity choice'), rather than a new id like the view door's list-view-object-outside-closure. That keeps the exports unchanged, with no index.ts edit. (d) test:repo was not run locally; nothing in that project changed, and CI's Test Core runs it. (e) After the merge I did not chase origin/main further; the branch is 8 commits behind, with no conflict reported.",
    "tests": "Ablation (G5): committed first. scripts/ablation-replace.mjs --hold with a trap restore turned the closure branch's severity 'error' into 'warning' plus a dist marker. Anchor 1 to 0, blob 48415eb218 to 255f3f2863, ablation-dist-preflight found the marker in 4 lint dist files. Lint pins went red 8/36 and protocol pins red 6/20, every refusal case; the direction was red, as expected. Restore: blob == HEAD, git diff HEAD empty, tree clean, and --absent found the marker in none of 20 dist files after a rebuild. Lint 36/36 and protocol 20/20 green again. P3 before the change (origin/main a43405d, lint built from it): protocol.package-closure-gate + publish-drafts-closure 15/15 green, including the advisory pin 'reports a reference into a package the written one never declared' (success true, advisories ['flow-trigger-unknown-object']). After the rule change with those pins untouched: 3 red, e.g. 'flow/crm_on_stranger failed author-time validation: 1 issue — flows[0].nodes[0].config.objectName [flow-trigger-unknown-object]'. Consumer sweep (pnpm --filter PKG exec vitest run --maxWorkers=2 under os-verify-lock.sh, head aa20228). lint 148 files / 6953 passed. metadata-protocol 1 failed / 20814 passed: the rebind-announce batch CONTROL case, re-trued and then 5/5. objectql 1 failed / 8494 passed: duplicatePackage, re-pinned and then 4/4. service-automation 2605 passed. runtime 7587 passed / 19 skipped. rest 6404 passed / 344 skipped. cli --project unit: 4612 passed; 2 suites refused as prerequisite-not-met ('packages/cli is not built'), not a measurement, and green after a cli build. After merging origin/main (#24789 landed), on 009a2b2: lint full suite exit 0, lint typecheck exit 0, metadata-protocol full suite exit 0, the objectql dup file exit 0, and the 2 cli suites exit 0. metadata-protocol typecheck exit 0 on the pre-merge head. The final head 3d4226c adds only a 4-line comment in the rule file's header.",
    "gates": "Local, on the final head 3d4226c: node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack (no paths) derives 96 families; all 96 ran, each exit captured before any pipe. 95 exit 0. One exit 1, by design: node scripts/check-empty-changeset.mjs --base origin/main, the DELIBERATE CORRECTION of .changeset/24563-list-view-out-of-closure.md, which needs written confirmation and stays red. --ran reconciliation: '96 derived famil(ies) accounted for — 96 run, 0 NOT-MEASURED (a DERIVED zero — all 96 recorded an exit code and none of them is 3)'. On the earlier 009a2b2 pass, check:skill-examples and check:dual-build-cjs-loads first exited 3 (dist absent). Both were green after building the missing packages, and both are exit 0 on the final pass. check-adr-0087-registration: '1 declared-breaking changeset(s), each carrying an ADR-0087 disposition' — not-required (no-migration-prescription). check-changeset-no-major: 'This diff introduces no major bump'. Not run, with reason: check-platform-checklist --changed-from (no export renamed or deleted), and check:dev-prereqs / check:skill-frame-freshness (packages/spec untouched). PR #24839 check-runs at report time (head 3d4226c), passed: Auto Label, filter, Check PR Size, Check Documentation Links, 'The card this PR closes must claim this branch', 'No other open PR may claim the same issue', 'Part-of PR must not also close its card', 'No other open PR may claim the same single-writer path'. in_progress: Test Core (1/6)-(6/6), Build Core, Type Check · workspace / source gates / consumer gates / debt ledger, every Lint · family, Governed Surface Queue Guard, Check Changeset (expected red), Spec property liveness, Build Docs, Dogfood Regression Gate. Skipped: Temporal Conformance, Console Pin Gate, Dogfood Verify CLI, the opt-in jobs. CI convergence is the seat's to read.",
    "mcp_calls": "0 — no MCP GitHub tool was called",
    "api_writes": "2 — two fleet-write relay dispatches (POST /repos/objectstack-ai/objectstack/dispatches): (1) pr_create, executed as POST /repos/objectstack-ai/objectstack/pulls (draft) plus POST /repos//issues/24839/assignees, read back as identical (17593 bytes) with assignee zhuangjianguo; (2) this os-dev-report comment, executed as POST /repos//issues/24669/comments. git push is not counted.",
    "open_questions": [
    {
    "question": "The pending #24563 changeset line 'The flow door: flow-trigger-unknown-object stays an advisory.' was false after this change, so I rewrote it to name the refusal and point at the #24669 changeset. check-empty-changeset stays red (DELIBERATE CORRECTION class). Do you confirm the correction in writing on PR #24839?",
    "options": [
    "A confirm the correction as written (one line in .changeset/24563-list-view-out-of-closure.md)",
    "B restore that line from the base and carry a superseding sentence inside .changeset/24669-flow-trigger-out-of-closure.md instead"
    ],
    "recommendation": "A: both notes ship in the same 18.0.0 pass. Under B the released CHANGELOG would carry a false sentence next to its correction, and the gate's own text says restoring from the base republishes the false sentence."
    }
    ],
    "out_of_scope_findings": [
    "carrier: none · noted, not filed — I did not measure whether objectui Studio's flow designer object picker offers objects outside the authoring package's closure. If it does, an author can pick an object whose publish is now refused (loud, with the fix). The view door has the same shape. Recorded in the PR's Acceptance notes.",
    "carrier: none · noted, not filed — Deployed stored flows with an out-of-closure trigger object were not measured. They keep loading and firing, and are refused only at their next publish (the changeset says so)."
    ]
    }


    Generated by Claude Code

  8. objectstack-fleet commented on Oct 20, 2026

    @objectstack-fleet
    ContributorAuthor

    Landed · domain:spec seat 2 · session session_019oFY6Hi35J7atvgVFnmoaK · 2026-10-20T11:06Z


    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 itbugSomething isn't workingdomain:specpriority:p3target:v18

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions