diff --git a/.beads/issues.jsonl b/.beads/issues.jsonl
index 6a801ba..a7b04c0 100644
--- a/.beads/issues.jsonl
+++ b/.beads/issues.jsonl
@@ -13,6 +13,7 @@
{"_type":"issue","id":"islandflow-ayo","title":"Drop stale backlog events from live fanout","description":"Follow-up to live freshness rollout: /ws/live was still fanning out stale backlog events for freshness-gated channels, which kept tape panes in Live feed behind despite active synthetic ingest. Gate fanout and cache ingest by freshness for options/nbbo/equities/flow.","status":"closed","priority":1,"issue_type":"bug","assignee":"dirtydishes","owner":"dishes@dpdrm.com","created_at":"2026-04-28T21:26:39Z","created_by":"dirtydishes","updated_at":"2026-04-28T21:26:44Z","started_at":"2026-04-28T21:26:44Z","closed_at":"2026-04-28T21:26:44Z","close_reason":"Completed","dependency_count":0,"dependent_count":0,"comment_count":0}
{"_type":"issue","id":"islandflow-0v6","title":"Fix tape freshness, NBBO coverage, pause controls, and filter popup","description":"Implement the tape fixes requested for synthetic options notional sizing, strict live freshness, live-mode pause/resume behavior, stronger NBBO snapshot coverage, and moving flow filters behind a popup. Includes server-side live cache changes, web terminal state/UI changes, and tests for synthetic pricing, live snapshot freshness/NBBO retention, and live pause/filter interactions.","status":"closed","priority":1,"issue_type":"task","assignee":"dirtydishes","owner":"dishes@dpdrm.com","created_at":"2026-04-28T21:02:52Z","created_by":"dirtydishes","updated_at":"2026-04-28T21:13:38Z","started_at":"2026-04-28T21:02:57Z","closed_at":"2026-04-28T21:13:38Z","close_reason":"Completed","dependency_count":0,"dependent_count":0,"comment_count":0}
{"_type":"issue","id":"islandflow-e4r","title":"Implement smart-money flow filtering and synthetic firehose modes","description":"Implement the approved multi-surface plan for named synthetic market profiles, options raw-vs-signal filtering, live/API filter contracts, Tape page client-side flow filters, firehose-readiness improvements, tests, and README updates.","status":"closed","priority":1,"issue_type":"feature","assignee":"dirtydishes","owner":"dishes@dpdrm.com","created_at":"2026-04-28T20:10:49Z","created_by":"dirtydishes","updated_at":"2026-04-28T20:29:29Z","started_at":"2026-04-28T20:10:53Z","closed_at":"2026-04-28T20:29:29Z","close_reason":"Implemented synthetic market profiles, options signal-path filtering, signal-aware API/replay contracts, Tape page filters, tests, and README updates. Follow-up tracked in islandflow-biq.","dependency_count":0,"dependent_count":0,"comment_count":0}
+{"_type":"issue","id":"islandflow-xod","title":"Add --fast mode to deploy helper","description":"Why: full main deploys rebuild all images and run full verification, which is slow for routine rollouts. What: add a --fast flag to scripts/deploy.ts with explicit behavior that short-circuits slow steps while preserving basic safety checks; update help text/docs for discoverability.","status":"closed","priority":2,"issue_type":"feature","assignee":"dirtydishes","owner":"dishes@dpdrm.com","created_at":"2026-05-18T02:50:47Z","created_by":"dirtydishes","updated_at":"2026-05-18T02:53:41Z","started_at":"2026-05-18T02:50:50Z","closed_at":"2026-05-18T02:53:41Z","close_reason":"Closed","dependency_count":0,"dependent_count":0,"comment_count":0}
{"_type":"issue","id":"islandflow-cif","title":"hydrate alert evidence context from clickhouse","description":"Implement alert detail hydration from ClickHouse with a new context endpoint and frontend drawer evidence resolution. Includes storage lookup by alert trace_id/evidence refs, unresolved refs diagnostics, API route GET /flow/alerts/:trace_id/context, terminal evidence hydration + loading states/copy updates, and tests across storage/api/web.","status":"closed","priority":2,"issue_type":"feature","assignee":"dirtydishes","owner":"dishes@dpdrm.com","created_at":"2026-05-18T00:15:55Z","created_by":"dirtydishes","updated_at":"2026-05-18T00:17:38Z","started_at":"2026-05-18T00:16:00Z","closed_at":"2026-05-18T00:17:38Z","close_reason":"Closed","dependency_count":0,"dependent_count":0,"comment_count":0}
{"_type":"issue","id":"islandflow-4e9","title":"Polish terminal view","description":"Improve the Islandflow web terminal view with a focused UI polish pass aligned to the product design system.","status":"closed","priority":2,"issue_type":"task","assignee":"dirtydishes","owner":"dishes@dpdrm.com","created_at":"2026-05-17T15:18:18Z","created_by":"dirtydishes","updated_at":"2026-05-17T15:25:02Z","started_at":"2026-05-17T15:18:21Z","closed_at":"2026-05-17T15:25:02Z","close_reason":"Polished terminal shell styling, responsive Tape actions, and documented the turn.","dependency_count":0,"dependent_count":0,"comment_count":0}
{"_type":"issue","id":"islandflow-lyt","title":"Summarize 2026-05-16 git activity for standup","description":"Create a grounded standup summary for yesterday's git activity, anchored to commits, changed files, and any linked PR context if present. Produce the required HTML document in docs/general and complete the beads + git handoff workflow.","status":"closed","priority":2,"issue_type":"task","assignee":"dirtydishes","owner":"dishes@dpdrm.com","created_at":"2026-05-17T14:02:57Z","created_by":"dirtydishes","updated_at":"2026-05-17T14:05:37Z","started_at":"2026-05-17T14:03:09Z","closed_at":"2026-05-17T14:05:37Z","close_reason":"Created docs/general standup summary for 2026-05-16 git activity, grounded to commits and changed files, and prepared the repo handoff workflow.","dependency_count":0,"dependent_count":0,"comment_count":0}
diff --git a/deployment/docker/README.md b/deployment/docker/README.md
index 0f5c886..2b167da 100644
--- a/deployment/docker/README.md
+++ b/deployment/docker/README.md
@@ -271,6 +271,7 @@ Examples:
./deploy main --runtime docker --web-only
./deploy main --runtime docker --api-only
./deploy current-branch --runtime docker --services-only
+./deploy main --runtime docker --fast
./deploy main --runtime docker --web-only --no-build
```
@@ -279,6 +280,7 @@ Scoped Docker deploys now build only the selected image set and then restart onl
- `--web-only`: `docker compose build web`, then `docker compose up -d web`
- `--api-only`: `docker compose build api`, then `docker compose up -d api`
- `--services-only`: builds and restarts `api`, `compute`, `candles`, `ingest-options`, and `ingest-equities`
+- `--fast`: when no explicit scope flag is given, treats the deploy as `--services-only` and skips the public API route suite for quicker completion. It still runs remote service health checks.
Use `--no-build` only when the image is already correct and you need Compose to recreate or restart containers, such as after changing server-side environment values that do not affect a Next.js build-time variable. Do not use `--no-build` for dependency changes, application source changes, or `NEXT_PUBLIC_*` changes.
diff --git a/deployment/native/README.md b/deployment/native/README.md
index 03c5bf7..a9903cc 100644
--- a/deployment/native/README.md
+++ b/deployment/native/README.md
@@ -75,6 +75,7 @@ Examples:
./deploy main --runtime native --web-only
./deploy main --runtime native --api-only
./deploy current-branch --runtime native --services-only
+./deploy main --runtime native --fast
./deploy main --runtime native --web-only --no-build
```
@@ -84,6 +85,7 @@ Scope behavior:
- `--web-only`: rebuild/restart only the web unit
- `--api-only`: restart only the API unit
- `--services-only`: restart API + backend units without touching the web unit
+- `--fast`: when no explicit scope flag is provided, uses the same `--services-only` scope and trims verbose verification output for quicker completion
- `--no-build`: skip `bun install --frozen-lockfile` and skip the web build step
## Current status
diff --git a/docs/turns/2026-05-17-add-fast-deploy-mode.html b/docs/turns/2026-05-17-add-fast-deploy-mode.html
new file mode 100644
index 0000000..94493cd
--- /dev/null
+++ b/docs/turns/2026-05-17-add-fast-deploy-mode.html
@@ -0,0 +1,137 @@
+
+
+
+
+
+ Turn Report: Add --fast Deploy Mode
+
+
+
+
+
+ Added --fast mode to deploy helper
+ Date: 2026-05-17 · Repo: islandflow · Task: make ./deploy main faster for routine rollouts
+
+ Summary
+
+ Added a new --fast flag to ./deploy so operators can run a quicker deploy profile without manually combining multiple flags. In fast mode, default full-scope deploys switch to backend-services scope and skip expensive public route-suite checks.
+
+
+ Changes Made
+
+ - Updated
scripts/deploy.ts to parse and advertise --fast.
+ - Added effective-scope logic so
--fast + default scope behaves like --services-only.
+ - Adjusted verification behavior in fast mode:
+ - Skipped Docker log tail dump during remote verification.
+ - Skipped verbose native
systemctl status / journalctl output.
+ - Skipped public API route suite (
scripts/check-public-api-routes.ts) in fast mode.
+ - Documented fast mode in
deployment/docker/README.md and deployment/native/README.md.
+
+
+ Context
+
+ The default ./deploy main path is intentionally thorough and safe, but it can be slow because it rebuilds multiple service images and runs full verification. Fast mode provides an explicit, opt-in speed profile for routine operations.
+
+
+ Important Implementation Details
+
+ Fast mode does not silently alter explicitly requested scopes. It only remaps scope when the caller leaves scope at default full-stack.
+
+ function effectiveScope(scope: DeployScope, fast: boolean): DeployScope {
+ if (fast && scope === "full") {
+ return "services";
+ }
+ return scope;
+}
+
+ Public verification now keeps behavior explicit. In fast mode, it logs why API route checks were skipped and points operators to DEPLOY_PUBLIC_API_HEALTH_URL if they want a public API probe.
+
+
+ Expected Impact for End-Users
+
+ Internal operators should see noticeably faster deploy completion in common backend-first rollouts. End-user-facing impact is indirect: faster operational iteration and quicker server refreshes when web changes are not required.
+
+
+ Validation
+
+ - Ran
bun run scripts/deploy.ts --help to validate CLI parsing/help output for the new flag.
+ - Ran full test suite with
bun test (pass, 232 passing tests).
+
+
+ Issues, Limitations, and Mitigations
+
+ --fast intentionally reduces verification depth; it is not equivalent to the full rollout safety envelope.
+ - Fast mode defaults away from web rollout on full scope, so web changes should use explicit web/full scope deploys.
+ - Mitigation: behavior is opt-in, surfaced in help text, and documented in deployment READMEs.
+
+
+ Follow-up Work
+
+ - No immediate follow-up required for this change.
+ - Optional future work: add an automatic changed-path-to-scope mapper to choose the smallest safe build set without operator guesswork.
+ - Beads issue:
islandflow-xod (this task).
+
+
+
+
+
diff --git a/scripts/deploy.ts b/scripts/deploy.ts
index d78db01..70e54e1 100644
--- a/scripts/deploy.ts
+++ b/scripts/deploy.ts
@@ -13,6 +13,7 @@ type DeployOptions = {
mode: DeployMode;
runtime: DeployRuntime;
scope: DeployScope;
+ fast: boolean;
forceRecreate: boolean;
noBuild: boolean;
};
@@ -69,9 +70,9 @@ const repoRoot = path.resolve(path.dirname(scriptPath), "..");
function usage(exitCode = 1): never {
console.error(`Usage:
- ./deploy main [--runtime docker|native] [--web-only|--api-only|--services-only] [--no-build] [--force-recreate]
- ./deploy current-branch [--runtime docker|native] [--web-only|--api-only|--services-only] [--no-build] [--force-recreate]
- ./deploy current branch [--runtime docker|native] [--web-only|--api-only|--services-only] [--no-build] [--force-recreate]
+ ./deploy main [--runtime docker|native] [--web-only|--api-only|--services-only] [--fast] [--no-build] [--force-recreate]
+ ./deploy current-branch [--runtime docker|native] [--web-only|--api-only|--services-only] [--fast] [--no-build] [--force-recreate]
+ ./deploy current branch [--runtime docker|native] [--web-only|--api-only|--services-only] [--fast] [--no-build] [--force-recreate]
Modes:
main Deploy origin/main to the live server checkout.
@@ -89,6 +90,7 @@ Scopes:
Options:
--runtime Explicit runtime selector (docker or native).
+ --fast Prefer a quicker rollout profile (defaults full scope to --services-only and skips public API route suite).
--no-build Skip docker image builds or native bun install/web build steps.
--force-recreate Docker-only escalation path for docker compose when a normal refresh is not enough.
--help Show this help text.
@@ -218,11 +220,13 @@ function parseArgs(rawArgs: string[]): DeployOptions {
const runtime = parseRuntime(rawArgs);
const scope = parseScope(rawArgs);
+ const fast = rawArgs.includes("--fast");
const forceRecreate = rawArgs.includes("--force-recreate");
const noBuild = rawArgs.includes("--no-build");
const positional = rawArgs.filter(
(arg, index) =>
arg !== "--force-recreate" &&
+ arg !== "--fast" &&
arg !== "--no-build" &&
arg !== "--web-only" &&
arg !== "--api-only" &&
@@ -238,7 +242,7 @@ function parseArgs(rawArgs: string[]): DeployOptions {
}
if (positional.length === 1 && positional[0] === "main") {
- return { mode: "main", runtime, scope, forceRecreate, noBuild };
+ return { mode: "main", runtime, scope, fast, forceRecreate, noBuild };
}
if (
@@ -249,6 +253,7 @@ function parseArgs(rawArgs: string[]): DeployOptions {
mode: "current-branch",
runtime,
scope,
+ fast,
forceRecreate,
noBuild
};
@@ -302,6 +307,13 @@ function describeScope(scope: DeployScope): string {
}
}
+function effectiveScope(scope: DeployScope, fast: boolean): DeployScope {
+ if (fast && scope === "full") {
+ return "services";
+ }
+ return scope;
+}
+
function scopeIncludesWeb(scope: DeployScope): boolean {
return scope === "full" || scope === "web";
}
@@ -649,14 +661,16 @@ function remoteRollout(
remoteNativeRollout(mode, branch, scope, noBuild);
}
-function remoteDockerVerification(scope: DeployScope): void {
+function remoteDockerVerification(scope: DeployScope, fast: boolean): void {
const psServices = dockerServicesForScope(scope);
const logServices = dockerLogServicesForScope(scope);
const psCommand =
psServices.length > 0
? `docker compose ps ${psServices.join(" ")}`
: "docker compose ps";
- const logCommand = `docker compose logs --tail=100 ${logServices.join(" ")}`;
+ const logCommand = fast
+ ? `echo '[deploy] Fast mode: skipping docker compose logs tail for quicker feedback.'`
+ : `docker compose logs --tail=100 ${logServices.join(" ")}`;
const checks: string[] = [];
if (scopeIncludesApi(scope)) {
@@ -684,7 +698,7 @@ ${checks.join("\n")}
);
}
-function remoteNativeVerification(scope: DeployScope): void {
+function remoteNativeVerification(scope: DeployScope, fast: boolean): void {
const units = nativeUnitsForScope(scope).map((value) => shellEscape(value)).join(" ");
const checks: string[] = [];
@@ -704,26 +718,29 @@ set -euo pipefail
declare -a units=(${units})
for unit in "\${units[@]}"; do
${NATIVE_SYSTEMCTL_PREFIX} is-active --quiet "$unit"
- ${NATIVE_SYSTEMCTL_PREFIX} status --no-pager "$unit" || true
- journalctl -u "$unit" -n 50 --no-pager || true
+ ${fast ? "echo \"[deploy] Fast mode: skipping unit status and recent journal dump for $unit.\"": `${NATIVE_SYSTEMCTL_PREFIX} status --no-pager "$unit" || true\n journalctl -u "$unit" -n 50 --no-pager || true`}
done
${checks.join("\n")}
`
);
}
-function remoteVerification(runtime: DeployRuntime, scope: DeployScope): void {
+function remoteVerification(runtime: DeployRuntime, scope: DeployScope, fast: boolean): void {
if (runtime === "docker") {
- remoteDockerVerification(scope);
+ remoteDockerVerification(scope, fast);
return;
}
- remoteNativeVerification(scope);
+ remoteNativeVerification(scope, fast);
}
-function publicVerification(scope: DeployScope): void {
+function publicVerification(scope: DeployScope, fast: boolean): void {
section("Public Verification");
- runChecked("curl", ["-I", "-fksS", PUBLIC_APP_URL]);
+ if (!fast || scopeIncludesWeb(scope)) {
+ runChecked("curl", ["-I", "-fksS", PUBLIC_APP_URL]);
+ } else {
+ console.log("[deploy] Fast mode: skipping public app HEAD check because web scope is not included.");
+ }
if (scopeIncludesApi(scope) && PUBLIC_API_HEALTH_URL) {
runChecked("curl", ["-fksS", PUBLIC_API_HEALTH_URL]);
@@ -731,29 +748,39 @@ function publicVerification(scope: DeployScope): void {
}
if (scopeIncludesApi(scope)) {
+ if (fast) {
+ console.log(
+ "[deploy] Fast mode: skipping scripts/check-public-api-routes.ts route suite. Set DEPLOY_PUBLIC_API_HEALTH_URL to keep a public API health probe in fast mode."
+ );
+ return;
+ }
runChecked("bun", ["run", "scripts/check-public-api-routes.ts", PUBLIC_APP_URL]);
}
}
function main(): void {
const options = parseArgs(process.argv.slice(2));
+ const scope = effectiveScope(options.scope, options.fast);
assertSshKeyExists();
printRuntimeAdvisory(options.runtime);
console.log(
`Deploying ${options.mode === "main" ? "origin/main" : "the current local branch"} ` +
- `via ${describeRuntime(options.runtime)} (${describeScope(options.scope)}).`
+ `via ${describeRuntime(options.runtime)} (${describeScope(scope)}${options.fast ? ", fast mode" : ""}).`
);
+ if (options.fast && options.scope === "full") {
+ console.log("[deploy] Fast mode changed default full scope to --services-only.");
+ }
if (options.mode === "main") {
localMainPrecheck(options.runtime, options.noBuild);
remoteGitPrecheck();
- remoteRuntimePrecheck(options.runtime, options.scope);
+ remoteRuntimePrecheck(options.runtime, scope);
remoteRollout(
options.mode,
options.runtime,
null,
- options.scope,
+ scope,
options.forceRecreate,
options.noBuild
);
@@ -762,19 +789,19 @@ function main(): void {
localBranchPrecheck(branch, options.runtime, options.noBuild);
publishCurrentBranch(branch);
remoteGitPrecheck();
- remoteRuntimePrecheck(options.runtime, options.scope);
+ remoteRuntimePrecheck(options.runtime, scope);
remoteRollout(
options.mode,
options.runtime,
branch,
- options.scope,
+ scope,
options.forceRecreate,
options.noBuild
);
}
- remoteVerification(options.runtime, options.scope);
- publicVerification(options.scope);
+ remoteVerification(options.runtime, scope, options.fast);
+ publicVerification(scope, options.fast);
}
main();