feat(planctl): v2 task-state commands (next, list, complete, status) #1
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "feature/26174-planctl-task-cmds"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Adds four new planctl subcommands: next, list, complete, status. Full golden-file fixture coverage, emit unit tests, and pre-PR codex review (3 rounds, 4 bugs fixed). See dev/plans/26174-planctl-task-cmds/prd.md for full spec.
* main.go: resolvePlans implementing the R5.1 / design §3.5 decision tree — Case A (explicit path stat) and a unified upward walk for Cases B (cwd inside plan dir) and C (cwd ancestor has dev/plans/) with archive/ filter and lex sort; Case D returns the 3-option error. No downward WalkDir. * Hand-rolled parseLintFlags accepting --format={text,json}, --strict, --no-ears, --color={auto,always,never} (no-op per D-1), both --flag=value and --flag value forms. Unknown flag → error. * runLint orchestrator: resolvePlans → loadPlan (reads prd/design/ tasks via Scan + os.Stat for close-out markers) → lintPlan (BuildIndex + 4 rule checkers, missing-PRD short-circuit per R3.2, PlanDir backfill, sortDiagnostics). Placeholder text emitter — task 6 replaces with the full emitText/emitJSON from design §3.7. * computeExit returns 0/1 per R5.4/R5.5; 2 is reserved for outer discovery/I-O failures (runLint returns 2 directly on those paths). * main_test.go: TestResolvePlans covers Cases A (valid + invalid), B (deeply-nested cwd), C (3 plans + archive filter + lex sort), D (no ancestor); TestParseLintFlags covers every documented flag plus unknown-flag rejection and last-value-wins. The prior stub test TestRun_LintStub was replaced with TestRun_LintMissingPRD — the stub assertion no longer holds now that runLint actually runs the pipeline. Output-format assertions may need revision when task 6.6 lands per tasks.md 5.6 note. Parent task 5.0 from dev/plans/26172-planctl/tasks.md. Codex code-review session: 019db2ca-721d-7b11-8760-639b2588b114 (1 round, approved on R1).* emit.go (new): PlanResult (moved from main.go), emitText, emitJSON, shared severityLabel / countSeverities helpers. * emitText: R5.10 single-plan branch (diagnostics or R5.3 clean- summary, no headers / aggregate) + R5.9 multi-plan branch (`=== <basename> ===` per-plan header, blank-line separator, aggregate "N plans linted, E errors, W warnings" with always- plural labels). * emitJSON: jsonl format per R5.11 with struct-tag-pinned field order (plan_dir, path, line, severity, code, message), terminal {"summary":{"plans":N,"errors":E,"warnings":W}} object, SetEscapeHTML(false) so ampersands / `<` stay raw. * Empty Path (directory-level diagnostics: missing-prd, missing-closeout-file) renders with the plan-dir basename in text mode; in JSON the shape is uniform with `path=""` and plan_dir carrying the basename. * main.go: runLint selects emitText or emitJSON based on flags.format; placeholder emitter removed. * emit_test.go: single-plan clean, single-plan dirty, multi-plan text, multi-plan JSONL validity, clean-plan JSON (summary-only), --strict promoting warnings → exit 1, clean → 0, errors → 1. Parent task 6.0 from dev/plans/26172-planctl/tasks.md. Codex code-review session: 019db2d1-e9ae-7fc0-9b8b-270db5f0b2a3 (1 round, approved on R1).* main_test.go: TestGoldenFixtures sweeps testdata/{clean,dirty,inline-code-exclusion,multi}/**; compares stdout against expected.golden and exit against expected.exit. --update flag regenerates sidecars. Per-fixture invocation overrides via optional args.txt (with FIXTURE substitution) and cwd-rel.txt. Handles flat-layout fixtures (prd.md at class root) and multi-plan layouts (dev/plans/ subtree). * CRLF normalisation on both sides of the golden compare per design §7.4's Windows-CI contract. * Clean fixtures: simple-plan (prd+tasks), with-design-plan (prd+design+tasks, full coverage). * Dirty single-class fixtures: orphan-requirement, orphan-design, uncovered-requirement, uncovered-design, tag-syntax, tag-unclosed, ears-violation, missing-closeout-file. Each isolates one diagnostic class; ears-violation-strict and ears-violation-no-ears share the plan via args.txt overrides. * tag-unclosed-with-recovery fixture: codex R1 regression guard for design §3.3 recovery — the recovery line uniquely cites D§2.2 so broken recovery would surface as uncovered-design. * inline-code-exclusion fixture: decoys cite an undeclared R9.9 so any masking leak would trip orphan-requirement. * Multi-plan fixtures: case-c (repo root with dev/plans/{alpha,beta, archive/retired}/, Case C upward walk + archive skip); case-b (deeply-nested cwd inside a plan dir, Case B resolution). * Perf fixture testdata/perf/big-plan/ — synthetic 5-file plan (~90 KB) with 36 R-ids, 18 D§ sections, 72 tasks (all covered). Parent 8 wires Benchmark_Lint_BigPlan. Parent task 7.0 from dev/plans/26172-planctl/tasks.md. Codex code-review session: 019db2ed-d621-7bc0-90f2-05feb5e2fe50 (2 rounds).* .forgejo/workflows/planctl.yml: build/test matrix across {ubuntu-latest, macos-latest, windows-latest} × {1.22, stable} per D-3 / PRD R7.4. Dedicated bench job on ubuntu+stable so ns/op numbers stay comparable across runs. Path filters scope CI to planctl-adjacent changes only. * cmd/planctl/bench_test.go: Benchmark_Lint_BigPlan times the full lint pipeline on testdata/perf/big-plan/. Local M4 Pro: ~720µs, two orders of magnitude under M3's 100ms target. * TestLint_BigPlan_SoftCeiling logs (via direct os.Stderr write — not t.Logf, which is suppressed without -v) when wall time exceeds 100ms. Soft check per task 8.3 — CI runner variance means a hard assert would be flaky; the visible stderr line is the regression signal. * Windows line-ending handling already landed in parent-7's harness (CRLF → LF normalisation on both sides of golden compare), so 8.4 is satisfied by construction. Parent task 8.0 from dev/plans/26172-planctl/tasks.md. Codex code-review session: 019db2f3-2f80-7fc0-b7bb-9e1f677f978e (2 rounds).* README.md: new `## planctl` section after the jj-commitd section — description, `go install` command, classification-code list, pointer to the plan dir. * AGENTS.md: bullet under `dev/ workflow` pointing agents at `planctl lint` as a pre-codex sanity gate. * dev/README.md: "Pre-codex planctl lint gate" paragraph in the Skill workflow section. * tasks.md: appended full traceability matrix — one row per PRD R-id and one per design D§ id, with the tasks and tests covering each. Grep-verifiable against the `// spec:planctl/*` anchors. * Dogfood pass (task 9.5) against dev/plans/26172-planctl/ flushed out real self-violations in the plan docs: - Expanded en-dash range tags (`R1.1–R1.7`) to explicit comma-separated lists. - Dropped comma-containing annotations (`D§0 (D-2, D-5)` → `D§0`). - Added D§2 / D§3 / D§7 umbrella citations to tasks 5.3 / 3.1 / 7.7. - Applied the design §3.4 bold-prefix EARS exemption to R5.3 / R5.4 / R5.5 / R5.11 (grammatically valid but non-strict EARS) by prepending short bold labels. - Updated PRD R5.11 to say `plan-directory basename` instead of `relative path from CWD` — resolving a long-standing divergence with task 6.4 + design §3.7 + the implementation. * Final dogfood: `26172-planctl: clean (79 tasks, 45 requirements, 21 design sections)`. Parent task 9.0 from dev/plans/26172-planctl/tasks.md. Codex code-review session: 019db302-b8a9-7e53-b1e3-feab4ed7081f (2 rounds).2f5ad32113tob8ae95373cb8ae95373ctoaff5a30b27Pull request closed