Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .claude/agent-memory/epic-planner/MEMORY.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
# Epic-Planner Memory Index

- [epic-planner-state required fields](feedback_epic_planner_state_required_fields.md) — checkpoint validator also requires top-level max_parallel_features (int 1-8) and per-feature research_path
- [epic-planner-state required fields](feedback_epic_planner_state_required_fields.md) — checkpoint validator also requires max_parallel_features + per-feature research_path, and exact enums verdict=epic|non_epic, next_step=NON_EPIC_RECOMMENDED
- [Check in-flight branches before decomposing](feedback_check_inflight_branches_before_decomposition.md) — bugs spawned by another feature's work often collide with that unmerged branch; diff candidate files against every local branch before planning waves
- [epic-plan tooling not vendored](reference_epic_plan_tooling_not_vendored.md) — epic_wave_computation.py + epic-manifest validator absent in this repo; verify DAG/waves manually, no `plan`-type validation of epic.md
- [Concurrent prep children need worktree isolation](feedback_concurrent_prep_children_worktree_isolation.md) — each concurrent prep child gets isolation:worktree + child-scoped orchestrator-state.<slug>.json or siblings overwrite the canonical checkpoint
- [Force-remove prep-child worktree](feedback_prep_child_worktree_force_remove.md) — worktree remove may block on uncommitted orchestrator-agent-memory scratch; force-remove is safe once HEAD == merged tip and only .claude/agent-memory/orchestrator/** is dirty
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
---
name: check-inflight-branches-before-decomposition
description: Before computing an epic decomposition, diff each candidate feature's target files against every unmerged local branch and worktree, not just origin/main
metadata:
type: feedback
---

Before deciding a decomposition or wave layering, enumerate unmerged work and check whether any
candidate feature's target files are being moved or rewritten there:

```
git worktree list --porcelain
git branch -a
git diff --stat origin/main...<branch> -- '*.cs'
git show <branch>:<path> | grep -n <symbol>
```

Also read that branch's `artifacts/orchestration/orchestrator-state.json` (`next_step`,
`step9_status`) from its own worktree to judge how far it is from merging. A branch at
`step9_status: pending` with no PR is not about to land.

**Why:** Bugs promoted out of another feature's review are usually located in the exact code that
feature is refactoring. In the 505/506/507/508 planning run, all four issues were spawned by the
in-flight `bug/ribbon-engine-readiness-guard-503` branch, and that branch relocated the four
callback methods named by #505 and #506 out of `RibbonViewer.cs` into a new
`RibbonViewer.EngineCommands.cs` while carrying both defects forward unchanged. An integration
branch cut from `origin/main` could not even have run preparation for those two issues: the
atomic-planner would have targeted a path the parent branch deletes, guaranteeing a modify/delete
conflict at fan-in. Checking only `origin/main` would have missed this entirely.

**How to apply:** Run this check during the epic-worthiness gate, before authoring the manifest or
creating the integration branch. When an unmerged branch relocates or rewrites a candidate's target
file, that candidate is sequencing-blocked behind it; say so rather than adding a `depends_on` edge
(the blocker is outside the epic's DAG and cannot be modeled as a wave). Split the objective into
the conflict-free subset that can proceed now and the blocked remainder.

Two related decomposition rules this run confirmed:
- Two issues whose fixes edit adjacent lines of the same methods cannot be separate parallel
features; merge them into one feature (one PR closing both issues) rather than serializing them
with a dependency edge, which costs a wave and still risks conflict.
- A "contract" coupling (feature A consumes a property feature B makes null-safe) is only a real
`depends_on` edge if A cannot be written correctly under B's current contract. Prefer encoding
the constraint in A's prepared plan over adding an edge, since preparation happens with full
knowledge of both.

Related: [[epic-planner-state-required-fields]], [[epic-plan-tooling-not-vendored]].
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
---
name: epic-planner-state-required-fields
description: epic-planner-state checkpoint validator requires top-level max_parallel_features and per-feature research_path, beyond the fields listed in the agent doc
description: epic-planner-state checkpoint validator requires top-level max_parallel_features and per-feature research_path, and enforces exact enum values for epic_worthiness.verdict / next_step, beyond the fields listed in the agent doc
metadata:
type: feedback
---
Expand All @@ -14,6 +14,17 @@ The `epic-planner-state` schema enforced by `mcp__drm-copilot__validate_orchestr
- per-feature `research_path` — every entry in `features[]` must carry it (the research artifact
path under `<feature-folder>/research/`).

The validator also enforces exact enum strings the skill/agent docs never state:

- `epic_worthiness.verdict` must be exactly `"epic"` or `"non_epic"`. Descriptive values such as
`"pass"` / `"fail"` are rejected.
- When the verdict is `"non_epic"`, `next_step` must be exactly `"NON_EPIC_RECOMMENDED"`. This is
the terminal state for a gate-failed planning run; there is no scaffolding to build, and the
checkpoint validates with `features: []`, `epic_manifest_path: null`, and
`integration_branch: null`. Extra descriptive keys (e.g. a `candidate_decomposition[]` array
recording the rejected decomposition) are permitted and are the right place to preserve the
analysis.

**Why:** A resumed run inherited a prior checkpoint that lacked both fields; the validator failed
until they were added. The agent doc's field list is necessary but not sufficient for the schema.

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
# claudemd-nullable-gate-diverges-from-ci (Issue #522)

- Date captured: 2026-08-08
- Author: Dan Moisan
- Status: Promoted -> docs/features/active/claudemd-nullable-gate-diverges-from-ci/ (Issue #522)

> Automation note: Keep the section headings below unchanged; the promotion tooling maps each of them into the GitHub bug issue template.

- Issue: #522
- Issue URL: https://github.com/drmoisan/TaskMaster/issues/522
- Last Updated: 2026-08-08
## Summary

The mandatory C# type-check toolchain command documented in `CLAUDE.md` (and two other governance files) passes `/p:Nullable=enable`, but `.github/workflows/ci.yml` deliberately omits that flag. Forcing it recompiles the whole solution under a nullable context the repository never adopted, producing roughly 200-414 errors that are red on `main` with no local change. The documented gate therefore can never pass, and every agent that runs it literally manufactures a false blocking finding.

## Environment

- OS/version: Windows 11, `windows-latest` runner for CI
- Runtime: .NET Framework 4.8.1, MSBuild via Visual Studio
- Command/flags used: `msbuild TaskMaster.sln /t:Build /p:Configuration=Debug /p:Platform='Any CPU' /p:Nullable=enable /p:TreatWarningsAsErrors=true`
- Data source or fixture: none

## Steps to Reproduce

1. Check out `main` with no local modifications.
2. Run the `CLAUDE.md` step-3 type-check command verbatim:
`msbuild TaskMaster.sln /t:Build /p:Configuration=Debug /p:Platform='Any CPU' /p:Nullable=enable /p:TreatWarningsAsErrors=true`
3. Observe several hundred `CS86xx` nullable errors in files that carry no `#nullable enable` pragma.
4. Run CI's actual command and observe exit code 0:
`msbuild TaskMaster.sln /t:Rebuild /m /p:Configuration=Debug "/p:Platform=Any CPU" /p:TreatWarningsAsErrors=true`

## Expected Behavior

The type-check command documented in the governance files matches the command CI enforces, so that a clean `main` passes the documented gate and any failure an agent sees is a real regression it introduced.

## Actual Behavior

`.github/workflows/ci.yml` (step "Build with nullable warnings treated as errors", lines 103-116) omits `/p:Nullable=enable` and states the rationale in-line:

```yaml
# Enforcement now relies entirely on each file's own #nullable
# enable pragma (the repo's per-file opt-in convention; UtilitiesCS.csproj and
# SVGControl.csproj carry no project-level <Nullable> element) plus
# /p:TreatWarningsAsErrors=true.
& msbuild $env:SOLUTION_PATH /t:Rebuild /m /p:Configuration=Debug `
"/p:Platform=Any CPU" `
/p:TreatWarningsAsErrors=true
```

The repository uses per-file `#nullable enable` opt-in. Solution-wide `/p:Nullable=enable` opts in every file at once, including the large majority that were never written for it.

The divergent command appears in six places across three files:

- `CLAUDE.md:206`, `CLAUDE.md:383`, `CLAUDE.md:401`
- `.claude/rules/csharp.md:16` (and referenced again at `:83`)
- `.claude/skills/csharp-qa-gate/SKILL.md:32`

## Logs / Screenshots

- [x] Attached minimal logs or snippet
- Snippet:

```text
error CS8603: Possible null reference return.
```

Observed on a changed file with no `#nullable enable` pragma. The same build returns 0 errors under CI's command. Independently reproduced on two separate deliveries on 2026-08-08: issue #507 (measured ~414 errors under the forced flag) and issue #508 (measured 195 pre-existing errors under a forced `/t:Rebuild`, none in either changed file).

## Impact / Severity

- [ ] Blocker
- [ ] High
- [x] Medium
- [ ] Low

Not a product defect, but it corrupts the quality loop that every C# change depends on. An agent following `CLAUDE.md` literally will report a blocking nullable failure on work that is actually clean, and will then either "fix" a non-defect by adding unnecessary null handling, or halt and escalate. Both #507 and #508 required a human-level override of a subagent's false `CS8603` blocker on 2026-08-08; without that override each would have shipped a spurious remediation cycle. The cost recurs on every C#-touching run until the documentation is corrected.

## Suspected Cause / Notes

The governance files appear to predate the CI decision to rely on per-file pragmas. The `ci.yml` comment documents the reasoning for dropping the flag, but the change was never propagated back into `CLAUDE.md`, `.claude/rules/csharp.md`, or `.claude/skills/csharp-qa-gate/SKILL.md`.

Note the interaction documented at `.claude/rules/csharp.md:83`: new analyzer rule severities are pinned to `suggestion` specifically because the type-check step promotes `warning` diagnostics to errors. That rationale survives the fix — `/p:TreatWarningsAsErrors=true` is retained either way — but the text referencing `/p:Nullable=enable` should be updated with the rest.

## Proposed Fix / Validation Ideas

- [ ] Update all six occurrences to match CI's command exactly, including `/t:Rebuild` and the `/m` and quoting form.
- [ ] Preserve and relocate the `ci.yml` rationale comment into `.claude/rules/csharp.md` so the per-file-pragma convention is stated in the governance layer, not only in the workflow.
- [ ] Unit coverage areas: none; documentation-only change.
- [ ] Integration scenario to retest: run the corrected command on a clean `main` and confirm exit code 0.
- [ ] Manual verification notes: confirm the corrected command still fails when a file with `#nullable enable` genuinely regresses, so the gate is corrected rather than merely disabled.

## Next Step

- [x] Promote to GitHub issue (bug-report template)
- [ ] Move to active fix folder / branch
Loading