Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,8 @@ bun run reset
```

`bun run reset` drops the platform database schema and removes the hub's
and the dev sidecar's on-disk asset directories — everything boot-time
on-disk asset directory (which also holds provisioned sidecar state) —
everything boot-time
seeding and onboarding created. Nothing is re-seeded until the next `bun
run dev` — that recreates the schema and, once the hub is serving again,
reprovisions and re-seeds the root tenant from scratch, landing you at a
Expand Down
4 changes: 2 additions & 2 deletions docs/local-rip.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,8 @@ bun run dev
`bun run dev` and its boot-time seeding created — skip it on a
genuinely fresh checkout. `bun run dev` validates `.env`, confirms
`DATABASE_URL` is reachable, applies pending migrations, builds the web
UI, seeds the administrator account, and starts the hub, one sidecar, and
the web dev server together — the hub then provisions and seeds the root
UI, seeds the administrator account, and starts the hub and the web
build — the hub then provisions and seeds the root
tenant itself once it is serving (see
[README.md](../README.md#running-locally) for exactly what it checks).
Leave `ANTHROPIC_API_KEY` unset in `.env` for
Expand Down
27 changes: 15 additions & 12 deletions packages/chat-ui/test/use-typing-indicator.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,11 @@ import type { TypingState } from "../src/typing-indicator";
const sleep = (ms: number) => new Promise((resolve) => setTimeout(resolve, ms));

// Long enough that real event-loop jitter can't flip a "before expiry" /
// "after expiry" assertion; short enough to keep the suite well under a
// second even so.
const TEST_TIMEOUT_MS = 120;
// "after expiry" assertion — CI runners under load have been observed to
// stretch a single await by well over 100ms, so every "before expiry"
// margin below is a quarter of the expiry or better. Short enough to keep
// the suite around two seconds even so.
const TEST_TIMEOUT_MS = 500;

function mount(
selfPrincipalId: string | undefined,
Expand Down Expand Up @@ -77,19 +79,20 @@ describe("useTypingIndicator (real timer wiring)", () => {

test("a second ping re-arms the expiry rather than doubling timers", async () => {
const harness = mount("prn_self1", "chan_a");
harness.ping("prn_other1"); // t=0, would expire at t=120 unless re-armed
harness.ping("prn_other1"); // t=0, would expire at t=500 unless re-armed

await harness.settle(50); // t=50
harness.ping("prn_other1"); // re-armed: now expires at t=170
await harness.settle(150); // t=150
harness.ping("prn_other1"); // re-armed: now expires at t=650

// t=140 — past the original (unarmed) expiry at 120 with a 20ms
// margin, but well before the re-armed one at 170. Still showing here
// only makes sense if the re-arm actually took effect.
await harness.settle(90);
// t=400 — past the original (unarmed) expiry at 500 would be a
// failure of the re-arm, and it is still 250ms before the re-armed
// expiry at 650. Still showing here only makes sense if the re-arm
// actually took effect.
await harness.settle(250);
expect(harness.get()?.principalId).toBe("prn_other1");

// t=210 — past the re-armed expiry at 170 with a 40ms margin.
await harness.settle(70);
// t=800 — past the re-armed expiry at 650 with a 150ms margin.
await harness.settle(400);
expect(harness.get()).toBeNull();
harness.unmount();
});
Expand Down
5 changes: 2 additions & 3 deletions scripts/reset.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,10 +41,9 @@ describe("requireLocalDatabase", () => {
});

describe("resolveLocalStateDirs", () => {
test("resolves the hub dir against apps/hub and the sidecar dir at the repo root", () => {
test("resolves the hub dir against apps/hub", () => {
const dirs = resolveLocalStateDirs("/repo", ".data/hub");
expect(dirs.hubDataDir).toBe(path.resolve("/repo/apps/hub/.data/hub"));
expect(dirs.sidecarDataDir).toBe(path.resolve("/repo/.data/sidecar"));
});

test("honors an absolute HUB_DATA_DIR", () => {
Expand Down Expand Up @@ -98,7 +97,7 @@ describe("resetLocalState", () => {
]);
});

test("reports no removed directories when neither is present", async () => {
test("reports no removed directories when it is not present", async () => {
const deps: ResetDeps = {
root: "/repo",
resetSchema: async () => undefined,
Expand Down
22 changes: 10 additions & 12 deletions scripts/reset.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,9 @@
// onboarding flow: drops the platform schema (database, auth tables,
// every installed package's tables, and the db-setup ledger all live
// in the same schema, so one drop clears them all) and removes the
// on-disk directories the hub and the dev sidecar keep durable repo
// and asset state in.
// on-disk directory the hub keeps durable repo and asset state in.
// Provisioned sidecar state lives under the hub data dir, so the hub
// reset covers it.
//
// Refuses outright against a non-local DATABASE_URL — there is no
// override. A schema drop is unrecoverable, and this script exists for
Expand Down Expand Up @@ -46,19 +47,16 @@ export function requireLocalDatabase(databaseUrl: string): void {
}

/**
* The on-disk directories a local `bun run dev` checkout keeps durable
* The on-disk directory a local `bun run dev` checkout keeps durable
* state in: the hub's `HUB_DATA_DIR` (resolved the same way the hub
* itself resolves it — against `apps/hub`'s working directory) and the
* dev sidecar's data directory, which `scripts/dev.ts` always pins to
* `.data/sidecar` at the repo root regardless of `SIDECAR_DATA_DIR`.
* itself resolves it — against `apps/hub`'s working directory).
*/
export function resolveLocalStateDirs(
root: string,
hubDataDir: string,
): { hubDataDir: string; sidecarDataDir: string } {
): { hubDataDir: string } {
return {
hubDataDir: path.resolve(path.join(root, "apps", "hub"), hubDataDir),
sidecarDataDir: path.join(root, ".data", "sidecar"),
};
}

Expand All @@ -82,10 +80,10 @@ const defaultDeps: ResetDeps = {
};

/**
* Drop the platform schema and remove the on-disk asset directories,
* Drop the platform schema and remove the on-disk asset directory,
* leaving a checkout in the same state as a fresh clone with `.env`
* already filled in. `bun run dev` recreates the schema and the
* directories on its next start.
* directory on its next start.
*/
export async function resetLocalState(
env: Record<string, string | undefined>,
Expand All @@ -98,7 +96,7 @@ export async function resetLocalState(

const dirs = resolveLocalStateDirs(deps.root, config.hubDataDir);
const removedDirs: string[] = [];
for (const dir of [dirs.hubDataDir, dirs.sidecarDataDir]) {
for (const dir of [dirs.hubDataDir]) {
if (!deps.exists(dir)) continue;
await deps.rm(dir, { recursive: true, force: true });
removedDirs.push(dir);
Expand Down Expand Up @@ -128,7 +126,7 @@ if (import.meta.main) {
`reset: dropped the platform schema in database ${JSON.stringify(report.database)}`,
);
if (report.removedDirs.length === 0) {
console.log("reset: no on-disk asset directories were present");
console.log("reset: no on-disk asset directory was present");
} else {
for (const dir of report.removedDirs) {
console.log(`reset: removed ${dir}`);
Expand Down
Loading