Repository navigation
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
Activity
- addedbugSomething isn't workingSomething isn't workingbackendServer-side behaviour — hooks, flows, actionsServer-side behaviour — hooks, flows, actions
on Sep 11, 2026 Related framework cards (same production incident):
- driver-turso: remote mode never materializes object-level
indexes— every declared secondary index is absent on production Turso tenant databases, so hot polling queries full-scan objectstack#17609 — remote Turso never builds declared indexes (every filter here is a full scan) - service-messaging: NotificationDispatcher issues 32 statements per tick on an EMPTY outbox (reap runs per partition, twice) — idle cost scales with partitions × table size and never backs off objectstack#17610 — notification dispatcher idle cost
- service-messaging: fan-out writes an
emaildelivery for a tenant with no email transport — it dead-letters on its first attempt and is kept 90d, so the hot outbox grows ~1 dead row per notification objectstack#17611 — deademaildeliveries for tenants without an email transport (the 12 notify nodes'emailchannel)
- driver-turso: remote mode never materializes object-level
- addedpm:queueReady for the PM dispatch loopReady for the PM dispatch looppriority:p1High: required for production / M2High: required for production / M2
on Sep 11, 2026 os-project-manager commented
on Sep 11, 2026 CollaboratorMore actionsFirst-touch grading →
pm:queue+bug·backend·priority:p1, typeBugrepo:hotcrmseat (single-lane repo — self-serves grading andtype),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 inrunning— ⛔ 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_bootstrapby 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,
claimSeedOwnershipfailed at boot and left rows ownerless; the*/10sweep 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) andcrm_event_attendee(27 rows) are 100% unowned after a full boot AND after the sweep — both carry a physicalowner_idcolumn, and neither is inCLAIMED_OBJECTS(event_attendeeby explicit documented ruling;campaign_memberwithout 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 anowner_idcolumn".⚠️ The fence question is real, and the fix shape decides itdemo_bootstrapis pinned across six test files, includingtest/flow-scheduled-org-partition.test.ts, which asserts its schedule shape and its multi-organization exemption by name.test/**is epic #1579's fence.- Option 1 (drop the cron, trigger once at install/seed) almost certainly reds those schedule assertions ⇒ hits the fence ⇒ becomes another card behind [Decision] Does the
test/**fence release accuracy fixes to existing guards, or does it hold whole? Five queued cards are unfixable and R59 crossed it twice on its own word #1874, which already carries 11. - Option 2 (keep the registration, add a self-disable / early return) may leave the registration-shape assertions intact and stay inside
src/.
⛔ 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/, nottest/, and at least one legitimate shape stays inside it. If measurement shows every shape needs atest/**edit, this card converts topm:blockedon #1874.Not in scope here
The card's item 2 (whether the 12
notifynodes 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 ownnotifyconversion. ⛔ 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 othernotifycard) · #1874 (the fence, if option 1 wins).
Generated by Claude Code
- Option 1 (drop the cron, trigger once at install/seed) almost certainly reds those schedule assertions ⇒ hits the fence ⇒ becomes another card behind [Decision] Does the
- addedpm:dispatchedDispatched to a dev agent by /pm-dispatchDispatched to a dev agent by /pm-dispatchand removedpm:queueReady for the PM dispatch loopReady for the PM dispatch loop
on Sep 11, 2026 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 — ⛔ nodomain:*)
File surface:src/flows/demo-bootstrap.flow.ts(+ whatever the chosen shape requires insidesrc/). ⛔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 --tierREFUSES in this repo (noscripts/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) holdssrc/flows/*.flow.tsfor the 15 notify nodes:⚠️ do NOT touch notify nodes in this card. PR #1882 (draft, maintainer's) holdssrc/profiles/.
Generated by Claude Code
- addedpm:queueReady for the PM dispatch loopReady for the PM dispatch loopand removedpm:dispatchedDispatched to a dev agent by /pm-dispatchDispatched to a dev agent by /pm-dispatch
on Sep 11, 2026 Released at shift close — R63, ⛔ zero work lost
Release:sessionsession_0132iDHq4FLW2zS9VPXqbf9f· cause: maintainer ended the shift on budget (「没 token 了」, 2026-09-11T04:2xZ) while this card was in flight · destination: back topm:queue, unassigned.Verified before releasing, ⛔ not assumed: the dispatched branch
claude/issue-1892-demo-bootstrap-one-shotexists on the remote but points at99a6c990— byte-identical tomain. 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 at5629333907: (1) the*/10sweep 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 anowner_idcolumn" never becomes true —crm_campaign_memberandcrm_event_attendeeare permanently unowned by design and are not inCLAIMED_OBJECTS. Scope it toCLAIMED_OBJECTS.⚠️ Stillpriority:p1, still the maintainer's own production card.
Generated by Claude Code
10 remaining items
objectstack-fleet commented
on Sep 25, 2026 ContributorMore actionsrepo:hotcrmseat,session_01X8U3asekbiC7yWoEPWR4Dg· stock re-triage group 6 (maintainer-confirmed ten-card group; maintainer reply verbatim: 「同意」) · 2026-09-25T04:38Zpm: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 12CLAIMED_OBJECTS, then take option 1 or retire the flow. #1874 is unreadable andtest/is edited routinely onmain, so the two test edits are not a blocker.
Generated by Claude Code
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.0marketplace install there leaves all 9 scheduled flowsNOT BOUND. Filed as #1969 (pm:queue, p1); it blocks the next hosted production release. This card's own restart condition is unchanged.Correction to my pointer above (2026-09-28T13:44Z): #1969 is closed
not_planned. Its premise was falsified before dispatch: under objectstack#18420, asingle-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.- addedpm:dispatchedDispatched to a dev agent by /pm-dispatchDispatched to a dev agent by /pm-dispatchand removed
on Oct 2, 2026 objectstack-fleet commented
on Oct 2, 2026 ContributorMore actionsClaim: PM loop round R69
Session:session_01ER8ntXZhYebyQ66aXWdjfT
Account:hotlong(the seat's linked user asGET /useranswers it; always the card's assignee)
Branch:claude/issue-1892-demo-bootstrap-run-once
Worktree:hotcrm-issue-1892
Domain:repo:hotcrm(single-lane repo, nodomain:*taxonomy)
Seat:repo:hotcrm#1
File surface:src/sales/flows/demo-bootstrap.flow.ts(retired or made non-scheduled) and its registration insrc/sales/flows/index.ts; the pins that move with it, measured earlier astest/actions-flows-integrity.test.ts,test/flow-scheduled-org-partition.test.tsand theautomation-docs-coveragerows incontent/docs/;test/flow-scheduled*.test.tsper 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/hotcrmanswers "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) touchessrc/revenue/flows/quote-generation.flow.ts,src/sales/flows/forecast-snapshot.flow.ts,test/flow-quote.test.ts,test/forecast-snapshot-amounts.test.tsand 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:hotcrmseat · 2026-10-02T22:04Z- Double-check ①: the latest transition comment
5826837588names this body'sRestart-when:. The pin is now 17.6.0 (PR chore(deps): upgrade @objectstack/* to 17.6.0 #1982,68f3701). - The probe the line asks for: the installed
@objectstack/plugin-security@17.6.0(dist/index.mjs) registersctx.hook("app:seeded", …), and its body callsclaimSeedOwnership(ql, adminUserId, { … seedSettlement: readSeedSettlement() }). That is the re-run on seed settle that objectstack#17872 added. - Double-check ②: no merged PR references this card after
5826837588. The timeline shows only All 9 scheduled flows declare noconfig.organization— the hosted runtime (framework past objectstackecdfc9411) already refuses to bind them, and it blocks the next hosted production release #1969, closednot_planned. - Not decided by this unlock: whether that re-run actually leaves zero ownerless rows across all 12
CLAIMED_OBJECTS. That is the dispatch's first measurement, and the cron is removed only if it reads zero.
Generated by Claude Code
- Double-check ①: the latest transition comment
objectstack-fleet commented
on Oct 2, 2026 ContributorMore actionsos-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
objectstack-fleet commented
on Oct 2, 2026 ContributorMore actionsos-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
objectstack-fleet commented
on Oct 2, 2026 ContributorMore actionsACCEPT: PR #1988 at
5e0fe91f.demo_bootstrapis retired outright, because the platform now claims seeded rows on a new install's first boot.repo:hotcrmseat,session_01ER8ntXZhYebyQ66aXWdjfT, 2026-10-02T22:54Z. Reports:5962651035, and the patch-round addendum5962737306.Measurement first: the dispatch's stop condition is cleared on evidence, not prose.
- A fresh
objectstack devboot oncf422b83(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:seededclaim, 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.0registers theapp:seededre-claim.
Seat decision on the dev's open question: land now (A), not hold (B). The governing text decides it.
- hotcrm
AGENTS.md§1: 「A gap you find in the platform … is filed upstream: ⛔ never compensated for or re-invented here」. The*/10sweep was exactly that compensation. - §2's resume condition is the defect card's own fixture, the fresh install, and it reads 0.
- The dev's new class (a) finding is filed upstream as plugin-security: the seed-ownership claim never runs on a warm boot — seed rows inserted on a later boot (existing admin, in-budget seed) stay ownerless for good objectstack#21486: seed rows inserted on a warm boot (existing admin, in-budget seed) stay ownerless. It is a separate platform defect, not a half of this card.
- On deployments at the 17.5.0+ default (scheduled work OFF) the sweep never ran, so that gap was already live without it.
Review readings:
-
Form: draft, base
main.Fixes #1892is the only closing keyword. PR assigneehotlong. Not governed:check-governed-merges --pr objectstack-ai/hotcrm#1988reports 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(theisSaasfilter is gone, soflows: allFlows), andobjectstack.composition.ts. -
Surface beyond the claim, accepted: a non-comment line count over the 14 out-of-surface
src/,scripts/ande2e/files gives 0 everywhere, except one message string inscripts/demo-staff.ts. Every edit restates the retired mechanism.README.mdanddocs/STATUS.mdmoved 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,onlyortodo. -
Changeset, after the patch round:
- The claim is scoped to "a new install's first boot".
- The known limit names plugin-security: the seed-ownership claim never runs on a warm boot — seed rows inserted on a later boot (existing admin, in-budget seed) stay ownerless for good objectstack#21486.
- "30 flows, eight of them scheduled" matches
validate's30 Flows. - The upgrade note about the stale
sys_jobrow is measured: Boot D shows it inert, withrun_count0 across a tick while another job ran on the same kernel.
-
Gates: the dev's
pnpm verifyat5e0fe91fendedVERDICT command-exit 0: 174 files, 3,706 tests. CI is 10 of 10successon5e0fe91f. Tokens:src/salesauthored total −890 (business semantics −890), no ceiling moved. -
Noted, not filed:
- The stale
sys_jobrow on upgrade (inert, and the changeset tells operators). - Two comment-only
demo_bootstrapmentions 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.
- The stale
Landing: not governed, so ready → auto-merge → queue.
Generated by Claude Code
- A fresh
- removedpm:dispatchedDispatched to a dev agent by /pm-dispatchDispatched to a dev agent by /pm-dispatch
on Oct 2, 2026
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:flow-schedule:demo_bootstrap*/10 * * * *另有 2 次自该租户首次开机起一直停在
running。demo_bootstrap每次对 12 个crm_*对象各做一次owner_id IS NULL过滤(limit 500)再逐条认领。首轮之后每次都是空操作:sys_automation_run保留的 100 次运行里 selected 合计 100、acted 0。为什么要紧
channels: ['inbox', 'email']通知;未配置邮件的租户,每条通知都产生一条必死的 email 投递行。框架侧会另外处理渠道可用性,这里先知情建议
demo_bootstrap改为一次性:安装 / seed 完成时触发一次,或自检到 ownerless 记录归零后自我停用——不再是常驻 cron验收
demo_bootstrap至多运行到 ownerless 记录归零为止;sys_job中不再保留常驻的*/10调度test/flow-scheduled*.test.ts相应更新并通过Generated by Claude Code