Skip to content

fix(flows): retire demo_bootstrap, the platform claims seeded rows once at seed settle - #1988

Merged
objectstack-fleet[bot] merged 4 commits into
mainfrom
claude/issue-1892-demo-bootstrap-run-once
Oct 2, 2026
Merged

objectstack-fleet[bot] merged 4 commits into
mainfrom
claude/issue-1892-demo-bootstrap-run-once

Conversation

@objectstack-fleet

Copy link
Copy Markdown
Contributor

Fixes #1892

What changed

demo_bootstrap is retired. It was a type: 'schedule' flow on */10 * * * * that, in every tenant, filtered twelve crm_* objects for owner_id IS NULL and stamped the first user onto what it found, forever. On the 17.6.0 pin the platform re-runs its own seed-ownership claim on app:seeded (claimSeedOwnership in @objectstack/plugin-security, objectstack#17872, the change for objectstack#17628). Measurement 1 below shows that claim leaves zero ownerless rows on all twelve objects of a fresh boot with the sweep unable to fire. So the flow goes, together with its registration, the SaaS-composition filter that existed only to drop it, its exemption-register entry, its test pins and its docs rows. No scheduled job of any kind is added.

Measurement 1: fresh boot on 17.6.0 with the sweep out

Recipe. Worktree at origin/main cf422b83 (pin 17.6.0), tree untouched. rm -rf .objectstack/data && pnpm build under the shared lock (VERDICT command-exit 0). Then objectstack dev -p 4892 --no-watch --log-level info, spawned by a small wrapper that holds an IPC channel so objectstack:seed-settled is timestamped. OS_AUTOMATION_SCHEDULED_WORK_ENABLED was unset, which is the 17.6.0 default and arms no time trigger.

The safety net was provably out. The boot log says Flow 'demo_bootstrap' is not armed on trigger 'schedule' — disabled by deployment policy (22:09:35.626Z). At every reading, sys_automation_run and sys_job held 0 rows for demo_bootstrap.

The instrument is the same query the 17.4.0 run used (owner_id IS NULL), on the same twelve CLAIMED_OBJECTS, read-only over .objectstack/data/objectstack.db.

Timeline (2026-10-02, UTC):

time event
22:09:20.6 server spawned
22:09:35.5 Inline seed exceeded 8000ms budget … continuing in background
22:09:36.5 first user promoted to platform admin: admin@objectos.ai
22:09:49.8 kernel:ready claim, handed 195 seeded record(s) … PROVISIONAL: 1 seed source(s) were still writing
22:09:51.9 objectstack:seed-settled, inserted: 354
22:09:52.6 reading A, after settle and before the app:seeded claim
22:10:05.4 app:seeded claim, handed 155 seeded record(s) … final (case 38, contract 4, event 29, knowledge_article 4, campaign_member 51, event_attendee 29)
22:10:14.8 reading B
22:20:20.3 reading C, after the 22:10 and 22:20 tick windows; demo_bootstrap runs: 0

Per object, ownerless / total:

object A (22:09:52.6) B (22:10:14.8) C (22:20:20.3) 17.4.0 run, comment 5629781208
crm_lead 0 / 21 0 / 21 0 / 21 0
crm_account 0 / 9 0 / 9 0 / 9 0
crm_contact 0 / 9 0 / 9 0 / 9 0
crm_opportunity 0 / 23 0 / 23 0 / 23 0
crm_case 38 / 38 0 / 38 0 / 38 38
crm_task 0 / 7 0 / 11 0 / 11 0
crm_quote 0 / 6 0 / 6 0 / 6 0
crm_contract 4 / 4 0 / 4 0 / 4 4
crm_forecast 0 / 7 0 / 7 0 / 7 0
crm_campaign 0 / 7 0 / 7 0 / 7 0
crm_knowledge_article 4 / 4 0 / 4 0 / 4 4
crm_event 29 / 29 0 / 29 0 / 29 27
sum 75 0 0 73

Reading A is the positive control for the instrument. The same query sees exactly the four objects the 17.4.0 run lost (the event seed has grown from 27 to 29 rows since then). A second control comes at the end of the run: after planting owner_id = NULL on one crm_case row and one crm_contract row, the query reads case 38/1 · contract 4/1. crm_task growing from 7 to 11 is the claim's own update of crm_case firing case_escalation four times, which then fired task_urgent_alert four times. The sweep's update_record writes fired record-change flows the same way.

The acceptance on both trees, plus the upgrade path

All boots use the same recipe with OS_AUTOMATION_SCHEDULED_WORK_ENABLED=true.

boot artifact DB sys_job ownerless (12 objects)
B, control base cf422b83 fresh 10 rows, including flow-schedule:demo_bootstrap · */10 * * * * · active: 1 (the production symptom) 0. The platform claim got there before the first tick.
C this branch fresh 9 rows (8 flow schedules and approvals-sla-escalation), none for demo_bootstrap 0, after the final claim at 22:26:30.8
D, upgrade this branch Boot B's DB the old flow-schedule:demo_bootstrap row stays active: 1, but nothing runs it: run_count 0 and no sys_job_run row across the 22:30:00 tick. Control on the same kernel: approvals-sla-escalation ran at 22:32:04, success. unchanged

Hypothesis 2: the claim was the flow's only job

Read on today's tree: every node was either the first-user lookup or a get_record / update_record pair on owner_id over the twelve objects. Nothing else was written. No runtime producer relied on the sweep either. Every create_record on those objects stamps owner_id itself: contract_renewal, forecast_snapshot, opportunity_stagnation, quote_generation, lead_conversion and schedule_followup, plus the hook and action inserts. That matches the card's production reading of acted 0 over 100 retained runs.

Files

  • Flow and registration: src/sales/flows/demo-bootstrap.flow.ts (deleted), src/sales/flows/index.ts, objectstack.composition.ts, objectstack.config.ts. Both compositions now register the same 30 flows.

  • Pins under test/:

    • flow-scheduled: both demo_bootstrap blocks removed. The forecast_snapshot 与启动重播种的互动:每次 dev 重启后,当季出现一条无 owner 的幻影快照行与 owner 键控行并存 #702 forecast ordering cases now run the platform's real claimSeedOwnership over the harness in both orders, in place of the retired flow.
    • actions-flows-integrity: two pins removed.
    • flow-scheduled-org-partition: the exemption register is now empty, and the composition-backed exemption block is removed.
    • automation-docs-coverage: ledger row removed.
    • flow-variable-conditions: the zero-user case is removed.
    • saas-composition: the flow pins now assert that both shapes register the same flows. The engine measurement that justified the exclusion is removed with it.
    • activity-seed-coverage, hooks-runtime-sales, ownership-model and forecast-seeds: wording only.
  • Docs that follow the code:

    • content/docs/administration/automation.mdx and its zh-Hans and zh-Hant pages: the row is removed, 31 flows becomes 30, nine scheduled becomes eight, and one sentence now says who owns seeded records.
    • README.md and docs/STATUS.md: the flow count, transcribed from this run's pnpm validate.
    • docs/feature-inventory.md: ADM-011 is marked removed, per the file's own rule.
    • docs/architecture/module-split-inventory.json: the row is removed and a $hand_edits entry added, per its protocol.
    • docs/MAINTENANCE.md.
  • Comments that named the sweep as the current mechanism:

    • src/sales/data/ (_shared.ts, activity.seed.ts, forecast.seed.ts, index.ts)
    • src/sales/objects/ (account.hook.ts, forecast.hook.ts, lead.hook.ts)
    • src/sales/sharing/demo-staffing.ts
    • billing-handoff-closed-won, billing-handoff-contract-activated and opportunity-won-alert flows
    • scripts/demo-staff.ts
    • e2e/fixtures.ts and e2e/opportunity-lifecycle.spec.ts

    Dated measurements ("measured on 17.4.0", "used to") are left as written.

  • .changeset/1892-demo-bootstrap-run-once.md (patch).

Beyond the surface the claim listed, objectstack.config.ts and objectstack.composition.ts were touched because the build imports the flow there. The extra test files pin the retired flow. README.md and docs/STATUS.md changed because their count guards went red, and the comment files stated the retired sweep as the current mechanism. No governed path is touched. origin/main c7c5fb7d is merged in, with no overlap with these files.

Verification

  • pnpm verify at e5acc256: os-verify-lock: VERDICT command-exit 0.
    • validate passed (Logic: 30 Flows); typecheck, lint, lint:i18n-gate and hygiene passed.
    • ✓ source token ratchet clean; build passed.
    • test: Test Files 174 passed (174) · Tests 3706 passed | 1 skipped (3707).
  • The first pnpm verify, at b0ac3914, was red on two docs-count guards: README.md and docs/STATUS.md still said 31 flows. e5acc256 updates both.
  • Token ratchet (comment-stripped), against the merged base c7c5fb7d:
    • src/sales business semantics: 54,323 → 53,433
    • src/sales interaction layer: 27,999 → 27,999
    • src/sales authored total: 97,801 → 96,911
    • src/revenue: unchanged (comment-only edits)
    • No ceiling touched.

Acceptance notes

  1. Platform gap found, not fixed here. On a boot where an admin already exists and the seed settles within the inline budget, the seed-ownership claim does not run at all. The app:seeded hook fires before kernel:ready has set the claim target, and the already_have_admin pass does not claim. Measured on the base artifact by warm-booting the measurement-1 DB:

    • the two planted nulls stayed null;
    • a seeded crm_knowledge_article deleted before the boot was re-inserted by the replay (inserted: 1) with owner_id null;
    • no handed … seeded record(s) line appeared.

    So a seed row added by a later HotCRM version stays ownerless on an existing install. On deployments with scheduled work enabled, the */10 sweep used to cover this within ten minutes. On the 17.6.0 default (scheduled work off) it never ran anyway. This is handed to the seat for an upstream card. It does not affect the fresh-install acceptance above.

  2. Upgraded installs keep the inert flow-schedule:demo_bootstrap row (Boot D), and the changeset tells operators so.

  3. Left untouched on purpose:

    • the comment at src/sales/flows/forecast-snapshot.flow.ts:420 ("same constraint as demo_bootstrap / case_sla_monitor"), because the dispatch fenced that file;
    • src/service/objects/case.hook.ts:102, which lists "demo bootstrap" among system writers, because it sat in a sibling claim's surface at dispatch time.
  4. .changeset/objectstack-17-5-0.md, still pending, counts "nine scheduled flows … and demo bootstrap". That is true of that change. If both ship in one release, this changeset's eight is the later state.

  5. content/docs/administration/sharing-and-security.mdx:133 says a seeded write "keeps first-install intake visible in the tab". Seeded cases are owned once the claim runs (38 of 38 measured), as they were within ten minutes under the sweep. This is pre-existing and not touched.

  6. The platform claim covers every object carrying owner_id: 18 are eligible, including crm_product and crm_event_attendee. The retired flow's header said those two had no column to stamp; measured, they do.


Generated by Claude Code

claude added 3 commits October 2, 2026 22:32
…ed rows once

demo_bootstrap was a */10 schedule flow that re-filtered twelve objects for
ownerless rows forever. On the 17.6.0 pin the platform re-runs its
seed-ownership claim on app:seeded (objectstack#17872): a fresh dev boot with
the sweep unable to fire leaves zero ownerless rows on all twelve objects, so
the sweep is removed with its registration, its saas-composition exclusion,
its exemption-register entry, its test pins and its docs rows. The #702
forecast ordering cases now run the platform's real claimSeedOwnership in
both orders instead of the retired flow.

Co-Authored-By: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01ER8ntXZhYebyQ66aXWdjfT
@vercel

vercel Bot commented Oct 2, 2026 •

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

1 Skipped Deployment
Project Deployment Actions Updated
hotcrm Ignored Ignored Oct 2, 2026 10:50pm UTC

Request Review

@github-actions github-actions Bot added documentation Improvements or additions to documentation ci/cd CI plumbing and the verification pipeline metadata Declarative metadata — schema, security posture, UI surfaces configuration Build and app configuration files backend Server-side behaviour — hooks, flows, actions labels Oct 2, 2026
…rst boot

The platform's seed-settle claim covers a new install's first boot only;
seed rows a later upgrade adds to an existing install are not claimed yet,
tracked upstream in objectstack-ai/objectstack#21486.

Co-Authored-By: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01ER8ntXZhYebyQ66aXWdjfT
@objectstack-fleet
objectstack-fleet Bot marked this pull request as ready for review October 2, 2026 22:55
@objectstack-fleet
objectstack-fleet Bot added this pull request to the merge queue Oct 2, 2026
Merged via the queue into main with commit 572aa44 Oct 2, 2026
11 checks passed
hotlong pushed a commit that referenced this pull request Oct 3, 2026
Refresh of PR #1953 onto main 25cd8d7 (26 commits). The merge is clean:
main touched none of the PR's four files. Its one README edit (31 -> 30
flows, #1988) is not a figure test/docs-readme-token-figures.test.ts pins,
and that test stays green on the merged tree.

Claude-Session: https://claude.ai/code/session_01ER8ntXZhYebyQ66aXWdjfT
Co-authored-by: Claude <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

backend Server-side behaviour — hooks, flows, actions ci/cd CI plumbing and the verification pipeline configuration Build and app configuration files documentation Improvements or additions to documentation metadata Declarative metadata — schema, security posture, UI surfaces

Projects

None yet

Development

Successfully merging this pull request may close these issues.

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

2 participants