- fromTasks: bulk import via serialized blob, orphan nodes for dangling refs, DuplicateNodeError for duplicates, edge dedup, null→undefined stripping - fromRecords: strict validation (TaskNotFoundError for dangling refs, DuplicateEdgeError for duplicate edges), per-edge qualityRetention - fromJSON: TypeBox Value.Check validation, InvalidInputError on schema failure, orphan nodes preserved - addTask: throws DuplicateNodeError if ID exists - addDependency: throws TaskNotFoundError/DuplicateEdgeError, deterministic edge keys per ADR-006, default qualityRetention 0.9 - taskInputToNodeAttrs: strips null→undefined for categorical fields, drops non-graph fields (tags, assignee, due, created, modified) - 47 new unit tests (304 total, all passing)
4.4 KiB
4.4 KiB
id, name, status, depends_on, scope, risk, impact, level
| id | name | status | depends_on | scope | risk | impact | level | |
|---|---|---|---|---|---|---|---|---|
| graph/construction | Implement TaskGraph construction methods (fromTasks, fromRecords, fromJSON, addTask, addDependency) | completed |
|
broad | high | phase | 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, 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, callsgraph.import() - Each
dependsOnentry creates an edge with defaultqualityRetention: 0.9 dependsOntargets not matching any task ID become orphan nodes with default attributes- Duplicate task IDs throw
DuplicateNodeError - Uses
mergeNodefor idempotent node merging (same ID gets merged attributes) - Duplicate
dependsOnentries for the same pair create only one edge (idempotent viaaddEdgeWithKey)
- Transforms
TaskGraph.fromRecords(tasks: TaskInput[], edges: DependencyEdge[]): TaskGraph:- Edges must reference tasks that exist in the
tasksarray — throwsTaskNotFoundErrorfor dangling references - Per-edge
qualityRetentionfrom theDependencyEdgeobjects - Duplicate task IDs throw
DuplicateNodeError - Duplicate edges (same prerequisite→dependent pair) throw
DuplicateEdgeError
- Edges must reference tasks that exist in the
TaskGraph.fromJSON(data: TaskGraphSerialized): TaskGraph:- Validates input against
TaskGraphSerializedschema (using TypeBoxValue.Check) - Uses
graph.import()on the validated data - Orphan nodes in JSON are preserved
- Validates input against
addTask(id: string, attributes: TaskGraphNodeAttributes): void:- Throws
DuplicateNodeErrorif ID already exists - Adds node to internal graphology instance
- Throws
addDependency(prerequisite: string, dependent: string, qualityRetention?: number): void:- Throws
TaskNotFoundErrorif either endpoint doesn't exist - Throws
DuplicateEdgeErrorif edge already exists - Uses
addEdgeWithKeywith deterministic key${prerequisite}->${dependent} - Default
qualityRetention: 0.9if not provided
- Throws
fromTasks/fromRecordsstripnull→undefinedfor categorical fields duringTaskInput→TaskGraphNodeAttributestransformationTaskInputfieldstags,assignee,due,created,modifiedare 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
Implementation approach:
fromTasksandfromRecordsuse the bulkgraph.import()approach per architecture recommendation (build serialized blob, import in one call).fromJSONadds TypeBoxValue.Check()validation before importing, throwingInvalidInputErrorfor schema violations.fromTaskscreates orphan nodes for dangling dependsOn references with default attributes{ name: <dep-id> }.fromRecordsis strict — any dangling edge reference throwsTaskNotFoundError.addTaskandaddDependencyare thin wrappers with validation on the underlying graphology instance.- The
taskInputToNodeAttrshelper strips null→undefined for categorical fields and drops non-graph fields (tags, assignee, due, created, modified).
Summary
Implemented all five construction methods on the TaskGraph class.
- Modified:
src/graph/construction.ts(full implementation of fromTasks, fromRecords, fromJSON with validation, addTask, addDependency; taskInputToNodeAttrs helper) - Modified:
test/graph.test.ts(added 47 new tests for construction methods, preserved 42 existing tests) - Tests: 304 total (all passing), lint clean