Uh oh!
There was an error while loading. Please reload this page.
Make the demo seed opt-in, default off, and add pnpm demo - #88
Conversation
Duly is meant to be a general product, and a general product does not install 459 rows of a fictional manufacturer's org chart into every fresh deployment. Someone evaluating Duly for their own company wants an empty app to put their own duties into; someone evaluating the idea wants the demo. Those are two intentions, and now they are two commands. - `src/data/index.ts` gates the whole demo array on `DULY_DEMO_SEED`. Off means genuinely empty, not "empty of users". - `scripts/demo.mjs` (`pnpm demo`) sequences the two boots this needs on a brand-new database and VERIFIES the handover with a real sign-in, so a half-finished run fails loudly instead of looking like it worked. - Both `dev` and `demo` boot with `--compile`: the gate is read at compile time and `os dev` otherwise reuses whichever artifact is on disk. - `test/demo-seed-opt-in.test.ts` fails if the default path stops being empty; `test/seed.test.ts` now opts in explicitly. - README documents the two commands as first-class choices. The login bug on a clean `git clone && pnpm dev` falls out of this for free: with no `sys_user` rows in the default seed the database is zero-user at `kernel:ready`, so `plugin-auth` mints the dev admin exactly as documented. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01SqkTcrxUFci7nqXdbBSe2p
os-warren
commented
Sep 1, 2026
Reviewed — and I ran the acceptance myself, from empty data directories. Merging.This card hid for a whole round because a reused
A clean Gates on the head merged with current The finding beyond the scope is the one that would have sunk this
Two more things worth recording:
And the ablation note about the first mutation attempt is the most useful paragraph in the report: mutating
Noted on the report-marker sanitization — GitHub ate the HTML comment. Not worth another attempt; the second comment is legible. Generated by Claude Code |
Uh oh!
There was an error while loading. Please reload this page.
Fixes#73
Implements the five-item scope adjudicated on the card.
Duly is meant to be a general product, and a general product does not install 459 rows of a fictional manufacturer's org chart into every fresh deployment. Someone evaluating Duly for their own company wants an empty app to put their own duties into; someone evaluating the idea wants the demo. Those are two intentions, and now they are two commands. The login bug on a clean
git clone && pnpm devfalls out of that for free — with nosys_userrows in the default seed the database is zero-user atkernel:ready, soplugin-authmints the dev admin exactly as documented.What changed
dulySeedson an explicit opt-in, default off, genuinely emptysrc/data/index.ts— the demo array is exported asdemoSeeds, anddulySeedsisdemoSeedRequested() ? demoSeeds : []. The gate wraps the whole array rather than filtering rows, so "off" is empty, not "empty of users".pnpm demo, working on a clean checkout in one commandscripts/demo.mjs+package.json. Boots once quietly with the flag off, verifies the handover with a real sign-in, stops, then boots with the flag on in the foreground.README.md— a two-row table under Quick start, no mention of the platform interaction.test/demo-seed-opt-in.test.ts(12 cases).test/seed.test.tsnow opts in explicitly.src/data/index.ts, including what collapses when it lands:pnpm demobecomes a single boot, and the gate stays.Two things worth a reviewer's attention
Both
devanddemonow boot with--compile. The seed is baked intodist/objectstack.jsonat compile time, andos dev's--compiledefaults to false — it auto-compiles only when the artifact is missing. Without this,pnpm demo's second boot would serve the artifact its own priming boot just built (the one with no seed) and print success over an empty app; and apnpm devafter apnpm demowould serve the demo artifact, so the default would not be a default. Measured: default build →0 datasets / 0 rowsin the artifact;DULY_DEMO_SEED=1build →10 datasets / 459 rows.The handover is verified, not assumed.
scripts/demo.mjspollsPOST /api/v1/auth/sign-in/emailagainst the priming server until it returns 200, rather than watching for a log line or sleeping. A seeded database with no login is worse than the bug it replaces because it looks like it worked, so the failure path is loud, names the remedy, and never reaches the second boot.Verification
Every run below deleted
.objectstack/data(anddist/) immediately before booting, since a directory that already holds a minted admin makes both paths look fine whatever the code says — the exact mistake that hid this for a round. Servers ran on ports 3173-3175; port 3000 belongs to another agent.Acceptance —
pnpm devon an empty databaseAcceptance —
pnpm demoon an empty database, one command273 read back against 459 declared is the expected shape, not a shortfall: the two
mode: 'update'backdate passes re-walk the same 186 task rows (273 + 186 = 459), which is whattest/seed.test.tshas always asserted.Reverse verification — the new guard actually goes red. Gate mutated on disk to
export const dulySeeds: Seed[] = demoSeeds;(drift back into the default path), confirmed on disk by grep before running (gated=0 drift=1), restored by anEXITtrap. No rebuild is involved: both suites read the TypeScript sources, andseed.test.tsalready pointsartifactPathat a file that cannot exist so nodist/artifact is ever loaded. Result —9 failed | 33 passed, all nine indemo-seed-opt-in.test.ts;seed.test.tsstayed green, which is the correct direction (the demo still lands, it is only the default that broke). Tree verified clean afterwards (0 modified).Reverse verification — the loud failure path.
scripts/demo.mjsmutated to a 20s priming budget and a--no-seed-adminpriming boot, so no admin can ever be minted:Worth recording: the first attempt at this mutated only the environment (
OS_SEED_ADMIN=0) and the handover succeeded —os devsetsOS_SEED_ADMINitself in itsservechild from its own--seed-adminflag, so a parent-side value never reachesplugin-auth. That is an ineffective mutation that reads as a pass; the mutation had to move onto the spawn arguments.Gates, all four on the pushed commit
b2df2ae, after the reverse verifications had been restored (tree: 0 modified):The one
validatewarning is the expectedhierarchy-securitycapability-provider notice AGENTS.md says not to silence.Deliberately not included
No changeset. This repo has no changeset mechanism — no
.changeset/in the tree or anywhere ingit log --all, no@changesets/*dependency, no script, no mention inAGENTS.md. Adding one would mint a mechanism nothing reads.Generated by Claude Code
Generated by Claude Code