* 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).