Skip to content

T-NUSP-run-quality-checks-logs-cwd-and-forwards-project-root

Status: closed/superseded · Impact: medium · Complexity: small

Auto-generated from a /sdlc:task-work post-mortem. Review and promote to open/ready before picking up.

run_quality_checks.py’s behavior depends on the cwd it was invoked from — audit_entities.py failed in the lease-CLI task’s first run because the runner was started from a non-worktree cwd, and the same verb invoked directly from the worktree root passed 12/12. The runner gives no diagnostic about where it started, so the operator has to spelunk to figure out why. Two cheap fixes close the gap: (1) log the cwd at the start of every run, and (2) when a verb supports --project-root, forward the runner’s resolved project-root to it so the verb stops inheriting whatever cwd the runner happened to have. Cite T-QC31-add-sdlc-lease-cli-commands for the live incident.

LocationRole today
plugin/scripts/run_quality_checks.pyRuns each declared verb in turn, captures exit codes, surfaces FAIL/OK summary. Does NOT log its starting cwd; does NOT inject --project-root into verbs that accept it.
plugin/scripts/audit_entities.pyAccepts --project-root but receives whatever cwd the runner inherited from its invoker. Failure mode in the lease-CLI task: started in a non-worktree cwd, audited the wrong tree, reported drift.
sdlc.yamlDeclares the verb list but has no syntax for “this verb supports --project-root, please pass it.”
  • run_quality_checks.py logs cwd=<absolute-path> as its first stdout line on every invocation, so a failing run’s transcript always self-documents the entry point.
  • The runner resolves its own intended project-root (the worktree root — already known because sdlc.yaml is discovered relative to it) and forwards it as --project-root <resolved-root> to verbs that accept the flag. Per-verb opt-in via a tiny addition to sdlc.yaml’s verb syntax (e.g. --project-root: true per verb entry) OR a runner-side allowlist of well-known verbs that support it (smaller surface, easier to land).
  • Verbs that don’t accept --project-root are invoked unchanged.
  1. Add the cwd log line as the first thing main() does after argparse. One commit, trivially reviewable.
  2. Decide the opt-in shape: per-verb config in sdlc.yaml vs runner-side allowlist. Recommend the allowlist first (smaller blast radius) and graduate to the per-verb config if/when a third verb wants it.
  3. Implement the forwarding: for each verb in the allowlist, append --project-root <resolved-root> to the invocation.
  4. Regression test: a runner invocation from a deliberately wrong cwd still produces correct verb behavior because the verb receives the explicit --project-root.
LocationKindChange
plugin/scripts/run_quality_checks.pymodifyAdd cwd log line; add --project-root forwarding to a runner-side allowlist of verbs.
plugin/scripts/test_run_quality_checks.py (or wherever existing tests live)modifyAdd tests: (a) cwd log line is present in stdout; (b) audit_entities.py invoked from wrong cwd still audits the correct root.
plugin/scripts/run_quality_checks.py module docstringmodifyDocument the cwd-log invariant and the project-root forwarding allowlist as a maintenance note.
  • AC-1: Every invocation of run_quality_checks.py prints cwd=<absolute-path> as its first stdout line.
  • AC-2: A regression test invokes the runner from a non- worktree cwd and asserts audit_entities.py still audits the correct project root (via the forwarded --project-root flag).
  • AC-3: Verbs not in the runner’s --project-root-capable allowlist are invoked unchanged — backward-compatible by default.
  • AC-4: A failing run’s stderr / stdout transcript is now self-diagnostic for the cwd-confusion class of failure (i.e. a future operator hitting the same issue can read the cwd=... line and immediately spot the mismatch).
  • Promoting the allowlist to a per-verb config field in sdlc.yaml. Tracked as a future extension; the allowlist is enough for slice 1.
  • Forcing the runner itself to chdir to the worktree root. Cwd is sometimes load-bearing for verbs that resolve relative paths (e.g. test runners); the explicit --project-root forwarding is the lower-risk fix.
  • none

Spawned by /sdlc:task-work post-mortem of T-QC31-add-sdlc-lease-cli-commands on 2026-05-23.

Bullet: Quality runner is cwd-sensitive. First run reported audit_entities.py failing even though direct invocation passed (the runner started from a non-worktree cwd). Running from the worktree root made it pass 12/12. Suggests: run_quality_checks.py could log its working directory at start, or each verb could be invoked with an explicit —project-root if the verb supports it. Keywords searched: run_quality_checks, audit_entities, cwd-sensitive, non-worktree, project-root, invocation, directory, reported Excluded: 2026-05-23-add-sdlc-lease-cli-commands Top candidates (score / status / headline):

  • 36 / closed/done / 2026-05-21-run-quality-checks-isolates-pre-existing-drift — run_quality_checks.py only fails on drift the current branch introduced
  • 25 / closed/done / 2026-05-19-implement-entities-migrate — Implement /sdlc:entities-migrate to apply mechanical schema-drift fixes
  • 21 / planning/draft / 2026-05-21-audit-entities-baseline-allow — audit_entities.py: distinguish pre-existing drift from PR-introduced drift
  • 16 / closed/done / 2026-05-19-co-locate-skill-specific-scripts — Co-locate skill-specific scripts under their skill dir; promote when shared
  • 16 / closed/done / 2026-05-19-task-work-uses-per-project-quality-checks — Make /sdlc:task-work quality-check commands per-project configurable Decision: SPAWNED Rationale: SPAWNED stands. The high-scoring top match (run_quality_checks-isolates-pre-existing-drift) is closed/done and addresses pre-existing-drift baselining, a distinct concern from cwd-logging or —project-root passthrough. The audit-entities-baseline-allow candidate is also about drift baselining, not invocation cwd.

← Back to Tasks