You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
fix: act on a second review round, and correct two earlier claims
The conflict pre-check read block ids from the wrong side. The writer
inserts each block's own `id` field while the check read the record key,
and the two can diverge because preparation copies a value under its key
without reconciling them. Edges already read the value and subflows are
genuinely keyed by the record key, so only blocks were wrong — collecting
every family from the values, as first suggested, would have broken
subflows instead.
A minted API key carrying leading or trailing whitespace passed the
pre-write check but failed the writer, leaving the new endpoint on disk
beside the previous key. It is refused up front now rather than trimmed: a
key is opaque, so trimming would store a value the server never issued and
turn a loud failure into an unexplained 401 later. The endpoint normalizer
does trim, which is what made a padded `--endpoint` fail only after the
browser flow had already minted a key.
A metadata-only secret write raced with deletion returned 500, because the
follow-up read that only assembles the response body threw an unclassified
error; it now reports the same not-found the non-racing miss already gave.
An unusable output format in the environment silently printed a table
instead of refusing. Two validation messages printed control characters
verbatim. A dry run now reports the preparation warnings its own commit
path returns.
The chat route created a titled conversation and never wrote a message, so
it appeared in the Chat list promising content it did not have. Both sides
of a successful turn are now persisted; a failed turn still writes nothing,
so a question is never stored without its answer.
Two claims of mine were wrong. The earlier commit message said `secrets
set` sent an empty value that overwrote the stored secret — it did not; the
prompt refuses off a TTY and rejects empty on one, so the old behaviour was
a clean refusal. And the delay helper commit said this package's idiom is
`node:timers/promises`; the package carries its own `sleep`, which is the
audit's sanctioned home and has five callers. It uses that now.
Also: a test asserting a deadlock stays unclassified could not fail, since
every candidate rejects it; it now pins a unique violation carrying no
constraint name. Workflow ids spelled with the file prefix are corrected in
the remaining fixtures, leaving the genuine file ids alone.
Copy file name to clipboardExpand all lines: apps/docs/openapi-v2-knowledge.json
+1-1Lines changed: 1 addition & 1 deletion
Original file line number
Diff line number
Diff line change
@@ -3481,7 +3481,7 @@
3481
3481
"patch": {
3482
3482
"operationId": "bulkUpdateKnowledgeChunks",
3483
3483
"summary": "Bulk Update Chunks",
3484
-
"description": "Enable, disable, or delete many chunks of one document in a single request. Best-effort: an identifier naming no chunk in the document is skipped rather than failing the request, so `processed` is the authoritative count. Chunks of a connector-synced document are read-only and a write answers `403` with `error.details.code: \"CONNECTOR_MANAGED_RESOURCE_READ_ONLY\"` — change the content at the source and re-sync, or exclude the document from the connector. A workspace API key is rejected with `403`; use a personal API key.",
3484
+
"description": "Enable, disable, or delete many chunks of one document in a single request. Best-effort: an identifier naming no chunk in the document is reported in `errors` rather than failing the request. `processed` counts the chunks the operation matched, not the chunks it changed. Chunks of a connector-synced document are read-only and a write answers `403` with `error.details.code: \"CONNECTOR_MANAGED_RESOURCE_READ_ONLY\"` — change the content at the source and re-sync, or exclude the document from the connector. A workspace API key is rejected with `403`; use a personal API key.",
Copy file name to clipboardExpand all lines: apps/docs/openapi-v2-logs.json
+2-2Lines changed: 2 additions & 2 deletions
Original file line number
Diff line number
Diff line change
@@ -421,7 +421,7 @@
421
421
"get": {
422
422
"operationId": "getLogStats",
423
423
"summary": "Get Log Statistics",
424
-
"description": "Bucketed run counts, success rate, error count, and mean latency for a workspace and for each of its workflows — the aggregate a caller would otherwise have to page every run to compute. The window spans `startDate` through `endDate` when both are supplied; an omitted edge falls back to the oldest matching run on the left and to the later of the newest matching run and now on the right. With no matching runs only the left edge falls back, to 24 hours before that right edge — the trailing 24 hours when neither edge was supplied, and the 24 hours preceding `endDate` when only `endDate` was supplied. A supplied `startDate` is still used verbatim, so a `startDate` without an `endDate` yields `[startDate, now]`, which can be any width. The window is divided into exactly `segmentCount` equal buckets whose width is `max(60000, floor(windowMs / segmentCount))` milliseconds. The one-minute floor is a floor on bucket width, not on the window: when it applies, the series runs past `timeBounds.end` and the trailing buckets are empty rather than the window being compressed. A folder path covers its whole subtree. Per-workflow series are capped and `workflowsTruncated` reports whether the cap applied; the workspace totals are always computed from every workflow. Runs are hard-deleted once they pass the payer's log retention window, so an older run is simply absent rather than reported as removed. The window is 30 days from run start on the free plan, unbounded on Pro and Team, and set per organization on Enterprise with an optional per-workspace override. A workspace folder tree over 10,000 folders is a `413`.",
424
+
"description": "Bucketed run counts, success rate, error count, and mean latency for a workspace and for each of its workflows — the aggregate a caller would otherwise have to page every run to compute. The window spans `startDate` through `endDate` when both are supplied; an omitted edge falls back to the oldest matching run on the left and to the later of the newest matching run and now on the right. With no matching runs the right edge falls back to now and the left to 24 hours before that right edge — the trailing 24 hours when neither edge was supplied, and the 24 hours preceding `endDate` when only `endDate` was supplied. A supplied `startDate` is still used verbatim, so a `startDate` without an `endDate` yields `[startDate, now]`, which can be any width. The window is divided into exactly `segmentCount` equal buckets whose width is `max(60000, floor(windowMs / segmentCount))` milliseconds. The one-minute floor is a floor on bucket width, not on the window: when it applies, the series runs past `timeBounds.end` and the trailing buckets are empty rather than the window being compressed. A folder path covers its whole subtree. Per-workflow series are capped and `workflowsTruncated` reports whether the cap applied; the workspace totals are always computed from every workflow. Runs are hard-deleted once they pass the payer's log retention window, so an older run is simply absent rather than reported as removed. The window is 30 days from run start on the free plan, unbounded on Pro and Team, and set per organization on Enterprise with an optional per-workspace override. A workspace folder tree over 10,000 folders is a `413`.",
425
425
"tags": ["Logs"],
426
426
"parameters": [
427
427
{
@@ -1779,7 +1779,7 @@
1779
1779
},
1780
1780
"required": ["start", "end"],
1781
1781
"additionalProperties": false,
1782
-
"description": "The window the buckets span. `startDate` and `endDate` are used verbatim when supplied; an omitted edge falls back to the oldest matching run on the left and to the later of the newest matching run and now on the right. With no matching runs only the left edge falls back, to 24 hours before that right edge — the trailing 24 hours when neither edge was supplied, and the 24 hours preceding `endDate` when only `endDate` was supplied. A supplied `startDate` is still used verbatim, so a `startDate` without an `endDate` yields `[startDate, now]`, which can be any width."
1782
+
"description": "The window the buckets span. `startDate` and `endDate` are used verbatim when supplied; an omitted edge falls back to the oldest matching run on the left and to the later of the newest matching run and now on the right. With no matching runs the right edge falls back to now and the left to 24 hours before that right edge — the trailing 24 hours when neither edge was supplied, and the 24 hours preceding `endDate` when only `endDate` was supplied. A supplied `startDate` is still used verbatim, so a `startDate` without an `endDate` yields `[startDate, now]`, which can be any width."
Copy file name to clipboardExpand all lines: apps/docs/openapi-v2-workflows.json
+1-1Lines changed: 1 addition & 1 deletion
Original file line number
Diff line number
Diff line change
@@ -437,7 +437,7 @@
437
437
"post": {
438
438
"operationId": "applyWorkflowOperations",
439
439
"summary": "Apply Workflow Operations",
440
-
"description": "Apply a batch of semantic edits — add, edit, delete, and subflow membership changes — to a workflow graph, plus an optional set of block enable/disable changes.\n\nBest-effort per operation, atomic per write. The engine applies what it can to an in-memory graph and reports the rest in `skipped`, each with a machine-readable `type`; exactly one write of the fully-resolved graph then happens, so there is never a partially-applied graph. `deferred` is **not** a failure list: a forward-referencing edge is wired automatically once its target block exists, in this batch or a later one, so re-issuing a deferred edge is wrong.\n\nSet `atomic` to fail closed: any genuine skipped item, or any block input that would be dropped rather than persisted, then aborts before the write and answers `409` with `error.details.code: \"OPERATIONS_NOT_APPLIED\"`, the same `skipped` array, and a `droppedInputs` array, having persisted nothing.\n\nA `block_id` you supply on an `add` or `insert_into_subflow` is only a label unless it is already a UUID: the engine mints one and returns the pairing in `mintedBlockIds`. References between operations in the same batch are remapped for you, so `triage` can be wired up in the same call it is created in — but a later request must use the minted id. Send your own UUIDs when you want an id you chose to survive across requests.\n\nOperation `params` is an open object because the accepted inputs come from the block registry, not from this contract — see the per-operation schemas for the envelope: `inputs` keyed by sub-block id, with `retry`, `triggerMode` and `advancedMode` beside it rather than inside it, and `connections` keyed by source handle. `GET /blocks/{blockId}` publishes the inputs a given block type accepts. The Agent block’s `inputs.tools` value is the important exception to that open catalog shape: it is published here as the named `AgentToolInput` union, covering catalog integrations, workspace custom tools, and MCP tools.\n\n`lint` is advisory and never blocks the write. `lint.fieldIssues` is the most actionable part for a headless builder — it names blocks missing a required field, which fail at run time — and `lint.unresolvedReferences` names credential, resource, tool, and skill values that do not resolve. Those values stay persisted; only `inputValidationErrors` lists inputs that were actually dropped.\n\nAs with `PUT /workflows/{workflowId}/state`, this changes only the draft; deploy to publish it. A workspace API key is rejected with `403`; use a personal API key.\n\nSet `?dryRun=true` to validate and lint without persisting: nothing is written, no audit entry is recorded, and collaborators are not notified. The response carries the same shape and the same validation and `lint` findings the committed write would, with `dryRun: true` — including the same `409` when an id is already owned by another workflow. `needsRedeployment` describes the state before the write, and warnings raised by persistence itself are not reported.",
440
+
"description": "Apply a batch of semantic edits — add, edit, delete, and subflow membership changes — to a workflow graph, plus an optional set of block enable/disable changes.\n\nBest-effort per operation, atomic per write. The engine applies what it can to an in-memory graph and reports the rest in `skipped`, each with a machine-readable `type`; exactly one write of the fully-resolved graph then happens, so there is never a partially-applied graph. `deferred` is **not** a failure list: a forward-referencing edge is wired automatically once its target block exists, in this batch or a later one, so re-issuing a deferred edge is wrong.\n\nSet `atomic` to fail closed: any genuine skipped item, or any block input that would be dropped rather than persisted, then aborts before the write and answers `409` with `error.details.code: \"OPERATIONS_NOT_APPLIED\"`, the same `skipped` array, and a `droppedInputs` array, having persisted nothing.\n\nA `block_id` you supply on an `add` or `insert_into_subflow` is only a label unless it is already a UUID: the engine mints one and returns the pairing in `mintedBlockIds`. References between operations in the same batch are remapped for you, so `triage` can be wired up in the same call it is created in — but a later request must use the minted id. Send your own UUIDs when you want an id you chose to survive across requests.\n\nOperation `params` is an open object because the accepted inputs come from the block registry, not from this contract — see the per-operation schemas for the envelope: `inputs` keyed by sub-block id, with `retry`, `triggerMode` and `advancedMode` beside it rather than inside it, and `connections` keyed by source handle. `GET /blocks/{blockId}` publishes the inputs a given block type accepts. The Agent block’s `inputs.tools` value is the important exception to that open catalog shape: it is published here as the named `AgentToolInput` union, covering catalog integrations, workspace custom tools, and MCP tools.\n\n`lint` is advisory and never blocks the write. `lint.fieldIssues` is the most actionable part for a headless builder — it names blocks missing a required field, which fail at run time — and `lint.unresolvedReferences` names credential, resource, tool, and skill values that do not resolve. Those values stay persisted; only `inputValidationErrors` lists inputs that were actually dropped.\n\nAs with `PUT /workflows/{workflowId}/state`, this changes only the draft; deploy to publish it. A workspace API key is rejected with `403`; use a personal API key.\n\nSet `?dryRun=true` to validate and lint without persisting: nothing is written, no audit entry is recorded, and collaborators are not notified. The response carries the same shape and the same validation and `lint` findings the committed write would, with `dryRun: true` — including the warnings the write’s own preparation step raises, and the same `409` when an id is already owned by another workflow. Only `needsRedeployment` differs: it describes the state before the write.",
0 commit comments