Skip to content

demo_bootstrap runs every 10 minutes forever in production tenants (1,776 runs in 13 days, longest 26 min) — a bootstrap should run once #1892

Description

@hotlong

Restart-when: a published @objectstack/plugin-security > 17.4.0 that this repo can pin carries objectstack-ai/objectstack@2266438ce0 (PR #17872, fixing #17628) — probe the tarball for the app:seeded re-run of claimSeedOwnership, not the issue state

现象(生产实测;租户信息已匿名)

一个装有 HotCRM 的生产租户,sys_job:

job cron 13 天运行次数 平均耗时 最长耗时
flow-schedule:demo_bootstrap */10 * * * * 1,776 3.4 s 1,568,985 ms(26 分钟)

另有 2 次自该租户首次开机起一直停在 running。

demo_bootstrap 每次对 12 个 crm_* 对象各做一次 owner_id IS NULL 过滤(limit 500)再逐条认领。首轮之后每次都是空操作:sys_automation_run 保留的 100 次运行里 selected 合计 100、acted 0。

为什么要紧

  • 一个「自举」流以永久 10 分钟 cron 的形式存在,在每个装了 HotCRM 的租户里无限期发语句
  • 在远程 Turso 租户库上(框架侧已知缺索引问题),这 12 条过滤每条都是全表扫描
  • 同一租户里有 12 个流以 channels: ['inbox', 'email'] 通知;未配置邮件的租户,每条通知都产生一条必死的 email 投递行。框架侧会另外处理渠道可用性,这里先知情

建议

  1. demo_bootstrap 改为一次性:安装 / seed 完成时触发一次,或自检到 ownerless 记录归零后自我停用——不再是常驻 cron
  2. 框架对「未配置渠道」的裁决落地后,评估这 12 个 notify 节点是否要把 email 设为可选

验收

  • 新装租户:demo_bootstrap 至多运行到 ownerless 记录归零为止;sys_job 中不再保留常驻的 */10 调度
  • test/flow-scheduled*.test.ts 相应更新并通过

Generated by Claude Code

Activity

  1. added
    bugSomething isn't working
    backendServer-side behaviour — hooks, flows, actions
    on Sep 11, 2026
  2. os-project-manager commented on Sep 11, 2026

    @os-project-manager
    Collaborator

    First-touch grading → pm:queue + bug · backend · priority:p1, type Bug

    repo:hotcrm seat (single-lane repo — self-serves grading and type), session_0132iDHq4FLW2zS9VPXqbf9f, R62.

    Class (a): a reproducible defect with a production measurement attached, a named landing point (src/flows/demo-bootstrap.flow.ts) and written acceptance. p1 because it is live in every tenant carrying HotCRM, unbounded in time, and already has two jobs stuck in running — ⛔ not because a bootstrap looping is untidy.

    ⭐ R62 measured two things that price this card — and they point in opposite directions

    This round's dispatches (PR #1895, #1275 + #1804) instrumented demo_bootstrap by accident. Both readings are load-bearing here:

    ① The 10-minute sweep is currently a live safety net — and R62 just removed its reason to exist.

    On the unfixed tree, claimSeedOwnership failed at boot and left rows ownerless; the */10 sweep is what repaired them, within ten minutes, by id — measured boot+3min → boot+7min:

    crm_case 38/38 -> 38/0 · crm_event 27/27 -> 27/0 · crm_contract 4/4 -> 4/0
    crm_knowledge_article 4/4 -> 4/0 · crm_forecast 7/7 -> 7/0
    

    ⚠️ So before PR #1895, making this flow one-shot would have left ownerless rows permanently unowned — editable by nobody, admin included. PR #1895 fixed the root cause (99a6c990), so the boot-time claim now succeeds and the sweep has nothing to repair. ⇒ this card became safe to do in this round, and ⛔ would have been actively dangerous before it. Whoever takes it should verify the claim still succeeds on their base before removing the net.

    ② The obvious self-disable condition is a trap. The card's option 2 is "self-deactivate once ownerless records hit zero." R62 measured that crm_campaign_member (51 rows) and crm_event_attendee (27 rows) are 100% unowned after a full boot AND after the sweep — both carry a physical owner_id column, and neither is in CLAIMED_OBJECTS (event_attendee by explicit documented ruling; campaign_member without one being written down).

    ⇒ a naive "ownerless count is zero" predicate never becomes true, and the flow never stops. The condition must be scoped to CLAIMED_OBJECTS, ⛔ not to "rows with an owner_id column".

    ⚠️ The fence question is real, and the fix shape decides it

    demo_bootstrap is pinned across six test files, including test/flow-scheduled-org-partition.test.ts, which asserts its schedule shape and its multi-organization exemption by name. test/** is epic #1579's fence.

    ⛔ Not pre-decided here, and ⛔ not queued as "pick option 2 to dodge the fence" — that would be choosing an inferior design to avoid a governance question. The dispatch will require the implementer to establish which assertions actually move, and to stop and report rather than cross the fence.

    ⇒ queued because the primary landing point is src/flows/, not test/, and at least one legitimate shape stays inside it. If measurement shows every shape needs a test/** edit, this card converts to pm:blocked on #1874.

    Not in scope here

    The card's item 2 (whether the 12 notify nodes should make email optional) is downstream of a platform ruling that has not landed, and it overlaps #1185, which is in the decision box carrying its own notify conversion. ⛔ Not folded in; it stays an observation on this card until the channel-availability ruling exists.

    Refs PR #1895 / 99a6c990 (the root-cause fix that makes this safe) · #1804 (the correction recording the sweep's repair window) · #1185 (the other notify card) · #1874 (the fence, if option 1 wins).


    Generated by Claude Code

  3. added
    pm:dispatchedDispatched to a dev agent by /pm-dispatch
    and removed
    pm:queueReady for the PM dispatch loop
    on Sep 11, 2026
  4. claude commented on Sep 11, 2026

    @claude
    Contributor

    Claim: PM loop round R63
    Session: session_0132iDHq4FLW2zS9VPXqbf9f
    Branch: claude/issue-1892-demo-bootstrap-one-shot
    Worktree: hotcrm-issue-1892
    Domain: repo:hotcrm (single-lane repo — ⛔ no domain:*)
    File surface: src/flows/demo-bootstrap.flow.ts (+ whatever the chosen shape requires inside src/). ⛔ test/** is epic #1579's fence — STOP and report rather than cross (stop on breach; explain in the report)
    Container & model: M, mode:subagent, model: default judgement — ⚠️ dispatch-gates.mjs --tier REFUSES in this repo (no scripts/pm/), per seat post §1; tier set by the seat.
    Clause-②: no
    Thread-read: 5629333907
    Serial constraints cleared: none — sibling this wave is #1265 (src/objects/knowledge_article.hook.ts), disjoint. PR #1893 (#1185, draft, decision box) holds src/flows/*.flow.ts for the 15 notify nodes: ⚠️ do NOT touch notify nodes in this card. PR #1882 (draft, maintainer's) holds src/profiles/.


    Generated by Claude Code

  5. added
    pm:queueReady for the PM dispatch loop
    and removed
    pm:dispatchedDispatched to a dev agent by /pm-dispatch
    on Sep 11, 2026
  6. claude commented on Sep 11, 2026

    @claude
    Contributor

    Released at shift close — R63, ⛔ zero work lost

    Release: session session_0132iDHq4FLW2zS9VPXqbf9f · cause: maintainer ended the shift on budget (「没 token 了」, 2026-09-11T04:2xZ) while this card was in flight · destination: back to pm:queue, unassigned.

    Verified before releasing, ⛔ not assumed: the dispatched branch claude/issue-1892-demo-bootstrap-one-shot exists on the remote but points at 99a6c990 — byte-identical to main. No commit was pushed, so there is no WIP to rescue, no partial PR, and nothing for a successor to diff. ⇒ a clean release, ⛔ not a dead claim for someone to reclaim in 24h.

    ⭐ The dispatch order's analysis is not lost — it is on this card's claim comment and in the grading/verdict comments above. Whoever picks this up next should re-read those rather than re-derive, then re-verify every premise against the tree at their own base.

    ⚠️ Two things this card must not lose, both measured in R62 and written up at 5629333907: (1) the */10 sweep WAS the safety net for ownerless rows, and only PR #1895 (99a6c990) made removing it safe — re-verify the boot-time claim succeeds first; (2) a self-disable predicate scoped to "rows with an owner_id column" never becomes true — crm_campaign_member and crm_event_attendee are permanently unowned by design and are not in CLAIMED_OBJECTS. Scope it to CLAIMED_OBJECTS. ⚠️ Still priority:p1, still the maintainer's own production card.


    Generated by Claude Code

  7. 10 remaining items

  8. objectstack-fleet commented on Sep 25, 2026

    @objectstack-fleet
    Contributor

    repo:hotcrm seat, session_01X8U3asekbiC7yWoEPWR4Dg · stock re-triage group 6 (maintainer-confirmed ten-card group; maintainer reply verbatim: 「同意」) · 2026-09-25T04:38Z

    pm:blocked → pm:on-hold (p1 unchanged)

    objectstack#17628 closed via PR #17872 on 2026-09-12, after 17.4.0, so it is not installable yet. Removing the cron on 17.4.0 would strand 73 rows (5629781208), so nothing lands now. The same next release carries #17334 (schedule flows must declare an organization) and #17396 option G (scheduled flows off by default). The resuming dev must re-measure on the new pin whether the boot claim covers all 12 CLAIMED_OBJECTS, then take option 1 or retire the flow. #1874 is unreadable and test/ is edited routinely on main, so the two test edits are not a blocker.


    Generated by Claude Code

  9. hotlong commented on Sep 28, 2026

    @hotlong
    ContributorAuthor

    Pointer, 2026-09-28T12:01Z: the scheduled-flow organization contract this card expects "in the next release" has already reached the hosted runtime, which pins the framework by commit. A v3.1.0 marketplace install there leaves all 9 scheduled flows NOT BOUND. Filed as #1969 (pm:queue, p1); it blocks the next hosted production release. This card's own restart condition is unchanged.

  10. hotlong commented on Sep 28, 2026

    @hotlong
    ContributorAuthor

    Correction to my pointer above (2026-09-28T13:44Z): #1969 is closed not_planned. Its premise was falsified before dispatch: under objectstack#18420, a single-posture hosted kernel binds undeclared scheduled flows, so no HotCRM change is needed. The carrier is the hosted pin move, objectstack-ai/cloud#2332. This card's own restart condition is unchanged.

  11. objectstack-fleet commented on Oct 2, 2026

    @objectstack-fleet
    Contributor

    Claim: PM loop round R69
    Session: session_01ER8ntXZhYebyQ66aXWdjfT
    Account: hotlong (the seat's linked user as GET /user answers it; always the card's assignee)
    Branch: claude/issue-1892-demo-bootstrap-run-once
    Worktree: hotcrm-issue-1892
    Domain: repo:hotcrm (single-lane repo, no domain:* taxonomy)
    Seat: repo:hotcrm#1
    File surface: src/sales/flows/demo-bootstrap.flow.ts (retired or made non-scheduled) and its registration in src/sales/flows/index.ts; the pins that move with it, measured earlier as test/actions-flows-integrity.test.ts, test/flow-scheduled-org-partition.test.ts and the automation-docs-coverage rows in content/docs/; test/flow-scheduled*.test.ts per the card; one .changeset/1892-*.md (stop on breach; explain in the report)
    Container & model: M, mode:subagent, model: default (dispatch-gates --tier --repo objectstack-ai/hotcrm answers "no path-derived mandate … the tier stays the PM's per-card judgment call"; measurement-first, with a boot)
    Clause-②: no
    Thread-read: 5871131260
    Serial constraints cleared: in-flight #1984's pushed branch (151392a4) touches src/revenue/flows/quote-generation.flow.ts, src/sales/flows/forecast-snapshot.flow.ts, test/flow-quote.test.ts, test/forecast-snapshot-amounts.test.ts and its changeset; disjoint. No open PR carries these paths. The sibling dispatches #1980 (src/sales/views/forecast.view.ts) and #1974 (src/service/objects/*, test/case-sla-matrix.test.ts) are disjoint.

    Unlock: pm:on-hold → pm:dispatched. The restart condition holds on the installed pin. repo:hotcrm seat · 2026-10-02T22:04Z


    Generated by Claude Code

  12. objectstack-fleet commented on Oct 2, 2026

    @objectstack-fleet
    Contributor

    os-dev-report
    {
    "issue": 1892,
    "status": "done",
    "branch": "claude/issue-1892-demo-bootstrap-run-once",
    "pr": "#1988",
    "session": "session_01ER8ntXZhYebyQ66aXWdjfT",
    "premise_still_valid": true,
    "summary": "Measurement 1 came first and reads 0 ownerless rows on all 12 CLAIMED_OBJECTS. It was a fresh objectstack dev boot on untouched origin/main cf422b8 (17.6.0) with scheduled work at its default OFF; the boot log reads 'demo_bootstrap is not armed … disabled by deployment policy' and the flow had 0 runs. The positive control was the same query at seed settle (22:09:52.6Z), before the app:seeded claim: case 38, contract 4, knowledge_article 4 and event 29 ownerless, the same four objects the 17.4.0 run lost. The app:seeded 'final' claim at 22:10:05.4Z took them to 0, and it stayed 0 at 22:20:20.3Z. Hypothesis 2 holds: the flow's only writes were owner_id stamps, and every runtime creator on those objects stamps owner_id itself. So demo_bootstrap is retired outright, with its registration, its saas filter, its exemption-register entry, its pins and its docs rows. On a fresh install with scheduled work ON, sys_job now carries no flow-schedule:demo_bootstrap (the base-tree control carries */10 active:1). One new platform gap was measured, outside the fresh-install acceptance: on a warm boot with an existing admin and an in-budget seed, the claim does not run at all. See out_of_scope_findings and open_questions.",
    "tests": "Final run: pnpm verify at e5acc25, quoted from that run: 'os-verify-lock: VERDICT command-exit 0'. validate passed with 'Logic: 30 Flows'; typecheck, lint, lint:i18n-gate and hygiene passed; '✓ source token ratchet clean'; build passed; test 'Test Files 174 passed (174)' and 'Tests 3706 passed | 1 skipped (3707)'. The earlier verify at b0ac391 ended 'VERDICT command-exit 1' on 2 docs-count guards: test/docs-declared-versions (docs/STATUS.md 'Flows: page says 31, the stack registers 30') and test/docs-metadata-counts (README.md:8 and :72 said 31 flows). Both were fixed in e5acc25. The targeted re-run of those 2 files read VERDICT 0, 23 passed. Earlier targeted run of the 12 touched or adjacent test files, before the main merge: VERDICT 0, 12 files and 375 tests passed. Typecheck alone: VERDICT 0. Boots used the measurement wrapper, all on port 4892, each stopped by its recorded PID. A, base, scheduled OFF: measurement 1. A-warm: warm boot after planting 2 nulls, which stayed null. A-warm2: a deleted seeded article re-inserted ownerless, with no claim. B, base, fresh DB, scheduled ON: sys_job has flow-schedule:demo_bootstrap */10 active 1. C, branch, fresh DB, scheduled ON: 0 ownerless on all 12; sys_job has 9 rows and none for demo_bootstrap. D, branch on B's DB: the stale row stays active 1, but run_count is 0 across the 22:30:00 tick; control: approvals-sla-escalation ran at 22:32:04 on the same kernel. No ablation applies: nothing was mutated except planted DB rows on a throwaway DB, and the source tree was never mutated for measurement.",
    "mcp_calls": "0 (no MCP GitHub calls)",
    "api_writes": "3 REST writes, each one relay stroke as POST /repos/objectstack-ai/objectstack/dispatches executed as objectstack-fleet[bot]. (1) pr_create, i.e. POST /repos/objectstack-ai/hotcrm/pulls, draft: true, which became #1988; readback 10976 bytes sent and 10976 stored, identical. (2) label-write --assign hotlong, i.e. POST /repos//issues/1988/assignees; readback matches. (3) this os-dev-report comment via post-stamped, i.e. POST /repos//issues/1892/comments. Plus 2 git pushes, which are not REST writes: the empty branch marker at cf422b8, then bb70aaf, b0ac391 and e5acc25. Reads were single-card and single-PR REST GETs.",
    "line_budget": "Token ratchet, comment-stripped, measured against the merged base c7c5fb7 with git archive and the same script. src/sales business semantics 54,323 to 53,433; src/sales interaction layer 27,999 to 27,999; src/sales authored total 97,801 to 96,911. src/revenue is unchanged at 15,665, 2,136 and 18,775 (comment-only edits). src/service and src/marketing were not touched. No ceiling was touched. Headroom on the untouched dispatch base cf422b8 was src/sales authored total 97,805 against 100,000. Diff: 35 files, plus 233 and minus 1190 in commit bb70aaf, plus README.md and docs/STATUS.md in e5acc25.",
    "files_changed": [
    "src/sales/flows/demo-bootstrap.flow.ts (deleted)",
    "src/sales/flows/index.ts",
    "objectstack.composition.ts",
    "objectstack.config.ts",
    "test/flow-scheduled.test.ts",
    "test/actions-flows-integrity.test.ts",
    "test/flow-scheduled-org-partition.test.ts",
    "test/automation-docs-coverage.test.ts",
    "test/flow-variable-conditions.test.ts",
    "test/saas-composition.test.ts",
    "test/activity-seed-coverage.test.ts",
    "test/hooks-runtime-sales.test.ts",
    "test/ownership-model.test.ts",
    "test/forecast-seeds.test.ts",
    "content/docs/administration/automation.mdx",
    "content/docs/administration/automation.zh-Hans.mdx",
    "content/docs/administration/automation.zh-Hant.mdx",
    "README.md",
    "docs/STATUS.md",
    "docs/MAINTENANCE.md",
    "docs/feature-inventory.md",
    "docs/architecture/module-split-inventory.json",
    "src/sales/data/_shared.ts",
    "src/sales/data/activity.seed.ts",
    "src/sales/data/forecast.seed.ts",
    "src/sales/data/index.ts",
    "src/sales/objects/account.hook.ts",
    "src/sales/objects/forecast.hook.ts",
    "src/sales/objects/lead.hook.ts",
    "src/sales/sharing/demo-staffing.ts",
    "src/sales/flows/billing-handoff-closed-won.flow.ts",
    "src/sales/flows/opportunity-won-alert.flow.ts",
    "src/revenue/flows/billing-handoff-contract-activated.flow.ts",
    "scripts/demo-staff.ts",
    "e2e/fixtures.ts",
    "e2e/opportunity-lifecycle.spec.ts",
    ".changeset/1892-demo-bootstrap-run-once.md"
    ],
    "deviations": [
    "Base moved: origin/main was cf422b8 at worktree creation, not 39ba05e. #1984 had landed as #1985, with the pin unchanged at 17.6.0, so measurement 1 ran on cf422b8. Later #1986 and #1987 landed; I merged origin/main c7c5fb7 in (b0ac391), with no overlap with my files.",
    "Claim file surface exceeded, each with a reason. objectstack.config.ts and objectstack.composition.ts: the build imports the flow there. test/saas-composition, flow-variable-conditions, activity-seed-coverage, hooks-runtime-sales, ownership-model and forecast-seeds: pins or present-tense statements of the retired flow. README.md and docs/STATUS.md: their count guards went red. docs/MAINTENANCE.md, docs/feature-inventory.md, docs/architecture/module-split-inventory.json, scripts/demo-staff.ts, e2e/ and the src comment files: they stated the retired sweep as the current mechanism. No governed path was touched. Fenced files were left alone: src/sales/flows/forecast-snapshot.flow.ts (dispatch fence) and src/service/objects/case.hook.ts (sibling #1974's surface at dispatch).",
    "Safety net removal used the 17.6.0 deployment switch (OS_AUTOMATION_SCHEDULED_WORK_ENABLED unset, the default) rather than a source mutation. Proven by the boot log line and by 0 demo_bootstrap rows in sys_automation_run and sys_job at every reading.",
    "Fix shape: the PM-suggested retirement, not 'make it non-scheduled'. Hypothesis 2 found no non-claim side effect, and a non-scheduled flow could not cover the warm-boot gap either."
    ],
    "ci": "At report time on e5acc25: Check Changeset, Quality Checks, link-check, Label Pull Request and Vercel Preview Comments are success. Build and Test (22.x), Typecheck and Build, Playwright and Analyze Code are in_progress. Not awaited, per contract.",
    "open_questions": [
    {
    "question": "Land #1988 now, or hold the draft until objectstack fixes the warm-boot claim gap? The gap: on a boot with an existing admin and an in-budget seed, plugin-security's app:seeded handler returns before kernel:ready sets the claim target, and the already_have_admin pass never claims. So seed rows inserted on a later boot, for example by a HotCRM upgrade that adds seed rows, stay ownerless. The */10 sweep covered that within 10 minutes on deployments with scheduled work ON.",
    "options": [
    "A. Land now and file the gap upstream. The card's acceptance (fresh install) is met and measured. The gap already exists on every deployment running the 17.5.0+ default, scheduled work OFF, where the sweep never runs. Keeping a perpetual app-side cron to mask a platform gap is the compensation AGENTS.md §1/§2 forbid.",
    "B. Hold the draft with a Blocked-by line to the new upstream card, per AGENTS.md §2 WAIT. This keeps the 3.4 s average, 26-minute worst-case */10 sweep (and its 2 stuck runs) in every scheduled-work tenant until upstream lands and is pinned."
    ],
    "recommendation": "A, on the four axes. Real business need: the gap needs a version that adds seed rows to an existing community-composition tenant with scheduled work ON. No such change is queued, and production reads acted 0 across 100 retained runs, while the sweep's measured cost is real today. Long-term soundness: seed ownership is the platform's (§1), so the fix belongs upstream. Preventing AI authoring errors: neutral. Startup focus: retire immediately, with no staged window. Note the seat's own ruling text, 'If the platform still leaves rows ownerless, this card does not work around it in hotcrm'. Reading it as covering this warm-boot case is what option B means, so the seat owns that reading."
    }
    ],
    "out_of_scope_findings": [
    "class: a · reach: public door, objectstack dev/serve warm boot. Measured on the base artifact cf422b8 (17.6.0) by reusing the measurement-1 DB. Deleting the seeded crm_knowledge_article 'API Rate Limits' made the replay re-insert it (seed-settled 'inserted:1', no over-budget line) with owner_id null at 22:23:07Z. Two planted owner_id nulls on crm_case and crm_contract also stayed null. No '[security] handed … seeded record(s)' line appeared; bootstrap logged reason already_have_admin. Mechanism read in @objectstack/plugin-security 17.6.0 dist/index.mjs: ctx.hook('app:seeded') returns while claimTargetAdminUserId is unset (it is set only by runBootstrap at kernel:ready), and bootstrapPlatformAdmin calls claimSeedOwnership only inside promote(). This contradicts the plugin's own log contract, 'stay unowned until the claim re-runs on app:seeded' and 'the next run will claim them'. Fix lands in objectstack (plugin-security), so the seat files it there with a back-link to hotcrm#1892. Dedupe words: claimSeedOwnership, app:seeded, kernel:ready, claimTargetAdminUserId, already_have_admin, warm boot, in-budget seed.",
    "carrier:承接者:无 · noted, not filed. On upgrade the platform leaves the stale sys_job row 'flow-schedule:demo_bootstrap' */10 active:1 after the flow is removed. It is inert (Boot D: run_count 0 across the 22:30:00 tick; the approvals job ran on the same kernel), so it is misleading state, not a running job. The changeset tells operators they may delete it.",
    "carrier: the next PR touching src/sales/flows/forecast-snapshot.flow.ts or src/service/objects/case.hook.ts · noted, not filed. Comment-only mentions of demo_bootstrap remain at forecast-snapshot.flow.ts:420 and case.hook.ts:102, left because those files were fenced or held at dispatch.",
    "carrier: 承接者:无 · noted, not filed. The pending .changeset/objectstack-17-5-0.md says HotCRM ships 'nine scheduled flows … and demo bootstrap'. That was true of that change; if both ship in one release, #1988's changeset gives the later count of eight.",
    "carrier: 承接者:无 · noted, not filed. content/docs/administration/sharing-and-security.mdx:133 says a seeded write 'keeps first-install intake visible in the tab'. Seeded cases are owned after the claim (38/38 measured), and were within 10 minutes under the sweep. Pre-existing docs drift."
    ]
    }


    Generated by Claude Code

  13. objectstack-fleet commented on Oct 2, 2026

    @objectstack-fleet
    Contributor

    os-dev-report
    {
    "issue": 1892,
    "status": "done",
    "branch": "claude/issue-1892-demo-bootstrap-run-once",
    "pr": "#1988",
    "session": "session_01ER8ntXZhYebyQ66aXWdjfT",
    "premise_still_valid": true,
    "round": "patch round, same claim 5962213086; addendum to report comment 5962651035",
    "summary": "The changeset no longer overclaims. The platform's claim is scoped to a new install's first boot ('the platform does this itself, on a new install's first boot: when the seed data finishes loading, it hands every seeded record that has no owner to the first administrator'). The first-administrator bullet gains one plain-language known limit: seed records that a later upgrade adds to an existing install do not get an owner from the platform yet, tracked in objectstack-ai/objectstack#21486. Nothing else changed. The PR body was not edited, as instructed.",
    "tests": "pnpm verify at HEAD 5e0fe91: 'os-verify-lock: VERDICT command-exit 0 · held the lock 168s (2m48s) · waited 0s'. The run printed HEAD 5e0fe91 itself. validate: '✓ Validation passed'. hygiene:tokens: '✓ source token ratchet clean'. test: 'Test Files 174 passed (174)' and 'Tests 3706 passed | 1 skipped (3707)'. CI on 5e0fe91 at report time: Check Changeset, Build and Test (22.x), Typecheck and Build, Playwright, CodeQL, Analyze Code, Quality Checks, link-check, Label Pull Request and Vercel Preview Comments are all success.",
    "mcp_calls": "0 (no MCP GitHub calls)",
    "api_writes": "This round: 1. This addendum comment via post-stamped and the fleet relay, i.e. POST /repos/objectstack-ai/objectstack/dispatches, then POST /repos//issues/1892/comments. Plus 1 git push (not REST): e5acc25 to 5e0fe91, fast-forward, no force. Running total on this claim: 4 (pr_create, assign, report comment, this addendum).",
    "line_budget": "src/** untouched this round, so the token ratchet is unchanged: src/sales authored total ~96,911 (ceiling ~100,000), read from this run's hygiene:tokens. The changeset diff is +8/-6 lines in 1 file.",
    "files_changed": [
    ".changeset/1892-demo-bootstrap-run-once.md"
    ],
    "deviations": [
    "The worktree had been removed after the first round, so it was recreated from the unchanged remote tip e5acc25 (origin/main still c7c5fb7) and removed again after verify.",
    "Besides the two requested sentence changes, the one paragraph I edited was re-wrapped so the line break after 'A fresh' does not dangle. Rendering is identical and no other paragraph was touched."
    ],
    "open_questions": [],
    "out_of_scope_findings": []
    }


    Generated by Claude Code

  14. objectstack-fleet commented on Oct 2, 2026

    @objectstack-fleet
    Contributor

    ACCEPT: PR #1988 at 5e0fe91f. demo_bootstrap is retired outright, because the platform now claims seeded rows on a new install's first boot. repo:hotcrm seat, session_01ER8ntXZhYebyQ66aXWdjfT, 2026-10-02T22:54Z. Reports: 5962651035, and the patch-round addendum 5962737306.

    Measurement first: the dispatch's stop condition is cleared on evidence, not prose.

    • A fresh objectstack dev boot on cf422b83 (17.6.0), with scheduled work at its default OFF, so the sweep was out of the measurement (boot log: "demo_bootstrap is not armed … disabled by deployment policy"; 0 runs). It reads 0 ownerless rows on all 12 claimed objects.
    • Positive control: the same query at seed settle, before the app:seeded claim, reads case 38, contract 4, knowledge_article 4 and event 29. These are the same four objects the 17.4.0 run lost (5629799335).
    • The seat checked the mechanism independently: the installed plugin-security@17.6.0 registers the app:seeded re-claim.

    Seat decision on the dev's open question: land now (A), not hold (B). The governing text decides it.

    Review readings:

    • Form: draft, base main. Fixes #1892 is the only closing keyword. PR assignee hotlong. Not governed: check-governed-merges --pr objectstack-ai/hotcrm#1988 reports 0 of 37 paths. 1,429 changed lines, under 5,000.

    • Registration: removed in all three places: src/sales/flows/index.ts, objectstack.config.ts (the isSaas filter is gone, so flows: allFlows), and objectstack.composition.ts.

    • Surface beyond the claim, accepted: a non-comment line count over the 14 out-of-surface src/, scripts/ and e2e/ files gives 0 everywhere, except one message string in scripts/demo-staff.ts. Every edit restates the retired mechanism. README.md and docs/STATUS.md moved because their own count guards went red (31 → 30 flows).

    • Tests: 20 removed cases, each pinning the retired flow's own behaviour. One was kept and renamed (interaction ownership), and one parity case was added (saas = community flows). No skip, only or todo.

    • Changeset, after the patch round:

    • Gates: the dev's pnpm verify at 5e0fe91f ended VERDICT command-exit 0: 174 files, 3,706 tests. CI is 10 of 10 success on 5e0fe91f. Tokens: src/sales authored total −890 (business semantics −890), no ceiling moved.

    • Noted, not filed:

      • The stale sys_job row on upgrade (inert, and the changeset tells operators).
      • Two comment-only demo_bootstrap mentions in files that were fenced at dispatch.
      • The pending 17.5.0 changeset's flow count.
      • A docs drift line in sharing-and-security.mdx:133.

      All are outside the three filing classes.

    Landing: not governed, so ready → auto-merge → queue.


    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

No one assigned

    Labels

    backendServer-side behaviour — hooks, flows, actionsbugSomething isn't workingpriority:p1High: required for production / M2

    Type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions