Establishes the tasks/architecture/ blocker-task half of the Safe Exit protocol. Each deferred OQ now has an external-trigger tracker task representing its unblocking condition, and the OQ's Blocked on field names the tracker task ID — closing the gap where the deferral field existed but the task-graph half was unenforced. Changes: - Add 6 external-trigger tracker tasks for the deferred OQs (OQ-09, 10, 32, 41, 44, 46) under tasks/architecture/, tagged [external-trigger, deferred-oq] - Add structured Blocked on field to OQ-09 and OQ-10 (previously used legacy 'deferred' status with the reason in the Resolution prose); index now surfaces all 6 deferred OQs with concrete conditions, no placeholders - Document the architecture-task level mapping (level: implementation for ADRs/specs, decomposition for spec-to-ADR breakdown, planning for backlog seeding, research/review direct fits) and the deferred-OQ blocker-task pattern in docs/sdd_process.md - Mark architecture/safe-exit-blocker-task-mechanism and architecture/oq-09-10-blocking-conditions completed (implemented by this pass) - Fix 4 pre-existing ADR-050 implementation tasks: status: done → completed (taskgraph enum is 'completed', not 'done') — taskgraph validate now passes for all 100 tasks
2.8 KiB
id, name, status, depends_on, scope, risk, impact, level, tags
| id | name | status | depends_on | scope | risk | impact | level | tags | ||
|---|---|---|---|---|---|---|---|---|---|---|
| architecture/oq-41-stream-operators-use-case | External trigger — a handler that needs stream operators beyond existing combinators | pending | single | trivial | component | research |
|
Description
External-trigger tracker for OQ-41
(Stream Operators Library). This is not actionable work — it tracks
whether a handler has emerged that needs stream operators (filter, map, batch,
dedupe, window, etc. on BoxStream<T>) and finds the existing combinators
insufficient. The operators library is a convenience, not a prerequisite for
any handler.
Trigger condition
A handler that transforms subscription streams (BoxStream<ResponseEnvelope>)
and finds Box::pin(stream::iter(...)), async_stream::stream!, and
futures::stream combinators insufficient — i.e., the handler code is
demonstrably boilerplate-heavy for stream manipulation that the operators
library would collapse. The architectural decision (stream composition is
handler-level, not protocol-level) is already made in ADR-049; this tracks the
implementation of the utility library.
What unblocking looks like
When a handler needs the operators:
- Mark this task
status: completed. - Move OQ-41
from
deferred(scope)toresolved(the architectural decision is already made — ADR-049; what remains is the implementation, which is scheduling work). The OQ may transition directly toresolvedrather thanopen, since no architecture decision remains. - Implement the operators library (no ADR needed — internal utility code that doesn't cross crate boundaries as a contract; an ADR would be warranted only if the operators become part of a public API surface, e.g., a handler-registration DSL that references operator names).
Why this is a task, not just an OQ field
The OQ's Blocked on: field in open-questions.md is the human-readable
visibility surface. This task is the machine-readable half: it lives in the
task graph so taskgraph tools can reason about it, and so a handler that
needs the operators can declare depends_on: [architecture/oq-41-stream-operators-use-case].
Prior art
@alkdev/pubsub/src/operators.ts — 13 operators (filter, map, take,
batch, dedupe, window, chain, join, reduce, groupBy, flat,
pipe, toArray) on AsyncIterable<T>, forked from graphql-yoga's
subscription implementation. The Rust analogue would provide the same set on
BoxStream<T> / impl Stream<Item = T>.
Verification
This task is "completed" when a handler is identified that needs the operators
and OQ-41 has been moved to resolved.