Files
open-tasks/docs/architecture/decisions/004-frontmatter-field-normalization.md
glm-5.1 307b8a2b54 Add architecture specification and bump taskgraph to v0.0.2
Architecture docs for the open-tasks plugin covering the registry pattern
dispatch design, operation set, error handling, data flow, and constraints.
Includes four ADRs (registry pattern, no-cache policy, risk operation merge,
frontmatter normalization). The depends_on/dependsOn compatibility issue in
@alkdev/taskgraph is resolved in v0.0.2, so the dependency is bumped and
the docs reflect the fix.

AGENTS.md updated: canonical dependsOn field, dependents operation added,
hooks clarification, field naming note.
2026-04-28 09:29:26 +00:00

2.9 KiB

status, last_updated
status last_updated
stable 2026-04-28

ADR-004: Frontmatter Field Name Normalization (depends_on / dependsOn)

Context

There was a naming divergence between the Rust CLI and the TypeScript core library for the dependency field:

Source Field name in YAML Field name in struct
Rust CLI (taskgraph) depends_on depends_on
TypeScript lib (@alkdev/taskgraph) dependsOn dependsOn

The yaml npm package does not auto-convert snake_case to camelCase. A markdown file with depends_on: [a, b] would parse to {depends_on: ["a", "b"]}, which the TaskInput schema (expecting dependsOn) rejected as an unknown property. Value.Clean() would strip it, and Value.Check() would fail because the required field was missing.

This was a bug in @alkdev/taskgraph. The library's parseFrontmatter() function contract says it accepts "markdown with YAML frontmatter" — but the YAML convention established by the Rust CLI ecosystem was depends_on, and the parser silently discarded it.

Broader point: This was a textbook example of how issues upstream increase the surface area of issues downstream. A field naming convention in the Rust implementation created a compatibility fault line that propagated to every consumer. These are the "corners" that are hard to see around in linear text — exactly the kind of problem DAG-structured task analysis is designed to surface.

Decision

Fixed upstream in @alkdev/taskgraph v0.0.2: A normalization step was added to parseFrontmatter() between YAML parsing and Value.Clean(). Known snake_case aliases are mapped to their camelCase canonical names.

The normalization map:

const KEY_ALIASES: Record<string, string> = {
  depends_on: "dependsOn",
}

Applied after YAML parse, before Value.Clean(). Both depends_on and dependsOn are now accepted in YAML frontmatter. The canonical form for new files is dependsOn (camelCase).

Resolution

  • @alkdev/taskgraph v0.0.2 includes the fix
  • This plugin pins ^0.0.2 in its dependencies
  • No plugin-level workaround needed
  • The depends_on / dependsOn compatibility surface is resolved

Impact on This Plugin

Resolved. Task files using either depends_on (Rust CLI convention) or dependsOn (TypeScript canonical) parse correctly. No preprocessing, workarounds, or special handling required in the plugin.

AGENTS.md documents dependsOn as the canonical form for new task files, with a note that both forms are accepted.

References

  • Rust CLI struct TaskFrontmatter: uses depends_on (snake_case, Serde default)
  • TypeScript TaskInput schema: uses dependsOn (camelCase, JS convention)
  • yaml npm package: preserves YAML key casing as-is (no auto-conversion)
  • Value.Clean(): previously stripped depends_on as unknown property — now handled by normalization upstream