@@ -0,0 +1,56 @@
|
||||
---
|
||||
status: active
|
||||
system: tasks
|
||||
created: 2026-09-14
|
||||
owners:
|
||||
- kandev
|
||||
---
|
||||
|
||||
# Queue Admission Requirements
|
||||
|
||||
## Overview
|
||||
|
||||
Users need a reliable result when submitting a prompt to a busy session.
|
||||
The task system owns admission identity, persistence, and recovery. Composers expose this contract on desktop and phone.
|
||||
|
||||
An admission is one submission attempt, including its automatic retry. Queue editing, merging, and dispatch are later operations.
|
||||
|
||||
## Requirements
|
||||
|
||||
### REQ-TASKS-QUEUE-ADMISSION-001: Recoverable queue submission
|
||||
|
||||
**Intent:** Preserve user input and prevent duplicate admission when a response is lost.
|
||||
|
||||
#### Acceptance criteria
|
||||
|
||||
- **AC-TASKS-QUEUE-ADMISSION-001.1:** Every ordinary composer queue submission shall have a stable admission identity, including submissions without plan comments.
|
||||
- **AC-TASKS-QUEUE-ADMISSION-001.2:** Repeating an accepted admission with the same identity and payload shall not append content, claim attachments, or consume comments again.
|
||||
This applies after automatic merge, manual removal, queue clearing, reservation, dispatch, and backend restart.
|
||||
- **AC-TASKS-QUEUE-ADMISSION-001.3:** Reusing an admission identity with a different payload shall fail without changing the accepted work.
|
||||
An admission shall remain bound to its original task, session, and session incarnation.
|
||||
- **AC-TASKS-QUEUE-ADMISSION-001.4:** A queue submission shall allow 10 seconds for a response, or 30 seconds when it includes attachments.
|
||||
After uncertain transport failure, the client shall reconcile acceptance and retry at most once with the same identity and payload.
|
||||
- **AC-TASKS-QUEUE-ADMISSION-001.5:** Confirmed acceptance shall clear only the submitted draft. A failed queue refresh after acceptance shall not report admission failure.
|
||||
Rejected or unresolved submissions shall preserve the draft and attachments. A later unrelated draft shall remain unchanged.
|
||||
- **AC-TASKS-QUEUE-ADMISSION-001.6:** Queue capacity and validation rejections shall show localized rejection feedback.
|
||||
An unresolved timeout or connection loss shall show uncertain delivery feedback without claiming that the server rejected the message.
|
||||
- **AC-TASKS-QUEUE-ADMISSION-001.7:** Reliable admission shall preserve Auto-merge, capacity, attachment ownership, Auto-run, and plan-comment consumption rules.
|
||||
In particular, a compatible ordinary submission shall remain eligible for automatic merging.
|
||||
- **AC-TASKS-QUEUE-ADMISSION-001.8:** Task chat and Quick Chat shall provide equivalent recovery and draft preservation on desktop and phone.
|
||||
Phone feedback shall remain readable with the existing touch-accessible Send action.
|
||||
|
||||
## Compatibility and exclusions
|
||||
|
||||
Clients that omit admission identity retain their existing behavior without automatic replay guarantees.
|
||||
Existing plan-comment identities remain valid. A second deliberate submission is a new admission, not a replay of an edited draft.
|
||||
No provider-level exactly-once execution or offline outbox is promised. Browser reload does not restore an unacknowledged submission automatically.
|
||||
|
||||
## Related contracts
|
||||
|
||||
- [Resume prompt queue](resume-prompt-queue.md) owns startup eligibility and deferred dispatch.
|
||||
- [Plan comments](plan-comments.md) owns comment selection and atomic consumption.
|
||||
- [Automatic merge overrides](../../ui/requirements/message-queue-auto-merge-session-overrides.md) owns merge policy and capacity exceptions.
|
||||
|
||||
## Implementation plans
|
||||
|
||||
- [Queue admission reliability](../../../plans/queue-admission-reliability/plan.md)
|
||||
@@ -0,0 +1,101 @@
|
||||
---
|
||||
status: current
|
||||
system: tasks
|
||||
requirements:
|
||||
- REQ-TASKS-QUEUE-ADMISSION-001
|
||||
---
|
||||
|
||||
# Queue Admission System Design
|
||||
|
||||
## Boundary and mapping
|
||||
|
||||
The task system owns durable prompt admission. This design extends the existing queue transport and identity guards.
|
||||
|
||||
| Criteria (AC-TASKS-QUEUE-ADMISSION-001) | Sections |
|
||||
| --- | --- |
|
||||
| .1, .2, .3, .7 | Server admission, Persistence |
|
||||
| .4, .5 | Client recovery |
|
||||
| .6, .8 | Composer feedback |
|
||||
|
||||
## Server admission
|
||||
|
||||
`QueueHandlers.wsQueueMessage` already accepts optional `client_queue_id`. Preserve this field rather than adding a parallel `client_message_id`.
|
||||
Validate its length for every identified admission. Keep legacy unidentified callers on the existing path.
|
||||
Plan-comment admissions retain their existing transaction and merge exclusion.
|
||||
|
||||
For ordinary identified requests, add a typed admission request to the messagequeue service.
|
||||
Capture the immutable `QueueSessionIdentity`, normalized payload, and caller identity. Fingerprint content, model, plan mode, attachments, context, references, and admission options.
|
||||
Exclude request IDs, timeouts, and transport timestamps. Use the existing canonical fingerprint utility.
|
||||
|
||||
Under the existing task/session admission guards, validate authorization and incarnation before reading any receipt.
|
||||
An exact receipt replay returns acceptance without changing queue state. A mismatched fingerprint returns a typed conflict.
|
||||
Replay lookup precedes capacity evaluation and attachment claim preparation that can reject already-claimed uploads.
|
||||
Mutable reference validation applies to a first admission. Exact replay must not fail because an accepted reference later changed.
|
||||
|
||||
For a new admission, keep the existing insertion, full-capacity candidate fold, and staged attachment rules.
|
||||
Write the receipt in the same transaction as the accepted insertion or fold and any attachment ownership changes.
|
||||
A transaction failure commits neither content nor receipt. A database uniqueness constraint closes concurrent replay races.
|
||||
Do not implement a separate receipt write after queue commit or a read-then-insert deduplication check outside the transaction.
|
||||
|
||||
Store ordinary contributing IDs in a provenance metadata key that is ignored by merge compatibility and unioned by automatic and manual folds. Ordinary entries must retain their current compatibility behavior, while their provenance remains available after a source row is folded or dispatched.
|
||||
The earlier tail still survives automatic merging. A receipt identifies admission, not the continued existence of a visible source row.
|
||||
Post-admission readiness checks retain current behavior and cannot convert committed acceptance into rejection.
|
||||
|
||||
## Persistence
|
||||
|
||||
Add a queue-owned `queue_admission_receipts` table through `repository_sqlite.go` initialization and a focused repository helper.
|
||||
The shared SQL implementation must work with SQLite and PostgreSQL using established rebinding and lock conventions.
|
||||
|
||||
Use `(task_id, session_id, session_incarnation_id, client_queue_id)` as the receipt key.
|
||||
Store the normalized request fingerprint, accepted queue ID, bounded response snapshot, and acceptance timestamp.
|
||||
The response retains the current `QueuedMessage` shape. Omit inline attachment data from stored and replayed snapshots.
|
||||
Clients already hold the submitted attachment payload and refresh authoritative queue state separately.
|
||||
|
||||
Retain receipts after manual edits, merges, removal, clearing, reservation, and dispatch. These operations do not reverse admission.
|
||||
Session/task deletion purges associated receipts through existing lifecycle transactions. Reset invalidates old incarnation requests before replay lookup.
|
||||
Session transfer must not retarget a receipt. Reject an obsolete original identity under current ownership guards.
|
||||
Do not add a time-based expiry that allows a delayed duplicate within a retained session.
|
||||
Existing rows need no backfill. Historical unidentified requests have no replay guarantee.
|
||||
|
||||
## Client recovery
|
||||
|
||||
`useMessageHandler` passes its existing `clientAdmissionId` for every queue submission, not only plan-comment submissions.
|
||||
`useQueueAdmissionAction` preserves that ID and treats acknowledged admission as successful even if its terminal queue refresh fails.
|
||||
`queueMessage` keeps an explicitly supplied ID. It does not generate a replacement ID inside retry handling.
|
||||
|
||||
Use a shared request closure with numeric timeout `10000`, or `30000` for nonempty attachments, for both attempts.
|
||||
Classify timeout and connection closure using existing transport errors. Explicit server rejection is not a transport failure.
|
||||
Keep existing queue/transcript reconciliation as an optimization. Bound ordinary reconciliation to one queue read and one newest transcript page per pass.
|
||||
Each read has a 5-second timeout. Wait at most 3 seconds for reconnection before one replay-safe retry.
|
||||
After retry failure, one bounded reconciliation pass can confirm acceptance. Otherwise propagate typed rejection or uncertain delivery.
|
||||
The server receipt, not exhaustive transcript scanning, supplies deduplication when the original row has disappeared.
|
||||
Preserve existing plan-comment recovery coverage while extracting any shared helper.
|
||||
|
||||
A returned replay snapshot must not insert a phantom pending row into the store.
|
||||
Use the existing authoritative queue refresh and incarnation-aware mutation token.
|
||||
After unresolved failure, preserve the draft. A later deliberate Send remains a new admission and can duplicate an earlier uncertain submission.
|
||||
Feedback must not claim otherwise. Persistent draft retry identities are outside this package.
|
||||
|
||||
## Composer feedback
|
||||
|
||||
Keep typed queue error codes through the API boundary. Map capacity, validation, identity conflict, and unavailable-session errors to localized rejection copy.
|
||||
Do not display raw server diagnostics as translated UI copy. Preserve existing plan-comment-specific normalization.
|
||||
Only an unresolved transport outcome uses the existing uncertain-delivery message.
|
||||
Use shared failure presentation for Task chat and Quick Chat. Audit the passthrough composer if it receives the same error types.
|
||||
|
||||
No new controls or layout are needed. Reuse the current toast, composer, and `chat-input-toolbar-mobile.tsx`.
|
||||
The phone Task layout and Quick Chat retain their scroll ownership, safe-area spacing, and 44-pixel Send target.
|
||||
The plan's UI-01 preview defines the affected error state. Add desktop and phone rendered regression coverage.
|
||||
|
||||
## Security and observability
|
||||
|
||||
Apply existing queue authorization before receipt lookup. Never disclose another task's receipt by a guessed key.
|
||||
Fingerprinting and receipt handling must not log prompt content, attachment bytes, or credentials.
|
||||
Use bounded structured fields for initial acceptance, replay, conflict, and uncertain client recovery.
|
||||
No new metrics, high-cardinality labels, or global transport logging are required.
|
||||
|
||||
## Related decisions and implementation
|
||||
|
||||
- [Durable admission receipts](../../../decisions/2026-09-14-durable-queue-admission-receipts.md) records the accepted persistence choice.
|
||||
- [Server-owned Auto-run](../../../decisions/2026-08-16-server-owned-queue-auto-run.md) remains authoritative for dispatch.
|
||||
- [Implementation plan](../../../plans/queue-admission-reliability/plan.md)
|
||||
Reference in New Issue
Block a user