Repository navigation
Rust #325: record local activities like Server 2.11.1 - #766
Conversation
… 2.11.1 Raw workers complete workflow tasks with record_local_activity commands: the advertised local_activities contract and registration agreement, the protocol floor, capability and ownership gates, transport, scope and normalizer refusals, a success after a retried attempt, a failure after retries and a timeout, and the protocol 1.18 shape without attempts. History payloads, the run's activity view and status are recorded with identities as case-keeping labels and attempt times as offsets from each close. Recorded three times, identical. One published defect is bounded: transport validation reorders a nested report whose first entry lacks an optional field, so the normalizer refuses it as unordered.
Native now serves the record_local_activity workflow task command (worker protocol 1.18 and newer) as published Server 2.11.1 does with Workflow 2.10.2: - It advertises the local activity contract in server_capabilities and lists the command among the supported workflow task commands. Prepared local activities stay unadvertised, with no groups and no cancellation policies. - The portable worker affinity guard runs first, then the command normalizer's field, outcome, attempt and payload rules with PHP's messages. - The bridge records the activity's execution, attempts, history and failure under one authored sequence. - The run's activity view and attempt status follow Workflow 2.10+: each attempt carries failure_reason, and an expired attempt keeps a recorded lease loss as its stop reason. One published defect is not reproduced: PHP's validated() rebuilds a nested report in rule order, so a report whose first attempt lacks an optional field is refused as unordered. The record-local-activity fixture bounds that difference. The 2.5.22 activity metadata corpus predates the attempt failure_reason. Its test now requires that field to be null (no corpus case records a lease loss) and compares the rest as recorded. A payload unit test now expects PHP's final message for a completed record, whose missing-result check replaces the resolver's message under the same key. Native passes the record-local-activity fixture recorded from published 2.11.1, along with the capability-sensitive fixtures (cluster-info, admission, worker listing, namespaces, worker replacement). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…-activity # Conflicts: # .github/workflows/server-parity.yml
…-activity Conflicts with #745 resolved as unions. Capabilities advertise both the local-activity manifest and message streams. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…nto rust-325-record-local-activity The worker capability manifest keeps this branch's local activity entries and main's worker session and update validation entries. The comparator, probe and node test lists keep both sides' fixtures and tests. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Security exact-head review of
I found no local-activity external-payload prefetch/SSRF path at this head: external preparation selects only |
The record-local-activity fixture was recorded on SQLite, so each local
activity event's workflow task snapshot names the sqlite connection. On
the PostgreSQL and MySQL corpus lanes that snapshot names pgsql or mysql,
the backend that recorded it, and the contract compared the name exactly.
It now requires one known storage connection per observation and compares
it as {connection}. Every other step still compares exactly.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
New head: On The contract now requires a single known storage connection per observation and compares it as 🤖 Generated with Claude Code |
|
Security review of the exact The delta changes only the record-local-activity comparator and its unit test. It replaces a backend-local The two availability blockers in comment 6401983037 remain merge blockers. Workflow #930 must first ship the package-owned timing and whole-completion admission contract, then this PR must port and qualify it on SQLite, PostgreSQL, and MySQL. Current hosted matrix jobs were still running when I checked, so this is not full-head merge acceptance. |
|
All 56 checks pass at exact head 🤖 Generated with Claude Code |
Native applies phase A of Workflow #930 (Workflow PR #934) to record_local_activity and to every workflow task completion: - record_local_activity caps duration_ms and heartbeat elapsed_ms at 7 days and backoff_seconds at 1 day, with the package's field errors. The walk back from completion is summed with checked arithmetic and refused with local_activity_timestamp_out_of_range before it reaches the earliest timestamp every supported column stores. - After a run's deadline close, which is never metered, the local activities' exact events and rows (other commands at one event) are checked against DW_V2_LIMIT_HISTORY_TRANSACTION_SIZE and _ROWS, and a completion past them is refused with completion_budget_exceeded. - The rest of the completion runs under a meter. Each history event charges one event, its HistoryBudget bytes and two rows, and each local activity row is charged before it is written. A refusal answers history_transaction_limit_exceeded and rolls back, leaving the lease. A tripped meter also refuses the commit. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…-record-local-activity # Conflicts: # .github/workflows/server-parity.yml
|
Native port of Workflow #930 Phase A, ready for review. It mirrors the rule Security accepted and that was merged as Workflow #934 ( The exact commit is What it does, in
Tests
Local results at
Known gaps: the doc's entry records that native is ahead of published 2.11.1 here. Operator metrics' structural-limit snapshot stays as 2.11.1 reports it until the PHP Server takes the Workflow release. |
|
Security review of exact backup commit This candidate now reads and enforces configurable Consequently, a server configured with another event ceiling—or with the check disabled—reports 5,000 anyway, and neither of the other two enforced hard ceilings is inspectable. Operators cannot explain a This is the native counterpart of finding 4 on Workflow #934. Its accepted Phase A source added all three values to Before promotion, publish the active configured values (0 when disabled) in the configured and effective structural-limit views, including the health and nested backend-capability surfaces. Add controls with three distinctive non-default values plus disabled values, so a hard-coded/default snapshot cannot pass. Preserve backend-specific adjustments without replacing the active ceilings. No Rust tests were run on the lab host. This finding is from exact-source comparison with the merged Workflow Phase A contract. |
|
Second exact-commit blocker on
and their The missing primary names are therefore reported as unknown Before promotion, register all three as This is separate from the incomplete structural-limit runtime snapshot in the prior comment: fixing telemetry alone would still leave documented non-default configuration unable to start under the supported strict audit mode. |
|
Third exact-commit promotion blocker on bbc6025: the original aggregate-budget acceptance matrix is not yet represented by the native controls. The completion_budget execution module proves an exact event boundary (4 admitted, 7 refused) and an exact row boundary (9 refused, 10 admitted). Its byte control uses one arbitrary 4,000-byte refusal followed by a smaller unrelated completion; it does not prove the exact byte boundary and one-over behavior. The local helper uses a small fixed argument and 200-character heartbeat details, so it does not exercise the reported large-valid-argument plus heartbeat amplification. On refusal, the byte test compares history and counts only activity_executions and activity_attempts; it does not prove that every durable sibling/projection table remains unchanged. The PostgreSQL/MySQL handoff reports the same focused eight tests, so repeating them on three backends does not fill those semantic gaps. The original Security requirement in comment 6401983037 was exact-boundary and one-over coverage for events, rows, and serialized history bytes on SQLite, PostgreSQL, and MySQL; a large valid argument plus heartbeats; and proof that refusal leaves the lease and all durable rows unchanged. Please add that matrix before promotion. Derive the byte boundary from the same PHP-compatible event measurement used by the meter so the control cannot pass by relying on an incidental 4,000-byte estimate. Snapshot all completion-owned durable tables before and after the refused request, then prove the same lease succeeds with an admitted request. This evidence gap is independent of the runtime-snapshot and config-audit blockers already recorded. No Rust tests were run on the lab host. |
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…d-local-activity # Conflicts: # .github/workflows/server-parity.yml # docs/rust-server-port.md
Security's review of 6676720: - events() now orders the projected events from their boundary, time and source order alone, then builds, encodes and counts one event at a time. The first event past DW_V2_LIMIT_HISTORY_TRANSACTION_BYTES stops the build before it is kept or any later event is built. TooLarge reports how many events were built, and a test-only counter proves an early over-limit event builds none of the thousands after it. - history_rows is removed from this change: #766 adds it with its enforcement, audit and disclosure. - The no-write snapshots count every table of the test database, workflow_links included. - A lock barrier control holds each backend's transition lock while the projection's install waits on it: an append then finds no instance and writes nothing, and once the install commits an append is refused. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…d-local-activity
…snapshot helpers Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The byte matrix's large completion (a ~270 KB argument and 20 heartbeats) failed on MySQL 8.0 with "Out of sort memory": the run summary projection pages history with SELECT ... CAST(payload AS CHAR) ... ORDER BY sequence LIMIT 16, and MySQL may answer it with a filesort that carries a whole row; one large payload exceeds the default 256 KiB sort buffer and fails the completion with 503 storage_unavailable. The query now forces the workflow_run_id/sequence index, as the history page query already does. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…d-local-activity
|
Answer to Security's three holds on
New exact commit: It contains #768 (merged locally at 1. The snapshot publishes the active limits
Control:
2. The config audit honors all three
Control: strict mode starts with all three primary names set. The legacy names produce exactly the two deprecation warnings and nothing else. No enforced setting is ignored or unknown. The port doc's counts are reconciled: PHP's 164 contract settings, of which native honors 49, ignores 51 and refuses 64 non-default values. Native also honors 3. The acceptance matrix
A MySQL defect the matrix foundOn MySQL 8.0, the large completion failed with The run summary projection pages history with This defect exists independently of the budget: before this fix, any completion on MySQL with one history event larger than the sort buffer failed the same way. Local qualification at
|
|
Security exact-successor review of backup commit One byte-budget bypass remains before promotion. Build the terminal attribution into the payload before This is source-only review; no Rust build or runtime action was performed on the lab or development VPS. Promotion/full-head acceptance remains held on this correction, exact hosted evidence, and the separately recorded #768 SQLite interleaving blocker. |
A completed or failed run's terminal event is recorded, charged, and then rewritten to name the worker that completed the task. That growth was never charged, so a completion admitted at the exact byte limit could store more history than the limit allows. The attribution's growth is now charged before the update, measured on the same stored payload before and after, so nothing is charged twice. Controls for WorkflowCompleted and WorkflowFailed admit the stored terminal history at its exact size and refuse it one byte short; both fail without the charge. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…d-local-activity
|
Answer to #766 (comment). New exact commit:
Fix.
Controls, for both terminal events (
With the charge removed, both controls fail. Local qualification at this commit
|
|
Security exact-successor review — source boundary only. Reviewed backup-ref merge The terminal-attribution metering blocker from comment 6405437415 is materially closed:
This closes Security's source-level change request. It is not merge acceptance yet: PR #766 still points at |
|
|
Hosted qualification at exact head
SonarCloud decision. The quality gate is OK, with no bugs, vulnerabilities or hotspots. Sonar reports three
They are the native ports of Splitting these functions risks changing the order in which field errors are produced, and that order is what the parity fixture compares. I'm accepting the notes for this change. A later refactor can split them by rule group behind the existing fixture and unit tests. |
|
Exact-head receipt for #766, as Security asked in chat 1870. Tree identity
Hosted runs at
Check-run rollup for the commit: 57 success and 1 skipped (path-inapplicable), with none failing or pending. The merge state is clean. The MySQL large-probe path
|
|
Merged as
Native now serves Next in #325: cancellation scopes. |
…llation-scopes # Conflicts: # .github/workflows/server-parity.yml # rust/src/runtime/store.rs
…-operations Conflicts kept both sides: the parity contract, probe and workflow test list now carry the Nexus operations and record_local_activity entries together. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ust-325-bridge-adapters Conflicts kept both sides: the router, delegates, modules, parity contract, probe and workflow test list carry bridge adapters with the workflow imports and record_local_activity. The port guide counts 141 served route methods: bridge webhooks add one and the two imports two to the base 138. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>



Part of #325. Native now serves the
record_local_activityworkflow task command (worker protocol 1.18+) the way published Server 2.11.1 does with Workflow 2.10.2.What changes
server_capabilitiesand lists the command among supported workflow task commands. Prepared local activities stay unadvertised, with no groups and no cancellation policies.attempt_idis stored only asworker_attempt_idmetadata and is never resolved as a reference.failure_reason, and an expired attempt keeps a recorded lease loss as its stop reason.Completion budget (Workflow #930, phase A)
Security held this PR until the package bounded completions. Workflow #934 (merged as
4eb49a20) set that rule, and native now applies it.duration_msand heartbeatelapsed_msare capped at 7 days andbackoff_secondsat 1 day, each with the package's field error. The walk back from completion is overflow-checked, and refused withlocal_activity_timestamp_out_of_rangebefore it reaches the earliest storable timestamp.DW_V2_LIMIT_HISTORY_TRANSACTION_SIZEand_ROWS. A completion past either is refused withcompletion_budget_exceeded._BYTES) and two rows. Each local activity row is charged before it is written.history_transaction_limit_exceeded, writes nothing and keeps the lease. A tripped meter also refuses the commit.config_audithonors them, with their legacy aliases.Every Security finding along the way is answered in this PR's comments; the final source acceptance is #766 (comment).
Fixture
tests/Fixtures/ServerParity/record-local-activity.jsonwas recorded three times from published 2.11.1, with identical results. Raw workers cover:One published defect is bounded rather than reproduced. PHP's
validated()rebuilds a nested report in rule order, so a report whose first attempt lacks an optional field is refused as unordered.Qualification at
7f57016eThis head is main through #768. Its tree (
b85f11f7) is the Security-accepted tree of backup commit3f6a388c.cargo test --lib --test executionpasses, lib 306 and execution 519.completion_budgetpasses 10/10, including the event, row and byte exact/one-over matrix and both terminal attribution controls.local_activities,structural_limitsandwaterline_projection_guardspass too.The 2.5.22 activity metadata corpus predates
failure_reason. Its test now requires that field to be null, since no corpus case records a lease loss, and compares the rest as recorded.🤖 Generated with Claude Code