Skip to content
Go to console
Go to console

What v1 is and the names it fixes

Every stack is in sync: Penny rests on a calm quayEvery stack is in sync: Penny rests on a calm quay

What v1 is

v1 is the core loop and what real use asked for around it. The core loop: a scan previews stacks and writes the dashboard, a person ticks a box, exactly that stack deploys, and the row returns to in sync or shows why it failed.

Names fixed for v1

Every name, default and fixed value of v1 in one place. The record in the last column is the authority.

Action inputs and outputs

Name Kind Modes Default Meaning Record
mode input all auto auto, scan, resolve, apply, settle, check or init. auto runs the modes the event asks for in one step; the schedule and a dispatch run resolve before the scan, and a dispatched run that deployed outside records alone skips its scan 0003, 0042, 0065, 0077, 0104, 0109
concurrency input scan one per core, 1 to 8 Size of the preview pool. Without it the pool is the number of cores of the machine, at most 8, and the job log says which 0012, 0085
preview-timeout input scan, apply 10 Time limit for one preview, whole minutes, from when the preview starts 0012, 0035, 0085
strict input scan, auto false Any preview failure turns the job red, after the dashboard is written 0012
github-token input all the workflow token Always the workflow’s own GITHUB_TOKEN 0017, 0035
deployment-id input apply required there The deployment record to deploy 0035
dry-run input apply, auto false A rehearsal: everything up to the hash check, then no deploy. The record ends as inactive, “rehearsed, nothing was deployed” 0051
backend input check, auto false Also ask the backend which of the discovered stacks it holds, with the credentials of the job, and give one ignore block for the ones it does not hold. Refused in every other mode but auto 0074, 0077
pull-request-preview input check, auto false Preview the stacks the pull request claims as they would be after the merge, with the credentials of the job, and write a check run per stack on its head commit. Never deploys, never opens a record, leaves no row. A fork is refused and pull_request_target is never used. Refused in every other mode but auto 0101
deploy-timeout input apply, auto none A time limit on the deploy itself, whole minutes. The tool is interrupted and gets two minutes to stop 0003
env-file input scan, apply, auto, check with backend: true or pull-request-preview: true none A file of NAME=value lines, relative to the checkout or absolute, read once for the tool’s process. Every value is masked first, the file wins over the job environment, and the job log names what it loaded. A warning, and never read, on a step that runs no tool 0100
slack-webhook-url input scan, resolve, apply, auto none A Slack incoming webhook address, from a secret. A warning in any other mode 0078, 0077
telegram-bot-token input scan, resolve, apply, auto none A Telegram bot token, from a secret. Needs telegram-chat-id 0078
telegram-chat-id input scan, resolve, apply, auto none The chat the bot posts to: an id or an @ name 0078
telegram-thread-id input scan, resolve, apply, auto none The topic of a forum group the bot posts to, as message_thread_id. Needs the token and the chat id 0078
webhook-url input scan, resolve, apply, auto none An http or https address, from a secret, that gets { version, event, repository, stacks, dashboard, run, text } 0078
job-id input scan, apply ${{ job.check_run_id }} The id of the running job, for links to its log. Never set by hand 0044
matrix output resolve, scan [] [{ stack, environment, deployment }]. A scan sets one entry after a merge from the dashboard, and one per stack set to on-merge that the scan of a push hands on (slice 5.31). A resolve that no issue edit started sets one per outside record it hands on (slice 5.44) 0035, 0054, 0095, 0109
dashboard-url output scan, apply, settle none Web address of the dashboard issue 0041
pending output scan 0 Number of pending stacks after this scan 0041
preview-failed output scan 0 Number of stacks whose preview failed 0041
in-sync output scan 0 Number of stacks in sync 0041
dashboard-changed output scan false true when this scan wrote a different body, so a notify step can stay quiet otherwise 0041
outcome output apply none deployed, in-sync (nothing to deploy), rehearsed (dry-run), refused (the change moved, the record was not open, or deploys: false) or failed 0041, 0051
stack output apply none The stack id this job handled 0041
result-file output scan, apply none Path under RUNNER_TEMP of a JSON file with what the summary holds: no values, none of the tool’s words 0041

sluiceway.yaml

The file is optional and sits at the repo root. Since slice 5.9 sluiceway.yml is read the same way, and both at once is an error. Unknown keys are an error, because a typo in tickers would change who can deploy.

Key Default Meaning Record
dashboard.title Sluiceway dashboard Issue title, set again by every scan when it differs brief
dashboard.label sluiceway Label the dashboard is found by 0009, 0017
dashboard.pin true Pin the issue on every scan when it is not pinned, best effort —
dashboard.redact false Keep names out of the issue 0023
dashboard.personality true Header image and the voice 0034
dashboard.readOnly false No boxes: pending rows have none, there is no rescan box, and the line under the Pending heading says so. For a workflow that only scans (onboarding log, hurdle 16) 0045
dashboard.showValues [] Property paths whose old and new value may appear, as old → new after the path. Exact paths, * for part of one name. Never a value the tool marks secret, none with redact on. The hash covers a shown value (0008) 0052
dashboard.recentlyDeployed 10 How many lines Recently deployed lists, newest first, failed deploys included. 0 to 50, and 0 leaves the list out 0062
dashboard.timeZone UTC The IANA zone every time on the dashboard is shown in. A time that stands alone ends in its offset from UTC (UTC+2), the line under Recently deployed names the zone, and the markers keep UTC. A name that is not a zone fails the config 0089
dashboard.sections the order of 0063 The order of the sections: deploying, updates, pending, drifted, previewFailed, inSync, recentlyDeployed. The ones named come first, a section left out follows in the default order and is never hidden, a name twice fails the config 0114
dashboard.deployingSection true false moves the deploying and queued rows to one closed fold at the end of the sections, shared by every section that is off. The rows stay in the body 0114
dashboard.driftedSection true false moves the drifted rows to that fold, with no repair all box. A row with a failure line or a resource gone stays open under the heading 0114
dashboard.inSyncSection fold fold, list (every row open) or off (the rows to the fold at the end, no fold of ignored stacks). A row with a failure line stays open 0114
dashboard.zeroCounts true false leaves a count of 0 out of the counts line, except pending 0114
dashboard.destroyAlert destroys always draws a note in the alert’s place when nothing is destroyed. There is no off 0114
dashboard.pendingDetail full compact: the first line, the failure line, the lines of a failed policy, the notes about a tick, every delete and replace line. names: the first line without the preview link, the failure line, the policy’s lead line and every delete and replace line. The marker is the same 0024, 0114
dashboard.deployAll true false draws no deploy all box 0083, 0114
dashboard.repairAll true false draws no repair all box 0083, 0114
dashboard.rescanBox true false draws no rescan box 0114
dashboard.footer true false leaves out the version line, and the rule above it when there is no rescan box either 0114
tickers write Default tick rule: write, maintain, admin or a list of usernames 0018
deploys true false stops every deploy: resolve clears every ticked box with a note, apply ends before the tool runs 0051
recordWriters [] Logins, an app as name[bot], whose open deployment records that name a dispatched or scheduled run are deployed by that run: outside records. The writer is who GitHub records as the creator of the record, never a name in the payload. Empty hands none on 0109
deployWindows [] When the stacks may go out, in the dashboard zone: windows of days (full names, lower case), from and to (HH:MM, 24:00 the end of the day, the end after the start). A tick, a deploy on merge and the deploy after a merge outside every window open their record now and wait for the window; the resolve of a scheduled or dispatched run inside it starts them. Empty is any time 0104
freezes [] Periods when nothing goes out, in the dashboard zone: from and to as YYYY-MM-DDTHH:MM (the end after the start, the end outside), and an optional reason. A tick, a destroy, a deploy on merge and the deploy after a merge during a freeze open their record now, with window, and wait for the end, and for a window after it; no stack entry lifts one. The dashboard names each freeze under the scan line while it holds and for the week before it starts, and the check warns about one that ended 0115
ignore [] Globs matched against the stack id. An entry is a glob, or { glob, reason }, and a stack left out with a reason is listed with it under In sync 0010, 0051
scan.unrelated [] Globs for files that claim nothing and force nothing 0010
scan.logDiff false Print the tool’s own diff of every pending stack, values included, in that stack’s group of the job log and nowhere else 0048
drift.enabled false Check every stack for drift in each scan that a schedule starts or a person starts with Run workflow, and in a push’s scan only for the stacks whose row showed drift. There is no drift.schedule: the loader says the cron goes in the workflow 0055
valueFingerprint true Every pending and drifted row carries a value fingerprint, a hash of the values its diff holds that the row does not show, and apply compares it after the diff hash: a value that changed since the tick stops the deploy. A value the tool marks secret enters as its mark. Off for a repo whose programs make values that differ on every run 0102
policies [] Directories or files of Rego policies, relative to the repo root, that the preview document of every pending stack is tested against with Conftest, which the workflow installs. A policy that fails takes the box off the row until it passes and stops a deploy on merge. Empty runs nothing 0106
phases [] Names of phases in deploy order. A stack in a phase depends on every stack in every earlier phase 0067
cost.enabled false Estimate what each pending change of an OpenTofu or Terraform stack costs a month with the Infracost CLI the workflow installs, over the plan’s JSON the preview made, and show it on the row as a change to the monthly bill. The CLI sends resource types, regions and quantities to its pricing API, never a value or a credential. Other tools get no line, a failed estimate is a missing line and never a red scan, and the cost is not in the diff hash 0105
cost.threshold none The change to the monthly bill above which a stack set to on-merge waits for a tick, in the currency of the estimate, and its row says why. A failed estimate waits too. Needs cost.enabled 0105
stacks[].path required per entry Directory of the stack, relative to the repo root 0006
stacks[].name none Name of the stack. Without it the entry covers every stack in path 0006
stacks[].tool none opentofu, terraform, helm or kubectl: the entry declares a stack of that tool at path, because files alone cannot name one 0053, 0058, 0060, 0068
stacks[].id the derived id The id of the one stack the entry covers, in place of the one derived from its path and name, so a stack that moved keeps its row and its deploys. Unique among every stack id 0006
stacks[].environment sluiceway Label on the deployment record, and the GitHub Environment where one is used 0003
stacks[].tickers the top level value Tick rule for this stack 0018
stacks[].inputs [] Extra globs this stack claims 0010
stacks[].previewTimeout the input Time limit for this stack, whole minutes 0012, 0035
stacks[].dependsOn none Stack ids this stack depends on, or auto: the stacks its Pulumi program reads through stack references, read at each preview and carried on the row. A tick waits while one of them is pending and not ticked, ticks in one chain deploy one layer per run 0056, 0059
stacks[].phase none One of phases, or { from: <key> }: the text under that key of the stack’s Pulumi project file, under config or at the top level. The stack depends on every stack in every earlier phase, and dependsOn adds to that 0067
stacks[].deployWindows the top level value The windows of the stacks of this entry, in place of the top level ones. [] lets them go out at any time 0104
stacks[].deploy on-tick on-tick: the stack deploys when a person ticks its row. on-merge: it deploys by itself after the scan of a push to the default branch found it pending, through the path of a tick, attributed to whoever pushed. A delete or replace, drift, deploys: false, a read-only dashboard, any other scan and a dependency that waits for a tick keep it waiting for a tick, and its row says why 0095
stacks[].drift.enabled the top level The drift check on or off for the stacks of this entry, in the same scans as drift.enabled 0059
stacks[].valueFingerprint the top level The value fingerprint on or off for the stacks of this entry 0102
stacks[].envFile none A file of NAME=value lines, relative to the checkout or absolute, that the tool gets for the stacks of this entry alone, on top of the job environment and the step’s env-file. Every value is masked first, the file is read once per job, and a file that cannot be loaded fails the preview of these stacks and no other 0103
stacks[].policies [] Policy paths for the stacks of this entry, on top of the top level policies 0106
stacks[].createInBackend false true: a scan creates each Pulumi stack of the entry that the backend lacks, with pulumi stack init right before its first preview, and previews it as all creates. A deploy never creates a stack. Refused on an entry with tool 0107
stacks[].cost.enabled the top level The cost estimate on or off for the stacks of this entry 0105
stacks[].cost.threshold the top level The threshold of the stacks of this entry, in place of the top level one. Needs the estimate on for them 0105
stacks[].options {} Named adapter options, only with tool. OpenTofu and Terraform: workspace, varFiles and wrapper (terragrunt or cdktf). Helm: release, namespace, chart, version (a chart reference only), valuesFiles and createNamespace. kubectl: context, namespace, recursive, prune, forceConflicts and fieldManager 0006, 0015, 0053, 0058, 0060, 0068, 0069, 0070
discovery.rootModules true Find OpenTofu and Terraform root modules from their files: not a local module source of another directory, not under modules/, a backend or cloud block, one workspace, no var file that chooses, and a lock file or .tofu files that name the tool. Each is one stack in the default workspace with its path as its id. A directory a stacks entry with a tool names stays the entry’s. discovery is a mapping of switches that the adapters name, and an unknown one fails the config 0092
attribution.lookback 100 How many of the newest commits a job walks for attribution, 1 to 1,000, one GraphQL page per 100 0026, 0072
attribution.names 5 How many pull requests and direct pushes a row and a shipped line name before the rest is a count, 0 to 20 0026, 0072
mergeAndDeploy.authors [] Logins whose green pull requests are listed to merge and deploy with one tick, one deploy per stack that claims them. Empty turns it off 0054, 0064, 0071
notify.events [pending, drift, failed, refused] The events a notification is sent on, to each channel the step’s inputs name: pending (stacks newly pending after a scan), drift (newly drifted), deployed, failed, refused (a tick that deployed nothing). A channel is never a key here 0078
mergeAndDeploy.preview false Preview each listed update as it would be after the merge and show the counts on its row: one extra preview per stack of each of the oldest 30 updates, never for a fork 0071

Rules for config loading:

  • A stacks[] entry adds settings to stacks that discovery found. It never creates a stack, except an entry with tool, which declares one (0053) and takes its directory over from root module discovery (0092). An entry that matches no discovered stack is a config error.
  • A tickers entry with a slash fails with the message that teams are not supported yet (0018).
  • No key is reserved now. A reserved key fails with a message that says it is not in this version yet, and is never ignored. (dependsOn was one until slice 4.4, 0056, a top level drift until slice 4.3, 0055, and stacks[].drift until slice 4.7, 0059.)
  • The JSON schema is generated from the Zod schema into schema/sluiceway.schema.json, committed, and checked in CI the way dist/ is.

Fixed strings and numbers

What Value Record
Bot github-actions[bot], type Bot 0017
Deployment task sluiceway:<stack id> 0003
Deployment payload { "v": 1, "hash", "ticker", "run" }, plus "drift": true when the approved hash covers drift, and since slice 5.9 "attempt", the attempt of the run that created the record. behind on a queued record (0056), merge in place of hash on a merge record (0054), onMerge (0095), fingerprint, the value fingerprint the tick approved (0102), window on a record that waits for the deploy window (0104) or the end of a deploy freeze (0115). Since slice 5.33 the schema is schema/deployment-payload.schema.json, and every payload is checked against it before it is written 0003, 0055, 0044, 0096
Default environment label sluiceway 0003
Concurrency groups The one-step workflow: sluiceway-${{ github.event.issue.number }} with queue: max. The split workflow: sluiceway-scan, and sluiceway-resolve and sluiceway-apply-<stack id> with queue: max 0004, 0025, 0035, 0077, 0123
Dispatch input of the scan after a merge sluiceway-merged, the merged pull request numbers joined with commas, sent only to a workflow that declares it 0064
Marker version 1 0009
Row states pending, deploying, in-sync, preview-failed, queued since slice 4.4, and drift since slice 4.3, with the marker key drift="true" on a row whose hash covers drift, and since slice 4.7 depends-on="<ids>" on a row of a stack with dependsOn: auto, and since slice 5.37 fingerprint="<16 hex>", the value fingerprint, on a pending or drifted row whose diff holds values the row does not show, and since slice 5.54 busy="true" on a preview-failed row of a stack whose lock another update held, and since slice 5.56 drift-check="failed" on a row whose drift check failed 0009, 0055, 0056, 0059, 0102, 0117, 0121
Diff hash SHA-256 of the canonical document, first 16 hex characters 0008
Value fingerprint SHA-256 of the hidden values of a change, and of the change fingerprints of a row, first 16 hex characters each; a secret enters as {"path":p,"secret":true} 0102
Body target, hard limits 58,000 characters, 65,536 characters, 262,144 bytes 0028
Summary budget 1,000,000 bytes 0037
Preview page A check run named sluiceway / <stack id>, completed, neutral, its text cut on a line at 65,535 bytes. Needs checks: write 0050
Write loop at most 3 tries 0004
Second try of a failed preview once, after one pause of 10 seconds a scan. The job log shows the tool’s last 20 lines under a preview that did not work 0117
Lookback, names on a row, recently deployed 100 commits, 5, 10, the defaults of attribution.lookback, attribution.names and dashboard.recentlyDeployed 0026, 0029, 0062, 0072
Minimum Pulumi CLI v3.229.0 0001
Minimum OpenTofu CLI v1.11.0 0053
Minimum Terraform, Terragrunt and cdktf CLIs terraform v1.14.0, terragrunt v1.0.0, cdktf v0.21.0 0068
Minimum Helm CLI and diff plugin helm v3.18.0, helm-diff v3.15.11 0058
Minimum kubectl CLI v1.34.0 0060
Minimum Conftest, for a repo with policies v0.50.0 0106
Infracost CLI, for a repo with cost.enabled the open source 0.10 line, recorded with v0.10.45. No floor is checked: a failed estimate is a missing line, never a red scan 0105
Minimum self-hosted runner v2.328.0, no ARM32 —
API budget 1,000 requests per hour per repo 0017
GitHub API version 2026-03-10, in X-GitHub-Api-Version on every request, set once in src/github/client.ts (slice 5.47) 0017