flaky: LitestreamReplicator 'a failed launch releases its lock probe, so the next acquire starts a sidecar' fails by timing in verify-build
typed-secrets 4.4: persistence and resume hold references: rehydration stops reading the vault, every persisted copy uses the persisted form, and run events are masked
data_writer_property_test: a secret holding a newline and a literal backslash-n escapes the persisted-content property (seed 1648929202)
typed-secrets: the accessor adapter reads a legacy row stamped with the empty namespace as foreign, so its tagged fields stay reference text on the typed path
typed-secrets query view: route a row's JSON content by whether the adapter adapted the record, not by the service's namespace rule
flaky: for_each_name_property_test lets the text around a sentinel equal the secret's value, so the untyped value search replaces both and the property fails by seed
typed-secrets 4.3: the expression-facing query view registers Secret in DataQueryService
CEL duration arithmetic is off by a second when a duration has negative nanos (cel-js 7.6.1)
typed-secrets 4.2: live and reconstructed step outputs and child outputs return references through the accessor adapter
A coded UserError a model method throws reaches a workflow step without its code, because InProcessExecutor keeps only the message
Dashboard Workflows page takes ~19s on a serve with many extension workflows: workflow.search resolves each workflow's owner with a full extension-workflow scan
codegen: BROKEN_REGEXES override for the @swamp/aws/invoicing InvoiceUnit name lacks the u flag, so it rejects ordinary names
dashboard: run page polling stacks history.get and history.logs requests while serve is slow
serve: add child spans and attributes to workflow.history.get (and run_summary/run_search) to diagnose slow dashboard loads
serve: webhook-triggered workflow runs can't be cancelled — cancel can't find them, so it reports serve's own pid as "the process running it is still alive"
A workflow step fails on a static validation error in a method it does not invoke, where swamp behavior run of the same method succeeds
serve: a run orphaned by a container restart can't be cancelled — the restarted serve reuses the dead owner's pid, so cancel reports the owner still alive
typed-secrets 4.6: turn the typed path on for every entry point, remove the internal option, and delete the regular-expression rewrite, the value search and the plaintext resolution of tagged fields
typed-secrets 4.5: the inline resolutions refuse or mask: placement, task selectors, child references and deferred targets refuse secrets, assert messages mask them, and the deprecated resolvers go
typed-secrets 4.1: workflow passes bind sentinels as Secrets: typed guards and asserts, forEach items and identities, child bindings, webhook inputs, and the synchronous authorization step
typed-secrets 3.5: local entry points, validation diagnostics, context.runModel and model.method delivery
model.method in a workflow guard fails with 'Do not know how to serialize a BigInt' when its inputs hold an int
data query: filter on data lifecycle so deleted resources can be excluded
CEL expression results that hold a timestamp, duration or uint become an empty object
Catalog rebuild restores pre-rename versions of a name renamed away and written again
Remote resolveSecret allowlist is always empty for workflow steps that use vault.get
swamp issue redacts git commit SHAs as secrets and fast-check replay paths as IP addresses
typed-secrets 3.4: destination refusals, identifier stand-ins, shell safety and masking
Remote readResource does not apply the legacy schema fallback for untagged sensitive records
Flaky: datastore_v3_outbox_model_property_test throws MayLandLaterError on a random seed (aged commit, failed discard-and-mark checkpoint, power cut)
v3 outbox model property test fails: a commit dropped after a failed append-discard-and-mark reports MayLandLaterError instead of the expected outcome
Workflow step dataOutputOverrides vaultName is accepted but silently dropped
typed-secrets 3.3: sensitive-field accessors, data-origin sentinels and reference validation
Generated vault keys carry raw data-name and vary characters that strict vault providers reject
typed-secrets 3.2: vault.get as a CEL function, bare-token rewriting, AST extraction and up-front existence checks
typed-secrets 3.1: the production Secret, its refusals, the fault context, the container rule and the boundary conversion, behind the internal option
Flaky test: extension_pull_dependency_conflict_test fails with 'failed to copy esbuild binary' during deno bundle
Extension tarball analyzer ignores webhook entry points
Registry drops contentMetadata.extensions (method grafts) at confirm-push
digitalocean codegen leaves an orphaned security_secret.ts model file after its endpoint left the spec
A --repo-dir or SWAMP_REPO_DIR through a symlink fails with 'unable to open database file'
@swamp/1password: vault delete of a missing item probably fails instead of being a no-op
@swamp/1password: item or vault names containing 'authorization' are misreported as auth failures
typed-secrets 2.2: VaultSecretBag entries hold references, one registry per run, 128-bit sentinels
Show wait keys and pending signals to remote clients and the dashboard
Flaky: LitestreamReplicator.acquire 'concurrent acquires in one process share one sidecar and one hold' fails 'no hold leaked' under full-suite load
VaultService.requireExistenceProvider labels the vault instance name as its type
VaultService capability errors label the vault instance name as its type
typed-secrets 2.1: VaultExistenceProvider, its conformance suite, and has on the built-in providers
MockVaultProvider.get and delete throw synchronously instead of rejecting
typed-secrets 1.2: pin the Secret Proxy, refusal set and container rule on cel-js 7.6.1
issue-lifecycle: pr_merged and ship report success and advance the phase when swamp-club is unreachable, writing nothing upstream
serve check-config crashes with a TypeError when a list-valued auth key is a string
access grant list --server shows user subjects as user:user:<name>
Flaky: process_bundle_prober_test 'stopping a host that has already exited lists no children under its pid' fails under full-suite load
typed-secrets 0.4: characterize worker secret authorization and control-plane secret traffic
issue-lifecycle: an approved plan cannot be sent back to planning
typed-secrets 1.2: minimal opaque Secret, CelVaultNamespace receiver, policy inventory and evaluation frame
typed-secrets 1.1: commit the cel-js 7.6.1 probe harness as pinned behavior tests
typed-secrets 0.1: land the typed-secrets plan as a design enabler doc
swamp update: a slicker, colorful download progress bar that ends with a newline
gcs-datastore: a failed lock read is reported as "unlocked" — #2298 in the GCS backend
A manual worker verify racing an enrollment probe can leave a healthy worker unverified until it reconnects
bundle freshness: a one-off deno info failure leaves a source on the in-directory fallback for good
serve shutdown waits for an unsignalled run index rebuild: the continuation sweep's boot pass and request-led rebuilds cannot be stopped by SIGTERM
serve: handlers that sanitize an error for the client never log the original, so path-bearing failures are undiagnosable
literal() output in a step's inputs logs repeated Refusing to evaluate expression warnings
Read non-string sensitive resource fields back with their type
serve and swamp dashboard shutdown waits seconds for the run index warm-up: the plain index parse is not abortable, and the warm-up waits on request-led loads it joined (regression from #3105)
Run index snapshot cache keeps serving a stale run status: ctime is only second-resolution so in-place same-size rewrites alias the stamp, and snapshots are cached even when repair could not write the index (regression from #3105)
Flaky: serve_v3_extension_lockfile_test 'serve extension.pull commits the new entry' fails under full-suite load with extension_pull_failed
Run index repair-by-stat misses an in-place, same-size record rewrite that restores mtime within the same second as its entry: ctime is reported in whole seconds
Dashboard: an idle, visible tab keeps counting runs that have aged out of a preset time range
Dashboard: Models and a model's page re-send model.output.search every minute on a preset time range
Concurrent run writers leave finished runs stuck as running in the run index: repairIndex returns early once counts agree, so lost updates are never healed (regression from #3105)
Run index updates race across processes: concurrent writer processes can lose each other's index entry updates
Dashboard: a live run page polls a full workflow.run.search every 2.5 s, and time-range presets refetch the run summary every minute
Dashboard Workflows, workflow and run pages are slow with large history: workflow.run.summary and workflow.run.search read every run index of every workflow on each request
README, design docs and agent-constraints examples still teach swamp model commands
Decide and add behavior spellings for --model flags, enum values and SWAMP_MODELS_DIR outside the behavior tree
Telemetry records swamp behavior and swamp model invocations under different command names
swamp behavior help, hints and root help still say model in places
A new or edited extension source is imported at startup, so one that exits, hangs or prints at import breaks every command
Workflow step arguments pass any unknown ${{ }} root through; limit pass-through to known foreign roots
A worker that fails its enrollment probe becomes idle and schedulable in memory
A global argument that evaluates to swamp-namespace expression text is silently dropped, and literal() cannot pass it through
Flaky test: AccessDataPoller "a grant created by a real method run through A stays staged on A and reaches B" fails under full-suite load
WorkerGateway.dispatch leaks a capacity slot when recording the busy status fails
vault type search shows an extension vault type under its type id with no description, and cannot find it by name or description
literal() output is refused in a direct step globalArgs, so foreign ${{ }} text has no escape there
serve: a run whose crashed owner was reaped by a peer stays running on the restarted owner
workflow resume refuses a wait that has an applicable pending signal
Accept early signals through swamp serve
datastore namespace list --json reports a corrupt .namespace.json as an unexpected exception with a stack trace
signal_test fails on main: a signal by key handed over by the sweep is not answered taken
datastore namespace migrate treats the repo-local catalog as user data: it cannot be re-run, resumed, or reversed after a read
A signal by key can be answered pending or taken when that is not what happened to it
swamp serve lists every wait-key record on each continuation pass once any pending signal has lapsed
model method run --timeout exits 0 and prints nothing when the timeout cancels the run
Cross-namespace data.* reads return empty attributes in model method run and workflow run
Hold a signal that arrives before its wait opens
swamp-uat: the SIGTERM drain test does not check that the run succeeded
A running dispatch counts twice against worker capacity, so a --concurrency 2 worker queues a step while it has a free slot
data.latest("otherns:model", name) returns the caller's own record when a local model has that name
Record-typed arguments are not JSON-parsed from plain key=value, unlike array and object arguments
swamp model cancel <model> cancels a run of a different model of the same type and reports it under the named model
serve HA: worker enrollment on a replica that lacks the enrollment token's definition may create a second definition (unverified)
Deliver a signal by key through swamp serve
A garbled nested run record crashes a parent resume with a YAML stack trace
Cancel, reject and supersede of a parent run should settle its suspended nested child runs
workflow recover misjudges whether an unknown step is guarded: forEach iterations read as unguarded, and a same-named step in another job is matched
A log line with a closing brace but no opening brace prints the brace doubled
Signal a wait by workflow and key
manual_approval timeout is never enforced on a forEach-expanded gate
workflow run reports a forEach-expanded approval gate as waiting on a nested run
Let a wait_for_signal step declare a key held by one open wait at a time
Show signal waits to remote clients and the dashboard
extension source add imports src/cli/mod.ts, so every change lists extension as an affected command
Show expired approval gates as expired, with a Cancel action in the dashboard
Lazy hydration: content readers bypass hydration (stream, stale raw after append); add one ensuring read path and a fitness test
Lazy hydration: expressions reading another model's data get empty attributes; hydrate a step's read set before evaluation
Tell timeouts apart from cancels in method-run records, and review the hidden 30 s fallback timer for step-called model methods
Settle expired signal waits from swamp serve
serve never continues a signalled run after a manual resume re-entered its open wait
Resume signalled workflow runs automatically under swamp serve
audit verify is hidden by accident: auditCommand.hidden() in mod.ts hides the last subcommand, not audit
swamp help --json: emit aliases, hidden commands, and whether an option takes a value
GCS datastore: implement fetchContent, a read of one remote file that writes nothing locally
S3 datastore: implement fetchContent, a read of one remote file that writes nothing locally
serve: token secret migration repoints a token even when copying its OAuth access token failed
Extension quality check output carries ANSI codes when FORCE_COLOR is set
datastore setup can overwrite an existing remote config tier when it moves an in-repo tier into an extension datastore
Datastore sync: read one remote file without writing it to the local cache (fetchContent)
A cancelled shell step can fail with a lock timeout instead of reporting as cancelled
Docs: document DatastoreSyncService.fetchContent in the datastore provider reference
datastore lock release gives the wrong reason when the lock file is caught mid-write
A nested structural swamp that outlives the run that started it keeps skipping that run's lock while the holder writes
Flaky test: WalSink pruning the queue under a hung downstream keeps the checkpoint delivered segments wait on
A lock file read during its holder's heartbeat rewrite is treated as no lock
Record the commands affected by a change in the verification attestation
Deliver workflow signals through swamp serve
A nested structural swamp still waits on its run's lock when the lock holder is not a same-host ancestor (cross-host worker, --server into a non-ancestor serve)
Deliver workflow signals through a write-once outcome record instead of writing the run record
Forward held-lock identity over --server so a loopback nested swamp does not wait on its caller's lock
A nested structural swamp on a same-host remote worker waits on its own step's lock held by swamp serve
Fail fast when nested structural commands under parallel runs wait on each other's locks
Docs: remove followUpActions from the MethodResult reference in the extension model manual
signal_test: already-settled test fails by chance when a random UUID spells the sender name
Add a wait_for_signal workflow step that pauses a run for a JSON message
run doctor through serve interrupts a live run of another serve instance when no heartbeats are recorded
Flaky test: WalSink replayed segments are delivered before events written after replay leaves one WAL segment
Remove followUpActions: no model or extension can produce them
Workflow schedule watcher and workflow edit symlink lookup ignore the managed config workflows dir
main is red: repository_dirty_coverage_test fails for UnifiedData.collectGarbage(orphaned deferred write)
Relationships
#3136 serve: token secret migration repoints a token even when copying its OAuth access token failed
Opened by zack · 10/7/2026· Shipped 10/8/2026
Description
migrateOne in src/serve/token_secret_migration.ts copies a token's OAuth access token from the user vault to _token-secrets inside a catch that treats any failure as a missing key. It then repoints the record's vaultName to _token-secrets regardless. If the read failed for a transient reason and the key survives in the user vault (the vault has no delete, or the delete also fails), the token is left half migrated: its record names _token-secrets but its OAuth access token is only in the user vault.
Since the fix for swamp-club#3127 (PR 2896), the collective refresh no longer falls back to the user vault for a record that names _token-secrets. Such a token is therefore never refreshed. A userinfo 401 no longer revokes it, so a deprovisioned user's token stays active until it expires. The boot log reports the token as migrated and nothing is logged above debug.
Steps to reproduce
Observed end to end on a build of commit 362a1ce1 with a file-backed test vault that has no delete support.
- Mint a server token whose record names a user vault, and put its oauth-access-token key in that vault.
- Make reads of oauth-access-token keys in that vault fail, then start serve in OAuth mode so the boot migration runs.
- Restore the vault and make the provider return 401 from userinfo for that user.
- Wait for a collective refresh cycle. No userinfo call is made and the token stays active.
Expected
A key that is present but fails to copy should not be treated as absent. List the vault first, as migrateOAuthSecrets does, and skip the repoint and delete for that token so the next start retries.
Exposure
OAuth-login tokens live 30 days by default and the migration shipped on 2026-08-04, so this needs an older token kept alive by rotation, or a direct upgrade from a build before swamp-club#1511, plus a vault fault during migration. Records an older build already left in this state are affected too.
Shipped
Click a lifecycle step above to view its details.