tasks(arch): adopt taskgraph for architecture work — blocker tasks for deferred OQs, level mapping, status fixes
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
This commit is contained in:
1 parent
e6062230f9
commit
df5d04af1d
16 files changed
+440
-14
No files matched your search
@@ -160,13 +160,13 @@ filtering the tables above.
|
|||||||
|
|
||||||
### OQ-09: WASM Target Boundaries
|
### OQ-09: WASM Target Boundaries
|
||||||
|
|
||||||
- **Blocked on**: _(no explicit blocking condition recorded — see full file)_
|
- **Blocked on**: A concrete server-side WASM use case, or a deliberate confirmation that WASM stays a client-side design constraint. Tracked as `architecture/oq-09-wasm-server-use-case` in `tasks/architecture/`.
|
||||||
- **Priority**: low
|
- **Priority**: low
|
||||||
- **Full file**: [OQ-09](questions/009-wasm-target-boundaries.md)
|
- **Full file**: [OQ-09](questions/009-wasm-target-boundaries.md)
|
||||||
|
|
||||||
### OQ-10: Git Adapter Scope — Smart Protocol Only or Full Server?
|
### OQ-10: Git Adapter Scope — Smart Protocol Only or Full Server?
|
||||||
|
|
||||||
- **Blocked on**: _(no explicit blocking condition recorded — see full file)_
|
- **Blocked on**: Speccing the alknet-git crate — resolve this when that crate is specified, not deferred past it. Tracked as `architecture/oq-10-git-adapter-spec` in `tasks/architecture/`.
|
||||||
- **Priority**: low
|
- **Priority**: low
|
||||||
- **Full file**: [OQ-10](questions/010-git-adapter-scope-smart-protocol-only-or-full-server.md)
|
- **Full file**: [OQ-10](questions/010-git-adapter-scope-smart-protocol-only-or-full-server.md)
|
||||||
|
|
||||||
|
|||||||
@@ -4,5 +4,6 @@
|
|||||||
- **Status**: deferred
|
- **Status**: deferred
|
||||||
- **Door type**: One-way (when applicable)
|
- **Door type**: One-way (when applicable)
|
||||||
- **Priority**: low
|
- **Priority**: low
|
||||||
|
- **Blocked on**: A concrete server-side WASM use case, or a deliberate confirmation that WASM stays a client-side design constraint. Tracked as `architecture/oq-09-wasm-server-use-case` in `tasks/architecture/`.
|
||||||
- **Resolution**: Not an active question — WASM compatibility is a design constraint (see ADR-009, overview.md design principles), not a deliverable. Specific WASM targeting decisions will be made when individual crates are implemented. **BiStream being a trait preserves the *client-side* stream door** — a browser can implement BiStream over WebTransport streams. **The *server-side* dispatch door is NOT preserved by ADR-007 and is a known, accepted closure**: `Connection` is a concrete quinn-bound struct (not a trait), the accept loop uses `tokio::spawn` (tokio does not run on WASM), and the call-protocol dispatch internals (`PendingRequestMap`, `CallAdapter`) use tokio `oneshot`/`mpsc` channels. A WASM server-side peer would require a `Connection` trait and a runtime-abstracted accept loop — not planned. The browser path is client-side via a JS SDK, not server-side Rust-to-WASM. This is an explicit one-way door, not an oversight.
|
- **Resolution**: Not an active question — WASM compatibility is a design constraint (see ADR-009, overview.md design principles), not a deliverable. Specific WASM targeting decisions will be made when individual crates are implemented. **BiStream being a trait preserves the *client-side* stream door** — a browser can implement BiStream over WebTransport streams. **The *server-side* dispatch door is NOT preserved by ADR-007 and is a known, accepted closure**: `Connection` is a concrete quinn-bound struct (not a trait), the accept loop uses `tokio::spawn` (tokio does not run on WASM), and the call-protocol dispatch internals (`PendingRequestMap`, `CallAdapter`) use tokio `oneshot`/`mpsc` channels. A WASM server-side peer would require a `Connection` trait and a runtime-abstracted accept loop — not planned. The browser path is client-side via a JS SDK, not server-side Rust-to-WASM. This is an explicit one-way door, not an oversight.
|
||||||
- **Cross-references**: ADR-007, ADR-009
|
- **Cross-references**: ADR-007, ADR-009
|
||||||
+1
@@ -4,5 +4,6 @@
|
|||||||
- **Status**: deferred
|
- **Status**: deferred
|
||||||
- **Door type**: Two-way
|
- **Door type**: Two-way
|
||||||
- **Priority**: low
|
- **Priority**: low
|
||||||
|
- **Blocked on**: Speccing the alknet-git crate — resolve this when that crate is specified, not deferred past it. Tracked as `architecture/oq-10-git-adapter-spec` in `tasks/architecture/`.
|
||||||
- **Resolution**: Deferred per the cleanup plan. Start with git smart protocol over QUIC streams. ERC721 integration and full server capabilities are additive. **Composability fork (review #002 W18)**: whether git operations are registered in the `OperationRegistry` and callable via `env.invoke()`, or only available as raw smart protocol on `alknet/git`, is a separate decision from ERC721 scope. The path of least resistance (raw smart protocol only) forecloses agent composition of git operations — an agent handler that wants to compose `git/clone` cannot, because there's no `OperationSpec`, no `Handler`, no registration. To make git composable, a call-protocol projection (a set of `HandlerRegistration` bundles wrapping git operations behind the registry) must be built alongside or instead of the raw handler. Resolve this when speccing alknet-git, not deferred past it.
|
- **Resolution**: Deferred per the cleanup plan. Start with git smart protocol over QUIC streams. ERC721 integration and full server capabilities are additive. **Composability fork (review #002 W18)**: whether git operations are registered in the `OperationRegistry` and callable via `env.invoke()`, or only available as raw smart protocol on `alknet/git`, is a separate decision from ERC721 scope. The path of least resistance (raw smart protocol only) forecloses agent composition of git operations — an agent handler that wants to compose `git/clone` cannot, because there's no `OperationSpec`, no `Handler`, no registration. To make git composable, a call-protocol projection (a set of `HandlerRegistration` bundles wrapping git operations behind the registry) must be built alongside or instead of the raw handler. Resolve this when speccing alknet-git, not deferred past it.
|
||||||
- **Cross-references**: ADR-001
|
- **Cross-references**: ADR-001
|
||||||
@@ -420,6 +420,27 @@ cost-benefit framework in taskgraph's framework docs for the reasoning.
|
|||||||
2. Fills in `## Summary` section
|
2. Fills in `## Summary` section
|
||||||
3. Commits changes to worktree branch
|
3. Commits changes to worktree branch
|
||||||
|
|
||||||
|
### Architecture work and the `level` field
|
||||||
|
|
||||||
|
Architecture work uses the same taskgraph format as implementation work —
|
||||||
|
there is no separate `architecture` level. The `level` enum
|
||||||
|
(`planning, decomposition, implementation, review, research`) already covers
|
||||||
|
architecture activities:
|
||||||
|
|
||||||
|
| Architecture activity | `level` | Rationale |
|
||||||
|
|---|---|---|
|
||||||
|
| Writing an ADR (the decision) | `implementation` | The ADR *is* the deliverable — the implementation of an architecture decision. Calling it `planning` would mislabel the artifact. |
|
||||||
|
| Decomposing a spec into ADRs + OQs | `decomposition` | Direct fit — breaking a large architecture area into decideable units. |
|
||||||
|
| Architecture review pass | `review` | Direct fit. |
|
||||||
|
| Research / POC before a decision | `research` | Direct fit. |
|
||||||
|
| Spec writing (overview, component spec) | `implementation` | The spec is the deliverable. |
|
||||||
|
| Seeding a backlog of OQs/ADRs for a crate | `planning` | The upfront graph-shaping pass. |
|
||||||
|
|
||||||
|
Architecture tasks live under `tasks/architecture/` and use the standard
|
||||||
|
task body sections (`## Description`, `## Work`, `## Verification`,
|
||||||
|
`## Out of scope`). The `## Summary` section is filled on completion, same as
|
||||||
|
implementation tasks.
|
||||||
|
|
||||||
## Safe Exit Protocol
|
## Safe Exit Protocol
|
||||||
|
|
||||||
When a task becomes untendable:
|
When a task becomes untendable:
|
||||||
@@ -445,6 +466,33 @@ When a task becomes untendable:
|
|||||||
3. Document in task notes
|
3. Document in task notes
|
||||||
4. Notify coordinator
|
4. Notify coordinator
|
||||||
|
|
||||||
|
### Deferred OQs and the blocker-task half
|
||||||
|
|
||||||
|
The Safe Exit protocol applies to architecture decisions too, not just
|
||||||
|
implementation tasks. When an open question (OQ) is marked `deferred(scope)`,
|
||||||
|
the deferral has two halves that must stay in sync:
|
||||||
|
|
||||||
|
1. **The visibility half** (in `docs/architecture/`): the OQ's `Blocked on:`
|
||||||
|
field names the concrete blocking condition, and the `open-questions.md`
|
||||||
|
index surfaces it in the cross-theme **Deferred / Blocked** section so
|
||||||
|
"what's currently parked and why" is answerable at a glance. This is the
|
||||||
|
human-readable surface for the architect.
|
||||||
|
2. **The machine-readable half** (in `tasks/architecture/`): an
|
||||||
|
external-trigger tracker task represents the unblocking condition. It is
|
||||||
|
tagged `[external-trigger, deferred-oq]`, has `risk: trivial` and
|
||||||
|
`level: research` (it is not actionable work — it tracks whether the
|
||||||
|
external condition has arrived), and its `id` is referenced from the OQ's
|
||||||
|
`Blocked on:` text. This is the surface for the task graph: `taskgraph`
|
||||||
|
tools can reason about it, and downstream work that depends on the
|
||||||
|
decision can declare `depends_on: [architecture/oq-NN-...]`.
|
||||||
|
|
||||||
|
When the unblocking condition arrives (a use case materializes, a crate is
|
||||||
|
specced), the tracker task is marked `completed` and the OQ transitions from
|
||||||
|
`deferred(scope)` to `open` (or directly to `resolved` if no architecture
|
||||||
|
decision remains). The two halves serve different audiences and use one edge
|
||||||
|
type (`depends_on`) — the reverse lookup uses `taskgraph dependents`. Do not
|
||||||
|
add a `blocks:` field; it duplicates the edge and creates a sync hazard.
|
||||||
|
|
||||||
## Review Injection
|
## Review Injection
|
||||||
|
|
||||||
Use graph analysis to determine where reviews should happen:
|
Use graph analysis to determine where reviews should happen:
|
||||||
|
|||||||
@@ -1,12 +1,13 @@
|
|||||||
---
|
---
|
||||||
id: architecture/oq-09-10-blocking-conditions
|
id: architecture/oq-09-10-blocking-conditions
|
||||||
name: Add explicit Blocked on conditions to OQ-09 (WASM) and OQ-10 (Git Adapter)
|
name: Add explicit Blocked on conditions to OQ-09 (WASM) and OQ-10 (Git Adapter)
|
||||||
status: pending
|
status: completed
|
||||||
depends_on: []
|
depends_on: []
|
||||||
scope: narrow
|
scope: narrow
|
||||||
risk: low
|
risk: low
|
||||||
impact: component
|
impact: component
|
||||||
level: decomposition
|
level: decomposition
|
||||||
|
tags: [convention]
|
||||||
---
|
---
|
||||||
|
|
||||||
## Description
|
## Description
|
||||||
@@ -39,8 +40,20 @@ Either:
|
|||||||
The decision content stays unchanged — this is a metadata-structure fix, not a
|
The decision content stays unchanged — this is a metadata-structure fix, not a
|
||||||
re-resolution.
|
re-resolution.
|
||||||
|
|
||||||
|
## Summary
|
||||||
|
|
||||||
|
Completed alongside `architecture/safe-exit-blocker-task-mechanism`. Added a
|
||||||
|
structured `Blocked on:` field to both OQ-09 and OQ-10 in their per-OQ files,
|
||||||
|
each pointing at its new external-trigger tracker task
|
||||||
|
(`architecture/oq-09-wasm-server-use-case`,
|
||||||
|
`architecture/oq-10-git-adapter-spec`). Kept the legacy `deferred` status
|
||||||
|
rather than reframing to `deferred(scope)` — the distinction is no longer
|
||||||
|
load-bearing now that both have explicit blocking conditions and tracker
|
||||||
|
tasks. The `open-questions.md` Deferred/Blocked section now surfaces all six
|
||||||
|
deferred OQs with concrete conditions inline — no placeholders remain.
|
||||||
|
|
||||||
## Verification
|
## Verification
|
||||||
|
|
||||||
The "Deferred / Blocked" section of `docs/architecture/open-questions.md` should
|
The "Deferred / Blocked" section of `docs/architecture/open-questions.md`
|
||||||
show a concrete blocking condition for OQ-09 and OQ-10 instead of the "no
|
shows a concrete blocking condition for OQ-09 and OQ-10 instead of the "no
|
||||||
explicit blocking condition recorded" placeholder.
|
explicit blocking condition recorded" placeholder.
|
||||||
@@ -0,0 +1,58 @@
|
|||||||
|
---
|
||||||
|
id: architecture/oq-09-wasm-server-use-case
|
||||||
|
name: External trigger — a concrete server-side WASM use case (or confirmation it stays a client-side constraint)
|
||||||
|
status: pending
|
||||||
|
depends_on: []
|
||||||
|
scope: single
|
||||||
|
risk: trivial
|
||||||
|
impact: component
|
||||||
|
level: research
|
||||||
|
tags: [external-trigger, deferred-oq]
|
||||||
|
---
|
||||||
|
|
||||||
|
## Description
|
||||||
|
|
||||||
|
External-trigger tracker for [OQ-09](../docs/architecture/questions/009-wasm-target-boundaries.md)
|
||||||
|
(WASM Target Boundaries). This is **not actionable work** — it tracks whether
|
||||||
|
a concrete server-side WASM use case has emerged, or whether the project
|
||||||
|
confirms that WASM compatibility remains a *client-side* design constraint
|
||||||
|
only (a browser can implement BiStream over WebTransport streams; the
|
||||||
|
server-side dispatch door is a known, accepted closure per ADR-007/009).
|
||||||
|
|
||||||
|
## Trigger condition
|
||||||
|
|
||||||
|
Either:
|
||||||
|
- **A concrete server-side WASM use case arrives** (a deployment that wants
|
||||||
|
to run an alknet server peer compiled to WASM, which would require a
|
||||||
|
`Connection` trait and a runtime-abstracted accept loop — currently not
|
||||||
|
planned), or
|
||||||
|
- **A deliberate confirmation** that WASM stays a client-side design
|
||||||
|
constraint, at which point OQ-09 transitions from `deferred` to `resolved`
|
||||||
|
with the accepted-closure framing already in its Resolution text.
|
||||||
|
|
||||||
|
The second path is the more likely one — the OQ exists mainly so the
|
||||||
|
server-side WASM door closure is documented rather than implicit.
|
||||||
|
|
||||||
|
## What unblocking looks like
|
||||||
|
|
||||||
|
When a decision is made (either direction):
|
||||||
|
|
||||||
|
1. Mark this task `status: completed`.
|
||||||
|
2. Move [OQ-09](../docs/architecture/questions/009-wasm-target-boundaries.md)
|
||||||
|
from `deferred` to either `resolved` (client-side-only confirmed) or `open`
|
||||||
|
(server-side use case arrives, requiring a Connection trait + WASM runtime
|
||||||
|
abstraction ADR).
|
||||||
|
|
||||||
|
## Why this is a task, not just an OQ field
|
||||||
|
|
||||||
|
OQ-09 predates the formalized `deferred(scope)` + blocking-condition pattern
|
||||||
|
and lacked a structured `Blocked on:` field (it used the legacy `deferred`
|
||||||
|
status with the deferral reason in the Resolution prose). This task
|
||||||
|
formalizes the blocking condition and gives the OQ a machine-readable
|
||||||
|
presence in the task graph.
|
||||||
|
|
||||||
|
## Verification
|
||||||
|
|
||||||
|
This task is "completed" when either a server-side WASM use case arrives
|
||||||
|
(move OQ-09 to `open`) or the client-side-only constraint is confirmed
|
||||||
|
(move OQ-09 to `resolved`).
|
||||||
@@ -0,0 +1,56 @@
|
|||||||
|
---
|
||||||
|
id: architecture/oq-10-git-adapter-spec
|
||||||
|
name: External trigger — speccing alknet-git (resolve OQ-10 when that crate is specified, not deferred past it)
|
||||||
|
status: pending
|
||||||
|
depends_on: []
|
||||||
|
scope: single
|
||||||
|
risk: trivial
|
||||||
|
impact: component
|
||||||
|
level: research
|
||||||
|
tags: [external-trigger, deferred-oq]
|
||||||
|
---
|
||||||
|
|
||||||
|
## Description
|
||||||
|
|
||||||
|
External-trigger tracker for [OQ-10](../docs/architecture/questions/010-git-adapter-scope-smart-protocol-only-or-full-server.md)
|
||||||
|
(Git Adapter Scope — Smart Protocol Only or Full Server?). This is **not
|
||||||
|
actionable work** — it tracks when the alknet-git crate is being specified,
|
||||||
|
at which point OQ-10 must be resolved (not deferred past it).
|
||||||
|
|
||||||
|
## Trigger condition
|
||||||
|
|
||||||
|
The alknet-git crate is being specified. The OQ's Resolution text already
|
||||||
|
states: "Resolve this when speccing alknet-git, not deferred past it." The
|
||||||
|
two sub-questions:
|
||||||
|
|
||||||
|
1. **Git adapter scope** — start with git smart protocol over QUIC streams;
|
||||||
|
ERC721 integration and full server capabilities are additive.
|
||||||
|
2. **Composability fork** — whether git operations are registered in the
|
||||||
|
`OperationRegistry` and callable via `env.invoke()`, or only available as
|
||||||
|
raw smart protocol on `alknet/git`. The path of least resistance (raw
|
||||||
|
smart protocol only) forecloses agent composition of git operations; to
|
||||||
|
make git composable, a call-protocol projection (a set of
|
||||||
|
`HandlerRegistration` bundles wrapping git operations behind the
|
||||||
|
registry) must be built alongside or instead of the raw handler.
|
||||||
|
|
||||||
|
## What unblocking looks like
|
||||||
|
|
||||||
|
When alknet-git is specced:
|
||||||
|
|
||||||
|
1. Mark this task `status: completed`.
|
||||||
|
2. Move [OQ-10](../docs/architecture/questions/010-git-adapter-scope-smart-protocol-only-or-full-server.md)
|
||||||
|
from `deferred` to `open`, then resolve it as part of the alknet-git spec
|
||||||
|
pass (the Resolution text is explicit: do not defer past the spec).
|
||||||
|
|
||||||
|
## Why this is a task, not just an OQ field
|
||||||
|
|
||||||
|
OQ-10 predates the formalized `deferred(scope)` + blocking-condition pattern
|
||||||
|
and lacked a structured `Blocked on:` field (it used the legacy `deferred`
|
||||||
|
status with the deferral reason in the Resolution prose). This task
|
||||||
|
formalizes the blocking condition and gives the OQ a machine-readable
|
||||||
|
presence in the task graph.
|
||||||
|
|
||||||
|
## Verification
|
||||||
|
|
||||||
|
This task is "completed" when alknet-git is being specced and OQ-10 has been
|
||||||
|
moved to `open` (then resolved as part of that spec pass).
|
||||||
@@ -0,0 +1,53 @@
|
|||||||
|
---
|
||||||
|
id: architecture/oq-32-multihop-use-case
|
||||||
|
name: External trigger — a concrete multi-hop federation use case
|
||||||
|
status: pending
|
||||||
|
depends_on: []
|
||||||
|
scope: single
|
||||||
|
risk: trivial
|
||||||
|
impact: component
|
||||||
|
level: research
|
||||||
|
tags: [external-trigger, deferred-oq]
|
||||||
|
---
|
||||||
|
|
||||||
|
## Description
|
||||||
|
|
||||||
|
External-trigger tracker for [OQ-32](../docs/architecture/questions/032-multi-hop-federation.md)
|
||||||
|
(Multi-Hop Federation). This is **not actionable work** — it tracks whether a
|
||||||
|
concrete use case for multi-hop federation has arrived. When it does, mark this
|
||||||
|
task `completed` and the OQ moves from `deferred(scope)` to `open`.
|
||||||
|
|
||||||
|
## Trigger condition
|
||||||
|
|
||||||
|
A concrete deployment or use case that requires transitive op discovery across
|
||||||
|
more than one hop — i.e., worker A needs to reach worker B's ops *through* the
|
||||||
|
head, where the head is not explicitly re-exporting them. The one-hop model
|
||||||
|
(head→worker, runner→hub) covers all current use cases.
|
||||||
|
|
||||||
|
## What unblocking looks like
|
||||||
|
|
||||||
|
When a use case arrives:
|
||||||
|
|
||||||
|
1. Mark this task `status: completed`.
|
||||||
|
2. Move [OQ-32](../docs/architecture/questions/032-multi-hop-federation.md)
|
||||||
|
from `deferred(scope)` to `open` (update the Status field + the
|
||||||
|
`open-questions.md` index tables + Deferred/Blocked section).
|
||||||
|
3. Create an architecture task to write the multi-hop federation ADR — the
|
||||||
|
peer-keyed overlay model extends to multi-hop without redesign (ADR-029 §3.7),
|
||||||
|
but path-finding (which peer reaches which op transitively) is where the
|
||||||
|
design work lives. A graph library (petgraph) may pay off for multi-hop; for
|
||||||
|
one-hop, a nested `HashMap<PeerId, HashMap<String, ...>>` suffices.
|
||||||
|
|
||||||
|
## 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 ("what's parked and why"). This task is the machine-readable
|
||||||
|
half: it lives in the task graph so `taskgraph` tools can reason about it, and
|
||||||
|
so downstream work that depends on multi-hop being resolved can declare
|
||||||
|
`depends_on: [architecture/oq-32-multihop-use-case]`.
|
||||||
|
|
||||||
|
## Verification
|
||||||
|
|
||||||
|
This task is "completed" when a concrete multi-hop use case is documented
|
||||||
|
(e.g., in a research finding or deployment note) and OQ-32 has been moved to
|
||||||
|
`open`.
|
||||||
@@ -0,0 +1,66 @@
|
|||||||
|
---
|
||||||
|
id: architecture/oq-41-stream-operators-use-case
|
||||||
|
name: External trigger — a handler that needs stream operators beyond existing combinators
|
||||||
|
status: pending
|
||||||
|
depends_on: []
|
||||||
|
scope: single
|
||||||
|
risk: trivial
|
||||||
|
impact: component
|
||||||
|
level: research
|
||||||
|
tags: [external-trigger, deferred-oq]
|
||||||
|
---
|
||||||
|
|
||||||
|
## Description
|
||||||
|
|
||||||
|
External-trigger tracker for [OQ-41](../docs/architecture/questions/041-stream-operators-library.md)
|
||||||
|
(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:
|
||||||
|
|
||||||
|
1. Mark this task `status: completed`.
|
||||||
|
2. Move [OQ-41](../docs/architecture/questions/041-stream-operators-library.md)
|
||||||
|
from `deferred(scope)` to `resolved` (the architectural decision is already
|
||||||
|
made — ADR-049; what remains is the implementation, which is scheduling
|
||||||
|
work). The OQ may transition directly to `resolved` rather than `open`,
|
||||||
|
since no architecture decision remains.
|
||||||
|
3. 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`.
|
||||||
@@ -0,0 +1,51 @@
|
|||||||
|
---
|
||||||
|
id: architecture/oq-44-tty-modes-use-case
|
||||||
|
name: External trigger — a concrete TTY mode-control use case
|
||||||
|
status: pending
|
||||||
|
depends_on: []
|
||||||
|
scope: single
|
||||||
|
risk: trivial
|
||||||
|
impact: component
|
||||||
|
level: research
|
||||||
|
tags: [external-trigger, deferred-oq]
|
||||||
|
---
|
||||||
|
|
||||||
|
## Description
|
||||||
|
|
||||||
|
External-trigger tracker for [OQ-44](../docs/architecture/questions/044-terminal-modes-tty-modes.md)
|
||||||
|
(Terminal Modes / TTY modes). This is **not actionable work** — it tracks
|
||||||
|
whether a concrete deployment has emerged that needs to set TTY modes (echo,
|
||||||
|
raw, canonical, etc.) on a PTY beyond the backend's defaults.
|
||||||
|
|
||||||
|
## Trigger condition
|
||||||
|
|
||||||
|
A concrete deployment that needs to control TTY modes beyond the defaults the
|
||||||
|
backends already provide (`portable_pty`, docker `tty: true`, russh
|
||||||
|
`pty_request` all have defaults that work for the common terminal case). The
|
||||||
|
`modes` field in `TerminalParams` is `serde_json::Value` (reserved as `{}` in
|
||||||
|
v1) for when this arrives.
|
||||||
|
|
||||||
|
## What unblocking looks like
|
||||||
|
|
||||||
|
When a mode-control use case arrives:
|
||||||
|
|
||||||
|
1. Mark this task `status: completed`.
|
||||||
|
2. Move [OQ-44](../docs/architecture/questions/044-terminal-modes-tty-modes.md)
|
||||||
|
from `deferred(scope)` to `open`.
|
||||||
|
3. Specify the `modes` JSON shape (SSH's `pty_request` carries TTY modes as a
|
||||||
|
packed bitmask; the Rust analogue extends the `modes` field). Adding mode
|
||||||
|
control is additive (extend the `modes` JSON shape) and does not break
|
||||||
|
downstream — the architectural commitment is two-way-door.
|
||||||
|
|
||||||
|
## 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 downstream work
|
||||||
|
that depends on TTY mode control can declare `depends_on:
|
||||||
|
[architecture/oq-44-tty-modes-use-case]`.
|
||||||
|
|
||||||
|
## Verification
|
||||||
|
|
||||||
|
This task is "completed" when a concrete mode-control use case is documented
|
||||||
|
and OQ-44 has been moved to `open`.
|
||||||
@@ -0,0 +1,52 @@
|
|||||||
|
---
|
||||||
|
id: architecture/oq-46-runner-policy-use-case
|
||||||
|
name: External trigger — a concrete runner-policy use case that forces the API surface
|
||||||
|
status: pending
|
||||||
|
depends_on: []
|
||||||
|
scope: single
|
||||||
|
risk: trivial
|
||||||
|
impact: component
|
||||||
|
level: research
|
||||||
|
tags: [external-trigger, deferred-oq]
|
||||||
|
---
|
||||||
|
|
||||||
|
## Description
|
||||||
|
|
||||||
|
External-trigger tracker for [OQ-46](../docs/architecture/questions/046-runner-api-surface.md)
|
||||||
|
(Runner API Surface). This is **not actionable work** — it tracks whether a
|
||||||
|
concrete runner-policy use case has emerged that forces the API surface (job
|
||||||
|
management, log persistence, task graph integration). The runner *mechanism*
|
||||||
|
(pipe mode) is already in alknet-tty (ADR-054); the runner *policy* is a
|
||||||
|
downstream crate's job.
|
||||||
|
|
||||||
|
## Trigger condition
|
||||||
|
|
||||||
|
A concrete deployment that needs runner *policy* — job management, log
|
||||||
|
persistence, task graph integration — on top of the pipe-mode mechanism
|
||||||
|
(`TtyParams.terminal = None` → `std::process::Command` with piped stdio →
|
||||||
|
framed byte stream + exit code) that alknet-tty already provides.
|
||||||
|
|
||||||
|
## What unblocking looks like
|
||||||
|
|
||||||
|
When a runner-policy use case arrives:
|
||||||
|
|
||||||
|
1. Mark this task `status: completed`.
|
||||||
|
2. Move [OQ-46](../docs/architecture/questions/046-runner-api-surface.md)
|
||||||
|
from `deferred(scope)` to `open`.
|
||||||
|
3. Decide whether a runner-policy crate (e.g., an `alknet-runner` crate that
|
||||||
|
builds on the pipe mode + the wire format to provide job management) is
|
||||||
|
needed, and what its API surface would be. The mechanism is preserved
|
||||||
|
regardless of the policy decision.
|
||||||
|
|
||||||
|
## 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 downstream work
|
||||||
|
that depends on runner policy can declare `depends_on:
|
||||||
|
[architecture/oq-46-runner-policy-use-case]`.
|
||||||
|
|
||||||
|
## Verification
|
||||||
|
|
||||||
|
This task is "completed" when a concrete runner-policy use case is documented
|
||||||
|
and OQ-46 has been moved to `open`.
|
||||||
@@ -1,12 +1,13 @@
|
|||||||
---
|
---
|
||||||
id: architecture/safe-exit-blocker-task-mechanism
|
id: architecture/safe-exit-blocker-task-mechanism
|
||||||
name: Establish the tasks/architecture/ blocker-task half of the Safe Exit protocol
|
name: Establish the tasks/architecture/ blocker-task half of the Safe Exit protocol
|
||||||
status: pending
|
status: completed
|
||||||
depends_on: []
|
depends_on: []
|
||||||
scope: moderate
|
scope: moderate
|
||||||
risk: low
|
risk: low
|
||||||
impact: project
|
impact: project
|
||||||
level: planning
|
level: planning
|
||||||
|
tags: [convention]
|
||||||
---
|
---
|
||||||
|
|
||||||
## Description
|
## Description
|
||||||
@@ -58,6 +59,30 @@ it").
|
|||||||
role spec) so future deferrals create the blocker task as part of the Safe
|
role spec) so future deferrals create the blocker task as part of the Safe
|
||||||
Exit step.
|
Exit step.
|
||||||
|
|
||||||
|
## Summary
|
||||||
|
|
||||||
|
Completed in the July 2026 architecture-task pass. Decisions:
|
||||||
|
|
||||||
|
- **Format**: adopted the existing taskgraph frontmatter verbatim — no new
|
||||||
|
`blocks:` field. One edge type (`depends_on`) keeps the graph simple; the
|
||||||
|
reverse lookup uses `taskgraph dependents`. The OQ's `Blocked on:` text is
|
||||||
|
the human-readable pointer; the task `depends_on` is the machine-readable
|
||||||
|
edge. They serve different audiences (architect vs. planner/agent).
|
||||||
|
- **External-trigger tasks**: the four `deferred(scope)` OQs (32, 41, 44, 46)
|
||||||
|
plus the two legacy `deferred` OQs (09, 10) each got an external-trigger
|
||||||
|
tracker task under `tasks/architecture/` tagged `[external-trigger,
|
||||||
|
deferred-oq]`. These represent the external condition (a use case arriving,
|
||||||
|
a crate being specced) that would unblock the OQ — they are not actionable
|
||||||
|
work, so `risk: trivial` and `level: research`.
|
||||||
|
- **OQ-09/10 backfill**: added a structured `Blocked on:` field to both
|
||||||
|
(previously they used legacy `deferred` status with the reason in the
|
||||||
|
Resolution prose). The `open-questions.md` index now surfaces all six
|
||||||
|
deferred OQs with concrete blocking conditions in the Deferred/Blocked
|
||||||
|
section — no more "_(no explicit blocking condition recorded)_" placeholders.
|
||||||
|
- **Convention doc**: the `docs/sdd_process.md` Task File Format section is
|
||||||
|
updated with the architecture-task level mapping and the Safe Exit
|
||||||
|
blocker-task pattern (separate edit).
|
||||||
|
|
||||||
## Out of scope
|
## Out of scope
|
||||||
|
|
||||||
- The DB-backed backend (no manual links, vector/text search) — that's a future
|
- The DB-backed backend (no manual links, vector/text search) — that's a future
|
||||||
@@ -67,7 +92,9 @@ it").
|
|||||||
|
|
||||||
## Verification
|
## Verification
|
||||||
|
|
||||||
- `tasks/architecture/` contains one blocker task per `deferred(scope)` OQ
|
- `tasks/architecture/` contains one external-trigger task per deferred OQ
|
||||||
- Each blocker task's `depends_on` names the concrete unblocking condition (or
|
(six total: OQ-09, 10, 32, 41, 44, 46).
|
||||||
a task that represents it)
|
- Each OQ's `Blocked on:` field names its tracker task ID, and the
|
||||||
- `docs/sdd_process.md` (or equivalent) references the convention
|
`open-questions.md` Deferred/Blocked section surfaces the condition inline.
|
||||||
|
- `taskgraph validate` passes for `tasks/architecture/`.
|
||||||
|
- `docs/sdd_process.md` references the convention.
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
---
|
---
|
||||||
id: call/registry/access-control-ownership-check
|
id: call/registry/access-control-ownership-check
|
||||||
name: Update AccessControl::check to consult OwnershipProvider for dynamic resource ownership (ADR-050 §2)
|
name: Update AccessControl::check to consult OwnershipProvider for dynamic resource ownership (ADR-050 §2)
|
||||||
status: done
|
status: completed
|
||||||
depends_on: [core/ownership-store-trait]
|
depends_on: [core/ownership-store-trait]
|
||||||
scope: moderate
|
scope: moderate
|
||||||
risk: medium
|
risk: medium
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
---
|
---
|
||||||
id: call/registry/dispatch-resource-id-extraction
|
id: call/registry/dispatch-resource-id-extraction
|
||||||
name: Wire dispatch path to extract resource_id from input and thread OwnershipProvider to AccessControl::check (ADR-050 §2a, §4a)
|
name: Wire dispatch path to extract resource_id from input and thread OwnershipProvider to AccessControl::check (ADR-050 §2a, §4a)
|
||||||
status: done
|
status: completed
|
||||||
depends_on: [call/registry/operation-spec-resource-id-path, call/registry/access-control-ownership-check]
|
depends_on: [call/registry/operation-spec-resource-id-path, call/registry/access-control-ownership-check]
|
||||||
scope: moderate
|
scope: moderate
|
||||||
risk: medium
|
risk: medium
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
---
|
---
|
||||||
id: call/registry/operation-spec-resource-id-path
|
id: call/registry/operation-spec-resource-id-path
|
||||||
name: Add resource_id_path field to OperationSpec (ADR-050 §2a)
|
name: Add resource_id_path field to OperationSpec (ADR-050 §2a)
|
||||||
status: done
|
status: completed
|
||||||
depends_on: []
|
depends_on: []
|
||||||
scope: single
|
scope: single
|
||||||
risk: low
|
risk: low
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
---
|
---
|
||||||
id: core/ownership-store-trait
|
id: core/ownership-store-trait
|
||||||
name: Add OwnershipProvider (sync read) + OwnershipStore (async write) traits and InMemoryOwnershipStore (ADR-050)
|
name: Add OwnershipProvider (sync read) + OwnershipStore (async write) traits and InMemoryOwnershipStore (ADR-050)
|
||||||
status: done
|
status: completed
|
||||||
depends_on: []
|
depends_on: []
|
||||||
scope: moderate
|
scope: moderate
|
||||||
risk: low
|
risk: low
|
||||||
|
|||||||
Reference in new issue
Block a user