Decompose architecture into 28 atomic implementation tasks
Break the @alkdev/taskgraph architecture specs into dependency-ordered implementation tasks across 8 component directories: setup, schema, error, graph, analysis, cost-benefit, frontmatter, api, and review. Each task has clear acceptance criteria referencing specific architecture docs. Three review tasks serve as quality gates at critical junction points (schemas-and-errors, graph-complete, complete-library). The dependency graph is validated acyclic with 9 topological levels enabling significant parallelism across independent work streams.
This commit is contained in:
62
tasks/implementation/graph/construction.md
Normal file
62
tasks/implementation/graph/construction.md
Normal file
@@ -0,0 +1,62 @@
|
||||
---
|
||||
id: graph/construction
|
||||
name: Implement TaskGraph construction methods (fromTasks, fromRecords, fromJSON, addTask, addDependency)
|
||||
status: pending
|
||||
depends_on:
|
||||
- graph/taskgraph-class
|
||||
scope: broad
|
||||
risk: high
|
||||
impact: phase
|
||||
level: implementation
|
||||
---
|
||||
|
||||
## Description
|
||||
|
||||
Implement the four construction methods in `src/graph/construction.ts` and integrate them as static methods on `TaskGraph`. These are the primary ways to create a graph instance from structured data. Each method has distinct semantics for edge handling, error behavior, and validation.
|
||||
|
||||
Per [graph-model.md](../../../docs/architecture/graph-model.md), the preferred internal approach is to build a serialized graph JSON blob and call `graph.import()` for paths 1 and 2 (better performance than N individual addNode/addEdge calls).
|
||||
|
||||
## Acceptance Criteria
|
||||
|
||||
- [ ] `TaskGraph.fromTasks(tasks: TaskInput[]): TaskGraph`:
|
||||
- Transforms `TaskInput[]` into node data + edge data, builds serialized blob, calls `graph.import()`
|
||||
- Each `dependsOn` entry creates an edge with default `qualityRetention: 0.9`
|
||||
- `dependsOn` targets not matching any task ID become orphan nodes with default attributes
|
||||
- Duplicate task IDs throw `DuplicateNodeError`
|
||||
- Uses `mergeNode` for idempotent node merging (same ID gets merged attributes)
|
||||
- Duplicate `dependsOn` entries for the same pair create only one edge (idempotent via `addEdgeWithKey`)
|
||||
- [ ] `TaskGraph.fromRecords(tasks: TaskInput[], edges: DependencyEdge[]): TaskGraph`:
|
||||
- Edges must reference tasks that exist in the `tasks` array — throws `TaskNotFoundError` for dangling references
|
||||
- Per-edge `qualityRetention` from the `DependencyEdge` objects
|
||||
- Duplicate task IDs throw `DuplicateNodeError`
|
||||
- Duplicate edges (same prerequisite→dependent pair) throw `DuplicateEdgeError`
|
||||
- [ ] `TaskGraph.fromJSON(data: TaskGraphSerialized): TaskGraph`:
|
||||
- Validates input against `TaskGraphSerialized` schema (using TypeBox `Value.Check`)
|
||||
- Uses `graph.import()` on the validated data
|
||||
- Orphan nodes in JSON are preserved
|
||||
- [ ] `addTask(id: string, attributes: TaskGraphNodeAttributes): void`:
|
||||
- Throws `DuplicateNodeError` if ID already exists
|
||||
- Adds node to internal graphology instance
|
||||
- [ ] `addDependency(prerequisite: string, dependent: string, qualityRetention?: number): void`:
|
||||
- Throws `TaskNotFoundError` if either endpoint doesn't exist
|
||||
- Throws `DuplicateEdgeError` if edge already exists
|
||||
- Uses `addEdgeWithKey` with deterministic key `${prerequisite}->${dependent}`
|
||||
- Default `qualityRetention: 0.9` if not provided
|
||||
- [ ] `fromTasks`/`fromRecords` strip `null` → `undefined` for categorical fields during `TaskInput` → `TaskGraphNodeAttributes` transformation
|
||||
- [ ] `TaskInput` fields `tags`, `assignee`, `due`, `created`, `modified` are not stored on graph nodes (belong to caller)
|
||||
- [ ] Unit tests for each construction method: happy path, error cases, edge cases (empty arrays, cycles not rejected at construction time)
|
||||
- [ ] All construction methods use deterministic edge keys per ADR-006
|
||||
|
||||
## References
|
||||
|
||||
- docs/architecture/graph-model.md — construction paths, TaskInput→attributes transformation, error handling table
|
||||
- docs/architecture/api-surface.md — TaskGraph class, fromTasks/fromRecords/fromJSON/addTask/addDependency
|
||||
- docs/architecture/decisions/006-deterministic-edge-keys.md — deterministic edge keys
|
||||
|
||||
## Notes
|
||||
|
||||
> To be filled by implementation agent
|
||||
|
||||
## Summary
|
||||
|
||||
> To be filled on completion
|
||||
36
tasks/implementation/graph/export.md
Normal file
36
tasks/implementation/graph/export.md
Normal file
@@ -0,0 +1,36 @@
|
||||
---
|
||||
id: graph/export
|
||||
name: Implement TaskGraph export methods (export, toJSON)
|
||||
status: pending
|
||||
depends_on:
|
||||
- graph/taskgraph-class
|
||||
scope: single
|
||||
risk: trivial
|
||||
impact: component
|
||||
level: implementation
|
||||
---
|
||||
|
||||
## Description
|
||||
|
||||
Implement the `export()` and `toJSON()` methods on `TaskGraph`. These wrap graphology's `export()` to produce `TaskGraphSerialized` output.
|
||||
|
||||
## Acceptance Criteria
|
||||
|
||||
- [ ] `export(): TaskGraphSerialized` — wraps `graph.export()` and validates the output conforms to the `TaskGraphSerialized` schema
|
||||
- [ ] `toJSON(): TaskGraphSerialized` — alias for `export()` (enables `JSON.stringify(graph)` to work)
|
||||
- [ ] Exported data includes all node attributes and edge attributes (including `qualityRetention`)
|
||||
- [ ] Round-trip: `TaskGraph.fromJSON(graph.export())` produces an equivalent graph
|
||||
- [ ] Unit test: create graph, add tasks/edges, export, round-trip through fromJSON, verify equivalence
|
||||
|
||||
## References
|
||||
|
||||
- docs/architecture/api-surface.md — export/toJSON methods
|
||||
- docs/architecture/schemas.md — TaskGraphSerialized schema
|
||||
|
||||
## Notes
|
||||
|
||||
> To be filled by implementation agent
|
||||
|
||||
## Summary
|
||||
|
||||
> To be filled on completion
|
||||
38
tasks/implementation/graph/mutation.md
Normal file
38
tasks/implementation/graph/mutation.md
Normal file
@@ -0,0 +1,38 @@
|
||||
---
|
||||
id: graph/mutation
|
||||
name: Implement TaskGraph mutation methods (remove, update, updateEdgeAttributes)
|
||||
status: pending
|
||||
depends_on:
|
||||
- graph/taskgraph-class
|
||||
scope: narrow
|
||||
risk: low
|
||||
impact: component
|
||||
level: implementation
|
||||
---
|
||||
|
||||
## Description
|
||||
|
||||
Implement mutation methods in `src/graph/mutation.ts` and integrate on `TaskGraph`. These methods modify the graph in-place.
|
||||
|
||||
## Acceptance Criteria
|
||||
|
||||
- [ ] `removeTask(id: string): void` — No-op if node doesn't exist. Removes node and cascades edge removal (graphology handles this automatically).
|
||||
- [ ] `removeDependency(prerequisite: string, dependent: string): void` — No-op if edge doesn't exist. Uses deterministic edge key `${prerequisite}->${dependent}` to identify the edge.
|
||||
- [ ] `updateTask(id: string, attributes: Partial<TaskGraphNodeAttributes>): void` — Throws `TaskNotFoundError` if ID doesn't exist. Uses `mergeNodeAttributes` for shallow merge of provided attributes.
|
||||
- [ ] `updateEdgeAttributes(prerequisite: string, dependent: string, attrs: Partial<TaskGraphEdgeAttributes>): void` — Throws `TaskNotFoundError` (actually `TaskNotFoundError` for the edge itself, but per the spec, edge attributes need both endpoints to exist) if the edge doesn't exist. Uses `mergeEdgeAttributes` for shallow merge.
|
||||
- [ ] All mutations maintain the deterministic edge key format
|
||||
- [ ] Unit tests: remove nonexistent node/edge is no-op, update nonexistent throws, partial updates merge correctly
|
||||
|
||||
## References
|
||||
|
||||
- docs/architecture/api-surface.md — mutation methods
|
||||
- docs/architecture/errors-validation.md — mutation operation behavior table
|
||||
- docs/architecture/graph-model.md — edge attributes, mutation semantics
|
||||
|
||||
## Notes
|
||||
|
||||
> To be filled by implementation agent
|
||||
|
||||
## Summary
|
||||
|
||||
> To be filled on completion
|
||||
53
tasks/implementation/graph/queries.md
Normal file
53
tasks/implementation/graph/queries.md
Normal file
@@ -0,0 +1,53 @@
|
||||
---
|
||||
id: graph/queries
|
||||
name: Implement TaskGraph query methods (hasCycles, findCycles, topologicalOrder, dependencies, dependents, taskCount, getTask)
|
||||
status: pending
|
||||
depends_on:
|
||||
- graph/taskgraph-class
|
||||
scope: moderate
|
||||
risk: medium
|
||||
impact: component
|
||||
level: implementation
|
||||
---
|
||||
|
||||
## Description
|
||||
|
||||
Implement query methods in `src/graph/queries.ts` and integrate on `TaskGraph`. The `findCycles` implementation requires a custom 3-color DFS since `graphology-components` only gives SCCs, not cycle paths.
|
||||
|
||||
Per [errors-validation.md](../../../docs/architecture/errors-validation.md):
|
||||
- `hasCycles()` returns boolean (uses `graphology-dag` or `graphology-components` for fast check)
|
||||
- `findCycles()` returns `string[][]` — each inner array is an ordered cycle path
|
||||
- `topologicalOrder()` throws `CircularDependencyError` with `cycles` populated when graph is cyclic (per ADR-003)
|
||||
|
||||
## Acceptance Criteria
|
||||
|
||||
- [ ] `hasCycles(): boolean` — uses `graphology-dag.hasCycle()` or `graphology-components` SCC check as fast pre-check
|
||||
- [ ] `findCycles(): string[][]`:
|
||||
- Uses `stronglyConnectedComponents()` as pre-check: if zero multi-node SCCs and no self-loops, skip DFS
|
||||
- Custom 3-color DFS (WHITE/GREY/BLACK) to extract cycle paths
|
||||
- Returns one representative cycle per back edge, not exhaustive enumeration
|
||||
- Each inner array is an ordered node sequence where last node has edge back to first
|
||||
- [ ] `topologicalOrder(): string[]`:
|
||||
- Uses `graphology-dag.topologicalSort()` for the actual sort
|
||||
- **Throws `CircularDependencyError`** (with `cycles` from `findCycles()`) when graph is cyclic
|
||||
- Returns `string[]` of task IDs in prerequisite→dependent order
|
||||
- [ ] `dependencies(taskId: string): string[]` — returns prerequisite task IDs (inNeighbors). Throws `TaskNotFoundError` if ID doesn't exist.
|
||||
- [ ] `dependents(taskId: string): string[]` — returns dependent task IDs (outNeighbors). Throws `TaskNotFoundError` if ID doesn't exist.
|
||||
- [ ] `taskCount(): number` — returns number of nodes
|
||||
- [ ] `getTask(taskId: string): TaskGraphNodeAttributes | undefined` — returns node attributes or undefined
|
||||
- [ ] Unit tests: cycle detection on known cyclic/acyclic graphs, topologicalOrder on DAG, topologicalOrder throws on cyclic graph, dependency/dependent queries
|
||||
|
||||
## References
|
||||
|
||||
- docs/architecture/api-surface.md — query methods
|
||||
- docs/architecture/errors-validation.md — cycle handling, CircularDependencyError
|
||||
- docs/architecture/cost-benefit.md — findCycles algorithm description
|
||||
- docs/architecture/decisions/003-topo-order-throws-on-cycle.md — ADR-003
|
||||
|
||||
## Notes
|
||||
|
||||
> To be filled by implementation agent
|
||||
|
||||
## Summary
|
||||
|
||||
> To be filled on completion
|
||||
54
tasks/implementation/graph/subgraph-and-validation.md
Normal file
54
tasks/implementation/graph/subgraph-and-validation.md
Normal file
@@ -0,0 +1,54 @@
|
||||
---
|
||||
id: graph/subgraph-and-validation
|
||||
name: Implement TaskGraph subgraph and validation methods
|
||||
status: pending
|
||||
depends_on:
|
||||
- graph/taskgraph-class
|
||||
- graph/queries
|
||||
- schema/input-schemas
|
||||
- schema/graph-schemas
|
||||
scope: narrow
|
||||
risk: low
|
||||
impact: component
|
||||
level: implementation
|
||||
---
|
||||
|
||||
## Description
|
||||
|
||||
Implement the `subgraph()` method and the three validation methods (`validateSchema`, `validateGraph`, `validate`) on `TaskGraph`.
|
||||
|
||||
Per [ADR-007](../../../docs/architecture/decisions/007-subgraph-internal-only.md), `subgraph` returns only edges where both endpoints are in the filtered set.
|
||||
|
||||
Per [errors-validation.md](../../../docs/architecture/errors-validation.md), validation methods collect issues and return arrays — never throw.
|
||||
|
||||
## Acceptance Criteria
|
||||
|
||||
- [ ] `subgraph(filter: (taskId: string, attrs: TaskGraphNodeAttributes) => boolean): TaskGraph`:
|
||||
- Uses `graphology-operators.subgraph` to extract matching nodes
|
||||
- Returns only edges where both endpoints are in the filtered set (internal-only) per ADR-007
|
||||
- Returns a new `TaskGraph` instance (not mutating the original)
|
||||
- [ ] `validateSchema(): ValidationError[]`:
|
||||
- Uses TypeBox `Value.Check()` and `Value.Errors()` on each node's attributes
|
||||
- Returns structured `ValidationError[]` with `type: "schema"`, `taskId`, `field`, `message`, `value`
|
||||
- [ ] `validateGraph(): GraphValidationError[]`:
|
||||
- Runs `findCycles()` and checks for dangling dependency references
|
||||
- Returns structured `GraphValidationError[]` with `type: "graph"`, `category`, `message`, optional `details`
|
||||
- Cycle category: `"cycle"` with cycle paths in `details`
|
||||
- Dangling reference category: `"dangling-reference"` with the referencing task ID
|
||||
- [ ] `validate(): ValidationError[]` — runs both `validateSchema()` and `validateGraph()`, returns combined array
|
||||
- [ ] `ValidationError` and `GraphValidationError` interfaces defined (may be in error module or co-located)
|
||||
- [ ] Unit tests: subgraph filtering, subgraph excludes external edges, validateSchema catches invalid enums, validateGraph catches cycles and dangling refs
|
||||
|
||||
## References
|
||||
|
||||
- docs/architecture/api-surface.md — validation API, subgraph
|
||||
- docs/architecture/errors-validation.md — validation levels, return types
|
||||
- docs/architecture/decisions/007-subgraph-internal-only.md — subgraph semantics
|
||||
|
||||
## Notes
|
||||
|
||||
> To be filled by implementation agent
|
||||
|
||||
## Summary
|
||||
|
||||
> To be filled on completion
|
||||
45
tasks/implementation/graph/taskgraph-class.md
Normal file
45
tasks/implementation/graph/taskgraph-class.md
Normal file
@@ -0,0 +1,45 @@
|
||||
---
|
||||
id: graph/taskgraph-class
|
||||
name: Implement TaskGraph class skeleton with graphology DirectedGraph
|
||||
status: pending
|
||||
depends_on:
|
||||
- schema/enums
|
||||
- schema/input-schemas
|
||||
- schema/graph-schemas
|
||||
- error/error-hierarchy
|
||||
- setup/project-init
|
||||
scope: moderate
|
||||
risk: medium
|
||||
impact: phase
|
||||
level: implementation
|
||||
---
|
||||
|
||||
## Description
|
||||
|
||||
Create the `TaskGraph` class in `src/graph/index.ts` that wraps `graphology.DirectedGraph`. This is the data class that holds the graph instance and provides the foundation for construction, mutation, and query methods. At this stage, implement the constructor, `raw` getter, and the overall class structure. Actual construction and analysis methods come in dependent tasks.
|
||||
|
||||
## Acceptance Criteria
|
||||
|
||||
- [ ] `src/graph/index.ts` exports `TaskGraph` class
|
||||
- [ ] Constructor creates an internal `graphology.DirectedGraph` with options `{ type: 'directed', multi: false, allowSelfLoops: false }`
|
||||
- [ ] `get raw(): Graph` returns the underlying graphology instance
|
||||
- [ ] Constructor accepts optional `TaskGraphSerialized` for initializing from serialized data (delegates to `fromJSON` pattern)
|
||||
- [ ] Class stores edge key format: `${source}->${target}` (per ADR-006)
|
||||
- [ ] No parallel edges constraint enforced by `multi: false` graph option
|
||||
- [ ] No self-loops constraint enforced by `allowSelfLoops: false` graph option
|
||||
- [ ] Internal `_edgeKey(source, target): string` method producing deterministic keys
|
||||
- [ ] Re-exported from `src/index.ts`
|
||||
|
||||
## References
|
||||
|
||||
- docs/architecture/api-surface.md — TaskGraph class API
|
||||
- docs/architecture/graph-model.md — construction paths, edge direction, constraints
|
||||
- docs/architecture/decisions/006-deterministic-edge-keys.md — edge key format
|
||||
|
||||
## Notes
|
||||
|
||||
> To be filled by implementation agent
|
||||
|
||||
## Summary
|
||||
|
||||
> To be filled on completion
|
||||
Reference in New Issue
Block a user