Repository navigation
Message stream appends are accepted on read-only Waterline v1 projections #769
Description
Published Server 2.11.1 accepts a message stream append to a read-only Waterline v1 projection.
Behavior. POST /api/workflows/{workflowId}/message-streams/{streamName}/messages (MessageStreamController::append, MessageStreamService::append) never checks whether the instance's current run is a Waterline v1 projection (import_source = waterline_v1_projection). For a projection in an open status (pending, running or waiting), a valid append:
- creates the inbound stream and item;
- delivers a signal with its command and history event;
- creates a workflow task for a run whose execution is owned by the v1 runtime.
An invalid body still records malformed-input state on the projection's stream.
Why it matters. Every other run operation refuses a projection with v1_projection_read_only before reading its body (WorkflowController::rejectProjectedV1Operation / projectedV1OperationResponse: signal, query, update, cancel, terminate, repair, archive, redrive). The append path breaks the projection's read-only, no-tasks contract, and gives workers an execution path into a v1-owned run.
Expected. The append is refused with 409 v1_projection_read_only before the body is parsed. The service also checks under its lock, so a direct call cannot write any stream, item, signal, command, history, task or summary state. Malformed input is not counted against a projection.
Native. Server #768 (Rust #325) adds that refusal at the route and the service, plus a locked check in the store transaction. Its tests show valid and invalid appends, a direct service call and a direct store call change no rows. That will differ from published 2.11.1 until PHP is fixed.
Found by Security's review of #768. Handed to the General owner for the PHP fix.
Current implementation
Cloud's PHP implementation merged in PR #812 on October 28 at 03:55:17 UTC as 5b8bc4d7e856354f3b8fa152c91284e62fd82e40. All 43 Shared jobs, PHP feature qualification and public-boundary qualification passed on the actual cumulative commit.
Focused source qualification passed 43 tests / 992 assertions on both SQLite and MySQL 8.0.46. The previous implementation and former full-event byte meter fail the new controls. The published CLI 2.3.1 HTTP qualification passed 128 checks across all seven projection statuses, including dry run, idempotence, read-only/no-write refusal and independently calculated persisted canonical-byte totals. These remain source-qualification results.
Qualified publication and actual installed PHP acceptance are complete: 243-check published Server2.11.6/CLI2.3.1 receipt, actual October29 14:21UTC, amd64/SQLite. All original recorded consumer cases passed from fresh state after the observer-only cursor correction; all exact task runtime/data/helper resources are removed. Native/shared canonical-meter alignment remains open in#770 and SQLite contention in#796. Newly confirmed bridge regression#861 holds broader release qualification#857 and does not alter this scoped read-only result. Original failed combined/source evidence remains preserved.
Activity
Rust #325: keep Waterline v1 projections read-only and bounded
rmcdaniel commentedon Oct 25, 2026
Handoff record. The General owner accepted the PHP fix in the native agent chat (server-325, 2026-10-25 22:58 UTC). The planned shape:
MessageStreamService's locked transaction, before both the duplicate-replay update and the new item, so a direct service call cannot write either.Native counterpart. Server #768 does the same in three places: the route, the service, and the store transaction under its serialization lock. Its tests cover valid, invalid and non-object appends, direct service and store calls, and a lock-barrier control showing that an append cannot cross a projection install.
Merge ordering. Native #768 can merge first and is documented as ahead of published 2.11.1 here. This issue stays open until the PHP Server has the fix and a parity fixture covers it.
rmcdaniel commentedon Oct 27, 2026
Acknowledged ownership handoff, 2026-10-27: Cloud offered this accepted public PHP slice and General accepted. Cloud now owns the PHP implementation through normal CI/merge, publication coordination and installed acceptance. General has no source branch/worktree/PR in progress for this issue and will preserve Cloud's work.
The existing acceptance and shared contract above remain in force. Native/frozen fixture edits remain with the Rust Server owner; coordinate exact contract evidence without weakening assertions. Normal CI-first and release controls apply. General continues its separate #794/#796/#777 work; this handoff does not transfer #526's retained polling source work.
rmcdaniel commentedon Oct 27, 2026
Maintainer handoff accepted: Cloud owns the PHP implementation, focused regression coverage, normal CI/merge, coordinated protected publication and installed acceptance. This includes the pre-body read-only refusal, locked service fence before duplicate/new writes, and zero malformed-input accounting on projections. Native/frozen fixtures remain with their existing owner.
rmcdaniel commentedon Oct 29, 2026
Cloud installed acceptance passed on published Server2.11.6, linux/amd64 and SQLite, using official CLI2.3.1: 243 checks passed, zero failed,14.249246s. Release40885194236 and matching chart0.3.6 passed their normal publication gates.
Exact identities: Server source
d13ebdb5eccc3d33b9d3c0e1ebc9ab0cb116e121; indexsha256:28e1ddeea655760e99748c48f2fa9bbecda37d3924864f6ee9011764144f2c2b; tested GHCR amd64 childsha256:c20c901eaa8dedfa04e5b89280f93b23a5e84e143410e3ceb63ff0881d701641. CLI SHA25692b7108a2f54573e9ef14c10e59fc58e3268e8b5c62cc8d998a6ec9dab25e290. Core2.15.7 provenance and critical runtime blobs match source3aa98b84; Mime7.4.22 identity matches its release lock.The real CLI/HTTP run repeated the recorded128-check consumer scope with additional identity and observation controls:
v1_projection_read_only, with accepted=false/duplicate=false. Global malformed JSON stayed400.The first attempt exposed an observer defect: an unclosed PDO cursor pinned SQLite's read view across later imports. A held/fresh/closed-cursor control showed2/3/3runs. Only two cursor closes changed; the full unchanged strict assertions then passed from fresh state. No product overlay or assertion removal. Accepted report SHA256
a64d2bcef0cffde8e071378c7d8edbc4555b89c757b73596042446efcfa6f190.The isolated UID1000 containers and internal network are gone; fixture state, CLI binary and42task files totaling26,544,979bytes were removed after mount/open-handle checks. Shared images and other owners' resources were preserved.
This completes the published PHP read-only fix. Native canonical-meter/frozen-reference alignment remains in#770, SQLite contention remains in#796, and the newly found bridge regression#861 holds broader release qualification#857. SDK-Python223/Workflow956 remain open. The installed result above covers amd64/SQLite; the earlier43tests/992assertions perSQLite/MySQL source qualification remains separately attributed.