From df5d04af1d3166f6b5070db728fdd5e5dcdf5f8b Mon Sep 17 00:00:00 2001 From: "glm-5.2" Date: Mon, 6 Jul 2026 16:34:01 +0000 Subject: [PATCH] =?UTF-8?q?tasks(arch):=20adopt=20taskgraph=20for=20archit?= =?UTF-8?q?ecture=20work=20=E2=80=94=20blocker=20tasks=20for=20deferred=20?= =?UTF-8?q?OQs,=20level=20mapping,=20status=20fixes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 --- docs/architecture/open-questions.md | 4 +- .../questions/009-wasm-target-boundaries.md | 1 + ...cope-smart-protocol-only-or-full-server.md | 1 + docs/sdd_process.md | 48 ++++++++++++++ .../oq-09-10-blocking-conditions.md | 19 +++++- .../oq-09-wasm-server-use-case.md | 58 ++++++++++++++++ tasks/architecture/oq-10-git-adapter-spec.md | 56 ++++++++++++++++ tasks/architecture/oq-32-multihop-use-case.md | 53 +++++++++++++++ .../oq-41-stream-operators-use-case.md | 66 +++++++++++++++++++ .../architecture/oq-44-tty-modes-use-case.md | 51 ++++++++++++++ .../oq-46-runner-policy-use-case.md | 52 +++++++++++++++ .../safe-exit-blocker-task-mechanism.md | 37 +++++++++-- .../access-control-ownership-check.md | 2 +- .../dispatch-resource-id-extraction.md | 2 +- .../operation-spec-resource-id-path.md | 2 +- tasks/core/ownership-store-trait.md | 2 +- 16 files changed, 440 insertions(+), 14 deletions(-) create mode 100644 tasks/architecture/oq-09-wasm-server-use-case.md create mode 100644 tasks/architecture/oq-10-git-adapter-spec.md create mode 100644 tasks/architecture/oq-32-multihop-use-case.md create mode 100644 tasks/architecture/oq-41-stream-operators-use-case.md create mode 100644 tasks/architecture/oq-44-tty-modes-use-case.md create mode 100644 tasks/architecture/oq-46-runner-policy-use-case.md diff --git a/docs/architecture/open-questions.md b/docs/architecture/open-questions.md index b7125b9..bd69c32 100644 --- a/docs/architecture/open-questions.md +++ b/docs/architecture/open-questions.md @@ -160,13 +160,13 @@ filtering the tables above. ### 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 - **Full file**: [OQ-09](questions/009-wasm-target-boundaries.md) ### 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 - **Full file**: [OQ-10](questions/010-git-adapter-scope-smart-protocol-only-or-full-server.md) diff --git a/docs/architecture/questions/009-wasm-target-boundaries.md b/docs/architecture/questions/009-wasm-target-boundaries.md index 3693298..a7e299d 100644 --- a/docs/architecture/questions/009-wasm-target-boundaries.md +++ b/docs/architecture/questions/009-wasm-target-boundaries.md @@ -4,5 +4,6 @@ - **Status**: deferred - **Door type**: One-way (when applicable) - **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. - **Cross-references**: ADR-007, ADR-009 diff --git a/docs/architecture/questions/010-git-adapter-scope-smart-protocol-only-or-full-server.md b/docs/architecture/questions/010-git-adapter-scope-smart-protocol-only-or-full-server.md index f0b7ea8..0ab863a 100644 --- a/docs/architecture/questions/010-git-adapter-scope-smart-protocol-only-or-full-server.md +++ b/docs/architecture/questions/010-git-adapter-scope-smart-protocol-only-or-full-server.md @@ -4,5 +4,6 @@ - **Status**: deferred - **Door type**: Two-way - **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. - **Cross-references**: ADR-001 diff --git a/docs/sdd_process.md b/docs/sdd_process.md index 97651fa..3df7550 100644 --- a/docs/sdd_process.md +++ b/docs/sdd_process.md @@ -420,6 +420,27 @@ cost-benefit framework in taskgraph's framework docs for the reasoning. 2. Fills in `## Summary` section 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 When a task becomes untendable: @@ -445,6 +466,33 @@ When a task becomes untendable: 3. Document in task notes 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 Use graph analysis to determine where reviews should happen: diff --git a/tasks/architecture/oq-09-10-blocking-conditions.md b/tasks/architecture/oq-09-10-blocking-conditions.md index fb41b92..ce405d5 100644 --- a/tasks/architecture/oq-09-10-blocking-conditions.md +++ b/tasks/architecture/oq-09-10-blocking-conditions.md @@ -1,12 +1,13 @@ --- id: architecture/oq-09-10-blocking-conditions name: Add explicit Blocked on conditions to OQ-09 (WASM) and OQ-10 (Git Adapter) -status: pending +status: completed depends_on: [] scope: narrow risk: low impact: component level: decomposition +tags: [convention] --- ## Description @@ -39,8 +40,20 @@ Either: The decision content stays unchanged — this is a metadata-structure fix, not a 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 -The "Deferred / Blocked" section of `docs/architecture/open-questions.md` should -show a concrete blocking condition for OQ-09 and OQ-10 instead of the "no +The "Deferred / Blocked" section of `docs/architecture/open-questions.md` +shows a concrete blocking condition for OQ-09 and OQ-10 instead of the "no explicit blocking condition recorded" placeholder. \ No newline at end of file diff --git a/tasks/architecture/oq-09-wasm-server-use-case.md b/tasks/architecture/oq-09-wasm-server-use-case.md new file mode 100644 index 0000000..7effafd --- /dev/null +++ b/tasks/architecture/oq-09-wasm-server-use-case.md @@ -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`). \ No newline at end of file diff --git a/tasks/architecture/oq-10-git-adapter-spec.md b/tasks/architecture/oq-10-git-adapter-spec.md new file mode 100644 index 0000000..6e8587e --- /dev/null +++ b/tasks/architecture/oq-10-git-adapter-spec.md @@ -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). \ No newline at end of file diff --git a/tasks/architecture/oq-32-multihop-use-case.md b/tasks/architecture/oq-32-multihop-use-case.md new file mode 100644 index 0000000..bbf9404 --- /dev/null +++ b/tasks/architecture/oq-32-multihop-use-case.md @@ -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>` 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`. \ No newline at end of file diff --git a/tasks/architecture/oq-41-stream-operators-use-case.md b/tasks/architecture/oq-41-stream-operators-use-case.md new file mode 100644 index 0000000..568bf4d --- /dev/null +++ b/tasks/architecture/oq-41-stream-operators-use-case.md @@ -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`) 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`) +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`, forked from graphql-yoga's +subscription implementation. The Rust analogue would provide the same set on +`BoxStream` / `impl Stream`. + +## Verification + +This task is "completed" when a handler is identified that needs the operators +and OQ-41 has been moved to `resolved`. \ No newline at end of file diff --git a/tasks/architecture/oq-44-tty-modes-use-case.md b/tasks/architecture/oq-44-tty-modes-use-case.md new file mode 100644 index 0000000..e45c45e --- /dev/null +++ b/tasks/architecture/oq-44-tty-modes-use-case.md @@ -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`. \ No newline at end of file diff --git a/tasks/architecture/oq-46-runner-policy-use-case.md b/tasks/architecture/oq-46-runner-policy-use-case.md new file mode 100644 index 0000000..702fcf0 --- /dev/null +++ b/tasks/architecture/oq-46-runner-policy-use-case.md @@ -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`. \ No newline at end of file diff --git a/tasks/architecture/safe-exit-blocker-task-mechanism.md b/tasks/architecture/safe-exit-blocker-task-mechanism.md index df1033d..60f7e83 100644 --- a/tasks/architecture/safe-exit-blocker-task-mechanism.md +++ b/tasks/architecture/safe-exit-blocker-task-mechanism.md @@ -1,12 +1,13 @@ --- id: architecture/safe-exit-blocker-task-mechanism name: Establish the tasks/architecture/ blocker-task half of the Safe Exit protocol -status: pending +status: completed depends_on: [] scope: moderate risk: low impact: project level: planning +tags: [convention] --- ## Description @@ -58,6 +59,30 @@ it"). role spec) so future deferrals create the blocker task as part of the Safe 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 - The DB-backed backend (no manual links, vector/text search) — that's a future @@ -67,7 +92,9 @@ it"). ## Verification -- `tasks/architecture/` contains one blocker task per `deferred(scope)` OQ -- Each blocker task's `depends_on` names the concrete unblocking condition (or - a task that represents it) -- `docs/sdd_process.md` (or equivalent) references the convention \ No newline at end of file +- `tasks/architecture/` contains one external-trigger task per deferred OQ + (six total: OQ-09, 10, 32, 41, 44, 46). +- Each OQ's `Blocked on:` field names its tracker task ID, and the + `open-questions.md` Deferred/Blocked section surfaces the condition inline. +- `taskgraph validate` passes for `tasks/architecture/`. +- `docs/sdd_process.md` references the convention. \ No newline at end of file diff --git a/tasks/call/registry/access-control-ownership-check.md b/tasks/call/registry/access-control-ownership-check.md index ea97029..ebd490a 100644 --- a/tasks/call/registry/access-control-ownership-check.md +++ b/tasks/call/registry/access-control-ownership-check.md @@ -1,7 +1,7 @@ --- id: call/registry/access-control-ownership-check name: Update AccessControl::check to consult OwnershipProvider for dynamic resource ownership (ADR-050 §2) -status: done +status: completed depends_on: [core/ownership-store-trait] scope: moderate risk: medium diff --git a/tasks/call/registry/dispatch-resource-id-extraction.md b/tasks/call/registry/dispatch-resource-id-extraction.md index a877cb5..6b9c874 100644 --- a/tasks/call/registry/dispatch-resource-id-extraction.md +++ b/tasks/call/registry/dispatch-resource-id-extraction.md @@ -1,7 +1,7 @@ --- 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) -status: done +status: completed depends_on: [call/registry/operation-spec-resource-id-path, call/registry/access-control-ownership-check] scope: moderate risk: medium diff --git a/tasks/call/registry/operation-spec-resource-id-path.md b/tasks/call/registry/operation-spec-resource-id-path.md index 6e4918d..09d5abf 100644 --- a/tasks/call/registry/operation-spec-resource-id-path.md +++ b/tasks/call/registry/operation-spec-resource-id-path.md @@ -1,7 +1,7 @@ --- id: call/registry/operation-spec-resource-id-path name: Add resource_id_path field to OperationSpec (ADR-050 §2a) -status: done +status: completed depends_on: [] scope: single risk: low diff --git a/tasks/core/ownership-store-trait.md b/tasks/core/ownership-store-trait.md index 350f105..c65fe6e 100644 --- a/tasks/core/ownership-store-trait.md +++ b/tasks/core/ownership-store-trait.md @@ -1,7 +1,7 @@ --- id: core/ownership-store-trait name: Add OwnershipProvider (sync read) + OwnershipStore (async write) traits and InMemoryOwnershipStore (ADR-050) -status: done +status: completed depends_on: [] scope: moderate risk: low